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

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

Powered by Google App Engine
This is Rietveld 408576698