Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/filters/decoder_stream.h" | 5 #include "media/filters/decoder_stream.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| 11 #include "base/location.h" | 11 #include "base/location.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
| 14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
| 15 #include "media/base/bind_to_current_loop.h" | 15 #include "media/base/bind_to_current_loop.h" |
| 16 #include "media/base/cdm_context.h" | 16 #include "media/base/cdm_context.h" |
| 17 #include "media/base/decoder_buffer.h" | 17 #include "media/base/decoder_buffer.h" |
| 18 #include "media/base/limits.h" | 18 #include "media/base/limits.h" |
| 19 #include "media/base/media_log.h" | 19 #include "media/base/media_log.h" |
| 20 #include "media/base/timestamp_constants.h" | 20 #include "media/base/timestamp_constants.h" |
| 21 #include "media/base/video_decoder.h" | 21 #include "media/base/video_decoder.h" |
| 22 #include "media/base/video_frame.h" | 22 #include "media/base/video_frame.h" |
| 23 #include "media/filters/decrypting_demuxer_stream.h" | 23 #include "media/filters/decrypting_demuxer_stream.h" |
| 24 | 24 |
| 25 namespace media { | 25 namespace media { |
| 26 | 26 |
| 27 // Defines how many milliseconds of DecoderBuffer timestamp gap will be allowed | |
| 28 // before warning the user. See CheckForTimestampGap(). Value of 50 chosen, as | |
| 29 // this is low enough to catch issues early, but high enough to avoid noise for | |
| 30 // containers like WebM that default to low granularity timestamp precision. | |
| 31 const int kGapWarningThresholdMsec = 50; | |
| 32 | |
| 33 // Limits the number of adjustments to |audio_ts_offset_| in order to reach a | |
| 34 // stable state where gaps between encoded timestamps match decoded output | |
| 35 // intervals. See CheckForTimestampGap(). | |
| 36 const int kLimitTriesForStableTiming = 5; | |
| 37 | |
| 38 // Limits the milliseconds of difference between expected and actual timestamps | |
| 39 // gaps to consider timestamp expectations "stable". 1 chosen because some | |
| 40 // containers (WebM) default to millisecond timestamp precision. See | |
| 41 // CheckForTimestampGap(). | |
| 42 const int kStableTimeGapThrsholdMsec = 1; | |
| 43 | |
| 27 // TODO(rileya): Devise a better way of specifying trace/UMA/etc strings for | 44 // TODO(rileya): Devise a better way of specifying trace/UMA/etc strings for |
| 28 // templated classes such as this. | 45 // templated classes such as this. |
| 29 template <DemuxerStream::Type StreamType> | 46 template <DemuxerStream::Type StreamType> |
| 30 static const char* GetTraceString(); | 47 static const char* GetTraceString(); |
| 31 | 48 |
| 32 #define FUNCTION_DVLOG(level) \ | 49 #define FUNCTION_DVLOG(level) \ |
| 33 DVLOG(level) << __FUNCTION__ << "<" << GetStreamTypeString() << ">" | 50 DVLOG(level) << __FUNCTION__ << "<" << GetStreamTypeString() << ">" |
| 34 | 51 |
| 35 template <> | 52 template <> |
| 36 const char* GetTraceString<DemuxerStream::VIDEO>() { | 53 const char* GetTraceString<DemuxerStream::VIDEO>() { |
| 37 return "DecoderStream<VIDEO>::Decode"; | 54 return "DecoderStream<VIDEO>::Decode"; |
| 38 } | 55 } |
| 39 | 56 |
| 40 template <> | 57 template <> |
| 41 const char* GetTraceString<DemuxerStream::AUDIO>() { | 58 const char* GetTraceString<DemuxerStream::AUDIO>() { |
| 42 return "DecoderStream<AUDIO>::Decode"; | 59 return "DecoderStream<AUDIO>::Decode"; |
| 43 } | 60 } |
| 44 | 61 |
| 45 template <DemuxerStream::Type StreamType> | 62 template <DemuxerStream::Type StreamType> |
| 46 DecoderStream<StreamType>::DecoderStream( | 63 DecoderStream<StreamType>::DecoderStream( |
| 47 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 64 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 48 ScopedVector<Decoder> decoders, | 65 ScopedVector<Decoder> decoders, |
| 49 const scoped_refptr<MediaLog>& media_log) | 66 const scoped_refptr<MediaLog>& media_log) |
| 50 : task_runner_(task_runner), | 67 : task_runner_(task_runner), |
| 51 media_log_(media_log), | 68 media_log_(media_log), |
| 52 state_(STATE_UNINITIALIZED), | 69 state_(STATE_UNINITIALIZED), |
| 53 stream_(NULL), | 70 stream_(NULL), |
| 71 audio_base_ts_(kNoTimestamp()), | |
| 72 stable_audio_times_(false), | |
| 73 num_unstable_audio_tries_(0), | |
| 74 drift_warning_threshold_msec_(kGapWarningThresholdMsec), | |
| 54 decoder_selector_(new DecoderSelector<StreamType>(task_runner, | 75 decoder_selector_(new DecoderSelector<StreamType>(task_runner, |
| 55 std::move(decoders), | 76 std::move(decoders), |
| 56 media_log)), | 77 media_log)), |
| 57 decoded_frames_since_fallback_(0), | 78 decoded_frames_since_fallback_(0), |
| 58 active_splice_(false), | 79 active_splice_(false), |
| 59 decoding_eos_(false), | 80 decoding_eos_(false), |
| 60 pending_decode_requests_(0), | 81 pending_decode_requests_(0), |
| 61 duration_tracker_(8), | 82 duration_tracker_(8), |
| 62 received_config_change_during_reinit_(false), | 83 received_config_change_during_reinit_(false), |
| 63 pending_demuxer_read_(false), | 84 pending_demuxer_read_(false), |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 158 | 179 |
| 159 reset_cb_ = closure; | 180 reset_cb_ = closure; |
| 160 | 181 |
| 161 if (!read_cb_.is_null()) { | 182 if (!read_cb_.is_null()) { |
| 162 task_runner_->PostTask(FROM_HERE, | 183 task_runner_->PostTask(FROM_HERE, |
| 163 base::Bind(base::ResetAndReturn(&read_cb_), ABORTED, | 184 base::Bind(base::ResetAndReturn(&read_cb_), ABORTED, |
| 164 scoped_refptr<Output>())); | 185 scoped_refptr<Output>())); |
| 165 } | 186 } |
| 166 | 187 |
| 167 ready_outputs_.clear(); | 188 ready_outputs_.clear(); |
| 189 audio_base_ts_ = kNoTimestamp(); | |
| 190 audio_ts_offset_ = base::TimeDelta(); | |
| 191 audio_output_ts_helper_.reset(); | |
| 192 num_unstable_audio_tries_ = 0; | |
| 193 stable_audio_times_ = false; | |
| 194 drift_warning_threshold_msec_ = kGapWarningThresholdMsec; | |
| 168 | 195 |
| 169 // It's possible to have received a DECODE_ERROR and entered STATE_ERROR right | 196 // It's possible to have received a DECODE_ERROR and entered STATE_ERROR right |
| 170 // before a Reset() is executed. If we are still waiting for a demuxer read, | 197 // before a Reset() is executed. If we are still waiting for a demuxer read, |
| 171 // OnBufferReady() will handle the reset callback. | 198 // OnBufferReady() will handle the reset callback. |
| 172 // See crbug.com/597605 and crbug.com/607454. | 199 // See crbug.com/597605 and crbug.com/607454. |
| 173 if (state_ == STATE_ERROR && !pending_demuxer_read_) { | 200 if (state_ == STATE_ERROR && !pending_demuxer_read_) { |
| 174 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&reset_cb_)); | 201 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&reset_cb_)); |
| 175 return; | 202 return; |
| 176 } | 203 } |
| 177 | 204 |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 341 | 368 |
| 342 template <DemuxerStream::Type StreamType> | 369 template <DemuxerStream::Type StreamType> |
| 343 void DecoderStream<StreamType>::DecodeInternal( | 370 void DecoderStream<StreamType>::DecodeInternal( |
| 344 const scoped_refptr<DecoderBuffer>& buffer) { | 371 const scoped_refptr<DecoderBuffer>& buffer) { |
| 345 FUNCTION_DVLOG(2); | 372 FUNCTION_DVLOG(2); |
| 346 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER) << state_; | 373 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER) << state_; |
| 347 DCHECK_LT(pending_decode_requests_, GetMaxDecodeRequests()); | 374 DCHECK_LT(pending_decode_requests_, GetMaxDecodeRequests()); |
| 348 DCHECK(reset_cb_.is_null()); | 375 DCHECK(reset_cb_.is_null()); |
| 349 DCHECK(buffer.get()); | 376 DCHECK(buffer.get()); |
| 350 | 377 |
| 378 CheckForTimestampGap(buffer); | |
| 379 | |
| 351 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size(); | 380 int buffer_size = buffer->end_of_stream() ? 0 : buffer->data_size(); |
| 352 | 381 |
| 353 TRACE_EVENT_ASYNC_BEGIN2( | 382 TRACE_EVENT_ASYNC_BEGIN2( |
| 354 "media", GetTraceString<StreamType>(), this, "key frame", | 383 "media", GetTraceString<StreamType>(), this, "key frame", |
| 355 !buffer->end_of_stream() && buffer->is_key_frame(), "timestamp (ms)", | 384 !buffer->end_of_stream() && buffer->is_key_frame(), "timestamp (ms)", |
| 356 !buffer->end_of_stream() ? buffer->timestamp().InMilliseconds() : 0); | 385 !buffer->end_of_stream() ? buffer->timestamp().InMilliseconds() : 0); |
| 357 | 386 |
| 358 if (buffer->end_of_stream()) | 387 if (buffer->end_of_stream()) |
| 359 decoding_eos_ = true; | 388 decoding_eos_ = true; |
| 360 else if (buffer->duration() != kNoTimestamp()) | 389 else if (buffer->duration() != kNoTimestamp()) |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 469 if (state_ == STATE_ERROR) { | 498 if (state_ == STATE_ERROR) { |
| 470 DCHECK(read_cb_.is_null()); | 499 DCHECK(read_cb_.is_null()); |
| 471 return; | 500 return; |
| 472 } | 501 } |
| 473 | 502 |
| 474 // Drop decoding result if Reset() was called during decoding. | 503 // Drop decoding result if Reset() was called during decoding. |
| 475 // The resetting process will be handled when the decoder is reset. | 504 // The resetting process will be handled when the decoder is reset. |
| 476 if (!reset_cb_.is_null()) | 505 if (!reset_cb_.is_null()) |
| 477 return; | 506 return; |
| 478 | 507 |
| 508 RecordOutputDuration(output); | |
| 509 | |
| 479 ++decoded_frames_since_fallback_; | 510 ++decoded_frames_since_fallback_; |
| 480 | 511 |
| 481 // |decoder_| sucessfully decoded a frame. No need to keep buffers for a | 512 // |decoder_| sucessfully decoded a frame. No need to keep buffers for a |
| 482 // fallback decoder. | 513 // fallback decoder. |
| 483 // Note: |fallback_buffers_| might still have buffers, and we will keep | 514 // Note: |fallback_buffers_| might still have buffers, and we will keep |
| 484 // reading from there before requesting new buffers from |stream_|. | 515 // reading from there before requesting new buffers from |stream_|. |
| 485 pending_buffers_.clear(); | 516 pending_buffers_.clear(); |
| 486 | 517 |
| 487 if (!read_cb_.is_null()) { | 518 if (!read_cb_.is_null()) { |
| 488 // If |ready_outputs_| was non-empty, the read would have already been | 519 // If |ready_outputs_| was non-empty, the read would have already been |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 765 state_ = STATE_NORMAL; | 796 state_ = STATE_NORMAL; |
| 766 active_splice_ = false; | 797 active_splice_ = false; |
| 767 base::ResetAndReturn(&reset_cb_).Run(); | 798 base::ResetAndReturn(&reset_cb_).Run(); |
| 768 return; | 799 return; |
| 769 } | 800 } |
| 770 | 801 |
| 771 // The resetting process will be continued in OnDecoderReinitialized(). | 802 // The resetting process will be continued in OnDecoderReinitialized(). |
| 772 ReinitializeDecoder(); | 803 ReinitializeDecoder(); |
| 773 } | 804 } |
| 774 | 805 |
| 806 template <> | |
| 807 void DecoderStream<DemuxerStream::VIDEO>::CheckForTimestampGap( | |
| 808 const scoped_refptr<DecoderBuffer>& buffer) {} | |
| 809 | |
| 810 template <> | |
| 811 void DecoderStream<DemuxerStream::VIDEO>::RecordOutputDuration( | |
| 812 const scoped_refptr<Output>& output) {} | |
| 813 | |
| 814 template <> | |
| 815 void DecoderStream<DemuxerStream::AUDIO>::CheckForTimestampGap( | |
| 816 const scoped_refptr<DecoderBuffer>& buffer) { | |
| 817 if (buffer->end_of_stream()) | |
| 818 return; | |
| 819 DCHECK_NE(kNoTimestamp(), buffer->timestamp()); | |
| 820 | |
| 821 // Don't continue checking timestamps if we've exhausted tries to reach stable | |
| 822 // state. This suggests the media's encoded timestamps are way off. | |
| 823 if (num_unstable_audio_tries_ > kLimitTriesForStableTiming) | |
| 824 return; | |
| 825 | |
| 826 // Keep resetting encode base ts until we start getting decode output. Some | |
| 827 // codecs/containers (e.g. chained Ogg) will take several encoded buffers | |
| 828 // before producing the first decoded output. | |
| 829 if (!audio_output_ts_helper_) { | |
| 830 audio_base_ts_ = buffer->timestamp(); | |
| 831 DVLOG(3) << __FUNCTION__ | |
| 832 << " setting audio_base:" << audio_base_ts_.InMicroseconds(); | |
| 833 // Wait for decoded output to form expectations to verify timestamps. | |
| 834 return; | |
| 835 } | |
| 836 | |
| 837 base::TimeDelta expected_ts = | |
| 838 audio_output_ts_helper_->GetTimestamp() + audio_ts_offset_; | |
| 839 base::TimeDelta ts_delta = buffer->timestamp() - expected_ts; | |
| 840 | |
| 841 // Reconciling encoded buffer timestamps with decoded output often requires | |
|
DaleCurtis
2016/05/17 21:32:54
Notably this also hides errors at the beginning of
chcunningham
2016/05/18 00:18:00
Will try to do what we discussed, where we expect
| |
| 842 // adjusting expectations by some offset. This accounts for varied (and at | |
| 843 // this point unknown) handling of front trimming and codec delay. Codec delay | |
| 844 // and skip trimming may or may not be accounted for in the encoded timestamps | |
| 845 // depending on the codec (e.g. MP3 vs Opus) and demuxers used (e.g. FFmpeg | |
| 846 // vs MSE stream parsers). | |
| 847 if (!stable_audio_times_) { | |
| 848 if (std::abs(ts_delta.InMilliseconds()) < kStableTimeGapThrsholdMsec) { | |
| 849 stable_audio_times_ = true; | |
| 850 DVLOG(3) << __FUNCTION__ | |
| 851 << " stabilized! tries:" << num_unstable_audio_tries_ | |
| 852 << " offset:" << audio_ts_offset_.InMicroseconds(); | |
| 853 } else { | |
| 854 base::TimeDelta orig_offset = audio_ts_offset_; | |
| 855 audio_ts_offset_ += ts_delta; | |
|
DaleCurtis
2016/05/17 21:32:54
Seems like you should just set the base timestamp
chcunningham
2016/05/18 00:18:00
Done.
| |
| 856 DVLOG(3) << __FUNCTION__ | |
| 857 << " NOT stabilized. tries:" << num_unstable_audio_tries_ | |
| 858 << " offset was:" << orig_offset.InMicroseconds() | |
| 859 << " now:" << audio_ts_offset_.InMicroseconds(); | |
| 860 num_unstable_audio_tries_++; | |
| 861 | |
| 862 // Let developers know if their files timestamps are way off from | |
| 863 if (num_unstable_audio_tries_ > kLimitTriesForStableTiming) | |
|
DaleCurtis
2016/05/17 21:32:54
Needs {}
chcunningham
2016/05/18 00:18:00
Done.
| |
| 864 MEDIA_LOG(ERROR, media_log_) | |
| 865 << "Failed to reconcile encoded audio times with decoded output."; | |
| 866 } | |
| 867 | |
| 868 // Don't bother with further checking until we reach stable state. | |
| 869 return; | |
| 870 } | |
| 871 | |
| 872 if (std::abs(ts_delta.InMilliseconds()) > drift_warning_threshold_msec_) { | |
| 873 MEDIA_LOG(ERROR, media_log_) | |
| 874 << " Large timestamp gap detected; may cause AV sync to drift." | |
| 875 << " time:" << buffer->timestamp() | |
| 876 << " expected:" << expected_ts.InMicroseconds() | |
| 877 << " delta:" << ts_delta.InMicroseconds(); | |
| 878 // Increase threshold to avoid log spam but, let us know if gap widens. | |
| 879 drift_warning_threshold_msec_ = std::abs(ts_delta.InMilliseconds()); | |
| 880 } | |
| 881 DVLOG(3) << __FUNCTION__ << " delta:" << ts_delta.InMicroseconds() | |
| 882 << " expected_ts:" << expected_ts.InMicroseconds() | |
| 883 << " actual_ts:" << buffer->timestamp().InMicroseconds() | |
| 884 << " audio_ts_offset:" << audio_ts_offset_.InMicroseconds() | |
| 885 << " base_ts:" << audio_base_ts_.InMicroseconds(); | |
| 886 } | |
| 887 | |
| 888 template <> | |
| 889 void DecoderStream<DemuxerStream::AUDIO>::RecordOutputDuration( | |
| 890 const scoped_refptr<Output>& output) { | |
| 891 if (output.get()) { | |
| 892 AudioBuffer* audio_buffer = static_cast<AudioBuffer*>(output.get()); | |
| 893 | |
| 894 if (!audio_output_ts_helper_) { | |
| 895 DCHECK_NE(audio_base_ts_, kNoTimestamp()); | |
| 896 audio_output_ts_helper_.reset( | |
| 897 new AudioTimestampHelper(audio_buffer->sample_rate())); | |
| 898 audio_output_ts_helper_->SetBaseTimestamp(audio_base_ts_); | |
| 899 } | |
| 900 | |
| 901 DVLOG(3) << __FUNCTION__ << " " << audio_buffer->frame_count() << " frames"; | |
| 902 audio_output_ts_helper_->AddFrames(audio_buffer->frame_count()); | |
| 903 } | |
| 904 } | |
| 905 | |
| 775 template class DecoderStream<DemuxerStream::VIDEO>; | 906 template class DecoderStream<DemuxerStream::VIDEO>; |
| 776 template class DecoderStream<DemuxerStream::AUDIO>; | 907 template class DecoderStream<DemuxerStream::AUDIO>; |
| 777 | 908 |
| 778 } // namespace media | 909 } // namespace media |
| OLD | NEW |