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

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

Powered by Google App Engine
This is Rietveld 408576698