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

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

Issue 10828425: Add support for config changes during playback to FFmpegVideoDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add config_change_pending_ initializers to constructors. 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
« no previous file with comments | « media/filters/ffmpeg_video_decoder.cc ('k') | media/filters/source_buffer_stream.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 229
213 source->set_decryptor_client(encrypted_media); 230 source->set_decryptor_client(encrypted_media);
214 231
215 message_loop_.Run(); 232 message_loop_.Run();
216 } 233 }
217 234
218 // Verifies that seeking works properly for ChunkDemuxer when the 235 // Verifies that seeking works properly for ChunkDemuxer when the
219 // seek happens while there is a pending read on the ChunkDemuxer 236 // seek happens while there is a pending read on the ChunkDemuxer
220 // and no data is available. 237 // and no data is available.
221 bool TestSeekDuringRead(const std::string& filename, 238 bool TestSeekDuringRead(const std::string& filename,
239 const std::string& mimetype,
222 int initial_append_size, 240 int initial_append_size,
223 base::TimeDelta start_seek_time, 241 base::TimeDelta start_seek_time,
224 base::TimeDelta seek_time, 242 base::TimeDelta seek_time,
225 int seek_file_position, 243 int seek_file_position,
226 int seek_append_size, 244 int seek_append_size) {
227 bool has_audio, 245 MockMediaSource source(filename, mimetype, initial_append_size);
228 bool has_video) {
229 MockMediaSource source(filename, initial_append_size, has_audio, has_video);
230 StartPipelineWithMediaSource(&source); 246 StartPipelineWithMediaSource(&source);
231 247
232 if (pipeline_status_ != PIPELINE_OK) 248 if (pipeline_status_ != PIPELINE_OK)
233 return false; 249 return false;
234 250
235 Play(); 251 Play();
236 if (!WaitUntilCurrentTimeIsAfter(start_seek_time)) 252 if (!WaitUntilCurrentTimeIsAfter(start_seek_time))
237 return false; 253 return false;
238 254
239 source.Seek(seek_file_position, seek_append_size); 255 source.Seek(seek_file_position, seek_append_size);
(...skipping 22 matching lines...) Expand all
262 278
263 Play(); 279 Play();
264 280
265 ASSERT_TRUE(WaitUntilOnEnded()); 281 ASSERT_TRUE(WaitUntilOnEnded());
266 282
267 EXPECT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1"); 283 EXPECT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1");
268 EXPECT_EQ(GetAudioHash(), "5699a4415b620e45b9d0aae531c9df76"); 284 EXPECT_EQ(GetAudioHash(), "5699a4415b620e45b9d0aae531c9df76");
269 } 285 }
270 286
271 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) { 287 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) {
272 MockMediaSource source("bear-320x240.webm", 219229, true, true); 288 MockMediaSource source("bear-320x240.webm", kWebM, 219229);
273 StartPipelineWithMediaSource(&source); 289 StartPipelineWithMediaSource(&source);
274 source.EndOfStream(); 290 source.EndOfStream();
275 ASSERT_EQ(pipeline_status_, PIPELINE_OK); 291 ASSERT_EQ(pipeline_status_, PIPELINE_OK);
276 292
277 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u); 293 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u);
278 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0); 294 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0);
279 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 2737); 295 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 2737);
280 296
281 Play(); 297 Play();
282 298
283 ASSERT_TRUE(WaitUntilOnEnded()); 299 ASSERT_TRUE(WaitUntilOnEnded());
284 source.Abort(); 300 source.Abort();
285 Stop(); 301 Stop();
286 } 302 }
287 303
304 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_WebM) {
305 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM,
306 kAppendWholeFile);
307 StartPipelineWithMediaSource(&source);
308
309 scoped_refptr<DecoderBuffer> second_file =
310 ReadTestDataFile("bear-640x360.webm");
311
312 source.AppendAtTime(base::TimeDelta::FromSeconds(2),
313 second_file->GetData(), second_file->GetDataSize());
314
315 source.EndOfStream();
316 ASSERT_EQ(pipeline_status_, PIPELINE_OK);
317
318 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u);
319 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0);
320 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 4763);
321
322 Play();
323
324 ASSERT_TRUE(WaitUntilOnEnded());
325 source.Abort();
326 Stop();
327 }
328
329 #if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
330 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_MP4) {
331 MockMediaSource source("bear.640x360_dash.mp4", kMP4, kAppendWholeFile);
332 StartPipelineWithMediaSource(&source);
333
334 scoped_refptr<DecoderBuffer> second_file =
335 ReadTestDataFile("bear.1280x720_dash.mp4");
336
337 source.AppendAtTime(base::TimeDelta::FromSeconds(2),
338 second_file->GetData(), second_file->GetDataSize());
339
340 source.EndOfStream();
341 ASSERT_EQ(pipeline_status_, PIPELINE_OK);
342
343 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().size(), 1u);
344 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds(), 0);
345 EXPECT_EQ(pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds(), 4736);
346
347 Play();
348
349 ASSERT_TRUE(WaitUntilOnEnded());
350 source.Abort();
351 Stop();
352 }
353 #endif
354
288 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { 355 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) {
289 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240-16x9-aspect.webm"), 356 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240-16x9-aspect.webm"),
290 PIPELINE_OK)); 357 PIPELINE_OK));
291 Play(); 358 Play();
292 ASSERT_TRUE(WaitUntilOnEnded()); 359 ASSERT_TRUE(WaitUntilOnEnded());
293 } 360 }
294 361
295 TEST_F(PipelineIntegrationTest, EncryptedPlayback) { 362 TEST_F(PipelineIntegrationTest, EncryptedPlayback) {
296 MockMediaSource source("bear-320x240-encrypted.webm", 220788, true, true); 363 MockMediaSource source("bear-320x240-encrypted.webm", kWebM, 220788);
297 FakeDecryptorClient encrypted_media; 364 FakeDecryptorClient encrypted_media;
298 StartPipelineWithEncryptedMedia(&source, &encrypted_media); 365 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
299 366
300 source.EndOfStream(); 367 source.EndOfStream();
301 ASSERT_EQ(PIPELINE_OK, pipeline_status_); 368 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
302 369
303 Play(); 370 Play();
304 371
305 ASSERT_TRUE(WaitUntilOnEnded()); 372 ASSERT_TRUE(WaitUntilOnEnded());
306 source.Abort(); 373 source.Abort();
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 ASSERT_TRUE(WaitUntilOnEnded()); 413 ASSERT_TRUE(WaitUntilOnEnded());
347 414
348 // Make sure seeking after reaching the end works as expected. 415 // Make sure seeking after reaching the end works as expected.
349 ASSERT_TRUE(Seek(seek_time)); 416 ASSERT_TRUE(Seek(seek_time));
350 EXPECT_GE(pipeline_->GetMediaTime(), seek_time); 417 EXPECT_GE(pipeline_->GetMediaTime(), seek_time);
351 ASSERT_TRUE(WaitUntilOnEnded()); 418 ASSERT_TRUE(WaitUntilOnEnded());
352 } 419 }
353 420
354 // Verify audio decoder & renderer can handle aborted demuxer reads. 421 // Verify audio decoder & renderer can handle aborted demuxer reads.
355 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) { 422 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
356 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192, 423 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM,
424 8192,
357 base::TimeDelta::FromMilliseconds(464), 425 base::TimeDelta::FromMilliseconds(464),
358 base::TimeDelta::FromMilliseconds(617), 426 base::TimeDelta::FromMilliseconds(617),
359 0x10CA, 19730, true, false)); 427 0x10CA, 19730));
360 } 428 }
361 429
362 // Verify video decoder & renderer can handle aborted demuxer reads. 430 // Verify video decoder & renderer can handle aborted demuxer reads.
363 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { 431 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
364 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768, 432 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM,
433 32768,
365 base::TimeDelta::FromMilliseconds(200), 434 base::TimeDelta::FromMilliseconds(200),
366 base::TimeDelta::FromMilliseconds(1668), 435 base::TimeDelta::FromMilliseconds(1668),
367 0x1C896, 65536, false, true)); 436 0x1C896, 65536));
368 } 437 }
369 438
370 } // namespace media 439 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_video_decoder.cc ('k') | media/filters/source_buffer_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698