Media-mojo

media/mojo

このフォルダにはMOJOインターフェース、クライアントそして実装が含まれている。これはコア「メディア」ターゲットを拡張しプロセス外での動作をサポートする。Media Playerやメトリクス(WatchTime)などが含まれる。

メディアプレイヤー

メディアコンポーネント

メディアプレイヤー(WebMediaPlayer)はChromiumでHTML5の<video>再生をサポートする。機能は多くのメディアコンポーネントに分けられている(すわなちメディアレンダラー、音声デコーダー、映像デコーダーそしてコンテント暗号解除モジュール(CDM))。CDMは保護されたコンテントで必要である。詳しくは文書メディア?を参照。

大部分のHTML5メディアプレイヤースタックと暗号メディア拡張(EME)スタックはサンドボックス化されたレンダラープロセス内にある(セキュリティのため)ため、いくつかのメディアコンポーネントは他のプロセスで実行されなければならない。例えば以下:

  • ハードウェアベースのメディアレンダラー。この場合音声や映像のデコードとレンダリングはハードウェアで行われるためサンドボックス内では実行できない。
  • ハードウェアベースの映像デコーダ。この場合はハードウェアのデコードライブラリはサイドボックス内では利用できない。
  • Androidでは、メディアコンポーネントはAndroidJavaAPIに依存するため、サンドボックス内では利用できない。
  • サードパーティのコードが含まれるCDMは専用のサンドボックスプロセスが必要である。

よってプロセス外実行のメディアコンポーネントを提供する。

メディアプレイヤーMOJOインターフェース

メディアコンポーネントをリモートでホストするためにmojomインターフェースを使う。これらのインターフェースはメディアプレイヤーMOJOインターフェースと呼ばれる。それに対応するC++クラスと類似している。

  • media::Renderer -> media::mojom::Renderer
  • media::AudioDecoder -> media::mojom::AudioDecoder
  • media::VideoDecoder -> media::mojom::VideoDecoder
  • media::ContentDecryptionModule -> media::mojom::ContentDecryptionModule
  • media::Decryptor -> media::mojom::Decryptor

リモートメディアコンポーネントを有効にする

標準のクライアントとインターフェース実装はあらかじめ用意されている。例えばmedia::RendererではMojoRenderが実装し、呼び出しをmedia::mojom::RendererPtrに転送する。MojoRendererServicemedia::mojom::Rendererを実装し、media::Rederer実装をホストできる。

リモートメディアコンポーネントは簡単に有効にでき、現在のメディアパイプラインにシームレスに統合できる。やり方は単にgn引数のmojo_media_serviceで有効にしたいリモートメディアコンポーネントを指定すればよい。以下の例ではメディパイプラインはMojoRendererとMojoCdmを有効にする。

enable_mojo_media = true
mojo_media_services = ["renderer", "cdm"]

注:enable_mojo_mediaを最初に設定すること。

メディアMOJOインタフェースファクトリ

media::mojom::InterfaceFactoryCreateRenderer(),CreateCdm()のようなファクトリメソッドをもつ。メディアプレイヤーMOJOインタフェースを要求するために使われる。

レンダープロセスでは、それぞれのRenderFrameImplmedia::mojom::InterfaceFactoryPtrをもち、当該プロセスのためのメディアプレイヤーMOJOインタフェースをブラウザプロセスから要求する。ブラウザプロセスでは、それぞれのRenderFrameHostImplMediaInterfaceProxyを所有し、これはmedia::mojom::IntrefaceFactoryを実装する。

MediaInterfaceProxyはメディアプレイヤーMOJOインタフェース要求の中心ハブである。デフォルトではすべてのリクエストはMediaServiceに転送される。しかしより複雑な場合や特別な場合を想定した柔軟性ももっている。例えば、デスクトッププラットフォームでは、CDMライブラリが有効なとき、media::mojom::ContentDecryptionModule要求はそれ専用のユーティリティプロセスで動作しているCdmServiceに転送される。他の例としてアンドロイドでは、media::mojom::Renderer要求はRenderFrameHostImplで扱われ、ブラウザプロセス内にMediaPlayerRendererを作成する(設定でMediaServiceをGPUプロセスで動かすようにしていてもそうなる)。

注:media::mojom::InterfaceFactoryインターフェースはMediaInterfaceProxyMediaService間の通信で再利用される(以下参照)。

メディアサービス

メディアサービスはmojoのservice_manager::ServiceでメディアプレイヤーMOJOインタフェースを実装する。いくつかのの利点がある。

柔軟なプロセスモデル

プラットフォームやプロダクトの違いにより、リモートメディアコンポーネントをどこで実行すべきかに違いがある。例えばハードウェアデコーダは通常はGPUプロセスで動くべきである。ServiceManagerContextによりservice_manager::Serviceの実行場所を選択できる。すなわちインプロセス(ブラウザ)かプロセス外(ユーティリティ)かあるいはGPUプロセスかを選択できる。よってMediaServiceを使うことにより、リモートメディアコンポーネントをChromiumのプロセスタイプ(ブラウザ/ユーティリティ/GPU)でサポートするのが容易である。この設定はgn引数のmojo_media_hostで行うことができる。

