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

Side by Side Diff: media/filters/pipeline_integration_test.cc

Issue 10836304: Add support for config changes during playback to FFmpegVideoDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/pipeline_integration_test_base.h" 5 #include "media/filters/pipeline_integration_test_base.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/string_util.h"
8 #include "media/base/decoder_buffer.h" 9 #include "media/base/decoder_buffer.h"
9 #include "media/base/decryptor_client.h" 10 #include "media/base/decryptor_client.h"
10 #include "media/base/test_data_util.h" 11 #include "media/base/test_data_util.h"
11 #include "media/crypto/aes_decryptor.h" 12 #include "media/crypto/aes_decryptor.h"
12 #include "media/filters/chunk_demuxer_client.h" 13 #include "media/filters/chunk_demuxer_client.h"
13 14
14 namespace media { 15 namespace media {
15 16
16 static const char kSourceId[] = "SourceId"; 17 static const char kSourceId[] = "SourceId";
17 static const char kClearKeySystem[] = "org.w3.clearkey"; 18 static const char kClearKeySystem[] = "org.w3.clearkey";
18 static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 }; 19 static const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 };
19 20
21 static const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\"";
22 static const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\"";
23 static const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\"";
24 static const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\"";
25
20 // Key used to encrypt video track in test file "bear-320x240-encrypted.webm". 26 // Key used to encrypt video track in test file "bear-320x240-encrypted.webm".
21 static const uint8 kSecretKey[] = { 27 static const uint8 kSecretKey[] = {
22 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b, 28 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
23 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c 29 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
24 }; 30 };
25 31
32 static const int kAppendWholeFile = -1;
33
26 // Helper class that emulates calls made on the ChunkDemuxer by the 34 // Helper class that emulates calls made on the ChunkDemuxer by the
27 // Media Source API. 35 // Media Source API.
28 class MockMediaSource : public ChunkDemuxerClient { 36 class MockMediaSource : public ChunkDemuxerClient {
29 public: 37 public:
30 MockMediaSource(const std::string& filename, int initial_append_size, 38 MockMediaSource(const std::string& filename, const std::string& mimetype,
31 bool has_audio, bool has_video) 39 int initial_append_size)
32 : url_(GetTestDataURL(filename)), 40 : url_(GetTestDataURL(filename)),
33 current_position_(0), 41 current_position_(0),
34 initial_append_size_(initial_append_size), 42 initial_append_size_(initial_append_size),
35 has_audio_(has_audio), 43 mimetype_(mimetype) {
36 has_video_(has_video) {
37 file_data_ = ReadTestDataFile(filename); 44 file_data_ = ReadTestDataFile(filename);
38 45
46 if (initial_append_size_ == kAppendWholeFile)
47 initial_append_size_ = file_data_->GetDataSize();
48
39 DCHECK_GT(initial_append_size_, 0); 49 DCHECK_GT(initial_append_size_, 0);
40 DCHECK_LE(initial_append_size_, file_data_->GetDataSize()); 50 DCHECK_LE(initial_append_size_, file_data_->GetDataSize());
41 } 51 }
42 52
43 virtual ~MockMediaSource() {} 53 virtual ~MockMediaSource() {}
44 54
45 void set_decryptor_client(DecryptorClient* decryptor_client) { 55 void set_decryptor_client(DecryptorClient* decryptor_client) {
46 decryptor_client_ = decryptor_client; 56 decryptor_client_ = decryptor_client;
47 } 57 }
48 58
(...skipping 11 matching lines...) Expand all
60 70
61 void AppendData(int size) { 71 void AppendData(int size) {
62 DCHECK(chunk_demuxer_.get()); 72 DCHECK(chunk_demuxer_.get());
63 DCHECK_LT(current_position_, file_data_->GetDataSize()); 73 DCHECK_LT(current_position_, file_data_->GetDataSize());
64 DCHECK_LE(current_position_ + size, file_data_->GetDataSize()); 74 DCHECK_LE(current_position_ + size, file_data_->GetDataSize());
65 CHECK(chunk_demuxer_->AppendData( 75 CHECK(chunk_demuxer_->AppendData(
66 kSourceId, file_data_->GetData() + current_position_, size)); 76 kSourceId, file_data_->GetData() + current_position_, size));
67 current_position_ += size; 77 current_position_ += size;
68 } 78 }
69 79
80 void AppendAtTime(const base::TimeDelta& timestampOffset,
81 const uint8* pData, int size) {
82 CHECK(chunk_demuxer_->SetTimestampOffset(kSourceId, timestampOffset));
83 CHECK(chunk_demuxer_->AppendData(kSourceId, pData, size));
84 CHECK(chunk_demuxer_->SetTimestampOffset(kSourceId, base::TimeDelta()));
85 }
86
70 void EndOfStream() { 87 void EndOfStream() {
71 chunk_demuxer_->EndOfStream(PIPELINE_OK); 88 chunk_demuxer_->EndOfStream(PIPELINE_OK);
72 } 89 }
73 90
74 void Abort() { 91 void Abort() {
75 if (!chunk_demuxer_.get()) 92 if (!chunk_demuxer_.get())
76 return; 93 return;
77 chunk_demuxer_->Shutdown(); 94 chunk_demuxer_->Shutdown();
78 } 95 }
79 96
80 // ChunkDemuxerClient methods. 97 // ChunkDemuxerClient methods.
81 virtual void DemuxerOpened(ChunkDemuxer* demuxer) { 98 virtual void DemuxerOpened(ChunkDemuxer* demuxer) {
82 chunk_demuxer_ = demuxer; 99 chunk_demuxer_ = demuxer;
83 100
101 size_t semicolon = mimetype_.find(";");
102 std::string type = mimetype_.substr(0, semicolon);
103 size_t quote1 = mimetype_.find("\"");
104 size_t quote2 = mimetype_.find("\"", quote1 + 1);
105 std::string codecStr = mimetype_.substr(quote1 + 1, quote2 - quote1 - 1);
84 std::vector<std::string> codecs; 106 std::vector<std::string> codecs;
85 if (has_audio_) 107 Tokenize(codecStr, ",", &codecs);
86 codecs.push_back("vorbis");
87 108
88 if (has_video_) 109 CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk);
89 codecs.push_back("vp8");
90
91 chunk_demuxer_->AddId(kSourceId, "video/webm", codecs);
92 AppendData(initial_append_size_); 110 AppendData(initial_append_size_);
93 } 111 }
94 112
95 virtual void DemuxerClosed() { 113 virtual void DemuxerClosed() {
96 chunk_demuxer_ = NULL; 114 chunk_demuxer_ = NULL;
97 } 115 }
98 116
99 virtual void DemuxerNeedKey(scoped_array<uint8> init_data, 117 virtual void DemuxerNeedKey(scoped_array<uint8> init_data,
100 int init_data_size) { 118 int init_data_size) {
101 DCHECK(init_data.get()); 119 DCHECK(init_data.get());
102 DCHECK_GT(init_data_size, 0); 120 DCHECK_GT(init_data_size, 0);
103 DCHECK(decryptor_client_); 121 DCHECK(decryptor_client_);
104 decryptor_client_->NeedKey("", "", init_data.Pass(), init_data_size); 122 decryptor_client_->NeedKey("", "", init_data.Pass(), init_data_size);
105 } 123 }
106 124
107 private: 125 private:
108 std::string url_; 126 std::string url_;
109 scoped_refptr<DecoderBuffer> file_data_; 127 scoped_refptr<DecoderBuffer> file_data_;
110 int current_position_; 128 int current_position_;
111 int initial_append_size_; 129 int initial_append_size_;
112 bool has_audio_; 130 std::string mimetype_;
113 bool has_video_;
114 scoped_refptr<ChunkDemuxer> chunk_demuxer_; 131 scoped_refptr<ChunkDemuxer> chunk_demuxer_;
115 DecryptorClient* decryptor_client_; 132 DecryptorClient* decryptor_client_;
116 }; 133 };
117 134
118 class FakeDecryptorClient : public DecryptorClient { 135 class FakeDecryptorClient : public DecryptorClient {
119 public: 136 public:
120 FakeDecryptorClient() : decryptor_(this) {} 137 FakeDecryptorClient() : decryptor_(this) {}
121 138
122 AesDecryptor* decryptor() { 139 AesDecryptor* decryptor() {
123 return &decryptor_; 140 return &decryptor_;
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 221
205 source->set_decryptor_client(encrypted_media); 222 source->set_decryptor_client(encrypted_media);
206 223
207 message_loop_.Run(); 224 message_loop_.Run();
208 } 225 }
209 226
210 // Verifies that seeking works properly for ChunkDemuxer when the 227 // Verifies that seeking works properly for ChunkDemuxer when the
211 // seek happens while there is a pending read on the ChunkDemuxer 228 // seek happens while there is a pending read on the ChunkDemuxer
212 // and no data is available. 229 // and no data is available.
213 bool TestSeekDuringRead(const std::string& filename, 230 bool TestSeekDuringRead(const std::string& filename,
231 const std::string& mimetype,
214 int initial_append_size, 232 int initial_append_size,
215 base::TimeDelta start_seek_time, 233 base::TimeDelta start_seek_time,
216 base::TimeDelta seek_time, 234 base::TimeDelta seek_time,
217 int seek_file_position, 235 int seek_file_position,
218 int seek_append_size, 236 int seek_append_size) {
219 bool has_audio, 237 MockMediaSource source(filename, mimetype, initial_append_size);
220 bool has_video) {
221 MockMediaSource source(filename, initial_append_size, has_audio, has_video);
222 StartPipelineWithMediaSource(&source); 238 StartPipelineWithMediaSource(&source);
223 239
224 if (pipeline_status_ != PIPELINE_OK) 240 if (pipeline_status_ != PIPELINE_OK)
225 return false; 241 return false;
226 242
227 Play(); 243 Play();
228 if (!WaitUntilCurrentTimeIsAfter(start_seek_time)) 244 if (!WaitUntilCurrentTimeIsAfter(start_seek_time))
229 return false; 245 return false;
230 246
231 source.Seek(seek_file_position, seek_append_size); 247 source.Seek(seek_file_position, seek_append_size);
(...skipping 22 matching lines...) Expand all
254 270
255 Play(); 271 Play();
256 272
257 ASSERT_TRUE(WaitUntilOnEnded()); 273 ASSERT_TRUE(WaitUntilOnEnded());
258 274
259 EXPECT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1"); 275 EXPECT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1");
260 EXPECT_EQ(GetAudioHash(), "6138555be3389e6aba4c8e6f70195d50"); 276 EXPECT_EQ(GetAudioHash(), "6138555be3389e6aba4c8e6f70195d50");
261 } 277 }
262 278
263 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) { 279 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) {
264 MockMediaSource source("bear-320x240.webm", 219229, true, true); 280 MockMediaSource source("bear-320x240.webm", kWebM, 219229);
265 StartPipelineWithMediaSource(&source); 281 StartPipelineWithMediaSource(&source);
266 source.EndOfStream(); 282 source.EndOfStream();
267 ASSERT_EQ(pipeline_status_, PIPELINE_OK); 283 ASSERT_EQ(pipeline_status_, PIPELINE_OK);
268 284
269 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u); 285 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u);
270 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0); 286 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0);
271 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 2737); 287 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 2737);
272 288
273 Play(); 289 Play();
274 290
275 ASSERT_TRUE(WaitUntilOnEnded()); 291 ASSERT_TRUE(WaitUntilOnEnded());
276 source.Abort(); 292 source.Abort();
277 Stop(); 293 Stop();
278 } 294 }
279 295
296 TEST_F(PipelineIntegrationTest, MediaSource_MP4ConfigChange) {
297 MockMediaSource source("bear.640x360_dash.mp4", kMP4, kAppendWholeFile);
Ami GONE FROM CHROMIUM 2012/08/17 15:16:59 Did you forget to add this file to this CL?
acolwell GONE FROM CHROMIUM 2012/08/20 23:10:12 No. Binary file updates are here (http://coderevie
298 StartPipelineWithMediaSource(&source);
299
300 scoped_refptr<DecoderBuffer> second_file =
301 ReadTestDataFile("bear.1280x720_dash.mp4");
302
303 source.AppendAtTime(base::TimeDelta::FromSeconds(2),
304 second_file->GetData(), second_file->GetDataSize());
305
306 source.EndOfStream();
307 ASSERT_EQ(pipeline_status_, PIPELINE_OK);
308
309 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u);
310 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0);
311 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 4736);
312
313 Play();
314
315 ASSERT_TRUE(WaitUntilOnEnded());
316 source.Abort();
317 Stop();
318 }
319
280 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { 320 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) {
281 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240-16x9-aspect.webm"), 321 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240-16x9-aspect.webm"),
282 PIPELINE_OK)); 322 PIPELINE_OK));
283 Play(); 323 Play();
284 ASSERT_TRUE(WaitUntilOnEnded()); 324 ASSERT_TRUE(WaitUntilOnEnded());
285 } 325 }
286 326
287 TEST_F(PipelineIntegrationTest, EncryptedPlayback) { 327 TEST_F(PipelineIntegrationTest, EncryptedPlayback) {
288 MockMediaSource source("bear-320x240-encrypted.webm", 220788, true, true); 328 MockMediaSource source("bear-320x240-encrypted.webm", kWebM, 220788);
289 FakeDecryptorClient encrypted_media; 329 FakeDecryptorClient encrypted_media;
290 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 330 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
291 331
292 source.EndOfStream(); 332 source.EndOfStream();
293 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 333 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
294 334
295 Play(); 335 Play();
296 336
297 ASSERT_TRUE(WaitUntilOnEnded()); 337 ASSERT_TRUE(WaitUntilOnEnded());
298 source.Abort(); 338 source.Abort();
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 ASSERT_TRUE(WaitUntilOnEnded()); 378 ASSERT_TRUE(WaitUntilOnEnded());
339 379
340 // Make sure seeking after reaching the end works as expected. 380 // Make sure seeking after reaching the end works as expected.
341 ASSERT_TRUE(Seek(seek_time)); 381 ASSERT_TRUE(Seek(seek_time));
342 EXPECT_GE(pipeline_->GetMediaTime(), seek_time); 382 EXPECT_GE(pipeline_->GetMediaTime(), seek_time);
343 ASSERT_TRUE(WaitUntilOnEnded()); 383 ASSERT_TRUE(WaitUntilOnEnded());
344 } 384 }
345 385
346 // Verify audio decoder & renderer can handle aborted demuxer reads. 386 // Verify audio decoder & renderer can handle aborted demuxer reads.
347 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) { 387 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
348 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192, 388 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM,
389 8192,
349 base::TimeDelta::FromMilliseconds(464), 390 base::TimeDelta::FromMilliseconds(464),
350 base::TimeDelta::FromMilliseconds(617), 391 base::TimeDelta::FromMilliseconds(617),
351 0x10CA, 19730, true, false)); 392 0x10CA, 19730));
352 } 393 }
353 394
354 // Verify video decoder & renderer can handle aborted demuxer reads. 395 // Verify video decoder & renderer can handle aborted demuxer reads.
355 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { 396 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
356 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768, 397 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM,
398 32768,
357 base::TimeDelta::FromMilliseconds(200), 399 base::TimeDelta::FromMilliseconds(200),
358 base::TimeDelta::FromMilliseconds(1668), 400 base::TimeDelta::FromMilliseconds(1668),
359 0x1C896, 65536, false, true)); 401 0x1C896, 65536));
360 } 402 }
361 403
362 } // namespace media 404 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698