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

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

Powered by Google App Engine
This is Rietveld 408576698