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

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

Powered by Google App Engine
This is Rietveld 408576698