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 |