chromium 视频播放逻辑梳理(chromium41)


       作为浏览器,访问网络资源,除了文本网页,再就是音视频资源了。随着互联网的发展,视频资源除了提供让用户学习、娱乐的资源外,在当今时代,还演示着传播实时咨讯的角色。

趁着清明节,用一到两个blog,来说说chromium对于视频播放这块逻辑。


对于WebKit(chromium维护的版本更名为blink),解析到Video标签、Audio 标签时,会分别创建HTMLVideoElement和HTMLAudioElement。这两个类有共同的父类HTMLMediaElement。

        这篇blog,先来介绍下对于视频播放MediaPlayer相关逻辑。下个blog来说说对于Video标签的MediaControls。

     

关于MediaPlayer。实际上是个概念。在WebKit中,有MediaPlayer这个对象,且在content api中有对应的平台实现,WebMediaPlayerAndroid。而对于Android系统来讲,有个播放器内核。即MediaPlayer的具体实现。在android系统源码的Java层,有MediaPlayer.java来暴露相关的接口。

       一.  MediaPlayer(blink中)的创建。


JS invoke(网页JS调用)

       HTMLMediaElement::load()

      HTMLMediaElement::prepareForLoad()

      HTMLMediaElement::createMediaPlayer()

     在函数:HTMLMediaElement::createMediaPlayer()中,有代码:

        m_player = MediaPlayer::create(this);

     这里的MediaPlayer。是blink中的概念MediaPlayer 。这个类在文件platform/graphics/media/MediaPlayer.h中。

    关于MediaPlayer类,在blink中还有个子类:WebMediaPlayerClientImpl。 

    ==========================================================

  二.  WebMediaPlayer的创建

   说到上面的逻辑,但是我们还没有看到对系统MediaPlayer的调用。接着我们来看看对系统MediaPlayer调用这块。

   还是再从HTMLMediaElement讲起。

    

HTMLMediaElement::load()
HTMLMediaElement::loadInternal()
HTMLMediaElement::selectMediaResource()
HTMLMediaElement::loadResource
HTMLMediaElement::startPlayerLoad()

在方法:HTMLMediaElement::startPlayerLoad的函数体中有代码:

m_player->load(loadType(), requestURL, corsMode()); 
这个load的实现是在WebMediaPlayerClientImpl.cpp中。

void WebMediaPlayerClientImpl::load(WebMediaPlayer::LoadType loadType, const WTF::String& url, WebMediaPlayer::CORSMode corsMode)
{
    ASSERT(!m_webMediaPlayer);

    // FIXME: Remove this cast
    LocalFrame* frame = mediaElement().document().frame();

    WebURL poster = m_client->mediaPlayerPosterURL();

    KURL kurl(ParsedURLString, url);
    m_webMediaPlayer = createWebMediaPlayer(this, kurl, frame, HTMLMediaElementEncryptedMedia::contentDecryptionModule(mediaElement()));
    if (!m_webMediaPlayer)
        return;

#if ENABLE(WEB_AUDIO)
    // Make sure if we create/re-create the WebMediaPlayer that we update our wrapper.
    m_audioSourceProvider.wrap(m_webMediaPlayer->audioSourceProvider());
#endif

    m_webMediaPlayer->setVolume(mediaElement().effectiveMediaVolume());

    m_webMediaPlayer->setPoster(poster);

    m_webMediaPlayer->load(loadType, kurl, corsMode);

    if (mediaElement().isFullscreen())
        m_webMediaPlayer->enterFullscreen();
}


这里会调用同文件方法:createWebMediaPlayer

static PassOwnPtr<WebMediaPlayer> createWebMediaPlayer(WebMediaPlayerClient* client, const WebURL& url, LocalFrame* frame, WebContentDecryptionModule* initialCdm)
{
    
    WebLocalFrameImpl* webFrame = WebLocalFrameImpl::fromFrame(frame);

    if (!webFrame || !webFrame->client())
        return nullptr;
    return adoptPtr(webFrame->client()->createMediaPlayer(webFrame, url, client, initialCdm));
}

WebFrameClient的对象是content api中的RenderFrameImpl。

接着看调用逻辑

RenderFrameImpl::createMediaPlayer
RenderFrameImpl::CreateAndroidWebMediaPlayer


在函数CreateAndroidWebMediaPlayer中,会创建WebMediaPlayerAndroid对象和RendererMediaPlayerManager对象。

我们看看WebMediaPlayerAndroid类,是blink::WebMediaPlayer的子类。


三。系统MediaPlayer创建调用逻辑

 1. content api主要对象逻辑梳理

   我们在二中提到:

   WebMediaPlayerClientImpl::load 函数。二中,我们主要看了WebMediaPlayer的创建过程,即代码:

      m_webMediaPlayer = createWebMediaPlayer(this, kurl, frame, HTMLMediaElementEncryptedMedia::contentDecryptionModule(mediaElement()));

   的执行。这里,我们再看看后面m_webMediaPlayer->setVolume(mediaElement().effectiveMediaVolume());的执行。

  这个load的具体实现,就是content api中的WebMediaPlayer_android.cc中函数:WebMediaPlayerAndroid::setVolume的执行。

