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

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

Powered by Google App Engine
This is Rietveld 408576698