1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_ANDROID_MEDIA_CODEC_PLAYER_H_
#define MEDIA_BASE_ANDROID_MEDIA_CODEC_PLAYER_H_
#include "base/android/scoped_java_ref.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "base/time/default_tick_clock.h"
#include "media/base/android/demuxer_android.h"
#include "media/base/android/media_drm_bridge.h"
#include "media/base/android/media_player_android.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_export.h"
#include "media/base/time_delta_interpolator.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/android/scoped_java_surface.h"
// The MediaCodecPlayer class implements the media player by using Android's
// MediaCodec. It differs from MediaSourcePlayer in that it removes most
// processing away from the UI thread: it uses a dedicated Media thread to
// receive the data and to handle the commands.
// The player works as a state machine. Here are relationships between states:
//
// [ Paused ] ------------------------ (Any state)
// | | |
// | v v
// | <------------------[ WaitingForConfig ] [ Error ]
// |
// |
// | <----------------------------------------------
// | |
// [ Waiting for permission ] |
// | |
// | |
// v |
// [ Prefetching ] ------------------- |
// | | |
// | v |
// | <-----------------[ WaitingForSurface ] |
// v |
// [ Playing ] |
// | |
// | |
// v |
// [ Stopping ] --------------------------------> [ WaitingForSeek ]
// Events and actions for pause/resume workflow.
// ---------------------------------------------
//
// Start, no config:
// ------------------------> [ Paused ] -----------------> [ Waiting ]
// | StopDone: [ for configs ]
// | ^ | /
// | | | /
// | Pause: | | Start w/config: /
// | Permission denied: | | requestPermission /
// | | | /
// | | | /
// | | | /
// | | | / DemuxerConfigs:
// | | | / requestPermission
// | | | /
// | | | /
// | | v /
// | /
// | ------------------> [ Waiting for ] <--------/
// | | [ permission ]
// | | |
// | | |
// | | | Permission granted:
// | | | dec.Prefetch
// | | |
// | | |
// | | v
// | |
// | | [ Prefetching ] [ Waiting ]
// | | [ ] --------------> [ for surface ]
// | | | PrefetchDone, /
// | | | no surface: /
// | | | /
// | | | /
// | | StopDone w/ | /
// | | pending start: | PrefetchDone: /
// | | dec.Prefetch | dec.Start /
// | | | / SetSurface:
// | | | / dec.Start
// | | | /
// | | v /
// | | /
// | | [ Playing ] <----------/
// | |
// | | |
// | | |
// | | | Pause: dec.RequestToStop
// | | |
// | | |
// | | v
// | |
// ------------------------- [ Stopping ]
// Events and actions for seek workflow.
// -------------------------------------
//
// Seek: -- --
// demuxer.RequestSeek | |
// [ Paused ] -----------------------> | |
// [ ] <----------------------- | |--
// SeekDone: | | |
// | | |
// | | |
// | | |
// | | | Start:
// | | | SetPendingStart
// Seek: dec.Stop | | |
// SetPendingStart | | |
// demuxer.RequestSeek | | |
// [ Waiting for ] -----------------------> | | |
// [ permission ] <---------------------- | | | Pause:
// SeekDone | | | RemovePendingStart
// | w/pending start: | | |
// | requestPermission | Waiting | |
// | | for | | Seek:
// | | seek | | SetPendingSeek
// | | | |
// | Seek: dec.Stop | | |
// v SetPendingStart | | |
// demuxer.RequestSeek | | |
// [ Prefetching ] ----------------------> | | |
// | | |
// | | | |
// | PrefetchDone: dec.Start | | |
// | | | | SeekDone
// v | | | w/pending seek:
// | | | demuxer.RequestSeek
// [ Playing ] | | |
// | | |
// | | |<-
// | Seek: SetPendingStart | |
// | SetPendingSeek | |
// | dec.RequestToStop | |
// | | |
// | | |
// v | |
// | |
// [ Stopping ] -----------------------> | |
// StopDone -- --
// w/pending seek:
// demuxer.RequestSeek
namespace media {
class BrowserCdm;
class MediaCodecAudioDecoder;
class MediaCodecVideoDecoder;
class MEDIA_EXPORT MediaCodecPlayer : public MediaPlayerAndroid,
public DemuxerAndroidClient {
public:
// Typedefs for the notification callbacks
typedef base::Callback<void(base::TimeDelta, const gfx::Size&)>
MetadataChangedCallback;
typedef base::Callback<void(base::TimeDelta, base::TimeTicks)>
TimeUpdateCallback;
typedef base::Callback<void(const base::TimeDelta& current_timestamp)>
SeekDoneCallback;
typedef base::Callback<void(int)> ErrorCallback;
// For testing only.
typedef base::Callback<void(DemuxerStream::Type,
base::TimeDelta,
base::TimeDelta)> DecodersTimeCallback;
// For testing only.
typedef base::Callback<void(DemuxerStream::Type)> CodecCreatedCallback;
// Constructs a player with the given ID and demuxer. |manager| must outlive
// the lifetime of this object.
MediaCodecPlayer(int player_id,
base::WeakPtr<MediaPlayerManager> manager,
const RequestMediaResourcesCB& request_media_resources_cb,
scoped_ptr<DemuxerAndroid> demuxer,
const GURL& frame_url);
~MediaCodecPlayer() override;
// A helper method that performs the media thread part of initialization.
void Initialize();
// MediaPlayerAndroid implementation.
void DeleteOnCorrectThread() override;
void SetVideoSurface(gfx::ScopedJavaSurface surface) override;
void Start() override;
void Pause(bool is_media_related_action) override;
void SeekTo(base::TimeDelta timestamp) override;
void Release() override;
void SetVolume(double volume) override;
int GetVideoWidth() override;
int GetVideoHeight() override;
base::TimeDelta GetCurrentTime() override;
base::TimeDelta GetDuration() override;
bool IsPlaying() override;
bool CanPause() override;
bool CanSeekForward() override;
bool CanSeekBackward() override;
bool IsPlayerReady() override;
void SetCdm(BrowserCdm* cdm) override;
// DemuxerAndroidClient implementation.
void OnDemuxerConfigsAvailable(const DemuxerConfigs& params) override;
void OnDemuxerDataAvailable(const DemuxerData& params) override;
void OnDemuxerSeekDone(base::TimeDelta actual_browser_seek_time) override;
void OnDemuxerDurationChanged(base::TimeDelta duration) override;
// For testing only.
void SetDecodersTimeCallbackForTests(DecodersTimeCallback cb);
void SetCodecCreatedCallbackForTests(CodecCreatedCallback cb);
void SetAlwaysReconfigureForTests(DemuxerStream::Type type);
bool IsPrerollingForTests(DemuxerStream::Type type) const;
private:
// The state machine states.
enum PlayerState {
kStatePaused,
kStateWaitingForConfig,
kStateWaitingForPermission,
kStatePrefetching,
kStatePlaying,
kStateStopping,
kStateWaitingForSurface,
kStateWaitingForKey,
kStateWaitingForMediaCrypto,
kStateWaitingForSeek,
kStateError,
};
enum StartStatus {
kStartOk = 0,
kStartBrowserSeekRequired,
kStartCryptoRequired,
kStartFailed,
};
// Cached values for the manager.
struct MediaMetadata {
base::TimeDelta duration;
gfx::Size video_size;
};
// Information about current seek in progress.
struct SeekInfo {
const base::TimeDelta seek_time;
const bool is_browser_seek;
SeekInfo(base::TimeDelta time, bool browser_seek)
: seek_time(time), is_browser_seek(browser_seek) {}
};
// MediaPlayerAndroid implementation.
// This method requests playback permission from the manager on UI thread,
// passing total duration as an argiment. The duration must be known by the
// time of the call. The method posts the result to the media thread.
void RequestPermissionAndPostResult(base::TimeDelta duration) override;
// This method caches the data and calls manager's OnMediaMetadataChanged().
void OnMediaMetadataChanged(base::TimeDelta duration,
const gfx::Size& video_size) override;
// This method caches the current time and calls manager's OnTimeUpdate().
void OnTimeUpdate(base::TimeDelta current_timestamp,
base::TimeTicks current_time_ticks) override;
// Callback from manager
void OnPermissionDecided(bool granted);
// Callbacks from decoders
void RequestDemuxerData(DemuxerStream::Type stream_type);
void OnPrefetchDone();
void OnPrerollDone();
void OnDecoderDrained(DemuxerStream::Type type);
void OnStopDone(DemuxerStream::Type type);
void OnMissingKeyReported(DemuxerStream::Type type);
void OnError();
void OnStarvation(DemuxerStream::Type stream_type);
void OnTimeIntervalUpdate(DemuxerStream::Type stream_type,
base::TimeDelta now_playing,
base::TimeDelta last_buffered,
bool postpone);
// Callbacks from video decoder
void OnVideoCodecCreated();
void OnVideoResolutionChanged(const gfx::Size& size);
// Callbacks from CDM
void OnMediaCryptoReady(MediaDrmBridge::JavaObjectPtr media_crypto,
bool needs_protected_surface);
void OnKeyAdded();
void OnCdmUnset();
// Operations called from the state machine.
void SetState(PlayerState new_state);
void SetPendingStart(bool need_to_start);
bool HasPendingStart() const;
void SetPendingSeek(base::TimeDelta timestamp);
base::TimeDelta GetPendingSeek() const;
bool HasVideo() const;
bool HasAudio() const;
void SetDemuxerConfigs(const DemuxerConfigs& configs);
void RequestPlayPermission();
void StartPrefetchDecoders();
void StartPlaybackOrBrowserSeek();
StartStatus StartPlaybackDecoders();
StartStatus ConfigureDecoders();
StartStatus MaybePrerollDecoders(bool* preroll_required);
StartStatus StartDecoders();
void StopDecoders();
void RequestToStopDecoders();
void RequestDemuxerSeek(base::TimeDelta seek_time,
bool is_browser_seek = false);
void ReleaseDecoderResources();
// Helper methods.
void CreateDecoders();
bool AudioFinished() const;
bool VideoFinished() const;
base::TimeDelta GetInterpolatedTime();
static const char* AsString(PlayerState state);
// Data.
// Object for posting tasks on UI thread.
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
// Major components: demuxer, audio and video decoders.
scoped_ptr<DemuxerAndroid> demuxer_;
scoped_ptr<MediaCodecAudioDecoder> audio_decoder_;
scoped_ptr<MediaCodecVideoDecoder> video_decoder_;
// The state of the state machine.
PlayerState state_;
// Notification callbacks, they call MediaPlayerManager.
base::Closure request_resources_cb_;
TimeUpdateCallback time_update_cb_;
base::Closure completion_cb_;
base::Closure waiting_for_decryption_key_cb_;
SeekDoneCallback seek_done_cb_;
ErrorCallback error_cb_;
// A callback that updates metadata cache and calls the manager.
MetadataChangedCallback metadata_changed_cb_;
// We call the base class' AttachListener() and DetachListener() methods on UI
// thread with these callbacks.
base::Closure attach_listener_cb_;
base::Closure detach_listener_cb_;
// Error callback is posted by decoders or by this class itself if we cannot
// configure or start decoder.
base::Closure internal_error_cb_;
// Total duration reported by demuxer.
base::TimeDelta duration_;
// base::TickClock used by |interpolator_|.
base::DefaultTickClock default_tick_clock_;
// Tracks the most recent media time update and provides interpolated values
// as playback progresses.
TimeDeltaInterpolator interpolator_;
// Pending data to be picked up by the upcoming state.
gfx::ScopedJavaSurface pending_surface_;
bool pending_start_;
base::TimeDelta pending_seek_;
// Data associated with a seek in progress.
scoped_ptr<SeekInfo> seek_info_;
// Configuration data for the manager, accessed on the UI thread.
MediaMetadata metadata_cache_;
// Cached current time, accessed on UI thread.
base::TimeDelta current_time_cache_;
// For testing only.
DecodersTimeCallback decoders_time_cb_;
// DRM
MediaDrmBridge::JavaObjectPtr media_crypto_;
MediaDrmBridge* drm_bridge_;
int cdm_registration_id_;
// The flag is set when the player receives the error from decoder that the
// decoder needs a new decryption key. Cleared on starting the playback.
bool key_is_required_;
// The flag is set after the new encryption key is added to MediaDrm. Cleared
// on starting the playback.
bool key_is_added_;
base::WeakPtr<MediaCodecPlayer> media_weak_this_;
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<MediaCodecPlayer> media_weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MediaCodecPlayer);
};
} // namespace media
#endif // MEDIA_BASE_ANDROID_MEDIA_CODEC_PLAYER_H_
|