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

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

Powered by Google App Engine
This is Rietveld 408576698