void WebMediaPlayerAndroid::setVolume(double volume) {
  DCHECK(main_thread_checker_.CalledOnValidThread());
  LOG(INFO)<<"vnbo0401 WebMediaPlayerAndroid::setVolume volume is %f "<<volume;
  player_manager_->SetVolume(player_id_, volume);
}


 WebMediaPlayerAndroid对象中维护着一个RenderMediaPlayerManager的对象。  

 我们看看RendererMediaPlayerManager::SetVolume函数。

void RendererMediaPlayerManager::SetVolume(int player_id, double volume) {
  Send(new MediaPlayerHostMsg_SetVolume(routing_id(), player_id, volume));
}


这里发送了IPC通讯信息。消息的处理是在content api中的MediaWebContentsObserver对象中。

    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetVolume,
                        GetMediaPlayerManager(render_frame_host),
                        BrowserMediaPlayerManager::OnSetVolume)

在MediaWebContentsObserver对象中,管理着所有的BrowserMediaPlayerManager对象。

BrowserMediaPlayerManager* MediaWebContentsObserver::GetMediaPlayerManager(
    RenderFrameHost* render_frame_host) {
  LOG(INFO)<<"vnbo0401 MediaWebContentsObserver::GetMediaPlayerManager";
  uintptr_t key = reinterpret_cast<uintptr_t>(render_frame_host);
  if (!media_player_managers_.contains(key)) {
    LOG(INFO)<<"vnbo0401 MediaWebContentsObserver::GetMediaPlayerManager 1 new BrowserMediaPlayerManager";
    media_player_managers_.set(
        key,
        make_scoped_ptr(BrowserMediaPlayerManager::Create(render_frame_host)));
  }
  return media_player_managers_.get(key);
}

通过这里,我们可以看出不同的BrowserMediaPlayerManager对象是通过RenderFrameHost对象来查找的。

   总结:上面这段逻辑主要说了,RenderMediaPlayerManager对象、BrowserMediaPlayerManager对象、WebMediaPlayer对象之间的联系。

  blink内核中的WebMediaPlayer对象,含有成员变量RenderMediaPlayerManager,而RenderMediaPlayerManager通过IPC联系MediaWebContentsObserver;

   MediaWebContentsObserver对象管理BrowserMediaPlayerManager对象。

  

  2. chromium media api相关对象创建与逻辑梳理

     视频播放模块是android系统中主要模块之一,也就是我们平时所讲的MediaPlayer(狭义的MediaPlayer,文中之前提到的MediaPlayer是广义的MediaPlayer)。这里api会调用系统MediaPlayer。我们来梳理下这块逻辑

    之前的逻辑梳理中,我们只看到了BrowserMediaPlayerManager对象的创建。BrowserMediaPlayerManager类是media api中MediaPlayerManager类的子类。

    BrowserMediaPlayerManager主要职责就是管理media api中的MediaPlayerAndroid对象。

    

WebMediaPlayerClientImpl::load
WebMediaPlayerAndroid::load
WebMediaPlayerAndroid::InitializePlayer
RendererMediaPlayerManager::Initialize
××××××IPC××××××
BrowserMediaPlayerManager::OnInitialize

在函数中OnInitialize中调用同类中函数:BrowserMediaPlayerManager::CreateMediaPlayer。这里创建的对象是media api中MediaPlayerBridge对象。MediaPlayerBridge类是media api中MediaPlayerAndroid的子类。

MediaPlayerBridge对象的职责是负责chromium kernel与Android系统的MediaPlayer打交道。

MediaPlayerBridge通过JNI调用MediaPlayerBridge的java对象联系。MediaPlayerBridge.java调用了系统的MediaPlayer.java

另外,media api中重写了MediaPlayerListener.java。 MediaPlayerListener通过JNI与C++对象MediaPlayerListener联系。C++对象MediaPlayerListener,是在MediaPlayerAndroid中构造函数中创建。

MediaPlayerAndroid::MediaPlayerAndroid(
    int player_id,
    MediaPlayerManager* manager,
    const RequestMediaResourcesCB& request_media_resources_cb,
    const GURL& frame_url)
    : request_media_resources_cb_(request_media_resources_cb),
      player_id_(player_id),
      manager_(manager),
      frame_url_(frame_url),
      weak_factory_(this) {
        LOG(INFO)<<"vnbo0401 MediaPlayerAndroid::MediaPlayerAndroid";
  listener_.reset(new MediaPlayerListener(base::MessageLoopProxy::current(),
                                          weak_factory_.GetWeakPtr()));
}


现在,我们就梳理从video元素开始执行load函数之后,进行的MediaPlayer的创建的所有逻辑。通过这块逻辑,我们也可以看出blink内核与content api等打交道,采用XXXclient、 WebXXX的设计方式,实现接口的暴漏。




       


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值