GStreamer基础教程07 - 播放速率控制

 

摘要

  在常见的媒体播放器中,通常可以看到快进,快退,慢放等功能,这部分功能被称为“特技模式(Trick Mode)”,这些模式有个共同点:都通过修改播放的速率来达到相应的目的。 本文将介绍如何通过GStreamer去实现快进,快退,慢放以及单帧播放。

 

GStreamer Seek与Step事件

  快进(Fast-Forward),快退(Fast-Rewind)和慢放(Slow-Motion)都是通过修改播放的速率来达到相应的目的。在GStreamer中,将1倍速作为正常的播放速率,将大于1倍速的2倍,4倍,8倍等倍速称为快进,慢放则是播放速率的绝对值小于1倍速,当播放速率小于0时,则进行倒放。
在GStreamer中,我们通过seek与step事件来控制Element的播放速率及区域。Step事件允许跳过指定的区域并设置后续的播放速率(此速率必须大于0)。Seek事件允许跳转到播放文件中的的任何位置,并且播放速率可以大于0或小于0.
播放时间控制中,我们使用gst_element_seek_simple 来快速的跳转到指定的位置,此函数是对seek事件的封装。实际使用时,我们首先需要构造一个seek event,设置seek的绝对起始位置和停止位置,停止位置可以设置为0,这样会执行seek的播放速率直到结束。同时可以支持按buffer的方式进行seek,以及设置不同的标志指定seek的行为。
Step事件相较于Seek事件需要更少的参数,更易用于修改播放速率,但是不够灵活。Step事件只会作用于最终的sink,Seek事件则可以作用于Pipeline中所有的Element。Step操作的效率高于Seek。
在GStreamer中,单帧播放(Frame Stepping)与快进相同,也是通过事件实现。单帧播放通常在暂停的状态下,构造并发送step event每次播放一帧。
需要注意的是,seek event需要直接作用于sink element(eg: audio sink或video sink),如果直接将seek event作用于Pipeline,Pipeline会自动将事件转发给所有的sink,如果有多个sink,就会造成多次seek。通常是先获取Pipeline中的video-sink或audio-sink,然后发送seek event到指定的sink,完成seek的操作。 Seek时间的构造及发送示例如下:

复制代码
   GstEvent *event;    gboolean result;    ...    // construct a seek event to play the media from second 2 to 5, flush    // the pipeline to decrease latency.   event = gst_event_new_seek (1.0,       GST_FORMAT_TIME,       GST_SEEK_FLAG_FLUSH,       GST_SEEK_TYPE_SET, 2 * GST_SECOND,       GST_SEEK_TYPE_SET, 5 * GST_SECOND);    ...    result = gst_element_send_event (video_sink, event);    if (!result)      g_warning ("seek failed");    ...
复制代码

示例代码

下面通过一个完整的示例,来查看GStreamer是如何通过seek和step达到相应的播放速度。

复制代码
#include <string.h> #include <stdio.h> #include <gst/gst.h>  typedef struct _CustomData {   GstElement *pipeline;   GstElement *video_sink;   GMainLoop *loop;    gboolean playing;             /* Playing or Paused */   gdouble rate;                 /* Current playback rate (can be negative) */ } CustomData;  /* Send seek event to change rate */static void send_seek_event (CustomData * data) {   gint64 position;   GstEvent *seek_event;    /* Obtain the current position, needed for the seek event */  if (!gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &position)) {     g_printerr ("Unable to retrieve current position.\n");     return;   }    /* Create the seek event */  if (data->rate > 0) {     seek_event =         gst_event_new_seek (data->rate, GST_FORMAT_TIME,         GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,         position, GST_SEEK_TYPE_END, 0);   } else {     seek_event =         gst_event_new_seek (data->rate, GST_FORMAT_TIME,         GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, 0,         GST_SEEK_TYPE_SET, position);   }    if (data->video_sink == NULL) {     /* If we have not done so, obtain the sink through which we will send the seek events */     g_object_get (data->pipeline, "video-sin
                    
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信