Chromium為視頻標(biāo)簽創(chuàng)建播放器的過程分析_第1頁
Chromium為視頻標(biāo)簽創(chuàng)建播放器的過程分析_第2頁
Chromium為視頻標(biāo)簽創(chuàng)建播放器的過程分析_第3頁
Chromium為視頻標(biāo)簽創(chuàng)建播放器的過程分析_第4頁
Chromium為視頻標(biāo)簽創(chuàng)建播放器的過程分析_第5頁
已閱讀5頁,還剩36頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

Chromium為視頻標(biāo)簽創(chuàng)建播放器的過程分析Chromium為視頻標(biāo)簽<video>創(chuàng)建播放器的過程分析Chromium是通過WebKit解析網(wǎng)頁內(nèi)容的。當(dāng)WebKit遇到<video>標(biāo)簽時,就會創(chuàng)建一個播放器實例。WebKit是平臺無關(guān)的,而播放器實現(xiàn)是平臺相關(guān)的。因此,WebKit并沒有自己實現(xiàn)播放器,而僅僅是創(chuàng)建一個播放器接口。通過這個播放器接口,可以使用平臺提供的播放器來播放視頻的內(nèi)容。這就簡化了Chromium對視頻標(biāo)簽的支持。本文接下來就分析Chromium為視頻標(biāo)簽創(chuàng)建播放器的過程。以Android平臺為例,它的SDK提供了一個MediaPlayer接口,用來播放視頻。Chromium的目標(biāo)就是為網(wǎng)頁中的每一個<video>標(biāo)簽創(chuàng)建一個MediaPlayer實例,如圖1所示:首先,WebKit會為網(wǎng)頁中的每一個<video>標(biāo)簽創(chuàng)建一個類型為HTMLMediaElement的DOM節(jié)點。HTMLMediaElement類內(nèi)部有一個WebMediaPlayerClientImpl接口。這個WebMediaPlayerClientImpl接口指向的是一個運(yùn)行在Render進(jìn)程的Content模塊中的一個WebMediaPlayerAndroid對象。這些WebMediaPlayerAndroid對象歸一個稱為RendererMediaPayerManager的對象管理。Render進(jìn)程中的每一個WebMediaPlayerAndroid對象,在Browser進(jìn)程中都有一個對應(yīng)的WebMediaPlayerBridge對象。這些WebMediaPlayerBridge對象歸一個稱為BrowserMediaPayerManager的對象管理。每一個WebMediaPlayerBridge對象在Java層中又都對應(yīng)有一個MediaPlayer對象。這些MediaPlayer對象描述的就是Android平臺提供的播放器。接下來,我們就從WebKit解析<video>標(biāo)簽的屬性開始,分析Chromium為它們創(chuàng)建MediaPlayer的過程,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::parseAttribute(constQualifiedName&name,constAtomicString&value){if(name==srcAttr){//Triggerareload,aslongasthe'src'attributeispresent.if(!value.isNull()){scheduleDelayedAction(LoadMediaResource);}}}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。WebKit為網(wǎng)頁的每一個標(biāo)簽創(chuàng)建了相應(yīng)的DOM節(jié)點之后,就會調(diào)用這個DOM節(jié)點的成員函數(shù)parseAtrribute對它的屬性進(jìn)行解析。從文章中一文可以容易知道,WebKit為<video>標(biāo)簽創(chuàng)建的DOM節(jié)點的實際類型為HTMLVideoElement。HTMLVideoElement類是從HTMLMediaElement類繼承下來的,WebKit是調(diào)用后者的成同員函數(shù)parseAttribute來解析<video>的屬性。我們假設(shè)<video>標(biāo)簽通過src屬性設(shè)置了要播放的視頻文件的URL。這時候HTMLMediaElement類的成員函數(shù)parseAttribute就會調(diào)用另外一個成員函數(shù)scheduleDelayedAction為<video>標(biāo)簽創(chuàng)建播放器,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::scheduleDelayedAction(DelayedActionTypeactionType){if((actionType&LoadMediaResource)&&!(m_pendingActionFlags&LoadMediaResource)){prepareForLoad();m_pendingActionFlags|=LoadMediaResource;}if(!m_loadTimer.isActive())m_loadTimer.startOneShot(0,FROM_HERE);}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。從前面的調(diào)用過程可以知道,參數(shù)actionType的值等于LoadMediaResource。這時候如果HTMLMediaElement類的成員變量m_pendingActionFlags的LoadMediaResource位等于0,那么就說明WebKit還沒有為當(dāng)前正在解析的<video>標(biāo)簽創(chuàng)建過播放器接口。于是接下來就會做兩件事情:1.調(diào)用另外一個成員函數(shù)prepareForLoad開始為當(dāng)前正在解析的<video>標(biāo)簽創(chuàng)建圖1所示的WebMediaPlayerClientImpl接口;2.將成員變量m_pendingActionFlags的LoadMediaResource位設(shè)置為1,表示W(wǎng)ebKit正在為當(dāng)前正在解析的<video>標(biāo)簽創(chuàng)建過播放器接口,避免接下來出現(xiàn)重復(fù)創(chuàng)建的情況。HTMLMediaElement類的另外一個成員變量m_loadTimer描述的是一個定時器。如果這個定時器還沒有被啟動,那么HTMLMediaElement類的成員函數(shù)scheduleDelayedAction就會調(diào)用它的成員函數(shù)startOneShot馬上進(jìn)行啟動。指定的啟動時間單位為0,這意味著這個定時器會馬上超時。超時后它將會調(diào)用HTMLMediaElement類的成員函數(shù)loadTimerFired。HTMLMediaElement類的成員函數(shù)loadTimerFired將會繼續(xù)創(chuàng)建圖1所示的WebMediaPlayerAndroid、WebMediaPlayerBridge和MediaPlayer接口。接下來我們就先分析HTMLMediaElement類的成員函數(shù)prepareForLoad的實現(xiàn),如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::prepareForLoad(){createMediaPlayer();}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)prepareForLoad主要是調(diào)用另外一個成員函數(shù)createMediaPlayer為當(dāng)前正在解析的<video>標(biāo)簽創(chuàng)建一個WebMediaPlayerClientImpl接口,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::createMediaPlayer(){m_player=MediaPlayer::create(this);}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)createMediaPlayer調(diào)用MediaPlayer類的靜態(tài)成員函數(shù)create創(chuàng)建了一個WebMediaPlayerClientImpl接口,并且保存在HTMLMediaElement類的成員變量m_player中。MediaPlayer類的靜態(tài)成員函數(shù)create的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片staticCreateMediaEnginePlayercreateMediaEngineFunction=0;voidMediaPlayer::setMediaEngineCreateFunction(CreateMediaEnginePlayercreateFunction){ASSERT(createFunction);ASSERT(!createMediaEngineFunction);createMediaEngineFunction=createFunction;}PassOwnPtr<MediaPlayer>MediaPlayer::create(MediaPlayerClient*client){ASSERT(createMediaEngineFunction);returncreateMediaEngineFunction(client);}這兩個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/media/MediaPlayer.cpp中。MediaPlayer類的靜態(tài)成員函數(shù)create調(diào)用全局變量createMediaEngineFunction描述的一個函數(shù)創(chuàng)建一個播放器接口返回給調(diào)用者。全局變量createMediaEngineFunction描述的函數(shù)實際上是WebMediaPlayerClientImpl類的靜態(tài)成員函數(shù)create,它是通過調(diào)用MediaPlayer類的靜態(tài)成員函數(shù)setMediaEngineCreateFunction設(shè)置的。WebMediaPlayerClientImpl類的靜態(tài)成員函數(shù)create的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片PassOwnPtr<MediaPlayer>WebMediaPlayerClientImpl::create(MediaPlayerClient*client){returnadoptPtr(newWebMediaPlayerClientImpl(client));}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/web/WebMediaPlayerClientImpl.cpp中。從這里可以看到,WebMediaPlayerClientImpl類的靜態(tài)成員函數(shù)create返回的是一個WebMediaPlayerClientImpl對象。這個WebMediaPlayerClientImpl對象描述的就是WebKit層的播放器接口。這一步執(zhí)行完成之后,WebKit就為當(dāng)前正在解析的<video>標(biāo)簽創(chuàng)建了一個類型為WebMediaPlayerClientImpl的播放器接口?;氐角懊娣治龅腍TMLMediaElement類的成員函數(shù)scheduleDelayedAction中,接下來它啟動的定時器就會馬上執(zhí)行,也就HTMLMediaElement類的成員函數(shù)loadTimerFired會馬上被調(diào)用。HTMLMediaElement類的成員函數(shù)loadTimerFired的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*){if(m_pendingActionFlags&LoadMediaResource){if(m_loadState==LoadingFromSourceElement)loadNextSourceChild();elseloadInternal();}m_pendingActionFlags=0;}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。前面分析的HTMLMediaElement類的成員函數(shù)scheduleDelayedAction已經(jīng)將成員變量m_pendingActionFlags的LoadMediaResource位設(shè)置為1。這時候HTMLMediaElement類的成員函數(shù)loadTimerFired就會檢查HTMLMediaElement類的另外一個成員變量m_loadState的值是否等于LoadingFromSourceElement。如果等于,那么就說明當(dāng)前正在解析的<video>標(biāo)簽通過子元素<source>指定要播放的視頻的URL。否則的話,就通過屬性src指定要播放的視頻的URL。前面我們假定了當(dāng)前正在解析的<video>標(biāo)簽通過屬性src指定要播放的視頻的URL,因此HTMLMediaElement類的成員函數(shù)loadTimerFired接下來就會調(diào)用成員函數(shù)loadInternal繼續(xù)為其創(chuàng)建其它的播放器接口,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::loadInternal(){selectMediaResource();}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)loadInternal調(diào)用另外一個成員函數(shù)selectMediaResource為當(dāng)前正在解析的<video>標(biāo)簽選擇當(dāng)前要播放的視頻的URL。確定了當(dāng)前要播放的視頻的URL之后,就會加載視頻元數(shù)據(jù)。有了這些元數(shù)據(jù)之后,就可以為其創(chuàng)建真正的播放器。HTMLMediaElement類的成員函數(shù)selectMediaResource的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::selectMediaResource(){enumMode{attribute,children};Modemode=attribute;if(!fastHasAttribute(srcAttr)){//Otherwise,ifthemediaelementdoesnothaveasrcattributebuthasasource//elementchild,thenletmodebechildrenandletcandidatebethefirstsuch//sourceelementchildintreeorder.if(HTMLSourceElement*element=Traversal<HTMLSourceElement>::firstChild(*this)){mode=children;}}if(mode==attribute){//Ifthesrcattribute'svalueistheemptystring...jumpdowntothefailedstepbelowKURLmediaURL=getNonEmptyURLAttribute(srcAttr);loadResource(mediaURL,contentType,String());return;}}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)selectMediaResource所做的事情就要確定是從當(dāng)前正在解析的<video>標(biāo)簽的src屬性獲得要加載的視頻的URL,還是從它的子元素<source>獲得要加載的視頻的URL。如果當(dāng)前正在解析的<video>標(biāo)簽設(shè)置了src屬性,那么就會優(yōu)先從這個屬性獲得要加載的視頻的URL。有了這個URL之后,HTMLMediaElement類的成員函數(shù)selectMediaResource就會調(diào)用另外一個成員函數(shù)loadResource加載它所描述的視頻的元數(shù)據(jù)。在我們這個情景中,當(dāng)前正在解析的<video>標(biāo)簽設(shè)置了src屬性。因此,接下來我們就繼續(xù)分析HTMLMediaElement類的成員函數(shù)loadResource的實現(xiàn),如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::loadResource(constKURL&url,ContentType&contentType,constString&keySystem){m_currentSrc=url;boolattemptLoad=true;if(tocolIs(mediaSourceBlobProtocol)){if(isMediaStreamURL(url.string())){m_userGestureRequiredForPlay=false;}else{m_mediaSource=HTMLMediaSource::lookup(url.string());if(m_mediaSource){if(!m_mediaSource->attachToElement(this)){//ForgetourreferencetotheMediaSource,soweleaveitalone//whileprocessingremainderofloadfailure.m_mediaSource=nullptr;attemptLoad=false;}}}}if(attemptLoad&&canLoadURL(url,contentType,keySystem)){if(!m_havePreparedToPlay&&!autoplay()&&m_preload==MediaPlayer::None){deferLoad();}else{startPlayerLoad();}}}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)loadResource首先將當(dāng)前要播放的視頻的URL保存在成員變量m_currentSrc中,接下來判斷該URL的協(xié)議部分是否為“blob”。協(xié)議“blob”是“BinaryLargeOBject”的縮寫,表示一組二進(jìn)制數(shù)據(jù)。例如,我們手頭上有一組表示一個Image的二進(jìn)制數(shù)據(jù),這時候可以調(diào)用URL.createObjectURL函數(shù)為這組二進(jìn)制數(shù)據(jù)創(chuàng)建一個blob協(xié)議地址,然后再將該地址設(shè)置為一個<img>標(biāo)簽的src,這樣就可以將圖像顯示出來。通過blob協(xié)議,還可以描述媒體數(shù)據(jù)。在WebKit中,媒體數(shù)據(jù)可以通過MediaSource或者M(jìn)ediaStreamAPI描述。MediaSourceAPI的設(shè)計初衷是讓JavaScript能動態(tài)產(chǎn)生媒體流,然后交給<video>標(biāo)簽播放。MediaStreamAPI是為WebRTC設(shè)計的,不僅可以使用<video>標(biāo)簽播放從本地攝像頭采集的圖像,還可以播放從網(wǎng)絡(luò)發(fā)送過來的實時媒體流。關(guān)于MediaSource和MediaSteamAPI的更詳細(xì)信息,可以參考文章中和文章中這兩篇文檔。如果當(dāng)前要播放的視頻的URL的協(xié)議部分為“blob”,HTMLMediaElement類的成員函數(shù)loadResource首先會檢查它描述的是否是一個MediaStream。如果是的話,那么就會將HTMLMediaElement類的成員變量m_userGestureRequiredForPlay設(shè)置為false,表示后臺Tab網(wǎng)頁的視頻可以自動播放。Render進(jìn)程有一個“disable-gesture-requirement-for-media-playback”選項。當(dāng)這個選項的值設(shè)置為false時,HTMLMediaElement類的成員變量m_userGestureRequiredForPlay就會被設(shè)置為true,表示后臺Tab網(wǎng)頁的視頻不可以自動播放。不過,如果要播放的視頻是一個MediaStream,那么不會受到此限制。關(guān)于Render進(jìn)程的“disable-gesture-requirement-for-media-playback”啟動選項的更多信息,可以參考文章中一文。如果當(dāng)前要播放的視頻的URL的協(xié)議部分為“blob”,但是它描述的不是一個MediaStreamAPI,那么HTMLMediaElement類的成員函數(shù)loadResource再檢查它是否是一個MediaSource。如果是的話,就會將該MediaSource作為當(dāng)前正在解析的<video>標(biāo)簽的播放源。在這種情況下,WebKit不需要從網(wǎng)絡(luò)上下載媒體數(shù)據(jù)回來,只需要從指定的MediaSource讀取回來就可以了。這時候本地變量attemptLoad的值會被設(shè)置為false。在其余情況下,本地變量attemptLoad的值保持為初始值true。在本地變量attemptLoad的值為true的情況下,HTMLMediaElement類的成員函數(shù)loadResource會調(diào)用另外一個成員函數(shù)canLoadURL繼續(xù)檢查當(dāng)前要播放的視頻的URL描述的內(nèi)容是否為多媒體數(shù)據(jù),以及該多媒體使用的編碼方式是否被支持。如果檢查通過,HTMLMediaElement類的成員函數(shù)loadResource再判斷當(dāng)前解析的<video>標(biāo)簽的是否需要preload和autoplay。如果不需要,那么就會調(diào)用成員函數(shù)deferLoad延遲加載要播放的視頻的內(nèi)容。否則的話,就會調(diào)用成員函數(shù)startPlayerLoad馬上加載要播放的視頻的內(nèi)容回來。我們假設(shè)當(dāng)前解析的<video>標(biāo)簽設(shè)置了autoplay,因此接下來我們就繼續(xù)分析HTMLMediaElement類的成員函數(shù)startPlayerLoad的實現(xiàn),如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::startPlayerLoad(){KURLrequestURL=m_currentSrc;m_player->load(loadType(),requestURL,corsMode());}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。從前面的分析可以知道,HTMLMediaElement類的成員變量m_player指向的是一個WebMediaPlayerClientImpl對象。HTMLMediaElement類的成員函數(shù)startPlayerLoad主要是調(diào)用這個WebMediaPlayerClientImpl對象的成員函數(shù)load加載當(dāng)前要播放的視頻的內(nèi)容。WebMediaPlayerClientImpl類的成員函數(shù)load的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidWebMediaPlayerClientImpl::load(WebMediaPlayer::LoadTypeloadType,constWTF::String&url,WebMediaPlayer::CORSModecorsMode){KURLkurl(ParsedURLString,url);m_webMediaPlayer=createWebMediaPlayer(this,kurl,frame);m_webMediaPlayer->load(loadType,kurl,corsMode);}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/web/WebMediaPlayerClientImpl.cpp中。WebMediaPlayerClientImpl類的成員函數(shù)load首先調(diào)用函數(shù)createWebMediaPlayer請求運(yùn)行在當(dāng)前進(jìn)程(Render進(jìn)程)中的Content模塊創(chuàng)建一個播放器接口。這個Content模塊的播放器接口會保存在WebMediaPlayerClientImpl類的成員變量m_webMediaPlayer中。有了Content模塊的播放器接口之后,WebMediaPlayerClientImpl類的成員函數(shù)load再調(diào)用它的成員函數(shù)load請求加載當(dāng)前要播放的視頻的內(nèi)容。接下來我們先分析Content模塊的播放器接口的創(chuàng)建過程,也就是函數(shù)createWebMediaPlayer的實現(xiàn),如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片staticPassOwnPtr<WebMediaPlayer>createWebMediaPlayer(WebMediaPlayerClient*client,constWebURL&url,LocalFrame*frame){WebLocalFrameImpl*webFrame=WebLocalFrameImpl::fromFrame(frame);returnadoptPtr(webFrame->client()->createMediaPlayer(webFrame,url,client));}這個函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/web/WebMediaPlayerClientImpl.cpp中。函數(shù)createWebMediaPlayer首先獲得一個類型為blink::WebFrameClient的接口。這個接口是由WebKit的使用者設(shè)置給WebKit的,以便WebKit可以通過它執(zhí)行一些平臺相關(guān)的功能。在我們這個情景中,WebKit的使用者即為Render進(jìn)程中的Content模塊。Content模塊中的RenderFrameImpl類實現(xiàn)了該接口,并且會設(shè)置給WebKit。因此,函數(shù)createWebMediaPlayer接下來就會調(diào)用它的成員函數(shù)createMediaPlayer創(chuàng)建一個播放器接口。RenderFrameImpl類的成員函數(shù)createMediaPlayer的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片blink::WebMediaPlayer*RenderFrameImpl::createMediaPlayer(blink::WebLocalFrame*frame,constblink::WebURL&url,blink::WebMediaPlayerClient*client){blink::WebMediaStreamweb_stream(blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url));if(!web_stream.isNull())returnCreateWebMediaPlayerForMediaStream(url,client);#ifdefined(OS_ANDROID)returnCreateAndroidWebMediaPlayer(url,client);#else#endif//defined(OS_ANDROID)}這個函數(shù)定義在文件external/chromium_org/content/renderer/render_frame_impl.cc中。RenderFrameImpl類的成員函數(shù)createMediaPlayer首先判斷當(dāng)前要播放的視頻的URL描述的是否是一個MediaStream。如果是的話,那么就會調(diào)用成員函數(shù)CreateWebMediaPlayerForMediaStream創(chuàng)建一個類型為WebMediaPlayerMS的播放器。這個類型為WebMediaPlayerMS的播放器是在WebRTC中實現(xiàn)的。我們不考慮這種情況。如果當(dāng)前要播放的視頻的URL描述的不是一個MediaStream,那么RenderFrameImpl類的成員函數(shù)createMediaPlayer就會調(diào)用另外一個成員函數(shù)CreateAndroidWebMediaPlayer創(chuàng)建另外一種類型的播放器,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片WebMediaPlayer*RenderFrameImpl::CreateAndroidWebMediaPlayer(constblink::WebURL&url,WebMediaPlayerClient*client){GpuChannelHost*gpu_channel_host=RenderThreadImpl::current()->EstablishGpuChannelSync(CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE);scoped_refptr<StreamTextureFactory>stream_texture_factory;if(SynchronousCompositorFactory*factory=SynchronousCompositorFactory::GetInstance()){stream_texture_factory=factory->CreateStreamTextureFactory(routing_id_);}else{scoped_refptr<webkit::gpu::ContextProviderWebContext>context_provider=RenderThreadImpl::current()->SharedMainThreadContextProvider();stream_texture_factory=StreamTextureFactoryImpl::Create(context_provider,gpu_channel_host,routing_id_);}returnnewWebMediaPlayerAndroid(frame_,client,weak_factory_.GetWeakPtr(),GetMediaPlayerManager(),GetCdmManager(),stream_texture_factory,RenderThreadImpl::current()->GetMediaThreadMessageLoopProxy(),newRenderMediaLog());}這個函數(shù)定義在文件external/chromium_org/content/renderer/render_frame_impl.cc中。RenderFrameImpl類的成員函數(shù)CreateAndroidWebMediaPlayer首先是調(diào)用RenderThreadImpl類的成員函數(shù)EstablishGpuChannelSync為接下來要創(chuàng)建的播放器創(chuàng)建一個到GPU進(jìn)程的GPU通道。之所以要創(chuàng)建這個GPU通道,是因為Render要在GPU進(jìn)程中創(chuàng)建一個紋理,然后將這個紋理封裝為一個SurfaceTexture,作為Android平臺的MediaPlayer的解碼輸出。也就是說,Render進(jìn)程會通過這個SurfaceTexture接收Android平臺的MediaPlayer的解碼輸出,然后再以紋理的形式渲染在網(wǎng)頁上。GPU通道的創(chuàng)建過程,也就是RenderThreadImpl類的成員函數(shù)EstablishGpuChannelSync的實現(xiàn),可以參考前面文章中一文。RenderFrameImpl類的成員函數(shù)CreateAndroidWebMediaPlayer最終創(chuàng)建的是一個類型為WebMediaPlayerAndroid的播放器。創(chuàng)建這個類型為WebMediaPlayerAndroid的播放器需要用到兩個重要的對象。一個是StreamTextureFactory對象,另一個是RendererMediaPlayerManager對象。前者用來創(chuàng)建前面所述的紋理。后者用來管理在Render進(jìn)程中創(chuàng)建的播放器實例。在WebView的情況下,調(diào)用SynchronousCompositorFactory類的靜態(tài)成員函數(shù)GetInstance會獲得一個SynchronousCompositorFactory對象。在這種情況下,上述StreamTextureFactory對象通過調(diào)用這個SynchronousCompositorFactory對象的成員函數(shù)CreateStreamTextureFactory獲得。我們不考慮這一種情況。在獨立App的情況下,上述StreamTextureFactory對象實際上是一個StreamTextureFactoryImpl對象,它是通過調(diào)用StreamTextureFactoryImpl類的靜態(tài)成員函數(shù)Create創(chuàng)建的,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片scoped_refptr<StreamTextureFactoryImpl>StreamTextureFactoryImpl::Create(constscoped_refptr<cc::ContextProvider>&context_provider,GpuChannelHost*channel,intframe_id){returnnewStreamTextureFactoryImpl(context_provider,channel,frame_id);}這個函數(shù)定義在文件external/chromium_org/content/renderer/media/android/stream_texture_factory_impl.cc中。從這里可以看到,StreamTextureFactoryImpl類的靜態(tài)成員函數(shù)Create返回的是一個StreamTextureFactoryImpl對象?;氐角懊娣治龅腞enderFrameImpl類的成員函數(shù)CreateAndroidWebMediaPlayer中,它創(chuàng)建了一個StreamTextureFactoryImpl對象之后,接下來又會調(diào)用另外一個成員函數(shù)GetMediaPlayerManager獲得一個RendererMediaPlayerManager對象,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片RendererMediaPlayerManager*RenderFrameImpl::GetMediaPlayerManager(){if(!media_player_manager_){media_player_manager_=newRendererMediaPlayerManager(this);}returnmedia_player_manager_;}這個函數(shù)定義在文件external/chromium_org/content/renderer/render_frame_impl.cc中。從這里可以看到,RenderFrameImpl類的成員函數(shù)GetMediaPlayerManager返回的是成員變量media_player_manager_指向的是一個RendererMediaPlayerManager對象。如果這個RendererMediaPlayerManager對象還沒有創(chuàng)建,那么就會先進(jìn)行創(chuàng)建。再回到前面分析的RenderFrameImpl類的成員函數(shù)CreateAndroidWebMediaPlayer中,有了一個StreamTextureFactoryImpl對象和一個RendererMediaPlayerManager對象之后,它就會創(chuàng)建一個類型為WebMediaPlayerAndroid的播放器。類型為WebMediaPlayerAndroid的播放器的創(chuàng)建過程,也就是WebMediaPlayerAndroid類的構(gòu)造函數(shù)的實現(xiàn),如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片WebMediaPlayerAndroid::WebMediaPlayerAndroid(blink::WebFrame*frame,blink::WebMediaPlayerClient*client,base::WeakPtr<WebMediaPlayerDelegate>delegate,RendererMediaPlayerManager*player_manager,RendererCdmManager*cdm_manager,scoped_refptr<StreamTextureFactory>factory,constscoped_refptr<base::MessageLoopProxy>&media_loop,media::MediaLog*media_log):,player_manager_(player_manager),,stream_texture_factory_(factory),{player_id_=player_manager_->RegisterMediaPlayer(this);TryCreateStreamTextureProxyIfNeeded();}這個函數(shù)定義在文件external/chromium_org/content/renderer/media/android/webmediaplayer_android.cc中。WebMediaPlayerAndroid類的構(gòu)造函數(shù)首先是將參數(shù)player_manager和factory描述的StreamTextureFactoryImpl對象和RendererMediaPlayerManager對象分別保存在成員變量player_manager_和stream_texture_factory_中。WebMediaPlayerAndroid類的構(gòu)造函數(shù)接下來又會做兩件事情:1.調(diào)用上述RendererMediaPlayerManager對象的成員函數(shù)RegisterMediaPlayer將當(dāng)前正在創(chuàng)建的WebMediaPlayerAndroid對象保存在其內(nèi)部,并且為其分配一個ID。以后通過這個ID就可以在該RendererMediaPlayerManager對象中找到當(dāng)前正在創(chuàng)建的WebMediaPlayerAndroid對象。2.調(diào)用另外一個成員函數(shù)TryCreateStreamTextureProxyIfNeeded創(chuàng)建一個SurfaceTexture,以便后面可以用來接收Android平臺的MediaPlayer的解碼輸出。關(guān)于WebMediaPlayerAndroid類的成員函數(shù)TryCreateStreamTextureProxyIfNeeded創(chuàng)建SurfaceTexture的過程,我們在接下來一篇文章中分析<video>標(biāo)簽的視頻渲染過程時再分析。這一步執(zhí)行完成之后,運(yùn)行在Render進(jìn)程中的Content模塊就創(chuàng)建了一個類型為WebMediaPlayerAndroid的播放器接口。這個播放器接口會返回給WebKit層的WebMediaPlayerClientImpl類的成員函數(shù)load。WebMediaPlayerClientImpl類的成員函數(shù)load獲得了這個播放器接口之后,就會調(diào)用它的成員函數(shù)load加載當(dāng)前要播放的視頻的內(nèi)容,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidWebMediaPlayerAndroid::load(LoadTypeload_type,constblink::WebURL&url,CORSModecors_mode){switch(load_type){caseLoadTypeURL:player_type_=MEDIA_PLAYER_TYPE_URL;break;caseLoadTypeMediaSource:player_type_=MEDIA_PLAYER_TYPE_MEDIA_SOURCE;break;caseLoadTypeMediaStream:CHECK(false)<<"WebMediaPlayerAndroiddoesn'tsupportMediaStreamon""thisplatform";return;}url_=url;intdemuxer_client_id=0;if(player_type_!=MEDIA_PLAYER_TYPE_URL){RendererDemuxerAndroid*demuxer=RenderThreadImpl::current()->renderer_demuxer();demuxer_client_id=demuxer->GetNextDemuxerClientID();media_source_delegate_.reset(newMediaSourceDelegate(demuxer,demuxer_client_id,media_loop_,media_log_));if(player_type_==MEDIA_PLAYER_TYPE_MEDIA_SOURCE){media::SetDecryptorReadyCBset_decryptor_ready_cb=media::BindToCurrentLoop(base::Bind(&WebMediaPlayerAndroid::SetDecryptorReadyCB,weak_factory_.GetWeakPtr()));media_source_delegate_->InitializeMediaSource(base::Bind(&WebMediaPlayerAndroid::OnMediaSourceOpened,weak_factory_.GetWeakPtr()),base::Bind(&WebMediaPlayerAndroid::OnNeedKey,weak_factory_.GetWeakPtr()),set_decryptor_ready_cb,base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,weak_factory_.GetWeakPtr()),base::Bind(&WebMediaPlayerAndroid::OnDurationChanged,weak_factory_.GetWeakPtr()));InitializePlayer(url_,frame_->document().firstPartyForCookies(),true,demuxer_client_id);}}else{info_loader_.reset(newMediaInfoLoader(url,cors_mode,base::Bind(&WebMediaPlayerAndroid::DidLoadMediaInfo,weak_factory_.GetWeakPtr())));info_loader_->Start(frame_);}}這個函數(shù)定義在文件external/chromium_org/content/renderer/media/android/webmediaplayer_android.cc中。類型為WebMediaPlayerAndroid的播放器只能處理普通URL描述的媒體流,以及BLOB協(xié)議描述的類型為MediaSource的媒體流,不能處理類型為MediaStream的媒體流(需要由WebRTC處理)。類型為MediaSource的媒體流數(shù)據(jù)直接從指定的MediaSource獲得。WebMediaPlayerAndroid類的成員函數(shù)load將該MediaSource封裝在一個MediaSourceDelegate對象中,然后通過這個MediaSourceDelegate對象來獲得要播放的視頻的元數(shù)據(jù)。有了要播放的視頻的元數(shù)據(jù)之后,就可以調(diào)用WebMediaPlayerAndroid類的成員函數(shù)InitializePlayer初始化當(dāng)前正在處理的播放器。我們假設(shè)當(dāng)前要播放的視頻的URL是一個普通的URL,它描述的媒體流的元數(shù)據(jù)要通過一個MediaInfoLoader對象從網(wǎng)絡(luò)上下載回來。下載完成后,WebMediaPlayerAndroid類的成員函數(shù)DidLoadMediaInfo會被調(diào)用,它的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidWebMediaPlayerAndroid::DidLoadMediaInfo(MediaInfoLoader::Statusstatus,constGURL&redirected_url,constGURL&first_party_for_cookies,boolallow_stored_credentials){InitializePlayer(redirected_url,first_party_for_cookies,allow_stored_credentials,0);}這個函數(shù)定義在文件external/chromium_org/content/renderer/media/android/webmediaplayer_android.cc中。WebMediaPlayerAndroid類的成員函數(shù)DidLoadMediaInfo會用下載回來的視頻元數(shù)據(jù)初始化當(dāng)前正在處理的播放器。這同樣是通過調(diào)用WebMediaPlayerAndroid類的成員函數(shù)InitializePlayer進(jìn)行的,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidWebMediaPlayerAndroid::InitializePlayer(constGURL&url,constGURL&first_party_for_cookies,boolallow_stored_credentials,intdemuxer_client_id){player_manager_->Initialize(player_type_,player_id_,url,first_party_for_cookies,demuxer_client_id,frame_->document().url(),allow_stored_credentials);}這個函數(shù)定義在文件external/chromium_org/content/renderer/media/android/webmediaplayer_android.cc中。從前面的分析可以知道,WebMediaPlayerAndroid類的成員變量player_manager_指向的是一個RendererMediaPlayerManager對象。WebMediaPlayerAndroid類的成員函數(shù)InitializePlayer調(diào)用這個RendererMediaPlayerManager對象的成員函數(shù)Initialize對當(dāng)前正在處理的播放器進(jìn)行初始化,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidRendererMediaPlayerManager::Initialize(MediaPlayerHostMsg_Initialize_Typetype,intplayer_id,constGURL&url,constGURL&first_party_for_cookies,intdemuxer_client_id,constGURL&frame_url,boolallow_credentials){MediaPlayerHostMsg_Initialize_Paramsmedia_player_params;media_player_params.type=type;media_player_params.player_id=player_id;media_player_params.demuxer_client_id=demuxer_client_id;media_player_params.url=url;media_player_params.first_party_for_cookies=first_party_for_cookies;media_player_params.frame_url=frame_url;media_player_params.allow_credentials=allow_credentials;Send(newMediaPlayerHostMsg_Initialize(routing_id(),media_player_params));}這個函數(shù)定義在文件external/chromium_org/content/renderer/media/android/renderer_media_player_manager.cc中。RendererMediaPlayerManager對象的成員函數(shù)Initialize向Browser進(jìn)程發(fā)送一個類型為MediaPlayerHostMsg_Initialize的IPC消息,用來請求Browser進(jìn)程為當(dāng)前正在處理的類型為WebMediaPlayerAndroid的播放器創(chuàng)建一個由Android平臺實現(xiàn)的播放器。Browser進(jìn)程是通過MediaWebContentsObserver類的成員函數(shù)OnMediaPlayerMessageReceived接收類型為MediaPlayerHostMsg_Initialize的IPC消息的,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片boolMediaWebContentsObserver::OnMediaPlayerMessageReceived(constIPC::Message&msg,RenderFrameHost*render_frame_host){boolhandled=true;IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserver,msg)IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize,GetMediaPlayerManager(render_frame_host),IPC_MESSAGE_UNHANDLED(handled=false)IPC_END_MESSAGE_MAP()returnhandled;}這個函數(shù)定義在文件external/chromium_org/content/browser/media/media_web_contents_observer.cc中。MediaWebContentsObserver類的成員函數(shù)OnMediaPlayerMessageReceived會將類型為MediaPlayerHostMsg_Initialize的IPC消息分發(fā)給運(yùn)行在Browser進(jìn)程中的一個BrowserMediaPlayerManager對象的成員函數(shù)OnInitialize處理。這個BrowserMediaPlayerManager對象負(fù)責(zé)管理在Browser進(jìn)程中創(chuàng)建的播放器實例,它與運(yùn)行在Render進(jìn)程中的RendererMediaPlayerManager對象是對應(yīng)的,不過后者用來管理在Render進(jìn)程中創(chuàng)建的播放器實例。BrowserMediaPlayerManager類的成員函數(shù)OnInitialize的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidBrowserMediaPlayerManager::OnInitialize(constMediaPlayerHostMsg_Initialize_Params&media_player_params){MediaPlayerAndroid*player=CreateMediaPlayer(media_player_params,host->GetBrowserContext()->IsOffTheRecord(),this,host->browser_demuxer_android());AddPlayer(player);}這個函數(shù)定義在文件external/chromium_org/content/browser/media/android/browser_media_player_manager.cc中。BrowserMediaPlayerManager類的成員函數(shù)OnInitialize主要是調(diào)用成員函數(shù)CreateMediaPlayer創(chuàng)建一個類型為MediaPlayerBridge的播放器實例,并且調(diào)用另外一個成員函數(shù)AddPlayer將這個播放器實例保存在內(nèi)部。BrowserMediaPlayerManager類的成員函數(shù)CreateMediaPlayer的實現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片MediaPlayerAndroid*BrowserMediaPlayerManager::CreateMediaPlayer(constMediaPlayerHostMsg_Initialize_Params&media_player_params,boolhide_url_log,MediaPlayerManager*manager,BrowserDemuxerAndroid*demuxer){switch(media_player_params.type){caseMEDIA_PLAYER_TYPE_URL:{conststd::stringuser_agent=GetContentClient()->GetUserAgent();MediaPlayerBridge*media_player_bridge=newMediaPlayerBridge(media_player_params.player_id,media_player_params.url,media_player_params.first_party_for_cookies,user_agent,hide_url_log,manager,base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesRequested,weak_ptr_factory_.GetWeakPtr()),base::Bind(&BrowserMediaPlayerManager::OnMediaResourcesReleased,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論