summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorservolk <servolk@chromium.org>2016-03-04 19:29:15 -0800
committerCommit bot <commit-bot@chromium.org>2016-03-05 03:30:48 +0000
commit81e01e07b928180ce12b0229dbb7ca0e157984d2 (patch)
tree2e70dc23dfe29eef339ae15f488df01376d45bfa
parentebeddadd639d34653036db5c29246cea272c9920 (diff)
downloadchromium_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.cc7
-rw-r--r--media/base/demuxer.h6
-rw-r--r--media/base/demuxer_perftest.cc10
-rw-r--r--media/blink/webmediaplayer_impl.cc15
-rw-r--r--media/blink/webmediaplayer_impl.h6
-rw-r--r--media/blink/websourcebuffer_impl.cc12
-rw-r--r--media/blink/websourcebuffer_impl.h3
-rw-r--r--media/filters/chunk_demuxer.cc29
-rw-r--r--media/filters/chunk_demuxer.h21
-rw-r--r--media/filters/chunk_demuxer_unittest.cc70
-rw-r--r--media/filters/ffmpeg_demuxer.cc3
-rw-r--r--media/filters/ffmpeg_demuxer.h3
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc8
-rw-r--r--media/filters/media_source_state.cc35
-rw-r--r--media/filters/media_source_state.h20
-rw-r--r--media/test/pipeline_integration_test.cc22
-rw-r--r--media/test/pipeline_integration_test_base.cc12
-rw-r--r--media/test/pipeline_integration_test_base.h2
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_,
- &timestamp_offset_,
- base::Bind(&WebSourceBufferImpl::InitSegmentReceived,
- base::Unretained(this)));
+ demuxer_->AppendData(id_, data, length, append_window_start_,
+ append_window_end_, &timestamp_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_,
- &timestamp_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_, &timestamp_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_,
- &timestamp_offset_map_[kSourceId],
- init_segment_received_cb_);
+ &timestamp_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_,
- &timestamp_offset_map_[kSourceId],
- init_segment_received_cb_);
+ &timestamp_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_,
- &timestamp_offset_map_[kSourceId],
- init_segment_received_cb_);
+ &timestamp_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_,
- &timestamp_offset_map_[kSourceId],
- init_segment_received_cb_);
+ &timestamp_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_,
- &timestamp_offset_map_[kSourceId],
- init_segment_received_cb_);
+ &timestamp_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_,
- &timestamp_offset_map_[kSourceId],
- init_segment_received_cb_);
+ &timestamp_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(), &timestamp_offset,
- base::Bind(&MockMediaSource::InitSegmentReceived,
- base::Unretained(this)));
+ kInfiniteDuration(), &timestamp_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, &timestamp_offset,
- base::Bind(&MockMediaSource::InitSegmentReceived,
- base::Unretained(this)));
+ append_window_end, &timestamp_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);