mojo_media_host = "browser" or “gpu” or “utility”

メディアサービスはkMediaServiceNameを使ってServiceManagerContext内で登録される。mojo_media_hostによりどのプロセスでサービスが登録され実行されるかが決定される。

異なるメディアコンポーネントを接続する。

いくつかのリモートメディアコンポーネントは他のコンポーネントに依存している。例えばレンダラーや音声映像デコーダが暗号ストリームを扱うにはCDMが必要である。通常はSetCdm()呼び出しでレンダラなどをCDMと接続する。もし、レンダラインターフェースとCDMインタフェースが別々にホストされていたら、SetCdm()呼び出しを実装するのが難しくなるだろう。その両サイドを知るオブジェクトが必要になる。メディアサービスはこれを内部的に処理し、そのようなオブジェクトとして振る舞う。車輪の再開発は必要ない。詳しくは以下を参照。

MojoMediaClientによるカスタマイズ

MediaServiceはプロセス外メディアコンポーネントをホストするのに必要なすべての機能を提供する。しかしメディアコンポーネント自体は提供しない。それは具体的なメディアコンポーネント実装を提唱するのはクライアントの役割である。

MojoMediaClientインターフェースはMediaServiceクライアントがメディアコンポーネントの実装を提供する方法を提供する。MediaServiceが作成されるとき、MojoMediaClientを渡せばMediaServiceは作成方法を知ることができる。

例えばChromeCastはMediaServiceを使ってメディアレンダラとCDMをブラウザプロセス内でホストし、CastRendererCastCdmCastMojoMediaClient経由で提供している。すべての状況でこのオーバーライド機構を使うわけではない。

サイト孤立化

Blinkでは、メディアエレメントとEMEメディアキーはどちらもWebLocalFrameに属している。Chromiumでは、メディアプレイヤーとCDMはRenderFrameに属していると解釈される。レンダプロセスではこれは明確であるが、すべてのメディアコンポーネントを1つMediaServiceでホストすると(サービスマネージャは1プロセスに対して1つのサービスインスタンスしかサポートしない)フレーム境界が曖昧になる。互いにやりとりするメディアコンポーネントにとってこれは特に危険である。例えばfoo.comのレンダラはbar.netのCDMと同じMediaService内に存在することになる。bar.netのCDMがfoo.comレンダラの暗号解除に使われることは間違っている。

これを防ぐために、RenderFrame境界をシミュレートする追加レイヤーを導入している。MediaServiceは複数のInterfaceFactoryをホストし(RenderFrameごとに)、それぞれのIterfaceFactoryはそれが作成したメディアコンポーネントを管理する。

この理由からmedia::mojom::InterfaceFactoryインタフェースはMediaInterfaceProxyMediaService間の通信で再利用される。

注:media::mojom::InterfaceFactoryの責任を分割してどのインターフェイスがどこで使われているかを明確にするプランもある。

特別なプロセス外media::Renderer達

The media::Renderer interface is a simple API, which is general enough to capture the essence of high level media playback commands. This allows us to extend the functionality of the WebMediaPlayer via specialized renderers. Specifically, we can build a sub-component that encapsulates the complexities of an advanced scenario, write a small adapter layer that exposes the component as a media::Renderer, and embed it within the existing media::Pipeline state machine. Specialized Renderers reduce technical complexity costs, by limiting the scope of details to the files and classes need them, by requiring little control flow boilerplate, and by generally having little impact on the default paths that WebMediaPlayer uses most of the time.

Two examples of complex scenarios enabled by specialized renderers are: handling HLS playback on Android by delegating it to the Android Media Player (see MediaPlayerRenderer) and casting “src=” media from an Android phone to a cast device (see FlingingRenderer). Both of these examples have sub-components that need to live in the Browser process. We therefore proxy the MediaPlayerRenderer and FlingingRenderer to the Browser process, using the Mojo interfaces defined in renderer.mojom and renderer_extensions.mojom. This idea can be generalized to handle any special case Foo scenario as a specialized OOP FooRenderer.

The classes required to create a specialized OOP FooRenderer come in pairs, serving similar purposes in their respective processes. By convention, the FooRenderer lives in the target process and the FooRendererClient lives in the Renderer process. The MojoRenderer and MojoRendererService proxies media::Renderer and media::RendererClient calls to/from the FooRenderer[Client]. One-off commands and events that can't be expressed as a media::Renderer[Client] call are carried across process boundaries by renderer extensions instead (see renderer_extension.mojom). The FooRenderer[Client]Extension mojo interfaces are implemented by their respective FooRenderer[Client] instances directly. The FooRenderer[Client]Factory sets up the scenario specific boilerplate, and all of the mojo interface pointers/requests needed to talk to the other process. Interface pointers and requests are connected across process boundaries when mojom::InterfaceFactory::CreateFooRenderer() is called. The end result is illustrated below:

Page last modified on October 23, 2019, at 10:21 AM
Powered by PmWiki