diff options
author | servolk <servolk@chromium.org> | 2016-03-04 19:29:15 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-05 03:30:48 +0000 |
commit | 81e01e07b928180ce12b0229dbb7ca0e157984d2 (patch) | |
tree | 2e70dc23dfe29eef339ae15f488df01376d45bfa | |
parent | ebeddadd639d34653036db5c29246cea272c9920 (diff) | |
download | chromium_src-81e01e07b928180ce12b0229dbb7ca0e157984d2.zip chromium_src-81e01e07b928180ce12b0229dbb7ca0e157984d2.tar.gz chromium_src-81e01e07b928180ce12b0229dbb7ca0e157984d2.tar.bz2 |
Unify media track info reporting on a demuxer level
This will work for both FFmpegDemuxer and MSE/ChunkDemuxer
Review URL: https://codereview.chromium.org/1727243002
Cr-Commit-Position: refs/heads/master@{#379449}
-rw-r--r-- | chromecast/media/cma/test/frame_segmenter_for_test.cc | 7 | ||||
-rw-r--r-- | media/base/demuxer.h | 6 | ||||
-rw-r--r-- | media/base/demuxer_perftest.cc | 10 | ||||
-rw-r--r-- | media/blink/webmediaplayer_impl.cc | 15 | ||||
-rw-r--r-- | media/blink/webmediaplayer_impl.h | 6 | ||||
-rw-r--r-- | media/blink/websourcebuffer_impl.cc | 12 | ||||
-rw-r--r-- | media/blink/websourcebuffer_impl.h | 3 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.cc | 29 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.h | 21 | ||||
-rw-r--r-- | media/filters/chunk_demuxer_unittest.cc | 70 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.cc | 3 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer.h | 3 | ||||
-rw-r--r-- | media/filters/ffmpeg_demuxer_unittest.cc | 8 | ||||
-rw-r--r-- | media/filters/media_source_state.cc | 35 | ||||
-rw-r--r-- | media/filters/media_source_state.h | 20 | ||||
-rw-r--r-- | media/test/pipeline_integration_test.cc | 22 | ||||
-rw-r--r-- | media/test/pipeline_integration_test_base.cc | 12 | ||||
-rw-r--r-- | media/test/pipeline_integration_test_base.h | 2 |
18 files changed, 189 insertions, 95 deletions
diff --git a/chromecast/media/cma/test/frame_segmenter_for_test.cc b/chromecast/media/cma/test/frame_segmenter_for_test.cc index 7d4d06d..b8172ee 100644 --- a/chromecast/media/cma/test/frame_segmenter_for_test.cc +++ b/chromecast/media/cma/test/frame_segmenter_for_test.cc @@ -15,6 +15,7 @@ #include "media/base/decoder_buffer.h" #include "media/base/demuxer.h" #include "media/base/media_log.h" +#include "media/base/media_tracks.h" #include "media/base/test_helpers.h" #include "media/filters/ffmpeg_demuxer.h" #include "media/filters/file_data_source.h" @@ -269,6 +270,9 @@ void OnEncryptedMediaInitData(::media::EmeInitDataType init_data_type, LOG(FATAL) << "Unexpected test failure: file is encrypted."; } +void OnMediaTracksUpdated(scoped_ptr<::media::MediaTracks> tracks) { +} + void OnNewBuffer(BufferList* buffer_list, const base::Closure& finished_cb, ::media::DemuxerStream::Status status, @@ -310,7 +314,8 @@ DemuxResult FFmpegDemuxForTest(const base::FilePath& filepath, ::media::FFmpegDemuxer demuxer( base::ThreadTaskRunnerHandle::Get(), &data_source, - base::Bind(&OnEncryptedMediaInitData), new ::media::MediaLog()); + base::Bind(&OnEncryptedMediaInitData), base::Bind(&OnMediaTracksUpdated), + new ::media::MediaLog()); ::media::WaitableMessageLoopEvent init_event; demuxer.Initialize(&fake_demuxer_host, init_event.GetPipelineStatusCB(), diff --git a/media/base/demuxer.h b/media/base/demuxer.h index afacdf3..7e1dbc8 100644 --- a/media/base/demuxer.h +++ b/media/base/demuxer.h @@ -22,6 +22,7 @@ namespace media { class TextTrackConfig; +class MediaTracks; class MEDIA_EXPORT DemuxerHost { public: @@ -64,6 +65,11 @@ class MEDIA_EXPORT Demuxer : public DemuxerStreamProvider { const std::vector<uint8_t>& init_data)> EncryptedMediaInitDataCB; + // Notifies demuxer clients that media track configuration has been updated + // (e.g. the inital stream metadata has been parsed successfully, or a new + // init segment has been parsed successfully in MSE case). + typedef base::Callback<void(scoped_ptr<MediaTracks>)> MediaTracksUpdatedCB; + Demuxer(); ~Demuxer() override; diff --git a/media/base/demuxer_perftest.cc b/media/base/demuxer_perftest.cc index 7d8a10b..6703222 100644 --- a/media/base/demuxer_perftest.cc +++ b/media/base/demuxer_perftest.cc @@ -14,6 +14,7 @@ #include "build/build_config.h" #include "media/base/media.h" #include "media/base/media_log.h" +#include "media/base/media_tracks.h" #include "media/base/test_data_util.h" #include "media/base/timestamp_constants.h" #include "media/filters/ffmpeg_demuxer.h" @@ -54,6 +55,10 @@ static void OnEncryptedMediaInitData(EmeInitDataType init_data_type, VLOG(0) << "File is encrypted."; } +static void OnMediaTracksUpdated(scoped_ptr<MediaTracks> tracks) { + VLOG(0) << "Got media tracks info, tracks = " << tracks->tracks().size(); +} + typedef std::vector<media::DemuxerStream* > Streams; // Simulates playback reading requirements by reading from each stream @@ -183,8 +188,11 @@ static void RunDemuxerBenchmark(const std::string& filename) { Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb = base::Bind(&OnEncryptedMediaInitData); + Demuxer::MediaTracksUpdatedCB tracks_updated_cb = + base::Bind(&OnMediaTracksUpdated); FFmpegDemuxer demuxer(message_loop.task_runner(), &data_source, - encrypted_media_init_data_cb, new MediaLog()); + encrypted_media_init_data_cb, tracks_updated_cb, + new MediaLog()); demuxer.Initialize(&demuxer_host, base::Bind(&QuitLoopWithStatus, &message_loop), diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index 4b5f749..2185d93 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc @@ -804,6 +804,14 @@ void WebMediaPlayerImpl::OnEncryptedMediaInitData( base::saturated_cast<unsigned int>(init_data.size())); } +void WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated( + scoped_ptr<MediaTracks> tracks) { + // For MSE/chunk_demuxer case the media track updates are handled by + // WebSourceBufferImpl. + DCHECK(demuxer_.get()); + DCHECK(!chunk_demuxer_); +} + void WebMediaPlayerImpl::OnWaitingForDecryptionKey() { encrypted_client_->didBlockPlaybackWaitingForKey(); @@ -1205,8 +1213,13 @@ void WebMediaPlayerImpl::StartPipeline() { DCHECK(data_source_); #if !defined(MEDIA_DISABLE_FFMPEG) + Demuxer::MediaTracksUpdatedCB media_tracks_updated_cb = + base::Bind(&WebMediaPlayerImpl::OnFFmpegMediaTracksUpdated, + base::Unretained(this)); + demuxer_.reset(new FFmpegDemuxer(media_task_runner_, data_source_.get(), - encrypted_media_init_data_cb, media_log_)); + encrypted_media_init_data_cb, + media_tracks_updated_cb, media_log_)); #else OnPipelineError(PipelineStatus::DEMUXER_ERROR_COULD_NOT_OPEN); return; diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index 0283efb..5ae347c 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h @@ -18,6 +18,7 @@ #include "base/memory/weak_ptr.h" #include "base/threading/thread.h" #include "build/build_config.h" +#include "media/base/media_tracks.h" #include "media/base/pipeline_impl.h" #include "media/base/renderer_factory.h" #include "media/base/surface_manager.h" @@ -256,6 +257,11 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl void OnEncryptedMediaInitData(EmeInitDataType init_data_type, const std::vector<uint8_t>& init_data); + // Called when the FFmpegDemuxer encounters new media tracks. This is only + // invoked when using FFmpegDemuxer, since MSE/ChunkDemuxer handle media + // tracks separately in WebSourceBufferImpl. + void OnFFmpegMediaTracksUpdated(scoped_ptr<MediaTracks> tracks); + // Called when a decoder detects that the key needed to decrypt the stream // is not available. void OnWaitingForDecryptionKey(); diff --git a/media/blink/websourcebuffer_impl.cc b/media/blink/websourcebuffer_impl.cc index ea09bde..6b08b131 100644 --- a/media/blink/websourcebuffer_impl.cc +++ b/media/blink/websourcebuffer_impl.cc @@ -46,6 +46,9 @@ WebSourceBufferImpl::WebSourceBufferImpl( client_(NULL), append_window_end_(kInfiniteDuration()) { DCHECK(demuxer_); + demuxer_->SetTracksWatcher( + id, base::Bind(&WebSourceBufferImpl::InitSegmentReceived, + base::Unretained(this))); } WebSourceBufferImpl::~WebSourceBufferImpl() { @@ -99,11 +102,8 @@ void WebSourceBufferImpl::append( unsigned length, double* timestamp_offset) { base::TimeDelta old_offset = timestamp_offset_; - demuxer_->AppendData(id_, data, length, - append_window_start_, append_window_end_, - ×tamp_offset_, - base::Bind(&WebSourceBufferImpl::InitSegmentReceived, - base::Unretained(this))); + demuxer_->AppendData(id_, data, length, append_window_start_, + append_window_end_, ×tamp_offset_); // Coded frame processing may update the timestamp offset. If the caller // provides a non-NULL |timestamp_offset| and frame processing changes the @@ -159,7 +159,7 @@ void WebSourceBufferImpl::removedFromMediaSource() { client_ = NULL; } -void WebSourceBufferImpl::InitSegmentReceived(const MediaTracks& tracks) { +void WebSourceBufferImpl::InitSegmentReceived(scoped_ptr<MediaTracks> tracks) { DVLOG(1) << __FUNCTION__; // TODO(servolk): Implement passing MediaTrack info to blink level. // https://crbug.com/249428 diff --git a/media/blink/websourcebuffer_impl.h b/media/blink/websourcebuffer_impl.h index 1dc54e6..b9b4404 100644 --- a/media/blink/websourcebuffer_impl.h +++ b/media/blink/websourcebuffer_impl.h @@ -11,6 +11,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" +#include "base/memory/scoped_ptr.h" #include "base/time/time.h" #include "third_party/WebKit/public/platform/WebSourceBuffer.h" @@ -43,7 +44,7 @@ class WebSourceBufferImpl : public blink::WebSourceBuffer { private: // Demuxer callback handler to process an initialization segment received // during an append() call. - void InitSegmentReceived(const MediaTracks& tracks); + void InitSegmentReceived(scoped_ptr<MediaTracks> tracks); std::string id_; ChunkDemuxer* demuxer_; // Owned by WebMediaPlayerImpl. diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index e931c3f..40daf24 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -549,6 +549,14 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, return kOk; } +void ChunkDemuxer::SetTracksWatcher( + const std::string& id, + const MediaTracksUpdatedCB& tracks_updated_cb) { + base::AutoLock auto_lock(lock_); + CHECK(IsValidId(id)); + source_state_map_[id]->SetTracksWatcher(tracks_updated_cb); +} + void ChunkDemuxer::RemoveId(const std::string& id) { base::AutoLock auto_lock(lock_); CHECK(IsValidId(id)); @@ -596,19 +604,16 @@ bool ChunkDemuxer::EvictCodedFrames(const std::string& id, return itr->second->EvictCodedFrames(media_time_dts, newDataSize); } -void ChunkDemuxer::AppendData( - const std::string& id, - const uint8_t* data, - size_t length, - TimeDelta append_window_start, - TimeDelta append_window_end, - TimeDelta* timestamp_offset, - const MediaSourceState::InitSegmentReceivedCB& init_segment_received_cb) { +void ChunkDemuxer::AppendData(const std::string& id, + const uint8_t* data, + size_t length, + TimeDelta append_window_start, + TimeDelta append_window_end, + TimeDelta* timestamp_offset) { DVLOG(1) << "AppendData(" << id << ", " << length << ")"; DCHECK(!id.empty()); DCHECK(timestamp_offset); - DCHECK(!init_segment_received_cb.is_null()); Ranges<TimeDelta> ranges; @@ -629,11 +634,9 @@ void ChunkDemuxer::AppendData( case INITIALIZING: case INITIALIZED: DCHECK(IsValidId(id)); - if (!source_state_map_[id]->Append(data, length, - append_window_start, + if (!source_state_map_[id]->Append(data, length, append_window_start, append_window_end, - timestamp_offset, - init_segment_received_cb)) { + timestamp_offset)) { ReportError_Locked(PIPELINE_ERROR_DECODE); return; } diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index 2425412..73d1525 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h @@ -221,6 +221,11 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { Status AddId(const std::string& id, const std::string& type, std::vector<std::string>& codecs); + // Notifies a caller via |tracks_updated_cb| that the set of media tracks + // for a given |id| has changed. + void SetTracksWatcher(const std::string& id, + const MediaTracksUpdatedCB& tracks_updated_cb); + // Removed an ID & associated resources that were previously added with // AddId(). void RemoveId(const std::string& id); @@ -233,16 +238,12 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { // |append_window_start| and |append_window_end| correspond to the MSE spec's // similarly named source buffer attributes that are used in coded frame // processing. - // |init_segment_received_cb| is run for each newly successfully parsed - // initialization segment. - void AppendData( - const std::string& id, - const uint8_t* data, - size_t length, - base::TimeDelta append_window_start, - base::TimeDelta append_window_end, - base::TimeDelta* timestamp_offset, - const MediaSourceState::InitSegmentReceivedCB& init_segment_received_cb); + void AppendData(const std::string& id, + const uint8_t* data, + size_t length, + base::TimeDelta append_window_start, + base::TimeDelta append_window_end, + base::TimeDelta* timestamp_offset); // Aborts parsing the current segment and reset the parser to a state where // it can accept a new segment. diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index bd2a87e..e71751e 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc @@ -263,9 +263,8 @@ class ChunkDemuxerTest : public ::testing::Test { ChunkDemuxerTest() : media_log_(new StrictMock<MockMediaLog>()), append_window_end_for_next_append_(kInfiniteDuration()) { - init_segment_received_cb_ = - base::Bind(&ChunkDemuxerTest::InitSegmentReceived, - base::Unretained(this)); + init_segment_received_cb_ = base::Bind( + &ChunkDemuxerTest::InitSegmentReceivedWrapper, base::Unretained(this)); CreateNewDemuxer(); } @@ -451,7 +450,12 @@ class ChunkDemuxerTest : public ::testing::Test { return AddId(kSourceId, HAS_AUDIO | HAS_VIDEO); } - return demuxer_->AddId(source_id, type, codecs); + ChunkDemuxer::Status status = demuxer_->AddId(source_id, type, codecs); + if (status == ChunkDemuxer::kOk) + demuxer_->SetTracksWatcher( + source_id, base::Bind(&ChunkDemuxerTest::InitSegmentReceivedWrapper, + base::Unretained(this))); + return status; } #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) @@ -460,7 +464,12 @@ class ChunkDemuxerTest : public ::testing::Test { std::string type = "video/mp2t"; codecs.push_back("mp4a.40.2"); codecs.push_back("avc1.640028"); - return demuxer_->AddId(source_id, type, codecs); + ChunkDemuxer::Status status = demuxer_->AddId(source_id, type, codecs); + if (status == ChunkDemuxer::kOk) + demuxer_->SetTracksWatcher( + source_id, base::Bind(&ChunkDemuxerTest::InitSegmentReceivedWrapper, + base::Unretained(this))); + return status; } #endif @@ -715,11 +724,9 @@ class ChunkDemuxerTest : public ::testing::Test { size_t length) { EXPECT_CALL(host_, OnBufferedTimeRangesChanged(_)).Times(AnyNumber()); - demuxer_->AppendData(source_id, data, length, - append_window_start_for_next_append_, - append_window_end_for_next_append_, - ×tamp_offset_map_[source_id], - init_segment_received_cb_); + demuxer_->AppendData( + source_id, data, length, append_window_start_for_next_append_, + append_window_end_for_next_append_, ×tamp_offset_map_[source_id]); } void AppendDataInPieces(const uint8_t* data, size_t length) { @@ -1346,7 +1353,7 @@ class ChunkDemuxerTest : public ::testing::Test { void(EmeInitDataType init_data_type, const std::vector<uint8_t>& init_data)); - MOCK_METHOD1(InitSegmentReceived, void(const MediaTracks&)); + MOCK_METHOD1(InitSegmentReceived, void(scoped_ptr<MediaTracks>&)); void Seek(base::TimeDelta seek_time) { demuxer_->StartWaitingForSeek(seek_time); @@ -1374,7 +1381,7 @@ class ChunkDemuxerTest : public ::testing::Test { scoped_refptr<StrictMock<MockMediaLog>> media_log_; scoped_ptr<ChunkDemuxer> demuxer_; - MediaSourceState::InitSegmentReceivedCB init_segment_received_cb_; + Demuxer::MediaTracksUpdatedCB init_segment_received_cb_; base::TimeDelta append_window_start_for_next_append_; base::TimeDelta append_window_end_for_next_append_; @@ -1383,6 +1390,12 @@ class ChunkDemuxerTest : public ::testing::Test { // operation for that source id. std::map<std::string, base::TimeDelta> timestamp_offset_map_; + public: + // A workaround for gtest mocks not allowing moving scoped_ptrs. + void InitSegmentReceivedWrapper(scoped_ptr<MediaTracks> tracks) { + InitSegmentReceived(tracks); + } + private: DISALLOW_COPY_AND_ASSIGN(ChunkDemuxerTest); }; @@ -1552,8 +1565,7 @@ TEST_F(ChunkDemuxerTest, SingleTextTrackIdChange) { demuxer_->AppendData(kSourceId, info_tracks.get(), info_tracks_size, append_window_start_for_next_append_, append_window_end_for_next_append_, - ×tamp_offset_map_[kSourceId], - init_segment_received_cb_); + ×tamp_offset_map_[kSourceId]); AppendMuxedCluster( MuxedStreamInfo(kAudioTrackNum, "46K 69K", 23), @@ -1746,8 +1758,7 @@ TEST_F(ChunkDemuxerTest, AppendDataBeforeInit) { demuxer_->AppendData(kSourceId, info_tracks.get(), info_tracks_size, append_window_start_for_next_append_, append_window_end_for_next_append_, - ×tamp_offset_map_[kSourceId], - init_segment_received_cb_); + ×tamp_offset_map_[kSourceId]); } // Make sure Read() callbacks are dispatched with the proper data. @@ -1786,8 +1797,7 @@ TEST_F(ChunkDemuxerTest, OutOfOrderClusters) { demuxer_->AppendData(kSourceId, cluster_c->data(), cluster_c->size(), append_window_start_for_next_append_, append_window_end_for_next_append_, - ×tamp_offset_map_[kSourceId], - init_segment_received_cb_); + ×tamp_offset_map_[kSourceId]); } TEST_F(ChunkDemuxerTest, NonMonotonicButAboveClusterTimecode) { @@ -1814,8 +1824,7 @@ TEST_F(ChunkDemuxerTest, NonMonotonicButAboveClusterTimecode) { demuxer_->AppendData(kSourceId, cluster_b->data(), cluster_b->size(), append_window_start_for_next_append_, append_window_end_for_next_append_, - ×tamp_offset_map_[kSourceId], - init_segment_received_cb_); + ×tamp_offset_map_[kSourceId]); } TEST_F(ChunkDemuxerTest, BackwardsAndBeforeClusterTimecode) { @@ -1842,8 +1851,7 @@ TEST_F(ChunkDemuxerTest, BackwardsAndBeforeClusterTimecode) { demuxer_->AppendData(kSourceId, cluster_b->data(), cluster_b->size(), append_window_start_for_next_append_, append_window_end_for_next_append_, - ×tamp_offset_map_[kSourceId], - init_segment_received_cb_); + ×tamp_offset_map_[kSourceId]); } @@ -2332,11 +2340,9 @@ TEST_F(ChunkDemuxerTest, ParseErrorDuringInit) { EXPECT_MEDIA_LOG(StreamParsingFailed()); uint8_t tmp = 0; - demuxer_->AppendData(kSourceId, &tmp, 1, - append_window_start_for_next_append_, + demuxer_->AppendData(kSourceId, &tmp, 1, append_window_start_for_next_append_, append_window_end_for_next_append_, - ×tamp_offset_map_[kSourceId], - init_segment_received_cb_); + ×tamp_offset_map_[kSourceId]); } TEST_F(ChunkDemuxerTest, AVHeadersWithAudioOnlyType) { @@ -2349,6 +2355,9 @@ TEST_F(ChunkDemuxerTest, AVHeadersWithAudioOnlyType) { codecs[0] = "vorbis"; ASSERT_EQ(demuxer_->AddId(kSourceId, "audio/webm", codecs), ChunkDemuxer::kOk); + demuxer_->SetTracksWatcher( + kSourceId, base::Bind(&ChunkDemuxerTest::InitSegmentReceivedWrapper, + base::Unretained(this))); // Video track is unexpected per mimetype. EXPECT_MEDIA_LOG(InitSegmentMismatchesMimeType("a video", true)); @@ -2366,6 +2375,9 @@ TEST_F(ChunkDemuxerTest, AVHeadersWithVideoOnlyType) { codecs[0] = "vp8"; ASSERT_EQ(demuxer_->AddId(kSourceId, "video/webm", codecs), ChunkDemuxer::kOk); + demuxer_->SetTracksWatcher( + kSourceId, base::Bind(&ChunkDemuxerTest::InitSegmentReceivedWrapper, + base::Unretained(this))); // Audio track is unexpected per mimetype. EXPECT_MEDIA_LOG(InitSegmentMismatchesMimeType("an audio", true)); @@ -2383,6 +2395,9 @@ TEST_F(ChunkDemuxerTest, AudioOnlyHeaderWithAVType) { codecs[1] = "vp8"; ASSERT_EQ(demuxer_->AddId(kSourceId, "video/webm", codecs), ChunkDemuxer::kOk); + demuxer_->SetTracksWatcher( + kSourceId, base::Bind(&ChunkDemuxerTest::InitSegmentReceivedWrapper, + base::Unretained(this))); // Video track is also expected per mimetype. EXPECT_MEDIA_LOG(InitSegmentMismatchesMimeType("a video", false)); @@ -2400,6 +2415,9 @@ TEST_F(ChunkDemuxerTest, VideoOnlyHeaderWithAVType) { codecs[1] = "vp8"; ASSERT_EQ(demuxer_->AddId(kSourceId, "video/webm", codecs), ChunkDemuxer::kOk); + demuxer_->SetTracksWatcher( + kSourceId, base::Bind(&ChunkDemuxerTest::InitSegmentReceivedWrapper, + base::Unretained(this))); // Audio track is also expected per mimetype. EXPECT_MEDIA_LOG(InitSegmentMismatchesMimeType("an audio", false)); diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 20adebe..9472e18 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc @@ -740,6 +740,7 @@ FFmpegDemuxer::FFmpegDemuxer( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, DataSource* data_source, const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, + const MediaTracksUpdatedCB& media_tracks_updated_cb, const scoped_refptr<MediaLog>& media_log) : host_(NULL), task_runner_(task_runner), @@ -755,9 +756,11 @@ FFmpegDemuxer::FFmpegDemuxer( text_enabled_(false), duration_known_(false), encrypted_media_init_data_cb_(encrypted_media_init_data_cb), + media_tracks_updated_cb_(media_tracks_updated_cb), weak_factory_(this) { DCHECK(task_runner_.get()); DCHECK(data_source_); + DCHECK(!media_tracks_updated_cb_.is_null()); } FFmpegDemuxer::~FFmpegDemuxer() {} diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h index 9bad5ff..dbaaea2 100644 --- a/media/filters/ffmpeg_demuxer.h +++ b/media/filters/ffmpeg_demuxer.h @@ -190,6 +190,7 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer { FFmpegDemuxer(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, DataSource* data_source, const EncryptedMediaInitDataCB& encrypted_media_init_data_cb, + const MediaTracksUpdatedCB& media_tracks_updated_cb, const scoped_refptr<MediaLog>& media_log); ~FFmpegDemuxer() override; @@ -329,6 +330,8 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer { const EncryptedMediaInitDataCB encrypted_media_init_data_cb_; + const MediaTracksUpdatedCB media_tracks_updated_cb_; + // NOTE: Weak pointers must be invalidated before all other member variables. base::WeakPtrFactory<FFmpegDemuxer> weak_factory_; diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc index a0611e9..a6b82e2 100644 --- a/media/filters/ffmpeg_demuxer_unittest.cc +++ b/media/filters/ffmpeg_demuxer_unittest.cc @@ -17,6 +17,7 @@ #include "base/threading/thread.h" #include "media/base/decrypt_config.h" #include "media/base/media_log.h" +#include "media/base/media_tracks.h" #include "media/base/mock_demuxer_host.h" #include "media/base/test_helpers.h" #include "media/base/timestamp_constants.h" @@ -91,9 +92,12 @@ class FFmpegDemuxerTest : public testing::Test { Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb = base::Bind( &FFmpegDemuxerTest::OnEncryptedMediaInitData, base::Unretained(this)); + Demuxer::MediaTracksUpdatedCB tracks_updated_cb = base::Bind( + &FFmpegDemuxerTest::OnMediaTracksUpdated, base::Unretained(this)); + demuxer_.reset(new FFmpegDemuxer( message_loop_.task_runner(), data_source_.get(), - encrypted_media_init_data_cb, new MediaLog())); + encrypted_media_init_data_cb, tracks_updated_cb, new MediaLog())); } MOCK_METHOD1(CheckPoint, void(int v)); @@ -204,6 +208,8 @@ class FFmpegDemuxerTest : public testing::Test { void(EmeInitDataType init_data_type, const std::vector<uint8_t>& init_data)); + void OnMediaTracksUpdated(scoped_ptr<MediaTracks> tracks) {} + // Accessor to demuxer internals. void set_duration_known(bool duration_known) { demuxer_->duration_known_ = duration_known; diff --git a/media/filters/media_source_state.cc b/media/filters/media_source_state.cc index 8f2f87c..89d488e 100644 --- a/media/filters/media_source_state.cc +++ b/media/filters/media_source_state.cc @@ -145,21 +145,24 @@ void MediaSourceState::SetGroupStartTimestampIfInSequenceMode( frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset); } -bool MediaSourceState::Append( - const uint8_t* data, - size_t length, - TimeDelta append_window_start, - TimeDelta append_window_end, - TimeDelta* timestamp_offset, - const InitSegmentReceivedCB& init_segment_received_cb) { +void MediaSourceState::SetTracksWatcher( + const Demuxer::MediaTracksUpdatedCB& tracks_updated_cb) { + DCHECK(init_segment_received_cb_.is_null()); + init_segment_received_cb_ = tracks_updated_cb; + DCHECK(!init_segment_received_cb_.is_null()); +} + +bool MediaSourceState::Append(const uint8_t* data, + size_t length, + TimeDelta append_window_start, + TimeDelta append_window_end, + TimeDelta* timestamp_offset) { + append_in_progress_ = true; DCHECK(timestamp_offset); DCHECK(!timestamp_offset_during_append_); - DCHECK(!init_segment_received_cb.is_null()); - DCHECK(init_segment_received_cb_.is_null()); append_window_start_during_append_ = append_window_start; append_window_end_during_append_ = append_window_end; timestamp_offset_during_append_ = timestamp_offset; - init_segment_received_cb_ = init_segment_received_cb; // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with // append window and timestamp offset pointer. See http://crbug.com/351454. @@ -172,7 +175,7 @@ bool MediaSourceState::Append( << " append_window_end=" << append_window_end.InSecondsF(); } timestamp_offset_during_append_ = NULL; - init_segment_received_cb_.Reset(); + append_in_progress_ = false; return result; } @@ -480,7 +483,9 @@ bool MediaSourceState::OnNewConfigs( DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video << ", " << audio_config.IsValidConfig() << ", " << video_config.IsValidConfig() << ")"; - DCHECK(!init_segment_received_cb_.is_null()); + // MSE spec allows new configs to be emitted only during Append, but not + // during Flush or parser reset operations. + CHECK(append_in_progress_); if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; @@ -643,8 +648,10 @@ bool MediaSourceState::OnNewConfigs( frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint(); DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); - if (success) - init_segment_received_cb_.Run(*media_tracks_); + if (success) { + DCHECK(!init_segment_received_cb_.is_null()); + init_segment_received_cb_.Run(std::move(media_tracks_)); + } return success; } diff --git a/media/filters/media_source_state.h b/media/filters/media_source_state.h index 1197015..e6878f6 100644 --- a/media/filters/media_source_state.h +++ b/media/filters/media_source_state.h @@ -28,8 +28,6 @@ class MEDIA_EXPORT MediaSourceState { typedef base::Callback<ChunkDemuxerStream*(DemuxerStream::Type)> CreateDemuxerStreamCB; - typedef base::Callback<void(const MediaTracks&)> InitSegmentReceivedCB; - typedef base::Callback<void(ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; @@ -52,14 +50,12 @@ class MEDIA_EXPORT MediaSourceState { // error occurred. |*timestamp_offset| is used and possibly updated by the // append. |append_window_start| and |append_window_end| correspond to the MSE // spec's similarly named source buffer attributes that are used in coded - // frame processing. |init_segment_received_cb| is run for each new fully - // parsed initialization segment. + // frame processing. bool Append(const uint8_t* data, size_t length, TimeDelta append_window_start, TimeDelta append_window_end, - TimeDelta* timestamp_offset, - const InitSegmentReceivedCB& init_segment_received_cb); + TimeDelta* timestamp_offset); // Aborts the current append sequence and resets the parser. void ResetParserState(TimeDelta append_window_start, @@ -117,6 +113,8 @@ class MEDIA_EXPORT MediaSourceState { const RangesList& activeRanges, bool ended); + void SetTracksWatcher(const Demuxer::MediaTracksUpdatedCB& tracks_updated_cb); + private: // Called by the |stream_parser_| when a new initialization segment is // encountered. @@ -195,11 +193,13 @@ class MEDIA_EXPORT MediaSourceState { StreamParser::InitCB init_cb_; // During Append(), OnNewConfigs() will trigger the initialization segment - // received algorithm. This callback is only non-NULL during the lifetime of - // an Append() call. Note, the MSE spec explicitly disallows this algorithm + // received algorithm. Note, the MSE spec explicitly disallows this algorithm // during an Abort(), since Abort() is allowed only to emit coded frames, and - // only if the parser is PARSING_MEDIA_SEGMENT (not an INIT segment). - InitSegmentReceivedCB init_segment_received_cb_; + // only if the parser is PARSING_MEDIA_SEGMENT (not an INIT segment). So we + // also have a flag here that indicates if Append is in progress and we can + // invoke this callback. + Demuxer::MediaTracksUpdatedCB init_segment_received_cb_; + bool append_in_progress_ = false; // Indicates that timestampOffset should be updated automatically during // OnNewBuffers() based on the earliest end timestamp of the buffers provided. diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index 51a845b..9f4deaf 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc @@ -535,9 +535,7 @@ class MockMediaSource { chunk_demuxer_->AppendData( kSourceId, file_data_->data() + current_position_, size, - base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_, - base::Bind(&MockMediaSource::InitSegmentReceived, - base::Unretained(this))); + base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_); current_position_ += size; } @@ -546,9 +544,7 @@ class MockMediaSource { int size) { CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId)); chunk_demuxer_->AppendData(kSourceId, pData, size, base::TimeDelta(), - kInfiniteDuration(), ×tamp_offset, - base::Bind(&MockMediaSource::InitSegmentReceived, - base::Unretained(this))); + kInfiniteDuration(), ×tamp_offset); last_timestamp_offset_ = timestamp_offset; } @@ -559,9 +555,7 @@ class MockMediaSource { int size) { CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId)); chunk_demuxer_->AppendData(kSourceId, pData, size, append_window_start, - append_window_end, ×tamp_offset, - base::Bind(&MockMediaSource::InitSegmentReceived, - base::Unretained(this))); + append_window_end, ×tamp_offset); last_timestamp_offset_ = timestamp_offset; } @@ -622,6 +616,9 @@ class MockMediaSource { } CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk); + chunk_demuxer_->SetTracksWatcher( + kSourceId, base::Bind(&MockMediaSource::InitSegmentReceivedWrapper, + base::Unretained(this))); AppendData(initial_append_size_); } @@ -637,7 +634,12 @@ class MockMediaSource { return last_timestamp_offset_; } - MOCK_METHOD1(InitSegmentReceived, void(const MediaTracks&)); + // A workaround for gtest mocks not allowing moving scoped_ptrs. + void InitSegmentReceivedWrapper(scoped_ptr<MediaTracks> tracks) { + InitSegmentReceived(tracks); + } + + MOCK_METHOD1(InitSegmentReceived, void(scoped_ptr<MediaTracks>&)); private: scoped_refptr<DecoderBuffer> file_data_; diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc index dbaa37c..17647ba 100644 --- a/media/test/pipeline_integration_test_base.cc +++ b/media/test/pipeline_integration_test_base.cc @@ -10,6 +10,7 @@ #include "base/memory/scoped_vector.h" #include "media/base/cdm_context.h" #include "media/base/media_log.h" +#include "media/base/media_tracks.h" #include "media/base/test_data_util.h" #include "media/filters/chunk_demuxer.h" #if !defined(MEDIA_DISABLE_FFMPEG) @@ -79,6 +80,11 @@ void PipelineIntegrationTestBase::DemuxerEncryptedMediaInitDataCB( encrypted_media_init_data_cb_.Run(type, init_data); } +void PipelineIntegrationTestBase::DemuxerMediaTracksUpdatedCB( + scoped_ptr<MediaTracks> tracks) { + CHECK(tracks); +} + void PipelineIntegrationTestBase::OnEnded() { DCHECK(!ended_); ended_ = true; @@ -267,12 +273,16 @@ void PipelineIntegrationTestBase::CreateDemuxer( scoped_ptr<DataSource> data_source) { data_source_ = std::move(data_source); + Demuxer::MediaTracksUpdatedCB tracks_updated_cb = + base::Bind(&PipelineIntegrationTestBase::DemuxerMediaTracksUpdatedCB, + base::Unretained(this)); + #if !defined(MEDIA_DISABLE_FFMPEG) demuxer_ = scoped_ptr<Demuxer>(new FFmpegDemuxer( message_loop_.task_runner(), data_source_.get(), base::Bind(&PipelineIntegrationTestBase::DemuxerEncryptedMediaInitDataCB, base::Unretained(this)), - new MediaLog())); + tracks_updated_cb, new MediaLog())); #endif } diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h index 2cbbdea..8230489 100644 --- a/media/test/pipeline_integration_test_base.h +++ b/media/test/pipeline_integration_test_base.h @@ -148,6 +148,8 @@ class PipelineIntegrationTestBase { void DemuxerEncryptedMediaInitDataCB(EmeInitDataType type, const std::vector<uint8_t>& init_data); + void DemuxerMediaTracksUpdatedCB(scoped_ptr<MediaTracks> tracks); + void OnEnded(); void OnError(PipelineStatus status); void QuitAfterCurrentTimeTask(const base::TimeDelta& quit_time); |