OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |