diff options
author | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-11 15:15:28 +0000 |
---|---|---|
committer | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-11 15:15:28 +0000 |
commit | e563a9456c981eb07c4bae91eb39b5de3c339900 (patch) | |
tree | fe53b471041856090a8882d27563070cd35aad17 /media | |
parent | b248ecdda188dd6341c941c76b386d73fca7498e (diff) | |
download | chromium_src-e563a9456c981eb07c4bae91eb39b5de3c339900.zip chromium_src-e563a9456c981eb07c4bae91eb39b5de3c339900.tar.gz chromium_src-e563a9456c981eb07c4bae91eb39b5de3c339900.tar.bz2 |
Refactor ChunkDemuxer initialization so INFO & TRACKS elements are passed via appendData().
BUG=86536
TEST=ChunkDemuxerTest.*
Review URL: http://codereview.chromium.org/7329026
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92011 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/filters/chunk_demuxer.cc | 133 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.h | 22 | ||||
-rw-r--r-- | media/filters/chunk_demuxer_factory.cc | 139 | ||||
-rw-r--r-- | media/filters/chunk_demuxer_factory.h | 9 | ||||
-rw-r--r-- | media/filters/chunk_demuxer_unittest.cc | 76 |
5 files changed, 186 insertions, 193 deletions
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 67877de..eb8412d 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -283,53 +283,20 @@ ChunkDemuxer::~ChunkDemuxer() { format_context_ = NULL; } -bool ChunkDemuxer::Init(const uint8* data, int size) { - DCHECK(data); - DCHECK_GT(size, 0); - +void ChunkDemuxer::Init(PipelineStatusCB cb) { base::AutoLock auto_lock(lock_); DCHECK_EQ(state_, WAITING_FOR_INIT); - const uint8* cur = data; - int cur_size = size; - WebMInfoParser info_parser; - int res = info_parser.Parse(cur, cur_size); - - if (res <= 0) { - ChangeState(INIT_ERROR); - return false; - } - - cur += res; - cur_size -= res; - - WebMTracksParser tracks_parser(info_parser.timecode_scale()); - res = tracks_parser.Parse(cur, cur_size); + ChangeState(INITIALIZING); + init_cb_ = cb; - if (res <= 0) { - ChangeState(INIT_ERROR); - return false; - } - - double mult = info_parser.timecode_scale() / 1000.0; - duration_ = base::TimeDelta::FromMicroseconds(info_parser.duration() * mult); - - cluster_parser_.reset(new WebMClusterParser( - info_parser.timecode_scale(), - tracks_parser.audio_track_num(), - tracks_parser.audio_default_duration(), - tracks_parser.video_track_num(), - tracks_parser.video_default_duration())); + if (pending_buffers_.empty()) + return; - format_context_ = CreateFormatContext(data, size); + scoped_refptr<Buffer> buf = pending_buffers_.front(); + pending_buffers_.pop_front(); - if (!format_context_ || !SetupStreams() || !ParsePendingBuffers()) { - ChangeState(INIT_ERROR); - return false; - } - - ChangeState(INITIALIZED); - return true; + ParseInfoAndTracks_Locked(buf->GetData(), buf->GetDataSize()); } // Filter implementation. @@ -353,6 +320,7 @@ void ChunkDemuxer::Seek(base::TimeDelta time, const FilterStatusCB& cb) { base::AutoLock auto_lock(lock_); if (seek_waits_for_data_) { + VLOG(1) << "Seek() : waiting for more data to arrive."; seek_cb_ = cb; return; } @@ -398,8 +366,8 @@ void ChunkDemuxer::FlushData() { seek_waits_for_data_ = true; } -bool ChunkDemuxer::AddData(const uint8* data, unsigned length) { - VLOG(1) << "AddData(" << length << ")"; +bool ChunkDemuxer::AppendData(const uint8* data, unsigned length) { + VLOG(1) << "AppendData(" << length << ")"; DCHECK(data); DCHECK_GT(length, 0u); @@ -416,16 +384,24 @@ bool ChunkDemuxer::AddData(const uint8* data, unsigned length) { return true; break; + case INITIALIZING: + if (!ParseInfoAndTracks_Locked(data, length)) { + VLOG(1) << "AppendData(): parsing info & tracks failed"; + return false; + } + return true; + break; + case INITIALIZED: - if (!ParseAndAddData_Locked(data, length)) { - VLOG(1) << "AddData(): parsing data failed"; + if (!ParseAndAppendData_Locked(data, length)) { + VLOG(1) << "AppendData(): parsing data failed"; return false; } break; case INIT_ERROR: case SHUTDOWN: - VLOG(1) << "AddData(): called in unexpected state " << state_; + VLOG(1) << "AppendData(): called in unexpected state " << state_; return false; break; } @@ -491,6 +467,56 @@ void ChunkDemuxer::ChangeState(State new_state) { state_ = new_state; } +bool ChunkDemuxer::ParseInfoAndTracks_Locked(const uint8* data, int size) { + DCHECK(data); + DCHECK_GT(size, 0); + + DCHECK_EQ(state_, INITIALIZING); + + const uint8* cur = data; + int cur_size = size; + WebMInfoParser info_parser; + int res = info_parser.Parse(cur, cur_size); + + if (res <= 0) { + InitFailed_Locked(); + return false; + } + + cur += res; + cur_size -= res; + + WebMTracksParser tracks_parser(info_parser.timecode_scale()); + res = tracks_parser.Parse(cur, cur_size); + + if (res <= 0) { + InitFailed_Locked(); + return false; + } + + double mult = info_parser.timecode_scale() / 1000.0; + duration_ = base::TimeDelta::FromMicroseconds(info_parser.duration() * mult); + + cluster_parser_.reset(new WebMClusterParser( + info_parser.timecode_scale(), + tracks_parser.audio_track_num(), + tracks_parser.audio_default_duration(), + tracks_parser.video_track_num(), + tracks_parser.video_default_duration())); + + format_context_ = CreateFormatContext(data, size); + + if (!format_context_ || !SetupStreams() || !ParsePendingBuffers_Locked()) { + InitFailed_Locked(); + return false; + } + + ChangeState(INITIALIZED); + init_cb_.Run(PIPELINE_OK); + init_cb_.Reset(); + return true; +} + AVFormatContext* ChunkDemuxer::CreateFormatContext(const uint8* data, int size) const { int segment_size = size + sizeof(kEmptyCluster); @@ -556,7 +582,7 @@ bool ChunkDemuxer::SetupStreams() { return !no_supported_streams; } -bool ChunkDemuxer::ParsePendingBuffers() { +bool ChunkDemuxer::ParsePendingBuffers_Locked() { bool had_pending_buffers = !pending_buffers_.empty(); // Handle any buffers that came in between the time the pipeline was // started and Init() was called. @@ -564,7 +590,7 @@ bool ChunkDemuxer::ParsePendingBuffers() { scoped_refptr<media::Buffer> buf = pending_buffers_.front(); pending_buffers_.pop_front(); - if (!ParseAndAddData_Locked(buf->GetData(), buf->GetDataSize())) { + if (!ParseAndAppendData_Locked(buf->GetData(), buf->GetDataSize())) { pending_buffers_.clear(); ChangeState(INIT_ERROR); return false; @@ -575,7 +601,7 @@ bool ChunkDemuxer::ParsePendingBuffers() { return true; } -bool ChunkDemuxer::ParseAndAddData_Locked(const uint8* data, int length) { +bool ChunkDemuxer::ParseAndAppendData_Locked(const uint8* data, int length) { if (!cluster_parser_.get()) return false; @@ -586,7 +612,7 @@ bool ChunkDemuxer::ParseAndAddData_Locked(const uint8* data, int length) { int res = cluster_parser_->Parse(cur, cur_size); if (res <= 0) { - VLOG(1) << "ParseAndAddData_Locked() : cluster parsing failed."; + VLOG(1) << "ParseAndAppendData_Locked() : cluster parsing failed."; return false; } @@ -616,4 +642,11 @@ bool ChunkDemuxer::ParseAndAddData_Locked(const uint8* data, int length) { return true; } +void ChunkDemuxer::InitFailed_Locked() { + ChangeState(INIT_ERROR); + PipelineStatusCB cb; + std::swap(cb, init_cb_); + cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); +} + } // namespace media diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index 7f599e6..8013c4f 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h @@ -24,7 +24,7 @@ class ChunkDemuxer : public Demuxer { ChunkDemuxer(); virtual ~ChunkDemuxer(); - bool Init(const uint8* data, int size); + void Init(PipelineStatusCB cb); // Filter implementation. virtual void set_host(FilterHost* filter_host); @@ -39,12 +39,13 @@ class ChunkDemuxer : public Demuxer { // Methods used by MediaDataSink void FlushData(); - bool AddData(const uint8* data, unsigned length); + bool AppendData(const uint8* data, unsigned length); void Shutdown(); private: enum State { WAITING_FOR_INIT, + INITIALIZING, INITIALIZED, INIT_ERROR, SHUTDOWN, @@ -52,6 +53,11 @@ class ChunkDemuxer : public Demuxer { void ChangeState(State new_state); + // Parses a buffer that contains an INFO & TRACKS element. Returns false if + // the parse fails. This method handles calling & clearing |init_cb_| + // before it returns. + bool ParseInfoAndTracks_Locked(const uint8* data, int size); + // Generates an AVFormatContext for the INFO & TRACKS elements contained // in |data|. Returns NULL if parsing |data| fails. AVFormatContext* CreateFormatContext(const uint8* data, int size) const; @@ -63,15 +69,19 @@ class ChunkDemuxer : public Demuxer { // Parse all the buffers in |pending_buffers_|. Returns false if parsing one // of the buffers fails. - bool ParsePendingBuffers(); + bool ParsePendingBuffers_Locked(); + + // Parse a buffer that was passed to AppendData(). |data| is expected to + // contain one or more WebM Clusters. Returns false if parsing the data fails. + bool ParseAndAppendData_Locked(const uint8* data, int length); - // Parse a buffer that was passed to AddData(). |data| is expected to contain - // one or more WebM Clusters. Returns false if parsing the data fails. - bool ParseAndAddData_Locked(const uint8* data, int length); + // Called when initialization fails. Handles calling & clearing init_cb_. + void InitFailed_Locked(); base::Lock lock_; State state_; + PipelineStatusCB init_cb_; FilterStatusCB seek_cb_; scoped_refptr<ChunkDemuxerStream> audio_; diff --git a/media/filters/chunk_demuxer_factory.cc b/media/filters/chunk_demuxer_factory.cc index 4cb81ce..a354b39 100644 --- a/media/filters/chunk_demuxer_factory.cc +++ b/media/filters/chunk_demuxer_factory.cc @@ -4,11 +4,32 @@ #include "media/filters/chunk_demuxer_factory.h" +#include "base/bind.h" #include "base/message_loop.h" #include "media/filters/chunk_demuxer.h" namespace media { +static void DoInitDone(DemuxerFactory::BuildCallback* cb, + const scoped_refptr<Demuxer>& demuxer, + PipelineStatus status) { + scoped_ptr<DemuxerFactory::BuildCallback> callback(cb); + if (status != PIPELINE_OK) { + callback->Run(status, static_cast<Demuxer*>(NULL)); + return; + } + + callback->Run(status, demuxer); +} + +static void InitDone(MessageLoop* message_loop, + DemuxerFactory::BuildCallback* cb, + const scoped_refptr<Demuxer>& demuxer, + PipelineStatus status) { + message_loop->PostTask(FROM_HERE, + NewRunnableFunction(&DoInitDone, cb, demuxer, status)); +} + MediaDataSink::MediaDataSink(const scoped_refptr<ChunkDemuxer>& demuxer) : demuxer_(demuxer) { } @@ -19,8 +40,8 @@ void MediaDataSink::Flush() { demuxer_->FlushData(); } -bool MediaDataSink::AddData(const uint8* data, unsigned length) { - return demuxer_->AddData(data, length); +bool MediaDataSink::AppendData(const uint8* data, unsigned length) { + return demuxer_->AppendData(data, length); } void MediaDataSink::Shutdown() { @@ -29,107 +50,7 @@ void MediaDataSink::Shutdown() { const char ChunkDemuxerFactory::kURLPrefix[] = "x-media-chunks:"; -class ChunkDemuxerFactory::BuildState - : public base::RefCountedThreadSafe<BuildState> { - public: - static const int64 kMaxInfoSize = 32678; - - BuildState(const std::string& url, BuildCallback* cb, - const scoped_refptr<ChunkDemuxer>& demuxer) - : url_(url), - cb_(cb), - demuxer_(demuxer), - read_buffer_(NULL), - message_loop_(MessageLoop::current()) { - AddRef(); - } - - virtual ~BuildState() {} - - void OnBuildDone(PipelineStatus status, DataSource* data_source) { - message_loop_->PostTask( - FROM_HERE, - NewRunnableMethod(this, &BuildState::DoBuildDone, - status, scoped_refptr<DataSource>(data_source))); - } - - void DoBuildDone(PipelineStatus status, DataSource* data_source) { - if (status != PIPELINE_OK) { - cb_->Run(status, static_cast<Demuxer*>(NULL)); - Release(); - return; - } - - data_source_ = data_source; - - int64 size = 0; - - if (!data_source_->GetSize(&size) || size >= kMaxInfoSize) { - RunCallbackAndStop(DEMUXER_ERROR_COULD_NOT_OPEN); - return; - } - - DCHECK(!read_buffer_.get()); - read_buffer_.reset(new uint8[size]); - data_source_->Read(0, size, read_buffer_.get(), - NewCallback(this, &BuildState::OnReadDone)); - } - - void OnReadDone(size_t size) { - message_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, - &BuildState::DoReadDone, - size)); - } - - void DoReadDone(size_t size) { - if (size == DataSource::kReadError) { - RunCallbackAndStop(PIPELINE_ERROR_READ); - return; - } - - if (!demuxer_->Init(read_buffer_.get(), size)) { - RunCallbackAndStop(DEMUXER_ERROR_COULD_NOT_OPEN); - return; - } - - RunCallbackAndStop(PIPELINE_OK); - } - - void RunCallbackAndStop(PipelineStatus status) { - scoped_refptr<Demuxer> demuxer; - - if (status == PIPELINE_OK) - demuxer = demuxer_.get(); - - cb_->Run(status, demuxer.get()); - data_source_->Stop(NewCallback(this, &BuildState::OnStopDone)); - } - - void OnStopDone() { - message_loop_->PostTask(FROM_HERE, - NewRunnableMethod(this, - &BuildState::DoStopDone)); - } - - void DoStopDone() { Release(); } - - private: - std::string url_; - scoped_ptr<BuildCallback> cb_; - scoped_refptr<ChunkDemuxer> demuxer_; - - scoped_refptr<DataSource> data_source_; - scoped_array<uint8> read_buffer_; - MessageLoop* message_loop_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(BuildState); -}; - -ChunkDemuxerFactory::ChunkDemuxerFactory( - DataSourceFactory* data_source_factory) - : data_source_factory_(data_source_factory) { -} +ChunkDemuxerFactory::ChunkDemuxerFactory() {} ChunkDemuxerFactory::~ChunkDemuxerFactory() {} @@ -149,17 +70,15 @@ void ChunkDemuxerFactory::Build(const std::string& url, BuildCallback* cb) { return; } - std::string info_url = url.substr(strlen(kURLPrefix)); - - data_source_factory_->Build( - info_url, - NewCallback(new BuildState(info_url, cb, demuxer_), - &ChunkDemuxerFactory::BuildState::OnBuildDone)); + // Call Init() on demuxer. Note that ownership is being passed to the + // callback here. + demuxer_->Init(base::Bind(&InitDone, MessageLoop::current(), cb, + scoped_refptr<Demuxer>(demuxer_.get()))); demuxer_ = NULL; } DemuxerFactory* ChunkDemuxerFactory::Clone() const { - return new ChunkDemuxerFactory(data_source_factory_->Clone()); + return new ChunkDemuxerFactory(); } } // namespace media diff --git a/media/filters/chunk_demuxer_factory.h b/media/filters/chunk_demuxer_factory.h index df6f742..614820e 100644 --- a/media/filters/chunk_demuxer_factory.h +++ b/media/filters/chunk_demuxer_factory.h @@ -32,7 +32,7 @@ class MediaDataSink { void Flush(); // Sends media data to the demuxer. Returns true if the data is valid. - bool AddData(const uint8* data, unsigned length); + bool AppendData(const uint8* data, unsigned length); // Signals that playback is shutting down and further AddData() calls // should fail. This also cancels pending Read()s on DemuxerStreams. @@ -46,7 +46,7 @@ class MediaDataSink { class ChunkDemuxerFactory : public DemuxerFactory { public: // Takes a reference to |demuxer_factory|. - ChunkDemuxerFactory(DataSourceFactory* data_source_factory); + ChunkDemuxerFactory(); virtual ~ChunkDemuxerFactory(); bool IsUrlSupported(const std::string& url) const; @@ -58,12 +58,9 @@ class ChunkDemuxerFactory : public DemuxerFactory { private: static const char kURLPrefix[]; - class BuildState; - - scoped_ptr<DataSourceFactory> data_source_factory_; scoped_refptr<ChunkDemuxer> demuxer_; - DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerFactory); + DISALLOW_COPY_AND_ASSIGN(ChunkDemuxerFactory); }; } // namespace media diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index 83795e5..695cee3 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc @@ -134,7 +134,7 @@ class ChunkDemuxerTest : public testing::Test{ } } - void InitDemuxer(bool has_audio, bool has_video) { + void AppendInfoTracks(bool has_audio, bool has_video) { EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0))); @@ -153,8 +153,27 @@ class ChunkDemuxerTest : public testing::Test{ SetupAVFormatContext(has_audio, has_video); - EXPECT_EQ(demuxer_->Init(info_tracks.get(), info_tracks_size), - has_audio || has_video); + demuxer_->AppendData(info_tracks.get(), info_tracks_size); + } + + static void InitDoneCalled(bool* was_called, PipelineStatus expectedStatus, + PipelineStatus status) { + EXPECT_EQ(status, expectedStatus); + *was_called = true; + } + + void InitDemuxer(bool has_audio, bool has_video) { + bool init_done_called = false; + PipelineStatus expectedStatus = + (has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN; + demuxer_->Init(base::Bind(&ChunkDemuxerTest::InitDoneCalled, + &init_done_called, expectedStatus)); + + EXPECT_FALSE(init_done_called); + + AppendInfoTracks(has_audio, has_video); + + EXPECT_TRUE(init_done_called); } void ShutdownDemuxer() { @@ -240,7 +259,7 @@ TEST_F(ChunkDemuxerTest, TestShutdownBeforeFirstSeekCompletes) { // Test that Seek() completes successfully when the first cluster // arrives. -TEST_F(ChunkDemuxerTest, TestAddDataAfterSeek) { +TEST_F(ChunkDemuxerTest, TestAppendDataAfterSeek) { InitDemuxer(true, true); InSequence s; @@ -259,23 +278,25 @@ TEST_F(ChunkDemuxerTest, TestAddDataAfterSeek) { Checkpoint(1); - EXPECT_TRUE(demuxer_->AddData(cluster->data(), cluster->size())); + EXPECT_TRUE(demuxer_->AppendData(cluster->data(), cluster->size())); Checkpoint(2); } -// Test the case where AddData() is called before Init(). This can happen +// Test the case where AppendData() is called before Init(). This can happen // when JavaScript starts sending data before the pipeline is completely // initialized. -TEST_F(ChunkDemuxerTest, TestAddDataBeforeInit) { +TEST_F(ChunkDemuxerTest, TestAppendDataBeforeInit) { + AppendInfoTracks(true, true); + ClusterBuilder cb; cb.SetClusterTimecode(0); AddSimpleBlock(&cb, kVideoTrackNum, 0); scoped_ptr<Cluster> cluster(cb.Finish()); - EXPECT_TRUE(demuxer_->AddData(cluster->data(), cluster->size())); + EXPECT_TRUE(demuxer_->AppendData(cluster->data(), cluster->size())); - InitDemuxer(true, true); + demuxer_->Init(NewExpectedStatusCB(PIPELINE_OK)); demuxer_->Seek(base::TimeDelta::FromSeconds(0), NewExpectedStatusCB(PIPELINE_OK)); @@ -313,7 +334,7 @@ TEST_F(ChunkDemuxerTest, TestRead) { AddSimpleBlock(&cb, kVideoTrackNum, 123); scoped_ptr<Cluster> cluster(cb.Finish()); - EXPECT_TRUE(demuxer_->AddData(cluster->data(), cluster->size())); + EXPECT_TRUE(demuxer_->AppendData(cluster->data(), cluster->size())); EXPECT_TRUE(audio_read_done); EXPECT_TRUE(video_read_done); @@ -331,7 +352,7 @@ TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) { AddSimpleBlock(&cb, kVideoTrackNum, 43); scoped_ptr<Cluster> clusterA(cb.Finish()); - EXPECT_TRUE(demuxer_->AddData(clusterA->data(), clusterA->size())); + EXPECT_TRUE(demuxer_->AppendData(clusterA->data(), clusterA->size())); // Cluster B starts before clusterA and has data // that overlaps. @@ -342,9 +363,9 @@ TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) { AddSimpleBlock(&cb, kVideoTrackNum, 40); scoped_ptr<Cluster> clusterB(cb.Finish()); - // Make sure that AddData() fails because this cluster data + // Make sure that AppendData() fails because this cluster data // is before previous data. - EXPECT_FALSE(demuxer_->AddData(clusterB->data(), clusterB->size())); + EXPECT_FALSE(demuxer_->AppendData(clusterB->data(), clusterB->size())); // Cluster C starts after clusterA. cb.SetClusterTimecode(56); @@ -355,15 +376,15 @@ TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) { scoped_ptr<Cluster> clusterC(cb.Finish()); // Verify that clusterC is accepted. - EXPECT_TRUE(demuxer_->AddData(clusterC->data(), clusterC->size())); + EXPECT_TRUE(demuxer_->AppendData(clusterC->data(), clusterC->size())); // Flush and try clusterB again. demuxer_->FlushData(); - EXPECT_TRUE(demuxer_->AddData(clusterB->data(), clusterB->size())); + EXPECT_TRUE(demuxer_->AppendData(clusterB->data(), clusterB->size())); // Following that with clusterC should work too since it doesn't // overlap with clusterB. - EXPECT_TRUE(demuxer_->AddData(clusterC->data(), clusterC->size())); + EXPECT_TRUE(demuxer_->AppendData(clusterC->data(), clusterC->size())); } TEST_F(ChunkDemuxerTest, TestInvalidBlockSequences) { @@ -380,7 +401,7 @@ TEST_F(ChunkDemuxerTest, TestInvalidBlockSequences) { AddSimpleBlock(&cb, kVideoTrackNum, 15); scoped_ptr<Cluster> clusterA(cb.Finish()); - EXPECT_FALSE(demuxer_->AddData(clusterA->data(), clusterA->size())); + EXPECT_FALSE(demuxer_->AppendData(clusterA->data(), clusterA->size())); // Test timecodes going backwards before cluster timecode. cb.SetClusterTimecode(5); @@ -390,7 +411,7 @@ TEST_F(ChunkDemuxerTest, TestInvalidBlockSequences) { AddSimpleBlock(&cb, kVideoTrackNum, 3); scoped_ptr<Cluster> clusterB(cb.Finish()); - EXPECT_FALSE(demuxer_->AddData(clusterB->data(), clusterB->size())); + EXPECT_FALSE(demuxer_->AppendData(clusterB->data(), clusterB->size())); // Test strict monotonic increasing timestamps on a per stream // basis. @@ -401,7 +422,7 @@ TEST_F(ChunkDemuxerTest, TestInvalidBlockSequences) { AddSimpleBlock(&cb, kVideoTrackNum, 7); scoped_ptr<Cluster> clusterC(cb.Finish()); - EXPECT_FALSE(demuxer_->AddData(clusterC->data(), clusterC->size())); + EXPECT_FALSE(demuxer_->AppendData(clusterC->data(), clusterC->size())); // Test strict monotonic increasing timestamps on a per stream // basis across clusters. @@ -410,14 +431,27 @@ TEST_F(ChunkDemuxerTest, TestInvalidBlockSequences) { AddSimpleBlock(&cb, kVideoTrackNum, 5); scoped_ptr<Cluster> clusterD(cb.Finish()); - EXPECT_TRUE(demuxer_->AddData(clusterD->data(), clusterD->size())); + EXPECT_TRUE(demuxer_->AppendData(clusterD->data(), clusterD->size())); cb.SetClusterTimecode(5); AddSimpleBlock(&cb, kAudioTrackNum, 5); AddSimpleBlock(&cb, kVideoTrackNum, 7); scoped_ptr<Cluster> clusterE(cb.Finish()); - EXPECT_FALSE(demuxer_->AddData(clusterE->data(), clusterE->size())); + EXPECT_FALSE(demuxer_->AppendData(clusterE->data(), clusterE->size())); +} + +// Test the case where a cluster is passed to AppendData() before +// INFO & TRACKS data. +TEST_F(ChunkDemuxerTest, TestClusterBeforeInfoTracks) { + demuxer_->Init(NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); + + ClusterBuilder cb; + cb.SetClusterTimecode(0); + AddSimpleBlock(&cb, kVideoTrackNum, 0); + scoped_ptr<Cluster> cluster(cb.Finish()); + + EXPECT_FALSE(demuxer_->AppendData(cluster->data(), cluster->size())); } } // namespace media |