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

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

Powered by Google App Engine
This is Rietveld 408576698