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

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: Rebased 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
« no previous file with comments | « media/base/android/media_codec_decoder.h ('k') | media/base/android/media_codec_player.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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:
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 // http://crbug.com/526755 396 // http://crbug.com/526755
395 DVLOG(0) << class_name() << "::" << __FUNCTION__ 397 DVLOG(0) << class_name() << "::" << __FUNCTION__
396 << " eos_encountered:" << eos_encountered; 398 << " eos_encountered:" << eos_encountered;
397 399
398 decoder_thread_.Stop(); // synchronous 400 decoder_thread_.Stop(); // synchronous
399 401
400 SetState(kStopped); 402 SetState(kStopped);
401 completed_ = (eos_encountered && !drain_decoder_); 403 completed_ = (eos_encountered && !drain_decoder_);
402 404
405 // If the stream is completed during preroll we need to report it since
406 // another stream might be running and the player waits for two callbacks.
403 if (completed_ && !preroll_done_cb_.is_null()) { 407 if (completed_ && !preroll_done_cb_.is_null()) {
404 // http://crbug.com/526755 408 // http://crbug.com/526755
405 DVLOG(0) << class_name() << "::" << __FUNCTION__ 409 DVLOG(0) << class_name() << "::" << __FUNCTION__
406 << ": completed, calling preroll_done_cb_"; 410 << ": completed, calling preroll_done_cb_";
411
412 preroll_timestamp_ = base::TimeDelta();
407 media_task_runner_->PostTask(FROM_HERE, 413 media_task_runner_->PostTask(FROM_HERE,
408 base::ResetAndReturn(&preroll_done_cb_)); 414 base::ResetAndReturn(&preroll_done_cb_));
409 } 415 }
410 416
411 if (eos_encountered && drain_decoder_) { 417 if (eos_encountered && drain_decoder_) {
412 ReleaseMediaCodec();
413 drain_decoder_ = false; 418 drain_decoder_ = false;
414 eos_enqueued_ = false; 419 eos_enqueued_ = false;
415 preroll_mode_ = kPrerollTillOutputIsPresent; 420 ReleaseMediaCodec();
416 media_task_runner_->PostTask(FROM_HERE, decoder_drained_cb_); 421 media_task_runner_->PostTask(FROM_HERE, decoder_drained_cb_);
417 } 422 }
418 423
419 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); 424 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
420 } 425 }
421 426
422 void MediaCodecDecoder::OnPrerollDone() { 427 void MediaCodecDecoder::OnPrerollDone() {
423 DCHECK(media_task_runner_->BelongsToCurrentThread()); 428 DCHECK(media_task_runner_->BelongsToCurrentThread());
424 429
425 // http://crbug.com/526755 430 // http://crbug.com/526755
426 DVLOG(0) << class_name() << "::" << __FUNCTION__ 431 DVLOG(0) << class_name() << "::" << __FUNCTION__
427 << " state:" << AsString(GetState()); 432 << " state:" << AsString(GetState());
428 433
429 preroll_mode_ = kNoPreroll; 434 preroll_timestamp_ = base::TimeDelta();
430 435
431 // The state might be kStopping. 436 // The state might be kStopping (?)
432 if (GetState() == kPrerolling) { 437 if (GetState() == kPrerolling)
433 SetState(kPrerolled); 438 SetState(kPrerolled);
434 media_task_runner_->PostTask(FROM_HERE, 439
435 base::ResetAndReturn(&preroll_done_cb_)); 440 if (!preroll_done_cb_.is_null())
436 } 441 base::ResetAndReturn(&preroll_done_cb_).Run();
437 } 442 }
438 443
439 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { 444 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
440 DCHECK(media_task_runner_->BelongsToCurrentThread()); 445 DCHECK(media_task_runner_->BelongsToCurrentThread());
441 446
442 // If |data| contains an aborted data, the last AU will have kAborted status. 447 // If |data| contains an aborted data, the last AU will have kAborted status.
443 bool aborted_data = 448 bool aborted_data =
444 !data.access_units.empty() && 449 !data.access_units.empty() &&
445 data.access_units.back().status == DemuxerStream::kAborted; 450 data.access_units.back().status == DemuxerStream::kAborted;
446 451
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 DVLOG(0) << class_name() << "::" << __FUNCTION__ 596 DVLOG(0) << class_name() << "::" << __FUNCTION__
592 << ": kStopping, no delayed tasks, posting OnLastFrameRendered"; 597 << ": kStopping, no delayed tasks, posting OnLastFrameRendered";
593 media_task_runner_->PostTask( 598 media_task_runner_->PostTask(
594 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, 599 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered,
595 weak_factory_.GetWeakPtr(), false)); 600 weak_factory_.GetWeakPtr(), false));
596 last_frame_posted_ = true; 601 last_frame_posted_ = true;
597 } 602 }
598 603
599 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze. 604 // We can stop processing, the |au_queue_| and MediaCodec queues can freeze.
600 // We only need to let finish the delayed rendering tasks. 605 // We only need to let finish the delayed rendering tasks.
606 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " kStopping, returning";
601 return; 607 return;
602 } 608 }
603 609
604 DCHECK(state == kPrerolling || state == kRunning); 610 DCHECK(state == kPrerolling || state == kRunning);
605 611
606 if (!EnqueueInputBuffer()) 612 if (!EnqueueInputBuffer())
607 return; 613 return;
608 614
609 if (!DepleteOutputBufferQueue()) 615 if (!DepleteOutputBufferQueue())
610 return; 616 return;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
810 816
811 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED: 817 case MEDIA_CODEC_OUTPUT_FORMAT_CHANGED:
812 DVLOG(2) << class_name() << "::" << __FUNCTION__ 818 DVLOG(2) << class_name() << "::" << __FUNCTION__
813 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED"; 819 << " MEDIA_CODEC_OUTPUT_FORMAT_CHANGED";
814 OnOutputFormatChanged(); 820 OnOutputFormatChanged();
815 break; 821 break;
816 822
817 case MEDIA_CODEC_OK: 823 case MEDIA_CODEC_OK:
818 // We got the decoded frame. 824 // We got the decoded frame.
819 825
826 is_prepared_ = true;
827
820 if (pts < preroll_timestamp_) 828 if (pts < preroll_timestamp_)
821 render_mode = kRenderSkip; 829 render_mode = kRenderSkip;
822 else if (GetState() == kPrerolling) 830 else if (GetState() == kPrerolling)
823 render_mode = kRenderAfterPreroll; 831 render_mode = kRenderAfterPreroll;
824 else 832 else
825 render_mode = kRenderNow; 833 render_mode = kRenderNow;
826 834
827 Render(buffer_index, offset, size, render_mode, pts, eos_encountered); 835 Render(buffer_index, offset, size, render_mode, pts, eos_encountered);
828 836
829 if (render_mode == kRenderAfterPreroll) { 837 if (render_mode == kRenderAfterPreroll) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 RETURN_STRING(kStopping); 913 RETURN_STRING(kStopping);
906 RETURN_STRING(kInEmergencyStop); 914 RETURN_STRING(kInEmergencyStop);
907 RETURN_STRING(kError); 915 RETURN_STRING(kError);
908 } 916 }
909 return nullptr; // crash early 917 return nullptr; // crash early
910 } 918 }
911 919
912 #undef RETURN_STRING 920 #undef RETURN_STRING
913 921
914 } // namespace media 922 } // namespace media
OLDNEW
« no previous file with comments | « media/base/android/media_codec_decoder.h ('k') | media/base/android/media_codec_player.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698