[Gstreamer] GstBaseSink 及其同步逻辑

前言:

GstBaseSink 继承自 GstElement , 提供了 preroll,时钟同步,state change 处理,query 和 pad 模式激活流程 等功能,子类只需要再理解GstBaseSink属性使用的基础上实现一些虚函数(共18个)。

GstBaseSink的属性:

max-lateness 
“max-lateness” gint64

Flags :Read / Write

Default : -1 (表示无限大,只要开启sync模式就不会被drop)

单位 : 纳秒

简介:丢帧容忍值

解析:时钟同步功能相关,当到达的 GstBuffer 中的 pts + duration 小于 当前时钟的值时,说明这个 GstBuffer 到达 Sink 的时间太晚了,理论上会被丢弃而不会进入 render 函数处理 。但是GstBaseSink 提供一个容忍时间,如果  pts + duration 距离 当前时间的差值 在这个容忍时间内,则说明当前 GstBuffer 还是 “可以抢救一下的” , 因此会被放行进入 render 虚函数。

如上图,当前时钟时间减去 max_lateness 的红色区域长度 如果过能够覆盖到 GstBuffer.pts ~ GstBuffer.pts+GstBuffer.duration 的绿色区域,则说明 GstBuffer 落在了容忍区间内,因此是可以破例 render 而不被 drop 的。

此属性必须和 sync = true 一起使用。

提前到达的 GstBuffer 不会被 drop。


ts-offset 
“ts-offset” gint64

Flags : Read / Wirte

Default :0

单位:纳秒

简介:render时机动态补偿

解析:这个值同样用于同步场景,但是不是控制是否 drop 的,而是控制 render 的时机的,正值代表滞后于预先约定的时间点调用 render,负值表示提前于预先约定的时间点调用 render。相当于是一个手动的 render 补偿。预先约定的时间为 GstBuffer 中的 pts 。


sync 
“sync” gboolean

Flags : Read / Write

Default :True

简介:是否开启时钟同步

解析:此属性控制是否开启时钟同步,如果开启,则收到的GstBuffer如果不满足时钟同步条件则会被 drop 而失去 render 的机会。具体的同步条件由多种条件决定,上面的max_lateness就是其中之一。

GstBaseSink 虚函数原语及 default 实现:

get_times 
get_times (GstBaseSink * sink,
           GstBuffer * buffer,
           GstClockTime * start,
           GstClockTime * end)

Called to get the start and end times for synchronising the passed buffer to the clock

Parameters:

sink – 当前element实例

buffer – 待处理的 GstBuffer

start – 输出,根据 GstBuffer 的 pts 和 duration 计算出来的时间区间的开始时刻

end – 输出,根据 GstBuffer 的 pts 和 duration 计算出来的时间区间的结束时刻

原语:根据GstBuffer的信息,计算出当前GstBuffer落于哪一个时间段内,起止时间为 start 和 end。

default实现:区间为 [ GstBuffer.pts , GstBuffer.pts + GstBuffer.duration ]


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
以下是一个简单的用 GStreamer 实现音视频同步的示例代码: ```python import gi gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject GObject.threads_init() Gst.init(None) player = Gst.ElementFactory.make("playbin", "player") player.set_property("uri", "file:///path/to/media/file") audio_sink = Gst.ElementFactory.make("autoaudiosink", "audio_sink") video_sink = Gst.ElementFactory.make("autovideosink", "video_sink") player.set_property("audio-sink", audio_sink) player.set_property("video-sink", video_sink) bus = player.get_bus() def on_message(bus, message): t = message.type if t == Gst.MessageType.EOS: player.set_state(Gst.State.NULL) loop.quit() elif t == Gst.MessageType.ERROR: err, debug = message.parse_error() print ("Error: %s" % err, debug) player.set_state(Gst.State.NULL) loop.quit() elif t == Gst.MessageType.STATE_CHANGED: if message.src == player: old_state, new_state, pending_state = message.parse_state_changed() if new_state == Gst.State.PLAYING: # Get the current time when playing starts query = Gst.Query.new_seeking(Gst.Format.TIME) if player.query(query): _, start, _ = query.parse_seeking() global start_time start_time = start elif t == Gst.MessageType.QOS: # Get the running time of the pipeline query = Gst.Query.new_position(Gst.Format.TIME) if player.query(query): _, running_time = query.parse_position() running_time += start_time # Get the running time of the last buffer struct = message.get_structure() _, running_time_buffer, _ = struct.get("running-time") running_time_buffer += start_time # Calculate the difference between the two running times diff = running_time - running_time_buffer # If the difference is too big, seek to the correct position if abs(diff) > Gst.SECOND / 10: player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, running_time) bus.add_signal_watch() bus.connect("message", on_message) # Start playing player.set_state(Gst.State.PLAYING) # Start the main loop loop = GObject.MainLoop() loop.run() ``` 此示例中使用了 `autoaudiosink` 和 `autovideosink` 作为音视频的输出,你还可以将其替换为其他的 sink。在收到 QOS 消息时,获取管道的当前时间以及最后一个缓冲区的运行时间,并在两个运行时间之间计算差异,如果差异太大,则使用 `seek_simple()` 函数跳转到正确的位置,以保持音视频同步
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值