版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Chromium为视频标签创建播放器的过
程分析
Chromium为视频标签〈video〉创建播放器的过程分析Chromium是通过WebKit解析网页
内容的。当WebKit遇到〈video〉标签时,就会创建一个播放器实例。WebKit是平台无关的,
而播放器实现是平台相关的。因此,WebKit并没有自己实现播放器,而仅仅是创建一个播
放器接口。通过这个播放器接口,可以使用平台提供的播放器来播放视频的内容。这就简化
\Chromium对视频标签的支持。本文接下来就分析Chromium为视频标签创建播放器的过
程。
以Android平台为例,它的SDK提供了一个MediaPlayer接口,用来播放视频。
Chromium的目标就是为网页中的每一个<video>标签创建一个MediaPlayer实例,如图I所
示:
图1Chromum为,deci>标签创建MediaPlayg的过程
首先,WebKit会为网页中的每一个vvideo>标签创建一个类型为HTMLMediaElement的DOM
节点。HTMLMediaElement类内部有一个WcbMcdiaPlaycrClientlmpl接口。这个
WebMediaPlayerClienllnipl接口指向的是一个运行在Render进程的Content模块中的一个
WebMediaPlayerAndroid对象。这些WebMediaPlayerAndroid对象归一个称为
RendererMediaPayerManager的对象管理。
Render进程中的每一个WebMediaPlayerAndroid对象,在Browser进程中都有一个
对应的WebMediaPlayerBricige对象。这些WebMediaPlayerBridge对象归一个称为
BrowscrMcdiaPaycrManagcr的对象管理。每一个WebMediaPlayerBridge对象在Java层中又
都对应有一个MediaPlayer•对象。这些MediaPlayer对象描述的就是Android平台提供的播放
器。
接下来,我们就从WebKit解析〈video〉标签的属性开始,分析Chromium为它们创
建MediaPlayer的过程,如下所示:
[cppjviewplaincopy在CODE上查看代码片派生到我的代码片
voidHTMLMediaElement::parseAttribute(constQualifiedName&name,constAtomicString&
value)
(
if(name==srcAtti){
//Triggerareload,aslongasthe'src'attributeispresent.
if(lvalue.isNullO){
scheduleDelayedAction(LoadMediaResource);
这个函数定义在文件
external/chromium_org/thinl_party/WebKil/Sourcc/core/htnil/HTMLMcdiaElcmcnt.cpp中。
WebKit为网页的每一个标签创建了相应的DOM节点之后,就会调用这个DOM节
点的成员函数parseAlrribule对它的属性进行解析。从文章中一文可以容易知道,WebKit为
<video>标签创建的DOM节点的实际类型为HTMLVideoElementoHTMLVideoElement类是
从HTMLMediaElement类继承下来的,WebKit是调用后者的成同员函数parseAttribute来解
析〈video〉的属性。
我们假设Wide。〉标签通过src属性设置了要播放的视频文件的URL。这时候
HTMLMediaElement类的成员函数parseAttribute就会调用另外一个成员函数
scheduleDelayedAction为<video>标签创建播放器,如下所示:
[epp]viewplaincopy在CODE上杳看代码片派生到我的代码片
voidHTMLMediaElement::scheduleDelayedAction(DelayedActionTypeactionType)
if((actionType&LoadMediaResource)&&!(m_pendingAc(ionFlags&
LoadMediaResource)){
prepareForLoad();
m_pendingActionFlags|=LoadMediaResource;
if(!m_loadTimer.isActive())
m_loadTiiTier.siarOneShoc(0,FROM_HERE);
1
这个函数定义在文件
exteinal/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp中。
从前面的调用过程可以知道,参数actionType的值等于LoadMediaResourceo这时候
如果HTMLMediaElement类的成员变量m_pendingAclionFlags的LoadMediaResource位等于
0,那么就说明WebKit还没有为当前正在解析的vvideo>标签创建过播放器接口。于是接下
来就会做两件事情:
I.调用另夕I'一个成员函数prepareForLoad开始为当前正在解析的〈video〉标签创建
图1所示的WebMediaPlayerClientlmpl接口:
2.将成员变量m_pendingActionFlags的LoadMediaResource位设置为1,表示WebKit
正在为当前正在:解析的<video>标签创建过播放器接口,避免接下来出现重复创建的情况。
HTMLMediaElement类的另外一个成员变量m」oadTimer描述的是一个定时器。如
果这个定时器还没有被启动,那么HTMLMediaElement类的成员函数scheduleDelayedAction
就会调用它的成员函数slarlOneShot马上进行启动。指定的启动时间单位为0,这意味着这
个定时器会马上超时。超时后它将会调用HTMLMediaElement类的成员函数loadTimcrFircd。
HTMLMediaElement类的成员函数loadTimerrired将会继续创建图1所示的
WebMediaPlayerAndroidWebMediaPlayerBridgeMediaPlayer接口。
接下来我们就先分析HTMLMediaElement类的成员函数prepareForLoad的实现,如
下所示:
[epp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidHTMLMediaElement::prepareForLoad()
createMediaPlayer();
这个函数定义在文件
ex(ernal/chromium_org/(hird_party/WebKit/Source/core/htnil/HTMLMediaElemenl.cpp中。
HTMLMediaElement类的成员函数prepareForLoad主要是调用另外•个成员函数
createMediaPlayer为当前正在解析的<video>标签创建一个WebMediaPlayerClientlmpl接口,
如下所示:
[epp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidHTMLMcdiaElcmcnt::crcatcMcdiaPlaycr()
ni_player=MediaPlayer::create(this);
层的播放器接口。
这一步执行完成之后,WebKit就为当前正在解析的<video>标签创建了一个类型为
WebMediaPlayerClienllnipl的播放器接口。回到前面分析的HTMLMediaElement类的成员函
数scheduleDelayedAction中,接下来它启动的定时器就会马上执行,也就
HTMLMediaElement类的成员函数loadTimerFired会马上被调用。
HTMLMediaElement类的成员函数loadTimerFired的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidHTMLMediaElemen(::loadTimerFired(Timer<HTMLMediaElement>*)
if(m_pendingActionFlags&LoadMediaResource){
if(m_loadState==LoadingFromSourceElement)
loadNcxtSoiirccChild();
else
loadlntcrnal();
)
m_pendingAc(ionFlag$=0;
}
这个函数定义在文件
exteinal/chromiuni_org/third_party/WebKit/Source/core/html/HTMLMediaElenient.cpp中。
前面分析的HTMLMediaElement类的成员函数scheduleDelayedAction已经将成员变
量m_pendingActionFlags的LoadMediaResource位设置为1。这时候HTMLMediaElement类
的成员函数loadTimerFired就会检查HTMLMediaElement类的另外一个成员变量
m_loadState的值是否等于LoadingFromSourceElement。如果等广,那么就说明当前正在解
析的〈video〉标签通过子元素〈source〉指定要播放的视频的URL。否则的话,就通过属性sre
指定要播放的视频的URL。
前面我们假定了当前正在解析的<vidco>标签通过属性sre指定要播放的视频的
URL,因此HTMLMediaElement类的成员函数loadTimerFired接下来就会调用成员函数
loadinternal继续为其创建其它的播放器接口,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidHTMLMediaElement:loadlntcrnalO
selectMediaResource();
这个函数定义在文件
ex(ernal/chromium_org/third_party/WzebKit/Source/core/htnil/HTMLMediaElernent.cpp中。
HTMLMediaElement类的成员函数loadlnternal调用另外一个成员函数
selectMediaResource为当前正在解析的<video>标签选择当前要播放的视频的URL“确定了
当前要播放的视频的URL之后,就会加载视频元数据。有了这些元数据之后,就可以为其
创建真正的播放器。
HTMLMediaElement类的成员函数selectMediaResource的实现如下所示:
[cpplviewplaincopy在CODE上查看代码片派生到我的代码片
voidHTMLMediaElement::selcctMcdiaResourcc()
enuniMode{attribute,children};
Modemode=attribute;
if(!fastiIasAttribu(e(srcAttr)){
//Otherwise,ifthemediaelementdoesnothaveasreattributebuthasasource
//elementchild,thenletmodebechildrenandletcandidatebe(hefirstsuch
//sourceelementchildintreeorder.
if(HTMLSourceElement*element
Traversal<HTMLSourceElement>::firstChild(*this)){
mode=children;
if(mode==attribute){
//Ifthesreattribute'svalueistheemptystring...jumpdowntothefailedstepbelow
KURLmediaURL=getNonEmptyURLAttribute(srcAttr);
loadResource(mediaURL,contentType,StringO);
return;
这个函数定义在文件
external/chroniiuin_org/third_party/WebKit/Source/core/htnil/HTMLMcdiaElcment.cpp中。
HTMLMediaElement类的成员函数selectMediaResource所做的事情就要确定是从当
前正在解析的<video>标签的src属性获得要加载的视频的URL,还是从它的了•元素(source〉
获得要加载的视频的URL。
如果当前正在解析的<video>标签设置了src属性,那么就会优先从这个属性获得要
加载的视频的URL。有了这个URL之后,HTMLMediaElement类的成员函数
selectMediaResource就会调用另外一个成员函数loadRcsourcc加载它所描述的视频的元数
据。
在我们这个情景中,当前正在解析的〈video〉标签设置了src属性。因此,接下来我
们就继续分析HTMLMediaElement类的成员函数loadResource的实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidHTMLMcdiaElcmcnt::loadRcsourcc(constK.URL&url,ContcntTypc&contcntTypc,const
String&keySystcm)
m_currentSrc=url;
boolattcmptLoad=true;
if(tocolIs(nicdiaSourccBlobProtocoi)){
if(isMediaStreamURL(url.stringO)){
m_usei-GestureRequiredForPlay=false;
}else{
m_mediaSource=HTMLMediaSource::lookup(url.string());
if(m_mediaSource){
if(!m_mcdiaSource->attachToElcmcnt(tliis)){
//ForgetourreferencetotheMediaSource,soweleaveitalone
//whileprocessingremainderofloadfailure.
m_mediaSource=nullptr;
attcmptLoad=false;
if(attempiLoad&&canLoadURL(ur),contentType,keySys(em)){
if(!m_havePreparedToPlay&&!autoplay()&&m_preload==MediaPlayer::None){
deferLoad();
}else{
starlPlayerLoadO;
这个函数定义在文件
external/chromium_org/third_party/WebKit/Source/core/html/HTMLMediaElemenl.cpp中。
HTMLMediaElement类的成员函数loadResource首先将当前要播放的视频的URL保
存在成员变量m_currentSrc中,接下来判断该URL的协议部分是否为“blob"。协议“blob”
是“BinaryLargeOBject”的缩写,表示一组二进制数据。例如,我们手头上有一组表示一
个Image的二进制数据,这时候可以调用URL.crcatcObjcctURL函数为这组二进制数据创建
一个blob协议地址,然后再将该地址设置为一个<img>标签的sre,这样就可以将图像显示
出来。
通过blob协议,还可以描述媒体数据。在WebKit中,媒体数据可以通过MediaSource
或者MediaStreamAPI描述。MediaSourceAPI的设计初衷是让JavaScript能动态产生媒体
流,然后交给〈video〉标签播放。MediaStreamAPI是为WebRTC设计的,不仅可以使用
<vidco>标签播放从本地摄像头采集的图像,还可以播放从网络发送过来的实时媒体流。关
于MediaSource和MediaSteamAPI的更详细信息,可以参考文章中和文章中这两篇文档。
如果当前要播放的视频的URL的协议部分为“blob",HTMLMediaElement类的成
员函数loadResource首先会检查它描述的是否是一个MediaStreamo如果是的话,那么就会
将HTMLMediaElement类的成员变量m_userGestureRequiredForPlay设置为false,表示后台
Tab网页的视频可以自动播放。Render进程有一个
udisable-gesture-requirement-for-media-playbackM选项。当这个选项的值设置为false时,
HTMLMediaElement类的成员变量m_userGestureRequiredForPlay就会被设置为true,表示
后台Tab网页的视频不可以自动播放。不过,如果要播放的视频是一个MediaStream,那么
不会受到此限制。关于Render进程的“disable-gesiure-requiremeni-「or-media-playback”启动
选项的更多信息,可以参考文章中一文。
如果当前要播放的视频的URL的协议部分为“blob”,但是它描述的不是一个Media
StreamAPI,那么HTMLMediaElement类的成员函数loadResource再检查它是否是一个Media
Sourceo如果是的话,就会将该MediaSource作为当前正在解析的〈video〉标签的播放源。
在这种情况卜,WebKit不需要从网络上下载媒体数据回来,只需要从指定的MediaSource
读取【可来就可以了。这时候木地变量auempiLoad的值会被设置为false。在其余情况下,木
地变量attemptLoad的值俣持为初始值true。
在本地变量attemptLoad的值为true的情况下,HTMLMediaElement类的成员函数
loadResource会调用另夕I、一'个成员函数canLoadURL继续检查当前要播放的视频的URL描
述的内容是否为多媒体数据,以及该多媒体使用的编码方式是否被支持。如果检查通过,
HTMLMediaElcmcnt类的成员函数loadResource再判断当前解析的<video>标签的是否需要
preload和autoplayo如果不需要,那么就会调用成员函数deferLoad延迟加载要播放的视频
的内容。否则的话,就会调用成员函数stailPlayerLoad马上加载要播放的视频的内容回来。
我们假设当前解析的<video>标签设置了autoplay,因此接下来我们就继续分析
HTMLMediaElenient类的成员函数startPlayerLoad的实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidHTMLMediaElemen(::startPlayerLoad()
KURLrequestURL=m_currentSrc;
m_playcr->load(loadType(),requcstURL,corsMode());
I
这个函数定义在文件
exteinal/chroniiuni_org/third_party/WebKit/Source/core/htnil/HTMLMediaElenient.cpp中。
从前面的分析可以知道,HTMLMediaElement类的成员变量m_player指向的是一个
WebMediaPlayerClienllmpl对象。HTMLMediaElement类的成员函数startPlayerLoad主要是
调用这个WcbMcdiaPlaycrClicntlmpl对象的成员函数load加载当前要播放的视频的内容。
WcbMcdiaPlaycrClientlmpl类的成员函数load的实现如卜所示:
[cpp]viewplaincopy在CODE1:查看代码片派生到我的代码片
voidWebMediaPlayerClientImpl::load(WebMediaPIayer::LoadTypeloadType,const
WTF::String&url,WebMediaPlayer::CORSModecorsMode)
KURLkurl(ParsedURLString,url);
ni_webMediaPlayer=createWebMediaPlayer(this,kurl,frame);
m_wcbMcdiaPlaycr->load(loadTypc,kurl,corsMode);
}
这个函数定义在文件
external/chromium_org/(hird_par(y/WebKit/Source/web/WebMediaPlayerClienlImpl.cpp中。
WebMediaPlayerClientlmpl类的成员函数load首先调用函数createWebMediaPiayer
请求运行在当前进程(Render进程)中的Comem模块创建一个播放器接口。这个Conleni
模块的播放器接口会保存在WebMediaPlayerClientlmpl类的成员变量m_webMediaPlayer中。
有了Content模块的播放器接口之后,WebMediaPlayerClientlmpI类的成员函数load再调用
它的成员函数load请求加载当前要播放的视频的内容。
接下来我们先分析Content模块的播放器接口的创建过程,也就是函数
createWebMediaPlayer的实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
staticPassOwnPtr<WebMediaPlayer>createWebMediaPlayer(WebMediaPlayerClient*client,
constWebURL&url,LocalFrame*frame)
(
WebLocalFramelmpl*webFrame=WebLocalFramelmpl::fromFrame(frame);
returnadoptPtr(webFraine->client()->createMediaPlayer(webFrame,url,client));
}
这个函数定义在文件
ex(ernal/chromium_org/third_party/WebKit/Source/web/WebMediaPlayei'ClientImpl.cpp中。
函数createWebMediaPlayer首先获得一个类型为blink::WcbFramcClient的接口。这
个接口是由WebKit的使用者设置给WebKit的,以便WcbKil可以通过它执行一些平台相关
的功能。在我们这个情景中,WebKit的使用者即为Render进程中的Content模块。Content
模块中的RenderFramelmpl类实现了该接口,并且会设置给WebKito因此,函数
createWebMediaPlayer接下来就会调用它的成员函数createMediaPlayer创建一个播放器接
□o
RenderFramelmpl类的成员函数crcatcMcdiaPlaycr的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
blink::WebMediaPlayer*RenderFramelmpl::createMediaPlayer(
blink::WebLocalFrame*frame,
constblink::WebURL&url,
blink::WebMediaPlayei'Client*client){
blink::WcbMcdiaStrcamwcb_strcam(
blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url));
if(!wcb_strcain.isNull())
returnCreateWebMediaPlayerForMediaStream(url,client);
#ifdefined(OS_ANDR()ID)
returnCreateAndroidWebMediaPlayer(url,client);
#clse
#cndif//dcfincd(OS_ANDROID)
)
这个函数定义在文件external/chromium_org/content/renderer/render_franie_in)pl.cc
中。
RenderFramelmpl类的成员函数createMediaPlayer首先判断当前要播放的视频的
URL描述的是否是一个MediaStream。如果是的话,那么就会调用成员函数
CreateWebMediaPlayerForMediaStream创建一个类型为WebMediaPlayerMS的播放器。这个
类型为WebMediaPlayerMS的播放器是在WebRTC中实现的。我们不考虑这种情况。
如果当前要播放的视频的URL描述的不是一个MediaStream,那么RenderFramelmpl
类的成员函数createMediaPlayer就会调用另夕I、一个成员函数CreateAndroidWebMediaPlayer
创建另外一种类型的播放器,如下所示:
fcpp]viewplaincopy在CODE上查看代码片派生到我的代码片
WcbMcdiaPlaycr*RcndcrFraniclmpi::CrcatcAndroidWcbMediaPlaycr(
constblink::WebURL&url,
WebMediaPlayerClient*client){
GpuChannelHost*gpu_channel_hosl=
RenderThreadImpl::current()->EstablishGpuChannelSync(
CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE);
scoped_refptr<S(rcamTextureractory>strcam_tcxturc_factory;
if(SynchronousComposiiorFactory*factory=
SynchronousCompositorFactory::GelInstance()){
stream_texture_factory=factory->CreateStreaniTextureFactory(routing_id_);
}else(
scoped_refptr<webkit::gpu::ContextProviderWebConteKt>context_provider=
RcndcrThrcadIinpl::currcnt()->SharcdMainThrcadContcxtProvidcr();
stream_texlure_faciory=SlreamTextureFactoryImp)::Create(
context_provider,gpu_channel_host,routing_id_);
)
returnnewWcbMcdiaPlaycrAndroid(
frame_,
client,
weak_factory_.GelWeakP(r(),
GetMediaPIayerManager(),
GetCdrnManager(),
stream_texture_factory,
RcndcrThrcadIinpl::currcnt()->GctMcdiaThrcadMessageLoopProxy(),
newRenderMediaLogO);
I
这个函数定义在文件extemal/chromiuin_org/content/renderer/render_frame_inipl.cc
中。
RenderFramelmpl类的成员函数CreateAndroidWebMediaPlayer首先是调用
RenderThreadlmpl类的成员函数EstablishGpuChannelSync为接下来要创建的播放器创建一
个到GPU进程的GPU通道。之所以要创建这个GPU通道,是因为Render要在GPU进程
中创建一个纹理,然后将这个纹理封装为一个SurfaceTexture,作为Android平台的
MediaPlayer的解码输出。也就是说,Render进程会通过这个SurfaceTexture接收Android平
台的MediaPlayer的解码输出,然后再以纹理的形式渲染在网贝上。GPU通道的创建过程,
也就是RenderThreadlinpl类的成员函数EstablishGpuChannelSync的实现,可以参考前面文
章中一文。
RenderFramelrnpl类的成员函数CreateAndroidWsbMediaPlayer最终创建的是一个类
型为WebMediaPlayerAndroid的播放器。创建这个类型为WebMediaPlayerAndroid的播放器
需要用到两个重要的对象。一个是StrcamTexturcFactory对象,另一个是
RendererMediaPlayerManage「对象。前者用来创建前面所述的纹理。后者用来管理在Render
进程中创建的播放器实例,
在WebView的情况下,调用SynchronousCompositorFactory类的静态成员函数
Getlnstance会获得一个SynchronousCompositorFactory对象。在这种情况下,上述
StreaniTextureFactory对象通过调用这个SynchronousCompositorFactory对象的成员函数
CrcatcStrcamTcxtureFactory获得。我们不考虑这一种情况。
在独立App的情况下,上述StreaniTextureFactory对象实际上是一个
SlreamTexlureFactorylmpl对象,它是通过调用StreamTexlureFactorylnipl类的静态成员函数
Create创建的,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
scopcd_rcfptr<StrcamTcxturcFactoryImpl>StrcamTcxturcFactoryhnpl::Crcatc(
constscoped_refptr<cc::ContextProvider>&context_provider,
GpuChannclHost*channel,
iniframe_id){
returnnewStreamTextureFactoryImpl(context_provider,channel,frame_id);
)
这个函数定义在文件
cxtcrnal/chromium_org/contcnt/rcndcrcr/mcdia/android/strcam_tcxturc_factory_iinpl.cc
从这里可以看到,StreamTextureFactoryImpI类论静态成员函数Create返回的是一个
StrcamTcxtureFactorylmpl对象。
回到前面分析的RenderFramelrnpl类的成员函数CreateAndroidWebMediaPlayer中,
它创建了一个StreamTextureFactoryImpI对象之后,接下来又会调用另外一个成员函数
GetMediaPlayerManager获得一个RendererMediaPlayerManager对象,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
RendererMediaPlayerManager*RcndcrFraincImpl::GctMcdiaPlaycrManagcr(){
if(!media_player_manager_){
media_player_inanager_=newRendererMediaPlayerManager(this);
returninedia_player_manager_;
这个函数定义在文件external/chromium_org/content/renderer/render_frame_impLcc
中。
从这里可以看到,RenderFramelmpI类的成员函数GetMediaPlayerManager返回的是
成员变量media_player_manager_指向的是一个RendererMediaPIayerManager对象。如果这个
RendererMediaPlayerManager对象还没有创建,那么就会先进行创建。
再回到前面分析的RenderFramelmpI类的成员函数CreateAndroidWebMediaPlayer
中,有了一个StreamTcxtureFactorjdinpl对象和一个RendererMediaPlayerManager对象之后,
它就会创建一个类型为WebMediaPlayerAndroid的播放器。
类型为WebMediaPlayerAndroid的播放器的创建过程,也就是
WebMediaPlayerAndroid类的构造函数的实现,如下所示:
[epp]viewplaincopy在CODE上查看代码片派生到我的代码片
WcbMcdiaPlaycr/Xndroid::\VcbMcdiaPlaycrAndroid(
blink:WcbFramc*frame,
blink::WcbMcdiaPlayci'Client*client,
base::WeakP(r<WebMediaPlayerDelegate>delegate,
RendererMediaPlayerManager*player_manager,
RendererCdmManager*cdm_manager,
scoped_refptr<StreamTextureFactory>factory,
constscopcd_rcfptr<basc::McssagcLoopProxy>&mcdia_loop,
media::MediaLog*media_log)
player_manager_(player_manager),
stream_texture_factory_(factory),
player_id_=player_manager_->RegislerMediaPlayer(lhis);
T^CreateStreamTextureProxylfNeededO;
)
这个函数定义在文件
cxtcrnal/chroinium_org/contcnt/rcndcrcr/mcdia/android/wcbmcdiaplaycr_android.cc「我。
WebMediaPlayerAndroid类的构造函数首先是将参数player_manager和factory描述
的StreamTextureFactorylmpl对象和RendererMediaPlayerManager对象分别保存在成员变量
player_manager_和siream」exture_faclory_中。
WebMediaPlayerAndroid类的构造函数接下来又会做两件事情:
I.调用上述RendererMcdiaPlayerManager对象的成员函数RcgisterMediaPlayer将当
前正在创建的WebMediaPlayerAndroid对象保存在其内部,并且为其分配一个ID。以后通
过这个ID就可以在该RendererMcdiaPlayerManager对象中找到当前正在创建的
WebMediaPlayerAndroid对象。
2.调用另外一个成员函数TryCreateStreainTextureProxylfNeeded创建一个
SurfaceTexture,以便后面可以用来接收Android平台的MediaPlayer的解码输出。
关于WebMediaPlayerAndroid类的成员函数TryCrealeStreamTextureProxyHNeeded创
建SurfaceTexture的过程,我们在接下来一篇文章中分析〈video,标签的视频渲染过程时再分
析。
这一步执行完成之后,运行在Render进程中的Conient模块就创建了一个类型为
WebMediaPlayerAndroid的播放器接口。这个播放器接口会返回给WebKit层的
WcbMcdiaPlaycrClicntlmpI类的成员函数load。WebMediaPlayerClientlmpl类的成员函数load
获得了这个播放器接口之后,就会调用它的成员函数load加载当前要播放的视频的内容,
如下所示:
[cpp]viewplaincopy在CODE1:查看代码片派生到我的代码片
voidWebMediaPlayerAndroid::load(LoadTypeload_type,
constblink::WebURL&url,
CORSModccors_modc){
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;
1
url_=url:
inidemuxer_clien(_id=0;
if(player_type_!=MEDIA_PLAYER_TYPE_URL){
RendererDemuxerAndroid*demuxer=
RenderThreadImpl::current()->ienderer_demuxer();
deniuxer_client_id=demuxer->GetNextDcmuxerClientID();
niedia_souice_delegate_.reset(newMediaSourceDelegate(
demuxer,demuxer_client_id,media_loop_,media_log_));
if(player_type_==MEDIA_PLAYER_TYPE_MEDIA_SOURCE){
media::SetDec^ptorReadyCBset_decryptor_ready_cb=
media::BindToCurrentLoop(
base::Bind(&WebMediaPlayerAndroid::SeiDecryp(orReadyCB,
weak_factory_.GetWeakPtr()));
media_source_delegate_->InitializeMediaSource(
base::Bind(&WebMediaPlayerAndroid::OnMediaSourceOpened,
ueak_factory_.GetWeakPtr()),
basc::Bind(&WcbMcdiaPlaycrAndroid::OnNccdKcy,
vveak_factory_.GclWcakPtr()),
set_decrjzptor_ready_cb,
base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
vveak_factory_.GetWeakPtr()),
base::Bind(&WebMediaPlayerAndroid::OnDurationChanged,
ueak_factory_.GetWeakPtr()));
InitializcPlaycr(url_,framc_->documcnt().firstPartyForCookics(),
true,demuxer_client_id);
}else(
info」oader_.reset(
newMediaInfbLoader(
url,
cors_modc,
base::Bind(&WebMediaPlayerAndroid::DidLoadMediaInfo,
wcak_factory_.GctWcakPtr())));
info」oader_->Slarl(frame_);
这个函数定义在文件
cxtcrnal/chromium_org/contcnt/rcndcrcr/mcdia/android/wcbincdiaplaycr_android.cc「我。
类型为WebMediaPlayerAndroid的播放器只能史理普通URL描述的媒体流,以及
BLOB协议描述的类型为MediaSource的媒体流,不能处理类型为MediaStream的媒体流
(需要由WebRTC处理)。
类型为MediaSource的媒体流数据直接从指定的MediaSource获得。
WebMediaPlayerAndroid类的成员函数load将该MediaSource封装在一个
MediaSourceDelegate对象中,然后通过这个McdiaSourceDclegate对象来获得要播放的视频
的元数据。有了要播放的视频的元数据之后,就可以调用WebMediaPlayerAndroid类的成员
函数InitializePlayer初始化当前正在处理的播放器。
我们假设当前要播放的视频的URL是一个普通的URL,它描述的媒体流的元数据
要通过一个MedialnfoLoader对象从网络上下载回来。下载完成后,WebMediaPlayerAndroid
类的成员函数DidLoadMedialnfo会被调用,它的实现如下所示:
[cpplviewplaincopy在CODE上查看代码片派生到我的代码片
voidWebMediaPlayerAndroid::DidLoadMediaInfo(
MediainfbLoader::Slatusstatus,
constGURL&redirected_url,
constGURL&first_party_for_cookies,
boolallow_stored_credentials){
InitializePlayer(
redirected_url,first_party_for_cookies,allow_stored_credentials,0);
这个函数定义在文件
exteinal/chromium_org/content/renderer/media/android/webmecliaplayer_android.cc中。
WebMediaPlayerAndroid类的成员函数DidLoadMedialnfo会用卜载回来的视频元数
据初始化当前正在处理的播放器。这同样是通过调用WebMediaPlayerAndroid类的成员函数
InitializePlayer进行的,如下所示:
fepp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidWcbMcdiaPlaycrAndroid::InitializcPlaycr(
constGURL&url,
constGURL&first_paiiy_for_cookies,
boolallow_stored_credenlials,
intdemuxer_client_id){
player_manager_->Initialize(
player_type_,player_id_,url,first_party_for_cookies,dcmuxcr_clicnt_id,
frame_->document(>.url(),allow_stored_credentials);
这个函数定义在文件
ex(ernal/chromium_org/content/renderer/media/android/webmediaplayer_android.cc中。
从前面的分析可以知道,WebMediaPlayerAndroid类的成员变量player_manager_指
向的是一个RendererMediaPlayerManager对象。WebMediaPlayerAndroid类的成员函数
InitializePlayer调用这个RendererMediaPlayerManager对象的成员函数Initialize对当前正在
处理的播放器进行初始化,如下所示:
[cpp]viewplaincopy在CODE1:查看代码片派生到我的代码片
voidRendererMediaPlayerManager::Initialize(
MediaPlayerHostMsg_Initialize_Typetype.
intplayer_id,
constGURL&url,
constGURL&first_party_for_cookies,
inidemuxer_client_id,
constGURL&frame_url,
boolallow_credentials){
MediaPlayerHostMsg_Initialize_Paramsmedia_player_params;
media_player_params.type=type;
media_player_params.player_id=player_id;
mcdia_playcr_params.dcmuxcr_clicnt_id=dcmuxcr_clicnt_id;
mcdia_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.albw_credentials=allow_credentials;
Send(newMediaPlayerHDstMsg_Initialize(routing_id().niedia_player_params));
)
这个函数定义在文件
cxtcrnal/chroniium_org/contcnt/rcndcrcr/mcdia/android/rcndcrcr_incdia_playcr_managcr.cc
RendererMediaPlayerManager^Initialize向Browser进程发送一个类型
为MediaPlayerHostMsg_Initialize的IPC消息,用来请求Browser进程为当前正在处理的类
型为WebMediaPlayerAndroid的播放器创建一个由Android平台实现的播放器。
Browser进程是通过McdiaWcbContcntsObscrvcr类的成员函数
OnMediaPlayerMessageReceived接收类型为MediaPlayerHostMsg_Initialize的IPC消息的,
如下所示:
[cpp]viewplaincopy在CODE1:查看代码片派生到我的代码片
boolMediaWebContentsObserver::OnMediaPlayerMessageReceived(
constIPC::Message&msg,
RcndcrFrameHost*rcndcr_framc_host){
boolhandled=true;
IPC_BEGIN_MESSAGE_MAP(McdiaWcbContcntsObscrvcr,msg)
IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize,
GelMediaPlayerManager(rendsr_frame_hosl),
IPC_MESSAGE_UNHANDLED(handled=false)
IPC_END_MESSAGE_MAP()
returnhandled;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- (零模)2026届广州市高三年级调研测试地理试卷(含答案及解析)
- 2025年福州大学附属省立医院高层次人才招聘备考题库及参考答案详解一套
- 2025年晋江市文化体育和旅游局公开招聘编外人员的备考题库参考答案详解
- 2025年代招某行政机关派遣制工作人员招聘备考题库及答案详解一套
- 2025重庆市永川区朱沱镇人民政府招聘非全日制公益性岗位人员10人备考考试试题及答案解析
- 2025年西安交通大学管理学院招聘(3人)备考笔试试题及答案解析
- 2025浙江杭州市拱墅区工大未来技术研究院招聘1人模拟笔试试题及答案解析
- 2025重庆海航国际食品有限公司招聘参考考试题库及答案解析
- 2025成都银行招聘总行专职信用审批人等岗位7人备考笔试题库及答案解析
- 2025年陕西建工控股集团有限公司招聘(4人)备考笔试试题及答案解析
- 2024秋期国家开放大学《国际法》一平台在线形考(形考任务1至5)试题及答案
- 电动机正反转控制电路安装调试教案
- (完整)初二数学(上)期末易错题、难题培优复习精心整
- 高压断路器和隔离开关的原理与选择
- 新生儿护士述职报告
- 手机短视频拍摄与剪辑智慧树知到课后章节答案2023年下哈尔滨职业技术学院
- 统编版语文五年级上册按要求改写句子过关练习(含答案)
- 人教版美术-装饰画教学课件
- NY/T 455-2001胡椒
- GB/T 18710-2002风电场风能资源评估方法
- 《家庭、私有制和国家的起源》课件
评论
0/150
提交评论