使用GstApp.AppSrc循环播放Gst.Sample列表 [英] Looping playback of a list of Gst.Sample with GstApp.AppSrc
问题描述
我正在尝试使用GStreamer编写一个简单的音乐播放器.我想播放任意音乐文件ABS_FILE_PATH
,将样本存储用于其他目的,并在达到流的原始结尾后无限期地循环这些样本.
I'm trying to write a simple music player using GStreamer. I want to play any arbitrary music file ABS_FILE_PATH
, store the samples for other purposes and later loop over these indefinitely, once the original end of stream is reached.
现在播放音乐的效果很好,直到播放完曲目的最后一个样本后不久.在大多数情况下,只有寂静,但有时会有一两个可听见的样本表明轨道刚刚开始播放.终端输出也是如此.它表明,在循环开始后的几个样本中,need-data
信号的发送频率比以前更高.
Now playing the music works fine until short after the last sample of the track was played. Most of the time there's just silence, but sometimes there are one or two audible samples indicating, that the track just started playing again. The same holds for the terminal output. It shows, that a few samples after looping was started, the need-data
signal is sent more frequently than before.
我已经使用fakesink
来转储数据,这似乎工作得很好.数据像预期的那样被循环.
I've used fakesink
for dumping the data, which seemed to work perfectly fine. The data was just looped, like it was intended.
那么这里会发生什么呢?为什么样本不播放第二(第三,第四,...)时间?我的想法用光了.
So what happens here? Why don't the samples play a second (third, fourth, ...) time? I've run out of ideas.
下面,我添加了一个最小的示例,说明我在没有任何UI的情况下所做的事情,但存在相同的问题:
Following I added a minimal example of what I'm doing without any UI, but with the same problem:
import itertools, signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
from gi.repository import Gst, GstApp, Gtk
Gst.init(None)
# read samples with Gst.AppSink from a playbin
playbin = Gst.ElementFactory.make("playbin")
playbin.props.uri = "file://" + ABS_FILE_PATH # only works with absolute paths
playbin.props.audio_sink = GstApp.AppSink(sync=False, emit_signals=True)
playbin.set_state(Gst.State.PLAYING)
# loop over all samples
def samples(app_sink):
samples = []
sample = app_sink.pull_sample()
while sample:
yield sample
samples.append(sample)
sample = app_sink.pull_sample()
print('looping')
for sample in itertools.cycle(samples):
yield sample
# write samples with Gst.AppSrc
def need_data(appsrc, length, samples):
print('sample')
sample = next(samples)
appsrc.set_caps(sample.get_caps())
appsrc.push_buffer(sample.get_buffer())
src = GstApp.AppSrc(format=Gst.Format.TIME, emit_signals=True)
src.connect('need-data', need_data, samples(playbin.props.audio_sink))
# to the autoaudiosink or just a fakesink
sink = Gst.ElementFactory.make("autoaudiosink")
#sink = Gst.ElementFactory.make("fakesink")
#sink.props.dump = True # dump contents of fakesink
# playback
play = Gst.Pipeline()
play.add(src)
play.add(sink)
src.link(sink)
play.set_state(Gst.State.PLAYING)
Gtk.main()
gst-plugins-base:1.4.4
推荐答案
在的评论蒂亚戈斯(Thiagoss).
I've found a working solution with help of the comment of thiagoss.
GstBuffer结构文档列出与时间戳相关的所有字段
The GstBuffer struct documentation lists all the fields relevant for the timestamp
struct GstBuffer {
[...]
/* timestamp */
GstClockTime pts;
GstClockTime dts;
GstClockTime duration;
[...]
};
其中演示时间戳记pts
是相关值.在第二次使用该样本之前将其设置为Gst.CLOCK_TIME_NONE
将解决此问题:
where the presentation timestamp pts
is the relevant value. Setting it to Gst.CLOCK_TIME_NONE
before using the sample for a second time will solve the issue:
# loop over all samples
def samples(app_sink):
samples = []
sample = app_sink.pull_sample()
while sample:
yield sample
sample.get_buffer().pts = Gst.CLOCK_TIME_NONE #unset the pts
samples.append(sample)
sample = app_sink.pull_sample()
print('looping')
for sample in itertools.cycle(samples):
yield sample
这篇关于使用GstApp.AppSrc循环播放Gst.Sample列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!