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

Side by Side Diff: media/base/android/media_codec_decoder.cc

Issue 1312103006: MediaCodecPlayer - preroll and reconfiguration fixes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mtplayer-reconfig
Patch Set: Addressed Min's comments, small changes in stop sequence Created 5 years, 3 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_decoder.h" 5 #include "media/base/android/media_codec_decoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/callback_helpers.h" 9 #include "base/callback_helpers.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 decoder_thread_(decoder_thread_name), 43 decoder_thread_(decoder_thread_name),
44 needs_reconfigure_(false), 44 needs_reconfigure_(false),
45 drain_decoder_(false), 45 drain_decoder_(false),
46 always_reconfigure_for_tests_(false), 46 always_reconfigure_for_tests_(false),
47 external_request_data_cb_(external_request_data_cb), 47 external_request_data_cb_(external_request_data_cb),
48 starvation_cb_(starvation_cb), 48 starvation_cb_(starvation_cb),
49 decoder_drained_cb_(decoder_drained_cb), 49 decoder_drained_cb_(decoder_drained_cb),
50 stop_done_cb_(stop_done_cb), 50 stop_done_cb_(stop_done_cb),
51 error_cb_(error_cb), 51 error_cb_(error_cb),
52 state_(kStopped), 52 state_(kStopped),
53 preroll_mode_(kPrerollTillPTS), 53 is_prepared_(false),
54 eos_enqueued_(false), 54 eos_enqueued_(false),
55 completed_(false), 55 completed_(false),
56 last_frame_posted_(false), 56 last_frame_posted_(false),
57 is_data_request_in_progress_(false), 57 is_data_request_in_progress_(false),
58 is_incoming_data_invalid_(false), 58 is_incoming_data_invalid_(false),
59 #ifndef NDEBUG 59 #ifndef NDEBUG
60 verify_next_frame_is_key_(false), 60 verify_next_frame_is_key_(false),
61 #endif 61 #endif
62 weak_factory_(this) { 62 weak_factory_(this) {
63 DCHECK(media_task_runner_->BelongsToCurrentThread()); 63 DCHECK(media_task_runner_->BelongsToCurrentThread());
(...skipping 24 matching lines...) Expand all
88 // Flush() is a part of the Seek request. Whenever we request a seek we need 88 // Flush() is a part of the Seek request. Whenever we request a seek we need
89 // to invalidate the current data request. 89 // to invalidate the current data request.
90 if (is_data_request_in_progress_) 90 if (is_data_request_in_progress_)
91 is_incoming_data_invalid_ = true; 91 is_incoming_data_invalid_ = true;
92 92
93 eos_enqueued_ = false; 93 eos_enqueued_ = false;
94 completed_ = false; 94 completed_ = false;
95 drain_decoder_ = false; 95 drain_decoder_ = false;
96 au_queue_.Flush(); 96 au_queue_.Flush();
97 97
98 // |is_prepared_| is set on the decoder thread, it shouldn't be running now.
99 DCHECK(!decoder_thread_.IsRunning());
100 is_prepared_ = false;
101
98 #ifndef NDEBUG 102 #ifndef NDEBUG
99 // We check and reset |verify_next_frame_is_key_| on Decoder thread. 103 // We check and reset |verify_next_frame_is_key_| on Decoder thread.
100 // This DCHECK ensures we won't need to lock this variable. 104 // We have just DCHECKed that decoder thread is not running.
101 DCHECK(!decoder_thread_.IsRunning());
102 105
103 // For video the first frame after flush must be key frame. 106 // For video the first frame after flush must be key frame.
104 verify_next_frame_is_key_ = true; 107 verify_next_frame_is_key_ = true;
105 #endif 108 #endif
106 109
107 preroll_mode_ = kPrerollTillPTS;
108
109 if (media_codec_bridge_) { 110 if (media_codec_bridge_) {
110 // MediaCodecBridge::Reset() performs MediaCodecBridge.flush() 111 // MediaCodecBridge::Reset() performs MediaCodecBridge.flush()
111 MediaCodecStatus flush_status = media_codec_bridge_->Reset(); 112 MediaCodecStatus flush_status = media_codec_bridge_->Reset();
112 if (flush_status != MEDIA_CODEC_OK) { 113 if (flush_status != MEDIA_CODEC_OK) {
113 DVLOG(0) << class_name() << "::" << __FUNCTION__ 114 DVLOG(0) << class_name() << "::" << __FUNCTION__
114 << "MediaCodecBridge::Reset() failed"; 115 << "MediaCodecBridge::Reset() failed";
115 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); 116 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
116 } 117 }
117 } 118 }
118 } 119 }
119 120
120 void MediaCodecDecoder::ReleaseMediaCodec() { 121 void MediaCodecDecoder::ReleaseMediaCodec() {
121 DCHECK(media_task_runner_->BelongsToCurrentThread()); 122 DCHECK(media_task_runner_->BelongsToCurrentThread());
122 123
123 DVLOG(1) << class_name() << "::" << __FUNCTION__; 124 DVLOG(1) << class_name() << "::" << __FUNCTION__;
124 125
126 DCHECK(!decoder_thread_.IsRunning());
127
125 media_codec_bridge_.reset(); 128 media_codec_bridge_.reset();
126 preroll_mode_ = kPrerollTillPTS; 129
130 // |is_prepared_| is set on the decoder thread, it shouldn't be running now.
131 is_prepared_ = false;
127 } 132 }
128 133
129 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { 134 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const {
130 DCHECK(media_task_runner_->BelongsToCurrentThread()); 135 DCHECK(media_task_runner_->BelongsToCurrentThread());
131 136
132 // Whether decoder needs to be stopped. 137 // Whether decoder needs to be stopped.
133 base::AutoLock lock(state_lock_); 138 base::AutoLock lock(state_lock_);
134 switch (state_) { 139 switch (state_) {
135 case kPrefetching: 140 case kPrefetching:
136 case kPrefetched: 141 case kPrefetched:
(...skipping 19 matching lines...) Expand all
156 161
157 bool MediaCodecDecoder::IsCompleted() const { 162 bool MediaCodecDecoder::IsCompleted() const {
158 DCHECK(media_task_runner_->BelongsToCurrentThread()); 163 DCHECK(media_task_runner_->BelongsToCurrentThread());
159 164
160 return completed_; 165 return completed_;
161 } 166 }
162 167
163 bool MediaCodecDecoder::NotCompletedAndNeedsPreroll() const { 168 bool MediaCodecDecoder::NotCompletedAndNeedsPreroll() const {
164 DCHECK(media_task_runner_->BelongsToCurrentThread()); 169 DCHECK(media_task_runner_->BelongsToCurrentThread());
165 170
166 return HasStream() && preroll_mode_ != kNoPreroll && !completed_; 171 return HasStream() && !completed_ &&
172 (!is_prepared_ || preroll_timestamp_ != base::TimeDelta());
167 } 173 }
168 174
169 void MediaCodecDecoder::SetDecodingUntilOutputIsPresent() { 175 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) {
170 DCHECK(media_task_runner_->BelongsToCurrentThread()); 176 DCHECK(media_task_runner_->BelongsToCurrentThread());
171 DVLOG(1) << class_name() << "::" << __FUNCTION__; 177 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp;
172 178
173 preroll_mode_ = kPrerollTillOutputIsPresent; 179 preroll_timestamp_ = preroll_timestamp;
174 } 180 }
175 181
176 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() { 182 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() {
177 base::android::ScopedJavaLocalRef<jobject> media_crypto; 183 base::android::ScopedJavaLocalRef<jobject> media_crypto;
178 184
179 // TODO(timav): implement DRM. 185 // TODO(timav): implement DRM.
180 // drm_bridge_ is not implemented 186 // drm_bridge_ is not implemented
181 // if (drm_bridge_) 187 // if (drm_bridge_)
182 // media_crypto = drm_bridge_->GetMediaCrypto(); 188 // media_crypto = drm_bridge_->GetMediaCrypto();
183 return media_crypto; 189 return media_crypto;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 DCHECK(!decoder_thread_.IsRunning()); 241 DCHECK(!decoder_thread_.IsRunning());
236 242
237 // For video the first frame after reconfiguration must be key frame. 243 // For video the first frame after reconfiguration must be key frame.
238 if (result == kConfigOk) 244 if (result == kConfigOk)
239 verify_next_frame_is_key_ = true; 245 verify_next_frame_is_key_ = true;
240 #endif 246 #endif
241 247
242 return result; 248 return result;
243 } 249 }
244 250
245 bool MediaCodecDecoder::Preroll(base::TimeDelta preroll_timestamp, 251 bool MediaCodecDecoder::Preroll(const base::Closure& preroll_done_cb) {
246 const base::Closure& preroll_done_cb) {
247 DCHECK(media_task_runner_->BelongsToCurrentThread()); 252 DCHECK(media_task_runner_->BelongsToCurrentThread());
248 253
249 DVLOG(1) << class_name() << "::" << __FUNCTION__ 254 DVLOG(1) << class_name() << "::" << __FUNCTION__
250 << " preroll_timestamp:" << preroll_timestamp; 255 << " preroll_timestamp:" << preroll_timestamp_;
251 256
252 DecoderState state = GetState(); 257 DecoderState state = GetState();
253 if (state != kPrefetched) { 258 if (state != kPrefetched) {
254 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " 259 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state "
255 << AsString(state) << ", ignoring"; 260 << AsString(state) << ", ignoring";
256 return false; 261 return false;
257 } 262 }
258 263
259 if (!media_codec_bridge_) { 264 if (!media_codec_bridge_) {
260 DVLOG(0) << class_name() << "::" << __FUNCTION__ 265 DVLOG(0) << class_name() << "::" << __FUNCTION__
261 << ": not configured, ignoring"; 266 << ": not configured, ignoring";
262 return false; 267 return false;
263 } 268 }
264 269
265 DCHECK(!decoder_thread_.IsRunning()); 270 DCHECK(!decoder_thread_.IsRunning());
266 DCHECK(preroll_mode_ != kNoPreroll);
267 271
268 preroll_done_cb_ = preroll_done_cb; 272 preroll_done_cb_ = preroll_done_cb;
269 273
270 // We only synchronize video stream. 274 // We only synchronize video stream.
271 DissociatePTSFromTime(); // associaton will happen after preroll is done. 275 DissociatePTSFromTime(); // associaton will happen after preroll is done.
272 276
273 preroll_timestamp_ = (preroll_mode_ == kPrerollTillPTS) ? preroll_timestamp
274 : base::TimeDelta();
275
276 last_frame_posted_ = false; 277 last_frame_posted_ = false;
277 278
278 // Start the decoder thread 279 // Start the decoder thread
279 if (!decoder_thread_.Start()) { 280 if (!decoder_thread_.Start()) {
280 DVLOG(0) << class_name() << "::" << __FUNCTION__ 281 DVLOG(0) << class_name() << "::" << __FUNCTION__
281 << ": cannot start decoder thread"; 282 << ": cannot start decoder thread";
282 return false; 283 return false;
283 } 284 }
284 285
285 SetState(kPrerolling); 286 SetState(kPrerolling);
(...skipping 20 matching lines...) Expand all
306 } 307 }
307 308
308 if (!media_codec_bridge_) { 309 if (!media_codec_bridge_) {
309 DVLOG(0) << class_name() << "::" << __FUNCTION__ 310 DVLOG(0) << class_name() << "::" << __FUNCTION__
310 << ": not configured, ignoring"; 311 << ": not configured, ignoring";
311 return false; 312 return false;
312 } 313 }
313 314
314 // We only synchronize video stream. 315 // We only synchronize video stream.
315 AssociateCurrentTimeWithPTS(start_timestamp); 316 AssociateCurrentTimeWithPTS(start_timestamp);
316 preroll_timestamp_ = base::TimeDelta(); 317
318 DCHECK(preroll_timestamp_ == base::TimeDelta());
317 319
318 // Start the decoder thread 320 // Start the decoder thread
319 if (!decoder_thread_.IsRunning()) { 321 if (!decoder_thread_.IsRunning()) {
320 last_frame_posted_ = false; 322 last_frame_posted_ = false;
321 if (!decoder_thread_.Start()) { 323 if (!decoder_thread_.Start()) {
322 DVLOG(1) << class_name() << "::" << __FUNCTION__ 324 DVLOG(1) << class_name() << "::" << __FUNCTION__
323 << ": cannot start decoder thread"; 325 << ": cannot start decoder thread";
324 return false; 326 return false;
325 } 327 }
326 } 328 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 break; 368 break;
367 case kPrerolling: 369 case kPrerolling:
368 case kPrerolled: 370 case kPrerolled:
369 DCHECK(decoder_thread_.IsRunning()); 371 DCHECK(decoder_thread_.IsRunning());
370 // Synchronous stop. 372 // Synchronous stop.
371 decoder_thread_.Stop(); 373 decoder_thread_.Stop();
372 SetState(kStopped); 374 SetState(kStopped);
373 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 375 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
374 break; 376 break;
375 case kStopping: 377 case kStopping:
378 case kStopped:
Tima Vaisburd 2015/09/03 19:55:27 Moved kStopped here so RequestToStop will be ignor
376 break; // ignore 379 break; // ignore
377 case kStopped:
378 case kPrefetching: 380 case kPrefetching:
379 case kPrefetched: 381 case kPrefetched:
380 // There is nothing to wait for, we can sent notification right away. 382 // There is nothing to wait for, we can sent notification right away.
381 DCHECK(!decoder_thread_.IsRunning()); 383 DCHECK(!decoder_thread_.IsRunning());
382 SetState(kStopped); 384 SetState(kStopped);
383 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 385 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
384 break; 386 break;
385 default: 387 default:
386 NOTREACHED(); 388 NOTREACHED();
387 break; 389 break;
388 } 390 }
389 } 391 }
390 392
391 void MediaCodecDecoder::OnLastFrameRendered(bool eos_encountered) { 393 void MediaCodecDecoder::OnLastFrameRendered(bool eos_encountered) {
392 DCHECK(media_task_runner_->BelongsToCurrentThread()); 394 DCHECK(media_task_runner_->BelongsToCurrentThread());
393 395
394 DVLOG(1) << class_name() << "::" << __FUNCTION__ 396 DVLOG(1) << class_name() << "::" << __FUNCTION__
395 << " eos_encountered:" << eos_encountered; 397 << " eos_encountered:" << eos_encountered;
396 398
397 decoder_thread_.Stop(); // synchronous 399 decoder_thread_.Stop(); // synchronous
398 400
399 SetState(kStopped); 401 SetState(kStopped);
400 completed_ = (eos_encountered && !drain_decoder_); 402 completed_ = (eos_encountered && !drain_decoder_);
401 403
404 // If the stream is completed during preroll we need to report it since
405 // another stream might be running and the player waits for two callbacks.
402 if (completed_ && !preroll_done_cb_.is_null()) { 406 if (completed_ && !preroll_done_cb_.is_null()) {
407 preroll_timestamp_ = base::TimeDelta();
liberato (no reviews please) 2015/09/04 21:59:13 there's a kNoTimestamp that you might want to cons
Tima Vaisburd 2015/09/04 23:17:35 Zero timestamp compares nicely at line 807, it was
403 media_task_runner_->PostTask(FROM_HERE, 408 media_task_runner_->PostTask(FROM_HERE,
404 base::ResetAndReturn(&preroll_done_cb_)); 409 base::ResetAndReturn(&preroll_done_cb_));
405 } 410 }
406 411
407 if (eos_encountered && drain_decoder_) { 412 if (eos_encountered && drain_decoder_) {
408 ReleaseMediaCodec();
409 drain_decoder_ = false; 413 drain_decoder_ = false;
410 eos_enqueued_ = false; 414 eos_enqueued_ = false;
411 preroll_mode_ = kPrerollTillOutputIsPresent; 415 ReleaseMediaCodec();
412 media_task_runner_->PostTask(FROM_HERE, decoder_drained_cb_); 416 media_task_runner_->PostTask(FROM_HERE, decoder_drained_cb_);
413 } 417 }
414 418
415 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 419 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
416 } 420 }
417 421
418 void MediaCodecDecoder::OnPrerollDone() { 422 void MediaCodecDecoder::OnPrerollDone() {
419 DCHECK(media_task_runner_->BelongsToCurrentThread()); 423 DCHECK(media_task_runner_->BelongsToCurrentThread());
420 424
421 DVLOG(1) << class_name() << "::" << __FUNCTION__; 425 DVLOG(1) << class_name() << "::" << __FUNCTION__;
422 426
423 preroll_mode_ = kNoPreroll; 427 preroll_timestamp_ = base::TimeDelta();
424 428
425 // The state might be kStopping. 429 // The state might be kStopping (?)
426 if (GetState() == kPrerolling) { 430 if (GetState() == kPrerolling)
427 SetState(kPrerolled); 431 SetState(kPrerolled);
428 media_task_runner_->PostTask(FROM_HERE, 432
429 base::ResetAndReturn(&preroll_done_cb_)); 433 if (!preroll_done_cb_.is_null())
430 } 434 base::ResetAndReturn(&preroll_done_cb_).Run();
431 } 435 }
432 436
433 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { 437 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
434 DCHECK(media_task_runner_->BelongsToCurrentThread()); 438 DCHECK(media_task_runner_->BelongsToCurrentThread());
435 439
436 // If |data| contains an aborted data, the last AU will have kAborted status. 440 // If |data| contains an aborted data, the last AU will have kAborted status.
437 bool aborted_data = 441 bool aborted_data =
438 !data.access_units.empty() && 442 !data.access_units.empty() &&
439 data.access_units.back().status == DemuxerStream::kAborted; 443 data.access_units.back().status == DemuxerStream::kAborted;
440 444
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 DVLOG(1) << class_name() << "::" << __FUNCTION__ 575 DVLOG(1) << class_name() << "::" << __FUNCTION__
572 << ": kStopping, posting OnLastFrameRendered"; 576 << ": kStopping, posting OnLastFrameRendered";
573 media_task_runner_->PostTask( 577 media_task_runner_->PostTask(
574 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, 578 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered,
575 weak_factory_.GetWeakPtr(), false)); 579 weak_factory_.GetWeakPtr(), false));
576 last_frame_posted_ = true; 580 last_frame_posted_ = true;
577 } 581 }
578 582
579 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. 583 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze.
580 // We only need to let finish the delayed rendering tasks. 584 // We only need to let finish the delayed rendering tasks.
585 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " kStopping, returning";
581 return; 586 return;
582 } 587 }
583 588
584 DCHECK(state == kPrerolling || state == kRunning); 589 DCHECK(state == kPrerolling || state == kRunning);
585 590
586 if (!EnqueueInputBuffer()) 591 if (!EnqueueInputBuffer())
587 return; 592 return;
588 593
589 if (!DepleteOutputBufferQueue()) 594 if (!DepleteOutputBufferQueue())
590 return; 595 return;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
790 795
791 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 796 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
792 DVLOG(2) << class_name() << "::" << __FUNCTION__ 797 DVLOG(2) << class_name() << "::" << __FUNCTION__
793 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; 798 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED";
794 OnOutputFormatChanged(); 799 OnOutputFormatChanged();
795 break; 800 break;
796 801
797 case MEDIA_CODEC_OK: 802 case MEDIA_CODEC_OK:
798 // We got the decoded frame. 803 // We got the decoded frame.
799 804
805 is_prepared_ = true;
806
800 if (pts < preroll_timestamp_) 807 if (pts < preroll_timestamp_)
801 render_mode = kRenderSkip; 808 render_mode = kRenderSkip;
802 else if (GetState() == kPrerolling) 809 else if (GetState() == kPrerolling)
803 render_mode = kRenderAfterPreroll; 810 render_mode = kRenderAfterPreroll;
804 else 811 else
805 render_mode = kRenderNow; 812 render_mode = kRenderNow;
806 813
807 Render(buffer_index, offset, size, render_mode, pts, eos_encountered); 814 Render(buffer_index, offset, size, render_mode, pts, eos_encountered);
808 815
809 if (render_mode == kRenderAfterPreroll) { 816 if (render_mode == kRenderAfterPreroll) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
885 RETURN_STRING(kStopping); 892 RETURN_STRING(kStopping);
886 RETURN_STRING(kInEmergencyStop); 893 RETURN_STRING(kInEmergencyStop);
887 RETURN_STRING(kError); 894 RETURN_STRING(kError);
888 } 895 }
889 return nullptr; // crash early 896 return nullptr; // crash early
890 } 897 }
891 898
892 #undef RETURN_STRING 899 #undef RETURN_STRING
893 900
894 } // namespace media 901 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698