Index: media/filters/chunk_demuxer.cc |
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc |
index be4fa60ce46ed00b59e8d39b3c8d30784ada33c5..29e31af00d7aae8f5fc64596f357c770e4af7136 100644 |
--- a/media/filters/chunk_demuxer.cc |
+++ b/media/filters/chunk_demuxer.cc |
@@ -111,7 +111,7 @@ static bool IsSupported(const std::string& type, |
*has_audio = false; |
*has_video = false; |
- // Search for the SupportedTypeInfo for |type| |
+ // Search for the SupportedTypeInfo for |type|. |
for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { |
const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; |
if (type == type_info.type) { |
@@ -637,19 +637,24 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
audio_cb, |
video_cb, |
base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
- base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id)); |
+ base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
+ base::Bind(&ChunkDemuxer::OnEndOfMediaSegment, |
+ base::Unretained(this), id)); |
stream_parser_map_[id] = stream_parser.release(); |
+ SourceInfo info = { base::TimeDelta(), true }; |
+ source_info_map_[id] = info; |
return kOk; |
} |
void ChunkDemuxer::RemoveId(const std::string& id) { |
- CHECK_GT(stream_parser_map_.count(id), 0u); |
+ CHECK(IsValidId(id)); |
base::AutoLock auto_lock(lock_); |
delete stream_parser_map_[id]; |
stream_parser_map_.erase(id); |
+ source_info_map_.erase(id); |
if (source_id_audio_ == id && audio_) |
audio_->Shutdown(); |
@@ -660,7 +665,7 @@ void ChunkDemuxer::RemoveId(const std::string& id) { |
Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
DCHECK(!id.empty()); |
- DCHECK_GT(stream_parser_map_.count(id), 0u); |
+ DCHECK(IsValidId(id)); |
DCHECK(id == source_id_audio_ || id == source_id_video_); |
base::AutoLock auto_lock(lock_); |
@@ -730,7 +735,7 @@ bool ChunkDemuxer::AppendData(const std::string& id, |
switch (state_) { |
case INITIALIZING: |
case WAITING_FOR_START_TIME: |
- DCHECK_GT(stream_parser_map_.count(id), 0u); |
+ DCHECK(IsValidId(id)); |
if (!stream_parser_map_[id]->Parse(data, length)) { |
ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
return true; |
@@ -738,7 +743,7 @@ bool ChunkDemuxer::AppendData(const std::string& id, |
break; |
case INITIALIZED: { |
- DCHECK_GT(stream_parser_map_.count(id), 0u); |
+ DCHECK(IsValidId(id)); |
if (!stream_parser_map_[id]->Parse(data, length)) { |
ReportError_Locked(PIPELINE_ERROR_DECODE); |
return true; |
@@ -780,11 +785,24 @@ bool ChunkDemuxer::AppendData(const std::string& id, |
void ChunkDemuxer::Abort(const std::string& id) { |
DVLOG(1) << "Abort(" << id << ")"; |
DCHECK(!id.empty()); |
- DCHECK_GT(stream_parser_map_.count(id), 0u); |
+ CHECK(IsValidId(id)); |
stream_parser_map_[id]->Flush(); |
} |
+bool ChunkDemuxer::SetTimestampOffset(const std::string& id, double offset) { |
+ DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset << ")"; |
+ CHECK(IsValidId(id)); |
+ |
+ if (!source_info_map_[id].can_update_offset) |
+ return false; |
+ |
+ TimeDelta time_offset = TimeDelta::FromMicroseconds( |
+ offset * base::Time::kMicrosecondsPerSecond); |
+ source_info_map_[id].timestamp_offset = time_offset; |
+ return true; |
+} |
+ |
bool ChunkDemuxer::EndOfStream(PipelineStatus status) { |
DVLOG(1) << "EndOfStream(" << status << ")"; |
base::AutoLock auto_lock(lock_); |
@@ -983,6 +1001,10 @@ bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
if (!audio_) |
return false; |
+ CHECK(IsValidId(source_id_audio_)); |
+ AdjustBufferTimestamps( |
+ buffers, source_info_map_[source_id_audio_].timestamp_offset); |
+ |
return audio_->Append(buffers); |
} |
@@ -993,6 +1015,10 @@ bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { |
if (!video_) |
return false; |
+ CHECK(IsValidId(source_id_video_)); |
+ AdjustBufferTimestamps( |
+ buffers, source_info_map_[source_id_video_].timestamp_offset); |
+ |
return video_->Append(buffers); |
} |
@@ -1003,11 +1029,16 @@ bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, |
} |
void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, |
- TimeDelta start_timestamp) { |
+ TimeDelta timestamp) { |
DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " |
- << start_timestamp.InSecondsF() << ")"; |
+ << timestamp.InSecondsF() << ")"; |
lock_.AssertAcquired(); |
+ CHECK(IsValidId(source_id)); |
+ source_info_map_[source_id].can_update_offset = false; |
+ base::TimeDelta start_timestamp = |
+ timestamp + source_info_map_[source_id].timestamp_offset; |
+ |
if (start_time_ == kNoTimestamp()) { |
DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); |
// Use the first reported media segment start time as the |start_time_| |
@@ -1037,4 +1068,29 @@ void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, |
base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
} |
+void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) { |
+ DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")"; |
+ CHECK(IsValidId(source_id)); |
+ source_info_map_[source_id].can_update_offset = true; |
+} |
+ |
+void ChunkDemuxer::AdjustBufferTimestamps( |
+ const StreamParser::BufferQueue& buffers, |
+ base::TimeDelta timestamp_offset) { |
+ if (timestamp_offset == base::TimeDelta()) |
+ return; |
+ |
+ for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
+ itr != buffers.end(); ++itr) { |
+ (*itr)->SetDecodeTimestamp( |
+ (*itr)->GetDecodeTimestamp() + timestamp_offset); |
+ (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset); |
+ } |
+} |
+ |
+bool ChunkDemuxer::IsValidId(const std::string& source_id) const { |
+ return source_info_map_.count(source_id) > 0u && |
+ stream_parser_map_.count(source_id) > 0u; |
+} |
+ |
} // namespace media |