summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authoracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-21 15:55:50 +0000
committeracolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-21 15:55:50 +0000
commit81bb33281c4924303a6408b08187cc63608f87ac (patch)
tree5647f3661b1afd6d0ed4157eb9841ccdef1a28e9 /media
parent44531dd1760538f33f7b6d41f5754a2dd3b732f3 (diff)
downloadchromium_src-81bb33281c4924303a6408b08187cc63608f87ac.zip
chromium_src-81bb33281c4924303a6408b08187cc63608f87ac.tar.gz
chromium_src-81bb33281c4924303a6408b08187cc63608f87ac.tar.bz2
End of stream logic implemented & removed the need for pending_buffers_.
BUG=86536 TEST=ChunkDemuxerTest.* Review URL: http://codereview.chromium.org/7401029 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93405 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/filters/chunk_demuxer.cc138
-rw-r--r--media/filters/chunk_demuxer.h16
-rw-r--r--media/filters/chunk_demuxer_client.h26
-rw-r--r--media/filters/chunk_demuxer_factory.cc51
-rw-r--r--media/filters/chunk_demuxer_factory.h52
-rw-r--r--media/filters/chunk_demuxer_unittest.cc55
-rw-r--r--media/media.gyp1
7 files changed, 184 insertions, 155 deletions
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index c404408..ea50ba4 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -14,6 +14,7 @@
#include "media/base/filter_host.h"
#include "media/base/data_buffer.h"
#include "media/ffmpeg/ffmpeg_common.h"
+#include "media/filters/chunk_demuxer_client.h"
#include "media/filters/ffmpeg_glue.h"
#include "media/filters/in_memory_url_protocol.h"
#include "media/webm/webm_cluster_parser.h"
@@ -53,11 +54,8 @@ static const uint8 kEmptyCluster[] = {
0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0)
};
-static Buffer* CreateBuffer(const uint8* data, size_t size) {
- scoped_array<uint8> buf(new uint8[size]);
- memcpy(buf.get(), data, size);
- return new DataBuffer(buf.release(), size);
-}
+// Create an "end of stream" buffer.
+static Buffer* CreateEOSBuffer() { return new DataBuffer(0, 0); }
class ChunkDemuxerStream : public DemuxerStream {
public:
@@ -142,13 +140,15 @@ void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) {
for (BufferQueue::const_iterator itr = buffers.begin();
itr != buffers.end(); itr++) {
- base::TimeDelta current_ts = (*itr)->GetTimestamp();
- if (last_buffer_timestamp_ != kNoTimestamp) {
- DCHECK_GT(current_ts.ToInternalValue(),
- last_buffer_timestamp_.ToInternalValue());
- }
+ if (!(*itr)->IsEndOfStream()) {
+ base::TimeDelta current_ts = (*itr)->GetTimestamp();
+ if (last_buffer_timestamp_ != kNoTimestamp) {
+ DCHECK_GT(current_ts.ToInternalValue(),
+ last_buffer_timestamp_.ToInternalValue());
+ }
- last_buffer_timestamp_ = current_ts;
+ last_buffer_timestamp_ = current_ts;
+ }
buffers_.push_back(*itr);
}
@@ -181,9 +181,10 @@ void ChunkDemuxerStream::Shutdown() {
}
}
- // Pass NULL to all callbacks to signify read failure.
+ // Pass end of stream buffers to all callbacks to signal that no more data
+ // will be sent.
while (!callbacks.empty()) {
- callbacks.front().Run(NULL);
+ callbacks.front().Run(CreateEOSBuffer());
callbacks.pop_front();
}
}
@@ -229,7 +230,9 @@ void ChunkDemuxerStream::Read(const ReadCallback& read_callback) {
{
base::AutoLock auto_lock(lock_);
- if (!shutdown_called_) {
+ if (shutdown_called_) {
+ buffer = CreateEOSBuffer();
+ } else {
if (buffers_.empty()) {
// Wrap & store |read_callback| so that it will
// get called on the current MessageLoop.
@@ -253,6 +256,7 @@ void ChunkDemuxerStream::Read(const ReadCallback& read_callback) {
}
}
+ DCHECK(buffer.get());
read_callback.Run(buffer);
}
@@ -262,11 +266,13 @@ void ChunkDemuxerStream::EnableBitstreamConverter() {}
AVStream* ChunkDemuxerStream::GetAVStream() { return av_stream_; }
-ChunkDemuxer::ChunkDemuxer()
+ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
: state_(WAITING_FOR_INIT),
+ client_(client),
format_context_(NULL),
buffered_bytes_(0),
seek_waits_for_data_(true) {
+ DCHECK(client);
}
ChunkDemuxer::~ChunkDemuxer() {
@@ -280,19 +286,16 @@ ChunkDemuxer::~ChunkDemuxer() {
}
void ChunkDemuxer::Init(PipelineStatusCB cb) {
- base::AutoLock auto_lock(lock_);
- DCHECK_EQ(state_, WAITING_FOR_INIT);
-
- ChangeState(INITIALIZING);
- init_cb_ = cb;
-
- if (pending_buffers_.empty())
- return;
+ VLOG(1) << "Init()";
+ {
+ base::AutoLock auto_lock(lock_);
+ DCHECK_EQ(state_, WAITING_FOR_INIT);
- scoped_refptr<Buffer> buf = pending_buffers_.front();
- pending_buffers_.pop_front();
+ ChangeState(INITIALIZING);
+ init_cb_ = cb;
+ }
- ParseInfoAndTracks_Locked(buf->GetData(), buf->GetDataSize());
+ client_->DemuxerOpened(this);
}
// Filter implementation.
@@ -305,6 +308,8 @@ void ChunkDemuxer::set_host(FilterHost* filter_host) {
void ChunkDemuxer::Stop(FilterCallback* callback) {
VLOG(1) << "Stop()";
+ Shutdown();
+
callback->Run();
delete callback;
}
@@ -351,15 +356,21 @@ base::TimeDelta ChunkDemuxer::GetStartTime() const {
}
void ChunkDemuxer::FlushData() {
+ VLOG(1) << "FlushData()";
base::AutoLock auto_lock(lock_);
+ DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN);
+
+ if (state_ == SHUTDOWN)
+ return;
+
if (audio_.get())
audio_->Flush();
if (video_.get())
video_->Flush();
- pending_buffers_.clear();
seek_waits_for_data_ = true;
+ ChangeState(INITIALIZED);
}
bool ChunkDemuxer::AppendData(const uint8* data, unsigned length) {
@@ -373,13 +384,7 @@ bool ChunkDemuxer::AppendData(const uint8* data, unsigned length) {
FilterStatusCB cb;
{
base::AutoLock auto_lock(lock_);
-
switch(state_) {
- case WAITING_FOR_INIT:
- pending_buffers_.push_back(CreateBuffer(data, length));
- return true;
- break;
-
case INITIALIZING:
if (!ParseInfoAndTracks_Locked(data, length)) {
VLOG(1) << "AppendData(): parsing info & tracks failed";
@@ -395,6 +400,8 @@ bool ChunkDemuxer::AppendData(const uint8* data, unsigned length) {
}
break;
+ case WAITING_FOR_INIT:
+ case ENDED:
case INIT_ERROR:
case SHUTDOWN:
VLOG(1) << "AppendData(): called in unexpected state " << state_;
@@ -438,11 +445,53 @@ bool ChunkDemuxer::AppendData(const uint8* data, unsigned length) {
return true;
}
+void ChunkDemuxer::EndOfStream(PipelineStatus status) {
+ VLOG(1) << "EndOfStream(" << status << ")";
+ base::AutoLock auto_lock(lock_);
+ DCHECK((state_ == INITIALIZING) || (state_ == INITIALIZED) ||
+ (state_ == SHUTDOWN));
+
+ if (state_ == SHUTDOWN)
+ return;
+
+ if (state_ == INITIALIZING) {
+ InitFailed_Locked();
+ return;
+ }
+
+ ChangeState(ENDED);
+
+ if (status != PIPELINE_OK) {
+ host()->SetError(status);
+ return;
+ }
+
+ // Create an end of stream buffer.
+ ChunkDemuxerStream::BufferQueue buffers;
+ buffers.push_back(CreateEOSBuffer());
+
+ if (audio_.get())
+ audio_->AddBuffers(buffers);
+
+ if (video_.get())
+ video_->AddBuffers(buffers);
+}
+
+bool ChunkDemuxer::HasEnded() {
+ base::AutoLock auto_lock(lock_);
+ return (state_ == ENDED);
+}
+
+
void ChunkDemuxer::Shutdown() {
+ VLOG(1) << "Shutdown()";
FilterStatusCB cb;
{
base::AutoLock auto_lock(lock_);
+ if (state_ == SHUTDOWN)
+ return;
+
std::swap(cb, seek_cb_);
if (audio_.get())
@@ -456,6 +505,8 @@ void ChunkDemuxer::Shutdown() {
if (!cb.is_null())
cb.Run(PIPELINE_ERROR_ABORT);
+
+ client_->DemuxerClosed();
}
void ChunkDemuxer::ChangeState(State new_state) {
@@ -502,7 +553,7 @@ bool ChunkDemuxer::ParseInfoAndTracks_Locked(const uint8* data, int size) {
format_context_ = CreateFormatContext(data, size);
- if (!format_context_ || !SetupStreams() || !ParsePendingBuffers_Locked()) {
+ if (!format_context_ || !SetupStreams()) {
InitFailed_Locked();
return false;
}
@@ -578,25 +629,6 @@ bool ChunkDemuxer::SetupStreams() {
return !no_supported_streams;
}
-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.
- while(!pending_buffers_.empty()) {
- scoped_refptr<media::Buffer> buf = pending_buffers_.front();
- pending_buffers_.pop_front();
-
- if (!ParseAndAppendData_Locked(buf->GetData(), buf->GetDataSize())) {
- pending_buffers_.clear();
- ChangeState(INIT_ERROR);
- return false;
- }
- }
-
- seek_waits_for_data_ = !had_pending_buffers;
- return true;
-}
-
bool ChunkDemuxer::ParseAndAppendData_Locked(const uint8* data, int length) {
if (!cluster_parser_.get())
return false;
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index 8013c4f..43ec0a5 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -15,13 +15,14 @@ struct AVFormatContext;
namespace media {
+class ChunkDemuxerClient;
class ChunkDemuxerStream;
// Demuxer implementation that allows chunks of WebM media data to be passed
// from JavaScript to the media stack.
class ChunkDemuxer : public Demuxer {
public:
- ChunkDemuxer();
+ explicit ChunkDemuxer(ChunkDemuxerClient* client);
virtual ~ChunkDemuxer();
void Init(PipelineStatusCB cb);
@@ -37,9 +38,11 @@ class ChunkDemuxer : public Demuxer {
virtual scoped_refptr<DemuxerStream> GetStream(DemuxerStream::Type type);
virtual base::TimeDelta GetStartTime() const;
- // Methods used by MediaDataSink
+ // Methods used by an external object to control this demuxer.
void FlushData();
bool AppendData(const uint8* data, unsigned length);
+ void EndOfStream(PipelineStatus status);
+ bool HasEnded();
void Shutdown();
private:
@@ -47,6 +50,7 @@ class ChunkDemuxer : public Demuxer {
WAITING_FOR_INIT,
INITIALIZING,
INITIALIZED,
+ ENDED,
INIT_ERROR,
SHUTDOWN,
};
@@ -67,10 +71,6 @@ class ChunkDemuxer : public Demuxer {
// found.
bool SetupStreams();
- // Parse all the buffers in |pending_buffers_|. Returns false if parsing one
- // of the buffers fails.
- 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);
@@ -81,6 +81,7 @@ class ChunkDemuxer : public Demuxer {
base::Lock lock_;
State state_;
+ ChunkDemuxerClient* client_;
PipelineStatusCB init_cb_;
FilterStatusCB seek_cb_;
@@ -95,9 +96,6 @@ class ChunkDemuxer : public Demuxer {
scoped_ptr<WebMClusterParser> cluster_parser_;
- typedef std::list<scoped_refptr<media::Buffer> > BufferList;
- BufferList pending_buffers_;
-
// Should a Seek() call wait for more data before calling the
// callback.
bool seek_waits_for_data_;
diff --git a/media/filters/chunk_demuxer_client.h b/media/filters/chunk_demuxer_client.h
new file mode 100644
index 0000000..691f81e
--- /dev/null
+++ b/media/filters/chunk_demuxer_client.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_FILTERS_CHUNK_DEMUXER_CLIENT_H_
+#define MEDIA_FILTERS_CHUNK_DEMUXER_CLIENT_H_
+
+namespace media {
+
+class ChunkDemuxer;
+
+// Interface used to notify an external object when a ChunkDemuxer
+// is opened & closed.
+class ChunkDemuxerClient {
+ public:
+ // Called when a ChunkDemuxer object is opened.
+ virtual void DemuxerOpened(ChunkDemuxer* demuxer) = 0;
+
+ // The ChunkDemuxer passed via last DemuxerOpened() call is now
+ // closed. Any further calls on the demuxer will result in an error.
+ virtual void DemuxerClosed() = 0;
+};
+
+} // namespace media
+
+#endif // MEDIA_FILTERS_CHUNK_DEMUXER_CLIENT_H_
diff --git a/media/filters/chunk_demuxer_factory.cc b/media/filters/chunk_demuxer_factory.cc
index a354b39..ed3346c 100644
--- a/media/filters/chunk_demuxer_factory.cc
+++ b/media/filters/chunk_demuxer_factory.cc
@@ -30,55 +30,34 @@ static void InitDone(MessageLoop* message_loop,
NewRunnableFunction(&DoInitDone, cb, demuxer, status));
}
-MediaDataSink::MediaDataSink(const scoped_refptr<ChunkDemuxer>& demuxer)
- : demuxer_(demuxer) {
+ChunkDemuxerFactory::ChunkDemuxerFactory(const std::string& url,
+ DemuxerFactory* delegate_factory,
+ ChunkDemuxerClient* client)
+ : url_(url),
+ delegate_factory_(delegate_factory),
+ client_(client) {
+ DCHECK(delegate_factory_.get());
}
-MediaDataSink::~MediaDataSink() {}
-
-void MediaDataSink::Flush() {
- demuxer_->FlushData();
-}
-
-bool MediaDataSink::AppendData(const uint8* data, unsigned length) {
- return demuxer_->AppendData(data, length);
-}
-
-void MediaDataSink::Shutdown() {
- demuxer_->Shutdown();
-}
-
-const char ChunkDemuxerFactory::kURLPrefix[] = "x-media-chunks:";
-
-ChunkDemuxerFactory::ChunkDemuxerFactory() {}
-
ChunkDemuxerFactory::~ChunkDemuxerFactory() {}
-bool ChunkDemuxerFactory::IsUrlSupported(const std::string& url) const {
- return (url.find(kURLPrefix) == 0);
-}
-
-MediaDataSink* ChunkDemuxerFactory::CreateMediaDataSink() {
- demuxer_ = new ChunkDemuxer();
- return new MediaDataSink(demuxer_);
-}
-
void ChunkDemuxerFactory::Build(const std::string& url, BuildCallback* cb) {
- if (!IsUrlSupported(url) || !demuxer_.get()) {
- cb->Run(DEMUXER_ERROR_COULD_NOT_OPEN, static_cast<Demuxer*>(NULL));
- delete cb;
+ // Check to see if this is the URL we are looking for. If not delegate
+ // building to the delegate factory.
+ if (url != url_) {
+ delegate_factory_->Build(url, cb);
return;
}
+ scoped_refptr<ChunkDemuxer> demuxer(new ChunkDemuxer(client_));
// 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;
+ demuxer->Init(base::Bind(&InitDone, MessageLoop::current(), cb,
+ scoped_refptr<Demuxer>(demuxer.get())));
}
DemuxerFactory* ChunkDemuxerFactory::Clone() const {
- return new ChunkDemuxerFactory();
+ return new ChunkDemuxerFactory(url_, delegate_factory_->Clone(), client_);
}
} // namespace media
diff --git a/media/filters/chunk_demuxer_factory.h b/media/filters/chunk_demuxer_factory.h
index 614820e..a3d004a 100644
--- a/media/filters/chunk_demuxer_factory.h
+++ b/media/filters/chunk_demuxer_factory.h
@@ -11,56 +11,30 @@
namespace media {
class ChunkDemuxer;
+class ChunkDemuxerClient;
-// Class used by an external object to send media data to the
-// Demuxer. This object is created by the DemuxerFactory and
-// contains the Demuxer that will be returned in the next Build()
-// call on the factory. The external object tells the factory
-// to create one of these objects before it starts the Pipeline.
-// It does this because the external object may need to make AddData()
-// calls before the pipeline has completely initialized. This class
-// allows data from these calls to be queued until initialization
-// completes. It represents the minimal operations needed by
-// the external object to talk to the Demuxer. It also allows
-// the external object to have a longer lifetime than the pipeline.
-class MediaDataSink {
- public:
- MediaDataSink(const scoped_refptr<ChunkDemuxer>& demuxer);
- ~MediaDataSink();
-
- // Flush all data passed via AddData().
- void Flush();
-
- // Sends media data to the demuxer. Returns true if the data is valid.
- 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.
- void Shutdown();
-
- private:
- scoped_refptr<ChunkDemuxer> demuxer_;
- DISALLOW_IMPLICIT_CONSTRUCTORS(MediaDataSink);
-};
-
+// Factory for building ChunkDemuxers. The factory will only build a
+// ChunkDemuxer for build URLs that match the one passed into the constructor.
+// All other URLs are delegated to |delegate_factory_|. The url passed to
+// the constructor represents the "special" URL that indicates that the
+// ChunkDemuxer should be used for playback.
class ChunkDemuxerFactory : public DemuxerFactory {
public:
- // Takes a reference to |demuxer_factory|.
- ChunkDemuxerFactory();
+ // Takes ownership of |delegate_factory|.
+ ChunkDemuxerFactory(const std::string& url, DemuxerFactory* delegate_factory,
+ ChunkDemuxerClient* client);
virtual ~ChunkDemuxerFactory();
- bool IsUrlSupported(const std::string& url) const;
- MediaDataSink* CreateMediaDataSink();
-
// DemuxerFactory methods.
virtual void Build(const std::string& url, BuildCallback* cb);
virtual DemuxerFactory* Clone() const;
private:
- static const char kURLPrefix[];
- scoped_refptr<ChunkDemuxer> demuxer_;
+ std::string url_;
+ scoped_ptr<DemuxerFactory> delegate_factory_;
+ ChunkDemuxerClient* client_;
- DISALLOW_COPY_AND_ASSIGN(ChunkDemuxerFactory);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerFactory);
};
} // namespace media
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 695cee3..13d0c93 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -10,12 +10,14 @@
#include "media/base/mock_callback.h"
#include "media/base/mock_ffmpeg.h"
#include "media/filters/chunk_demuxer.h"
+#include "media/filters/chunk_demuxer_client.h"
#include "media/webm/cluster_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::InSequence;
using ::testing::Return;
using ::testing::SetArgumentPointee;
+using ::testing::NiceMock;
using ::testing::_;
namespace media {
@@ -31,6 +33,18 @@ static const int kTracksSizeOffset = 4;
static const int kVideoTrackNum = 1;
static const int kAudioTrackNum = 2;
+class MockChunkDemuxerClient : public ChunkDemuxerClient {
+ public:
+ MockChunkDemuxerClient() {}
+ virtual ~MockChunkDemuxerClient() {}
+
+ MOCK_METHOD1(DemuxerOpened, void(ChunkDemuxer* demuxer));
+ MOCK_METHOD0(DemuxerClosed, void());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockChunkDemuxerClient);
+};
+
class ChunkDemuxerTest : public testing::Test{
protected:
enum CodecsIndex {
@@ -40,7 +54,8 @@ class ChunkDemuxerTest : public testing::Test{
};
ChunkDemuxerTest()
- : demuxer_(new ChunkDemuxer()) {
+ : client_(new MockChunkDemuxerClient()),
+ demuxer_(new ChunkDemuxer(client_.get())) {
memset(&format_context_, 0, sizeof(format_context_));
memset(&streams_, 0, sizeof(streams_));
memset(&codecs_, 0, sizeof(codecs_));
@@ -166,8 +181,11 @@ class ChunkDemuxerTest : public testing::Test{
bool init_done_called = false;
PipelineStatus expectedStatus =
(has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN;
+
+ EXPECT_CALL(*client_, DemuxerOpened(_));
demuxer_->Init(base::Bind(&ChunkDemuxerTest::InitDoneCalled,
- &init_done_called, expectedStatus));
+ &init_done_called,
+ expectedStatus));
EXPECT_FALSE(init_done_called);
@@ -178,6 +196,7 @@ class ChunkDemuxerTest : public testing::Test{
void ShutdownDemuxer() {
if (demuxer_) {
+ EXPECT_CALL(*client_, DemuxerClosed());
demuxer_->Shutdown();
}
@@ -201,6 +220,7 @@ class ChunkDemuxerTest : public testing::Test{
AVCodecContext codecs_[MAX_CODECS_INDEX];
AVStream streams_[MAX_CODECS_INDEX];
+ scoped_ptr<MockChunkDemuxerClient> client_;
scoped_refptr<ChunkDemuxer> demuxer_;
private:
@@ -237,7 +257,8 @@ TEST_F(ChunkDemuxerTest, TestInit) {
bool has_audio = (i & 0x1) != 0;
bool has_video = (i & 0x2) != 0;
- demuxer_ = new ChunkDemuxer();
+ client_.reset(new MockChunkDemuxerClient());
+ demuxer_ = new ChunkDemuxer(client_.get());
InitDemuxer(has_audio, has_video);
EXPECT_EQ(demuxer_->GetStream(DemuxerStream::AUDIO).get() != NULL,
has_audio);
@@ -283,23 +304,13 @@ TEST_F(ChunkDemuxerTest, TestAppendDataAfterSeek) {
Checkpoint(2);
}
-// Test the case where AppendData() is called before Init(). This can happen
-// when JavaScript starts sending data before the pipeline is completely
-// initialized.
+// Test the case where AppendData() is called before Init().
TEST_F(ChunkDemuxerTest, TestAppendDataBeforeInit) {
- AppendInfoTracks(true, true);
+ scoped_array<uint8> info_tracks;
+ int info_tracks_size = 0;
+ CreateInfoTracks(true, true, &info_tracks, &info_tracks_size);
- ClusterBuilder cb;
- cb.SetClusterTimecode(0);
- AddSimpleBlock(&cb, kVideoTrackNum, 0);
- scoped_ptr<Cluster> cluster(cb.Finish());
-
- EXPECT_TRUE(demuxer_->AppendData(cluster->data(), cluster->size()));
-
- demuxer_->Init(NewExpectedStatusCB(PIPELINE_OK));
-
- demuxer_->Seek(base::TimeDelta::FromSeconds(0),
- NewExpectedStatusCB(PIPELINE_OK));
+ EXPECT_FALSE(demuxer_->AppendData(info_tracks.get(), info_tracks_size));
}
static void OnReadDone(const base::TimeDelta& expected_time,
@@ -444,6 +455,7 @@ TEST_F(ChunkDemuxerTest, TestInvalidBlockSequences) {
// Test the case where a cluster is passed to AppendData() before
// INFO & TRACKS data.
TEST_F(ChunkDemuxerTest, TestClusterBeforeInfoTracks) {
+ EXPECT_CALL(*client_, DemuxerOpened(_));
demuxer_->Init(NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN));
ClusterBuilder cb;
@@ -454,4 +466,11 @@ TEST_F(ChunkDemuxerTest, TestClusterBeforeInfoTracks) {
EXPECT_FALSE(demuxer_->AppendData(cluster->data(), cluster->size()));
}
+
+// Test cases where we get an EndOfStream() call during initialization.
+TEST_F(ChunkDemuxerTest, TestEOSDuringInit) {
+ EXPECT_CALL(*client_, DemuxerOpened(_));
+ demuxer_->Init(NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN));
+ demuxer_->EndOfStream(PIPELINE_OK);
+}
} // namespace media
diff --git a/media/media.gyp b/media/media.gyp
index df86e03..d024f57 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -152,6 +152,7 @@
'filters/bitstream_converter.h',
'filters/chunk_demuxer.cc',
'filters/chunk_demuxer.h',
+ 'filters/chunk_demuxer_client.h',
'filters/chunk_demuxer_factory.cc',
'filters/chunk_demuxer_factory.h',
'filters/decoder_base.h',