GstPipeline在从PAUSED转成PLAYING的时候,会select一个clock并计算出basetime,这两样东西都会赋给pipeline中每个element。那这个basetime每次是怎么计算的呢?
原来认为这个basetime就是当前的clock time,但是后来发现不对。比如:在播放了2秒的时候PAUSE,等了3秒后再PLAY,此时如果这个basetime是当前时间的话,那就是5秒时刻,此时继续播放的话,会发现传过来的buffer中的timestamp是从第3秒开始的,不是从0秒开始的,因为上次暂停的时候是在2秒的时间点上。所以如果此时basetime是5秒的话,那么sink组件就要到8秒以后再播放这些buffer(因为buffer的timestamp是从3秒开始的)。
于是回到gst_pipeline_change_state函数研究,发现其实很简单:
base_time = start_time - stream_time + delay;
start_time就是当前clock的时间,stream_time就是已经播放的时间(注意和running_time不一样,running_time是变成PLAYING状态后流逝的时间,而stream_time是变成PLAYING状态后sink实际播放的时间,所以stream_time一般就直接用在POSITION的QUERY上,作为POSITION直接返回的(当然,这里还有一些逻辑,不是直接返回stream time的,详情参考gst_base_sink_get_position函数)),delay是GstPipeline的一个property,可以设置的。
这样一来就对了,还是上面的例子,先播了2秒,所以stream_time是2秒,等了3秒,到第5秒的时候play,所以start_time是5,这样算下来base_time就是3秒(如果delay设置是0的话,默认值就是0),所以接下来的buffer timestamp是3秒开始的,这样就正好接上播放了。
如果是第一次播放,之前没有PAUSE过,那么上面的公式很清楚,此时basetime就正好是start time了。
原来认为这个basetime就是当前的clock time,但是后来发现不对。比如:在播放了2秒的时候PAUSE,等了3秒后再PLAY,此时如果这个basetime是当前时间的话,那就是5秒时刻,此时继续播放的话,会发现传过来的buffer中的timestamp是从第3秒开始的,不是从0秒开始的,因为上次暂停的时候是在2秒的时间点上。所以如果此时basetime是5秒的话,那么sink组件就要到8秒以后再播放这些buffer(因为buffer的timestamp是从3秒开始的)。
于是回到gst_pipeline_change_state函数研究,发现其实很简单:
base_time = start_time - stream_time + delay;
start_time就是当前clock的时间,stream_time就是已经播放的时间(注意和running_time不一样,running_time是变成PLAYING状态后流逝的时间,而stream_time是变成PLAYING状态后sink实际播放的时间,所以stream_time一般就直接用在POSITION的QUERY上,作为POSITION直接返回的(当然,这里还有一些逻辑,不是直接返回stream time的,详情参考gst_base_sink_get_position函数)),delay是GstPipeline的一个property,可以设置的。
这样一来就对了,还是上面的例子,先播了2秒,所以stream_time是2秒,等了3秒,到第5秒的时候play,所以start_time是5,这样算下来base_time就是3秒(如果delay设置是0的话,默认值就是0),所以接下来的buffer timestamp是3秒开始的,这样就正好接上播放了。
如果是第一次播放,之前没有PAUSE过,那么上面的公式很清楚,此时basetime就正好是start time了。