Chromium Code Reviews| 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 22 matching lines...) Expand all Loading... | |
| 33 | 33 |
| 34 MediaCodecDecoder::MediaCodecDecoder( | 34 MediaCodecDecoder::MediaCodecDecoder( |
| 35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, | 35 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner, |
| 36 const base::Closure& external_request_data_cb, | 36 const base::Closure& external_request_data_cb, |
| 37 const base::Closure& starvation_cb, | 37 const base::Closure& starvation_cb, |
| 38 const base::Closure& stop_done_cb, | 38 const base::Closure& stop_done_cb, |
| 39 const base::Closure& error_cb, | 39 const base::Closure& error_cb, |
| 40 const char* decoder_thread_name) | 40 const char* decoder_thread_name) |
| 41 : media_task_runner_(media_task_runner), | 41 : media_task_runner_(media_task_runner), |
| 42 decoder_thread_(decoder_thread_name), | 42 decoder_thread_(decoder_thread_name), |
| 43 needs_reconfigure_(false), | |
| 43 external_request_data_cb_(external_request_data_cb), | 44 external_request_data_cb_(external_request_data_cb), |
| 44 starvation_cb_(starvation_cb), | 45 starvation_cb_(starvation_cb), |
| 45 stop_done_cb_(stop_done_cb), | 46 stop_done_cb_(stop_done_cb), |
| 46 error_cb_(error_cb), | 47 error_cb_(error_cb), |
| 47 state_(kStopped), | 48 state_(kStopped), |
| 48 eos_enqueued_(false), | 49 eos_enqueued_(false), |
| 49 completed_(false), | 50 completed_(false), |
| 50 last_frame_posted_(false), | 51 last_frame_posted_(false), |
| 51 is_data_request_in_progress_(false), | 52 is_data_request_in_progress_(false), |
| 52 is_incoming_data_invalid_(false), | 53 is_incoming_data_invalid_(false), |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 75 | 76 |
| 76 const char* MediaCodecDecoder::class_name() const { | 77 const char* MediaCodecDecoder::class_name() const { |
| 77 return "Decoder"; | 78 return "Decoder"; |
| 78 } | 79 } |
| 79 | 80 |
| 80 void MediaCodecDecoder::ReleaseDecoderResources() { | 81 void MediaCodecDecoder::ReleaseDecoderResources() { |
| 81 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 82 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 82 | 83 |
| 83 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 84 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 84 | 85 |
| 86 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). | |
| 87 SetState(kInEmergencyStop); | |
| 88 | |
| 85 decoder_thread_.Stop(); // synchronous | 89 decoder_thread_.Stop(); // synchronous |
| 86 state_ = kStopped; | 90 |
| 91 SetState(kStopped); | |
| 87 media_codec_bridge_.reset(); | 92 media_codec_bridge_.reset(); |
| 88 } | 93 } |
| 89 | 94 |
| 90 void MediaCodecDecoder::Flush() { | 95 void MediaCodecDecoder::Flush() { |
| 91 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 96 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 92 | 97 |
| 93 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 98 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 94 | 99 |
| 95 DCHECK_EQ(GetState(), kStopped); | 100 DCHECK_EQ(GetState(), kStopped); |
| 96 | 101 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 179 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 184 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 180 | 185 |
| 181 if (GetState() == kError) { | 186 if (GetState() == kError) { |
| 182 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError"; | 187 DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError"; |
| 183 return CONFIG_FAILURE; | 188 return CONFIG_FAILURE; |
| 184 } | 189 } |
| 185 | 190 |
| 186 // Here I assume that OnDemuxerConfigsAvailable won't come | 191 // Here I assume that OnDemuxerConfigsAvailable won't come |
| 187 // in the middle of demuxer data. | 192 // in the middle of demuxer data. |
| 188 | 193 |
| 194 if (needs_reconfigure_) { | |
| 195 DVLOG(1) << class_name() << "::" << __FUNCTION__ | |
| 196 << ": needs reconfigure, deleting MediaCodec"; | |
| 197 needs_reconfigure_ = false; | |
| 198 media_codec_bridge_.reset(); | |
| 199 | |
| 200 // No need to release these buffers since the MediaCodec is deleted, just | |
| 201 // remove their indexes from |delayed_buffers_|. | |
| 202 | |
| 203 // Shall we move |delayed_buffers_| from VideoDecoder to Decoder class? | |
| 204 ClearDelayedBuffers(false); | |
| 205 } | |
| 206 | |
| 189 MediaCodecDecoder::ConfigStatus result; | 207 MediaCodecDecoder::ConfigStatus result; |
| 190 if (media_codec_bridge_) { | 208 if (media_codec_bridge_) { |
| 191 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 209 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 192 << ": reconfiguration is not required, ignoring"; | 210 << ": reconfiguration is not required, ignoring"; |
| 193 result = CONFIG_OK; | 211 result = CONFIG_OK; |
| 194 } else { | 212 } else { |
| 195 result = ConfigureInternal(); | 213 result = ConfigureInternal(); |
| 196 | 214 |
| 197 #ifndef NDEBUG | 215 #ifndef NDEBUG |
| 198 // We check and reset |verify_next_frame_is_key_| on Decoder thread. | 216 // We check and reset |verify_next_frame_is_key_| on Decoder thread. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 280 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 263 | 281 |
| 264 if (GetState() == kError) { | 282 if (GetState() == kError) { |
| 265 DVLOG(0) << class_name() << "::" << __FUNCTION__ | 283 DVLOG(0) << class_name() << "::" << __FUNCTION__ |
| 266 << ": wrong state kError, ignoring"; | 284 << ": wrong state kError, ignoring"; |
| 267 return; | 285 return; |
| 268 } | 286 } |
| 269 | 287 |
| 270 // After this method returns, decoder thread will not be running. | 288 // After this method returns, decoder thread will not be running. |
| 271 | 289 |
| 290 // Set [kInEmergencyStop| state to block already posted ProcessNextFrame(). | |
| 291 SetState(kInEmergencyStop); | |
| 292 | |
| 272 decoder_thread_.Stop(); // synchronous | 293 decoder_thread_.Stop(); // synchronous |
| 273 state_ = kStopped; | 294 |
| 295 SetState(kStopped); | |
| 274 | 296 |
| 275 // Shall we move |delayed_buffers_| from VideoDecoder to Decoder class? | 297 // Shall we move |delayed_buffers_| from VideoDecoder to Decoder class? |
| 276 ReleaseDelayedBuffers(); | 298 ClearDelayedBuffers(true); // release prior to clearing |delayed_buffers_|. |
| 277 } | 299 } |
| 278 | 300 |
| 279 void MediaCodecDecoder::RequestToStop() { | 301 void MediaCodecDecoder::RequestToStop() { |
| 280 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 302 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 281 | 303 |
| 282 DVLOG(1) << class_name() << "::" << __FUNCTION__; | 304 DVLOG(1) << class_name() << "::" << __FUNCTION__; |
| 283 | 305 |
| 284 DecoderState state = GetState(); | 306 DecoderState state = GetState(); |
| 285 switch (state) { | 307 switch (state) { |
| 286 case kError: | 308 case kError: |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 306 } | 328 } |
| 307 } | 329 } |
| 308 | 330 |
| 309 void MediaCodecDecoder::OnLastFrameRendered(bool completed) { | 331 void MediaCodecDecoder::OnLastFrameRendered(bool completed) { |
| 310 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 332 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 311 | 333 |
| 312 DVLOG(1) << class_name() << "::" << __FUNCTION__ | 334 DVLOG(1) << class_name() << "::" << __FUNCTION__ |
| 313 << " completed:" << completed; | 335 << " completed:" << completed; |
| 314 | 336 |
| 315 decoder_thread_.Stop(); // synchronous | 337 decoder_thread_.Stop(); // synchronous |
| 316 state_ = kStopped; | 338 |
| 339 SetState(kStopped); | |
| 317 completed_ = completed; | 340 completed_ = completed; |
| 318 | 341 |
| 319 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); | 342 media_task_runner_->PostTask(FROM_HERE, stop_done_cb_); |
| 320 } | 343 } |
| 321 | 344 |
| 322 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { | 345 void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) { |
| 323 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 346 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 324 | 347 |
| 325 // If |data| contains an aborted data, the last AU will have kAborted status. | 348 // If |data| contains an aborted data, the last AU will have kAborted status. |
| 326 bool aborted_data = | 349 bool aborted_data = |
| 327 !data.access_units.empty() && | 350 !data.access_units.empty() && |
| 328 data.access_units.back().status == DemuxerStream::kAborted; | 351 data.access_units.back().status == DemuxerStream::kAborted; |
| 329 | 352 |
| 330 #ifndef NDEBUG | 353 #ifndef NDEBUG |
| 331 const char* explain_if_skipped = | 354 const char* explain_if_skipped = |
| 332 is_incoming_data_invalid_ ? " skipped as invalid" | 355 is_incoming_data_invalid_ ? " skipped as invalid" |
| 333 : (aborted_data ? " skipped as aborted" : ""); | 356 : (aborted_data ? " skipped as aborted" : ""); |
| 334 | 357 |
| 335 for (const auto& unit : data.access_units) | 358 for (const auto& unit : data.access_units) |
| 336 DVLOG(1) << class_name() << "::" << __FUNCTION__ << explain_if_skipped | 359 DVLOG(2) << class_name() << "::" << __FUNCTION__ << explain_if_skipped |
| 337 << " au: " << unit; | 360 << " au: " << unit; |
| 338 for (const auto& configs : data.demuxer_configs) | 361 for (const auto& configs : data.demuxer_configs) |
| 339 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " configs: " << configs; | 362 DVLOG(2) << class_name() << "::" << __FUNCTION__ << " configs: " << configs; |
| 340 #endif | 363 #endif |
| 341 | 364 |
| 342 if (!is_incoming_data_invalid_ && !aborted_data) | 365 if (!is_incoming_data_invalid_ && !aborted_data) |
| 343 au_queue_.PushBack(data); | 366 au_queue_.PushBack(data); |
| 344 | 367 |
| 345 is_incoming_data_invalid_ = false; | 368 is_incoming_data_invalid_ = false; |
| 346 is_data_request_in_progress_ = false; | 369 is_data_request_in_progress_ = false; |
| 347 | 370 |
| 348 // Do not request data if we got kAborted. There is no point to request the | 371 // Do not request data if we got kAborted. There is no point to request the |
| 349 // data after kAborted and before the OnDemuxerSeekDone. | 372 // data after kAborted and before the OnDemuxerSeekDone. |
| 350 if (state_ == kPrefetching && !aborted_data) | 373 if (GetState() == kPrefetching && !aborted_data) |
| 351 PrefetchNextChunk(); | 374 PrefetchNextChunk(); |
| 352 } | 375 } |
| 353 | 376 |
| 354 int MediaCodecDecoder::NumDelayedRenderTasks() const { | 377 int MediaCodecDecoder::NumDelayedRenderTasks() const { |
| 355 return 0; | 378 return 0; |
| 356 } | 379 } |
| 357 | 380 |
| 358 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, | 381 void MediaCodecDecoder::CheckLastFrame(bool eos_encountered, |
| 359 bool has_delayed_tasks) { | 382 bool has_delayed_tasks) { |
| 360 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); | 383 DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread()); |
| 361 | 384 |
| 362 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; | 385 bool last_frame_when_stopping = GetState() == kStopping && !has_delayed_tasks; |
| 363 | 386 |
| 364 if (last_frame_when_stopping || eos_encountered) { | 387 if (last_frame_when_stopping || eos_encountered) { |
| 365 media_task_runner_->PostTask( | 388 media_task_runner_->PostTask( |
| 366 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, | 389 FROM_HERE, base::Bind(&MediaCodecDecoder::OnLastFrameRendered, |
| 367 weak_factory_.GetWeakPtr(), eos_encountered)); | 390 weak_factory_.GetWeakPtr(), eos_encountered)); |
| 368 last_frame_posted_ = true; | 391 last_frame_posted_ = true; |
| 369 } | 392 } |
| 370 } | 393 } |
| 371 | 394 |
| 372 void MediaCodecDecoder::OnCodecError() { | 395 void MediaCodecDecoder::OnCodecError() { |
| 373 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 396 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 374 | 397 |
| 398 // Ignore codec errors from the moment surface is changed till the | |
|
Tima Vaisburd
2015/07/23 00:37:49
Also added this check.
| |
| 399 // |media_codec_bridge_| is deleted. | |
| 400 if (needs_reconfigure_) { | |
| 401 DVLOG(1) << class_name() << "::" << __FUNCTION__ | |
| 402 << ": needs reconfigure, ignoring"; | |
| 403 return; | |
| 404 } | |
| 405 | |
| 375 SetState(kError); | 406 SetState(kError); |
| 376 error_cb_.Run(); | 407 error_cb_.Run(); |
| 377 } | 408 } |
| 378 | 409 |
| 379 void MediaCodecDecoder::RequestData() { | 410 void MediaCodecDecoder::RequestData() { |
| 380 DCHECK(media_task_runner_->BelongsToCurrentThread()); | 411 DCHECK(media_task_runner_->BelongsToCurrentThread()); |
| 381 | 412 |
| 382 // Ensure one data request at a time. | 413 // Ensure one data request at a time. |
| 383 if (!is_data_request_in_progress_) { | 414 if (!is_data_request_in_progress_) { |
| 384 is_data_request_in_progress_ = true; | 415 is_data_request_in_progress_ = true; |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 630 | 661 |
| 631 return status != MEDIA_CODEC_ERROR; | 662 return status != MEDIA_CODEC_ERROR; |
| 632 } | 663 } |
| 633 | 664 |
| 634 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const { | 665 MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const { |
| 635 base::AutoLock lock(state_lock_); | 666 base::AutoLock lock(state_lock_); |
| 636 return state_; | 667 return state_; |
| 637 } | 668 } |
| 638 | 669 |
| 639 void MediaCodecDecoder::SetState(DecoderState state) { | 670 void MediaCodecDecoder::SetState(DecoderState state) { |
| 640 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << state; | 671 DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << AsString(state); |
| 641 | 672 |
| 642 base::AutoLock lock(state_lock_); | 673 base::AutoLock lock(state_lock_); |
| 643 state_ = state; | 674 state_ = state; |
| 644 } | 675 } |
| 645 | 676 |
| 646 #undef RETURN_STRING | 677 #undef RETURN_STRING |
| 647 #define RETURN_STRING(x) \ | 678 #define RETURN_STRING(x) \ |
| 648 case x: \ | 679 case x: \ |
| 649 return #x; | 680 return #x; |
| 650 | 681 |
| 651 const char* MediaCodecDecoder::AsString(DecoderState state) { | 682 const char* MediaCodecDecoder::AsString(DecoderState state) { |
| 652 switch (state) { | 683 switch (state) { |
| 653 RETURN_STRING(kStopped); | 684 RETURN_STRING(kStopped); |
| 654 RETURN_STRING(kPrefetching); | 685 RETURN_STRING(kPrefetching); |
| 655 RETURN_STRING(kPrefetched); | 686 RETURN_STRING(kPrefetched); |
| 656 RETURN_STRING(kRunning); | 687 RETURN_STRING(kRunning); |
| 657 RETURN_STRING(kStopping); | 688 RETURN_STRING(kStopping); |
| 689 RETURN_STRING(kInEmergencyStop); | |
| 658 RETURN_STRING(kError); | 690 RETURN_STRING(kError); |
| 659 default: | 691 default: |
| 660 return "Unknown DecoderState"; | 692 return "Unknown DecoderState"; |
| 661 } | 693 } |
| 662 } | 694 } |
| 663 | 695 |
| 664 #undef RETURN_STRING | 696 #undef RETURN_STRING |
| 665 | 697 |
| 666 } // namespace media | 698 } // namespace media |
| OLD | NEW |