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

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

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

Powered by Google App Engine
This is Rietveld 408576698