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

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: Added more unit tests 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 97
98 #ifndef NDEBUG 98 #ifndef NDEBUG
99 // We check and reset |verify_next_frame_is_key_| on Decoder thread. 99 // We check and reset |verify_next_frame_is_key_| on Decoder thread.
100 // This DCHECK ensures we won't need to lock this variable. 100 // This DCHECK ensures we won't need to lock this variable.
101 DCHECK(!decoder_thread_.IsRunning()); 101 DCHECK(!decoder_thread_.IsRunning());
102 102
103 // For video the first frame after flush must be key frame. 103 // For video the first frame after flush must be key frame.
104 verify_next_frame_is_key_ = true; 104 verify_next_frame_is_key_ = true;
105 #endif 105 #endif
106 106
107 preroll_mode_ = kPrerollTillPTS; 107 is_prepared_ = false;
108 108
109 if (media_codec_bridge_) { 109 if (media_codec_bridge_) {
110 // MediaCodecBridge::Reset() performs MediaCodecBridge.flush() 110 // MediaCodecBridge::Reset() performs MediaCodecBridge.flush()
111 MediaCodecStatus flush_status = media_codec_bridge_->Reset(); 111 MediaCodecStatus flush_status = media_codec_bridge_->Reset();
112 if (flush_status != MEDIA_CODEC_OK) { 112 if (flush_status != MEDIA_CODEC_OK) {
113 DVLOG(0) << class_name() << "::" << __FUNCTION__ 113 DVLOG(0) << class_name() << "::" << __FUNCTION__
114 << "MediaCodecBridge::Reset() failed"; 114 << "MediaCodecBridge::Reset() failed";
115 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_); 115 media_task_runner_->PostTask(FROM_HERE, internal_error_cb_);
116 } 116 }
117 } 117 }
118 } 118 }
119 119
120 void MediaCodecDecoder::ReleaseMediaCodec() { 120 void MediaCodecDecoder::ReleaseMediaCodec() {
121 DCHECK(media_task_runner_->BelongsToCurrentThread()); 121 DCHECK(media_task_runner_->BelongsToCurrentThread());
122 122
123 DVLOG(1) << class_name() << "::" << __FUNCTION__; 123 DVLOG(1) << class_name() << "::" << __FUNCTION__;
124 124
125 media_codec_bridge_.reset(); 125 media_codec_bridge_.reset();
126 preroll_mode_ = kPrerollTillPTS; 126 is_prepared_ = false;
qinmin 2015/09/03 05:30:04 this variable is updated on both decoder thread an
Tima Vaisburd 2015/09/03 19:55:27 During Flush() and ReleaseMediaCodec() the decoder
127 } 127 }
128 128
129 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const { 129 bool MediaCodecDecoder::IsPrefetchingOrPlaying() const {
130 DCHECK(media_task_runner_->BelongsToCurrentThread()); 130 DCHECK(media_task_runner_->BelongsToCurrentThread());
131 131
132 // Whether decoder needs to be stopped. 132 // Whether decoder needs to be stopped.
133 base::AutoLock lock(state_lock_); 133 base::AutoLock lock(state_lock_);
134 switch (state_) { 134 switch (state_) {
135 case kPrefetching: 135 case kPrefetching:
136 case kPrefetched: 136 case kPrefetched:
(...skipping 19 matching lines...) Expand all
156 156
157 bool MediaCodecDecoder::IsCompleted() const { 157 bool MediaCodecDecoder::IsCompleted() const {
158 DCHECK(media_task_runner_->BelongsToCurrentThread()); 158 DCHECK(media_task_runner_->BelongsToCurrentThread());
159 159
160 return completed_; 160 return completed_;
161 } 161 }
162 162
163 bool MediaCodecDecoder::NotCompletedAndNeedsPreroll() const { 163 bool MediaCodecDecoder::NotCompletedAndNeedsPreroll() const {
164 DCHECK(media_task_runner_->BelongsToCurrentThread()); 164 DCHECK(media_task_runner_->BelongsToCurrentThread());
165 165
166 return HasStream() && preroll_mode_ != kNoPreroll && !completed_; 166 return HasStream() && !completed_ &&
167 (!is_prepared_ || preroll_timestamp_ != base::TimeDelta());
167 } 168 }
168 169
169 void MediaCodecDecoder::SetDecodingUntilOutputIsPresent() { 170 void MediaCodecDecoder::SetPrerollTimestamp(base::TimeDelta preroll_timestamp) {
170 DCHECK(media_task_runner_->BelongsToCurrentThread()); 171 DCHECK(media_task_runner_->BelongsToCurrentThread());
171 DVLOG(1) << class_name() << "::" << __FUNCTION__; 172 DVLOG(1) << class_name() << "::" << __FUNCTION__ << ": " << preroll_timestamp;
172 173
173 preroll_mode_ = kPrerollTillOutputIsPresent; 174 preroll_timestamp_ = preroll_timestamp;
174 } 175 }
175 176
176 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() { 177 base::android::ScopedJavaLocalRef<jobject> MediaCodecDecoder::GetMediaCrypto() {
177 base::android::ScopedJavaLocalRef<jobject> media_crypto; 178 base::android::ScopedJavaLocalRef<jobject> media_crypto;
178 179
179 // TODO(timav): implement DRM. 180 // TODO(timav): implement DRM.
180 // drm_bridge_ is not implemented 181 // drm_bridge_ is not implemented
181 // if (drm_bridge_) 182 // if (drm_bridge_)
182 // media_crypto = drm_bridge_->GetMediaCrypto(); 183 // media_crypto = drm_bridge_->GetMediaCrypto();
183 return media_crypto; 184 return media_crypto;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 DCHECK(!decoder_thread_.IsRunning()); 236 DCHECK(!decoder_thread_.IsRunning());
236 237
237 // For video the first frame after reconfiguration must be key frame. 238 // For video the first frame after reconfiguration must be key frame.
238 if (result == kConfigOk) 239 if (result == kConfigOk)
239 verify_next_frame_is_key_ = true; 240 verify_next_frame_is_key_ = true;
240 #endif 241 #endif
241 242
242 return result; 243 return result;
243 } 244 }
244 245
245 bool MediaCodecDecoder::Preroll(base::TimeDelta preroll_timestamp, 246 bool MediaCodecDecoder::Preroll(const base::Closure& preroll_done_cb) {
246 const base::Closure& preroll_done_cb) {
247 DCHECK(media_task_runner_->BelongsToCurrentThread()); 247 DCHECK(media_task_runner_->BelongsToCurrentThread());
248 248
249 DVLOG(1) << class_name() << "::" << __FUNCTION__ 249 DVLOG(1) << class_name() << "::" << __FUNCTION__
250 << " preroll_timestamp:" << preroll_timestamp; 250 << " preroll_timestamp:" << preroll_timestamp_;
251 251
252 DecoderState state = GetState(); 252 DecoderState state = GetState();
253 if (state != kPrefetched) { 253 if (state != kPrefetched) {
254 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state " 254 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state "
255 << AsString(state) << ", ignoring"; 255 << AsString(state) << ", ignoring";
256 return false; 256 return false;
257 } 257 }
258 258
259 if (!media_codec_bridge_) { 259 if (!media_codec_bridge_) {
260 DVLOG(0) << class_name() << "::" << __FUNCTION__ 260 DVLOG(0) << class_name() << "::" << __FUNCTION__
261 << ": not configured, ignoring"; 261 << ": not configured, ignoring";
262 return false; 262 return false;
263 } 263 }
264 264
265 DCHECK(!decoder_thread_.IsRunning()); 265 DCHECK(!decoder_thread_.IsRunning());
266 DCHECK(preroll_mode_ != kNoPreroll);
267 266
268 preroll_done_cb_ = preroll_done_cb; 267 preroll_done_cb_ = preroll_done_cb;
269 268
270 // We only synchronize video stream. 269 // We only synchronize video stream.
271 DissociatePTSFromTime(); // associaton will happen after preroll is done. 270 DissociatePTSFromTime(); // associaton will happen after preroll is done.
272 271
273 preroll_timestamp_ = (preroll_mode_ == kPrerollTillPTS) ? preroll_timestamp
274 : base::TimeDelta();
275
276 last_frame_posted_ = false; 272 last_frame_posted_ = false;
277 273
278 // Start the decoder thread 274 // Start the decoder thread
279 if (!decoder_thread_.Start()) { 275 if (!decoder_thread_.Start()) {
280 DVLOG(0) << class_name() << "::" << __FUNCTION__ 276 DVLOG(0) << class_name() << "::" << __FUNCTION__
281 << ": cannot start decoder thread"; 277 << ": cannot start decoder thread";
282 return false; 278 return false;
283 } 279 }
284 280
285 SetState(kPrerolling); 281 SetState(kPrerolling);
(...skipping 20 matching lines...) Expand all
306 } 302 }
307 303
308 if (!media_codec_bridge_) { 304 if (!media_codec_bridge_) {
309 DVLOG(0) << class_name() << "::" << __FUNCTION__ 305 DVLOG(0) << class_name() << "::" << __FUNCTION__
310 << ": not configured, ignoring"; 306 << ": not configured, ignoring";
311 return false; 307 return false;
312 } 308 }
313 309
314 // We only synchronize video stream. 310 // We only synchronize video stream.
315 AssociateCurrentTimeWithPTS(start_timestamp); 311 AssociateCurrentTimeWithPTS(start_timestamp);
316 preroll_timestamp_ = base::TimeDelta(); 312 // preroll_timestamp_ = base::TimeDelta();
qinmin 2015/09/03 05:30:04 remove this if unused
Tima Vaisburd 2015/09/03 19:55:26 Replaced with DCHECK(preroll_timestamp_ == base:
317 313
318 // Start the decoder thread 314 // Start the decoder thread
319 if (!decoder_thread_.IsRunning()) { 315 if (!decoder_thread_.IsRunning()) {
320 last_frame_posted_ = false; 316 last_frame_posted_ = false;
321 if (!decoder_thread_.Start()) { 317 if (!decoder_thread_.Start()) {
322 DVLOG(1) << class_name() << "::" << __FUNCTION__ 318 DVLOG(1) << class_name() << "::" << __FUNCTION__
323 << ": cannot start decoder thread"; 319 << ": cannot start decoder thread";
324 return false; 320 return false;
325 } 321 }
326 } 322 }
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 DCHECK(media_task_runner_->BelongsToCurrentThread()); 388 DCHECK(media_task_runner_->BelongsToCurrentThread());
393 389
394 DVLOG(1) << class_name() << "::" << __FUNCTION__ 390 DVLOG(1) << class_name() << "::" << __FUNCTION__
395 << " eos_encountered:" << eos_encountered; 391 << " eos_encountered:" << eos_encountered;
396 392
397 decoder_thread_.Stop(); // synchronous 393 decoder_thread_.Stop(); // synchronous
398 394
399 SetState(kStopped); 395 SetState(kStopped);
400 completed_ = (eos_encountered && !drain_decoder_); 396 completed_ = (eos_encountered && !drain_decoder_);
401 397
398 // If the stream is completed during preroll we need to report it since
399 // another stream might be running and the player waits for two callbacks.
402 if (completed_ && !preroll_done_cb_.is_null()) { 400 if (completed_ && !preroll_done_cb_.is_null()) {
401 preroll_timestamp_ = base::TimeDelta();
403 media_task_runner_->PostTask(FROM_HERE, 402 media_task_runner_->PostTask(FROM_HERE,
404 base::ResetAndReturn(&preroll_done_cb_)); 403 base::ResetAndReturn(&preroll_done_cb_));
405 } 404 }
406 405
407 if (eos_encountered && drain_decoder_) { 406 if (eos_encountered && drain_decoder_) {
408 ReleaseMediaCodec();
409 drain_decoder_ = false; 407 drain_decoder_ = false;
410 eos_enqueued_ = false; 408 eos_enqueued_ = false;
411 preroll_mode_ = kPrerollTillOutputIsPresent; 409 ReleaseMediaCodec();
412 media_task_runner_->PostTask(FROM_HERE, decoder_drained_cb_); 410 media_task_runner_->PostTask(FROM_HERE, decoder_drained_cb_);
413 } 411 }
414 412
415 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 413 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
416 } 414 }
417 415
418 void MediaCodecDecoder::OnPrerollDone() { 416 void MediaCodecDecoder::OnPrerollDone() {
419 DCHECK(media_task_runner_->BelongsToCurrentThread()); 417 DCHECK(media_task_runner_->BelongsToCurrentThread());
420 418
421 DVLOG(1) << class_name() << "::" << __FUNCTION__; 419 DVLOG(1) << class_name() << "::" << __FUNCTION__;
422 420
423 preroll_mode_ = kNoPreroll; 421 preroll_timestamp_ = base::TimeDelta();
424 422
425 // The state might be kStopping. 423 // The state might be kStopping (?)
426 if (GetState() == kPrerolling) { 424 if (GetState() == kPrerolling)
427 SetState(kPrerolled); 425 SetState(kPrerolled);
428 media_task_runner_->PostTask(FROM_HERE, 426
429 base::ResetAndReturn(&preroll_done_cb_)); 427 if (!preroll_done_cb_.is_null())
430 } 428 base::ResetAndReturn(&preroll_done_cb_).Run();
431 } 429 }
432 430
433 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { 431 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
434 DCHECK(media_task_runner_->BelongsToCurrentThread()); 432 DCHECK(media_task_runner_->BelongsToCurrentThread());
435 433
436 // If |data| contains an aborted data, the last AU will have kAborted status. 434 // If |data| contains an aborted data, the last AU will have kAborted status.
437 bool aborted_data = 435 bool aborted_data =
438 !data.access_units.empty() && 436 !data.access_units.empty() &&
439 data.access_units.back().status == DemuxerStream::kAborted; 437 data.access_units.back().status == DemuxerStream::kAborted;
440 438
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 DVLOG(1) << class_name() << "::" << __FUNCTION__ 569 DVLOG(1) << class_name() << "::" << __FUNCTION__
572 << ": kStopping, posting OnLastFrameRendered"; 570 << ": kStopping, posting OnLastFrameRendered";
573 media_task_runner_->PostTask( 571 media_task_runner_->PostTask(
574 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, 572 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered,
575 weak_factory_.GetWeakPtr(), false)); 573 weak_factory_.GetWeakPtr(), false));
576 last_frame_posted_ = true; 574 last_frame_posted_ = true;
577 } 575 }
578 576
579 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. 577 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze.
580 // We only need to let finish the delayed rendering tasks. 578 // We only need to let finish the delayed rendering tasks.
579 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " kStopping, returning";
581 return; 580 return;
582 } 581 }
583 582
584 DCHECK(state == kPrerolling || state == kRunning); 583 DCHECK(state == kPrerolling || state == kRunning);
585 584
586 if (!EnqueueInputBuffer()) 585 if (!EnqueueInputBuffer())
587 return; 586 return;
588 587
589 if (!DepleteOutputBufferQueue()) 588 if (!DepleteOutputBufferQueue())
590 return; 589 return;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
790 789
791 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 790 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
792 DVLOG(2) << class_name() << "::" << __FUNCTION__ 791 DVLOG(2) << class_name() << "::" << __FUNCTION__
793 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; 792 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED";
794 OnOutputFormatChanged(); 793 OnOutputFormatChanged();
795 break; 794 break;
796 795
797 case MEDIA_CODEC_OK: 796 case MEDIA_CODEC_OK:
798 // We got the decoded frame. 797 // We got the decoded frame.
799 798
799 is_prepared_ = true;
800
800 if (pts < preroll_timestamp_) 801 if (pts < preroll_timestamp_)
801 render_mode = kRenderSkip; 802 render_mode = kRenderSkip;
802 else if (GetState() == kPrerolling) 803 else if (GetState() == kPrerolling)
803 render_mode = kRenderAfterPreroll; 804 render_mode = kRenderAfterPreroll;
804 else 805 else
805 render_mode = kRenderNow; 806 render_mode = kRenderNow;
806 807
807 Render(buffer_index, offset, size, render_mode, pts, eos_encountered); 808 Render(buffer_index, offset, size, render_mode, pts, eos_encountered);
808 809
809 if (render_mode == kRenderAfterPreroll) { 810 if (render_mode == kRenderAfterPreroll) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
885 RETURN_STRING(kStopping); 886 RETURN_STRING(kStopping);
886 RETURN_STRING(kInEmergencyStop); 887 RETURN_STRING(kInEmergencyStop);
887 RETURN_STRING(kError); 888 RETURN_STRING(kError);
888 } 889 }
889 return nullptr; // crash early 890 return nullptr; // crash early
890 } 891 }
891 892
892 #undef RETURN_STRING 893 #undef RETURN_STRING
893 894
894 } // namespace media 895 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698