Position tracking and seeking
到目前为止,我们已经了解了如何创建pipeline 来进行媒体处理以及如何使其运行。大多数应用程序开发人员会对向用户提供有关媒体进度的反馈感兴趣。例如,媒体播放器会想要显示一个显示歌曲进度的滑块,通常还有一个指示流长度的标签。转码应用程序需要显示任务完成百分比的进度条。 GStreamer 内置支持使用称为querying的概念来完成所有这些工作。由于seeking 非常相似,因此也将在此处讨论。seeking 是使用事件的概念来完成的。
查询:获取流的位置或长度
查询定义为请求与进度跟踪相关的特定流属性。这包括获取流的时长(如果可用)或获取当前位置。可以以各种格式检索这些流属性,例如时间、音频采样、视频帧或字节。最常用的函数是 gst_element_query (),尽管也提供了一些方便的封装(例如 gst_element_query_position () 和 gst_element_query_duration ())。您通常可以直接查询pipeline,它会为您计算内部细节,例如要查询的element。
在内部,查询将被发送到sinks,然后向后 “转发(dispatched)”,直到一个element 可以处理它;该结果将被发送回函数调用者。通常情况下,这就是demuxer,尽管有实时源(live sources)(来自网络摄像头),但它本身就是源。
#include <gst/gst.h>
static gboolean
cb_print_position (GstElement *pipeline)
{
gint64 pos, len;
if (gst_element_query_position (pipeline, GST_FORMAT_TIME, &pos)
&& gst_element_query_duration (pipeline, GST_FORMAT_TIME, &len)) {
g_print ("Time: %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
GST_TIME_ARGS (pos), GST_TIME_ARGS (len));
}
/* call me again */
return TRUE;
}
gint
main (gint argc,
gchar *argv[])
{
GstElement *pipeline;
[..]
/* run pipeline */
g_timeout_add (200, (GSourceFunc) cb_print_position, pipeline);
g_main_loop_run (loop);
[..]
}
事件:seeking(以及更多)
事件的工作原理与查询非常相似。例如,dispatching对于事件的工作原理完全相同(并且也有相同的限制),并且它们可以类似地发送到顶层pipeline ,它会为你解决所有问题。尽管应用程序和elements 可以通过事件进行交互的方式还有很多,但我们在这里只重点seeking。这是使用seek-event完成的。一个seek-event包含一个播放速率、一个seek 的偏移格式(它是要遵循的偏移单位,例如时间、音频采样、视频帧或字节),一组可选的与seeking-related相关的标志(例如,内部缓冲区是否应该被刷新),一种seek 方法(指示相对于给定的偏移量)和 seek 偏移量。第一个偏移量 (cur) 是要寻找的新位置,而第二个偏移量 (stop) 是可选的,它指定流应该停止的位置。通常只指定 GST_SEEK_TYPE_NONE 和 -1 作为 end_method 和 end offset 就可以了。seek 的行为也包含在 gst_element_seek() 中。
static void
seek_to_time (GstElement *pipeline,
gint64 time_nanoseconds)
{
if (!gst_element_seek (pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
GST_SEEK_TYPE_SET, time_nanoseconds,
GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
g_print ("Seek failed!\n");
}
}
当pipeline 处于 PAUSED 或 PLAYING 状态时,应该使用 GST_SEEK_FLAG_FLUSH 进行搜索。pipeline 将自动进入预卷状态,直到查找后的新数据将导致pipeline再次预卷。pipeline预卷后,它将返回到执行查找时所处的状态(暂停或播放)。您可以使用 gst_element_get_state() 等待(阻塞)完成 或者等待ASYNC_DONE 消息出现在总线上。
没有 GST_SEEK_FLAG_FLUSH 标志的seek应该只在pipeline处于 PLAYING 状态时进行。在 PAUSED 状态下执行non-flushing seek可能会死锁,因为pipeline的流线程可能在sinks中被阻塞。
重要的是要认识到,在函数 gst_element_seek () 调用完成并返回时,seek不会立即执行。根据所涉及的特定element,实际查找可能会稍后在另一个线程(流线程)中完成,并且可能需要很短的时间,直到来自新查找位置的缓冲区到达 downstream elements ,例如sinks (如果 是 non-flushing 的seek 那么它可能需要更长的时间)。
可以在短时间内进行多次seeks,例如对滑块移动的直接响应。在seek之后,pipeline将在内部暂停(如果它正在播放),位置将在内部重新设置,demuxers 和解码器decoders 从新位置开始解码,这将一直持续到所有sinks 再次有数据。如果它原来是在播放,它也会被设置为再次播放。由于新位置在视频输出中立即可用,因此即使您的pipeline未处于播放状态,您也会看到最新帧。