循环播放 Gst.Sample 和 GstApp.AppSrc 的列表
Looping playback of a list of Gst.Sample with GstApp.AppSrc
我正在尝试使用 GStreamer 编写一个简单的音乐播放器。我想播放任意音乐文件 ABS_FILE_PATH
,存储样本用于其他目的,然后在到达流的原始结尾后无限期地循环播放这些样本。
现在可以正常播放音乐,直到播放完曲目的最后一个样本后不久。大多数时候只是一片寂静,但有时会有一两个声音样本表明曲目刚刚再次开始播放。终端输出也是如此。它表明,在开始循环后的几个样本中,need-data
信号比之前更频繁地发送。
我已经使用 fakesink
来转储数据,这似乎工作得很好。数据只是循环播放,就像预期的那样。
那么这里发生了什么?为什么样本不播放第二次(第三次、第四次……)?我 运行 没主意了。
下面我添加了一个没有任何 UI 的最小示例,但存在同样的问题:
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
我在 of thiagoss 的帮助下找到了一个可行的解决方案。
The GstBuffer struct documentation 列出与时间戳相关的所有字段
struct GstBuffer {
[...]
/* timestamp */
GstClockTime pts;
GstClockTime dts;
GstClockTime duration;
[...]
};
其中演示时间戳 pts
是相关值。在第二次使用示例之前将其设置为 Gst.CLOCK_TIME_NONE
将解决问题:
# 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
我正在尝试使用 GStreamer 编写一个简单的音乐播放器。我想播放任意音乐文件 ABS_FILE_PATH
,存储样本用于其他目的,然后在到达流的原始结尾后无限期地循环播放这些样本。
现在可以正常播放音乐,直到播放完曲目的最后一个样本后不久。大多数时候只是一片寂静,但有时会有一两个声音样本表明曲目刚刚再次开始播放。终端输出也是如此。它表明,在开始循环后的几个样本中,need-data
信号比之前更频繁地发送。
我已经使用 fakesink
来转储数据,这似乎工作得很好。数据只是循环播放,就像预期的那样。
那么这里发生了什么?为什么样本不播放第二次(第三次、第四次……)?我 运行 没主意了。
下面我添加了一个没有任何 UI 的最小示例,但存在同样的问题:
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
我在
The GstBuffer struct documentation 列出与时间戳相关的所有字段
struct GstBuffer {
[...]
/* timestamp */
GstClockTime pts;
GstClockTime dts;
GstClockTime duration;
[...]
};
其中演示时间戳 pts
是相关值。在第二次使用示例之前将其设置为 Gst.CLOCK_TIME_NONE
将解决问题:
# 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