Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: media/base/android/media_codec_player.cc

Issue 2276343005: Delete MediaCodecPlayer, it's time! (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/base/android/media_codec_player.h"
6
7 #include <utility>
8
9 #include "base/barrier_closure.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/threading/thread.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "media/base/android/audio_media_codec_decoder.h"
17 #include "media/base/android/media_drm_bridge.h"
18 #include "media/base/android/media_player_manager.h"
19 #include "media/base/android/media_task_runner.h"
20 #include "media/base/android/video_media_codec_decoder.h"
21 #include "media/base/bind_to_current_loop.h"
22 #include "media/base/timestamp_constants.h"
23
24 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \
25 do { \
26 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
27 DCHECK(ui_task_runner_->BelongsToCurrentThread()); \
28 GetMediaTaskRunner()->PostTask( \
29 FROM_HERE, base::Bind(&MediaCodecPlayer::METHOD, media_weak_this_, \
30 ##__VA_ARGS__)); \
31 return; \
32 } \
33 } while (0)
34
35 namespace media {
36
37 // MediaCodecPlayer implementation.
38
39 MediaCodecPlayer::MediaCodecPlayer(
40 int player_id,
41 base::WeakPtr<MediaPlayerManager> manager,
42 const OnDecoderResourcesReleasedCB& on_decoder_resources_released_cb,
43 std::unique_ptr<DemuxerAndroid> demuxer,
44 const GURL& frame_url,
45 int media_session_id)
46 : MediaPlayerAndroid(player_id,
47 manager.get(),
48 on_decoder_resources_released_cb,
49 frame_url,
50 media_session_id),
51 ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
52 demuxer_(std::move(demuxer)),
53 state_(kStatePaused),
54 interpolator_(&default_tick_clock_),
55 pending_start_(false),
56 pending_seek_(kNoTimestamp),
57 cdm_registration_id_(0),
58 key_is_required_(false),
59 key_is_added_(false),
60 media_weak_factory_(this) {
61 DCHECK(ui_task_runner_->BelongsToCurrentThread());
62
63 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id;
64
65 completion_cb_ =
66 base::Bind(&MediaPlayerManager::OnPlaybackComplete, manager, player_id);
67 waiting_for_decryption_key_cb_ = base::Bind(
68 &MediaPlayerManager::OnWaitingForDecryptionKey, manager, player_id);
69 seek_done_cb_ =
70 base::Bind(&MediaPlayerManager::OnSeekComplete, manager, player_id);
71 error_cb_ = base::Bind(&MediaPlayerManager::OnError, manager, player_id);
72
73 attach_listener_cb_ = base::Bind(&MediaPlayerAndroid::AttachListener,
74 WeakPtrForUIThread(), nullptr);
75 detach_listener_cb_ =
76 base::Bind(&MediaPlayerAndroid::DetachListener, WeakPtrForUIThread());
77 metadata_changed_cb_ = base::Bind(&MediaPlayerAndroid::OnMediaMetadataChanged,
78 WeakPtrForUIThread());
79 time_update_cb_ =
80 base::Bind(&MediaPlayerAndroid::OnTimeUpdate, WeakPtrForUIThread());
81
82 media_weak_this_ = media_weak_factory_.GetWeakPtr();
83
84 // Finish initializaton on Media thread
85 GetMediaTaskRunner()->PostTask(
86 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, media_weak_this_));
87 }
88
89 MediaCodecPlayer::~MediaCodecPlayer()
90 {
91 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer";
92 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
93
94 media_stat_->StopAndReport(GetInterpolatedTime());
95
96 // Currently the unit tests wait for the MediaCodecPlayer destruction by
97 // watching the demuxer, which is destroyed as one of the member variables.
98 // Release the codecs here, before any member variable is destroyed to make
99 // the unit tests happy.
100
101 if (video_decoder_)
102 video_decoder_->ReleaseDecoderResources();
103 if (audio_decoder_)
104 audio_decoder_->ReleaseDecoderResources();
105
106 if (cdm_) {
107 // Cancel previously registered callback (if any).
108 static_cast<MediaDrmBridge*>(cdm_.get())
109 ->SetMediaCryptoReadyCB(MediaDrmBridge::MediaCryptoReadyCB());
110
111 DCHECK(cdm_registration_id_);
112 static_cast<MediaDrmBridge*>(cdm_.get())
113 ->UnregisterPlayer(cdm_registration_id_);
114 }
115 }
116
117 void MediaCodecPlayer::Initialize() {
118 DVLOG(1) << __FUNCTION__;
119 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
120
121 interpolator_.SetUpperBound(base::TimeDelta());
122
123 CreateDecoders();
124
125 // This call might in turn call MediaCodecPlayer::OnDemuxerConfigsAvailable()
126 // which propagates configs into decoders. Therefore CreateDecoders() should
127 // be called first.
128 demuxer_->Initialize(this);
129 }
130
131 // The implementation of MediaPlayerAndroid interface.
132
133 void MediaCodecPlayer::DeleteOnCorrectThread() {
134 DVLOG(1) << __FUNCTION__;
135 DCHECK(ui_task_runner_->BelongsToCurrentThread());
136
137 DetachListener();
138
139 // The base class part that deals with MediaPlayerListener
140 // has to be destroyed on UI thread.
141 DestroyListenerOnUIThread();
142
143 // Post deletion onto Media thread
144 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this);
145 }
146
147 void MediaCodecPlayer::SetVideoSurface(gl::ScopedJavaSurface surface) {
148 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface));
149
150 DVLOG(1) << __FUNCTION__ << (surface.IsEmpty() ? " empty" : " non-empty");
151
152 // Save the empty-ness before we pass the surface to the decoder.
153 bool surface_is_empty = surface.IsEmpty();
154
155 // Apparently RemoveVideoSurface() can be called several times in a row,
156 // ignore the second and subsequent calls.
157 if (surface_is_empty && !video_decoder_->HasVideoSurface()) {
158 DVLOG(1) << __FUNCTION__ << ": surface already removed, ignoring";
159 return;
160 }
161
162 // Do not set unprotected surface if we know that we need a protected one.
163 // Empty surface means the surface removal and we always allow for it.
164 if (!surface_is_empty && video_decoder_->IsProtectedSurfaceRequired() &&
165 !surface.is_protected()) {
166 DVLOG(0) << __FUNCTION__ << ": surface is not protected, ignoring";
167 return;
168 }
169
170 video_decoder_->SetVideoSurface(std::move(surface));
171
172 if (surface_is_empty) {
173 // Remove video surface.
174 switch (state_) {
175 case kStatePlaying:
176 if (VideoFinished())
177 break;
178
179 DVLOG(1) << __FUNCTION__ << ": stopping and restarting";
180 // Stop decoders as quickly as possible.
181 StopDecoders(); // synchronous stop
182
183 // Prefetch or wait for initial configuration.
184 if (HasAudio() || HasVideo()) {
185 SetState(kStatePrefetching);
186 StartPrefetchDecoders();
187 } else {
188 SetState(kStateWaitingForConfig);
189 }
190 break;
191
192 default:
193 break; // ignore
194 }
195 } else {
196 // Replace video surface.
197 switch (state_) {
198 case kStateWaitingForSurface:
199 SetState(kStatePlaying);
200 StartPlaybackOrBrowserSeek();
201 break;
202
203 case kStatePlaying:
204 if (VideoFinished())
205 break;
206
207 DVLOG(1) << __FUNCTION__ << ": requesting to stop and restart";
208 SetState(kStateStopping);
209 RequestToStopDecoders();
210 SetPendingStart(true);
211 break;
212
213 default:
214 break; // ignore
215 }
216 }
217 }
218
219 void MediaCodecPlayer::Start() {
220 RUN_ON_MEDIA_THREAD(Start);
221
222 DVLOG(1) << __FUNCTION__;
223
224 switch (state_) {
225 case kStatePaused:
226 // Request play permission or wait for initial configuration.
227 if (HasAudio() || HasVideo()) {
228 SetState(kStateWaitingForPermission);
229 RequestPlayPermission();
230 } else {
231 SetState(kStateWaitingForConfig);
232 }
233 break;
234 case kStateStopping:
235 case kStateWaitingForSeek:
236 SetPendingStart(true);
237 break;
238 case kStateWaitingForConfig:
239 case kStateWaitingForPermission:
240 case kStatePrefetching:
241 case kStatePlaying:
242 case kStateWaitingForSurface:
243 case kStateWaitingForKey:
244 case kStateWaitingForMediaCrypto:
245 case kStateError:
246 break; // Ignore
247 default:
248 NOTREACHED();
249 break;
250 }
251 }
252
253 void MediaCodecPlayer::Pause(bool is_media_related_action) {
254 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action);
255
256 DVLOG(1) << __FUNCTION__;
257
258 media_stat_->StopAndReport(GetInterpolatedTime());
259
260 SetPendingStart(false);
261
262 switch (state_) {
263 case kStateWaitingForConfig:
264 case kStateWaitingForPermission:
265 case kStatePrefetching:
266 case kStateWaitingForSurface:
267 case kStateWaitingForKey:
268 case kStateWaitingForMediaCrypto:
269 SetState(kStatePaused);
270 StopDecoders();
271 break;
272 case kStatePlaying:
273 SetState(kStateStopping);
274 RequestToStopDecoders();
275 break;
276 case kStatePaused:
277 case kStateStopping:
278 case kStateWaitingForSeek:
279 case kStateError:
280 break; // Ignore
281 default:
282 NOTREACHED();
283 break;
284 }
285 }
286
287 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) {
288 RUN_ON_MEDIA_THREAD(SeekTo, timestamp);
289
290 DVLOG(1) << __FUNCTION__ << " " << timestamp;
291
292 media_stat_->StopAndReport(GetInterpolatedTime());
293
294 switch (state_) {
295 case kStatePaused:
296 SetState(kStateWaitingForSeek);
297 RequestDemuxerSeek(timestamp);
298 break;
299 case kStateWaitingForConfig:
300 case kStateWaitingForPermission:
301 case kStatePrefetching:
302 case kStateWaitingForSurface:
303 case kStateWaitingForKey:
304 case kStateWaitingForMediaCrypto:
305 SetState(kStateWaitingForSeek);
306 StopDecoders();
307 SetPendingStart(true);
308 RequestDemuxerSeek(timestamp);
309 break;
310 case kStatePlaying:
311 SetState(kStateStopping);
312 RequestToStopDecoders();
313 SetPendingStart(true);
314 SetPendingSeek(timestamp);
315 break;
316 case kStateStopping:
317 SetPendingSeek(timestamp);
318 break;
319 case kStateWaitingForSeek:
320 SetPendingSeek(timestamp);
321 break;
322 case kStateError:
323 break; // ignore
324 default:
325 NOTREACHED();
326 break;
327 }
328 }
329
330 void MediaCodecPlayer::Release() {
331 // TODO(qinmin): the callback should be posted onto the UI thread when
332 // Release() finishes on media thread. However, the BrowserMediaPlayerManager
333 // could be gone in that case, which cause the MediaThrottler unable to
334 // track the active players. We should pass
335 // MediaThrottler::OnDecodeRequestFinished() to this class in the ctor, but
336 // also need a way for BrowserMediaPlayerManager to track active players.
337 if (ui_task_runner_->BelongsToCurrentThread())
338 on_decoder_resources_released_cb_.Run(player_id());
339
340 RUN_ON_MEDIA_THREAD(Release);
341
342 DVLOG(1) << __FUNCTION__;
343
344 media_stat_->StopAndReport(GetInterpolatedTime());
345
346 // Stop decoding threads and delete MediaCodecs, but keep IPC between browser
347 // and renderer processes going. Seek should work across and after Release().
348
349 ReleaseDecoderResources();
350
351 SetPendingStart(false);
352
353 if (state_ != kStateWaitingForSeek)
354 SetState(kStatePaused);
355
356 // Crear encryption key related flags.
357 key_is_required_ = false;
358 key_is_added_ = false;
359
360 base::TimeDelta pending_seek_time = GetPendingSeek();
361 if (pending_seek_time != kNoTimestamp) {
362 SetPendingSeek(kNoTimestamp);
363 SetState(kStateWaitingForSeek);
364 RequestDemuxerSeek(pending_seek_time);
365 }
366 }
367
368 void MediaCodecPlayer::UpdateEffectiveVolumeInternal(double effective_volume) {
369 RUN_ON_MEDIA_THREAD(UpdateEffectiveVolumeInternal, effective_volume);
370
371 DVLOG(1) << __FUNCTION__ << " " << effective_volume;
372 audio_decoder_->SetVolume(effective_volume);
373 }
374
375 bool MediaCodecPlayer::HasAudio() const {
376 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
377 return audio_decoder_->HasStream();
378 }
379
380 bool MediaCodecPlayer::HasVideo() const {
381 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
382 return video_decoder_->HasStream();
383 }
384
385 int MediaCodecPlayer::GetVideoWidth() {
386 DCHECK(ui_task_runner_->BelongsToCurrentThread());
387 return metadata_cache_.video_size.width();
388 }
389
390 int MediaCodecPlayer::GetVideoHeight() {
391 DCHECK(ui_task_runner_->BelongsToCurrentThread());
392 return metadata_cache_.video_size.height();
393 }
394
395 base::TimeDelta MediaCodecPlayer::GetCurrentTime() {
396 DCHECK(ui_task_runner_->BelongsToCurrentThread());
397 return current_time_cache_;
398 }
399
400 base::TimeDelta MediaCodecPlayer::GetDuration() {
401 DCHECK(ui_task_runner_->BelongsToCurrentThread());
402 return metadata_cache_.duration;
403 }
404
405 bool MediaCodecPlayer::IsPlaying() {
406 DCHECK(ui_task_runner_->BelongsToCurrentThread());
407
408 // TODO(timav): Use another variable since |state_| should only be accessed on
409 // Media thread.
410 return state_ == kStatePlaying || state_ == kStateStopping;
411 }
412
413 bool MediaCodecPlayer::CanPause() {
414 DCHECK(ui_task_runner_->BelongsToCurrentThread());
415 NOTIMPLEMENTED();
416 return false;
417 }
418
419 bool MediaCodecPlayer::CanSeekForward() {
420 DCHECK(ui_task_runner_->BelongsToCurrentThread());
421 NOTIMPLEMENTED();
422 return false;
423 }
424
425 bool MediaCodecPlayer::CanSeekBackward() {
426 DCHECK(ui_task_runner_->BelongsToCurrentThread());
427 NOTIMPLEMENTED();
428 return false;
429 }
430
431 bool MediaCodecPlayer::IsPlayerReady() {
432 DCHECK(ui_task_runner_->BelongsToCurrentThread());
433 // This method is called to check whether it's safe to release the player when
434 // the OS needs more resources. This class can be released at any time.
435 return true;
436 }
437
438 void MediaCodecPlayer::SetCdm(const scoped_refptr<MediaKeys>& cdm) {
439 DCHECK(cdm);
440 RUN_ON_MEDIA_THREAD(SetCdm, cdm);
441
442 DVLOG(1) << __FUNCTION__;
443
444 // Currently we don't support DRM change during the middle of playback, even
445 // if the player is paused. There is no current plan to support it, see
446 // http://crbug.com/253792.
447 if (state_ != kStatePaused || GetInterpolatedTime() > base::TimeDelta()) {
448 VLOG(0) << "Setting DRM bridge after playback has started is not supported";
449 return;
450 }
451
452 if (cdm_) {
453 NOTREACHED() << "Currently we do not support resetting CDM.";
454 return;
455 }
456
457 cdm_ = cdm;
458
459 // Only MediaDrmBridge will be set on MediaCodecPlayer.
460 MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get());
461
462 // Register CDM callbacks. The callbacks registered will be posted back to the
463 // media thread via BindToCurrentLoop.
464
465 // Since |this| holds a reference to the |cdm_|, by the time the CDM is
466 // destructed, UnregisterPlayer() must have been called and |this| has been
467 // destructed as well. So the |cdm_unset_cb| will never have a chance to be
468 // called.
469 // TODO(xhwang): Remove |cdm_unset_cb| after it's not used on all platforms.
470 cdm_registration_id_ = drm_bridge->RegisterPlayer(
471 BindToCurrentLoop(
472 base::Bind(&MediaCodecPlayer::OnKeyAdded, media_weak_this_)),
473 base::Bind(&base::DoNothing));
474
475 drm_bridge->SetMediaCryptoReadyCB(BindToCurrentLoop(
476 base::Bind(&MediaCodecPlayer::OnMediaCryptoReady, media_weak_this_)));
477 }
478
479 // Callbacks from Demuxer.
480
481 void MediaCodecPlayer::OnDemuxerConfigsAvailable(
482 const DemuxerConfigs& configs) {
483 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
484
485 DVLOG(1) << __FUNCTION__;
486
487 duration_ = configs.duration;
488
489 SetDemuxerConfigs(configs);
490
491 // Update cache and notify manager on UI thread
492 gfx::Size video_size = HasVideo() ? configs.video_size : gfx::Size();
493 ui_task_runner_->PostTask(
494 FROM_HERE, base::Bind(metadata_changed_cb_, duration_, video_size));
495 }
496
497 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) {
498 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
499
500 DCHECK_LT(0u, data.access_units.size());
501 CHECK_GE(1u, data.demuxer_configs.size());
502
503 DVLOG(2) << "Player::" << __FUNCTION__;
504
505 if (data.type == DemuxerStream::AUDIO)
506 audio_decoder_->OnDemuxerDataAvailable(data);
507
508 if (data.type == DemuxerStream::VIDEO)
509 video_decoder_->OnDemuxerDataAvailable(data);
510 }
511
512 void MediaCodecPlayer::OnDemuxerSeekDone(
513 base::TimeDelta actual_browser_seek_time) {
514 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
515
516 DVLOG(1) << __FUNCTION__ << " actual_time:" << actual_browser_seek_time;
517
518 DCHECK(seek_info_.get());
519 DCHECK(seek_info_->seek_time != kNoTimestamp);
520
521 // A browser seek must not jump into the past. Ideally, it seeks to the
522 // requested time, but it might jump into the future.
523 DCHECK(!seek_info_->is_browser_seek ||
524 seek_info_->seek_time <= actual_browser_seek_time);
525
526 // Restrict the current time to be equal to seek_time
527 // for the next StartPlaybackDecoders() call.
528
529 base::TimeDelta seek_time = seek_info_->is_browser_seek
530 ? actual_browser_seek_time
531 : seek_info_->seek_time;
532
533 interpolator_.SetBounds(seek_time, seek_time);
534
535 audio_decoder_->SetBaseTimestamp(seek_time);
536
537 audio_decoder_->SetPrerollTimestamp(seek_time);
538 video_decoder_->SetPrerollTimestamp(seek_time);
539
540 // The Flush() might set the state to kStateError.
541 if (state_ == kStateError) {
542 // Notify the Renderer.
543 if (!seek_info_->is_browser_seek)
544 ui_task_runner_->PostTask(FROM_HERE,
545 base::Bind(seek_done_cb_, seek_time));
546
547 seek_info_.reset();
548 return;
549 }
550
551 DCHECK_EQ(kStateWaitingForSeek, state_);
552
553 base::TimeDelta pending_seek_time = GetPendingSeek();
554 if (pending_seek_time != kNoTimestamp) {
555 // Keep kStateWaitingForSeek
556 SetPendingSeek(kNoTimestamp);
557 RequestDemuxerSeek(pending_seek_time);
558 return;
559 }
560
561 if (HasPendingStart()) {
562 SetPendingStart(false);
563 // Request play permission or wait for initial configuration.
564 if (HasAudio() || HasVideo()) {
565 SetState(kStateWaitingForPermission);
566 RequestPlayPermission();
567 } else {
568 SetState(kStateWaitingForConfig);
569 }
570 } else {
571 SetState(kStatePaused);
572 }
573
574 // Notify the Renderer.
575 if (!seek_info_->is_browser_seek)
576 ui_task_runner_->PostTask(FROM_HERE, base::Bind(seek_done_cb_, seek_time));
577
578 seek_info_.reset();
579 }
580
581 void MediaCodecPlayer::OnDemuxerDurationChanged(
582 base::TimeDelta duration) {
583 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
584 DVLOG(1) << __FUNCTION__ << " duration:" << duration;
585
586 duration_ = duration;
587 }
588
589 void MediaCodecPlayer::SetDecodersTimeCallbackForTests(
590 DecodersTimeCallback cb) {
591 DCHECK(ui_task_runner_->BelongsToCurrentThread());
592 decoders_time_cb_ = cb;
593 }
594
595 void MediaCodecPlayer::SetCodecCreatedCallbackForTests(
596 CodecCreatedCallback cb) {
597 DCHECK(ui_task_runner_->BelongsToCurrentThread());
598 DCHECK(audio_decoder_ && video_decoder_);
599
600 audio_decoder_->SetCodecCreatedCallbackForTests(
601 base::Bind(cb, DemuxerStream::AUDIO));
602 video_decoder_->SetCodecCreatedCallbackForTests(
603 base::Bind(cb, DemuxerStream::VIDEO));
604 }
605
606 void MediaCodecPlayer::SetAlwaysReconfigureForTests(DemuxerStream::Type type) {
607 DCHECK(ui_task_runner_->BelongsToCurrentThread());
608 DCHECK(audio_decoder_ && video_decoder_);
609
610 if (type == DemuxerStream::AUDIO)
611 audio_decoder_->SetAlwaysReconfigureForTests();
612 else if (type == DemuxerStream::VIDEO)
613 video_decoder_->SetAlwaysReconfigureForTests();
614 }
615
616 bool MediaCodecPlayer::IsPrerollingForTests(DemuxerStream::Type type) const {
617 DCHECK(ui_task_runner_->BelongsToCurrentThread());
618 DCHECK(audio_decoder_ && video_decoder_);
619
620 if (type == DemuxerStream::AUDIO)
621 return audio_decoder_->IsPrerollingForTests();
622 else if (type == DemuxerStream::VIDEO)
623 return video_decoder_->IsPrerollingForTests();
624 else
625 return false;
626 }
627
628 // Events from Player, called on UI thread
629
630 void MediaCodecPlayer::RequestPermissionAndPostResult(base::TimeDelta duration,
631 bool has_audio) {
632 DCHECK(ui_task_runner_->BelongsToCurrentThread());
633 DVLOG(1) << __FUNCTION__ << " duration:" << duration;
634
635 bool granted = manager()->RequestPlay(player_id(), duration, has_audio);
636 GetMediaTaskRunner()->PostTask(
637 FROM_HERE, base::Bind(&MediaCodecPlayer::OnPermissionDecided,
638 media_weak_this_, granted));
639 }
640
641 void MediaCodecPlayer::OnMediaMetadataChanged(base::TimeDelta duration,
642 const gfx::Size& video_size) {
643 DCHECK(ui_task_runner_->BelongsToCurrentThread());
644
645 if (duration != kNoTimestamp)
646 metadata_cache_.duration = duration;
647
648 if (!video_size.IsEmpty())
649 metadata_cache_.video_size = video_size;
650
651 manager()->OnMediaMetadataChanged(player_id(), metadata_cache_.duration,
652 metadata_cache_.video_size.width(),
653 metadata_cache_.video_size.height(), true);
654 }
655
656 void MediaCodecPlayer::OnTimeUpdate(base::TimeDelta current_timestamp,
657 base::TimeTicks current_time_ticks) {
658 DCHECK(ui_task_runner_->BelongsToCurrentThread());
659
660 current_time_cache_ = current_timestamp;
661 manager()->OnTimeUpdate(player_id(), current_timestamp, current_time_ticks);
662 }
663
664 // Event from manager, called on Media thread
665
666 void MediaCodecPlayer::OnPermissionDecided(bool granted) {
667 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
668
669 DVLOG(1) << __FUNCTION__ << ": " << (granted ? "granted" : "denied");
670
671 switch (state_) {
672 case kStateWaitingForPermission:
673 if (granted) {
674 SetState(kStatePrefetching);
675 StartPrefetchDecoders();
676 } else {
677 SetState(kStatePaused);
678 StopDecoders();
679 }
680 break;
681
682 default:
683 break; // ignore
684 }
685 }
686
687 // Events from Decoders, called on Media thread
688
689 void MediaCodecPlayer::RequestDemuxerData(DemuxerStream::Type stream_type) {
690 DVLOG(2) << __FUNCTION__ << " streamType:" << stream_type;
691
692 // Use this method instead of directly binding with
693 // DemuxerAndroid::RequestDemuxerData() to avoid the race condition on
694 // deletion:
695 // 1. DeleteSoon is posted from UI to Media thread.
696 // 2. RequestDemuxerData callback is posted from Decoder to Media thread.
697 // 3. DeleteSoon arrives, we delete the player and detach from
698 // BrowserDemuxerAndroid.
699 // 4. RequestDemuxerData is processed by the media thread queue. Since the
700 // weak_ptr was invalidated in (3), this is a no-op. If we used
701 // DemuxerAndroid::RequestDemuxerData() it would arrive and will try to
702 // call the client, but the client (i.e. this player) would not exist.
703 demuxer_->RequestDemuxerData(stream_type);
704 }
705
706 void MediaCodecPlayer::OnPrefetchDone() {
707 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
708
709 if (state_ != kStatePrefetching) {
710 DVLOG(1) << __FUNCTION__ << " wrong state " << AsString(state_)
711 << " ignoring";
712 return; // Ignore
713 }
714
715 DVLOG(1) << __FUNCTION__;
716
717 if (!HasAudio() && !HasVideo()) {
718 // No configuration at all after prefetching.
719 // This is an error, initial configuration is expected
720 // before the first data chunk.
721 DCHECK(!internal_error_cb_.is_null());
722 GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_);
723 return;
724 }
725
726 if (HasVideo() && !video_decoder_->HasVideoSurface()) {
727 SetState(kStateWaitingForSurface);
728 return;
729 }
730
731 if (key_is_required_ && !key_is_added_) {
732 SetState(kStateWaitingForKey);
733 ui_task_runner_->PostTask(FROM_HERE, waiting_for_decryption_key_cb_);
734 return;
735 }
736
737 SetState(kStatePlaying);
738 StartPlaybackOrBrowserSeek();
739 }
740
741 void MediaCodecPlayer::OnPrerollDone() {
742 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
743
744 if (state_ != kStatePlaying) {
745 DVLOG(1) << __FUNCTION__ << ": in state " << AsString(state_)
746 << ", ignoring";
747 return;
748 }
749
750 DVLOG(1) << __FUNCTION__;
751
752 StartStatus status = StartDecoders();
753 if (status != kStartOk)
754 GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_);
755 }
756
757 void MediaCodecPlayer::OnDecoderDrained(DemuxerStream::Type type) {
758 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
759 DVLOG(1) << __FUNCTION__ << " " << type;
760
761 // We expect that OnStopDone() comes next.
762
763 DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO);
764
765 // DCHECK(state_ == kStatePlaying || state_ == kStateStopping)
766 // << __FUNCTION__ << " illegal state: " << AsString(state_);
767 //
768 // With simultaneous reconfiguration of audio and video streams the state
769 // can be kStatePrefetching as well:
770 // OnLastFrameRendered VIDEO (VIDEO decoder is stopped)
771 // OnLastFrameRendered AUDIO (AUDIO decoder is stopped)
772 // OnDecoderDrained VIDEO (kStatePlaying -> kStateStopping)
773 // OnStopDone VIDEO (kStateStopping -> kStatePrefetching)
774 // OnDecoderDrained AUDIO
775 // OnStopDone AUDIO
776 //
777 // TODO(timav): combine OnDecoderDrained() and OnStopDone() ?
778
779 switch (state_) {
780 case kStatePlaying:
781 SetState(kStateStopping);
782 SetPendingStart(true);
783
784 if (type == DemuxerStream::AUDIO && !VideoFinished()) {
785 DVLOG(1) << __FUNCTION__ << " requesting to stop video";
786 video_decoder_->RequestToStop();
787 } else if (type == DemuxerStream::VIDEO && !AudioFinished()) {
788 DVLOG(1) << __FUNCTION__ << " requesting to stop audio";
789 audio_decoder_->RequestToStop();
790 }
791 break;
792
793 default:
794 break;
795 }
796 }
797
798 void MediaCodecPlayer::OnStopDone(DemuxerStream::Type type) {
799 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
800 DVLOG(1) << __FUNCTION__ << " " << type
801 << " interpolated time:" << GetInterpolatedTime();
802
803 if (!(audio_decoder_->IsStopped() && video_decoder_->IsStopped())) {
804 DVLOG(1) << __FUNCTION__ << " both audio and video has to be stopped"
805 << ", ignoring";
806 return; // Wait until other stream is stopped
807 }
808
809 // At this point decoder threads should not be running
810 if (interpolator_.interpolating())
811 interpolator_.StopInterpolating();
812
813 base::TimeDelta seek_time;
814 switch (state_) {
815 case kStateStopping: {
816 base::TimeDelta seek_time = GetPendingSeek();
817 if (seek_time != kNoTimestamp) {
818 SetState(kStateWaitingForSeek);
819 SetPendingSeek(kNoTimestamp);
820 RequestDemuxerSeek(seek_time);
821 } else if (HasPendingStart()) {
822 SetPendingStart(false);
823 SetState(kStateWaitingForPermission);
824 RequestPlayPermission();
825 } else {
826 SetState(kStatePaused);
827 }
828 } break;
829 case kStatePlaying:
830 // Unexpected stop means completion
831 SetState(kStatePaused);
832 break;
833 default:
834 // DVLOG(0) << __FUNCTION__ << " illegal state: " << AsString(state_);
835 // NOTREACHED();
836 // Ignore! There can be a race condition: audio posts OnStopDone,
837 // then video posts, then first OnStopDone arrives at which point
838 // both streams are already stopped, then second OnStopDone arrives. When
839 // the second one arrives, the state us not kStateStopping any more.
840 return;
841 }
842
843 // DetachListener to UI thread
844 ui_task_runner_->PostTask(FROM_HERE, detach_listener_cb_);
845
846 if (AudioFinished() && VideoFinished()) {
847 media_stat_->StopAndReport(GetInterpolatedTime());
848 ui_task_runner_->PostTask(FROM_HERE, completion_cb_);
849 }
850 }
851
852 void MediaCodecPlayer::OnMissingKeyReported(DemuxerStream::Type type) {
853 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
854 DVLOG(1) << __FUNCTION__ << " " << type;
855
856 // Request stop and restart to pick up the key.
857 key_is_required_ = true;
858
859 if (state_ == kStatePlaying) {
860 media_stat_->StopAndReport(GetInterpolatedTime());
861
862 SetState(kStateStopping);
863 RequestToStopDecoders();
864 SetPendingStart(true);
865 }
866 }
867
868 void MediaCodecPlayer::OnError() {
869 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
870 DVLOG(1) << __FUNCTION__;
871
872 media_stat_->StopAndReport(GetInterpolatedTime());
873
874 // kStateError blocks all events
875 SetState(kStateError);
876
877 ReleaseDecoderResources();
878
879 ui_task_runner_->PostTask(FROM_HERE,
880 base::Bind(error_cb_, MEDIA_ERROR_DECODE));
881 }
882
883 void MediaCodecPlayer::OnStarvation(DemuxerStream::Type type) {
884 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
885 DVLOG(1) << __FUNCTION__ << " stream type:" << type;
886
887 if (state_ != kStatePlaying)
888 return; // Ignore
889
890 SetState(kStateStopping);
891 RequestToStopDecoders();
892 SetPendingStart(true);
893
894 media_stat_->AddStarvation();
895 }
896
897 void MediaCodecPlayer::OnTimeIntervalUpdate(DemuxerStream::Type type,
898 base::TimeDelta now_playing,
899 base::TimeDelta last_buffered,
900 bool postpone) {
901 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
902
903 DVLOG(2) << __FUNCTION__ << ": stream type:" << type << " [" << now_playing
904 << "," << last_buffered << "]" << (postpone ? " postpone" : "");
905
906 // For testing only: report time interval as we receive it from decoders
907 // as an indication of what is being rendered. Do not post this callback
908 // for postponed frames: although the PTS is correct, the tests also care
909 // about the wall clock time this callback arrives and deduce the rendering
910 // moment from it.
911 if (!decoders_time_cb_.is_null() && !postpone) {
912 ui_task_runner_->PostTask(
913 FROM_HERE,
914 base::Bind(decoders_time_cb_, type, now_playing, last_buffered));
915 }
916
917 // I assume that audio stream cannot be added after we get configs by
918 // OnDemuxerConfigsAvailable(), but that audio can finish early.
919
920 if (type == DemuxerStream::VIDEO) {
921 // Ignore video PTS if there is audio stream or if it's behind current
922 // time as set by audio stream.
923 if (!AudioFinished() ||
924 (HasAudio() && now_playing < interpolator_.GetInterpolatedTime()))
925 return;
926 }
927
928 interpolator_.SetBounds(now_playing, last_buffered);
929
930 // Post to UI thread
931 if (!postpone) {
932 ui_task_runner_->PostTask(FROM_HERE,
933 base::Bind(time_update_cb_, GetInterpolatedTime(),
934 base::TimeTicks::Now()));
935 }
936 }
937
938 void MediaCodecPlayer::OnVideoResolutionChanged(const gfx::Size& size) {
939 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
940
941 DVLOG(1) << __FUNCTION__ << " " << size.width() << "x" << size.height();
942
943 // Update cache and notify manager on UI thread
944 ui_task_runner_->PostTask(
945 FROM_HERE, base::Bind(metadata_changed_cb_, kNoTimestamp, size));
946 }
947
948 // Callbacks from MediaDrmBridge.
949
950 void MediaCodecPlayer::OnMediaCryptoReady(
951 MediaDrmBridge::JavaObjectPtr media_crypto,
952 bool needs_protected_surface) {
953 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
954 DVLOG(1) << __FUNCTION__ << " protected surface is "
955 << (needs_protected_surface ? "required" : "not required");
956
957 // We use the parameters that come with this callback every time we call
958 // Configure(). This is possible only if the MediaCrypto object remains valid
959 // and the surface requirement does not change until new SetCdm() is called.
960
961 DCHECK(media_crypto);
962
963 if (media_crypto->is_null()) {
964 // TODO(timav): Fail playback nicely here if needed. Note that we could get
965 // here even though the stream to play is unencrypted and therefore
966 // MediaCrypto is not needed. In that case, we may ignore this error and
967 // continue playback, or fail the playback.
968 LOG(ERROR) << "MediaCrypto creation failed.";
969 return;
970 }
971
972 media_crypto_ = std::move(media_crypto);
973
974 if (audio_decoder_) {
975 audio_decoder_->SetNeedsReconfigure();
976 }
977
978 if (video_decoder_) {
979 video_decoder_->SetNeedsReconfigure();
980 video_decoder_->SetProtectedSurfaceRequired(needs_protected_surface);
981 }
982
983 if (state_ == kStateWaitingForMediaCrypto) {
984 // Resume start sequence (configure, etc.)
985 SetState(kStatePlaying);
986 StartPlaybackOrBrowserSeek();
987 }
988
989 DVLOG(1) << __FUNCTION__ << " end";
990 }
991
992 void MediaCodecPlayer::OnKeyAdded() {
993 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
994 DVLOG(1) << __FUNCTION__;
995
996 key_is_added_ = true;
997
998 if (state_ == kStateWaitingForKey) {
999 SetState(kStatePlaying);
1000 StartPlaybackOrBrowserSeek();
1001 }
1002 }
1003
1004 // State machine operations, called on Media thread
1005
1006 void MediaCodecPlayer::SetState(PlayerState new_state) {
1007 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1008
1009 DVLOG(1) << "SetState:" << AsString(state_) << " -> " << AsString(new_state);
1010 state_ = new_state;
1011 }
1012
1013 void MediaCodecPlayer::SetPendingStart(bool need_to_start) {
1014 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1015 DVLOG(1) << __FUNCTION__ << ": " << need_to_start;
1016 pending_start_ = need_to_start;
1017 }
1018
1019 bool MediaCodecPlayer::HasPendingStart() const {
1020 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1021 return pending_start_;
1022 }
1023
1024 void MediaCodecPlayer::SetPendingSeek(base::TimeDelta timestamp) {
1025 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1026 DVLOG(1) << __FUNCTION__ << ": " << timestamp;
1027 pending_seek_ = timestamp;
1028 }
1029
1030 base::TimeDelta MediaCodecPlayer::GetPendingSeek() const {
1031 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1032 return pending_seek_;
1033 }
1034
1035 void MediaCodecPlayer::SetDemuxerConfigs(const DemuxerConfigs& configs) {
1036 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1037 DVLOG(1) << __FUNCTION__ << " " << configs;
1038
1039 DCHECK(audio_decoder_);
1040 DCHECK(video_decoder_);
1041
1042 // At least one valid codec must be present.
1043 DCHECK(configs.audio_codec != kUnknownAudioCodec ||
1044 configs.video_codec != kUnknownVideoCodec);
1045
1046 if (configs.audio_codec != kUnknownAudioCodec)
1047 audio_decoder_->SetDemuxerConfigs(configs);
1048
1049 if (configs.video_codec != kUnknownVideoCodec)
1050 video_decoder_->SetDemuxerConfigs(configs);
1051
1052 if (state_ == kStateWaitingForConfig) {
1053 SetState(kStateWaitingForPermission);
1054 RequestPlayPermission();
1055 }
1056 }
1057
1058 void MediaCodecPlayer::RequestPlayPermission() {
1059 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1060 DVLOG(1) << __FUNCTION__;
1061
1062 // Check that we have received demuxer config hence we know the duration.
1063 DCHECK(HasAudio() || HasVideo());
1064
1065 ui_task_runner_->PostTask(
1066 FROM_HERE, base::Bind(&MediaPlayerAndroid::RequestPermissionAndPostResult,
1067 WeakPtrForUIThread(), duration_, HasAudio()));
1068 }
1069
1070 void MediaCodecPlayer::StartPrefetchDecoders() {
1071 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1072 DVLOG(1) << __FUNCTION__;
1073
1074 bool do_audio = false;
1075 bool do_video = false;
1076 int count = 0;
1077 if (!AudioFinished()) {
1078 do_audio = true;
1079 ++count;
1080 }
1081 if (!VideoFinished()) {
1082 do_video = true;
1083 ++count;
1084 }
1085
1086 DCHECK_LT(0, count); // at least one decoder should be active
1087
1088 base::Closure prefetch_cb = base::BarrierClosure(
1089 count, base::Bind(&MediaCodecPlayer::OnPrefetchDone, media_weak_this_));
1090
1091 if (do_audio)
1092 audio_decoder_->Prefetch(prefetch_cb);
1093
1094 if (do_video)
1095 video_decoder_->Prefetch(prefetch_cb);
1096 }
1097
1098 void MediaCodecPlayer::StartPlaybackOrBrowserSeek() {
1099 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1100 DVLOG(1) << __FUNCTION__;
1101
1102 // TODO(timav): consider replacing this method with posting a
1103 // browser seek task (i.e. generate an event) from StartPlaybackDecoders().
1104
1105 // Clear encryption key related flags.
1106 key_is_required_ = false;
1107 key_is_added_ = false;
1108
1109 StartStatus status = StartPlaybackDecoders();
1110
1111 switch (status) {
1112 case kStartBrowserSeekRequired:
1113 // Browser seek
1114 SetState(kStateWaitingForSeek);
1115 SetPendingStart(true);
1116 StopDecoders();
1117 RequestDemuxerSeek(GetInterpolatedTime(), true);
1118 break;
1119 case kStartCryptoRequired:
1120 SetState(kStateWaitingForMediaCrypto);
1121 break;
1122 case kStartFailed:
1123 GetMediaTaskRunner()->PostTask(FROM_HERE, internal_error_cb_);
1124 break;
1125 case kStartOk:
1126 break;
1127 }
1128 }
1129
1130 MediaCodecPlayer::StartStatus MediaCodecPlayer::StartPlaybackDecoders() {
1131 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1132 DVLOG(1) << __FUNCTION__;
1133
1134 // Configure all streams before the start since we may discover that browser
1135 // seek is required.
1136 MediaCodecPlayer::StartStatus status = ConfigureDecoders();
1137 if (status != kStartOk)
1138 return status;
1139
1140 bool preroll_required = false;
1141 status = MaybePrerollDecoders(&preroll_required);
1142 if (preroll_required)
1143 return status;
1144
1145 return StartDecoders();
1146 }
1147
1148 MediaCodecPlayer::StartStatus MediaCodecPlayer::ConfigureDecoders() {
1149 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1150 DVLOG(1) << __FUNCTION__;
1151
1152 const bool do_audio = !AudioFinished();
1153 const bool do_video = !VideoFinished();
1154
1155 // If there is nothing to play, the state machine should determine this at the
1156 // prefetch state and never call this method.
1157 DCHECK(do_audio || do_video);
1158
1159 const bool need_audio_crypto =
1160 do_audio && audio_decoder_->IsContentEncrypted();
1161 const bool need_video_crypto =
1162 do_video && video_decoder_->IsContentEncrypted();
1163
1164 // Do we need to create a local ref from the global ref?
1165 jobject media_crypto = media_crypto_ ? media_crypto_->obj() : nullptr;
1166
1167 if (need_audio_crypto || need_video_crypto) {
1168 DVLOG(1) << (need_audio_crypto ? " audio" : "")
1169 << (need_video_crypto ? " video" : "") << " need(s) encryption";
1170 if (!media_crypto) {
1171 DVLOG(1) << __FUNCTION__ << ": MediaCrypto is not found, returning";
1172 return kStartCryptoRequired;
1173 }
1174 }
1175
1176 // Start with video: if browser seek is required it would not make sense to
1177 // configure audio.
1178
1179 MediaCodecDecoder::ConfigStatus status = MediaCodecDecoder::kConfigOk;
1180 if (do_video)
1181 status = video_decoder_->Configure(media_crypto);
1182
1183 if (status == MediaCodecDecoder::kConfigOk && do_audio)
1184 status = audio_decoder_->Configure(media_crypto);
1185
1186 switch (status) {
1187 case MediaCodecDecoder::kConfigOk:
1188 break;
1189 case MediaCodecDecoder::kConfigKeyFrameRequired:
1190 return kStartBrowserSeekRequired;
1191 case MediaCodecDecoder::kConfigFailure:
1192 return kStartFailed;
1193 }
1194 return kStartOk;
1195 }
1196
1197 MediaCodecPlayer::StartStatus MediaCodecPlayer::MaybePrerollDecoders(
1198 bool* preroll_required) {
1199 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1200
1201 DVLOG(1) << __FUNCTION__ << " current_time:" << GetInterpolatedTime();
1202
1203 // If requested, preroll is always done in the beginning of the playback,
1204 // after prefetch. The request might not happen at all though, in which case
1205 // we won't have prerolling phase. We need the prerolling when we (re)create
1206 // the decoder, because its configuration and initialization (getting input,
1207 // but not making output) can take time, and after the seek because there
1208 // could be some data to be skipped and there is again initialization after
1209 // the flush.
1210
1211 *preroll_required = false;
1212
1213 int count = 0;
1214 const bool do_audio = audio_decoder_->NotCompletedAndNeedsPreroll();
1215 if (do_audio)
1216 ++count;
1217
1218 const bool do_video = video_decoder_->NotCompletedAndNeedsPreroll();
1219 if (do_video)
1220 ++count;
1221
1222 if (count == 0) {
1223 DVLOG(1) << __FUNCTION__ << ": preroll is not required, skipping";
1224 return kStartOk;
1225 }
1226
1227 *preroll_required = true;
1228
1229 DCHECK(count > 0);
1230 DCHECK(do_audio || do_video);
1231
1232 DVLOG(1) << __FUNCTION__ << ": preroll for " << count << " stream(s)";
1233
1234 base::Closure preroll_cb = base::BarrierClosure(
1235 count, base::Bind(&MediaCodecPlayer::OnPrerollDone, media_weak_this_));
1236
1237 if (do_audio && !audio_decoder_->Preroll(preroll_cb))
1238 return kStartFailed;
1239
1240 if (do_video && !video_decoder_->Preroll(preroll_cb))
1241 return kStartFailed;
1242
1243 return kStartOk;
1244 }
1245
1246 MediaCodecPlayer::StartStatus MediaCodecPlayer::StartDecoders() {
1247 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1248
1249 if (!interpolator_.interpolating())
1250 interpolator_.StartInterpolating();
1251
1252 base::TimeDelta current_time = GetInterpolatedTime();
1253
1254 DVLOG(1) << __FUNCTION__ << " current_time:" << current_time;
1255
1256 // At this point decoder threads are either not running at all or their
1257 // message pumps are in the idle state after the preroll is done.
1258
1259 if (!AudioFinished()) {
1260 if (!audio_decoder_->Start(current_time))
1261 return kStartFailed;
1262
1263 // Attach listener on UI thread
1264 ui_task_runner_->PostTask(FROM_HERE, attach_listener_cb_);
1265 }
1266
1267 if (!VideoFinished()) {
1268 if (!video_decoder_->Start(current_time))
1269 return kStartFailed;
1270 }
1271
1272 media_stat_->Start(current_time);
1273
1274 return kStartOk;
1275 }
1276
1277 void MediaCodecPlayer::StopDecoders() {
1278 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1279 DVLOG(1) << __FUNCTION__;
1280
1281 video_decoder_->SyncStop();
1282 audio_decoder_->SyncStop();
1283 }
1284
1285 void MediaCodecPlayer::RequestToStopDecoders() {
1286 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1287 DVLOG(1) << __FUNCTION__;
1288
1289 bool do_audio = false;
1290 bool do_video = false;
1291
1292 if (audio_decoder_->IsPrefetchingOrPlaying())
1293 do_audio = true;
1294 if (video_decoder_->IsPrefetchingOrPlaying())
1295 do_video = true;
1296
1297 if (!do_audio && !do_video) {
1298 GetMediaTaskRunner()->PostTask(
1299 FROM_HERE, base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_,
1300 DemuxerStream::UNKNOWN));
1301 return;
1302 }
1303
1304 if (do_audio)
1305 audio_decoder_->RequestToStop();
1306 if (do_video)
1307 video_decoder_->RequestToStop();
1308 }
1309
1310 void MediaCodecPlayer::RequestDemuxerSeek(base::TimeDelta seek_time,
1311 bool is_browser_seek) {
1312 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1313 DVLOG(1) << __FUNCTION__ << " " << seek_time
1314 << (is_browser_seek ? " BROWSER_SEEK" : "");
1315
1316 // Flush decoders before requesting demuxer.
1317 audio_decoder_->Flush();
1318 video_decoder_->Flush();
1319
1320 // Save active seek data. Logically it is attached to kStateWaitingForSeek.
1321 DCHECK_EQ(kStateWaitingForSeek, state_);
1322 seek_info_.reset(new SeekInfo(seek_time, is_browser_seek));
1323
1324 demuxer_->RequestDemuxerSeek(seek_time, is_browser_seek);
1325 }
1326
1327 void MediaCodecPlayer::ReleaseDecoderResources() {
1328 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1329 DVLOG(1) << __FUNCTION__;
1330
1331 if (audio_decoder_)
1332 audio_decoder_->ReleaseDecoderResources();
1333
1334 if (video_decoder_)
1335 video_decoder_->ReleaseDecoderResources();
1336
1337 // At this point decoder threads should not be running
1338 if (interpolator_.interpolating())
1339 interpolator_.StopInterpolating();
1340 }
1341
1342 void MediaCodecPlayer::CreateDecoders() {
1343 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1344 DVLOG(1) << __FUNCTION__;
1345
1346 internal_error_cb_ = base::Bind(&MediaCodecPlayer::OnError, media_weak_this_);
1347
1348 media_stat_.reset(new MediaStatistics());
1349
1350 audio_decoder_.reset(new AudioMediaCodecDecoder(
1351 GetMediaTaskRunner(), &media_stat_->audio_frame_stats(),
1352 base::Bind(&MediaCodecPlayer::RequestDemuxerData, media_weak_this_,
1353 DemuxerStream::AUDIO),
1354 base::Bind(&MediaCodecPlayer::OnStarvation, media_weak_this_,
1355 DemuxerStream::AUDIO),
1356 base::Bind(&MediaCodecPlayer::OnDecoderDrained, media_weak_this_,
1357 DemuxerStream::AUDIO),
1358 base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_,
1359 DemuxerStream::AUDIO),
1360 base::Bind(&MediaCodecPlayer::OnMissingKeyReported, media_weak_this_,
1361 DemuxerStream::AUDIO),
1362 internal_error_cb_, base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate,
1363 media_weak_this_, DemuxerStream::AUDIO)));
1364
1365 video_decoder_.reset(new VideoMediaCodecDecoder(
1366 GetMediaTaskRunner(), &media_stat_->video_frame_stats(),
1367 base::Bind(&MediaCodecPlayer::RequestDemuxerData, media_weak_this_,
1368 DemuxerStream::VIDEO),
1369 base::Bind(&MediaCodecPlayer::OnStarvation, media_weak_this_,
1370 DemuxerStream::VIDEO),
1371 base::Bind(&MediaCodecPlayer::OnDecoderDrained, media_weak_this_,
1372 DemuxerStream::VIDEO),
1373 base::Bind(&MediaCodecPlayer::OnStopDone, media_weak_this_,
1374 DemuxerStream::VIDEO),
1375 base::Bind(&MediaCodecPlayer::OnMissingKeyReported, media_weak_this_,
1376 DemuxerStream::VIDEO),
1377 internal_error_cb_, base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate,
1378 media_weak_this_, DemuxerStream::VIDEO),
1379 base::Bind(&MediaCodecPlayer::OnVideoResolutionChanged,
1380 media_weak_this_)));
1381 }
1382
1383 bool MediaCodecPlayer::AudioFinished() const {
1384 return audio_decoder_->IsCompleted() || !audio_decoder_->HasStream();
1385 }
1386
1387 bool MediaCodecPlayer::VideoFinished() const {
1388 return video_decoder_->IsCompleted() || !video_decoder_->HasStream();
1389 }
1390
1391 base::TimeDelta MediaCodecPlayer::GetInterpolatedTime() {
1392 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
1393
1394 base::TimeDelta interpolated_time = interpolator_.GetInterpolatedTime();
1395 return std::min(interpolated_time, duration_);
1396 }
1397
1398 #undef RETURN_STRING
1399 #define RETURN_STRING(x) \
1400 case x: \
1401 return #x;
1402
1403 const char* MediaCodecPlayer::AsString(PlayerState state) {
1404 switch (state) {
1405 RETURN_STRING(kStatePaused);
1406 RETURN_STRING(kStateWaitingForConfig);
1407 RETURN_STRING(kStateWaitingForPermission);
1408 RETURN_STRING(kStatePrefetching);
1409 RETURN_STRING(kStatePlaying);
1410 RETURN_STRING(kStateStopping);
1411 RETURN_STRING(kStateWaitingForSurface);
1412 RETURN_STRING(kStateWaitingForKey);
1413 RETURN_STRING(kStateWaitingForMediaCrypto);
1414 RETURN_STRING(kStateWaitingForSeek);
1415 RETURN_STRING(kStateError);
1416 }
1417 return nullptr; // crash early
1418 }
1419
1420 #undef RETURN_STRING
1421
1422 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_codec_player.h ('k') | media/base/android/media_codec_player_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698