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

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: Comments, better Listener callbacks, removed unused includes Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/android/media_codec_player.h" 5 #include "media/base/android/media_codec_player.h"
6 6
7 #include "base/barrier_closure.h"
7 #include "base/bind.h" 8 #include "base/bind.h"
8 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
9 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/threading/thread.h"
12
13 #include "media/base/android/media_codec_audio_decoder.h"
14 #include "media/base/android/media_codec_player_state.h"
15 #include "media/base/android/media_codec_video_decoder.h"
16 #include "media/base/android/media_player_manager.h"
17 #include "media/base/buffers.h"
10 18
11 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \ 19 #define RUN_ON_MEDIA_THREAD(METHOD, ...) \
12 do { \ 20 do { \
13 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \ 21 if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \
14 GetMediaTaskRunner()->PostTask( \ 22 GetMediaTaskRunner()->PostTask( \
15 FROM_HERE, \ 23 FROM_HERE, \
16 base::Bind(&MediaCodecPlayer:: METHOD, weak_this_, ##__VA_ARGS__)); \ 24 base::Bind(&MediaCodecPlayer:: METHOD, weak_this_, ##__VA_ARGS__)); \
17 return; \ 25 return; \
18 } \ 26 } \
19 } while(0) 27 } while(0)
(...skipping 10 matching lines...) Expand all
30 38
31 // Create media thread 39 // Create media thread
32 base::LazyInstance<MediaThread>::Leaky 40 base::LazyInstance<MediaThread>::Leaky
33 g_media_thread = LAZY_INSTANCE_INITIALIZER; 41 g_media_thread = LAZY_INSTANCE_INITIALIZER;
34 42
35 43
36 scoped_refptr<base::SingleThreadTaskRunner> GetMediaTaskRunner() { 44 scoped_refptr<base::SingleThreadTaskRunner> GetMediaTaskRunner() {
37 return g_media_thread.Pointer()->task_runner(); 45 return g_media_thread.Pointer()->task_runner();
38 } 46 }
39 47
48
40 // MediaCodecPlayer implementation. 49 // MediaCodecPlayer implementation.
41 50
42 MediaCodecPlayer::MediaCodecPlayer( 51 MediaCodecPlayer::MediaCodecPlayer(
43 int player_id, 52 int player_id,
44 MediaPlayerManager* manager, 53 base::WeakPtr<MediaPlayerManager> manager,
45 const RequestMediaResourcesCB& request_media_resources_cb, 54 const RequestMediaResourcesCB& request_media_resources_cb,
46 scoped_ptr<DemuxerAndroid> demuxer, 55 scoped_ptr<DemuxerAndroid> demuxer,
47 const GURL& frame_url) 56 const GURL& frame_url)
48 : MediaPlayerAndroid(player_id, 57 : MediaPlayerAndroid(player_id,
49 manager, 58 manager.get(),
50 request_media_resources_cb, 59 request_media_resources_cb,
51 frame_url), 60 frame_url),
52 ui_task_runner_(base::MessageLoopProxy::current()), 61 ui_task_runner_(base::MessageLoopProxy::current()),
53 demuxer_(demuxer.Pass()), 62 demuxer_(demuxer.Pass()),
63 state_(StatePaused::Instance()),
64 interpolator_(&default_tick_clock_),
65 pending_start_(false),
54 weak_factory_(this) { 66 weak_factory_(this) {
55 // UI thread 67 // UI thread
56 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 68 DCHECK(ui_task_runner_->BelongsToCurrentThread());
57 69
58 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id; 70 DVLOG(1) << "MediaCodecPlayer::MediaCodecPlayer: player_id:" << player_id;
59 71
72 request_resources_cb_ = base::Bind(request_media_resources_cb_, player_id);
73
74 metadata_changed_cb_ = base::Bind(
75 &MediaPlayerManager::OnMediaMetadataChanged, manager, player_id);
76 time_update_cb_ = base::Bind(
77 &MediaPlayerManager::OnTimeUpdate, manager, player_id);
78 completion_cb_ = base::Bind(
79 &MediaPlayerManager::OnPlaybackComplete, manager, player_id);
80 attach_listener_cb_ = base::Bind(
81 &MediaPlayerAndroid::AttachListener, WeakPtrForUIThread(), nullptr);
82 detach_listener_cb_ = base::Bind(
83 &MediaPlayerAndroid::DetachListener, WeakPtrForUIThread());
84
60 weak_this_ = weak_factory_.GetWeakPtr(); 85 weak_this_ = weak_factory_.GetWeakPtr();
61 86
62 // Finish initializaton on Media thread 87 // Finish initializaton on Media thread
63 GetMediaTaskRunner()->PostTask( 88 GetMediaTaskRunner()->PostTask(
64 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, weak_this_)); 89 FROM_HERE, base::Bind(&MediaCodecPlayer::Initialize, weak_this_));
65 } 90 }
66 91
67 MediaCodecPlayer::~MediaCodecPlayer() 92 MediaCodecPlayer::~MediaCodecPlayer()
68 { 93 {
69 // Media thread 94 // Media thread
70 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer"; 95 DVLOG(1) << "MediaCodecPlayer::~MediaCodecPlayer";
71 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 96 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
97
98 // Stop decoder threads before destroying decoders
99 ReleaseDecoderResources();
72 } 100 }
73 101
74 void MediaCodecPlayer::Initialize() { 102 void MediaCodecPlayer::Initialize() {
75 // Media thread 103 // Media thread
76 DVLOG(1) << __FUNCTION__; 104 DVLOG(1) << __FUNCTION__;
77 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 105 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
78 106
79 demuxer_->Initialize(this); 107 demuxer_->Initialize(this);
108
109 interpolator_.SetUpperBound(base::TimeDelta());
110
111 CreateDecoders();
80 } 112 }
81 113
82 // MediaPlayerAndroid implementation. 114 // The implementation of MediaPlayerAndroid interface.
83 115
84 void MediaCodecPlayer::DeleteOnCorrectThread() { 116 void MediaCodecPlayer::DeleteOnCorrectThread() {
85 // UI thread 117 // UI thread
86 DVLOG(1) << __FUNCTION__; 118 DVLOG(1) << __FUNCTION__;
87 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 119 DCHECK(ui_task_runner_->BelongsToCurrentThread());
88 120
89 // The listener-related portion of the base class has to be 121 DetachListener();
90 // destroyed on UI thread. 122
123 // The base class part that deals with MediaPlayerListener
124 // has to be destroyed on UI thread.
91 DestroyListenerOnUIThread(); 125 DestroyListenerOnUIThread();
92 126
93 // Post deletion onto Media thread 127 // Post deletion onto Media thread
94 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this); 128 GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this);
95 } 129 }
96 130
97 void MediaCodecPlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { 131 void MediaCodecPlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) {
98 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface)); 132 RUN_ON_MEDIA_THREAD(SetVideoSurface, base::Passed(&surface));
99 133
100 // Media thread 134 // Media thread
101 DVLOG(1) << __FUNCTION__; 135 DVLOG(1) << __FUNCTION__ << (surface.IsEmpty() ? " empty" : " non-empty");
102 136
103 NOTIMPLEMENTED(); 137 // I assume that if video decoder already has the surface,
138 // there will be two calls:
139 // (1) SetVideoSurface(0)
140 // (2) SetVideoSurface(new_surface)
141 video_decoder_->SetPendingSurface(surface.Pass());
142
143 if (!video_decoder_->HasPendingSurface())
144 state_->EventVideoSurfaceRemoved(this);
145 else
146 state_->EventSetVideoSurface(this);
104 } 147 }
105 148
106 void MediaCodecPlayer::Start() { 149 void MediaCodecPlayer::Start() {
107 RUN_ON_MEDIA_THREAD(Start); 150 RUN_ON_MEDIA_THREAD(Start);
108 151
109 // Media thread 152 // Media thread
110 DVLOG(1) << __FUNCTION__; 153 DVLOG(1) << __FUNCTION__;
111 154 state_->EventStart(this);
112 NOTIMPLEMENTED();
113 } 155 }
114 156
115 void MediaCodecPlayer::Pause(bool is_media_related_action) { 157 void MediaCodecPlayer::Pause(bool is_media_related_action) {
116 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action); 158 RUN_ON_MEDIA_THREAD(Pause, is_media_related_action);
117 159
118 // Media thread 160 // Media thread
119 DVLOG(1) << __FUNCTION__; 161 DVLOG(1) << __FUNCTION__;
120 162 state_->EventPause(this);
121 NOTIMPLEMENTED();
122 } 163 }
123 164
124 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) { 165 void MediaCodecPlayer::SeekTo(base::TimeDelta timestamp) {
125 RUN_ON_MEDIA_THREAD(SeekTo, timestamp); 166 RUN_ON_MEDIA_THREAD(SeekTo, timestamp);
126 167
127 // Media thread 168 // Media thread
128 DVLOG(1) << __FUNCTION__ << " " << timestamp; 169 DVLOG(1) << __FUNCTION__ << " " << timestamp;
129 170 state_->EventSeekTo(this, timestamp);
130 NOTIMPLEMENTED();
131 } 171 }
132 172
133 void MediaCodecPlayer::Release() { 173 void MediaCodecPlayer::Release() {
134 RUN_ON_MEDIA_THREAD(Release); 174 RUN_ON_MEDIA_THREAD(Release);
135 175
136 // Media thread 176 // Media thread
137 DVLOG(1) << __FUNCTION__; 177 DVLOG(1) << __FUNCTION__;
138 178 state_->EventRelease(this);
139 NOTIMPLEMENTED();
140 } 179 }
141 180
142 void MediaCodecPlayer::SetVolume(double volume) { 181 void MediaCodecPlayer::SetVolume(double volume) {
143 RUN_ON_MEDIA_THREAD(SetVolume, volume); 182 RUN_ON_MEDIA_THREAD(SetVolume, volume);
144 183
145 // Media thread 184 // Media thread
146 DVLOG(1) << __FUNCTION__ << " " << volume; 185 DVLOG(1) << __FUNCTION__ << " " << volume;
147 186 audio_decoder_->SetVolume(volume);
148 NOTIMPLEMENTED();
149 } 187 }
150 188
151 int MediaCodecPlayer::GetVideoWidth() { 189 int MediaCodecPlayer::GetVideoWidth() {
152 // UI thread 190 // UI thread, Media thread
153 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 191 return video_decoder_->GetVideoWidth();
154
155 NOTIMPLEMENTED();
156 return 320;
157 } 192 }
158 193
159 int MediaCodecPlayer::GetVideoHeight() { 194 int MediaCodecPlayer::GetVideoHeight() {
160 // UI thread 195 // UI thread, Media thread
161 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 196 return video_decoder_->GetVideoHeight();
162
163 NOTIMPLEMENTED();
164 return 240;
165 } 197 }
166 198
167 base::TimeDelta MediaCodecPlayer::GetCurrentTime() { 199 base::TimeDelta MediaCodecPlayer::GetCurrentTime() {
168 // UI thread, Media thread 200 // UI thread, Media thread
169 NOTIMPLEMENTED(); 201 base::TimeDelta interpolator_result;
170 return base::TimeDelta(); 202 {
203 base::AutoLock lock(interpolator_lock_);
204 interpolator_result = interpolator_.GetInterpolatedTime();
205 }
206 return std::min(interpolator_result, duration_);
171 } 207 }
172 208
173 base::TimeDelta MediaCodecPlayer::GetDuration() { 209 base::TimeDelta MediaCodecPlayer::GetDuration() {
174 // UI thread 210 // UI thread
175 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 211 DCHECK(ui_task_runner_->BelongsToCurrentThread());
176 212 return duration_;
177 NOTIMPLEMENTED();
178 return base::TimeDelta();
179 } 213 }
180 214
181 bool MediaCodecPlayer::IsPlaying() { 215 bool MediaCodecPlayer::IsPlaying() {
182 // UI thread 216 // UI thread
183 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 217 DCHECK(ui_task_runner_->BelongsToCurrentThread());
184 NOTIMPLEMENTED(); 218 return state_ == StatePlaying::Instance();
185 return false;
186 } 219 }
187 220
188 bool MediaCodecPlayer::CanPause() { 221 bool MediaCodecPlayer::CanPause() {
189 // UI thread 222 // UI thread
190 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 223 DCHECK(ui_task_runner_->BelongsToCurrentThread());
191 NOTIMPLEMENTED(); 224 NOTIMPLEMENTED();
192 return false; 225 return false;
193 } 226 }
194 227
195 bool MediaCodecPlayer::CanSeekForward() { 228 bool MediaCodecPlayer::CanSeekForward() {
196 // UI thread 229 // UI thread
197 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 230 DCHECK(ui_task_runner_->BelongsToCurrentThread());
198 NOTIMPLEMENTED(); 231 NOTIMPLEMENTED();
199 return false; 232 return false;
200 } 233 }
201 234
202 bool MediaCodecPlayer::CanSeekBackward() { 235 bool MediaCodecPlayer::CanSeekBackward() {
203 // UI thread 236 // UI thread
204 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 237 DCHECK(ui_task_runner_->BelongsToCurrentThread());
205 NOTIMPLEMENTED(); 238 NOTIMPLEMENTED();
206 return false; 239 return false;
207 } 240 }
208 241
209 bool MediaCodecPlayer::IsPlayerReady() { 242 bool MediaCodecPlayer::IsPlayerReady() {
210 // UI thread 243 // UI thread
211 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 244 DCHECK(ui_task_runner_->BelongsToCurrentThread());
212 NOTIMPLEMENTED(); 245 // This method is called to check whether it' save to release
246 // this player if the OS needs more resources.
247 // For this player Release() can be called at any time.
213 return true; 248 return true;
214 } 249 }
215 250
216 void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) { 251 void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) {
217 // UI thread 252 // UI thread
218 DCHECK(ui_task_runner_->BelongsToCurrentThread()); 253 DCHECK(ui_task_runner_->BelongsToCurrentThread());
219 NOTIMPLEMENTED(); 254 NOTIMPLEMENTED();
220 } 255 }
221 256
222 // Callbacks from Demuxer. 257 // Callbacks from Demuxer.
223 258
224 void MediaCodecPlayer::OnDemuxerConfigsAvailable( 259 void MediaCodecPlayer::OnDemuxerConfigsAvailable(
225 const DemuxerConfigs& configs) { 260 const DemuxerConfigs& configs) {
226 // Media thread 261 // Media thread
227 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 262 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
228 263
229 NOTIMPLEMENTED(); 264 duration_ = configs.duration;
265
266 state_->EventDemuxerConfigsAvailable(this, configs);
267
268 // Post on UI thread
269 ui_task_runner_->PostTask(
270 FROM_HERE,
271 base::Bind(metadata_changed_cb_, duration_,
272 GetVideoWidth(), GetVideoHeight(), true));
230 } 273 }
231 274
232 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) { 275 void MediaCodecPlayer::OnDemuxerDataAvailable(const DemuxerData& data) {
233 // Media thread 276 // Media thread
234 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 277 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
235 NOTIMPLEMENTED(); 278
279 DCHECK_LT(0u, data.access_units.size());
280 CHECK_GE(1u, data.demuxer_configs.size());
281
282 DVLOG(2) << "Player::" << __FUNCTION__;
283
284 if (data.type == DemuxerStream::AUDIO)
285 audio_decoder_->OnDemuxerDataAvailable(data);
286
287 if (data.type == DemuxerStream::VIDEO)
288 video_decoder_->OnDemuxerDataAvailable(data);
236 } 289 }
237 290
238 void MediaCodecPlayer::OnDemuxerSeekDone( 291 void MediaCodecPlayer::OnDemuxerSeekDone(
239 base::TimeDelta actual_browser_seek_time) { 292 base::TimeDelta actual_browser_seek_time) {
240 // Media thread 293 // Media thread
241 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 294 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
295
296 DVLOG(1) << __FUNCTION__ << " actual_time:" << actual_browser_seek_time;
297
242 NOTIMPLEMENTED(); 298 NOTIMPLEMENTED();
243 } 299 }
244 300
245 void MediaCodecPlayer::OnDemuxerDurationChanged( 301 void MediaCodecPlayer::OnDemuxerDurationChanged(
246 base::TimeDelta duration) { 302 base::TimeDelta duration) {
247 // Media thread 303 // Media thread
248 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); 304 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
249 NOTIMPLEMENTED(); 305 DVLOG(1) << __FUNCTION__ << " duration:" << duration;
306 duration_ = duration;
307 }
308
309
310 // Events from Decoders, called on Media thread
311
312 void MediaCodecPlayer::RequestDemuxerData(DemuxerStream::Type stream_type) {
313 DVLOG(1) << __FUNCTION__ << " streamType:" << stream_type;
314
315 // Use this method instead of directly binding with
316 // DemuxerAndroid::RequestDemuxerData() to avoid the race condition
317 // on deletion:
318 // 1. DestroySelf is posted from UI to Media thread.
319 // 2. RequestDemuxerData callback is posted from Decoder to Media thread.
320 // 3. DestroySelf arrives, we delete the player and detach from
321 // BrowserDemuxerAndroid.
322 // 4. RequestDemuxerData is sent to the player, but weak_ptr blocks it.
323 // If we used DemuxerAndroid::RequestDemuxerData() it would arrive,
324 // but the client (i.e. this player) would not exist.
325 demuxer_->RequestDemuxerData(stream_type);
326 }
327
328 void MediaCodecPlayer::OnPrefetchDone() {
329 // Media thread
330 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
331 DVLOG(1) << __FUNCTION__;
332 state_->EventPrefetchDone(this);
333 }
334
335 void MediaCodecPlayer::OnStarvation() {
336 // Media thread
337 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
338 DVLOG(1) << __FUNCTION__;
339 state_->EventStarvation(this);
340 }
341
342 void MediaCodecPlayer::OnStopDone() {
343 // Media thread
344 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
345 DVLOG(1) << __FUNCTION__;
346
347 if (audio_decoder_->IsStopped() && video_decoder_->IsStopped()) {
348 // At this point decoder threads should not be running
349 if (interpolator_.interpolating())
350 interpolator_.StopInterpolating();
351
352 state_->EventStopDone(this);
353
354 // DetachListener to UI thread
355 ui_task_runner_->PostTask(FROM_HERE, detach_listener_cb_);
356
357 if (AudioFinished() && VideoFinished())
358 ui_task_runner_->PostTask(FROM_HERE, completion_cb_);
359 }
360 }
361
362 void MediaCodecPlayer::OnError() {
363 // Media thread
364 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
365 DVLOG(1) << __FUNCTION__;
366 state_->EventError(this);
367 }
368
369 // Event from Decoders, called on Decoder thread
370
371 void MediaCodecPlayer::OnTimeIntervalUpdate(base::TimeDelta now_playing,
372 base::TimeDelta last_buffered) {
373 // Decoder thread
374 base::TimeDelta current_time;
375 {
376 base::AutoLock lock(interpolator_lock_);
377 interpolator_.SetBounds(now_playing, last_buffered);
378
379 current_time = std::min(interpolator_.GetInterpolatedTime(), duration_);
380 }
381
382 // Post on UI thread
383 ui_task_runner_->PostTask(
384 FROM_HERE,
385 base::Bind(time_update_cb_, current_time, base::TimeTicks::Now()));
386 }
387
388 // State machine operations, called on Media thread
389
390 void MediaCodecPlayer::SetState(MediaCodecPlayerState* new_state) {
391 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
392 DCHECK(new_state);
393 DVLOG(1) << "SetState:" << state_->name() << " -> " << new_state->name();
394
395 state_ = new_state;
396 }
397
398 void MediaCodecPlayer::SetPendingSurface(gfx::ScopedJavaSurface surface) {
399 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
400 DVLOG(1) << __FUNCTION__;
401
402 video_decoder_->SetPendingSurface(surface.Pass());
403 }
404
405 bool MediaCodecPlayer::HasPendingSurface() {
406 return video_decoder_->HasPendingSurface();
407 }
408
409 void MediaCodecPlayer::SetPendingStart(bool need_to_start) {
410 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
411 DVLOG(1) << __FUNCTION__ << ": " << need_to_start;
412 pending_start_ = need_to_start;
413 }
414
415 bool MediaCodecPlayer::HasPendingStart() {
416 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
417 // Return and reset.
418 bool ret = pending_start_;
419 pending_start_ = false;
420 return ret;
421 }
422
423 bool MediaCodecPlayer::HasAudio() {
424 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
425 return audio_decoder_->HasStream();
426 }
427
428 bool MediaCodecPlayer::HasVideo() {
429 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
430 return video_decoder_->HasStream();
431 }
432
433 void MediaCodecPlayer::CreateDecoders() {
434 // Media thread
435 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
436 DVLOG(1) << __FUNCTION__;
437
438 error_cb_ = base::Bind(&MediaCodecPlayer::OnError, weak_this_);
439
440 audio_decoder_.reset(new MediaCodecAudioDecoder(
441 GetMediaTaskRunner(),
442 ui_task_runner_,
443 base::Bind(&MediaCodecPlayer::RequestDemuxerData, weak_this_,
444 DemuxerStream::AUDIO),
445 base::Bind(&MediaCodecPlayer::OnStarvation, weak_this_),
446 base::Bind(&MediaCodecPlayer::OnStopDone, weak_this_),
447 error_cb_,
448 base::Bind(&MediaCodecPlayer::OnTimeIntervalUpdate,
449 base::Unretained(this))));
450
451 video_decoder_.reset(new MediaCodecVideoDecoder(
452 GetMediaTaskRunner(),
453 ui_task_runner_,
454 base::Bind(&MediaCodecPlayer::RequestDemuxerData, weak_this_,
455 DemuxerStream::VIDEO),
456 base::Bind(&MediaCodecPlayer::OnStarvation, weak_this_),
457 base::Bind(&MediaCodecPlayer::OnStopDone, weak_this_),
458 error_cb_,
459 request_resources_cb_));
460 }
461
462 bool MediaCodecPlayer::AudioFinished() {
463 return audio_decoder_->IsCompleted() || !audio_decoder_->HasStream();
464 }
465
466 bool MediaCodecPlayer::VideoFinished() {
467 return video_decoder_->IsCompleted() || !video_decoder_->HasStream();
468 }
469
470 void MediaCodecPlayer::SetDemuxerConfigs(const DemuxerConfigs& configs) {
471 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
472 DVLOG(1) << __FUNCTION__;
473
474 if (configs.audio_codec != kUnknownAudioCodec)
475 audio_decoder_->SetDemuxerConfigs(configs);
476
477 if (configs.video_codec != kUnknownVideoCodec)
478 video_decoder_->SetDemuxerConfigs(configs);
479 }
480
481 void MediaCodecPlayer::StartPrefetchDecoders() {
482 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
483 DVLOG(1) << __FUNCTION__;
484
485 bool do_audio = false;
486 bool do_video = false;
487 int count = 0;
488 if (!AudioFinished()) {
489 do_audio = true;
490 ++count;
491 }
492 if (!VideoFinished()) {
493 do_video = true;
494 ++count;
495 }
496
497 DCHECK_LT(0, count); // at least one decoder should be active
498
499 base::Closure prefetch_cb = base::BarrierClosure(
500 count, base::Bind(&MediaCodecPlayer::OnPrefetchDone, weak_this_));
501
502 if (do_audio)
503 audio_decoder_->Prefetch(prefetch_cb);
504
505 if (do_video)
506 video_decoder_->Prefetch(prefetch_cb);
507 }
508
509 void MediaCodecPlayer::StartPlaybackDecoders() {
510 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
511 DVLOG(1) << __FUNCTION__;
512
513 // Configure all streams before the start since
514 // we may discover that browser seek is required.
515
516 bool do_audio = !AudioFinished();
517 bool do_video = !VideoFinished();
518
519 // If there is nothing to play, the state machine should determine
520 // this at the prefetch state and never call this method.
521 DCHECK(do_audio || do_video);
522
523 if (do_audio) {
524 MediaCodecDecoder::ConfigStatus status = audio_decoder_->Configure();
525 if (status != MediaCodecDecoder::CONFIG_OK) {
526 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
527 return;
528 }
529 }
530
531 if (do_video) {
532 MediaCodecDecoder::ConfigStatus status = video_decoder_->Configure();
533 if (status != MediaCodecDecoder::CONFIG_OK) {
534 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
535 return;
536 }
537 }
538
539 // At this point decoder threads should not be running
540 if (!interpolator_.interpolating())
541 interpolator_.StartInterpolating();
542
543 if (do_audio) {
544 if (!audio_decoder_->Start(GetCurrentTime())) {
545 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
546 return;
547 }
548
549 // Attach listener on UI thread
550 ui_task_runner_->PostTask(FROM_HERE, attach_listener_cb_);
551 }
552
553 if (do_video) {
554 if (!video_decoder_->Start(GetCurrentTime())) {
555 GetMediaTaskRunner()->PostTask(FROM_HERE, error_cb_);
556 return;
557 }
558 }
559 }
560
561 void MediaCodecPlayer::StopDecoders() {
562 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
563 DVLOG(1) << __FUNCTION__;
564
565 audio_decoder_->SyncStop();
566 video_decoder_->SyncStop();
567 }
568
569 void MediaCodecPlayer::RequestToStopDecoders() {
570 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
571 DVLOG(1) << __FUNCTION__;
572
573 bool do_audio = false;
574 bool do_video = false;
575 int count = 0;
576 if (audio_decoder_->IsPrefetchingOrPlaying()) {
577 do_audio = true;
578 ++count;
579 }
580 if (video_decoder_->IsPrefetchingOrPlaying()) {
581 do_video = true;
582 ++count;
583 }
584
585 if (count == 0) {
586 GetMediaTaskRunner()->PostTask(
587 FROM_HERE, base::Bind(&MediaCodecPlayer::OnStopDone, weak_this_));
588 return;
589 }
590
591 if (do_audio)
592 audio_decoder_->RequestToStop();
593
594 if (do_video)
595 video_decoder_->RequestToStop();
596 }
597
598 void MediaCodecPlayer::ReleaseDecoderResources() {
599 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
600 DVLOG(1) << __FUNCTION__;
601
602 audio_decoder_->ReleaseDecoderResources();
603 video_decoder_->ReleaseDecoderResources();
604
605 // At this point decoder threads should not be running
606 if (interpolator_.interpolating())
607 interpolator_.StopInterpolating();
250 } 608 }
251 609
252 } // namespace media 610 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698