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

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: AccessUnitQueue::GetInfo() returns result by value Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/android/media_codec_player.h" 5 #include "media/base/android/media_codec_player.h"
6 6
7 #include "base/barrier_closure.h"
7 #include "base/bind.h" 8 #include "base/bind.h"
8 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/threading/thread.h"
12 #include "media/base/android/media_codec_audio_decoder.h"
13 #include "media/base/android/media_codec_video_decoder.h"
14 #include "media/base/android/media_player_manager.h"
15 #include "media/base/buffers.h"
10 16
11 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \ 17 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \
12 do { \ 18 do { \
13 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \ 19 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
14 GetMediaTaskRunner()->PostTask( \ 20 GetMediaTaskRunner()->PostTask( \
15 FROM_HERE, \ 21 FROM_HERE, \
16 base::Bind(&MediaCodecPlayer:: METHOD, weak_this_, ##__VA_ARGS__)); \ 22 base::Bind(&MediaCodecPlayer:: METHOD, weak_this_, ##__VA_ARGS__)); \
17 return; \ 23 return; \
18 } \ 24 } \
19 } while(0) 25 } while(0)
(...skipping 14 matching lines...) Expand all
34 40
35 41
36 scoped_refptr<base::SingleThreadTaskRunner> GetMediaTaskRunner() { 42 scoped_refptr<base::SingleThreadTaskRunner> GetMediaTaskRunner() {
37 return g_media_thread.Pointer()->task_runner(); 43 return g_media_thread.Pointer()->task_runner();
38 } 44 }
39 45
40 // MediaCodecPlayer implementation. 46 // MediaCodecPlayer implementation.
41 47
42 MediaCodecPlayer::MediaCodecPlayer( 48 MediaCodecPlayer::MediaCodecPlayer(
43 int player_id, 49 int player_id,
44 MediaPlayerManager* manager, 50 base::WeakPtr<MediaPlayerManager> manager,
45 const RequestMediaResourcesCB& request_media_resources_cb, 51 const RequestMediaResourcesCB& request_media_resources_cb,
46 scoped_ptr<DemuxerAndroid> demuxer, 52 scoped_ptr<DemuxerAndroid> demuxer,
47 const GURL& frame_url) 53 const GURL& frame_url)
48 : MediaPlayerAndroid(player_id, 54 : MediaPlayerAndroid(player_id,
49 manager, 55 manager.get(),
50 request_media_resources_cb, 56 request_media_resources_cb,
51 frame_url), 57 frame_url),
52 ui_task_runner_(base::MessageLoopProxy::current()), 58 ui_task_runner_(base::MessageLoopProxy::current()),
53 demuxer_(demuxer.Pass()), 59 demuxer_(demuxer.Pass()),
60 state_(STATE_PAUSED),
61 interpolator_(&default_tick_clock_),
62 pending_start_(false),
54 weak_factory_(this) { 63 weak_factory_(this) {
55 // UI thread
56 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 64 DCHECK(ui_task_runner_->BelongsToCurrentThread());
57 65
58 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id; 66 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id;
59 67
68 request_resources_cb_ = base::Bind(request_media_resources_cb_, player_id);
69
70 completion_cb_ = base::Bind(
71 &MediaPlayerManager::OnPlaybackComplete, manager, player_id);
72 attach_listener_cb_ = base::Bind(
73 &MediaPlayerAndroid::AttachListener, WeakPtrForUIThread(), nullptr);
74 detach_listener_cb_ = base::Bind(
75 &MediaPlayerAndroid::DetachListener, WeakPtrForUIThread());
76 metadata_changed_cb_ = base::Bind(
77 &MediaPlayerAndroid::OnMediaMetadataChanged, WeakPtrForUIThread());
78 time_update_cb_ = base::Bind(
79 &MediaPlayerAndroid::OnTimeUpdate, WeakPtrForUIThread());
80
60 weak_this_ = weak_factory_.GetWeakPtr(); 81 weak_this_ = weak_factory_.GetWeakPtr();
61 82
62 // Finish initializaton on Media thread 83 // Finish initializaton on Media thread
63 GetMediaTaskRunner()->PostTask( 84 GetMediaTaskRunner()->PostTask(
64 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, weak_this_)); 85 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, weak_this_));
65 } 86 }
66 87
67 MediaCodecPlayer::~MediaCodecPlayer() 88 MediaCodecPlayer::~MediaCodecPlayer()
68 { 89 {
69 // Media thread
70 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer"; 90 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer";
71 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 91 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
92
93 // Stop decoder threads before destroying decoders
94 ReleaseDecoderResources();
72 } 95 }
73 96
74 void MediaCodecPlayer::Initialize() { 97 void MediaCodecPlayer::Initialize() {
75 // Media thread
76 DVLOG(1) << __FUNCTION__; 98 DVLOG(1) << __FUNCTION__;
77 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 99 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
78 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().
79 demuxer_->Initialize(this); 107 demuxer_->Initialize(this);
80 } 108 }
81 109
82 // MediaPlayerAndroid implementation. 110 // The implementation of MediaPlayerAndroid interface.
83 111
84 void MediaCodecPlayer::DeleteOnCorrectThread() { 112 void MediaCodecPlayer::DeleteOnCorrectThread() {
85 // UI thread
86 DVLOG(1) << __FUNCTION__; 113 DVLOG(1) << __FUNCTION__;
87 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 114 DCHECK(ui_task_runner_->BelongsToCurrentThread());
88 115
89 // The listener-related portion of the base class has to be 116 DetachListener();
90 // destroyed on UI thread. 117
118 // The base class part that deals with MediaPlayerListener
119 // has to be destroyed on UI thread.
91 DestroyListenerOnUIThread(); 120 DestroyListenerOnUIThread();
92 121
93 // Post deletion onto Media thread 122 // Post deletion onto Media thread
94 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this); 123 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this);
95 } 124 }
96 125
97 void MediaCodecPlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { 126 void MediaCodecPlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) {
98 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface)); 127 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface));
99 128
100 // Media thread 129 DVLOG(1) << __FUNCTION__ << (surface.IsEmpty() ? " empty" : " non-empty");
101 DVLOG(1) << __FUNCTION__;
102 130
103 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 }
104 } 142 }
105 143
106 void MediaCodecPlayer::Start() { 144 void MediaCodecPlayer::Start() {
107 RUN_ON_MEDIA_THREAD(Start); 145 RUN_ON_MEDIA_THREAD(Start);
108 146
109 // Media thread
110 DVLOG(1) << __FUNCTION__; 147 DVLOG(1) << __FUNCTION__;
111 148
112 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 }
113 } 165 }
114 166
115 void MediaCodecPlayer::Pause(bool is_media_related_action) { 167 void MediaCodecPlayer::Pause(bool is_media_related_action) {
116 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action); 168 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action);
117 169
118 // Media thread
119 DVLOG(1) << __FUNCTION__; 170 DVLOG(1) << __FUNCTION__;
120 171
121 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 }
122 } 189 }
123 190
124 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) { 191 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) {
125 RUN_ON_MEDIA_THREAD(SeekTo, timestamp); 192 RUN_ON_MEDIA_THREAD(SeekTo, timestamp);
126 193
127 // Media thread
128 DVLOG(1) << __FUNCTION__ << " " << timestamp; 194 DVLOG(1) << __FUNCTION__ << " " << timestamp;
129
130 NOTIMPLEMENTED(); 195 NOTIMPLEMENTED();
131 } 196 }
132 197
133 void MediaCodecPlayer::Release() { 198 void MediaCodecPlayer::Release() {
134 RUN_ON_MEDIA_THREAD(Release); 199 RUN_ON_MEDIA_THREAD(Release);
135 200
136 // Media thread
137 DVLOG(1) << __FUNCTION__; 201 DVLOG(1) << __FUNCTION__;
138 202
139 NOTIMPLEMENTED(); 203 SetState(STATE_PAUSED);
204 ReleaseDecoderResources();
140 } 205 }
141 206
142 void MediaCodecPlayer::SetVolume(double volume) { 207 void MediaCodecPlayer::SetVolume(double volume) {
143 RUN_ON_MEDIA_THREAD(SetVolume, volume); 208 RUN_ON_MEDIA_THREAD(SetVolume, volume);
144 209
145 // Media thread
146 DVLOG(1) << __FUNCTION__ << " " << volume; 210 DVLOG(1) << __FUNCTION__ << " " << volume;
147 211 audio_decoder_->SetVolume(volume);
148 NOTIMPLEMENTED();
149 } 212 }
150 213
151 int MediaCodecPlayer::GetVideoWidth() { 214 int MediaCodecPlayer::GetVideoWidth() {
152 // UI thread
153 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 215 DCHECK(ui_task_runner_->BelongsToCurrentThread());
154 216 return metadata_cache_.video_size.width();
155 NOTIMPLEMENTED();
156 return 320;
157 } 217 }
158 218
159 int MediaCodecPlayer::GetVideoHeight() { 219 int MediaCodecPlayer::GetVideoHeight() {
160 // UI thread
161 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 220 DCHECK(ui_task_runner_->BelongsToCurrentThread());
162 221 return metadata_cache_.video_size.height();
163 NOTIMPLEMENTED();
164 return 240;
165 } 222 }
166 223
167 base::TimeDelta MediaCodecPlayer::GetCurrentTime() { 224 base::TimeDelta MediaCodecPlayer::GetCurrentTime() {
168 // UI thread, Media thread 225 DCHECK(ui_task_runner_->BelongsToCurrentThread());
169 NOTIMPLEMENTED(); 226 return current_time_cache_;
170 return base::TimeDelta();
171 } 227 }
172 228
173 base::TimeDelta MediaCodecPlayer::GetDuration() { 229 base::TimeDelta MediaCodecPlayer::GetDuration() {
174 // UI thread
175 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 230 DCHECK(ui_task_runner_->BelongsToCurrentThread());
176 231 return metadata_cache_.duration;
177 NOTIMPLEMENTED();
178 return base::TimeDelta();
179 } 232 }
180 233
181 bool MediaCodecPlayer::IsPlaying() { 234 bool MediaCodecPlayer::IsPlaying() {
182 // UI thread
183 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 235 DCHECK(ui_task_runner_->BelongsToCurrentThread());
184 NOTIMPLEMENTED(); 236 return state_ == STATE_PLAYING;
185 return false;
186 } 237 }
187 238
188 bool MediaCodecPlayer::CanPause() { 239 bool MediaCodecPlayer::CanPause() {
189 // UI thread
190 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 240 DCHECK(ui_task_runner_->BelongsToCurrentThread());
191 NOTIMPLEMENTED(); 241 NOTIMPLEMENTED();
192 return false; 242 return false;
193 } 243 }
194 244
195 bool MediaCodecPlayer::CanSeekForward() { 245 bool MediaCodecPlayer::CanSeekForward() {
196 // UI thread
197 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 246 DCHECK(ui_task_runner_->BelongsToCurrentThread());
198 NOTIMPLEMENTED(); 247 NOTIMPLEMENTED();
199 return false; 248 return false;
200 } 249 }
201 250
202 bool MediaCodecPlayer::CanSeekBackward() { 251 bool MediaCodecPlayer::CanSeekBackward() {
203 // UI thread
204 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 252 DCHECK(ui_task_runner_->BelongsToCurrentThread());
205 NOTIMPLEMENTED(); 253 NOTIMPLEMENTED();
206 return false; 254 return false;
207 } 255 }
208 256
209 bool MediaCodecPlayer::IsPlayerReady() { 257 bool MediaCodecPlayer::IsPlayerReady() {
210 // UI thread
211 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 258 DCHECK(ui_task_runner_->BelongsToCurrentThread());
212 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.
213 return true; 261 return true;
214 } 262 }
215 263
216 void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) { 264 void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) {
217 // UI thread
218 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 265 DCHECK(ui_task_runner_->BelongsToCurrentThread());
219 NOTIMPLEMENTED(); 266 NOTIMPLEMENTED();
220 } 267 }
221 268
222 // Callbacks from Demuxer. 269 // Callbacks from Demuxer.
223 270
224 void MediaCodecPlayer::OnDemuxerConfigsAvailable( 271 void MediaCodecPlayer::OnDemuxerConfigsAvailable(
225 const DemuxerConfigs& configs) { 272 const DemuxerConfigs& configs) {
226 // Media thread 273 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
227 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 274
228 275 DVLOG(1) << __FUNCTION__;
229 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));
230 } 285 }
231 286
232 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) { 287 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) {
233 // Media thread 288 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
234 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 289
235 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);
236 } 300 }
237 301
238 void MediaCodecPlayer::OnDemuxerSeekDone( 302 void MediaCodecPlayer::OnDemuxerSeekDone(
239 base::TimeDelta actual_browser_seek_time) { 303 base::TimeDelta actual_browser_seek_time) {
240 // Media thread 304 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
241 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 305
306 DVLOG(1) << __FUNCTION__ << " actual_time:" << actual_browser_seek_time;
307
242 NOTIMPLEMENTED(); 308 NOTIMPLEMENTED();
243 } 309 }
244 310
245 void MediaCodecPlayer::OnDemuxerDurationChanged( 311 void MediaCodecPlayer::OnDemuxerDurationChanged(
246 base::TimeDelta duration) { 312 base::TimeDelta duration) {
247 // Media thread 313 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
248 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 314 DVLOG(1) << __FUNCTION__ << " duration:" << duration;
249 NOTIMPLEMENTED(); 315
250 } 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(
336 player_id(), metadata_cache_.duration, 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(
459 FROM_HERE, 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(),
676 base::Bind(&MediaCodecPlayer::RequestDemuxerData, weak_this_,
677 DemuxerStream::AUDIO),
678 base::Bind(&MediaCodecPlayer::OnStarvation, weak_this_),
679 base::Bind(&MediaCodecPlayer::OnStopDone, weak_this_),
680 error_cb_,
681 base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate, weak_this_)));
liberato (no reviews please) 2015/06/09 15:44:31 who calls the time interval update cb if there's n
Tima Vaisburd 2015/06/09 17:38:27 Noone! This part is not finished.
682
683 video_decoder_.reset(new MediaCodecVideoDecoder(
684 GetMediaTaskRunner(),
685 base::Bind(&MediaCodecPlayer::RequestDemuxerData, weak_this_,
686 DemuxerStream::VIDEO),
687 base::Bind(&MediaCodecPlayer::OnStarvation, weak_this_),
688 base::Bind(&MediaCodecPlayer::OnStopDone, weak_this_),
689 error_cb_,
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) case x: 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: return "Unknown PlayerState";
723 }
724 }
725 #undef RETURN_STRING
251 726
252 } // namespace media 727 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698