Chromium Code Reviews| 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 a762e2c40b34411594a5a30f0438e36f96d31a57..ed68f2bdc1ecd6242ab8a191545aa986103774e0 100644 |
| --- a/media/formats/webm/webm_cluster_parser.cc |
| +++ b/media/formats/webm/webm_cluster_parser.cc |
| @@ -15,10 +15,20 @@ |
| #include "media/formats/webm/webm_crypto_helpers.h" |
| #include "media/formats/webm/webm_webvtt_parser.h" |
| +// An arbitrarily-chosen number to estimate the duration of a buffer if none is |
| +// set and there is not enough information to get a better estimate. |
| +// TODO(wolenetz/acolwell): Parse audio codebook to determine missing audio |
| +// frame durations. See http://crbug.com/351166. |
| +static int kDefaultBufferDurationInMs = 50; |
|
acolwell GONE FROM CHROMIUM
2014/03/26 23:32:04
nit: If we are assuming this will be audio, then I
wolenetz
2014/03/27 18:01:48
Done. I've now differentiated audio vs video defau
|
| + |
| namespace media { |
| WebMClusterParser::WebMClusterParser( |
| - int64 timecode_scale, int audio_track_num, int video_track_num, |
| + int64 timecode_scale, |
| + int audio_track_num, |
| + base::TimeDelta audio_default_duration, |
| + int video_track_num, |
| + base::TimeDelta video_default_duration, |
| const WebMTracksParser::TextTracks& text_tracks, |
| const std::set<int64>& ignored_tracks, |
| const std::string& audio_encryption_key_id, |
| @@ -38,13 +48,14 @@ WebMClusterParser::WebMClusterParser( |
| cluster_timecode_(-1), |
| cluster_start_time_(kNoTimestamp()), |
| cluster_ended_(false), |
| - audio_(audio_track_num, false), |
| - video_(video_track_num, true), |
| + audio_(audio_track_num, false, audio_default_duration), |
| + video_(video_track_num, true, video_default_duration), |
| log_cb_(log_cb) { |
| for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); |
| it != text_tracks.end(); |
| ++it) { |
| - text_track_map_.insert(std::make_pair(it->first, Track(it->first, false))); |
| + text_track_map_.insert(std::make_pair( |
| + it->first, Track(it->first, false, kNoTimestamp()))); |
| } |
| } |
| @@ -56,8 +67,8 @@ void WebMClusterParser::Reset() { |
| cluster_start_time_ = kNoTimestamp(); |
| cluster_ended_ = false; |
| parser_.Reset(); |
| - audio_.Reset(); |
| - video_.Reset(); |
| + audio_.Flush(); |
|
acolwell GONE FROM CHROMIUM
2014/03/26 23:32:04
nit: I think Reset() should be "clear everything"
wolenetz
2014/03/27 18:01:48
Done.
|
| + video_.Flush(); |
| ResetTextTracks(); |
| } |
| @@ -99,6 +110,18 @@ int WebMClusterParser::Parse(const uint8* buf, int size) { |
| return result; |
| } |
| +const WebMClusterParser::BufferQueue& WebMClusterParser::GetAudioBuffers() { |
| + if (cluster_ended_) |
| + audio_.ApplyDurationDefaultOrEstimateIfNeeded(); |
| + return audio_.buffers(); |
| +} |
| + |
| +const WebMClusterParser::BufferQueue& WebMClusterParser::GetVideoBuffers() { |
| + if (cluster_ended_) |
| + video_.ApplyDurationDefaultOrEstimateIfNeeded(); |
| + return video_.buffers(); |
| +} |
| + |
| const WebMClusterParser::TextBufferQueueMap& |
| WebMClusterParser::GetTextBuffers() { |
| // Translate our |text_track_map_| into |text_buffers_map_|, inserting rows in |
| @@ -107,6 +130,9 @@ WebMClusterParser::GetTextBuffers() { |
| for (TextTrackMap::const_iterator itr = text_track_map_.begin(); |
| itr != text_track_map_.end(); |
| ++itr) { |
| + // Per OnBlock(), all text buffers should already have valid durations, so |
| + // there is no need to call |
| + // itr->second.ApplyDurationDefaultOrEstimateIfNeeded() here. |
| const BufferQueue& text_buffers = itr->second.buffers(); |
| if (!text_buffers.empty()) |
| text_buffers_map_.insert(std::make_pair(itr->first, text_buffers)); |
| @@ -390,9 +416,14 @@ bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num, |
| return track->AddBuffer(buffer); |
| } |
| -WebMClusterParser::Track::Track(int track_num, bool is_video) |
| +WebMClusterParser::Track::Track(int track_num, bool is_video, |
| + base::TimeDelta default_duration) |
| : track_num_(track_num), |
| - is_video_(is_video) { |
| + is_video_(is_video), |
| + default_duration_(default_duration), |
| + estimated_next_frame_duration_(kNoTimestamp()) { |
| + DCHECK(default_duration_ == kNoTimestamp() || |
| + default_duration_ > base::TimeDelta()); |
| } |
| WebMClusterParser::Track::~Track() {} |
| @@ -405,14 +436,88 @@ bool WebMClusterParser::Track::AddBuffer( |
| << " kf " << buffer->IsKeyframe() |
| << " size " << buffer->data_size(); |
| + if (last_added_buffer_missing_duration_) { |
| + base::TimeDelta derived_duration = |
| + buffer->timestamp() - last_added_buffer_missing_duration_->timestamp(); |
| + if (derived_duration < base::TimeDelta()) { |
| + DVLOG(2) << "AddBuffer() : Invalid derived duration: " |
| + << derived_duration.InSecondsF(); |
| + return false; |
| + } |
| + |
| + last_added_buffer_missing_duration_->set_duration(derived_duration); |
| + |
| + DVLOG(2) << "AddBuffer() : applied derived duration to held-back buffer : " |
| + << " ts " |
| + << last_added_buffer_missing_duration_->timestamp().InSecondsF() |
| + << " dur " |
| + << last_added_buffer_missing_duration_->duration().InSecondsF() |
| + << " kf " << last_added_buffer_missing_duration_->IsKeyframe() |
| + << " size " << last_added_buffer_missing_duration_->data_size(); |
| + estimated_next_frame_duration_ = std::max(derived_duration, |
| + estimated_next_frame_duration_); |
| + buffers_.push_back(last_added_buffer_missing_duration_); |
| + last_added_buffer_missing_duration_ = NULL; |
| + } |
| + |
| + if (buffer->duration() == kNoTimestamp()) { |
| + last_added_buffer_missing_duration_ = buffer; |
| + DVLOG(2) << "AddBuffer() : holding back buffer that is missing duration"; |
| + return true; |
| + } |
| + |
| + DCHECK(!last_added_buffer_missing_duration_); |
| + if (buffer->duration() < base::TimeDelta()) { |
|
acolwell GONE FROM CHROMIUM
2014/03/26 23:32:04
nit: Looks like we could avoid some duplicate code
wolenetz
2014/03/27 18:01:48
Done.
|
| + DVLOG(2) << "AddBuffer() : Invalid negative duration: " |
| + << buffer->duration().InSecondsF(); |
| + return false; |
| + } |
| + |
| + estimated_next_frame_duration_ = std::max(buffer->duration(), |
| + estimated_next_frame_duration_); |
| buffers_.push_back(buffer); |
| return true; |
| } |
| +void WebMClusterParser::Track::ApplyDurationDefaultOrEstimateIfNeeded() { |
| + if (!last_added_buffer_missing_duration_) |
| + return; |
| + |
| + if (default_duration_ != kNoTimestamp()) { |
| + DVLOG(3) << __FUNCTION__ << " : using TrackEntry DefaultDuration"; |
| + last_added_buffer_missing_duration_->set_duration(default_duration_); |
| + } else if (estimated_next_frame_duration_ != kNoTimestamp()) { |
| + DVLOG(3) << __FUNCTION__ << " : using estimated duration"; |
| + last_added_buffer_missing_duration_->set_duration( |
| + estimated_next_frame_duration_); |
| + } else { |
| + DVLOG(3) << __FUNCTION__ << " : using hardcoded default duration"; |
| + last_added_buffer_missing_duration_->set_duration( |
| + base::TimeDelta::FromMilliseconds(kDefaultBufferDurationInMs)); |
| + } |
| + |
| + DVLOG(2) << "ApplyDurationDefaultOrEstimateIfNeeded() : new dur : " |
| + << " ts " |
| + << last_added_buffer_missing_duration_->timestamp().InSecondsF() |
| + << " dur " |
| + << last_added_buffer_missing_duration_->duration().InSecondsF() |
| + << " kf " << last_added_buffer_missing_duration_->IsKeyframe() |
| + << " size " << last_added_buffer_missing_duration_->data_size(); |
| + buffers_.push_back(last_added_buffer_missing_duration_); |
| + last_added_buffer_missing_duration_ = NULL; |
| +} |
| + |
| void WebMClusterParser::Track::Reset() { |
| + // Note that |estimated_next_frame_duration_| is not reset, so it can be |
| + // reused on subsequent buffers added to this instance. |
| buffers_.clear(); |
| } |
| +void WebMClusterParser::Track::Flush() { |
| + Reset(); |
| + last_added_buffer_missing_duration_ = NULL; |
| +} |
| + |
| bool WebMClusterParser::Track::IsKeyframe(const uint8* data, int size) const { |
| // For now, assume that all blocks are keyframes for datatypes other than |
| // video. This is a valid assumption for Vorbis, WebVTT, & Opus. |