Position tracking and seeking
到目前为止,我们已经了解了如何创建管道来进行媒体处理以及如何使其运行。大多数应用程序开发人员会对向用户提供有关媒体进度的反馈感兴趣。例如,媒体播放器会想要显示一个显示歌曲进度的滑块,通常还有一个指示流长度的标签。转码应用程序需要显示任务完成百分比的进度条。GStreamer 内置支持使用称为querying的概念来完成所有这些操作。由于查找非常相似,因此也将在此处讨论。Seeking是使用event的概念来完成的。
Querying: 查询流的位置或长度
查询定义为请求与进度跟踪相关的特定流属性。这包括获取流的长度(如果可用)或获取当前位置。可以以各种格式检索这些流属性,例如时间、音频样本、视频帧或字节。最常用的函数是 gst_element_query ()
,尽管也提供了一些方便的包装器(例如gst_element_query_position ()
和 gst_element_query_duration ()
)。您通常可以直接查询管道,它会为您找出内部详细信息,例如要查询的元素。
在内部,查询将被发送到接收器,然后向后“分派”,直到一个元素可以处理它;该结果将被发送回函数调用者。通常,那是多路分配器,尽管使用实时源(来自网络摄像头),但它是源本身。
#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);
[..]
}
Events: seeking (and more)
事件的工作方式与查询非常相似。例如,调度对于事件的工作方式完全相同(并且也有相同的限制),它们可以类似地发送到顶级管道,它会为您解决所有问题。尽管应用程序和元素可以通过事件进行交互的方式还有很多,但我们在这里只重点关注seeking。这是使用seek-event完成的.一个seek-event包含一个播放速率、一个seek偏移格式(要遵循的偏移量的单位,例如时间、音频样本、视频帧或字节),可选的一组与seek相关的标志(例如,内部缓冲区是否应该被刷新),一种查找方法(指示相对于给定的偏移量)和查找偏移量。第一个偏移量 (cur) 是要寻找的新位置,而第二个偏移量(停止)是可选的,并指定流应该停止的位置。通常只指定 GST_SEEK_TYPE_NONE 和 -1 作为 end_method 和 end offset 就可以了。搜索的行为也包含在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");
}
}
当管道处于 PAUSED 或 PLAYING 状态时,应该使用 GST_SEEK_FLAG_FLUSH 进行搜索。管道将自动进入预卷状态,直到查找后的新数据将导致管道再次预卷。管道预卷后,它将返回到执行查找时所处的状态(暂停或播放)。您可以等待(阻塞)寻找完成, gst_element_get_state()
或者等待 ASYNC_DONE 消息出现在总线上。
没有 GST_SEEK_FLAG_FLUSH 的搜索应该只在管道处于 PLAYING 状态时进行。在 PAUSED 状态下执行非刷新查找可能会死锁,因为管道流线程可能在接收器中被阻塞。
重要的是要认识到,从函数gst_element_seek ()
返回时它们完成的意义上说,查找不会立即发生。根据所涉及的特定元素,实际查找可能稍后在另一个线程(流线程)中完成,并且可能需要很短的时间,直到来自新查找位置的缓冲区到达下游元素,例如接收器(如果查找不是-flushing 那么它可能需要更长的时间)。
可以在短时间内进行多次搜索,例如对滑块移动的直接响应。在查找之后,管道将在内部暂停(如果它正在播放),位置将在内部重新设置,分路器和解码器将从新位置开始解码,这将继续直到所有接收器再次有数据。如果它原来是在播放,它也会被设置为再次播放。由于新位置在视频输出中立即可用,因此即使您的管道未处于播放状态,您也会看到新帧。