Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1272)

Unified Diff: media/filters/ffmpeg_glue_unittest.cc

Issue 10912080: Switch to AVIO instead of a custom FFmpeg URLProtocol handler. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Comments. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/filters/ffmpeg_glue_unittest.cc
diff --git a/media/filters/ffmpeg_glue_unittest.cc b/media/filters/ffmpeg_glue_unittest.cc
index 8fded220a6347815418ae89f08637276ad5ac635..18d56f9625e4335d6cecac78100ce55fcde9e7c1 100644
--- a/media/filters/ffmpeg_glue_unittest.cc
+++ b/media/filters/ffmpeg_glue_unittest.cc
@@ -5,8 +5,10 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/mock_filters.h"
+#include "media/base/test_data_util.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/ffmpeg_glue.h"
+#include "media/filters/in_memory_url_protocol.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
@@ -20,10 +22,9 @@ namespace media {
class MockProtocol : public FFmpegURLProtocol {
public:
- MockProtocol() {
- }
+ MockProtocol() {}
- MOCK_METHOD2(Read, size_t(size_t size, uint8* data));
+ MOCK_METHOD2(Read, int(int size, uint8* data));
MOCK_METHOD1(GetPosition, bool(int64* position_out));
MOCK_METHOD1(SetPosition, bool(int64 position));
MOCK_METHOD1(GetSize, bool(int64* size_out));
@@ -35,289 +36,208 @@ class MockProtocol : public FFmpegURLProtocol {
class FFmpegGlueTest : public ::testing::Test {
public:
- FFmpegGlueTest() : protocol_(NULL) {}
-
- static void SetUpTestCase() {
- // Singleton should initialize FFmpeg.
- CHECK(FFmpegGlue::GetInstance());
+ FFmpegGlueTest()
+ : protocol_(new StrictMock<MockProtocol>()) {
+ // IsStreaming() is called when opening.
+ EXPECT_CALL(*protocol_.get(), IsStreaming()).WillOnce(Return(true));
+ glue_.reset(new FFmpegGlue(protocol_.get()));
+ CHECK(glue_->format_context());
+ CHECK(glue_->format_context()->pb);
}
- virtual void SetUp() {
- // Assign our static copy of URLProtocol for the rest of the tests.
- protocol_ = FFmpegGlue::url_protocol();
- CHECK(protocol_);
- }
+ virtual ~FFmpegGlueTest() {
+ // Ensure |glue_| and |protocol_| are still alive.
+ CHECK(glue_.get());
+ CHECK(protocol_.get());
- MOCK_METHOD1(CheckPoint, void(int val));
+ // |protocol_| should outlive |glue_|, so ensure it's destructed first.
+ glue_.reset();
+ }
- // Helper to open a URLContext pointing to the given mocked protocol.
- // Callers are expected to close the context at the end of their test.
- virtual void OpenContext(MockProtocol* protocol, URLContext* context) {
- // IsStreaming() is called when opening.
- EXPECT_CALL(*protocol, IsStreaming()).WillOnce(Return(true));
+ int ReadPacket(int size, uint8* data) {
+ return glue_->format_context()->pb->read_packet(
+ protocol_.get(), data, size);
+ }
- // Add the protocol to the glue layer and open a context.
- std::string key = FFmpegGlue::GetInstance()->AddProtocol(protocol);
- memset(context, 0, sizeof(*context));
- EXPECT_EQ(0, protocol_->url_open(context, key.c_str(), 0));
- FFmpegGlue::GetInstance()->RemoveProtocol(protocol);
+ int64 Seek(int64 offset, int whence) {
+ return glue_->format_context()->pb->seek(protocol_.get(), offset, whence);
}
protected:
- // Fixture members.
- URLProtocol* protocol_;
+ scoped_ptr<FFmpegGlue> glue_;
+ scoped_ptr< StrictMock<MockProtocol> > protocol_;
private:
DISALLOW_COPY_AND_ASSIGN(FFmpegGlueTest);
};
-TEST_F(FFmpegGlueTest, InitializeFFmpeg) {
- // Make sure URLProtocol was filled out correctly.
- EXPECT_STREQ("http", protocol_->name);
- EXPECT_TRUE(protocol_->url_close);
- EXPECT_TRUE(protocol_->url_open);
- EXPECT_TRUE(protocol_->url_read);
- EXPECT_TRUE(protocol_->url_seek);
- EXPECT_TRUE(protocol_->url_write);
-}
-
-TEST_F(FFmpegGlueTest, AddRemoveGetProtocol) {
- // Prepare testing data.
- FFmpegGlue* glue = FFmpegGlue::GetInstance();
-
- // Create our protocols and add them to the glue layer.
- scoped_ptr<StrictMock<Destroyable<MockProtocol> > > protocol_a(
- new StrictMock<Destroyable<MockProtocol> >());
- scoped_ptr<StrictMock<Destroyable<MockProtocol> > > protocol_b(
- new StrictMock<Destroyable<MockProtocol> >());
-
- // Make sure the keys are unique.
- std::string key_a = glue->AddProtocol(protocol_a.get());
- std::string key_b = glue->AddProtocol(protocol_b.get());
- EXPECT_EQ(0u, key_a.find("http://"));
- EXPECT_EQ(0u, key_b.find("http://"));
- EXPECT_NE(key_a, key_b);
-
- // Our keys should return our protocols.
- FFmpegURLProtocol* protocol_c;
- FFmpegURLProtocol* protocol_d;
- glue->GetProtocol(key_a, &protocol_c);
- glue->GetProtocol(key_b, &protocol_d);
- EXPECT_EQ(protocol_a.get(), protocol_c);
- EXPECT_EQ(protocol_b.get(), protocol_d);
-
- // Adding the same Protocol should create the same key and not add an extra
- // reference.
- std::string key_a2 = glue->AddProtocol(protocol_a.get());
- EXPECT_EQ(key_a, key_a2);
- glue->GetProtocol(key_a2, &protocol_c);
- EXPECT_EQ(protocol_a.get(), protocol_c);
-
- // Removes the protocols then releases our references. They should be
- // destroyed.
- InSequence s;
- EXPECT_CALL(*protocol_a, OnDestroy());
- EXPECT_CALL(*protocol_b, OnDestroy());
- EXPECT_CALL(*this, CheckPoint(0));
-
- glue->RemoveProtocol(protocol_a.get());
- glue->GetProtocol(key_a, &protocol_c);
- EXPECT_FALSE(protocol_c);
- glue->GetProtocol(key_b, &protocol_d);
- EXPECT_EQ(protocol_b.get(), protocol_d);
- glue->RemoveProtocol(protocol_b.get());
- glue->GetProtocol(key_b, &protocol_d);
- EXPECT_FALSE(protocol_d);
- protocol_a.reset();
- protocol_b.reset();
-
- // Data sources should be deleted by this point.
- CheckPoint(0);
-}
+class FFmpegGlueDestructionTest : public ::testing::Test {
+ public:
+ FFmpegGlueDestructionTest() {}
+
+ void Initialize(const char* filename) {
+ data_ = ReadTestDataFile(filename);
+ protocol_.reset(new InMemoryUrlProtocol(
+ data_->GetData(), data_->GetDataSize(), false));
+ glue_.reset(new FFmpegGlue(protocol_.get()));
+ CHECK(glue_->format_context());
+ CHECK(glue_->format_context()->pb);
+ }
-TEST_F(FFmpegGlueTest, OpenClose) {
- // Prepare testing data.
- FFmpegGlue* glue = FFmpegGlue::GetInstance();
+ virtual ~FFmpegGlueDestructionTest() {
+ // Ensure Initialize() was called.
+ CHECK(glue_.get());
+ CHECK(protocol_.get());
- // Create our protocol and add them to the glue layer.
- scoped_ptr<StrictMock<Destroyable<MockProtocol> > > protocol(
- new StrictMock<Destroyable<MockProtocol> >());
- EXPECT_CALL(*protocol, IsStreaming()).WillOnce(Return(true));
- std::string key = glue->AddProtocol(protocol.get());
+ // |glue_| should be destroyed before |protocol_|.
+ glue_.reset();
- // Prepare FFmpeg URLContext structure.
- URLContext context;
- memset(&context, 0, sizeof(context));
+ // |protocol_| should be destroyed before |data_|.
+ protocol_.reset();
+ data_ = NULL;
+ }
- // Test opening a URLContext with a protocol that doesn't exist.
- EXPECT_EQ(AVERROR(EIO), protocol_->url_open(&context, "foobar", 0));
+ protected:
+ scoped_ptr<FFmpegGlue> glue_;
- // Test opening a URLContext with our protocol.
- EXPECT_EQ(0, protocol_->url_open(&context, key.c_str(), 0));
- EXPECT_EQ(AVIO_FLAG_READ, context.flags);
- EXPECT_EQ(protocol.get(), context.priv_data);
- EXPECT_TRUE(context.is_streamed);
+ private:
+ scoped_ptr<InMemoryUrlProtocol> protocol_;
+ scoped_refptr<DecoderBuffer> data_;
- // We're going to remove references one by one until the last reference is
- // held by FFmpeg. Once we close the URLContext, the protocol should be
- // destroyed.
- InSequence s;
- EXPECT_CALL(*this, CheckPoint(0));
- EXPECT_CALL(*this, CheckPoint(1));
- EXPECT_CALL(*protocol, OnDestroy());
- EXPECT_CALL(*this, CheckPoint(2));
-
- // Remove the protocol from the glue layer, releasing a reference.
- glue->RemoveProtocol(protocol.get());
- CheckPoint(0);
-
- // Remove our own reference -- URLContext should maintain a reference.
- CheckPoint(1);
- protocol.reset();
-
- // Close the URLContext, which should release the final reference.
- EXPECT_EQ(0, protocol_->url_close(&context));
- CheckPoint(2);
-}
+ DISALLOW_COPY_AND_ASSIGN(FFmpegGlueDestructionTest);
+};
+// Ensure writing has been disabled.
TEST_F(FFmpegGlueTest, Write) {
- scoped_ptr<StrictMock<MockProtocol> > protocol(
- new StrictMock<MockProtocol>());
- URLContext context;
- OpenContext(protocol.get(), &context);
-
- const int kBufferSize = 16;
- uint8 buffer[kBufferSize];
-
- // Writing should always fail and never call the protocol.
- EXPECT_EQ(AVERROR(EIO), protocol_->url_write(&context, NULL, 0));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_write(&context, buffer, 0));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_write(&context, buffer, kBufferSize));
-
- // Destroy the protocol.
- protocol_->url_close(&context);
+ ASSERT_FALSE(glue_->format_context()->pb->write_packet);
+ ASSERT_FALSE(glue_->format_context()->pb->write_flag);
}
+// Test both successful and unsuccessful reads pass through correctly.
TEST_F(FFmpegGlueTest, Read) {
- scoped_ptr<StrictMock<MockProtocol> > protocol(
- new StrictMock<MockProtocol>());
- URLContext context;
- OpenContext(protocol.get(), &context);
-
const int kBufferSize = 16;
uint8 buffer[kBufferSize];
// Reads are for the most part straight-through calls to Read().
InSequence s;
- EXPECT_CALL(*protocol, Read(0, buffer))
+ EXPECT_CALL(*protocol_, Read(0, buffer))
.WillOnce(Return(0));
- EXPECT_CALL(*protocol, Read(kBufferSize, buffer))
+ EXPECT_CALL(*protocol_, Read(kBufferSize, buffer))
.WillOnce(Return(kBufferSize));
- EXPECT_CALL(*protocol, Read(kBufferSize, buffer))
+ EXPECT_CALL(*protocol_, Read(kBufferSize, buffer))
.WillOnce(Return(DataSource::kReadError));
- EXPECT_EQ(0, protocol_->url_read(&context, buffer, 0));
- EXPECT_EQ(kBufferSize, protocol_->url_read(&context, buffer, kBufferSize));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_read(&context, buffer, kBufferSize));
-
- // Destroy the protocol.
- protocol_->url_close(&context);
+ EXPECT_EQ(0, ReadPacket(0, buffer));
+ EXPECT_EQ(kBufferSize, ReadPacket(kBufferSize, buffer));
+ EXPECT_EQ(AVERROR(EIO), ReadPacket(kBufferSize, buffer));
}
+// Test a variety of seek operations.
TEST_F(FFmpegGlueTest, Seek) {
- scoped_ptr<StrictMock<MockProtocol> > protocol(
- new StrictMock<MockProtocol>());
- URLContext context;
- OpenContext(protocol.get(), &context);
-
// SEEK_SET should be a straight-through call to SetPosition(), which when
// successful will return the result from GetPosition().
InSequence s;
- EXPECT_CALL(*protocol, SetPosition(-16))
+ EXPECT_CALL(*protocol_, SetPosition(-16))
.WillOnce(Return(false));
- EXPECT_CALL(*protocol, SetPosition(16))
+ EXPECT_CALL(*protocol_, SetPosition(16))
.WillOnce(Return(true));
- EXPECT_CALL(*protocol, GetPosition(_))
+ EXPECT_CALL(*protocol_, GetPosition(_))
.WillOnce(DoAll(SetArgumentPointee<0>(8), Return(true)));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, -16, SEEK_SET));
- EXPECT_EQ(8, protocol_->url_seek(&context, 16, SEEK_SET));
+ EXPECT_EQ(AVERROR(EIO), Seek(-16, SEEK_SET));
+ EXPECT_EQ(8, Seek(16, SEEK_SET));
// SEEK_CUR should call GetPosition() first, and if it succeeds add the offset
// to the result then call SetPosition()+GetPosition().
- EXPECT_CALL(*protocol, GetPosition(_))
+ EXPECT_CALL(*protocol_, GetPosition(_))
.WillOnce(Return(false));
- EXPECT_CALL(*protocol, GetPosition(_))
+ EXPECT_CALL(*protocol_, GetPosition(_))
.WillOnce(DoAll(SetArgumentPointee<0>(8), Return(true)));
- EXPECT_CALL(*protocol, SetPosition(16))
+ EXPECT_CALL(*protocol_, SetPosition(16))
.WillOnce(Return(false));
- EXPECT_CALL(*protocol, GetPosition(_))
+ EXPECT_CALL(*protocol_, GetPosition(_))
.WillOnce(DoAll(SetArgumentPointee<0>(8), Return(true)));
- EXPECT_CALL(*protocol, SetPosition(16))
+ EXPECT_CALL(*protocol_, SetPosition(16))
.WillOnce(Return(true));
- EXPECT_CALL(*protocol, GetPosition(_))
+ EXPECT_CALL(*protocol_, GetPosition(_))
.WillOnce(DoAll(SetArgumentPointee<0>(16), Return(true)));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, 8, SEEK_CUR));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, 8, SEEK_CUR));
- EXPECT_EQ(16, protocol_->url_seek(&context, 8, SEEK_CUR));
+ EXPECT_EQ(AVERROR(EIO), Seek(8, SEEK_CUR));
+ EXPECT_EQ(AVERROR(EIO), Seek(8, SEEK_CUR));
+ EXPECT_EQ(16, Seek(8, SEEK_CUR));
// SEEK_END should call GetSize() first, and if it succeeds add the offset
// to the result then call SetPosition()+GetPosition().
- EXPECT_CALL(*protocol, GetSize(_))
+ EXPECT_CALL(*protocol_, GetSize(_))
.WillOnce(Return(false));
- EXPECT_CALL(*protocol, GetSize(_))
+ EXPECT_CALL(*protocol_, GetSize(_))
.WillOnce(DoAll(SetArgumentPointee<0>(16), Return(true)));
- EXPECT_CALL(*protocol, SetPosition(8))
+ EXPECT_CALL(*protocol_, SetPosition(8))
.WillOnce(Return(false));
- EXPECT_CALL(*protocol, GetSize(_))
+ EXPECT_CALL(*protocol_, GetSize(_))
.WillOnce(DoAll(SetArgumentPointee<0>(16), Return(true)));
- EXPECT_CALL(*protocol, SetPosition(8))
+ EXPECT_CALL(*protocol_, SetPosition(8))
.WillOnce(Return(true));
- EXPECT_CALL(*protocol, GetPosition(_))
+ EXPECT_CALL(*protocol_, GetPosition(_))
.WillOnce(DoAll(SetArgumentPointee<0>(8), Return(true)));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, -8, SEEK_END));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, -8, SEEK_END));
- EXPECT_EQ(8, protocol_->url_seek(&context, -8, SEEK_END));
+ EXPECT_EQ(AVERROR(EIO), Seek(-8, SEEK_END));
+ EXPECT_EQ(AVERROR(EIO), Seek(-8, SEEK_END));
+ EXPECT_EQ(8, Seek(-8, SEEK_END));
// AVSEEK_SIZE should be a straight-through call to GetSize().
- EXPECT_CALL(*protocol, GetSize(_))
+ EXPECT_CALL(*protocol_, GetSize(_))
.WillOnce(Return(false));
- EXPECT_CALL(*protocol, GetSize(_))
+ EXPECT_CALL(*protocol_, GetSize(_))
.WillOnce(DoAll(SetArgumentPointee<0>(16), Return(true)));
- EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, 0, AVSEEK_SIZE));
- EXPECT_EQ(16, protocol_->url_seek(&context, 0, AVSEEK_SIZE));
+ EXPECT_EQ(AVERROR(EIO), Seek(0, AVSEEK_SIZE));
+ EXPECT_EQ(16, Seek(0, AVSEEK_SIZE));
+}
+
+// Ensure destruction release the appropriate resources when OpenContext() is
+// never called.
+TEST_F(FFmpegGlueDestructionTest, WithoutOpen) {
+ Initialize("ten_byte_file");
+}
- // Destroy the protocol.
- protocol_->url_close(&context);
+// Ensure destruction releases the appropriate resources when
+// avformat_open_input() fails.
+TEST_F(FFmpegGlueDestructionTest, WithOpenFailure) {
+ Initialize("ten_byte_file");
+ ASSERT_FALSE(glue_->OpenContext());
}
-TEST_F(FFmpegGlueTest, Destroy) {
- // Create our protocol and add them to the glue layer.
- scoped_ptr<StrictMock<Destroyable<MockProtocol> > > protocol(
- new StrictMock<Destroyable<MockProtocol> >());
- std::string key = FFmpegGlue::GetInstance()->AddProtocol(protocol.get());
+// Ensure destruction release the appropriate resources when OpenContext() is
+// called, but no streams have been opened.
+TEST_F(FFmpegGlueDestructionTest, WithOpenNoStreams) {
+ Initialize("no_streams.webm");
+ ASSERT_TRUE(glue_->OpenContext());
+}
- // We should expect the protocol to get destroyed when the unit test
- // exits.
- InSequence s;
- EXPECT_CALL(*this, CheckPoint(0));
- EXPECT_CALL(*protocol, OnDestroy());
+// Ensure destruction release the appropriate resources when OpenContext() is
+// called and streams exist.
+TEST_F(FFmpegGlueDestructionTest, WithOpenWithStreams) {
+ Initialize("bear-320x240.webm");
+ ASSERT_TRUE(glue_->OpenContext());
+}
- // Remove our own reference, we shouldn't be destroyed yet.
- CheckPoint(0);
- protocol.reset();
+// Ensure destruction release the appropriate resources when OpenContext() is
+// called and streams have been opened.
+TEST_F(FFmpegGlueDestructionTest, WithOpenWithOpenStreams) {
+ Initialize("bear-320x240.webm");
+ ASSERT_TRUE(glue_->OpenContext());
+ ASSERT_GT(glue_->format_context()->nb_streams, 0u);
- // ~FFmpegGlue() will be called when this unit test finishes execution. By
- // leaving something inside FFmpegGlue's map we get to test our cleanup code.
+ AVCodecContext* context = glue_->format_context()->streams[0]->codec;
+ ASSERT_EQ(avcodec_open2(
+ context, avcodec_find_decoder(context->codec_id), NULL), 0);
}
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698