summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-13 20:47:40 +0000
committerscherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-13 20:47:40 +0000
commitf85a3dfb035114748fd3ea58b9f26ee3f8d785dc (patch)
tree823afd3d832eceb123413d242e6564f6ed13f514 /media
parent856eb49fe9279aba4f1a1602ce091a6d45b1d2b4 (diff)
downloadchromium_src-f85a3dfb035114748fd3ea58b9f26ee3f8d785dc.zip
chromium_src-f85a3dfb035114748fd3ea58b9f26ee3f8d785dc.tar.gz
chromium_src-f85a3dfb035114748fd3ea58b9f26ee3f8d785dc.tar.bz2
Refactor FFmpegURLProtocol code from FFmpegDemuxer into BlockingUrlProtocol.
I cleaned up some comments and surrounding test code in FFmpegDemuxer and FileDataSource as well. There'll be some more clean up after I get this landed. BUG=160640 TEST=FFmpegDemuxer and BlockingUrlProtocol tests Review URL: https://codereview.chromium.org/11410052 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167462 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/filters/blocking_url_protocol.cc87
-rw-r--r--media/filters/blocking_url_protocol.h73
-rw-r--r--media/filters/blocking_url_protocol_unittest.cc127
-rw-r--r--media/filters/ffmpeg_demuxer.cc99
-rw-r--r--media/filters/ffmpeg_demuxer.h35
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc94
-rw-r--r--media/filters/file_data_source.cc16
-rw-r--r--media/filters/file_data_source.h19
-rw-r--r--media/media.gyp6
9 files changed, 332 insertions, 224 deletions
diff --git a/media/filters/blocking_url_protocol.cc b/media/filters/blocking_url_protocol.cc
new file mode 100644
index 0000000..ceb5d71
--- /dev/null
+++ b/media/filters/blocking_url_protocol.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 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.
+
+#include "media/filters/blocking_url_protocol.h"
+
+#include "base/bind.h"
+#include "media/base/data_source.h"
+#include "media/ffmpeg/ffmpeg_common.h"
+
+namespace media {
+
+BlockingUrlProtocol::BlockingUrlProtocol(
+ const scoped_refptr<DataSource>& data_source,
+ const base::Closure& error_cb)
+ : data_source_(data_source),
+ error_cb_(error_cb),
+ read_event_(false, false),
+ read_has_failed_(false),
+ last_read_bytes_(0),
+ read_position_(0) {
+}
+
+BlockingUrlProtocol::~BlockingUrlProtocol() {}
+
+void BlockingUrlProtocol::Abort() {
+ SignalReadCompleted(DataSource::kReadError);
+}
+
+int BlockingUrlProtocol::Read(int size, uint8* data) {
+ // Read errors are unrecoverable.
+ if (read_has_failed_)
+ return AVERROR(EIO);
+
+ // Even though FFmpeg defines AVERROR_EOF, it's not to be used with I/O
+ // routines. Instead return 0 for any read at or past EOF.
+ int64 file_size;
+ if (data_source_->GetSize(&file_size) && read_position_ >= file_size)
+ return 0;
+
+ // Blocking read from data source until |last_read_bytes_| is set and event is
+ // signalled.
+ data_source_->Read(read_position_, size, data, base::Bind(
+ &BlockingUrlProtocol::SignalReadCompleted, base::Unretained(this)));
+ read_event_.Wait();
+
+ if (last_read_bytes_ == DataSource::kReadError) {
+ // TODO(scherkus): We shouldn't fire |error_cb_| if it was due to Abort().
+ error_cb_.Run();
+ read_has_failed_ = true;
+ return AVERROR(EIO);
+ }
+
+ read_position_ += last_read_bytes_;
+ return last_read_bytes_;
+}
+
+bool BlockingUrlProtocol::GetPosition(int64* position_out) {
+ *position_out = read_position_;
+ return true;
+}
+
+bool BlockingUrlProtocol::SetPosition(int64 position) {
+ int64 file_size;
+ if ((data_source_->GetSize(&file_size) && position >= file_size) ||
+ position < 0) {
+ return false;
+ }
+
+ read_position_ = position;
+ return true;
+}
+
+bool BlockingUrlProtocol::GetSize(int64* size_out) {
+ return data_source_->GetSize(size_out);
+}
+
+bool BlockingUrlProtocol::IsStreaming() {
+ return data_source_->IsStreaming();
+}
+
+void BlockingUrlProtocol::SignalReadCompleted(int size) {
+ last_read_bytes_ = size;
+ read_event_.Signal();
+}
+
+} // namespace media
diff --git a/media/filters/blocking_url_protocol.h b/media/filters/blocking_url_protocol.h
new file mode 100644
index 0000000..dbffbbc
--- /dev/null
+++ b/media/filters/blocking_url_protocol.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 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_BLOCKING_URL_PROTOCOL_H_
+#define MEDIA_FILTERS_BLOCKING_URL_PROTOCOL_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/synchronization/waitable_event.h"
+#include "media/filters/ffmpeg_glue.h"
+
+namespace media {
+
+class DataSource;
+
+// An implementation of FFmpegURLProtocol that blocks until the underlying
+// asynchronous DataSource::Read() operation completes.
+//
+// TODO(scherkus): Should be more thread-safe as |last_read_bytes_| is updated
+// from multiple threads without any protection.
+class MEDIA_EXPORT BlockingUrlProtocol : public FFmpegURLProtocol {
+ public:
+ // Implements FFmpegURLProtocol using the given |data_source|. |error_cb| is
+ // fired any time DataSource::Read() returns an error.
+ //
+ // TODO(scherkus): After all blocking operations are isolated on a separate
+ // thread we should be able to eliminate |error_cb|.
+ BlockingUrlProtocol(const scoped_refptr<DataSource>& data_source,
+ const base::Closure& error_cb);
+ virtual ~BlockingUrlProtocol();
+
+ // Aborts any pending reads by returning a read error. After this method
+ // returns all subsequent calls to Read() will immediately fail.
+ //
+ // TODO(scherkus): Currently this will cause |error_cb| to fire. Fix.
+ void Abort();
+
+ // FFmpegURLProtocol implementation.
+ virtual int Read(int size, uint8* data) OVERRIDE;
+ virtual bool GetPosition(int64* position_out) OVERRIDE;
+ virtual bool SetPosition(int64 position) OVERRIDE;
+ virtual bool GetSize(int64* size_out) OVERRIDE;
+ virtual bool IsStreaming() OVERRIDE;
+
+ private:
+ // Sets |last_read_bytes_| and signals the blocked thread that the read
+ // has completed.
+ void SignalReadCompleted(int size);
+
+ scoped_refptr<DataSource> data_source_;
+ base::Closure error_cb_;
+
+ // Used to convert an asynchronous DataSource::Read() into a blocking
+ // FFmpegUrlProtocol::Read().
+ base::WaitableEvent read_event_;
+
+ // Read errors and aborts are unrecoverable. Any subsequent reads will
+ // immediately fail when this is set to true.
+ bool read_has_failed_;
+
+ // Cached number of bytes last read from the data source.
+ int last_read_bytes_;
+
+ // Cached position within the data source.
+ int64 read_position_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BlockingUrlProtocol);
+};
+
+} // namespace media
+
+#endif // MEDIA_FILTERS_BLOCKING_URL_PROTOCOL_H_
diff --git a/media/filters/blocking_url_protocol_unittest.cc b/media/filters/blocking_url_protocol_unittest.cc
new file mode 100644
index 0000000..8bd30c1
--- /dev/null
+++ b/media/filters/blocking_url_protocol_unittest.cc
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 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.
+
+#include "base/bind.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+#include "media/filters/blocking_url_protocol.h"
+#include "media/filters/file_data_source.h"
+#include "media/ffmpeg/ffmpeg_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace media {
+
+class BlockingUrlProtocolTest : public testing::Test {
+ public:
+ BlockingUrlProtocolTest() {
+ FilePath file_path;
+ EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
+ file_path = file_path.Append(FILE_PATH_LITERAL("media"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .AppendASCII("bear-320x240.webm");
+
+ data_source_ = new FileDataSource();
+ CHECK(data_source_->Initialize(file_path.MaybeAsASCII()));
+
+ url_protocol_.reset(new BlockingUrlProtocol(data_source_, base::Bind(
+ &BlockingUrlProtocolTest::OnDataSourceError, base::Unretained(this))));
+ }
+
+ virtual ~BlockingUrlProtocolTest() {
+ base::WaitableEvent stop_event(false, false);
+ data_source_->Stop(base::Bind(
+ &base::WaitableEvent::Signal, base::Unretained(&stop_event)));
+ stop_event.Wait();
+ }
+
+ MOCK_METHOD0(OnDataSourceError, void());
+
+ scoped_refptr<FileDataSource> data_source_;
+ scoped_ptr<BlockingUrlProtocol> url_protocol_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BlockingUrlProtocolTest);
+};
+
+
+TEST_F(BlockingUrlProtocolTest, Read) {
+ // Set read head to zero as Initialize() will have parsed a bit of the file.
+ int64 position = 0;
+ EXPECT_TRUE(url_protocol_->SetPosition(0));
+ EXPECT_TRUE(url_protocol_->GetPosition(&position));
+ EXPECT_EQ(0, position);
+
+ // Read 32 bytes from offset zero and verify position.
+ uint8 buffer[32];
+ EXPECT_EQ(32, url_protocol_->Read(32, buffer));
+ EXPECT_TRUE(url_protocol_->GetPosition(&position));
+ EXPECT_EQ(32, position);
+
+ // Read an additional 32 bytes and verify position.
+ EXPECT_EQ(32, url_protocol_->Read(32, buffer));
+ EXPECT_TRUE(url_protocol_->GetPosition(&position));
+ EXPECT_EQ(64, position);
+
+ // Seek to end and read until EOF.
+ int64 size = 0;
+ EXPECT_TRUE(url_protocol_->GetSize(&size));
+ EXPECT_TRUE(url_protocol_->SetPosition(size - 48));
+ EXPECT_EQ(32, url_protocol_->Read(32, buffer));
+ EXPECT_TRUE(url_protocol_->GetPosition(&position));
+ EXPECT_EQ(size - 16, position);
+
+ EXPECT_EQ(16, url_protocol_->Read(32, buffer));
+ EXPECT_TRUE(url_protocol_->GetPosition(&position));
+ EXPECT_EQ(size, position);
+
+ EXPECT_EQ(0, url_protocol_->Read(32, buffer));
+ EXPECT_TRUE(url_protocol_->GetPosition(&position));
+ EXPECT_EQ(size, position);
+}
+
+TEST_F(BlockingUrlProtocolTest, ReadError) {
+ data_source_->force_read_errors_for_testing();
+
+ uint8 buffer[32];
+ EXPECT_CALL(*this, OnDataSourceError());
+ EXPECT_EQ(AVERROR(EIO), url_protocol_->Read(32, buffer));
+}
+
+TEST_F(BlockingUrlProtocolTest, GetSetPosition) {
+ int64 size;
+ int64 position;
+ EXPECT_TRUE(url_protocol_->GetSize(&size));
+ EXPECT_TRUE(url_protocol_->GetPosition(&position));
+
+ EXPECT_TRUE(url_protocol_->SetPosition(512));
+ EXPECT_FALSE(url_protocol_->SetPosition(size));
+ EXPECT_FALSE(url_protocol_->SetPosition(size + 1));
+ EXPECT_FALSE(url_protocol_->SetPosition(-1));
+ EXPECT_TRUE(url_protocol_->GetPosition(&position));
+ EXPECT_EQ(512, position);
+}
+
+TEST_F(BlockingUrlProtocolTest, GetSize) {
+ int64 data_source_size = 0;
+ int64 url_protocol_size = 0;
+ EXPECT_TRUE(data_source_->GetSize(&data_source_size));
+ EXPECT_TRUE(url_protocol_->GetSize(&url_protocol_size));
+ EXPECT_NE(0, data_source_size);
+ EXPECT_EQ(data_source_size, url_protocol_size);
+}
+
+TEST_F(BlockingUrlProtocolTest, IsStreaming) {
+ EXPECT_FALSE(data_source_->IsStreaming());
+ EXPECT_FALSE(url_protocol_->IsStreaming());
+
+ data_source_->force_streaming_for_testing();
+ EXPECT_TRUE(data_source_->IsStreaming());
+ EXPECT_TRUE(url_protocol_->IsStreaming());
+}
+
+} // namespace media
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index c1c12f3..ee04455 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -263,14 +263,12 @@ FFmpegDemuxer::FFmpegDemuxer(
: host_(NULL),
message_loop_(message_loop),
data_source_(data_source),
- read_event_(false, false),
- read_has_failed_(false),
- last_read_bytes_(0),
- read_position_(0),
bitrate_(0),
start_time_(kNoTimestamp()),
audio_disabled_(false),
- duration_known_(false) {
+ duration_known_(false),
+ url_protocol_(data_source, base::Bind(
+ &FFmpegDemuxer::OnDataSourceError, base::Unretained(this))) {
DCHECK(message_loop_);
DCHECK(data_source_);
}
@@ -287,8 +285,10 @@ void FFmpegDemuxer::Stop(const base::Closure& callback) {
message_loop_->PostTask(FROM_HERE,
base::Bind(&FFmpegDemuxer::StopTask, this, callback));
- // Then wakes up the thread from reading.
- SignalReadCompleted(DataSource::kReadError);
+ // TODO(scherkus): This should be on |message_loop_| but today that thread is
+ // potentially blocked. Move to StopTask() after all blocking calls are
+ // guaranteed to run on a separate thread.
+ url_protocol_.Abort();
}
void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
@@ -332,73 +332,6 @@ base::TimeDelta FFmpegDemuxer::GetStartTime() const {
return start_time_;
}
-int FFmpegDemuxer::Read(int size, uint8* data) {
- DCHECK(host_);
- DCHECK(data_source_);
-
- // If read has ever failed, return with an error.
- // TODO(hclam): use a more meaningful constant as error.
- if (read_has_failed_)
- return AVERROR(EIO);
-
- // Even though FFmpeg defines AVERROR_EOF, it's not to be used with I/O
- // routines. Instead return 0 for any read at or past EOF.
- int64 file_size;
- if (data_source_->GetSize(&file_size) && read_position_ >= file_size)
- return 0;
-
- // Asynchronous read from data source.
- data_source_->Read(read_position_, size, data, base::Bind(
- &FFmpegDemuxer::SignalReadCompleted, this));
-
- // TODO(hclam): The method is called on the demuxer thread and this method
- // call will block the thread. We need to implemented an additional thread to
- // let FFmpeg demuxer methods to run on.
- int last_read_bytes = WaitForRead();
- if (last_read_bytes == DataSource::kReadError) {
- host_->OnDemuxerError(PIPELINE_ERROR_READ);
-
- // Returns with a negative number to signal an error to FFmpeg.
- read_has_failed_ = true;
- return AVERROR(EIO);
- }
- read_position_ += last_read_bytes;
-
- return last_read_bytes;
-}
-
-bool FFmpegDemuxer::GetPosition(int64* position_out) {
- DCHECK(host_);
- *position_out = read_position_;
- return true;
-}
-
-bool FFmpegDemuxer::SetPosition(int64 position) {
- DCHECK(host_);
- DCHECK(data_source_);
-
- int64 file_size;
- if ((data_source_->GetSize(&file_size) && position >= file_size) ||
- position < 0) {
- return false;
- }
-
- read_position_ = position;
- return true;
-}
-
-bool FFmpegDemuxer::GetSize(int64* size_out) {
- DCHECK(host_);
- DCHECK(data_source_);
- return data_source_->GetSize(size_out);
-}
-
-bool FFmpegDemuxer::IsStreaming() {
- DCHECK(host_);
- DCHECK(data_source_);
- return data_source_->IsStreaming();
-}
-
scoped_refptr<base::MessageLoopProxy> FFmpegDemuxer::message_loop() {
return message_loop_;
}
@@ -448,7 +381,7 @@ void FFmpegDemuxer::InitializeTask(DemuxerHost* host,
// see http://crbug.com/122071
data_source_->set_host(host);
- glue_.reset(new FFmpegGlue(this));
+ glue_.reset(new FFmpegGlue(&url_protocol_));
AVFormatContext* format_context = glue_->format_context();
// Disable ID3v1 tag reading to avoid costly seeks to end of file for data we
@@ -539,7 +472,7 @@ void FFmpegDemuxer::InitializeTask(DemuxerHost* host,
duration_known_ = (max_duration != kInfiniteDuration());
int64 filesize_in_bytes = 0;
- GetSize(&filesize_in_bytes);
+ url_protocol_.GetSize(&filesize_in_bytes);
bitrate_ = CalculateBitrate(format_context, max_duration, filesize_in_bytes);
if (bitrate_ > 0)
data_source_->SetBitrate(bitrate_);
@@ -683,16 +616,6 @@ void FFmpegDemuxer::StreamHasEnded() {
}
}
-int FFmpegDemuxer::WaitForRead() {
- read_event_.Wait();
- return last_read_bytes_;
-}
-
-void FFmpegDemuxer::SignalReadCompleted(int size) {
- last_read_bytes_ = size;
- read_event_.Signal();
-}
-
void FFmpegDemuxer::NotifyBufferingChanged() {
DCHECK(message_loop_->BelongsToCurrentThread());
Ranges<base::TimeDelta> buffered;
@@ -712,4 +635,8 @@ void FFmpegDemuxer::NotifyBufferingChanged() {
host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
}
+void FFmpegDemuxer::OnDataSourceError() {
+ host_->OnDemuxerError(PIPELINE_ERROR_READ);
+}
+
} // namespace media
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 23b5dc80..eea4a0a 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -27,13 +27,12 @@
#include "base/callback.h"
#include "base/gtest_prod_util.h"
-#include "base/synchronization/waitable_event.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/decoder_buffer.h"
#include "media/base/demuxer.h"
#include "media/base/pipeline.h"
#include "media/base/video_decoder_config.h"
-#include "media/filters/ffmpeg_glue.h"
+#include "media/filters/blocking_url_protocol.h"
// FFmpeg forward declarations.
struct AVPacket;
@@ -43,6 +42,7 @@ struct AVStream;
namespace media {
class FFmpegDemuxer;
+class FFmpegGlue;
class FFmpegH264ToAnnexBBitstreamConverter;
class ScopedPtrAVFreePacket;
@@ -138,7 +138,7 @@ class FFmpegDemuxerStream : public DemuxerStream {
DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerStream);
};
-class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol {
+class MEDIA_EXPORT FFmpegDemuxer : public Demuxer {
public:
FFmpegDemuxer(const scoped_refptr<base::MessageLoopProxy>& message_loop,
const scoped_refptr<DataSource>& data_source);
@@ -157,13 +157,6 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol {
DemuxerStream::Type type) OVERRIDE;
virtual base::TimeDelta GetStartTime() const OVERRIDE;
- // FFmpegURLProtocol implementation.
- virtual int Read(int size, uint8* data) OVERRIDE;
- virtual bool GetPosition(int64* position_out) OVERRIDE;
- virtual bool SetPosition(int64 position) OVERRIDE;
- virtual bool GetSize(int64* size_out) OVERRIDE;
- virtual bool IsStreaming() OVERRIDE;
-
// Provide access to FFmpegDemuxerStream.
scoped_refptr<base::MessageLoopProxy> message_loop();
@@ -204,12 +197,8 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol {
// Must be called on the demuxer thread.
void StreamHasEnded();
- // Wait for asynchronous read to complete and return number of bytes read.
- virtual int WaitForRead();
-
- // Signal the blocked thread that the read has completed, with |size| bytes
- // read or kReadError in case of error.
- virtual void SignalReadCompleted(int size);
+ // Called by |url_protocol_| whenever |data_source_| returns a read error.
+ void OnDataSourceError();
// Returns the stream from |streams_| that matches |type| as an
// FFmpegDemuxerStream.
@@ -236,18 +225,6 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol {
// this object.
scoped_refptr<DataSource> data_source_;
- // This member is used to block on read method calls from FFmpeg and wait
- // until the asynchronous reads in the data source to complete. It is also
- // signaled when the demuxer is being stopped.
- base::WaitableEvent read_event_;
-
- // Flag to indicate if read has ever failed. Once set to true, it will
- // never be reset. This flag is set true and accessed in Read().
- bool read_has_failed_;
-
- int last_read_bytes_;
- int64 read_position_;
-
// Derived bitrate after initialization has completed.
int bitrate_;
@@ -264,6 +241,8 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol {
// stream -- at this moment we definitely know duration.
bool duration_known_;
+ // FFmpegURLProtocol implementation and corresponding glue bits.
+ BlockingUrlProtocol url_protocol_;
scoped_ptr<FFmpegGlue> glue_;
DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxer);
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index b86008b..2aff102 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -72,17 +72,13 @@ class FFmpegDemuxerTest : public testing::Test {
}
void CreateDemuxer(const std::string& name) {
- CreateDemuxer(name, false);
- }
-
- void CreateDemuxer(const std::string& name, bool disable_file_size) {
CHECK(!demuxer_);
EXPECT_CALL(host_, SetTotalBytes(_)).Times(AnyNumber());
EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber());
EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber());
- CreateDataSource(name, disable_file_size);
+ CreateDataSource(name);
demuxer_ = new FFmpegDemuxer(message_loop_.message_loop_proxy(),
data_source_);
}
@@ -160,7 +156,7 @@ class FFmpegDemuxerTest : public testing::Test {
}
private:
- void CreateDataSource(const std::string& name, bool disable_file_size) {
+ void CreateDataSource(const std::string& name) {
CHECK(!data_source_);
FilePath file_path;
@@ -171,7 +167,7 @@ class FFmpegDemuxerTest : public testing::Test {
.Append(FILE_PATH_LITERAL("data"))
.AppendASCII(name);
- data_source_ = new FileDataSource(disable_file_size);
+ data_source_ = new FileDataSource();
EXPECT_TRUE(data_source_->Initialize(file_path.MaybeAsASCII()));
}
@@ -191,7 +187,7 @@ TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) {
// avformat_open_input(), but has avformat_find_stream_info() fail.
//
//TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) {
-// CreateDemuxer("find_stream_info_fail.webm");
+// ("find_stream_info_fail.webm");
// demuxer_->Initialize(
// &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE));
// message_loop_.RunAllPending();
@@ -347,7 +343,7 @@ TEST_F(FFmpegDemuxerTest, Read_EndOfStream) {
TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration) {
// Verify that end of stream buffers are created.
- CreateDemuxer("bear-320x240.webm", false);
+ CreateDemuxer("bear-320x240.webm");
InitializeDemuxer();
set_duration_known(false);
EXPECT_CALL(host_, SetDuration(_));
@@ -529,86 +525,6 @@ TEST_F(FFmpegDemuxerTest, DisableAudioStream) {
EXPECT_TRUE(got_eos_buffer);
}
-TEST_F(FFmpegDemuxerTest, ProtocolRead) {
- CreateDemuxer("bear-320x240.webm");
- InitializeDemuxer();
-
- // Set read head to zero as Initialize() will have parsed a bit of the file.
- int64 position = 0;
- EXPECT_TRUE(demuxer_->SetPosition(0));
- EXPECT_TRUE(demuxer_->GetPosition(&position));
- EXPECT_EQ(0, position);
-
- // Read 32 bytes from offset zero and verify position.
- uint8 buffer[32];
- EXPECT_EQ(32, demuxer_->Read(32, buffer));
- EXPECT_TRUE(demuxer_->GetPosition(&position));
- EXPECT_EQ(32, position);
-
- // Read an additional 32 bytes and verify position.
- EXPECT_EQ(32, demuxer_->Read(32, buffer));
- EXPECT_TRUE(demuxer_->GetPosition(&position));
- EXPECT_EQ(64, position);
-
- // Seek to end and read until EOF.
- int64 size = 0;
- EXPECT_TRUE(demuxer_->GetSize(&size));
- EXPECT_TRUE(demuxer_->SetPosition(size - 48));
- EXPECT_EQ(32, demuxer_->Read(32, buffer));
- EXPECT_TRUE(demuxer_->GetPosition(&position));
- EXPECT_EQ(size - 16, position);
-
- EXPECT_EQ(16, demuxer_->Read(32, buffer));
- EXPECT_TRUE(demuxer_->GetPosition(&position));
- EXPECT_EQ(size, position);
-
- EXPECT_EQ(0, demuxer_->Read(32, buffer));
- EXPECT_TRUE(demuxer_->GetPosition(&position));
- EXPECT_EQ(size, position);
-
- demuxer_->Stop(NewExpectedClosure());
- message_loop_.RunAllPending();
-}
-
-TEST_F(FFmpegDemuxerTest, ProtocolGetSetPosition) {
- CreateDemuxer("bear-320x240.webm");
- InitializeDemuxer();
-
- InSequence s;
-
- int64 size;
- int64 position;
- EXPECT_TRUE(demuxer_->GetSize(&size));
- EXPECT_TRUE(demuxer_->GetPosition(&position));
-
- EXPECT_TRUE(demuxer_->SetPosition(512));
- EXPECT_FALSE(demuxer_->SetPosition(size));
- EXPECT_FALSE(demuxer_->SetPosition(size + 1));
- EXPECT_FALSE(demuxer_->SetPosition(-1));
- EXPECT_TRUE(demuxer_->GetPosition(&position));
- EXPECT_EQ(512, position);
-}
-
-TEST_F(FFmpegDemuxerTest, ProtocolGetSize) {
- CreateDemuxer("bear-320x240.webm");
- InitializeDemuxer();
-
- int64 data_source_size = 0;
- int64 demuxer_size = 0;
- EXPECT_TRUE(data_source_->GetSize(&data_source_size));
- EXPECT_TRUE(demuxer_->GetSize(&demuxer_size));
- EXPECT_NE(0, data_source_size);
- EXPECT_EQ(data_source_size, demuxer_size);
-}
-
-TEST_F(FFmpegDemuxerTest, ProtocolIsStreaming) {
- CreateDemuxer("bear-320x240.webm");
- InitializeDemuxer();
-
- EXPECT_FALSE(data_source_->IsStreaming());
- EXPECT_FALSE(demuxer_->IsStreaming());
-}
-
// Verify that seek works properly when the WebM cues data is at the start of
// the file instead of at the end.
TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
diff --git a/media/filters/file_data_source.cc b/media/filters/file_data_source.cc
index ceb7a5a..d8376b5 100644
--- a/media/filters/file_data_source.cc
+++ b/media/filters/file_data_source.cc
@@ -15,13 +15,8 @@ namespace media {
FileDataSource::FileDataSource()
: file_(NULL),
file_size_(0),
- disable_file_size_(false) {
-}
-
-FileDataSource::FileDataSource(bool disable_file_size)
- : file_(NULL),
- file_size_(0),
- disable_file_size_(disable_file_size) {
+ force_read_errors_(false),
+ force_streaming_(false) {
}
bool FileDataSource::Initialize(const std::string& url) {
@@ -63,7 +58,8 @@ void FileDataSource::Read(int64 position, int size, uint8* data,
const DataSource::ReadCB& read_cb) {
DCHECK(file_);
base::AutoLock l(lock_);
- if (file_) {
+
+ if (!force_read_errors_ && file_) {
#if defined(OS_WIN)
if (_fseeki64(file_, position, SEEK_SET)) {
read_cb.Run(DataSource::kReadError);
@@ -92,11 +88,11 @@ bool FileDataSource::GetSize(int64* size_out) {
DCHECK(file_);
base::AutoLock l(lock_);
*size_out = file_size_;
- return (NULL != file_ && !disable_file_size_);
+ return file_;
}
bool FileDataSource::IsStreaming() {
- return false;
+ return force_streaming_;
}
void FileDataSource::SetBitrate(int bitrate) {}
diff --git a/media/filters/file_data_source.h b/media/filters/file_data_source.h
index d5b81a4..a2c728d 100644
--- a/media/filters/file_data_source.h
+++ b/media/filters/file_data_source.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/gtest_prod_util.h"
#include "base/synchronization/lock.h"
#include "media/base/data_source.h"
@@ -18,7 +17,6 @@ namespace media {
class MEDIA_EXPORT FileDataSource : public DataSource {
public:
FileDataSource();
- FileDataSource(bool disable_file_size);
bool Initialize(const std::string& url);
@@ -31,6 +29,10 @@ class MEDIA_EXPORT FileDataSource : public DataSource {
virtual bool IsStreaming() OVERRIDE;
virtual void SetBitrate(int bitrate) OVERRIDE;
+ // Unit test helpers. Recreate the object if you want the default behaviour.
+ void force_read_errors_for_testing() { force_read_errors_ = true; }
+ void force_streaming_for_testing() { force_streaming_ = true; }
+
protected:
virtual ~FileDataSource();
@@ -44,17 +46,12 @@ class MEDIA_EXPORT FileDataSource : public DataSource {
// Size of the file in bytes.
int64 file_size_;
- // True if the FileDataSource should ignore its set file size, false
- // otherwise.
- bool disable_file_size_;
-
- // Critical section that protects all of the DataSource methods to prevent
- // a Stop from happening while in the middle of a file I/O operation.
- // TODO(ralphl): Ideally this would use asynchronous I/O or we will know
- // that we will block for a short period of time in reads. Otherwise, we can
- // hang the pipeline Stop.
+ // Serialize all operations to prevent stopping during reads.
base::Lock lock_;
+ bool force_read_errors_;
+ bool force_streaming_;
+
DISALLOW_COPY_AND_ASSIGN(FileDataSource);
};
diff --git a/media/media.gyp b/media/media.gyp
index 9fb5f37..d3b12c6 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -253,6 +253,8 @@
'filters/audio_renderer_algorithm.h',
'filters/audio_renderer_impl.cc',
'filters/audio_renderer_impl.h',
+ 'filters/blocking_url_protocol.cc',
+ 'filters/blocking_url_protocol.h',
'filters/chunk_demuxer.cc',
'filters/chunk_demuxer.h',
'filters/decrypting_audio_decoder.cc',
@@ -365,6 +367,8 @@
'filters/audio_file_reader.h',
'filters/chunk_demuxer.cc',
'filters/chunk_demuxer.h',
+ 'filters/blocking_url_protocol.cc',
+ 'filters/blocking_url_protocol.h',
'filters/ffmpeg_audio_decoder.cc',
'filters/ffmpeg_audio_decoder.h',
'filters/ffmpeg_demuxer.cc',
@@ -647,6 +651,7 @@
'ffmpeg/ffmpeg_common_unittest.cc',
'filters/audio_renderer_algorithm_unittest.cc',
'filters/audio_renderer_impl_unittest.cc',
+ 'filters/blocking_url_protocol_unittest.cc',
'filters/chunk_demuxer_unittest.cc',
'filters/decrypting_audio_decoder_unittest.cc',
'filters/decrypting_video_decoder_unittest.cc',
@@ -713,6 +718,7 @@
'base/test_data_util.cc',
'base/test_data_util.h',
'ffmpeg/ffmpeg_common_unittest.cc',
+ 'filters/blocking_url_protocol_unittest.cc',
'filters/chunk_demuxer_unittest.cc',
'filters/ffmpeg_audio_decoder_unittest.cc',
'filters/ffmpeg_demuxer_unittest.cc',