[M120 Migration][HBBTV] Merge track and subtitle related patches
[platform/framework/web/chromium-efl.git] / media / mojo / README.md
1 # media/mojo
2
3 This folder contains mojo interfaces, clients and implementations that extend
4 the core "media" target to support most out-of-process use cases, including
5 Media Player, Metrics (WatchTime), etc.
6
7 Currently the “media” target does not depend on mojo, so that other applications
8 can use the “media” target without having to pull in mojo dependency.
9
10 [TOC]
11
12 ## Media Player
13
14 ### Media Components
15
16 Media Player (`WebMediaPlayer`) supports HTML5 \<video\> playback in Chromium.
17 Internally, it depends on many **media components** to perform some specific
18 tasks, e.g. **media renderer**, **audio decoder**, **video decoder**, and
19 **content decryption module** (CDM). A CDM is required for a *media renderer*,
20 *audio decoder* or *video decoder* to handle protected content. See more details
21 in the general [media documentation](/media).
22
23 While most of HTML5 media player stack and Encrypted Media Extensions (EME)
24 stack live in the sandboxed render process (e.g. for security reasons), there
25 are some cases where some media components must live in a different process.
26 For example:
27
28 * A hardware-based media renderer, where all audio/video decoding and rendering
29   happens in hardware, which is not accessible in the sandboxed render process.
30 * A hardware based video decoder, where the hardware decoding libraries are not
31   accessible in the sandboxed render process.
32 * On Android, a media component depends on Android Java API, which is not
33   accessible in the sandboxed render process.
34 * A CDM contains third-party code and should run in its own sandboxed process.
35
36 Here we provide a generic framework to support most out-of-process (OOP) media
37 component use cases in Chromium.
38
39 ### Media Player Mojo Interfaces
40
41 We use mojom interfaces as the transport layer of each media component to
42 support hosting them remotely. These interfaces are called **media player mojo
43 interfaces**. They are very similar to their C++ counterparts:
44
45 * `media::Renderer` -> `media::mojom::Renderer`
46 * `media::AudioDecoder` -> `media::mojom::AudioDecoder`
47 * `media::VideoDecoder` -> `media::mojom::VideoDecoder`
48 * `media::ContentDecryptionModule` -> `media::mojom::ContentDecryptionModule`
49 * `media::Decryptor` -> `media::mojom::Decryptor`
50
51 ### Enable Remote Media Components
52
53 Standard clients and implementations of these interfaces are provided. For
54 example, for `media::Renderer`, `MojoRenderer` implements `media::Renderer`, and
55 forwards calls to a `media::mojom::RendererPtr`. `MojoRendererService`
56 implements `media::mojom::Renderer`, and can host any `media::Renderer`
57 implementation.
58
59 Remote media components can be easily enabled and seamlessly integrated in the
60 current media pipeline. Simply set the gn argument `mojo_media_services` to
61 specify which remote media components you want to enable. For example, with the
62 following gn arguments, the media pipeline will enable `MojoRenderer` and
63 `MojoCdm`:
64 ```
65 mojo_media_services = ["renderer", "cdm"]
66 ```
67
68 ### Media Mojo Interface Factory
69
70 `media::mojom::InterfaceFactory` has factory methods like `CreateRenderer()`,
71 `CreateCdm()` etc. It is used to request media player mojo interfaces.
72
73 In the render process, each `RenderFrameImpl` has a
74 `mojo::PendingRemote<media::mojom::InterfaceFactory>` which is used to request
75  all media player mojo interfaces for that frame from the browser process. In
76 the browser process, each `RenderFrameHostImpl` owns a `MediaInterfaceProxy`,
77 which implements `media::mojom::InterfaceFactory`.
78
79 `MediaInterfaceProxy` is a central hub for handling media player mojo interface
80 requests. By default it will forward all the requests to the
81 [`MediaService`](#MediaService). But it also has the flexibility to handle some
82 special or more complicated use cases. For example:
83 * On desktop platforms, when library CDM is enabled, the
84   `media::mojom::ContentDecryptionModule` request will be forwarded to the
85   [`CdmService`](#CdmService) running in its own CDM (utility) process.
86 * On Android, the `media::mojom::Renderer` request is handled in the
87   `RenderFrameHostImpl` context directly by creating `MediaPlayerRenderer` in
88   the browser process, even though the `MediaService` is configured to run in
89   the GPU process.
90 * On Chromecast, the `media::mojom::Renderer` and
91   `media::mojom::ContentDecryptionModule` requests are handled by
92   [`MediaRendererService`](#MediaRendererService) which runs in the browser
93   process. The `media::mojom::VideoDecoder` request is handled by the default
94   `MediaService` which runs in the GPU process.
95
96 Note that `media::mojom::InterfaceFactory` interface is reused in the
97 communication between `MediaInterfaceProxy` and `MediaService` (see
98 [below](#Site-Isolation)).
99
100 ### Frameless Media Interface Factory
101
102 In addition to the main `MediaInterfaceProxy`, which handles requests from
103 ordinary media playback, `FramelessMediaInterfaceProxy` handles requests for
104 media cases that do not need or have a frame.
105
106 A frame is required for protected media playback because media decoding and
107 the CDM are associated within a frame.
108
109 The `FramelessMediaInterfaceProxy` is used by WebCodecs (which may be operating
110 in a worker context), by WebRTC, and for early querying of supported codecs.
111
112 ### MediaService
113
114 The MediaService is a mojo `service_manager::Service` that provides media player
115 mojo interface implementations. It comes with some nice benefits.
116
117 #### Flexible Process Model
118
119 Different platforms or products have different requirements on where the remote
120 media components should run. For example, a hardware decoder typically should
121 run in the GPU process. The `ServiceManagerContext` provides the ability to run
122 a service in-process (browser) or in the GPU process. Therefore, by using a
123 `MediaService`, it’s very easy to support hosting remote media components
124 interfaces in most common Chromium process types (Browser/GPU). This can by set
125 using the gn argument  `mojo_media_host`,
126 e.g.
127 ```
128 mojo_media_host = "browser" or “gpu”
129 ```
130
131 MediaService is registered in `ServiceManagerContext` using `kMediaServiceName`.
132 `mojo_media_host` is checked to decide in which process the service is
133 registered to run.
134
135 #### Connects Different Media Components
136
137 Some remote media components depend on other components to work. For example, a
138 Renderer, an audio decoder or a video decoder needs a CDM to be able to handle
139 encrypted streams. Typically there's a `SetCdm()` call to connect the renderer
140 or decoder with the CDM. If, for example, a Renderer interface and a CDM
141 interface are hosted separately, then it will be hard to implement the
142 `SetCdm()` call. It would require an object or entity that are aware of both
143 sides to be able to connect them. `MediaService` handles this internally, and is
144  actually serving as such an object or entity, so you don’t have to reinvent
145  the wheel. See more details [below](#Using-CdmContext).
146
147 #### Customization through MojoMediaClient
148
149 `MediaService` provides everything needed to host an OOP media component, but
150 it doesn’t provide the media component itself. It’s up to the client of
151 `MediaService` to provide the concrete media component implementations.
152
153 The `MojoMediaClient` interface provides a way for `MediaService` clients to
154 provide concrete media components’ implementations. When `MediaService` is
155 created, a `MojoMediaClient` must be passed in so that `MediaService` knows how
156 to create the media components.
157
158 For example, ChromeCast uses `MediaService` to host a media Renderer and a CDM
159 in the browser process, and it provides the `CastRenderer` and `CastCdm` through
160 `CastMojoMediaClient`, a `MojoMediaClient` implementation. Note that this
161 overriding mechanism is not implemented everywhere. It’s trivial to add the
162 support and we’ll only add it when we need it.
163
164 #### Site Isolation
165
166 In Blink, both media element and EME MediaKeys belong to a `WebLocalFrame`. In
167 Chromium, this translates to media player and CDM belonging to a `RenderFrame`.
168 In the render process, this is clear. However, when hosting all remote media
169 components in a single `MediaService` (service manager only supports one service
170 instance per process), the Frame boundary could get fuzzy. This will be
171 especially dangerous for media components that interact with each other.
172 For example, a Renderer from foo.com lives in the same MediaService instance as
173 a CDM from bar.net. It would be  wrong if the bar.net CDM is set on the foo.com
174 Renderer to handle decryption.
175
176 To prevent this from happening, we introduce an additional layer to simulate
177 the `RenderFrame` boundary. A MediaService hosts multiple InterfaceFactory
178 (one per `RenderFrame`), and each InterfaceFactory creates and manages media
179 components it creates.
180
181 For this reason, `media::mojom::InterfaceFactory` interface is reused in the
182 communication between `MediaInterfaceProxy` and `MediaService`.
183
184 > Note: there are plans to split apart the responsibilities of
185 `media::mojom::InterfaceFactory` to make it clear which interfaces are used
186 where.
187
188 #### Specialized Out-of-Process media::Renderers
189
190 The `media::Renderer` interface is a simple API, which is general enough to
191 capture the essence of high level media playback commands. This allows us to
192 extend the functionality of the `WebMediaPlayer` via **specialized renderers**.
193 Specifically, we can build a sub-component that encapsulates the complexities of
194 an advanced scenario, write a small adapter layer that exposes the component as
195 a `media::Renderer`, and embed it within the existing `media::Pipeline` state
196 machine. Specialized Renderers reduce technical complexity costs, by limiting
197 the scope of details to the files and classes need them, by requiring little
198 control flow boilerplate, and by generally having little impact on the default
199 paths that `WebMediaPlayer` uses most of the time.
200
201 Two examples of complex scenarios enabled by specialized renderers are: handling
202 HLS playback on Android by delegating it to the Android Media Player (see
203 `MediaPlayerRenderer`) and casting "src=" media from an Android phone to a cast
204 device (see `FlingingRenderer`). Both of these examples have sub-components that
205 need to live in the Browser process. We therefore proxy the
206 `MediaPlayerRenderer` and `FlingingRenderer` to the Browser process, using the
207 Mojo interfaces defined in renderer.mojom and renderer_extensions.mojom. This
208 idea can be generalized to handle any special case *Foo scenario* as a
209 **specialized OOP FooRenderer**.
210
211 The classes required to create a *specialized OOP FooRenderer* come in pairs,
212 serving similar purposes in their respective processes. By convention, the
213 `FooRenderer` lives in the target process and the `FooRendererClient` lives in
214 the Renderer process. The `MojoRenderer` and `MojoRendererService` proxies
215 `media::Renderer` and `media::RendererClient` calls to/from the
216 `FooRenderer[Client]`. One-off commands and events that can't be expressed as a
217 `media::Renderer[Client]` call are carried across process boundaries by
218 *renderer extensions* instead (see `renderer_extension.mojom`). The
219 `FooRenderer[Client]Extension` mojo interfaces are implemented by their
220 respective `FooRenderer[Client]` instances directly. The
221 `FooRenderer[Client]Factory` sets up the scenario specific boilerplate, and all
222 of the mojo interface pointers/requests needed to talk to the other process.
223 Interface pointers and requests are connected across process boundaries when
224 mojom::InterfaceFactory::CreateFooRenderer() is called. The end result is
225 illustrated below:
226
227 ![Communication diagram for an OOP Renderer](./renderer_extension_diagram.png)
228
229 To allow the creation and use of a FooRenderer within WebMediaPlayer, a
230 `FooRendererClientFactory` must be built and passed to the
231 `RendererFactorySelector`. The `RendererFactorySelector` must also be given a
232 way to query if we are currently in a scenario that requires the use of the
233 `FooRenderer`. When we enter a *Foo scenario*, cycling the `media::Pipeline` via
234 suspend()/resume() should be enough for the next call to
235 `RendererFactorySelector::GetCurrentFactory()` to return the
236 `FooRendererClientFactory`. When `RendererFactory::CreateRenderer()` is called,
237 the pipeline will receive a `FooRendererClient` as an opaque `media::Renderer`.
238 The default pipeline state machine will control the OOP `FooRenderer`.
239 When we exit the *Foo scenario*, cycling the pipeline once more should bring us
240 back into the right state.
241
242 #### Support Other Clients
243
244 `MediaService`, as a `service_manager::Service`, can be used by clients other
245 than the media player in the render process. For example, we could have another
246 (mojo) service that handles audio data and wants to play it in a media Renderer.
247 Since `MediaService` is a mojo service, it’s very convenient for any other mojo
248 service to connect to it through a `service_manager::mojom::Connector` and use
249 the remote media Renderer it hosts.
250
251 ### CdmService
252
253 Although `MediaService` supports `media::mojom::CDM`, in some cases (e.g.
254 library CDM on desktop) the remote CDM needs to run in its own process,
255 typically for security reasons. `CdmService` is introduced to handle this. It
256 also implements `service_manager::Service`, and is registered in
257 `ServiceManagerContext` using `kCdmServiceName`. Currently it’s always
258 registered to run in the utility process (with CDM sandbox type). `CdmService`
259 also has additional support on library CDM, e.g. loading the library CDM etc.
260 Note that `CdmService` only supports `media::mojom::CDM` and does NOT support
261 other media player mojo interfaces.
262
263 ### MediaRendererService
264
265 `MediaRendererService` supports `media::mojom::Renderer` and
266 `media::mojom::CDM`. It's hosted in a different process than the default
267 `MediaService`. It's registered in `ServiceManagerContext` using
268 'kMediaRendererServiceName`. This allows to run `media::mojom::VideoDecoder` and
269 `media::mojom::Renderer` in two different processes. Currently Chromecast use
270 this to support `CastRenderer` `CDM` in browser process and GPU accelerated
271 video decoder in GPU process. The main goals are:
272 1. Allow two pages to hold their own video pipeline simultaneously, because
273    `CastRenderer` only support one video pipeline at a time.
274 2. Support GPU accelerated video decoder for RTC path.
275
276 ### Mojo CDM and Mojo Decryptor
277
278 Mojo CDM is special among all media player mojo interfaces because it is needed
279 by all local/remote media components to handle encrypted buffers:
280
281 1. Local media components like `DecryptingDemuxerStream`,
282    `DecryptingAudioDecoder` and `DecryptingVideoDecoder`.
283 2. Remote media components hosted in `MediaService`, e.g. by
284    `MojoRendererService`, `MojoAudioDecoderService` and
285    `MojoVideoDecoderService`.
286
287 At the JavaScript layer, the media player and MediaKeys are connected via
288 [`setMediaKeys()`](https://w3c.github.io/encrypted-media/#dom-htmlmediaelement-setmediakeys).
289 This is implemented by `SetCdm()` in the render process.
290
291 A media component can use a CDM in two ways.
292
293 #### Using a Decryptor (via CdmContext)
294
295 Some CDM provides a `Decryptor` implementation, which supports decrypting
296 methods directly, e.g. `Decrypt()`, `DecryptAndDecode()` etc. Both the
297 `AesDecryptor` and library CDM support the `Decryptor` interface.
298
299 In the case of a remote CDM, e.g. hosted by `MojoCdmService` in `MediaService`
300 or `CdmService`, if the remote CDM supports the `Decryptor` interface, the
301 `MojoCdm` will also support the `Decryptor` interface, implemented by
302 `MojoDecryptor`, which set up a new message pipe to forward all `Decryptor`
303 calls to the `Decryptor` in the remote CDM.
304
305 #### Using CdmContext
306
307 In some cases the media component is set to work with a specific CDM. For
308 example, on Android, MediaCodec-based decoders (e.g. `MediaCodecAudioDecoder`)
309 can only use MediaDrm-based CDM via `MediaCryptoContext`. The media component
310 and the CDM must live in the same process because the interaction of these two
311 are typically happening deep at the OS level. In theory, they can both live in
312 the render process. But in practice, typically both the CDM and the media
313 component are hosted by the MediaService in a remote (e.g. GPU) process.
314
315 To be able to attach a remote CDM with a remote media component, each
316 `InterfaceFactoryImpl` instance (corresponding to one `RenderFrame`) in the
317 `MediaService` maintains a `MojoCdmServiceContext` that keeps track of all
318 remote CDMs created for the `RenderFrame`. Each remote CDM is assigned a unique
319 CDM ID, which is sent back to the `MojoCdm` in the render process. In the render
320 process, when `SetCdm()` is called, the CDM ID is passed to the local media
321 component (e.g. `MojoRenderer`), which is forwarded the remote media component
322 (e.g. `MojoRendererService`). The remote media component will talk to
323 `MojoCdmServiceContext` to get the `CdmContext` associated with the CDM ID, and
324 complete the connection.
325
326 ### Secure Auxiliary Services
327
328 Media components often need other services to work. In the render process, the
329 local media components get services from content layer through the `MediaClient`
330 interface. In `MediaService` and `CdmService`, remote media components get
331 services from the through **secure auxiliary services**.
332
333 Some services do require `RenderFrame` or user profile identity, e.g. file
334 system. Since media components all belong to a given `RenderFrame`, we must
335 maintain the frame identity when accessing these services for security reasons.
336 These services are called secure auxiliary services. `FrameServiceBase` is a
337 base class for all secure auxiliary services to help manage the lifetime of
338 these services (e.g. to handle navigation).
339
340 When a `MediaInterfaceProxy` is created, in addition to providing the
341 `media::mojom::InterfaceFactory`, the `RenderFrame` is provisioned with a
342 `media::mojom::FrameInterfaceFactory` that exposes these secure auxiliary
343 services on a per-frame basis. The `FrameInterfaceFactory` directly provides
344 services from //content, and it provides a way for //content embedders to
345 register additional auxiliary services via the `BindEmbedderReceiver()` method.
346
347 Currently only the remote CDM needs secure auxiliary services. This is a list of
348 currently supported services:
349
350 * `OutputProtection`: to check output protection status
351 * `PlatformVerification`: to check whether the platform is secure
352 * `CdmFileIO`: for the CDM to store persistent data
353 * `ProvisionFetcher`: for Android MediaDrm device provisioning
354
355 ### Security
356
357 In most cases, the client side runs in the renderer process which is the least
358 trusted. Also always assume the client side code may be compromised, e.g. making
359 calls in random order or passing in garbage parameters.
360
361 Due to the [Flexible Process Model](#Flexible-Process-Model), it's sometimes
362 hard to know in which process the service side runs. As a rule of thumb, assume
363 all service side code may run in a privileged process (e.g. browser process),
364 including the common supporting code like `MojoVideoDecoderService`, as well as
365 the concrete [Media Component](#Media-Components), e.g. MediaCodecVideoDecoder
366 on Android.  To know exactly which [Media Component](#Media-Components) runs in
367 which process in production, see [Adoption](#Adoption) below.
368
369 Also note that all the [Secure Auxiliary Services](#Secure-Auxiliary-Services)
370 are running in a more privileged process than the process where the media
371 components that use them run in. For example, all of the existing services run
372 in the browser process. They must defend against compromised media components.
373
374 ### Adoption
375
376 #### Android
377
378 * `MediaService` in the GPU process (registered in `GpuServiceFactory` with
379   `GpuMojoMediaClient`)
380 * `MojoCdm` + `MediaDrmBridge` (CDM)
381 * `MediaDrmBridge` uses mojo `ProvisionFetcher` service for CDM provisioning
382 * `MojoAudioDecoder` + `MediaCodecAudioDecoder`
383 * `MojoVideoDecoder` + `MediaCodecVideoDecoder` (in progress)
384 * HLS support:
385     * `MojoRenderer` + `MediaPlayerRenderer`
386     * NOT using `MediaService`. Instead, `MojoRendererService` is hosted by
387       `RenderFrameHostImpl`/`MediaInterfaceProxy`  in the browser process
388       directly.
389 * Flinging media to cast devices (RemotePlayback API):
390     * `MojoRenderer` + `FlingingRenderer`
391     * NOT using `MediaService`. Instead, `MojoRendererService` is hosted by
392       `RenderFrameHostImpl`/`MediaInterfaceProxy`  in the browser process
393       directly.
394
395 #### ChromeCast
396
397 * `MediaService` in the Browser process (registered in
398   `CastContentBrowserClient` with `CastMojoMediaClient`)
399 * `MojoRenderer` + `CastRenderer`
400 * `MojoCdm` + `CastCdm`
401
402 #### Desktop (ChromeOS/Linux/Mac/Windows)
403
404 * CdmService
405     * `CdmService` in the utility process (registered in `UtilityServiceFactory`
406       with `ContentCdmServiceClient`)
407     * `MojoCdm` + `CdmAdapter` + Library CDM implementation
408     * `CdmAdapter` uses various secure auxiliary services
409 * MediaService (in progress)
410     * `MediaService` in the GPU process (registered in `GpuServiceFactory` with
411       `GpuMojoMediaClient`)
412     * `MojoVideoDecoder` + hardware video decoders such as D3D11VideoDecoder
413
414 ## Other Services
415
416 > TODO(xhwang): Add documentation on other mojo services, e.g. remoting, etc.
417