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

下載本文檔

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

文檔簡(jiǎn)介

Chromium為視頻標(biāo)簽創(chuàng)建播放器的過(guò)程分析Chromium為視頻標(biāo)簽<video>創(chuàng)建播放器的過(guò)程分析Chromium是通過(guò)WebKit解析網(wǎng)頁(yè)內(nèi)容的。當(dāng)WebKit遇到<video>標(biāo)簽時(shí),就會(huì)創(chuàng)建一個(gè)播放器實(shí)例。WebKit是平臺(tái)無(wú)關(guān)的,而播放器實(shí)現(xiàn)是平臺(tái)相關(guān)的。因此,WebKit并沒(méi)有自己實(shí)現(xiàn)播放器,而僅僅是創(chuàng)建一個(gè)播放器接口。通過(guò)這個(gè)播放器接口,可以使用平臺(tái)提供的播放器來(lái)播放視頻的內(nèi)容。這就簡(jiǎn)化了Chromium對(duì)視頻標(biāo)簽的支持。本文接下來(lái)就分析Chromium為視頻標(biāo)簽創(chuàng)建播放器的過(guò)程。以Android平臺(tái)為例,它的SDK提供了一個(gè)MediaPlayer接口,用來(lái)播放視頻。Chromium的目標(biāo)就是為網(wǎng)頁(yè)中的每一個(gè)<video>標(biāo)簽創(chuàng)建一個(gè)MediaPlayer實(shí)例,如圖1所示:首先,WebKit會(huì)為網(wǎng)頁(yè)中的每一個(gè)<video>標(biāo)簽創(chuàng)建一個(gè)類型為HTMLMediaElement的DOM節(jié)點(diǎn)。HTMLMediaElement類內(nèi)部有一個(gè)WebMediaPlayerClientImpl接口。這個(gè)WebMediaPlayerClientImpl接口指向的是一個(gè)運(yùn)行在Render進(jìn)程的Content模塊中的一個(gè)WebMediaPlayerAndroid對(duì)象。這些WebMediaPlayerAndroid對(duì)象歸一個(gè)稱為RendererMediaPayerManager的對(duì)象管理。Render進(jìn)程中的每一個(gè)WebMediaPlayerAndroid對(duì)象,在Browser進(jìn)程中都有一個(gè)對(duì)應(yīng)的WebMediaPlayerBridge對(duì)象。這些WebMediaPlayerBridge對(duì)象歸一個(gè)稱為BrowserMediaPayerManager的對(duì)象管理。每一個(gè)WebMediaPlayerBridge對(duì)象在Java層中又都對(duì)應(yīng)有一個(gè)MediaPlayer對(duì)象。這些MediaPlayer對(duì)象描述的就是Android平臺(tái)提供的播放器。接下來(lái),我們就從WebKit解析<video>標(biāo)簽的屬性開(kāi)始,分析Chromium為它們創(chuàng)建MediaPlayer的過(guò)程,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::parseAttribute(constQualifiedName&name,constAtomicString&value){if(name==srcAttr){//Triggerareload,aslongasthe'src'attributeispresent.if(!value.isNull()){scheduleDelayedAction(LoadMediaResource);}}}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。WebKit為網(wǎng)頁(yè)的每一個(gè)標(biāo)簽創(chuàng)建了相應(yīng)的DOM節(jié)點(diǎn)之后,就會(huì)調(diào)用這個(gè)DOM節(jié)點(diǎn)的成員函數(shù)parseAtrribute對(duì)它的屬性進(jìn)行解析。從文章中一文可以容易知道,WebKit為<video>標(biāo)簽創(chuàng)建的DOM節(jié)點(diǎn)的實(shí)際類型為HTMLVideoElement。HTMLVideoElement類是從HTMLMediaElement類繼承下來(lái)的,WebKit是調(diào)用后者的成同員函數(shù)parseAttribute來(lái)解析<video>的屬性。我們假設(shè)<video>標(biāo)簽通過(guò)src屬性設(shè)置了要播放的視頻文件的URL。這時(shí)候HTMLMediaElement類的成員函數(shù)parseAttribute就會(huì)調(diào)用另外一個(gè)成員函數(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);}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。從前面的調(diào)用過(guò)程可以知道,參數(shù)actionType的值等于LoadMediaResource。這時(shí)候如果HTMLMediaElement類的成員變量m_pendingActionFlags的LoadMediaResource位等于0,那么就說(shuō)明WebKit還沒(méi)有為當(dāng)前正在解析的<video>標(biāo)簽創(chuàng)建過(guò)播放器接口。于是接下來(lái)就會(huì)做兩件事情:1.調(diào)用另外一個(gè)成員函數(shù)prepareForLoad開(kāi)始為當(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)建過(guò)播放器接口,避免接下來(lái)出現(xiàn)重復(fù)創(chuàng)建的情況。HTMLMediaElement類的另外一個(gè)成員變量m_loadTimer描述的是一個(gè)定時(shí)器。如果這個(gè)定時(shí)器還沒(méi)有被啟動(dòng),那么HTMLMediaElement類的成員函數(shù)scheduleDelayedAction就會(huì)調(diào)用它的成員函數(shù)startOneShot馬上進(jìn)行啟動(dòng)。指定的啟動(dòng)時(shí)間單位為0,這意味著這個(gè)定時(shí)器會(huì)馬上超時(shí)。超時(shí)后它將會(huì)調(diào)用HTMLMediaElement類的成員函數(shù)loadTimerFired。HTMLMediaElement類的成員函數(shù)loadTimerFired將會(huì)繼續(xù)創(chuàng)建圖1所示的WebMediaPlayerAndroid、WebMediaPlayerBridge和MediaPlayer接口。接下來(lái)我們就先分析HTMLMediaElement類的成員函數(shù)prepareForLoad的實(shí)現(xiàn),如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::prepareForLoad(){createMediaPlayer();}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)prepareForLoad主要是調(diào)用另外一個(gè)成員函數(shù)createMediaPlayer為當(dāng)前正在解析的<video>標(biāo)簽創(chuàng)建一個(gè)WebMediaPlayerClientImpl接口,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::createMediaPlayer(){m_player=MediaPlayer::create(this);}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)createMediaPlayer調(diào)用MediaPlayer類的靜態(tài)成員函數(shù)create創(chuàng)建了一個(gè)WebMediaPlayerClientImpl接口,并且保存在HTMLMediaElement類的成員變量m_player中。MediaPlayer類的靜態(tài)成員函數(shù)create的實(shí)現(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);}這兩個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/media/MediaPlayer.cpp中。MediaPlayer類的靜態(tài)成員函數(shù)create調(diào)用全局變量createMediaEngineFunction描述的一個(gè)函數(shù)創(chuàng)建一個(gè)播放器接口返回給調(diào)用者。全局變量createMediaEngineFunction描述的函數(shù)實(shí)際上是WebMediaPlayerClientImpl類的靜態(tài)成員函數(shù)create,它是通過(guò)調(diào)用MediaPlayer類的靜態(tài)成員函數(shù)setMediaEngineCreateFunction設(shè)置的。WebMediaPlayerClientImpl類的靜態(tài)成員函數(shù)create的實(shí)現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片PassOwnPtr<MediaPlayer>WebMediaPlayerClientImpl::create(MediaPlayerClient*client){returnadoptPtr(newWebMediaPlayerClientImpl(client));}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/web/WebMediaPlayerClientImpl.cpp中。從這里可以看到,WebMediaPlayerClientImpl類的靜態(tài)成員函數(shù)create返回的是一個(gè)WebMediaPlayerClientImpl對(duì)象。這個(gè)WebMediaPlayerClientImpl對(duì)象描述的就是WebKit層的播放器接口。這一步執(zhí)行完成之后,WebKit就為當(dāng)前正在解析的<video>標(biāo)簽創(chuàng)建了一個(gè)類型為WebMediaPlayerClientImpl的播放器接口?;氐角懊娣治龅腍TMLMediaElement類的成員函數(shù)scheduleDelayedAction中,接下來(lái)它啟動(dòng)的定時(shí)器就會(huì)馬上執(zhí)行,也就HTMLMediaElement類的成員函數(shù)loadTimerFired會(huì)馬上被調(diào)用。HTMLMediaElement類的成員函數(shù)loadTimerFired的實(shí)現(xiàn)如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*){if(m_pendingActionFlags&LoadMediaResource){if(m_loadState==LoadingFromSourceElement)loadNextSourceChild();elseloadInternal();}m_pendingActionFlags=0;}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。前面分析的HTMLMediaElement類的成員函數(shù)scheduleDelayedAction已經(jīng)將成員變量m_pendingActionFlags的LoadMediaResource位設(shè)置為1。這時(shí)候HTMLMediaElement類的成員函數(shù)loadTimerFired就會(huì)檢查HTMLMediaElement類的另外一個(gè)成員變量m_loadState的值是否等于LoadingFromSourceElement。如果等于,那么就說(shuō)明當(dāng)前正在解析的<video>標(biāo)簽通過(guò)子元素<source>指定要播放的視頻的URL。否則的話,就通過(guò)屬性src指定要播放的視頻的URL。前面我們假定了當(dāng)前正在解析的<video>標(biāo)簽通過(guò)屬性src指定要播放的視頻的URL,因此HTMLMediaElement類的成員函數(shù)loadTimerFired接下來(lái)就會(huì)調(diào)用成員函數(shù)loadInternal繼續(xù)為其創(chuàng)建其它的播放器接口,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::loadInternal(){selectMediaResource();}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)loadInternal調(diào)用另外一個(gè)成員函數(shù)selectMediaResource為當(dāng)前正在解析的<video>標(biāo)簽選擇當(dāng)前要播放的視頻的URL。確定了當(dāng)前要播放的視頻的URL之后,就會(huì)加載視頻元數(shù)據(jù)。有了這些元數(shù)據(jù)之后,就可以為其創(chuàng)建真正的播放器。HTMLMediaElement類的成員函數(shù)selectMediaResource的實(shí)現(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;}}這個(gè)函數(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屬性,那么就會(huì)優(yōu)先從這個(gè)屬性獲得要加載的視頻的URL。有了這個(gè)URL之后,HTMLMediaElement類的成員函數(shù)selectMediaResource就會(huì)調(diào)用另外一個(gè)成員函數(shù)loadResource加載它所描述的視頻的元數(shù)據(jù)。在我們這個(gè)情景中,當(dāng)前正在解析的<video>標(biāo)簽設(shè)置了src屬性。因此,接下來(lái)我們就繼續(xù)分析HTMLMediaElement類的成員函數(shù)loadResource的實(shí)現(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();}}}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。HTMLMediaElement類的成員函數(shù)loadResource首先將當(dāng)前要播放的視頻的URL保存在成員變量m_currentSrc中,接下來(lái)判斷該URL的協(xié)議部分是否為“blob”。協(xié)議“blob”是“BinaryLargeOBject”的縮寫,表示一組二進(jìn)制數(shù)據(jù)。例如,我們手頭上有一組表示一個(gè)Image的二進(jìn)制數(shù)據(jù),這時(shí)候可以調(diào)用URL.createObjectURL函數(shù)為這組二進(jìn)制數(shù)據(jù)創(chuàng)建一個(gè)blob協(xié)議地址,然后再將該地址設(shè)置為一個(gè)<img>標(biāo)簽的src,這樣就可以將圖像顯示出來(lái)。通過(guò)blob協(xié)議,還可以描述媒體數(shù)據(jù)。在WebKit中,媒體數(shù)據(jù)可以通過(guò)MediaSource或者M(jìn)ediaStreamAPI描述。MediaSourceAPI的設(shè)計(jì)初衷是讓JavaScript能動(dòng)態(tài)產(chǎn)生媒體流,然后交給<video>標(biāo)簽播放。MediaStreamAPI是為WebRTC設(shè)計(jì)的,不僅可以使用<video>標(biāo)簽播放從本地?cái)z像頭采集的圖像,還可以播放從網(wǎng)絡(luò)發(fā)送過(guò)來(lái)的實(shí)時(shí)媒體流。關(guān)于MediaSource和MediaSteamAPI的更詳細(xì)信息,可以參考文章中和文章中這兩篇文檔。如果當(dāng)前要播放的視頻的URL的協(xié)議部分為“blob”,HTMLMediaElement類的成員函數(shù)loadResource首先會(huì)檢查它描述的是否是一個(gè)MediaStream。如果是的話,那么就會(huì)將HTMLMediaElement類的成員變量m_userGestureRequiredForPlay設(shè)置為false,表示后臺(tái)Tab網(wǎng)頁(yè)的視頻可以自動(dòng)播放。Render進(jìn)程有一個(gè)“disable-gesture-requirement-for-media-playback”選項(xiàng)。當(dāng)這個(gè)選項(xiàng)的值設(shè)置為false時(shí),HTMLMediaElement類的成員變量m_userGestureRequiredForPlay就會(huì)被設(shè)置為true,表示后臺(tái)Tab網(wǎng)頁(yè)的視頻不可以自動(dòng)播放。不過(guò),如果要播放的視頻是一個(gè)MediaStream,那么不會(huì)受到此限制。關(guān)于Render進(jìn)程的“disable-gesture-requirement-for-media-playback”啟動(dòng)選項(xiàng)的更多信息,可以參考文章中一文。如果當(dāng)前要播放的視頻的URL的協(xié)議部分為“blob”,但是它描述的不是一個(gè)MediaStreamAPI,那么HTMLMediaElement類的成員函數(shù)loadResource再檢查它是否是一個(gè)MediaSource。如果是的話,就會(huì)將該MediaSource作為當(dāng)前正在解析的<video>標(biāo)簽的播放源。在這種情況下,WebKit不需要從網(wǎng)絡(luò)上下載媒體數(shù)據(jù)回來(lái),只需要從指定的MediaSource讀取回來(lái)就可以了。這時(shí)候本地變量attemptLoad的值會(huì)被設(shè)置為false。在其余情況下,本地變量attemptLoad的值保持為初始值true。在本地變量attemptLoad的值為true的情況下,HTMLMediaElement類的成員函數(shù)loadResource會(huì)調(diào)用另外一個(gè)成員函數(shù)canLoadURL繼續(xù)檢查當(dāng)前要播放的視頻的URL描述的內(nèi)容是否為多媒體數(shù)據(jù),以及該多媒體使用的編碼方式是否被支持。如果檢查通過(guò),HTMLMediaElement類的成員函數(shù)loadResource再判斷當(dāng)前解析的<video>標(biāo)簽的是否需要preload和autoplay。如果不需要,那么就會(huì)調(diào)用成員函數(shù)deferLoad延遲加載要播放的視頻的內(nèi)容。否則的話,就會(huì)調(diào)用成員函數(shù)startPlayerLoad馬上加載要播放的視頻的內(nèi)容回來(lái)。我們假設(shè)當(dāng)前解析的<video>標(biāo)簽設(shè)置了autoplay,因此接下來(lái)我們就繼續(xù)分析HTMLMediaElement類的成員函數(shù)startPlayerLoad的實(shí)現(xiàn),如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片voidHTMLMediaElement::startPlayerLoad(){KURLrequestURL=m_currentSrc;m_player->load(loadType(),requestURL,corsMode());}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。從前面的分析可以知道,HTMLMediaElement類的成員變量m_player指向的是一個(gè)WebMediaPlayerClientImpl對(duì)象。HTMLMediaElement類的成員函數(shù)startPlayerLoad主要是調(diào)用這個(gè)WebMediaPlayerClientImpl對(duì)象的成員函數(shù)load加載當(dāng)前要播放的視頻的內(nèi)容。WebMediaPlayerClientImpl類的成員函數(shù)load的實(shí)現(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);}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/web/WebMediaPlayerClientImpl.cpp中。WebMediaPlayerClientImpl類的成員函數(shù)load首先調(diào)用函數(shù)createWebMediaPlayer請(qǐng)求運(yùn)行在當(dāng)前進(jìn)程(Render進(jìn)程)中的Content模塊創(chuàng)建一個(gè)播放器接口。這個(gè)Content模塊的播放器接口會(huì)保存在WebMediaPlayerClientImpl類的成員變量m_webMediaPlayer中。有了Content模塊的播放器接口之后,WebMediaPlayerClientImpl類的成員函數(shù)load再調(diào)用它的成員函數(shù)load請(qǐng)求加載當(dāng)前要播放的視頻的內(nèi)容。接下來(lái)我們先分析Content模塊的播放器接口的創(chuàng)建過(guò)程,也就是函數(shù)createWebMediaPlayer的實(shí)現(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));}這個(gè)函數(shù)定義在文件external/chromium_org/third_party/WebKit/Source/web/WebMediaPlayerClientImpl.cpp中。函數(shù)createWebMediaPlayer首先獲得一個(gè)類型為blink::WebFrameClient的接口。這個(gè)接口是由WebKit的使用者設(shè)置給WebKit的,以便WebKit可以通過(guò)它執(zhí)行一些平臺(tái)相關(guān)的功能。在我們這個(gè)情景中,WebKit的使用者即為Render進(jìn)程中的Content模塊。Content模塊中的RenderFrameImpl類實(shí)現(xiàn)了該接口,并且會(huì)設(shè)置給WebKit。因此,函數(shù)createWebMediaPlayer接下來(lái)就會(huì)調(diào)用它的成員函數(shù)createMediaPlayer創(chuàng)建一個(gè)播放器接口。RenderFrameImpl類的成員函數(shù)createMediaPlayer的實(shí)現(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)}這個(gè)函數(shù)定義在文件external/chromium_org/content/renderer/render_frame_impl.cc中。RenderFrameImpl類的成員函數(shù)createMediaPlayer首先判斷當(dāng)前要播放的視頻的URL描述的是否是一個(gè)MediaStream。如果是的話,那么就會(huì)調(diào)用成員函數(shù)CreateWebMediaPlayerForMediaStream創(chuàng)建一個(gè)類型為WebMediaPlayerMS的播放器。這個(gè)類型為WebMediaPlayerMS的播放器是在WebRTC中實(shí)現(xiàn)的。我們不考慮這種情況。如果當(dāng)前要播放的視頻的URL描述的不是一個(gè)MediaStream,那么RenderFrameImpl類的成員函數(shù)createMediaPlayer就會(huì)調(diào)用另外一個(gè)成員函數(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());}這個(gè)函數(shù)定義在文件external/chromium_org/content/renderer/render_frame_impl.cc中。RenderFrameImpl類的成員函數(shù)CreateAndroidWebMediaPlayer首先是調(diào)用RenderThreadImpl類的成員函數(shù)EstablishGpuChannelSync為接下來(lái)要?jiǎng)?chuàng)建的播放器創(chuàng)建一個(gè)到GPU進(jìn)程的GPU通道。之所以要?jiǎng)?chuàng)建這個(gè)GPU通道,是因?yàn)镽ender要在GPU進(jìn)程中創(chuàng)建一個(gè)紋理,然后將這個(gè)紋理封裝為一個(gè)SurfaceTexture,作為Android平臺(tái)的MediaPlayer的解碼輸出。也就是說(shuō),Render進(jìn)程會(huì)通過(guò)這個(gè)SurfaceTexture接收Android平臺(tái)的MediaPlayer的解碼輸出,然后再以紋理的形式渲染在網(wǎng)頁(yè)上。GPU通道的創(chuàng)建過(guò)程,也就是RenderThreadImpl類的成員函數(shù)EstablishGpuChannelSync的實(shí)現(xiàn),可以參考前面文章中一文。RenderFrameImpl類的成員函數(shù)CreateAndroidWebMediaPlayer最終創(chuàng)建的是一個(gè)類型為WebMediaPlayerAndroid的播放器。創(chuàng)建這個(gè)類型為WebMediaPlayerAndroid的播放器需要用到兩個(gè)重要的對(duì)象。一個(gè)是StreamTextureFactory對(duì)象,另一個(gè)是RendererMediaPlayerManager對(duì)象。前者用來(lái)創(chuàng)建前面所述的紋理。后者用來(lái)管理在Render進(jìn)程中創(chuàng)建的播放器實(shí)例。在WebView的情況下,調(diào)用SynchronousCompositorFactory類的靜態(tài)成員函數(shù)GetInstance會(huì)獲得一個(gè)SynchronousCompositorFactory對(duì)象。在這種情況下,上述StreamTextureFactory對(duì)象通過(guò)調(diào)用這個(gè)SynchronousCompositorFactory對(duì)象的成員函數(shù)CreateStreamTextureFactory獲得。我們不考慮這一種情況。在獨(dú)立App的情況下,上述StreamTextureFactory對(duì)象實(shí)際上是一個(gè)StreamTextureFactoryImpl對(duì)象,它是通過(guò)調(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);}這個(gè)函數(shù)定義在文件external/chromium_org/content/renderer/media/android/stream_texture_factory_impl.cc中。從這里可以看到,StreamTextureFactoryImpl類的靜態(tài)成員函數(shù)Create返回的是一個(gè)StreamTextureFactoryImpl對(duì)象。回到前面分析的RenderFrameImpl類的成員函數(shù)CreateAndroidWebMediaPlayer中,它創(chuàng)建了一個(gè)StreamTextureFactoryImpl對(duì)象之后,接下來(lái)又會(huì)調(diào)用另外一個(gè)成員函數(shù)GetMediaPlayerManager獲得一個(gè)RendererMediaPlayerManager對(duì)象,如下所示:[cpp]viewplaincopy在CODE上查看代碼片派生到我的代碼片RendererMediaPlayerManager*RenderFrameImpl::GetMediaPlayerManager(){if(!media_player_manager_){media_player_manager_=newRendererMediaPlayerManager(this);}returnmedia_player_manager_;}這個(gè)函數(shù)定義在文件external/chromium_org/content/renderer/render_frame_impl.cc中。從這里可以看到,RenderFrameImpl類的成員函數(shù)GetMediaPlayerManager返回的是成員變量media_player_manager_指向的是一個(gè)RendererMediaPlayerManager對(duì)象。如果這個(gè)RendererMediaPlayerManager對(duì)象還沒(méi)有創(chuàng)建,那么就會(huì)先進(jìn)行創(chuàng)建。再回到前面分析的RenderFrameImpl類的成員函數(shù)CreateAndroidWebMediaPlayer中,有了一個(gè)StreamTextureFactoryImpl對(duì)象和一個(gè)RendererMediaPlayerManager對(duì)象之后,它就會(huì)創(chuàng)建一個(gè)類型為WebMediaPlayerAndroid的播放器。類型為WebMediaPlayerAndroid的播放器的創(chuàng)建過(guò)程,也就是WebMediaPlayerAndroid類的構(gòu)造函數(shù)的實(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();}這個(gè)函數(shù)定義在文件external/chromium_org/content/renderer/media/android/webmediaplayer_android.cc中。WebMediaPlayerAndroid類的構(gòu)造函數(shù)首先是將參數(shù)player_manager和factory描述的StreamTextureFactoryImpl對(duì)象和RendererMediaPlayerManager對(duì)象分別保存在成員變量player_manager_和stream_texture_factory_中。WebMediaPlayerAndroid類的構(gòu)造函數(shù)接下來(lái)又會(huì)做兩件事情:1.調(diào)用上述RendererMediaPlayerManager對(duì)象的成員函數(shù)RegisterMediaPlayer將當(dāng)前正在創(chuàng)建的WebMediaPlayerAndroid對(duì)象保存在其內(nèi)部,并且為其分配一個(gè)ID。以后通過(guò)這個(gè)ID就可以在該RendererMediaPlayerManager對(duì)象中找到當(dāng)前正在創(chuàng)建的WebMediaPlayerAndroid對(duì)象。2.調(diào)用另外一個(gè)成員函數(shù)TryCreateStreamTextureProxyIfNeeded創(chuàng)建一個(gè)SurfaceTexture,以便后面可以用來(lái)接收Android平臺(tái)的MediaPlayer的解碼輸出。關(guān)于WebMediaPlayerAndroid類的成員函數(shù)TryCreateStreamTextureProxyIfNeeded創(chuàng)建SurfaceTexture的過(guò)程,我們?cè)诮酉聛?lái)一篇文章中分析<video>標(biāo)簽的視頻渲染過(guò)程時(shí)再分析。這一步執(zhí)行完成之后,運(yùn)行在Render進(jìn)程中的Content模塊就創(chuàng)建了一個(gè)類型為WebMediaPlayerAndroid的播放器接口。這個(gè)播放器接口會(huì)返回給WebKit層的WebMediaPlayerClientImpl類的成員函數(shù)load。WebMediaPlayerClientImpl類的成員函數(shù)load獲得了這個(gè)播放器接口之后,就會(huì)調(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_);}}這個(gè)函數(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封裝在一個(gè)MediaSourceDelegate對(duì)象中,然后通過(guò)這個(gè)MediaSourceDelegate對(duì)象來(lái)獲得要播放的視頻的元數(shù)據(jù)。有了要播放的視頻的元數(shù)據(jù)之后,就可以調(diào)用WebMediaPlayerAndroid類的成員函數(shù)InitializePlayer初始化當(dāng)前正在處理的播放器。我們假設(shè)當(dāng)前要播放的視頻的URL是一個(gè)普通的URL,它描述的媒體流的元數(shù)據(jù)要通過(guò)一個(gè)MediaInfoLoader對(duì)象從網(wǎng)絡(luò)上下載回來(lái)。下載完成后,WebMediaPlayerAndroid類的成員函數(shù)DidLoadMediaInfo會(huì)被調(diào)用,它的實(shí)現(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);}這個(gè)函數(shù)定義在文件external/chromium_org/content/renderer/media/android/webmediaplayer_android.cc中。WebMediaPlayerAndroid類的成員函數(shù)DidLoadMediaInfo會(huì)用下載回來(lái)的視頻元數(shù)據(jù)初始化當(dāng)前正在處理的播放器。這同樣是通過(guò)調(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);}這個(gè)函數(shù)定義在文件external/chromium_org/content/renderer/media/android/webmediaplayer_android.cc中。從前面的分析可以知道,WebMediaPlayerAndroid類的成員變量player_manager_指向的是一個(gè)RendererMediaPlayerManager對(duì)象。WebMediaPlayerAndroid類的成員函數(shù)InitializePlayer調(diào)用這個(gè)RendererMediaPlayerManager對(duì)象的成員函數(shù)Initialize對(duì)當(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));}這個(gè)函數(shù)定義在文件external/chromium_org/content/renderer/media/android/renderer_media_player_manager.cc中。RendererMediaPlayerManager對(duì)象的成員函數(shù)Initialize向Browser進(jìn)程發(fā)送一個(gè)類型為MediaPlayerHostMsg_Initialize的IPC消息,用來(lái)請(qǐng)求Browser進(jìn)程為當(dāng)前正在處理的類型為WebMediaPlayerAndroid的播放器創(chuàng)建一個(gè)由Android平臺(tái)實(shí)現(xiàn)的播放器。Browser進(jìn)程是通過(guò)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;}這個(gè)函數(shù)定義在文件external/chromium_org/content/browser/media/media_web_contents_observer.cc中。MediaWebContentsObserver類的成員函數(shù)OnMediaPlayerMessageReceived會(huì)將類型為MediaPlayerHostMsg_Initialize的IPC消息分發(fā)給運(yùn)行在Browser進(jìn)程中的一個(gè)BrowserMediaPlayerManager對(duì)象的成員函數(shù)OnInitialize處理。這個(gè)BrowserMediaPlayerManager對(duì)象負(fù)責(zé)管理在Browser進(jìn)程中創(chuàng)建的播放器實(shí)例,它與運(yùn)行在Render進(jìn)程中的RendererMediaPlayerManager對(duì)象是對(duì)應(yīng)的,不過(guò)后者用來(lái)管理在Render進(jìn)程中創(chuàng)建的播放器實(shí)例。BrowserMediaPlayerManager類的成員函數(shù)OnInitialize的實(shí)現(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);}這個(gè)函數(shù)定義在文件external/chromium_org/content/browser/media/android/browser_media_player_manager.cc中。BrowserMediaPlayerManager類的成員函數(shù)OnInitialize主要是調(diào)用成員函數(shù)CreateMediaPlayer創(chuàng)建一個(gè)類型為MediaPlayerBridge的播放器實(shí)例,并且調(diào)用另外一個(gè)成員函數(shù)AddPlayer將這個(gè)播放器實(shí)例保存在內(nèi)部。BrowserMediaPlayerManager類的成員函數(shù)CreateMediaPlayer的實(shí)現(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. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論