Gstreamer的音视频同步

前端之家收集整理的这篇文章主要介绍了Gstreamer的音视频同步前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

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

一 概述

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

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

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

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

二 提供时钟

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

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

@H_403_258@三 视频如何同步?

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

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

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

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

END

猜你在找的设计模式相关文章