Gstreamer的音视频同步

(Original: http://blog.csdn.net/maeom/article/details/7729840)

一 概述

Gstreamer的音频视频同步,概括起来是一个比较大的问题,因为在网上可以看到很多音视频同步的办法。这里我们只看最普通的一种。以音频时钟做为参考时钟(要求参考时钟上的时间是线性递增的);生成数据流时依据参考时钟上的时间给每个数据块都打上时间戳(一般包括开始时间和结束时间);在播放时,读取数据上的时间戳,同时参考当前参考时钟上的时间来安排播放(如果数据块上的时间大于参考时钟的时间,则不急于播放,直到参考时钟达到数据块的开始时间;如果数据块上的时间小于参考时钟的时间,则应"尽快"播放或者干脆"丢弃"该数据块,以使得播放赶上播放进度。)

Gstreamer的因视频分离器如下图:

demux element将音频,视频分离后,给各自的解码器进行解码播放。

  1. +-----------+
  2. |Audio|
  3. +--||
  4. /+-----------+
  5. +----------+/
  6. |demux|/
  7. ||\
  8. +----------+\
  9. \+-----------+
  10. +--|Video|
  11. ||
  12. +-----------+

二 提供时钟

默认情况下,是有AudioSink来提供参考时钟的。下面开始代码之旅。

copy
    /*gst-plugins-base-0.10.32/gst-libs/gst/audio/gstbaseaudiosink.c*/
  1. /*默认的情况下是由这个element来提供clock的。*/
  2. #defineDEFAULT_PROVIDE_CLOCKTRUE
  3. staticvoid
  4. gst_base_audio_sink_init(GstBaseAudioSink*baseaudiosink,
  5. GstBaseAudioSinkClass*g_class)
  6. {
  7. baseaudiosink->provide_clock=DEFAULT_PROVIDE_CLOCK
  8. /*这里在clock类里面新建了一个时钟*/
  9. baseaudiosink->provided_clock=gst_audio_clock_new("GstAudioSinkClock",
  10. (GstAudioClockGetTimeFunc)gst_base_audio_sink_get_time,baseaudiosink);
  11. }
  12. /*
  13. *查询是否@sink将提供clock
  14. */
  15. gboolean
  16. gst_base_audio_sink_get_provide_clock(GstBaseAudioSink*sink)
  17. gbooleanresult;
  18. result=sink->provide_clock;
  19. returnresult;
  20. }
  21. /*查询clock的时间
  22. *如果将这里的返回结果变慢,那么视频播放就会变慢。当然视频很音频就不同步了。
  23. */
  24. staticGstClockTime
  25. gst_base_audio_sink_get_time(GstClock*clock,GstBaseAudioSink*sink)
  26. {
  27. result=gst_util_uint64_scale_int(samples,GST_SECOND,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> sink->ringbuffer->spec.rate);
  28. returnresult;
  29. }

三 视频如何同步?

以我实验的视频为例,视频使用的是xvimagesink element它的继承关系如下

copy
    GObject
  1. +----GstObject
  2. +----GstElement
  3. +----GstBaseSink
  4. +----GstVideoSink
  5. +----GstXvImageSink
从element的chain func开始(PS: 为什么从chain开始,参考[Gstreamer初见]).

copy
    *gst-plugins-base/sys/xvimage/xvimagesink.c
  1. *gst-plugins-base/gst-libs/gst/video/gstvideosink.c
  2. *这两个文件里都没有chain函数.
  3. *在gstreamer-0.10.32/libs/gst/base/gstbasesink.c中chain函数为
  4. staticGstFlowReturn
  5. gst_base_sink_chain(GstPad*pad,GstBuffer*buf)
  6. basesink=GST_BASE_SINK(GST_OBJECT_PARENT(pad));
  7. returngst_base_sink_chain_main(basesink,pad,_PR_IS_BUFFER,buf);
  8. gst_base_sink_chain_main(GstBaseSink*basesink,GstPad*pad,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> guint8obj_type,gpointerobj)
  9. result=gst_base_sink_chain_unlocked(basesink,obj_type,obj);
  10. staticGstFlowReturn
  11. gst_base_sink_chain_unlocked(GstBaseSink*basesink,
  12. guint8obj_type,gpointerobj)
  13. result=gst_base_sink_queue_object_unlocked(basesink,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> obj_type,obj,TRUE);
  14. gst_base_sink_queue_object_unlocked(GstBaseSink*basesink,gpointerobj,gbooleanprerollable)
  15. while(G_UNLIKELY(!g_queue_is_empty(q))){
  16. ret=gst_base_sink_render_object(basesink,ot,o);
  17. /*gstreamer-0.10.32/libs/gst/base/gstbasesink.c*/
  18. gst_base_sink_render_object(GstBaseSink*basesink,0); background-color:inherit">/*这里开始做同步,同步成功后,才开始播放*/
  19. ret=
  20. gst_base_sink_do_sync(basesink,sync_obj,&late,&step_end,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> obj_type);
  21. if(G_UNLIKELY(ret!=GST_FLOW_OK))
  22. gotosync_failed;
  23. if(!OBJ_IS_BUFFERLIST(obj_type)){
  24. ret=bclass->render(basesink,buf);
  25. }else{
  26. ret=bclass->render_list(basesink,buflist);
  27. gst_base_sink_do_sync(GstBaseSink*basesink,248)"> GstMiniObject*obj,gboolean*late,gboolean*step_end,guint8obj_type)
  28. status=gst_base_sink_wait_clock(basesink,stime,&jitter);
  29. returnGST_FLOW_OK;
  30. *@time:therunning_timetobereached
  31. *@jitter:(out)(allow-none):thejittertobefilledwithtimediff,orNULL
  32. *
  33. *Thisfunctionwillblockuntil@timeisreached.Itisusuallycalledby
  34. *subclassesthatusetheirowninternalsynchronisation.
  35. GstClockReturn
  36. gst_base_sink_wait_clock(GstBaseSink*sink,GstClockTimetime,248)"> GstClockTimeDiff*jitter)
  37. if(G_UNLIKELY((clock=GST_ELEMENT_CLOCK(sink))==NULL))
  38. gotono_clock;
  39. base_time=GST_ELEMENT_CAST(sink)->base_time;
  40. sink->priv->cached_clock_id=gst_clock_new_single_shot_id(clock,time);
  41. /*这里一直等待到时间*/
  42. ret=gst_clock_id_wait(sink->priv->cached_clock_id,jitter);
  43. returnret;
  44. }

这里同步完成,其实这里还有最后一个小问题,那么就是AudioClock是以什么为时钟的呢。其实就是以声卡的时钟为时钟的。因为声卡有时钟同步功能。所以我们计算一同播放了多少个sample,就可以计算出当前播放了多长的时间。 So.

END

相关文章

什么是设计模式一套被反复使用、多数人知晓的、经过分类编目...
单一职责原则定义(Single Responsibility Principle,SRP)...
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强...
适配器模式将一个类的接口转换成客户期望的另一个接口,使得...
策略模式定义了一系列算法族,并封装在类中,它们之间可以互...
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,...