NuPlayer介绍

来源:互联网 发布:淘宝网保障基金 编辑:程序博客网 时间:2024/05/22 07:05
<div id="article_content" class="article_content tracking-ad" data-mod="popu_307" data-dsm="post"><h2 id="简介" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; line-height:26px"><a name="t0" target="_blank"></a>简介</h2><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">Android2.3时引入流媒体框架,而流媒体框架的核心是NuPlayer。Android4.0之后HttpLive和RTSP协议开始使用NuPlayer播放器,Android5.0(L版本)之后本地播放也开始使用NuPlayer播放器。 <br><img src="http://img.blog.csdn.net/20151011114713862" alt="类图" title="" style="border:none; max-width:100%"></p><h4 id="视频是如何播放的" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t1" target="_blank"></a><a target="_blank" name="t1" style="color:rgb(51,102,153)"></a><a target="_blank" name="t1" style="color:rgb(51,102,153)"></a>视频是如何播放的</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><img src="http://img.blog.csdn.net/20151011114848979" alt="这里写图片描述" title="" style="border:none; max-width:100%"><br>DataSource有两个概念:</p><ol style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><li>上面框图中的DataSourceInput(或者直接叫DataSource)指的是单纯的数据输入(未demux的)。</li><li>在后文中setDataSource中DataSource指的是从数据输入到demux输出的一个过程(即图中最外层的DataSource)。</li></ol><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">VideoTrack与AudioTrack指的是Extractor(即demux)的两个通道,从这里输出的分别就是单纯的解复用后的Video和Audio流。再经过Decoder后输出的就是音、视频的输出了:</p><ul style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><li>VideoRenderer + Surface即视频的输出;</li><li>AudioSink即音频的输出;</li></ul><h4 id="nuplayerdrivercpp" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t2" target="_blank"></a><a target="_blank" name="t2" style="color:rgb(51,102,153)"></a><a target="_blank" name="t2" style="color:rgb(51,102,153)"></a>NuPlayerDriver.cpp</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><img src="http://img.blog.csdn.net/20151011115238590" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="ahandle机制" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t3" target="_blank"></a><a target="_blank" name="t3" style="color:rgb(51,102,153)"></a><a target="_blank" name="t3" style="color:rgb(51,102,153)"></a>Ahandle机制</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">初始化NuPlayer对象,并进入NuPlayer播放流程,其实NuPlayer实现的是Ahandle机制: <br><img src="http://img.blog.csdn.net/20151011115342454" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011115354063" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><ul style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><li>Android5.0之前,StageFright架构使用的传递消息机制是TimedEventQueue模型</li><li>Android升级到5.0之后,NuPlayer使用的是AHandler消息机制,类似于Handler <br><img src="http://img.blog.csdn.net/20151011115509794" alt="这里写图片描述" title="" style="border:none; max-width:100%"></li></ul><h4 id="nuplayersetdatasourceasync" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t4" target="_blank"></a><a target="_blank" name="t4" style="color:rgb(51,102,153)"></a><a target="_blank" name="t4" style="color:rgb(51,102,153)"></a>NuPlayer::setDataSourceAsync</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">NuPlayer获取DataSource通过URI的前缀判断媒体类型,比如http、rtsp,还是本地播放,然后创建相应的DataSource,走入相应流程。根据URI创建相应的DataSource,再进一步的利用DataSource创建MediaExtractor做A/V分离。 <br><img src="http://img.blog.csdn.net/20151011115613051" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="nuplayeronmessagereceived" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t5" target="_blank"></a><a target="_blank" name="t5" style="color:rgb(51,102,153)"></a><a target="_blank" name="t5" style="color:rgb(51,102,153)"></a>NuPlayer::onMessageReceived</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">OnMessageReceived是Nuplayer的核心部分,大部分消息的实现均在OnMessageReceived中完成 <br><img src="http://img.blog.csdn.net/20151011115817970" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br>环境及相应DataSource都准备好以后,上层发送start开始播放流程以后,开始创建解码器 <br><img src="http://img.blog.csdn.net/20151011115905366" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011115914762" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br>创建解码器 <br><img src="http://img.blog.csdn.net/20151011115959326" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011120012339" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="nuplayerdecodercpp" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t6" target="_blank"></a><a target="_blank" name="t6" style="color:rgb(51,102,153)"></a><a target="_blank" name="t6" style="color:rgb(51,102,153)"></a>NuPlayerDecoder.cpp</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><img src="http://img.blog.csdn.net/20151011120056782" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="mediacodeccreatebytype" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t7" target="_blank"></a><a target="_blank" name="t7" style="color:rgb(51,102,153)"></a><a target="_blank" name="t7" style="color:rgb(51,102,153)"></a>MediaCodec::CreateByType</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">进入MediaCodec.cpp <br><img src="http://img.blog.csdn.net/20151011120137787" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br>进入init中 <br><img src="http://img.blog.csdn.net/20151011122840057" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011122850617" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="mediacodeconmessagereceived" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t8" target="_blank"></a><a target="_blank" name="t8" style="color:rgb(51,102,153)"></a><a target="_blank" name="t8" style="color:rgb(51,102,153)"></a>MediaCodec::onMessageReceived</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><img src="http://img.blog.csdn.net/20151011122948929" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011122958731" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="acodecinitiateallocatecomponent" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t9" target="_blank"></a><a target="_blank" name="t9" style="color:rgb(51,102,153)"></a><a target="_blank" name="t9" style="color:rgb(51,102,153)"></a>ACodec::initiateAllocateComponent</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><img src="http://img.blog.csdn.net/20151011123045492" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011123055805" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="acodeconallocatecomponet" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t10" target="_blank"></a><a target="_blank" name="t10" style="color:rgb(51,102,153)"></a><a target="_blank" name="t10" style="color:rgb(51,102,153)"></a>ACodec::onAllocateComponet</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><img src="http://img.blog.csdn.net/20151011123145516" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011123157704" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="omxmasteraddplugin" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t11" target="_blank"></a><a target="_blank" name="t11" style="color:rgb(51,102,153)"></a><a target="_blank" name="t11" style="color:rgb(51,102,153)"></a>OMXMaster::addPlugin</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">OMX的创建干了两件事,第一,初始化OMXMaster加载第三方解码器;第二,初始化节点数,为分配正在可用节点。 <br><img src="http://img.blog.csdn.net/20151011123249708" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="音视频同步" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t12" target="_blank"></a><a target="_blank" name="t12" style="color:rgb(51,102,153)"></a><a target="_blank" name="t12" style="color:rgb(51,102,153)"></a>音视频同步</h4><ul style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><li>在NuPlayer框架中,音视频同步的工作是由Renderer来完成的,而在StageFright框架, Render是显示用的。</li><li>NuPlayer框架中,音视频同步的策略是音/视频往后delay,被动同步,而不会主动seek;简单讲就是如果视频来早了会等一下音频,如果视频来晚了会通过丢帧机制同步,连续丢帧直到音视频同步上为止, <br>因为音频太敏感,所以只视频做此处理,而音频不做这样的处理,总之策略就是:视频早等晚丢。</li><li>Stagefright框架中,音视频同步的策略是,视频向前向后双向同步,too late时video会主动往前seek;too early的时候video会delay</li><li>在NuPlayer的start步骤中,新建了一个Renderer的循环线程mRendererLooper,并且把mRenderer作为这个循环线程的Handler,在这个线程内对音视频数据进行同步、送显等操作 <br><img src="http://img.blog.csdn.net/20151011123522100" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011123535076" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011123548670" alt="这里写图片描述" title="" style="border:none; max-width:100%"></li></ul><h4 id="nuplayerrenderbuffer" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t13" target="_blank"></a><a target="_blank" name="t13" style="color:rgb(51,102,153)"></a><a target="_blank" name="t13" style="color:rgb(51,102,153)"></a>NuPlayer::renderBuffer</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">当收到解码器kWhatDrainThisBuffer消息时,NuPlayer会调用到renderBuffer函数,renderBuffer直接调用mRenderer中的queueBuffer函数。 <br><img src="http://img.blog.csdn.net/20151011123718631" alt="这里写图片描述" title="" style="border:none; max-width:100%"><br><img src="http://img.blog.csdn.net/20151011123730828" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011123741817" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="nuplayerrendererqueuebuffer" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t14" target="_blank"></a><a target="_blank" name="t14" style="color:rgb(51,102,153)"></a><a target="_blank" name="t14" style="color:rgb(51,102,153)"></a>NuPlayerRenderer::queueBuffer</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">queueBuffer主要发送kWhatQueueBuffer消息,并在接收到kWhatQueueBuffer消息后调用onQueueBuffer函数,函数onQueueBuffer中对于音频和视频数据队列进行push_back和postDrainQueue操作,push_back就是往renderer中的数据队列中存放数据, postDrainQueue就是从renderer的数据队列中取数据,往外送显,因此可以看出renderer中的数据队列实际上只是个中转站,就是为了实现音视频同步。</p><h4 id="nuplayerrendereronqueuebuffer" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t15" target="_blank"></a><a target="_blank" name="t15" style="color:rgb(51,102,153)"></a><a target="_blank" name="t15" style="color:rgb(51,102,153)"></a>NuPlayerRenderer::onQueueBuffer</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><img src="http://img.blog.csdn.net/20151011123950768" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011124004287" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011124015676" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011124025730" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="nuplayerrendererpostdrainvideoqueue" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t16" target="_blank"></a><a target="_blank" name="t16" style="color:rgb(51,102,153)"></a><a target="_blank" name="t16" style="color:rgb(51,102,153)"></a>NuPlayerRenderer::postDrainVideoQueue</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">音视频同步的函数postDrainVideoQueue()(视频early情况) <br><img src="http://img.blog.csdn.net/20151011124157260" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011124208061" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011124218506" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011124228813" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br>判断repost的时间是10ms,还是500ms,根据下面分支判断(上一个时间戳序号减去当前时间戳序号) 。mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0,一般情况下这个值均小于0,所以NuPlayer里面一般repost时间为500ms。 <br><img src="http://img.blog.csdn.net/20151011124320833" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="nuplayerrendererpostdrainvideoqueue-1" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t17" target="_blank"></a><a target="_blank" name="t17" style="color:rgb(51,102,153)"></a><a target="_blank" name="t17" style="color:rgb(51,102,153)"></a>NuPlayerRenderer::postDrainVideoQueue</h4><h5 id="delayus的计算" style="color:rgb(51,51,51); font-family:Arial; line-height:26px"><a name="t18" target="_blank"></a><a target="_blank" name="t18" style="color:rgb(51,102,153)"></a><a target="_blank" name="t18" style="color:rgb(51,102,153)"></a>DelayUs的计算:</h5><blockquote style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><p>delayUs = realTimeUs – nowUs <br>realTimeUs = (mediaTimeUs - currentPositionUs) + nowUs <br>currentPositionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs <br>==》realTimeUs = mediaTimeUs – mAnchorTimeMediaUs + <br>mAnchorTimeRealUs</p></blockquote><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">mediaTimeUs为传入的时间, mAnchorTimeMediaUs为音频上一帧的时间戳,mAnchorTimeRealUs为播放的起锚时间戳,前2者相减获取当前播放的时间长度,再加上起锚时间从而得到当前的系统时间戳。 <br>nowUs是当前时间,通过函数GetNowUs()获取,每次重新获取的时间都不一样,若不重新获取,一直沿用前面获取的时间值。 <br>如果现在的时间点比预计要播放的时间点提前了500ms以上,就要等,则延时10ms再发送kWhatPostDrainVideoQueue消息,接收到这个消息后继续走回postDrainVideoQueue函数中,即做了10ms的等待。 <br><img src="http://img.blog.csdn.net/20151011124551137" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br>音视频同步的函数onDrainVideoQueue()(视频late情况) <br><img src="http://img.blog.csdn.net/20151011124646943" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011124657333" alt="这里写图片描述" title="" style="border:none; max-width:100%"> <br><img src="http://img.blog.csdn.net/20151011124709441" alt="这里写图片描述" title="" style="border:none; max-width:100%"><br>Too Late用来标记是否视频数据现在播放的时间比预期播放的时间晚40ms以上,如果超过40ms,说明现在播放这段数据的时间太晚,要是继续播放这段数据就会主观感觉到视频画面滞后,所以丢弃这段视频数据。</p><h2 id="流媒体简介" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; line-height:26px"><a name="t19" target="_blank"></a><a target="_blank" name="t19" style="color:rgb(51,102,153)"></a><a target="_blank" name="t19" style="color:rgb(51,102,153)"></a>流媒体简介</h2><ul style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><li>流媒体是Android2.3时引入的,流媒体框架的核心是NuPlayer,目前流媒体的协议类型主要有:HttpLive、RTSP、HTTP</li><li>HttpLive和RTSP协议在Android4.0之后开始使用NuPlayer播放器 <br><img src="http://img.blog.csdn.net/20151011125531085" alt="这里写图片描述" title="" style="border:none; max-width:100%"></li><li>RTSP是由Real network 和Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层实时流协议</li><li>用于远程建立和控制多媒体流,可以同时进行多个流</li><li>多媒体流的传输控制部分由RTP/RTCP负责,协议消息的承载可以是TCP和UDP</li><li>语法上和HTTP相似,但它是有状态协议(HTTP是无状态协议)</li></ul><h4 id="rtsp" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t20" target="_blank"></a><a target="_blank" name="t20" style="color:rgb(51,102,153)"></a><a target="_blank" name="t20" style="color:rgb(51,102,153)"></a><strong>RTSP</strong></h4><ul style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><li>RTP(Real-time Transport Protocol) <br>RTP是用于Internet上针对多媒体数据流的一种传输层协议,它详细说明了在互联网上传递音频和视频的标准数据包格式</li><li>RTCP (Real-time Transport Control Protocol <br>) RTCP是实时传输协议(RTP)的一个姐妹协议,RTCP为RTP媒体流提供信道外(out-of-band)控制,RTCP本身并不传输数据,但和RTP一起协作将多媒体数据打包和发送,RTCP定期在流多媒体会话参加者之间传输控制数据</li></ul><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">简单总结:RTSP发起、终结流媒体,RTP媒体数据载体 、RTCP对RTP进行控制、同步 <br><img src="http://img.blog.csdn.net/20151011125903107" alt="这里写图片描述" title="" style="border:none; max-width:100%"></p><h4 id="httplive" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t21" target="_blank"></a><a target="_blank" name="t21" style="color:rgb(51,102,153)"></a><a target="_blank" name="t21" style="color:rgb(51,102,153)"></a>HttpLive</h4><ul style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><li>HTTPLiveStreaming(缩写是HLS) <br>是一个由苹果公司提出的基于HTTP的流媒体网络传输协议,它允许内容提供者通过普通Web服务器向上述客户端提供接近实时的音视频流媒体服务,包括直播和点播;HLS支持将同一节目编码为不同码率的多个替换流,客户端软件可以根据网络带宽的变化在这些不同码率的替换流之间进行智能切换</li><li>M3U8码流 <br>M3U8文件是HTTPLive服务器在创建视频源的时候,会创建一个包含各媒体文件引用的索引文件,索引文件被保存为.M3U8文件,这是保存MP3播放列表的.m3u格式的一种扩展 <br><img src="http://img.blog.csdn.net/20151011130016542" alt="这里写图片描述" title="" style="border:none; max-width:100%"></li></ul><h4 id="媒体库相关代码路径" style="margin:0px; padding:0px; color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><a name="t22" target="_blank"></a><a target="_blank" name="t22" style="color:rgb(51,102,153)"></a><a target="_blank" name="t22" style="color:rgb(51,102,153)"></a>媒体库相关代码路径:</h4><p style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px">*framework/av/media <br>framework/base/media <br>vendor/hisi/ap/hardware/vcodec <br>vendor/hisi/thirdparty/vcodec/chipmedia/ <br>/vendor/opensource/ffmpeg/ <br>vendor/thirdparty/videocodec/helix/*</p>   </div>

原创粉丝点击