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

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

Issue 1128383003: Implementation of MediaCodecPlayer stage 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Accept configuration change from decoder, media metadata cache Created 5 years, 7 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/android/media_codec_player.h" 5 #include "media/base/android/media_codec_player.h"
6 6
7 #include "base/barrier_closure.h"
7 #include "base/bind.h" 8 #include "base/bind.h"
8 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/threading/thread.h"
12
13 #include "media/base/android/media_codec_audio_decoder.h"
14 #include "media/base/android/media_codec_video_decoder.h"
15 #include "media/base/android/media_player_manager.h"
16 #include "media/base/buffers.h"
10 17
11 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \ 18 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \
12 do { \ 19 do { \
13 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \ 20 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
14 GetMediaTaskRunner()->PostTask( \ 21 GetMediaTaskRunner()->PostTask( \
15 FROM_HERE, \ 22 FROM_HERE, \
16 base::Bind(&MediaCodecPlayer:: METHOD, weak_this_, ##__VA_ARGS__)); \ 23 base::Bind(&MediaCodecPlayer:: METHOD, weak_this_, ##__VA_ARGS__)); \
17 return; \ 24 return; \
18 } \ 25 } \
19 } while(0) 26 } while(0)
(...skipping 12 matching lines...) Expand all
32 base::LazyInstance<MediaThread>::Leaky 39 base::LazyInstance<MediaThread>::Leaky
33 g_media_thread = LAZY_INSTANCE_INITIALIZER; 40 g_media_thread = LAZY_INSTANCE_INITIALIZER;
34 41
35 42
36 scoped_refptr<base::SingleThreadTaskRunner> GetMediaTaskRunner() { 43 scoped_refptr<base::SingleThreadTaskRunner> GetMediaTaskRunner() {
37 return g_media_thread.Pointer()->task_runner(); 44 return g_media_thread.Pointer()->task_runner();
38 } 45 }
39 46
40 // MediaCodecPlayer implementation. 47 // MediaCodecPlayer implementation.
41 48
49 /*
50 State machine diagram.
51
52
53 --------------------------> Paused
54 | StopDone:
55 | ^ |
56 | | |
57 | Pause: | | Start: dec.Prefetch
58 | | |
59 | | |
60 | | |
61 | | v PrefetchDone,
62 | no surface:
63 | ------------------> Prefetching --------------> Waiting
64 | | for surface
65 | | | /
66 | | | /
67 | | StopDone w/ | /
68 | | pending start: | PrefetchDone: /
69 | | dec.Prefetch | dec.Start /
70 | | | / SetSurface:
71 | | | / dec.Start
72 | | | /
73 | | v /
74 | | /
75 | | Playing <----------/
76 | |
77 | | |
78 | | |
79 | | | Pause: dec.RequestToStop
80 | | |
81 | | |
82 | | v
83 | |
84 -------------------------- Stopping
85
86 */
87
42 MediaCodecPlayer::MediaCodecPlayer( 88 MediaCodecPlayer::MediaCodecPlayer(
43 int player_id, 89 int player_id,
44 MediaPlayerManager* manager, 90 base::WeakPtr<MediaPlayerManager> manager,
45 const RequestMediaResourcesCB& request_media_resources_cb, 91 const RequestMediaResourcesCB& request_media_resources_cb,
46 scoped_ptr<DemuxerAndroid> demuxer, 92 scoped_ptr<DemuxerAndroid> demuxer,
47 const GURL& frame_url) 93 const GURL& frame_url)
48 : MediaPlayerAndroid(player_id, 94 : MediaPlayerAndroid(player_id,
49 manager, 95 manager.get(),
50 request_media_resources_cb, 96 request_media_resources_cb,
51 frame_url), 97 frame_url),
52 ui_task_runner_(base::MessageLoopProxy::current()), 98 ui_task_runner_(base::MessageLoopProxy::current()),
53 demuxer_(demuxer.Pass()), 99 demuxer_(demuxer.Pass()),
100 state_(STATE_PAUSED),
101 interpolator_(&default_tick_clock_),
102 pending_start_(false),
54 weak_factory_(this) { 103 weak_factory_(this) {
55 // UI thread 104 // UI thread
56 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 105 DCHECK(ui_task_runner_->BelongsToCurrentThread());
57 106
58 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id; 107 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id;
59 108
109 request_resources_cb_ = base::Bind(request_media_resources_cb_, player_id);
110
111 time_update_cb_ = base::Bind(
112 &MediaPlayerManager::OnTimeUpdate, manager, player_id);
113 completion_cb_ = base::Bind(
114 &MediaPlayerManager::OnPlaybackComplete, manager, player_id);
115 attach_listener_cb_ = base::Bind(
116 &MediaPlayerAndroid::AttachListener, WeakPtrForUIThread(), nullptr);
117 detach_listener_cb_ = base::Bind(
118 &MediaPlayerAndroid::DetachListener, WeakPtrForUIThread());
119 metadata_changed_cb_ = base::Bind(
120 &MediaPlayerAndroid::OnMediaMetadataChanged, WeakPtrForUIThread());
121
60 weak_this_ = weak_factory_.GetWeakPtr(); 122 weak_this_ = weak_factory_.GetWeakPtr();
61 123
62 // Finish initializaton on Media thread 124 // Finish initializaton on Media thread
63 GetMediaTaskRunner()->PostTask( 125 GetMediaTaskRunner()->PostTask(
64 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, weak_this_)); 126 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, weak_this_));
65 } 127 }
66 128
67 MediaCodecPlayer::~MediaCodecPlayer() 129 MediaCodecPlayer::~MediaCodecPlayer()
68 { 130 {
69 // Media thread 131 // Media thread
70 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer"; 132 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer";
71 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 133 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
134
135 // Stop decoder threads before destroying decoders
136 ReleaseDecoderResources();
72 } 137 }
73 138
74 void MediaCodecPlayer::Initialize() { 139 void MediaCodecPlayer::Initialize() {
75 // Media thread 140 // Media thread
76 DVLOG(1) << __FUNCTION__; 141 DVLOG(1) << __FUNCTION__;
77 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 142 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
78 143
79 demuxer_->Initialize(this); 144 demuxer_->Initialize(this);
145
146 interpolator_.SetUpperBound(base::TimeDelta());
147
148 CreateDecoders();
80 } 149 }
81 150
82 // MediaPlayerAndroid implementation. 151 // The implementation of MediaPlayerAndroid interface.
83 152
84 void MediaCodecPlayer::DeleteOnCorrectThread() { 153 void MediaCodecPlayer::DeleteOnCorrectThread() {
85 // UI thread 154 // UI thread
86 DVLOG(1) << __FUNCTION__; 155 DVLOG(1) << __FUNCTION__;
87 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 156 DCHECK(ui_task_runner_->BelongsToCurrentThread());
88 157
89 // The listener-related portion of the base class has to be 158 DetachListener();
90 // destroyed on UI thread. 159
160 // The base class part that deals with MediaPlayerListener
161 // has to be destroyed on UI thread.
91 DestroyListenerOnUIThread(); 162 DestroyListenerOnUIThread();
92 163
93 // Post deletion onto Media thread 164 // Post deletion onto Media thread
94 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this); 165 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this);
95 } 166 }
96 167
97 void MediaCodecPlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { 168 void MediaCodecPlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) {
98 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface)); 169 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface));
99 170
100 // Media thread 171 // Media thread
101 DVLOG(1) << __FUNCTION__; 172 DVLOG(1) << __FUNCTION__ << (surface.IsEmpty() ? " empty" : " non-empty");
102 173
103 NOTIMPLEMENTED(); 174 // I assume that if video decoder already has the surface,
175 // there will be two calls:
176 // (1) SetVideoSurface(0)
177 // (2) SetVideoSurface(new_surface)
178 video_decoder_->SetPendingSurface(surface.Pass());
179
180 if (video_decoder_->HasPendingSurface() &&
181 state_ == STATE_WAITING_FOR_SURFACE) {
182 SetState(STATE_PLAYING);
183 StartPlaybackDecoders();
184 }
104 } 185 }
105 186
106 void MediaCodecPlayer::Start() { 187 void MediaCodecPlayer::Start() {
107 RUN_ON_MEDIA_THREAD(Start); 188 RUN_ON_MEDIA_THREAD(Start);
108 189
109 // Media thread 190 // Media thread
110 DVLOG(1) << __FUNCTION__; 191 DVLOG(1) << __FUNCTION__;
111 192
112 NOTIMPLEMENTED(); 193 switch (state_) {
194 case STATE_PAUSED:
195 if (HasAudio() || HasVideo()) {
196 SetState(STATE_PREFETCHING);
197 StartPrefetchDecoders();
198 } else {
199 SetState(STATE_WAITING_FOR_CONFIG);
200 }
201 break;
202 case STATE_STOPPING:
203 SetPendingStart(true);
204 break;
205 default:
206 // Ignore
207 break;
208 }
113 } 209 }
114 210
115 void MediaCodecPlayer::Pause(bool is_media_related_action) { 211 void MediaCodecPlayer::Pause(bool is_media_related_action) {
116 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action); 212 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action);
117 213
118 // Media thread 214 // Media thread
119 DVLOG(1) << __FUNCTION__; 215 DVLOG(1) << __FUNCTION__;
120 216
121 NOTIMPLEMENTED(); 217 switch (state_) {
218 case STATE_PREFETCHING:
219 SetState(STATE_PAUSED);
220 StopDecoders();
221 break;
222 case STATE_WAITING_FOR_SURFACE:
223 SetState(STATE_PAUSED);
224 StopDecoders();
225 break;
226 case STATE_PLAYING:
227 SetState(STATE_STOPPING);
228 RequestToStopDecoders();
229 break;
230 default:
231 // Ignore
232 break;
233 }
122 } 234 }
123 235
124 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) { 236 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) {
125 RUN_ON_MEDIA_THREAD(SeekTo, timestamp); 237 RUN_ON_MEDIA_THREAD(SeekTo, timestamp);
126 238
127 // Media thread 239 // Media thread
128 DVLOG(1) << __FUNCTION__ << " " << timestamp; 240 DVLOG(1) << __FUNCTION__ << " " << timestamp;
129
130 NOTIMPLEMENTED(); 241 NOTIMPLEMENTED();
131 } 242 }
132 243
133 void MediaCodecPlayer::Release() { 244 void MediaCodecPlayer::Release() {
134 RUN_ON_MEDIA_THREAD(Release); 245 RUN_ON_MEDIA_THREAD(Release);
135 246
136 // Media thread 247 // Media thread
137 DVLOG(1) << __FUNCTION__; 248 DVLOG(1) << __FUNCTION__;
138 249
139 NOTIMPLEMENTED(); 250 SetState(STATE_PAUSED);
251 ReleaseDecoderResources();
140 } 252 }
141 253
142 void MediaCodecPlayer::SetVolume(double volume) { 254 void MediaCodecPlayer::SetVolume(double volume) {
143 RUN_ON_MEDIA_THREAD(SetVolume, volume); 255 RUN_ON_MEDIA_THREAD(SetVolume, volume);
144 256
145 // Media thread 257 // Media thread
146 DVLOG(1) << __FUNCTION__ << " " << volume; 258 DVLOG(1) << __FUNCTION__ << " " << volume;
147 259 audio_decoder_->SetVolume(volume);
148 NOTIMPLEMENTED();
149 } 260 }
150 261
151 int MediaCodecPlayer::GetVideoWidth() { 262 int MediaCodecPlayer::GetVideoWidth() {
152 // UI thread 263 // UI thread
153 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 264 DCHECK(ui_task_runner_->BelongsToCurrentThread());
154 265 return cache_.video_size.width();
155 NOTIMPLEMENTED();
156 return 320;
157 } 266 }
158 267
159 int MediaCodecPlayer::GetVideoHeight() { 268 int MediaCodecPlayer::GetVideoHeight() {
160 // UI thread 269 // UI thread
161 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 270 DCHECK(ui_task_runner_->BelongsToCurrentThread());
162 271 return cache_.video_size.height();
163 NOTIMPLEMENTED();
164 return 240;
165 } 272 }
166 273
167 base::TimeDelta MediaCodecPlayer::GetCurrentTime() { 274 base::TimeDelta MediaCodecPlayer::GetCurrentTime() {
168 // UI thread, Media thread 275 // UI thread, Media thread
169 NOTIMPLEMENTED(); 276 base::TimeDelta interpolator_result;
170 return base::TimeDelta(); 277 {
278 base::AutoLock lock(interpolator_lock_);
279 interpolator_result = interpolator_.GetInterpolatedTime();
280 }
281 return std::min(interpolator_result, duration_);
171 } 282 }
172 283
173 base::TimeDelta MediaCodecPlayer::GetDuration() { 284 base::TimeDelta MediaCodecPlayer::GetDuration() {
174 // UI thread 285 // UI thread
175 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 286 DCHECK(ui_task_runner_->BelongsToCurrentThread());
176 287 return duration_;
177 NOTIMPLEMENTED();
178 return base::TimeDelta();
179 } 288 }
180 289
181 bool MediaCodecPlayer::IsPlaying() { 290 bool MediaCodecPlayer::IsPlaying() {
182 // UI thread 291 // UI thread
183 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 292 DCHECK(ui_task_runner_->BelongsToCurrentThread());
184 NOTIMPLEMENTED(); 293 return state_ == STATE_PLAYING;
185 return false;
186 } 294 }
187 295
188 bool MediaCodecPlayer::CanPause() { 296 bool MediaCodecPlayer::CanPause() {
189 // UI thread 297 // UI thread
190 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 298 DCHECK(ui_task_runner_->BelongsToCurrentThread());
191 NOTIMPLEMENTED(); 299 NOTIMPLEMENTED();
192 return false; 300 return false;
193 } 301 }
194 302
195 bool MediaCodecPlayer::CanSeekForward() { 303 bool MediaCodecPlayer::CanSeekForward() {
196 // UI thread 304 // UI thread
197 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 305 DCHECK(ui_task_runner_->BelongsToCurrentThread());
198 NOTIMPLEMENTED(); 306 NOTIMPLEMENTED();
199 return false; 307 return false;
200 } 308 }
201 309
202 bool MediaCodecPlayer::CanSeekBackward() { 310 bool MediaCodecPlayer::CanSeekBackward() {
203 // UI thread 311 // UI thread
204 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 312 DCHECK(ui_task_runner_->BelongsToCurrentThread());
205 NOTIMPLEMENTED(); 313 NOTIMPLEMENTED();
206 return false; 314 return false;
207 } 315 }
208 316
209 bool MediaCodecPlayer::IsPlayerReady() { 317 bool MediaCodecPlayer::IsPlayerReady() {
210 // UI thread 318 // UI thread
211 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 319 DCHECK(ui_task_runner_->BelongsToCurrentThread());
212 NOTIMPLEMENTED(); 320 // This method is called to check whether it' save to release
321 // this player if the OS needs more resources.
322 // For this player Release() can be called at any time.
213 return true; 323 return true;
214 } 324 }
215 325
216 void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) { 326 void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) {
217 // UI thread 327 // UI thread
218 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 328 DCHECK(ui_task_runner_->BelongsToCurrentThread());
219 NOTIMPLEMENTED(); 329 NOTIMPLEMENTED();
220 } 330 }
221 331
222 // Callbacks from Demuxer. 332 // Callbacks from Demuxer.
223 333
224 void MediaCodecPlayer::OnDemuxerConfigsAvailable( 334 void MediaCodecPlayer::OnDemuxerConfigsAvailable(
225 const DemuxerConfigs& configs) { 335 const DemuxerConfigs& configs) {
226 // Media thread 336 // Media thread
227 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 337 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
228 338
229 NOTIMPLEMENTED(); 339 DVLOG(1) << __FUNCTION__;
340
341 duration_ = configs.duration;
342
343 SetDemuxerConfigs(configs);
344
345 // Post on UI thread
346 ui_task_runner_->PostTask(
347 FROM_HERE, base::Bind(metadata_changed_cb_, duration_, gfx::Size()));
230 } 348 }
231 349
232 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) { 350 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) {
233 // Media thread 351 // Media thread
234 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 352 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
235 NOTIMPLEMENTED(); 353
354 DCHECK_LT(0u, data.access_units.size());
355 CHECK_GE(1u, data.demuxer_configs.size());
356
357 DVLOG(2) << "Player::" << __FUNCTION__;
358
359 if (data.type == DemuxerStream::AUDIO)
360 audio_decoder_->OnDemuxerDataAvailable(data);
361
362 if (data.type == DemuxerStream::VIDEO)
363 video_decoder_->OnDemuxerDataAvailable(data);
236 } 364 }
237 365
238 void MediaCodecPlayer::OnDemuxerSeekDone( 366 void MediaCodecPlayer::OnDemuxerSeekDone(
239 base::TimeDelta actual_browser_seek_time) { 367 base::TimeDelta actual_browser_seek_time) {
240 // Media thread 368 // Media thread
241 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 369 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
370
371 DVLOG(1) << __FUNCTION__ << " actual_time:" << actual_browser_seek_time;
372
242 NOTIMPLEMENTED(); 373 NOTIMPLEMENTED();
243 } 374 }
244 375
245 void MediaCodecPlayer::OnDemuxerDurationChanged( 376 void MediaCodecPlayer::OnDemuxerDurationChanged(
246 base::TimeDelta duration) { 377 base::TimeDelta duration) {
247 // Media thread 378 // Media thread
248 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 379 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
249 NOTIMPLEMENTED(); 380 DVLOG(1) << __FUNCTION__ << " duration:" << duration;
381
382 duration_ = duration;
383
384 // Post on UI thread
385 ui_task_runner_->PostTask(
386 FROM_HERE, base::Bind(metadata_changed_cb_, duration_, gfx::Size()));
387 }
388
389 // Event from Player and Decoders, called on UI thread
390
391 void MediaCodecPlayer::OnMediaMetadataChanged(base::TimeDelta duration,
392 const gfx::Size& video_size) {
393 // UI thread
394 DCHECK(ui_task_runner_->BelongsToCurrentThread());
395
396 if (duration != kNoTimestamp())
397 cache_.duration = duration;
398
399 if (!video_size.IsEmpty())
400 cache_.video_size = video_size;
401
402 manager()->OnMediaMetadataChanged(
403 player_id(), cache_.duration, cache_.video_size.width(),
404 cache_.video_size.height(), true);
405 }
406
407 // Events from Decoders, called on Media thread
408
409 void MediaCodecPlayer::RequestDemuxerData(DemuxerStream::Type stream_type) {
410 DVLOG(1) << __FUNCTION__ << " streamType:" << stream_type;
411
412 // Use this method instead of directly binding with
413 // DemuxerAndroid::RequestDemuxerData() to avoid the race condition
414 // on deletion:
415 // 1. DeleteSoon is posted from UI to Media thread.
416 // 2. RequestDemuxerData callback is posted from Decoder to Media thread.
417 // 3. DestroySelf arrives, we delete the player and detach from
wolenetz 2015/05/20 18:20:04 DestroySelf?
Tima Vaisburd 2015/05/22 23:37:52 Fixed.
418 // BrowserDemuxerAndroid.
419 // 4. RequestDemuxerData is sent to the player, but weak_ptr blocks it.
420 // If we used DemuxerAndroid::RequestDemuxerData() it would arrive,
421 // but the client (i.e. this player) would not exist.
422 demuxer_->RequestDemuxerData(stream_type);
423 }
424
425 void MediaCodecPlayer::OnPrefetchDone() {
426 // Media thread
427 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
428 DVLOG(1) << __FUNCTION__;
429
430 if (state_ != STATE_PREFETCHING)
431 return; // Ignore
432
433 if (!HasAudio() && !HasVideo()) {
434 // No configuration at all after prefetching.
435 // This is an error, initial configuration is expected
436 // before the first data chunk.
437 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
438 return;
439 }
440
441 if (HasVideo() && !HasPendingSurface()) {
442 SetState(STATE_WAITING_FOR_SURFACE);
443 return;
444 }
445
446 SetState(STATE_PLAYING);
447 StartPlaybackDecoders();
448 }
449
450 void MediaCodecPlayer::OnStarvation() {
451 // Media thread
452 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
453 DVLOG(1) << __FUNCTION__;
454
455 if (state_ != STATE_PLAYING)
456 return; // Ignore
457
458 SetState(STATE_STOPPING);
459 RequestToStopDecoders();
460 SetPendingStart(true);
461 }
462
463 void MediaCodecPlayer::OnStopDone() {
464 // Media thread
465 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
466 DVLOG(1) << __FUNCTION__;
467
468 if (!(audio_decoder_->IsStopped() && video_decoder_->IsStopped()))
469 return; // Wait until other stream is stopped
470
471 // At this point decoder threads should not be running
472 if (interpolator_.interpolating())
473 interpolator_.StopInterpolating();
474
475 switch (state_) {
476 case STATE_STOPPING:
477 if (HasPendingStart()) {
478 SetPendingStart(false);
479 SetState(STATE_PREFETCHING);
480 StartPrefetchDecoders();
481 } else {
482 SetState(STATE_PAUSED);
483 }
484 break;
485 case STATE_PLAYING:
486 // Unexpected stop means completion
487 SetState(STATE_PAUSED);
488 break;
489 default:
490 NOTREACHED();
491 break;
492 }
493
494 // DetachListener to UI thread
495 ui_task_runner_->PostTask(FROM_HERE, detach_listener_cb_);
496
497 if (AudioFinished() && VideoFinished())
498 ui_task_runner_->PostTask(FROM_HERE, completion_cb_);
499 }
500
501 void MediaCodecPlayer::OnError() {
502 // Media thread
503 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
504 DVLOG(1) << __FUNCTION__;
505
506 // STATE_ERROR blocks all events
507 SetState(STATE_ERROR);
508
509 ReleaseDecoderResources();
510 }
511
512 // Event from Decoders, called on Decoder thread
513
514 void MediaCodecPlayer::OnTimeIntervalUpdate(base::TimeDelta now_playing,
515 base::TimeDelta last_buffered) {
516 // Decoder thread
517 base::TimeDelta current_time;
518 {
519 base::AutoLock lock(interpolator_lock_);
520 interpolator_.SetBounds(now_playing, last_buffered);
521
522 current_time = std::min(interpolator_.GetInterpolatedTime(), duration_);
523 }
524
525 // Post on UI thread
526 ui_task_runner_->PostTask(
527 FROM_HERE,
528 base::Bind(time_update_cb_, current_time, base::TimeTicks::Now()));
529 }
530
531 // State machine operations, called on Media thread
532
533 void MediaCodecPlayer::SetState(PlayerState new_state) {
534 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
535
536 DVLOG(1) << "SetState:" << AsString(state_) << " -> " << AsString(new_state);
537 state_ = new_state;
538 }
539
540 #undef ENTRY
541 #define ENTRY(x) case x: return #x;
542
543 const char* MediaCodecPlayer::AsString(PlayerState state) {
544 switch (state) {
545 ENTRY(STATE_PAUSED);
546 ENTRY(STATE_WAITING_FOR_CONFIG);
547 ENTRY(STATE_PREFETCHING);
548 ENTRY(STATE_PLAYING);
549 ENTRY(STATE_STOPPING);
550 ENTRY(STATE_WAITING_FOR_SURFACE);
551 ENTRY(STATE_WAITING_FOR_SEEK);
552 ENTRY(STATE_ERROR);
553 default: return "Unknown PlayerState";
554 }
555 }
556 #undef ENTRY
557
558 void MediaCodecPlayer::SetPendingSurface(gfx::ScopedJavaSurface surface) {
559 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
560 DVLOG(1) << __FUNCTION__;
561
562 video_decoder_->SetPendingSurface(surface.Pass());
563 }
564
565 bool MediaCodecPlayer::HasPendingSurface() {
566 return video_decoder_->HasPendingSurface();
567 }
568
569 void MediaCodecPlayer::SetPendingStart(bool need_to_start) {
570 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
571 DVLOG(1) << __FUNCTION__ << ": " << need_to_start;
572 pending_start_ = need_to_start;
573 }
574
575 bool MediaCodecPlayer::HasPendingStart() {
576 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
577 return pending_start_;
578 }
579
580 bool MediaCodecPlayer::HasAudio() {
581 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
582 return audio_decoder_->HasStream();
583 }
584
585 bool MediaCodecPlayer::HasVideo() {
586 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
587 return video_decoder_->HasStream();
588 }
589
590 void MediaCodecPlayer::CreateDecoders() {
591 // Media thread
592 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
593 DVLOG(1) << __FUNCTION__;
594
595 error_cb_ = base::Bind(&MediaCodecPlayer::OnError, weak_this_);
596
597 audio_decoder_.reset(new MediaCodecAudioDecoder(
598 GetMediaTaskRunner(),
599 ui_task_runner_,
600 base::Bind(&MediaCodecPlayer::RequestDemuxerData, weak_this_,
601 DemuxerStream::AUDIO),
602 base::Bind(&MediaCodecPlayer::OnStarvation, weak_this_),
603 base::Bind(&MediaCodecPlayer::OnStopDone, weak_this_),
604 error_cb_,
605 base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate,
606 base::Unretained(this))));
607
608 video_decoder_.reset(new MediaCodecVideoDecoder(
609 GetMediaTaskRunner(),
610 ui_task_runner_,
611 base::Bind(&MediaCodecPlayer::RequestDemuxerData, weak_this_,
612 DemuxerStream::VIDEO),
613 base::Bind(&MediaCodecPlayer::OnStarvation, weak_this_),
614 base::Bind(&MediaCodecPlayer::OnStopDone, weak_this_),
615 error_cb_,
616 metadata_changed_cb_,
617 request_resources_cb_));
618 }
619
620 bool MediaCodecPlayer::AudioFinished() {
621 return audio_decoder_->IsCompleted() || !audio_decoder_->HasStream();
622 }
623
624 bool MediaCodecPlayer::VideoFinished() {
625 return video_decoder_->IsCompleted() || !video_decoder_->HasStream();
626 }
627
628 void MediaCodecPlayer::SetDemuxerConfigs(const DemuxerConfigs& configs) {
629 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
630 DVLOG(1) << __FUNCTION__
631 << (configs.audio_codec != kUnknownAudioCodec ? " AUDIO" : "")
632 << (configs.video_codec != kUnknownVideoCodec ? " VIDEO" : "");
633
634 if (configs.audio_codec != kUnknownAudioCodec)
635 audio_decoder_->SetDemuxerConfigs(configs);
636
637 if (configs.video_codec != kUnknownVideoCodec)
638 video_decoder_->SetDemuxerConfigs(configs);
639
640 if (state_ == STATE_WAITING_FOR_CONFIG) {
641 SetState(STATE_PREFETCHING);
642 StartPrefetchDecoders();
643 }
644 }
645
646 void MediaCodecPlayer::StartPrefetchDecoders() {
647 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
648 DVLOG(1) << __FUNCTION__;
649
650 bool do_audio = false;
651 bool do_video = false;
652 int count = 0;
653 if (!AudioFinished()) {
654 do_audio = true;
655 ++count;
656 }
657 if (!VideoFinished()) {
658 do_video = true;
659 ++count;
660 }
661
662 DCHECK_LT(0, count); // at least one decoder should be active
663
664 base::Closure prefetch_cb = base::BarrierClosure(
665 count, base::Bind(&MediaCodecPlayer::OnPrefetchDone, weak_this_));
666
667 if (do_audio)
668 audio_decoder_->Prefetch(prefetch_cb);
669
670 if (do_video)
671 video_decoder_->Prefetch(prefetch_cb);
672 }
673
674 void MediaCodecPlayer::StartPlaybackDecoders() {
675 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
676 DVLOG(1) << __FUNCTION__;
677
678 // Configure all streams before the start since
679 // we may discover that browser seek is required.
680
681 bool do_audio = !AudioFinished();
682 bool do_video = !VideoFinished();
683
684 // If there is nothing to play, the state machine should determine
685 // this at the prefetch state and never call this method.
686 DCHECK(do_audio || do_video);
687
688 if (do_audio) {
689 MediaCodecDecoder::ConfigStatus status = audio_decoder_->Configure();
690 if (status != MediaCodecDecoder::CONFIG_OK) {
691 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
692 return;
693 }
694 }
695
696 if (do_video) {
697 MediaCodecDecoder::ConfigStatus status = video_decoder_->Configure();
698 if (status != MediaCodecDecoder::CONFIG_OK) {
699 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
700 return;
701 }
702 }
703
704 // At this point decoder threads should not be running
705 if (!interpolator_.interpolating())
706 interpolator_.StartInterpolating();
707
708 if (do_audio) {
709 if (!audio_decoder_->Start(GetCurrentTime())) {
710 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
711 return;
712 }
713
714 // Attach listener on UI thread
715 ui_task_runner_->PostTask(FROM_HERE, attach_listener_cb_);
716 }
717
718 if (do_video) {
719 if (!video_decoder_->Start(GetCurrentTime())) {
720 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
721 return;
722 }
723 }
724 }
725
726 void MediaCodecPlayer::StopDecoders() {
727 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
728 DVLOG(1) << __FUNCTION__;
729
730 audio_decoder_->SyncStop();
731 video_decoder_->SyncStop();
732 }
733
734 void MediaCodecPlayer::RequestToStopDecoders() {
735 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
736 DVLOG(1) << __FUNCTION__;
737
738 bool do_audio = false;
739 bool do_video = false;
740
741 if (audio_decoder_->IsPrefetchingOrPlaying())
742 do_audio = true;
743 if (video_decoder_->IsPrefetchingOrPlaying())
744 do_video = true;
745
746 if (!do_audio && !do_video) {
747 GetMediaTaskRunner()->PostTask(
748 FROM_HERE, base::Bind(&MediaCodecPlayer::OnStopDone, weak_this_));
749 return;
750 }
751
752 if (do_audio)
753 audio_decoder_->RequestToStop();
754 if (do_video)
755 video_decoder_->RequestToStop();
756 }
757
758 void MediaCodecPlayer::ReleaseDecoderResources() {
759 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
760 DVLOG(1) << __FUNCTION__;
761
762 audio_decoder_->ReleaseDecoderResources();
763 video_decoder_->ReleaseDecoderResources();
764
765 // At this point decoder threads should not be running
766 if (interpolator_.interpolating())
767 interpolator_.StopInterpolating();
250 } 768 }
251 769
252 } // namespace media 770 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698