Updating trunk VERSION from 935.0 to 936.0
[chromium-blink-merge.git] / media / filters / ffmpeg_glue_unittest.cc
blob94258e9b85407439fadbd4d0a5a59d4b68589e5e
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/logging.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "media/base/mock_filters.h"
8 #include "media/ffmpeg/ffmpeg_common.h"
9 #include "media/filters/ffmpeg_glue.h"
10 #include "testing/gtest/include/gtest/gtest.h"
12 using ::testing::_;
13 using ::testing::DoAll;
14 using ::testing::InSequence;
15 using ::testing::Return;
16 using ::testing::SetArgumentPointee;
17 using ::testing::StrictMock;
19 namespace media {
21 class MockProtocol : public FFmpegURLProtocol {
22 public:
23 MockProtocol() {
26 MOCK_METHOD2(Read, size_t(size_t size, uint8* data));
27 MOCK_METHOD1(GetPosition, bool(int64* position_out));
28 MOCK_METHOD1(SetPosition, bool(int64 position));
29 MOCK_METHOD1(GetSize, bool(int64* size_out));
30 MOCK_METHOD0(IsStreaming, bool());
32 private:
33 DISALLOW_COPY_AND_ASSIGN(MockProtocol);
36 class FFmpegGlueTest : public ::testing::Test {
37 public:
38 FFmpegGlueTest() : protocol_(NULL) {}
40 static void SetUpTestCase() {
41 // Singleton should initialize FFmpeg.
42 CHECK(FFmpegGlue::GetInstance());
45 virtual void SetUp() {
46 // Assign our static copy of URLProtocol for the rest of the tests.
47 protocol_ = FFmpegGlue::url_protocol();
48 CHECK(protocol_);
51 MOCK_METHOD1(CheckPoint, void(int val));
53 // Helper to open a URLContext pointing to the given mocked protocol.
54 // Callers are expected to close the context at the end of their test.
55 virtual void OpenContext(MockProtocol* protocol, URLContext* context) {
56 // IsStreaming() is called when opening.
57 EXPECT_CALL(*protocol, IsStreaming()).WillOnce(Return(true));
59 // Add the protocol to the glue layer and open a context.
60 std::string key = FFmpegGlue::GetInstance()->AddProtocol(protocol);
61 memset(context, 0, sizeof(*context));
62 EXPECT_EQ(0, protocol_->url_open(context, key.c_str(), 0));
63 FFmpegGlue::GetInstance()->RemoveProtocol(protocol);
66 protected:
67 // Fixture members.
68 URLProtocol* protocol_;
70 private:
71 DISALLOW_COPY_AND_ASSIGN(FFmpegGlueTest);
74 TEST_F(FFmpegGlueTest, InitializeFFmpeg) {
75 // Make sure URLProtocol was filled out correctly.
76 EXPECT_STREQ("http", protocol_->name);
77 EXPECT_TRUE(protocol_->url_close);
78 EXPECT_TRUE(protocol_->url_open);
79 EXPECT_TRUE(protocol_->url_read);
80 EXPECT_TRUE(protocol_->url_seek);
81 EXPECT_TRUE(protocol_->url_write);
84 TEST_F(FFmpegGlueTest, AddRemoveGetProtocol) {
85 // Prepare testing data.
86 FFmpegGlue* glue = FFmpegGlue::GetInstance();
88 // Create our protocols and add them to the glue layer.
89 scoped_ptr<StrictMock<Destroyable<MockProtocol> > > protocol_a(
90 new StrictMock<Destroyable<MockProtocol> >());
91 scoped_ptr<StrictMock<Destroyable<MockProtocol> > > protocol_b(
92 new StrictMock<Destroyable<MockProtocol> >());
94 // Make sure the keys are unique.
95 std::string key_a = glue->AddProtocol(protocol_a.get());
96 std::string key_b = glue->AddProtocol(protocol_b.get());
97 EXPECT_EQ(0u, key_a.find("http://"));
98 EXPECT_EQ(0u, key_b.find("http://"));
99 EXPECT_NE(key_a, key_b);
101 // Our keys should return our protocols.
102 FFmpegURLProtocol* protocol_c;
103 FFmpegURLProtocol* protocol_d;
104 glue->GetProtocol(key_a, &protocol_c);
105 glue->GetProtocol(key_b, &protocol_d);
106 EXPECT_EQ(protocol_a.get(), protocol_c);
107 EXPECT_EQ(protocol_b.get(), protocol_d);
109 // Adding the same Protocol should create the same key and not add an extra
110 // reference.
111 std::string key_a2 = glue->AddProtocol(protocol_a.get());
112 EXPECT_EQ(key_a, key_a2);
113 glue->GetProtocol(key_a2, &protocol_c);
114 EXPECT_EQ(protocol_a.get(), protocol_c);
116 // Removes the protocols then releases our references. They should be
117 // destroyed.
118 InSequence s;
119 EXPECT_CALL(*protocol_a, OnDestroy());
120 EXPECT_CALL(*protocol_b, OnDestroy());
121 EXPECT_CALL(*this, CheckPoint(0));
123 glue->RemoveProtocol(protocol_a.get());
124 glue->GetProtocol(key_a, &protocol_c);
125 EXPECT_FALSE(protocol_c);
126 glue->GetProtocol(key_b, &protocol_d);
127 EXPECT_EQ(protocol_b.get(), protocol_d);
128 glue->RemoveProtocol(protocol_b.get());
129 glue->GetProtocol(key_b, &protocol_d);
130 EXPECT_FALSE(protocol_d);
131 protocol_a.reset();
132 protocol_b.reset();
134 // Data sources should be deleted by this point.
135 CheckPoint(0);
138 TEST_F(FFmpegGlueTest, OpenClose) {
139 // Prepare testing data.
140 FFmpegGlue* glue = FFmpegGlue::GetInstance();
142 // Create our protocol and add them to the glue layer.
143 scoped_ptr<StrictMock<Destroyable<MockProtocol> > > protocol(
144 new StrictMock<Destroyable<MockProtocol> >());
145 EXPECT_CALL(*protocol, IsStreaming()).WillOnce(Return(true));
146 std::string key = glue->AddProtocol(protocol.get());
148 // Prepare FFmpeg URLContext structure.
149 URLContext context;
150 memset(&context, 0, sizeof(context));
152 // Test opening a URLContext with a protocol that doesn't exist.
153 EXPECT_EQ(AVERROR(EIO), protocol_->url_open(&context, "foobar", 0));
155 // Test opening a URLContext with our protocol.
156 EXPECT_EQ(0, protocol_->url_open(&context, key.c_str(), 0));
157 EXPECT_EQ(URL_RDONLY, context.flags);
158 EXPECT_EQ(protocol.get(), context.priv_data);
159 EXPECT_TRUE(context.is_streamed);
161 // We're going to remove references one by one until the last reference is
162 // held by FFmpeg. Once we close the URLContext, the protocol should be
163 // destroyed.
164 InSequence s;
165 EXPECT_CALL(*this, CheckPoint(0));
166 EXPECT_CALL(*this, CheckPoint(1));
167 EXPECT_CALL(*protocol, OnDestroy());
168 EXPECT_CALL(*this, CheckPoint(2));
170 // Remove the protocol from the glue layer, releasing a reference.
171 glue->RemoveProtocol(protocol.get());
172 CheckPoint(0);
174 // Remove our own reference -- URLContext should maintain a reference.
175 CheckPoint(1);
176 protocol.reset();
178 // Close the URLContext, which should release the final reference.
179 EXPECT_EQ(0, protocol_->url_close(&context));
180 CheckPoint(2);
183 TEST_F(FFmpegGlueTest, Write) {
184 scoped_ptr<StrictMock<MockProtocol> > protocol(
185 new StrictMock<MockProtocol>());
186 URLContext context;
187 OpenContext(protocol.get(), &context);
189 const int kBufferSize = 16;
190 uint8 buffer[kBufferSize];
192 // Writing should always fail and never call the protocol.
193 EXPECT_EQ(AVERROR(EIO), protocol_->url_write(&context, NULL, 0));
194 EXPECT_EQ(AVERROR(EIO), protocol_->url_write(&context, buffer, 0));
195 EXPECT_EQ(AVERROR(EIO), protocol_->url_write(&context, buffer, kBufferSize));
197 // Destroy the protocol.
198 protocol_->url_close(&context);
201 TEST_F(FFmpegGlueTest, Read) {
202 scoped_ptr<StrictMock<MockProtocol> > protocol(
203 new StrictMock<MockProtocol>());
204 URLContext context;
205 OpenContext(protocol.get(), &context);
207 const int kBufferSize = 16;
208 uint8 buffer[kBufferSize];
210 // Reads are for the most part straight-through calls to Read().
211 InSequence s;
212 EXPECT_CALL(*protocol, Read(0, buffer))
213 .WillOnce(Return(0));
214 EXPECT_CALL(*protocol, Read(kBufferSize, buffer))
215 .WillOnce(Return(kBufferSize));
216 EXPECT_CALL(*protocol, Read(kBufferSize, buffer))
217 .WillOnce(Return(DataSource::kReadError));
219 EXPECT_EQ(0, protocol_->url_read(&context, buffer, 0));
220 EXPECT_EQ(kBufferSize, protocol_->url_read(&context, buffer, kBufferSize));
221 EXPECT_EQ(AVERROR(EIO), protocol_->url_read(&context, buffer, kBufferSize));
223 // Destroy the protocol.
224 protocol_->url_close(&context);
227 TEST_F(FFmpegGlueTest, Seek) {
228 scoped_ptr<StrictMock<MockProtocol> > protocol(
229 new StrictMock<MockProtocol>());
230 URLContext context;
231 OpenContext(protocol.get(), &context);
233 // SEEK_SET should be a straight-through call to SetPosition(), which when
234 // successful will return the result from GetPosition().
235 InSequence s;
236 EXPECT_CALL(*protocol, SetPosition(-16))
237 .WillOnce(Return(false));
239 EXPECT_CALL(*protocol, SetPosition(16))
240 .WillOnce(Return(true));
241 EXPECT_CALL(*protocol, GetPosition(_))
242 .WillOnce(DoAll(SetArgumentPointee<0>(8), Return(true)));
244 EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, -16, SEEK_SET));
245 EXPECT_EQ(8, protocol_->url_seek(&context, 16, SEEK_SET));
247 // SEEK_CUR should call GetPosition() first, and if it succeeds add the offset
248 // to the result then call SetPosition()+GetPosition().
249 EXPECT_CALL(*protocol, GetPosition(_))
250 .WillOnce(Return(false));
252 EXPECT_CALL(*protocol, GetPosition(_))
253 .WillOnce(DoAll(SetArgumentPointee<0>(8), Return(true)));
254 EXPECT_CALL(*protocol, SetPosition(16))
255 .WillOnce(Return(false));
257 EXPECT_CALL(*protocol, GetPosition(_))
258 .WillOnce(DoAll(SetArgumentPointee<0>(8), Return(true)));
259 EXPECT_CALL(*protocol, SetPosition(16))
260 .WillOnce(Return(true));
261 EXPECT_CALL(*protocol, GetPosition(_))
262 .WillOnce(DoAll(SetArgumentPointee<0>(16), Return(true)));
264 EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, 8, SEEK_CUR));
265 EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, 8, SEEK_CUR));
266 EXPECT_EQ(16, protocol_->url_seek(&context, 8, SEEK_CUR));
268 // SEEK_END should call GetSize() first, and if it succeeds add the offset
269 // to the result then call SetPosition()+GetPosition().
270 EXPECT_CALL(*protocol, GetSize(_))
271 .WillOnce(Return(false));
273 EXPECT_CALL(*protocol, GetSize(_))
274 .WillOnce(DoAll(SetArgumentPointee<0>(16), Return(true)));
275 EXPECT_CALL(*protocol, SetPosition(8))
276 .WillOnce(Return(false));
278 EXPECT_CALL(*protocol, GetSize(_))
279 .WillOnce(DoAll(SetArgumentPointee<0>(16), Return(true)));
280 EXPECT_CALL(*protocol, SetPosition(8))
281 .WillOnce(Return(true));
282 EXPECT_CALL(*protocol, GetPosition(_))
283 .WillOnce(DoAll(SetArgumentPointee<0>(8), Return(true)));
285 EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, -8, SEEK_END));
286 EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, -8, SEEK_END));
287 EXPECT_EQ(8, protocol_->url_seek(&context, -8, SEEK_END));
289 // AVSEEK_SIZE should be a straight-through call to GetSize().
290 EXPECT_CALL(*protocol, GetSize(_))
291 .WillOnce(Return(false));
293 EXPECT_CALL(*protocol, GetSize(_))
294 .WillOnce(DoAll(SetArgumentPointee<0>(16), Return(true)));
296 EXPECT_EQ(AVERROR(EIO), protocol_->url_seek(&context, 0, AVSEEK_SIZE));
297 EXPECT_EQ(16, protocol_->url_seek(&context, 0, AVSEEK_SIZE));
299 // Destroy the protocol.
300 protocol_->url_close(&context);
303 TEST_F(FFmpegGlueTest, Destroy) {
304 // Create our protocol and add them to the glue layer.
305 scoped_ptr<StrictMock<Destroyable<MockProtocol> > > protocol(
306 new StrictMock<Destroyable<MockProtocol> >());
307 std::string key = FFmpegGlue::GetInstance()->AddProtocol(protocol.get());
309 // We should expect the protocol to get destroyed when the unit test
310 // exits.
311 InSequence s;
312 EXPECT_CALL(*this, CheckPoint(0));
313 EXPECT_CALL(*protocol, OnDestroy());
315 // Remove our own reference, we shouldn't be destroyed yet.
316 CheckPoint(0);
317 protocol.reset();
319 // ~FFmpegGlue() will be called when this unit test finishes execution. By
320 // leaving something inside FFmpegGlue's map we get to test our cleanup code.
323 } // namespace media