audio_timestamp_validator.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/filters/audio_timestamp_validator.h"
  5. #include <memory>
  6. namespace media {
  7. // Defines how many milliseconds of DecoderBuffer timestamp gap will be allowed
  8. // before warning the user. See CheckForTimestampGap(). Value of 50 chosen, as
  9. // this is low enough to catch issues early, but high enough to avoid noise for
  10. // containers like WebM that default to low granularity timestamp precision.
  11. const int kGapWarningThresholdMsec = 50;
  12. // Limits the number of adjustments to |audio_ts_offset_| in order to reach a
  13. // stable state where gaps between encoded timestamps match decoded output
  14. // intervals. See CheckForTimestampGap().
  15. const int kLimitTriesForStableTiming = 5;
  16. // Limits the milliseconds of difference between expected and actual timestamps
  17. // gaps to consider timestamp expectations "stable". 1 chosen because some
  18. // containers (WebM) default to millisecond timestamp precision. See
  19. // CheckForTimestampGap().
  20. const int kStableTimeGapThrsholdMsec = 1;
  21. // Maximum number of timestamp gap warnings sent to MediaLog.
  22. const int kMaxTimestampGapWarnings = 10;
  23. AudioTimestampValidator::AudioTimestampValidator(
  24. const AudioDecoderConfig& decoder_config,
  25. MediaLog* media_log)
  26. : has_codec_delay_(decoder_config.codec_delay() > 0),
  27. media_log_(media_log),
  28. audio_base_ts_(kNoTimestamp),
  29. reached_stable_state_(false),
  30. num_unstable_audio_tries_(0),
  31. limit_unstable_audio_tries_(kLimitTriesForStableTiming),
  32. drift_warning_threshold_msec_(kGapWarningThresholdMsec) {
  33. DCHECK(decoder_config.IsValidConfig());
  34. }
  35. AudioTimestampValidator::~AudioTimestampValidator() = default;
  36. void AudioTimestampValidator::CheckForTimestampGap(
  37. const DecoderBuffer& buffer) {
  38. if (buffer.end_of_stream())
  39. return;
  40. DCHECK_NE(kNoTimestamp, buffer.timestamp());
  41. // If audio_base_ts_ == kNoTimestamp, we are processing our first buffer.
  42. // If stream has neither codec delay nor discard padding, we should expect
  43. // timestamps and output durations to line up from the start (i.e. be stable).
  44. if (audio_base_ts_ == kNoTimestamp && !has_codec_delay_ &&
  45. buffer.discard_padding().first == base::TimeDelta() &&
  46. buffer.discard_padding().second == base::TimeDelta()) {
  47. DVLOG(3) << __func__ << " Expecting stable timestamps - stream has neither "
  48. << "codec delay nor discard padding.";
  49. limit_unstable_audio_tries_ = 0;
  50. }
  51. // Don't continue checking timestamps if we've exhausted tries to reach stable
  52. // state. This suggests the media's encoded timestamps are way off.
  53. if (num_unstable_audio_tries_ > limit_unstable_audio_tries_)
  54. return;
  55. // Keep resetting encode base ts until we start getting decode output. Some
  56. // codecs/containers (e.g. chained Ogg) will take several encoded buffers
  57. // before producing the first decoded output.
  58. if (!audio_output_ts_helper_) {
  59. audio_base_ts_ = buffer.timestamp();
  60. DVLOG(3) << __func__
  61. << " setting audio_base:" << audio_base_ts_.InMicroseconds();
  62. return;
  63. }
  64. base::TimeDelta expected_ts = audio_output_ts_helper_->GetTimestamp();
  65. base::TimeDelta ts_delta = buffer.timestamp() - expected_ts;
  66. // Reconciling encoded buffer timestamps with decoded output often requires
  67. // adjusting expectations by some offset. This accounts for varied (and at
  68. // this point unknown) handling of front trimming and codec delay. Codec delay
  69. // and skip trimming may or may not be accounted for in the encoded timestamps
  70. // depending on the codec (e.g. MP3 vs Opus) and demuxers used (e.g. FFmpeg
  71. // vs MSE stream parsers).
  72. if (!reached_stable_state_) {
  73. if (std::abs(ts_delta.InMilliseconds()) < kStableTimeGapThrsholdMsec) {
  74. reached_stable_state_ = true;
  75. DVLOG(3) << __func__ << " stabilized! tries:" << num_unstable_audio_tries_
  76. << " offset:"
  77. << audio_output_ts_helper_->base_timestamp().InMicroseconds();
  78. } else {
  79. base::TimeDelta orig_offset = audio_output_ts_helper_->base_timestamp();
  80. // Save since this gets reset when we set new base time.
  81. int64_t decoded_frame_count = audio_output_ts_helper_->frame_count();
  82. audio_output_ts_helper_->SetBaseTimestamp(orig_offset + ts_delta);
  83. audio_output_ts_helper_->AddFrames(decoded_frame_count);
  84. DVLOG(3) << __func__
  85. << " NOT stabilized. tries:" << num_unstable_audio_tries_
  86. << " offset was:" << orig_offset.InMicroseconds() << " now:"
  87. << audio_output_ts_helper_->base_timestamp().InMicroseconds();
  88. num_unstable_audio_tries_++;
  89. // Let developers know if their files timestamps are way off from
  90. if (num_unstable_audio_tries_ > limit_unstable_audio_tries_) {
  91. MEDIA_LOG(WARNING, media_log_)
  92. << "Failed to reconcile encoded audio times with decoded output.";
  93. }
  94. }
  95. // Don't bother with further checking until we reach stable state.
  96. return;
  97. }
  98. if (std::abs(ts_delta.InMilliseconds()) > drift_warning_threshold_msec_) {
  99. LIMITED_MEDIA_LOG(WARNING, media_log_, num_timestamp_gap_warnings_,
  100. kMaxTimestampGapWarnings)
  101. << " Large timestamp gap detected; may cause AV sync to drift."
  102. << " time:" << buffer.timestamp().InMicroseconds() << "us"
  103. << " expected:" << expected_ts.InMicroseconds() << "us"
  104. << " delta:" << ts_delta.InMicroseconds() << "us";
  105. // Increase threshold to avoid log spam but, let us know if gap widens.
  106. drift_warning_threshold_msec_ = std::abs(ts_delta.InMilliseconds());
  107. }
  108. DVLOG(3) << __func__ << " delta:" << ts_delta.InMicroseconds()
  109. << " expected_ts:" << expected_ts.InMicroseconds()
  110. << " actual_ts:" << buffer.timestamp().InMicroseconds()
  111. << " audio_ts_offset:"
  112. << audio_output_ts_helper_->base_timestamp().InMicroseconds();
  113. }
  114. void AudioTimestampValidator::RecordOutputDuration(
  115. const AudioBuffer& audio_buffer) {
  116. if (!audio_output_ts_helper_) {
  117. DCHECK_NE(audio_base_ts_, kNoTimestamp);
  118. // SUBTLE: deliberately creating this with output buffer sample rate because
  119. // demuxer stream config is potentially stale for implicit AAC.
  120. audio_output_ts_helper_ =
  121. std::make_unique<AudioTimestampHelper>(audio_buffer.sample_rate());
  122. audio_output_ts_helper_->SetBaseTimestamp(audio_base_ts_);
  123. }
  124. DVLOG(3) << __func__ << " " << audio_buffer.frame_count() << " frames";
  125. audio_output_ts_helper_->AddFrames(audio_buffer.frame_count());
  126. }
  127. } // namespace media