Index: media/formats/webm/webm_cluster_parser.cc |
diff --git a/media/formats/webm/webm_cluster_parser.cc b/media/formats/webm/webm_cluster_parser.cc |
index 6f198ec66dc669d6b6876a12319a7a6e14b79f64..a76559d241ac157ab7f9fa0abf322385a3fb176d 100644 |
--- a/media/formats/webm/webm_cluster_parser.cc |
+++ b/media/formats/webm/webm_cluster_parser.cc |
@@ -25,7 +25,10 @@ const uint16_t WebMClusterParser::kOpusFrameDurationsMu[] = { |
enum { |
// Limits the number of MEDIA_LOG() calls in the path of reading encoded |
// duration to avoid spamming for corrupted data. |
- kMaxDurationLogs = 10, |
+ kMaxDurationErrorLogs = 10, |
+ // Limits the number of MEDIA_LOG() calls warning the user that buffer |
+ // durations have been estimated. |
+ kMaxDurationEstimateLogs = 10, |
}; |
WebMClusterParser::WebMClusterParser( |
@@ -185,7 +188,8 @@ base::TimeDelta WebMClusterParser::ReadOpusDuration(const uint8_t* data, |
base::TimeDelta::FromMilliseconds(120); |
if (size < 1) { |
- LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, kMaxDurationLogs) |
+ LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
+ kMaxDurationErrorLogs) |
<< "Invalid zero-byte Opus packet; demuxed block duration may be " |
"imprecise."; |
return kNoTimestamp(); |
@@ -207,7 +211,7 @@ base::TimeDelta WebMClusterParser::ReadOpusDuration(const uint8_t* data, |
// Type 3 indicates an arbitrary frame count described in the next byte. |
if (size < 2) { |
LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
- kMaxDurationLogs) |
+ kMaxDurationErrorLogs) |
<< "Second byte missing from 'Code 3' Opus packet; demuxed block " |
"duration may be imprecise."; |
return kNoTimestamp(); |
@@ -217,7 +221,7 @@ base::TimeDelta WebMClusterParser::ReadOpusDuration(const uint8_t* data, |
if (frame_count == 0) { |
LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
- kMaxDurationLogs) |
+ kMaxDurationErrorLogs) |
<< "Illegal 'Code 3' Opus packet with frame count zero; demuxed " |
"block duration may be imprecise."; |
return kNoTimestamp(); |
@@ -225,7 +229,8 @@ base::TimeDelta WebMClusterParser::ReadOpusDuration(const uint8_t* data, |
break; |
default: |
- LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, kMaxDurationLogs) |
+ LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
+ kMaxDurationErrorLogs) |
<< "Unexpected Opus frame count type: " << frame_count_type << "; " |
<< "demuxed block duration may be imprecise."; |
return kNoTimestamp(); |
@@ -243,7 +248,8 @@ base::TimeDelta WebMClusterParser::ReadOpusDuration(const uint8_t* data, |
// Intentionally allowing packet to pass through for now. Decoder should |
// either handle or fail gracefully. MEDIA_LOG as breadcrumbs in case |
// things go sideways. |
- LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, kMaxDurationLogs) |
+ LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
+ kMaxDurationErrorLogs) |
<< "Warning, demuxed Opus packet with encoded duration: " << duration |
<< ". Should be no greater than " << kPacketDurationMax; |
} |
@@ -562,7 +568,7 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, |
base::TimeDelta::FromMicroseconds(timecode_multiplier_ * 2); |
if (duration_difference.magnitude() > kWarnDurationDiff) { |
LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
- kMaxDurationLogs) |
+ kMaxDurationErrorLogs) |
<< "BlockDuration " |
<< "(" << block_duration_time_delta << ") " |
<< "differs significantly from encoded duration " |
@@ -589,7 +595,8 @@ WebMClusterParser::Track::Track(int track_num, |
bool is_video, |
base::TimeDelta default_duration, |
const LogCB& log_cb) |
- : track_num_(track_num), |
+ : num_duration_estimates_(0), |
+ track_num_(track_num), |
is_video_(is_video), |
default_duration_(default_duration), |
estimated_next_frame_duration_(kNoTimestamp()), |
@@ -682,10 +689,25 @@ void WebMClusterParser::Track::ApplyDurationEstimateIfNeeded() { |
if (!last_added_buffer_missing_duration_.get()) |
return; |
- last_added_buffer_missing_duration_->set_duration(GetDurationEstimate()); |
+ base::TimeDelta estimated_duration = GetDurationEstimate(); |
+ last_added_buffer_missing_duration_->set_duration(estimated_duration); |
- DVLOG(2) << "ApplyDurationEstimateIfNeeded() : new dur : " |
- << " ts " |
+ if (is_video_) { |
+ // Exposing estimation so splicing/overlap frame processing can make |
+ // informed decisions downstream. |
+ // TODO(chcunningham): Set this for audio as well in later change where |
+ // audio is switched to max estimation and splicing is disabled. |
+ last_added_buffer_missing_duration_->set_is_duration_estimated(true); |
+ } |
+ |
+ LIMITED_MEDIA_LOG(INFO, log_cb_, num_duration_estimates_, |
+ kMaxDurationEstimateLogs) |
+ << "Estimating WebM block duration to be " << estimated_duration << " " |
+ << "for the last (Simple)Block in the Cluster for this Track. Use " |
+ << "BlockGroups with BlockDurations at the end of each Track in a " |
+ << "Cluster to avoid estimation."; |
+ |
+ DVLOG(2) << __FUNCTION__ << " new dur : ts " |
<< last_added_buffer_missing_duration_->timestamp().InSecondsF() |
<< " dur " |
<< last_added_buffer_missing_duration_->duration().InSecondsF() |
@@ -751,16 +773,35 @@ bool WebMClusterParser::Track::QueueBuffer( |
return false; |
} |
- // The estimated frame duration is the minimum non-zero duration since the |
- // last initialization segment. The minimum is used to ensure frame durations |
- // aren't overestimated. |
+ // The estimated frame duration is the minimum (for audio) or the maximum |
+ // (for video) non-zero duration since the last initialization segment. The |
+ // minimum is used for audio to ensure frame durations aren't overestimated, |
+ // triggering unnecessary frame splicing. For video, splicing does not apply, |
+ // so maximum is used and overlap is simply resolved by showing the |
+ // later of the overlapping frames at its given PTS, effectively trimming down |
+ // the over-estimated duration of the previous frame. |
+ // TODO(chcunningham): Use max for audio and disable splicing whenever |
+ // estimated buffers are encountered. |
if (duration > base::TimeDelta()) { |
+ base::TimeDelta orig_duration_estimate = estimated_next_frame_duration_; |
if (estimated_next_frame_duration_ == kNoTimestamp()) { |
estimated_next_frame_duration_ = duration; |
+ } else if (is_video_) { |
+ estimated_next_frame_duration_ = |
+ std::max(duration, estimated_next_frame_duration_); |
} else { |
estimated_next_frame_duration_ = |
std::min(duration, estimated_next_frame_duration_); |
} |
+ |
+ if (orig_duration_estimate != estimated_next_frame_duration_) { |
+ DVLOG(3) << "Updated duration estimate:" |
+ << orig_duration_estimate |
+ << " -> " |
+ << estimated_next_frame_duration_ |
+ << " at timestamp: " |
+ << buffer->GetDecodeTimestamp().InSecondsF(); |
+ } |
} |
buffers_.push_back(buffer); |