diff options
-rw-r--r-- | media/base/stream_parser.h | 3 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.cc | 74 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.h | 22 | ||||
-rw-r--r-- | media/filters/chunk_demuxer_unittest.cc | 66 | ||||
-rw-r--r-- | media/filters/source_buffer_stream.cc | 2 | ||||
-rw-r--r-- | media/mp4/mp4_stream_parser.cc | 13 | ||||
-rw-r--r-- | media/mp4/mp4_stream_parser.h | 4 | ||||
-rw-r--r-- | media/mp4/mp4_stream_parser_unittest.cc | 8 | ||||
-rw-r--r-- | media/webm/webm_cluster_parser.cc | 9 | ||||
-rw-r--r-- | media/webm/webm_cluster_parser.h | 4 | ||||
-rw-r--r-- | media/webm/webm_stream_parser.cc | 9 | ||||
-rw-r--r-- | media/webm/webm_stream_parser.h | 4 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_impl.cc | 5 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_impl.h | 2 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_proxy.cc | 5 | ||||
-rw-r--r-- | webkit/media/webmediaplayer_proxy.h | 1 |
16 files changed, 211 insertions, 20 deletions
diff --git a/media/base/stream_parser.h b/media/base/stream_parser.h index 3ad3cd7..64a8c49 100644 --- a/media/base/stream_parser.h +++ b/media/base/stream_parser.h @@ -74,7 +74,8 @@ class MEDIA_EXPORT StreamParser { const NewBuffersCB& audio_cb, const NewBuffersCB& video_cb, const NeedKeyCB& need_key_cb, - const NewMediaSegmentCB& new_segment_cb) = 0; + const NewMediaSegmentCB& new_segment_cb, + const base::Closure& end_of_segment_cb) = 0; // Called when a seek occurs. This flushes the current parser state // and puts the parser in a state where it can receive data for the new seek diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index be4fa60..29e31af 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 diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index ced6d97..773f1d5 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h @@ -74,6 +74,12 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { // it can accept a new segment. void Abort(const std::string& id); + // Sets a time |offset| in seconds to be applied to subsequent buffers + // appended to the source buffer assicated with |id|. Returns true if the + // offset is set properly, false if the offset cannot be applied because we're + // in the middle of parsing a media segment. + bool SetTimestampOffset(const std::string& id, double offset); + // Signals an EndOfStream request. // Returns false if called in an unexpected state or if there is a gap between // the current position and the end of the buffered data. @@ -117,11 +123,19 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { bool OnNeedKey(scoped_array<uint8> init_data, int init_data_size); void OnNewMediaSegment(const std::string& source_id, base::TimeDelta start_timestamp); + void OnEndOfMediaSegment(const std::string& source_id); // Computes the intersection between the video & audio // buffered ranges. Ranges<base::TimeDelta> ComputeIntersection() const; + // Applies |time_offset| to the timestamps of |buffers|. + void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers, + base::TimeDelta timestamp_offset); + + // Returns true if |source_id| is valid, false otherwise. + bool IsValidId(const std::string& source_id) const; + mutable base::Lock lock_; State state_; @@ -138,6 +152,14 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { typedef std::map<std::string, StreamParser*> StreamParserMap; StreamParserMap stream_parser_map_; + // Contains state belonging to a source id. + struct SourceInfo { + base::TimeDelta timestamp_offset; + bool can_update_offset; + }; + typedef std::map<std::string, SourceInfo> SourceInfoMap; + SourceInfoMap source_info_map_; + // Used to ensure that (1) config data matches the type and codec provided in // AddId(), (2) only 1 audio and 1 video sources are added, and (3) ids may be // removed with RemoveID() but can not be re-added (yet). diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index fda9bb7..927636a 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc @@ -2064,4 +2064,70 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Seek) { ASSERT_TRUE(video_config_1.Matches(stream->video_decoder_config())); } +TEST_F(ChunkDemuxerTest, TestTimestampPositiveOffset) { + ASSERT_TRUE(InitDemuxer(true, true, false)); + + ASSERT_TRUE(demuxer_->SetTimestampOffset(kSourceId, 30)); + scoped_ptr<Cluster> cluster(GenerateCluster(0, 2)); + ASSERT_TRUE(AppendData(cluster->data(), cluster->size())); + + scoped_refptr<DemuxerStream> audio = + demuxer_->GetStream(DemuxerStream::AUDIO); + scoped_refptr<DemuxerStream> video = + demuxer_->GetStream(DemuxerStream::VIDEO); + GenerateExpectedReads(30000, 2, audio, video); +} + +TEST_F(ChunkDemuxerTest, TestTimestampNegativeOffset) { + ASSERT_TRUE(InitDemuxer(true, true, false)); + + ASSERT_TRUE(demuxer_->SetTimestampOffset(kSourceId, -1)); + scoped_ptr<Cluster> cluster = GenerateCluster(1000, 2); + ASSERT_TRUE(AppendData(cluster->data(), cluster->size())); + + scoped_refptr<DemuxerStream> audio = + demuxer_->GetStream(DemuxerStream::AUDIO); + scoped_refptr<DemuxerStream> video = + demuxer_->GetStream(DemuxerStream::VIDEO); + GenerateExpectedReads(0, 2, audio, video); +} + +TEST_F(ChunkDemuxerTest, TestTimestampOffsetSeparateStreams) { + std::string audio_id = "audio1"; + std::string video_id = "video1"; + ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id)); + + scoped_refptr<DemuxerStream> audio = + demuxer_->GetStream(DemuxerStream::AUDIO); + scoped_refptr<DemuxerStream> video = + demuxer_->GetStream(DemuxerStream::VIDEO); + + scoped_ptr<Cluster> cluster_a( + GenerateSingleStreamCluster( + 2500, 2500 + kAudioBlockDuration * 4, kAudioTrackNum, + kAudioBlockDuration)); + + scoped_ptr<Cluster> cluster_v( + GenerateSingleStreamCluster( + 0, kVideoBlockDuration * 4, kVideoTrackNum, kVideoBlockDuration)); + + ASSERT_TRUE(demuxer_->SetTimestampOffset(audio_id, -2.5)); + ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size())); + GenerateSingleStreamExpectedReads(0, 4, audio, kAudioBlockDuration); + + ASSERT_TRUE(demuxer_->SetTimestampOffset(video_id, 27.3)); + ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size())); + GenerateSingleStreamExpectedReads(27300, 4, video, kVideoBlockDuration); +} + +TEST_F(ChunkDemuxerTest, TestTimestampOffsetMidParse) { + ASSERT_TRUE(InitDemuxer(true, true, false)); + + scoped_ptr<Cluster> cluster = GenerateCluster(0, 2); + // Append only part of the cluster data. + ASSERT_TRUE(AppendData(cluster->data(), cluster->size() - 13)); + + // Setting a timestamp should fail because we're in the middle of a cluster. + ASSERT_FALSE(demuxer_->SetTimestampOffset(kSourceId, 25)); +} } // namespace media diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc index 2ffbb6a..8b85984 100644 --- a/media/filters/source_buffer_stream.cc +++ b/media/filters/source_buffer_stream.cc @@ -982,7 +982,7 @@ SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) { SourceBufferRange::KeyframeMap::iterator SourceBufferRange::GetFirstKeyframeAt(base::TimeDelta timestamp, - bool skip_given_timestamp) { + bool skip_given_timestamp) { KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp); // lower_bound() returns the first element >= |timestamp|, so if we don't want // to include keyframes == |timestamp|, we have to increment the iterator diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc index 757ea503..9d51959 100644 --- a/media/mp4/mp4_stream_parser.cc +++ b/media/mp4/mp4_stream_parser.cc @@ -37,13 +37,15 @@ void MP4StreamParser::Init(const InitCB& init_cb, const NewBuffersCB& audio_cb, const NewBuffersCB& video_cb, const NeedKeyCB& need_key_cb, - const NewMediaSegmentCB& new_segment_cb) { + const NewMediaSegmentCB& new_segment_cb, + const base::Closure& end_of_segment_cb) { DCHECK_EQ(state_, kWaitingForInit); DCHECK(init_cb_.is_null()); DCHECK(!init_cb.is_null()); DCHECK(!config_cb.is_null()); DCHECK(!audio_cb.is_null() || !video_cb.is_null()); DCHECK(!need_key_cb.is_null()); + DCHECK(!end_of_segment_cb.is_null()); ChangeState(kParsingBoxes); init_cb_ = init_cb; @@ -52,6 +54,7 @@ void MP4StreamParser::Init(const InitCB& init_cb, video_cb_ = video_cb; need_key_cb_ = need_key_cb; new_segment_cb_ = new_segment_cb; + end_of_segment_cb_ = end_of_segment_cb; } void MP4StreamParser::Flush() { @@ -316,8 +319,11 @@ bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers, // Flush any buffers we've gotten in this chunk so that buffers don't // cross NewSegment() calls *err = !SendAndFlushSamples(audio_buffers, video_buffers); - if (*err) return false; + if (*err) + return false; + ChangeState(kParsingBoxes); + end_of_segment_cb_.Run(); return true; } @@ -337,7 +343,8 @@ bool MP4StreamParser::EnqueueSample(BufferQueue* audio_buffers, bool video = has_video_ && video_track_id_ == runs_->track_id(); // Skip this entire track if it's not one we're interested in - if (!audio && !video) runs_->AdvanceRun(); + if (!audio && !video) + runs_->AdvanceRun(); // Attempt to cache the auxiliary information first. Aux info is usually // placed in a contiguous block before the sample data, rather than being diff --git a/media/mp4/mp4_stream_parser.h b/media/mp4/mp4_stream_parser.h index 53100a95..b950af2 100644 --- a/media/mp4/mp4_stream_parser.h +++ b/media/mp4/mp4_stream_parser.h @@ -31,7 +31,8 @@ class MEDIA_EXPORT MP4StreamParser : public StreamParser { const NewBuffersCB& audio_cb, const NewBuffersCB& video_cb, const NeedKeyCB& need_key_cb, - const NewMediaSegmentCB& new_segment_cb) OVERRIDE; + const NewMediaSegmentCB& new_segment_cb, + const base::Closure& end_of_segment_cb) OVERRIDE; virtual void Flush() OVERRIDE; virtual bool Parse(const uint8* buf, int size) OVERRIDE; @@ -70,6 +71,7 @@ class MEDIA_EXPORT MP4StreamParser : public StreamParser { NewBuffersCB video_cb_; NeedKeyCB need_key_cb_; NewMediaSegmentCB new_segment_cb_; + base::Closure end_of_segment_cb_; OffsetByteQueue queue_; diff --git a/media/mp4/mp4_stream_parser_unittest.cc b/media/mp4/mp4_stream_parser_unittest.cc index 63e1382..56f40df 100644 --- a/media/mp4/mp4_stream_parser_unittest.cc +++ b/media/mp4/mp4_stream_parser_unittest.cc @@ -93,6 +93,10 @@ class MP4StreamParserTest : public testing::Test { segment_start_ = start_dts; } + void EndOfSegmentF() { + DVLOG(1) << "EndOfSegmentF()"; + } + void InitializeParser() { parser_->Init( base::Bind(&MP4StreamParserTest::InitF, base::Unretained(this)), @@ -100,7 +104,9 @@ class MP4StreamParserTest : public testing::Test { base::Bind(&MP4StreamParserTest::NewBuffersF, base::Unretained(this)), base::Bind(&MP4StreamParserTest::NewBuffersF, base::Unretained(this)), base::Bind(&MP4StreamParserTest::KeyNeededF, base::Unretained(this)), - base::Bind(&MP4StreamParserTest::NewSegmentF, base::Unretained(this))); + base::Bind(&MP4StreamParserTest::NewSegmentF, base::Unretained(this)), + base::Bind(&MP4StreamParserTest::EndOfSegmentF, + base::Unretained(this))); } bool ParseMP4File(const std::string& filename, int append_bytes) { diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc index 14a360d..e9ef93e 100644 --- a/media/webm/webm_cluster_parser.cc +++ b/media/webm/webm_cluster_parser.cc @@ -43,6 +43,7 @@ WebMClusterParser::WebMClusterParser(int64 timecode_scale, block_duration_(-1), cluster_timecode_(-1), cluster_start_time_(kNoTimestamp()), + cluster_ended_(false), audio_(audio_track_num), video_(video_track_num) { CHECK_GE(video_encryption_key_id_size, 0); @@ -59,6 +60,7 @@ void WebMClusterParser::Reset() { last_block_timecode_ = -1; cluster_timecode_ = -1; cluster_start_time_ = kNoTimestamp(); + cluster_ended_ = false; parser_.Reset(); audio_.Reset(); video_.Reset(); @@ -70,10 +72,13 @@ int WebMClusterParser::Parse(const uint8* buf, int size) { int result = parser_.Parse(buf, size); - if (result <= 0) + if (result <= 0) { + cluster_ended_ = false; return result; + } - if (parser_.IsParsingComplete()) { + cluster_ended_ = parser_.IsParsingComplete(); + if (cluster_ended_) { // If there were no buffers in this cluster, set the cluster start time to // be the |cluster_timecode_|. if (cluster_start_time_ == kNoTimestamp()) { diff --git a/media/webm/webm_cluster_parser.h b/media/webm/webm_cluster_parser.h index 2bdb1e7..926e6a1 100644 --- a/media/webm/webm_cluster_parser.h +++ b/media/webm/webm_cluster_parser.h @@ -44,6 +44,9 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient { const BufferQueue& audio_buffers() const { return audio_.buffers(); } const BufferQueue& video_buffers() const { return video_.buffers(); } + // Returns true if the last Parse() call stopped at the end of a cluster. + bool cluster_ended() const { return cluster_ended_; } + private: // Helper class that manages per-track state. class Track { @@ -88,6 +91,7 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient { int64 cluster_timecode_; base::TimeDelta cluster_start_time_; + bool cluster_ended_; Track audio_; Track video_; diff --git a/media/webm/webm_stream_parser.cc b/media/webm/webm_stream_parser.cc index e9c8233..f27f7e7 100644 --- a/media/webm/webm_stream_parser.cc +++ b/media/webm/webm_stream_parser.cc @@ -192,7 +192,8 @@ void WebMStreamParser::Init(const InitCB& init_cb, const NewBuffersCB& audio_cb, const NewBuffersCB& video_cb, const NeedKeyCB& need_key_cb, - const NewMediaSegmentCB& new_segment_cb) { + const NewMediaSegmentCB& new_segment_cb, + const base::Closure& end_of_segment_cb) { DCHECK_EQ(state_, kWaitingForInit); DCHECK(init_cb_.is_null()); DCHECK(!init_cb.is_null()); @@ -200,6 +201,7 @@ void WebMStreamParser::Init(const InitCB& init_cb, DCHECK(!audio_cb.is_null() || !video_cb.is_null()); DCHECK(!need_key_cb.is_null()); DCHECK(!new_segment_cb.is_null()); + DCHECK(!end_of_segment_cb.is_null()); ChangeState(kParsingHeaders); init_cb_ = init_cb; @@ -208,6 +210,7 @@ void WebMStreamParser::Init(const InitCB& init_cb, video_cb_ = video_cb; need_key_cb_ = need_key_cb; new_segment_cb_ = new_segment_cb; + end_of_segment_cb_ = end_of_segment_cb; } void WebMStreamParser::Flush() { @@ -416,6 +419,7 @@ int WebMStreamParser::ParseCluster(const uint8* data, int size) { const BufferQueue& audio_buffers = cluster_parser_->audio_buffers(); const BufferQueue& video_buffers = cluster_parser_->video_buffers(); base::TimeDelta cluster_start_time = cluster_parser_->cluster_start_time(); + bool cluster_ended = cluster_parser_->cluster_ended(); if (waiting_for_buffers_ && cluster_start_time != kNoTimestamp()) { new_segment_cb_.Run(cluster_start_time); @@ -428,6 +432,9 @@ int WebMStreamParser::ParseCluster(const uint8* data, int size) { if (!video_buffers.empty() && !video_cb_.Run(video_buffers)) return -1; + if (cluster_ended) + end_of_segment_cb_.Run(); + return bytes_parsed; } diff --git a/media/webm/webm_stream_parser.h b/media/webm/webm_stream_parser.h index f555278..c5d06d5 100644 --- a/media/webm/webm_stream_parser.h +++ b/media/webm/webm_stream_parser.h @@ -26,7 +26,8 @@ class WebMStreamParser : public StreamParser { const NewBuffersCB& audio_cb, const NewBuffersCB& video_cb, const NeedKeyCB& need_key_cb, - const NewMediaSegmentCB& new_segment_cb) OVERRIDE; + const NewMediaSegmentCB& new_segment_cb, + const base::Closure& end_of_segment_cb) OVERRIDE; virtual void Flush() OVERRIDE; virtual bool Parse(const uint8* buf, int size) OVERRIDE; @@ -66,6 +67,7 @@ class WebMStreamParser : public StreamParser { NewBuffersCB video_cb_; NeedKeyCB need_key_cb_; NewMediaSegmentCB new_segment_cb_; + base::Closure end_of_segment_cb_; // True if a new cluster id has been seen, but no audio or video buffers have // been parsed yet. diff --git a/webkit/media/webmediaplayer_impl.cc b/webkit/media/webmediaplayer_impl.cc index a8b4ab9..b5f65d0 100644 --- a/webkit/media/webmediaplayer_impl.cc +++ b/webkit/media/webmediaplayer_impl.cc @@ -653,6 +653,11 @@ WebKit::WebMediaPlayer::AddIdStatus WebMediaPlayerImpl::sourceAddId( new_codecs)); } +bool WebMediaPlayerImpl::sourceTimestampOffset( + const WebKit::WebString& id, double offset) { + return proxy_->DemuxerSetTimestampOffset(id.utf8().data(), offset); +} + bool WebMediaPlayerImpl::sourceRemoveId(const WebKit::WebString& id) { DCHECK(!id.isEmpty()); proxy_->DemuxerRemoveId(id.utf8().data()); diff --git a/webkit/media/webmediaplayer_impl.h b/webkit/media/webmediaplayer_impl.h index 2b4a34c..22343cd 100644 --- a/webkit/media/webmediaplayer_impl.h +++ b/webkit/media/webmediaplayer_impl.h @@ -208,6 +208,8 @@ class WebMediaPlayerImpl unsigned length); virtual bool sourceAbort(const WebKit::WebString& id); virtual void sourceEndOfStream(EndOfStreamStatus status); + virtual bool sourceTimestampOffset( + const WebKit::WebString& id, double offset); virtual MediaKeyException generateKeyRequest( const WebKit::WebString& key_system, diff --git a/webkit/media/webmediaplayer_proxy.cc b/webkit/media/webmediaplayer_proxy.cc index 2809e68..911c9bc 100644 --- a/webkit/media/webmediaplayer_proxy.cc +++ b/webkit/media/webmediaplayer_proxy.cc @@ -196,6 +196,11 @@ media::ChunkDemuxer::Status WebMediaPlayerProxy::DemuxerAddId( return chunk_demuxer_->AddId(id, type, codecs); } +bool WebMediaPlayerProxy::DemuxerSetTimestampOffset( + const std::string& id, double offset) { + return chunk_demuxer_->SetTimestampOffset(id, offset); +} + void WebMediaPlayerProxy::DemuxerRemoveId(const std::string& id) { chunk_demuxer_->RemoveId(id); } diff --git a/webkit/media/webmediaplayer_proxy.h b/webkit/media/webmediaplayer_proxy.h index dcca88d..7dedcdf 100644 --- a/webkit/media/webmediaplayer_proxy.h +++ b/webkit/media/webmediaplayer_proxy.h @@ -105,6 +105,7 @@ class WebMediaPlayerProxy void DemuxerAbort(const std::string& id); void DemuxerEndOfStream(media::PipelineStatus status); void DemuxerShutdown(); + bool DemuxerSetTimestampOffset(const std::string& id, double offset); // DecryptorClient implementation. virtual void KeyAdded(const std::string& key_system, |