Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 "base/base_paths.h" | 5 #include "base/base_paths.h" |
| 6 #include "base/bind.h" | 6 #include "base/bind.h" |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/message_loop.h" | |
| 8 #include "base/path_service.h" | 9 #include "base/path_service.h" |
| 9 #include "media/base/media.h" | 10 #include "media/base/media.h" |
| 10 #include "media/base/mock_callback.h" | 11 #include "media/base/mock_callback.h" |
| 11 #include "media/base/mock_ffmpeg.h" | 12 #include "media/base/mock_ffmpeg.h" |
| 13 #include "media/base/mock_filter_host.h" | |
| 12 #include "media/filters/chunk_demuxer.h" | 14 #include "media/filters/chunk_demuxer.h" |
| 13 #include "media/filters/chunk_demuxer_client.h" | 15 #include "media/filters/chunk_demuxer_client.h" |
| 14 #include "media/webm/cluster_builder.h" | 16 #include "media/webm/cluster_builder.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 18 |
| 19 using ::testing::AnyNumber; | |
| 17 using ::testing::InSequence; | 20 using ::testing::InSequence; |
| 18 using ::testing::Return; | 21 using ::testing::Return; |
| 19 using ::testing::SetArgumentPointee; | 22 using ::testing::SetArgumentPointee; |
| 20 using ::testing::NiceMock; | 23 using ::testing::NiceMock; |
| 21 using ::testing::_; | 24 using ::testing::_; |
| 22 | 25 |
| 23 namespace media { | 26 namespace media { |
| 24 | 27 |
| 25 static const uint8 kTracksHeader[] = { | 28 static const uint8 kTracksHeader[] = { |
| 26 0x16, 0x54, 0xAE, 0x6B, // Tracks ID | 29 0x16, 0x54, 0xAE, 0x6B, // Tracks ID |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 codecs_[VIDEO].width = 320; | 68 codecs_[VIDEO].width = 320; |
| 66 codecs_[VIDEO].height = 240; | 69 codecs_[VIDEO].height = 240; |
| 67 | 70 |
| 68 codecs_[AUDIO].codec_type = AVMEDIA_TYPE_AUDIO; | 71 codecs_[AUDIO].codec_type = AVMEDIA_TYPE_AUDIO; |
| 69 codecs_[AUDIO].codec_id = CODEC_ID_VORBIS; | 72 codecs_[AUDIO].codec_id = CODEC_ID_VORBIS; |
| 70 codecs_[AUDIO].channels = 2; | 73 codecs_[AUDIO].channels = 2; |
| 71 codecs_[AUDIO].sample_rate = 44100; | 74 codecs_[AUDIO].sample_rate = 44100; |
| 72 } | 75 } |
| 73 | 76 |
| 74 virtual ~ChunkDemuxerTest() { | 77 virtual ~ChunkDemuxerTest() { |
| 78 message_loop_.RunAllPending(); | |
|
Ami GONE FROM CHROMIUM
2011/08/03 21:06:02
This makes me worry. Why do you have it?
acolwell GONE FROM CHROMIUM
2011/08/03 22:08:11
It was just catching the error on EndOfStream() ca
| |
| 75 ShutdownDemuxer(); | 79 ShutdownDemuxer(); |
| 76 } | 80 } |
| 77 | 81 |
| 78 void ReadFile(const std::string& name, scoped_array<uint8>* buffer, | 82 void ReadFile(const std::string& name, scoped_array<uint8>* buffer, |
| 79 int* size) { | 83 int* size) { |
| 80 FilePath file_path; | 84 FilePath file_path; |
| 81 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); | 85 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); |
| 82 file_path = file_path.Append(FILE_PATH_LITERAL("media")) | 86 file_path = file_path.Append(FILE_PATH_LITERAL("media")) |
| 83 .Append(FILE_PATH_LITERAL("test")) | 87 .Append(FILE_PATH_LITERAL("test")) |
| 84 .Append(FILE_PATH_LITERAL("data")) | 88 .Append(FILE_PATH_LITERAL("data")) |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 142 memcpy(buf, audio_track_entry.get(), audio_track_entry_size); | 146 memcpy(buf, audio_track_entry.get(), audio_track_entry_size); |
| 143 buf += audio_track_entry_size; | 147 buf += audio_track_entry_size; |
| 144 } | 148 } |
| 145 | 149 |
| 146 if (has_video) { | 150 if (has_video) { |
| 147 memcpy(buf, video_track_entry.get(), video_track_entry_size); | 151 memcpy(buf, video_track_entry.get(), video_track_entry_size); |
| 148 buf += video_track_entry_size; | 152 buf += video_track_entry_size; |
| 149 } | 153 } |
| 150 } | 154 } |
| 151 | 155 |
| 156 void AppendData(const uint8* data, unsigned length) { | |
| 157 EXPECT_CALL(mock_filter_host_, SetBufferedBytes(_)).Times(AnyNumber()); | |
| 158 EXPECT_CALL(mock_filter_host_, SetBufferedTime(_)).Times(AnyNumber()); | |
| 159 EXPECT_CALL(mock_filter_host_, SetNetworkActivity(true)).Times(AnyNumber()); | |
|
Ami GONE FROM CHROMIUM
2011/08/03 21:06:02
Ugh to the above three lines, and the other green
acolwell GONE FROM CHROMIUM
2011/08/03 22:08:11
Yes. Yes I can...These are on the must die list al
| |
| 160 EXPECT_TRUE(demuxer_->AppendData(data, length)); | |
| 161 message_loop_.RunAllPending(); | |
| 162 } | |
| 163 | |
| 152 void AppendInfoTracks(bool has_audio, bool has_video) { | 164 void AppendInfoTracks(bool has_audio, bool has_video) { |
| 153 EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) | 165 EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) |
| 154 .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), | 166 .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), |
| 155 Return(0))); | 167 Return(0))); |
| 156 | 168 |
| 157 EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_)) | 169 EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_)) |
| 158 .WillOnce(Return(0)); | 170 .WillOnce(Return(0)); |
| 159 | 171 |
| 160 EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_)); | 172 EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_)); |
| 161 | 173 |
| 162 EXPECT_CALL(mock_ffmpeg_, AVRegisterLockManager(_)) | 174 EXPECT_CALL(mock_ffmpeg_, AVRegisterLockManager(_)) |
| 163 .WillRepeatedly(Return(0)); | 175 .WillRepeatedly(Return(0)); |
| 164 | 176 |
| 165 scoped_array<uint8> info_tracks; | 177 scoped_array<uint8> info_tracks; |
| 166 int info_tracks_size = 0; | 178 int info_tracks_size = 0; |
| 167 CreateInfoTracks(has_audio, has_video, &info_tracks, &info_tracks_size); | 179 CreateInfoTracks(has_audio, has_video, &info_tracks, &info_tracks_size); |
| 168 | 180 |
| 169 SetupAVFormatContext(has_audio, has_video); | 181 SetupAVFormatContext(has_audio, has_video); |
| 170 | 182 |
| 171 demuxer_->AppendData(info_tracks.get(), info_tracks_size); | 183 AppendData(info_tracks.get(), info_tracks_size); |
| 172 } | 184 } |
| 173 | 185 |
| 174 static void InitDoneCalled(bool* was_called, PipelineStatus expectedStatus, | 186 static void InitDoneCalled(bool* was_called, PipelineStatus expectedStatus, |
| 175 PipelineStatus status) { | 187 PipelineStatus status) { |
| 176 EXPECT_EQ(status, expectedStatus); | 188 EXPECT_EQ(status, expectedStatus); |
| 177 *was_called = true; | 189 *was_called = true; |
| 178 } | 190 } |
| 179 | 191 |
| 180 void InitDemuxer(bool has_audio, bool has_video) { | 192 void InitDemuxer(bool has_audio, bool has_video) { |
| 181 bool init_done_called = false; | 193 bool init_done_called = false; |
| 182 PipelineStatus expectedStatus = | 194 PipelineStatus expectedStatus = |
| 183 (has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN; | 195 (has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN; |
| 184 | 196 |
| 185 EXPECT_CALL(*client_, DemuxerOpened(_)); | 197 EXPECT_CALL(*client_, DemuxerOpened(_)); |
| 186 demuxer_->Init(base::Bind(&ChunkDemuxerTest::InitDoneCalled, | 198 demuxer_->Init(base::Bind(&ChunkDemuxerTest::InitDoneCalled, |
| 187 &init_done_called, | 199 &init_done_called, |
| 188 expectedStatus)); | 200 expectedStatus)); |
| 189 | 201 |
| 190 EXPECT_FALSE(init_done_called); | 202 EXPECT_FALSE(init_done_called); |
| 191 | 203 |
| 192 AppendInfoTracks(has_audio, has_video); | 204 AppendInfoTracks(has_audio, has_video); |
| 193 | 205 |
| 194 EXPECT_TRUE(init_done_called); | 206 EXPECT_TRUE(init_done_called); |
| 207 EXPECT_CALL(mock_filter_host_, SetDuration(_)); | |
| 208 EXPECT_CALL(mock_filter_host_, SetCurrentReadPosition(_)); | |
| 209 demuxer_->set_host(&mock_filter_host_); | |
| 195 } | 210 } |
| 196 | 211 |
| 197 void ShutdownDemuxer() { | 212 void ShutdownDemuxer() { |
| 198 if (demuxer_) { | 213 if (demuxer_) { |
| 199 EXPECT_CALL(*client_, DemuxerClosed()); | 214 EXPECT_CALL(*client_, DemuxerClosed()); |
| 200 demuxer_->Shutdown(); | 215 demuxer_->Shutdown(); |
| 201 } | 216 } |
| 202 | 217 |
| 203 if (format_context_.streams) { | 218 if (format_context_.streams) { |
| 204 delete[] format_context_.streams; | 219 delete[] format_context_.streams; |
| 205 format_context_.streams = NULL; | 220 format_context_.streams = NULL; |
| 206 format_context_.nb_streams = 0; | 221 format_context_.nb_streams = 0; |
| 207 } | 222 } |
| 208 } | 223 } |
| 209 | 224 |
| 210 void AddSimpleBlock(ClusterBuilder* cb, int track_num, int64 timecode) { | 225 void AddSimpleBlock(ClusterBuilder* cb, int track_num, int64 timecode) { |
| 211 uint8 data[] = { 0x00 }; | 226 uint8 data[] = { 0x00 }; |
| 212 cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data)); | 227 cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data)); |
| 213 } | 228 } |
| 214 | 229 |
| 215 MOCK_METHOD1(Checkpoint, void(int id)); | 230 MOCK_METHOD1(Checkpoint, void(int id)); |
| 216 | 231 |
| 232 MessageLoop message_loop_; | |
|
Ami GONE FROM CHROMIUM
2011/08/03 21:06:02
I don't get where this is populated, only drained.
acolwell GONE FROM CHROMIUM
2011/08/03 22:08:11
The constructor is magical and initializes the thr
Ami GONE FROM CHROMIUM
2011/08/03 23:41:35
Per offline convo, I think you can avoid ML entire
acolwell GONE FROM CHROMIUM
2011/08/04 00:22:16
Removed
| |
| 217 MockFFmpeg mock_ffmpeg_; | 233 MockFFmpeg mock_ffmpeg_; |
| 234 MockFilterHost mock_filter_host_; | |
| 218 | 235 |
| 219 AVFormatContext format_context_; | 236 AVFormatContext format_context_; |
| 220 AVCodecContext codecs_[MAX_CODECS_INDEX]; | 237 AVCodecContext codecs_[MAX_CODECS_INDEX]; |
| 221 AVStream streams_[MAX_CODECS_INDEX]; | 238 AVStream streams_[MAX_CODECS_INDEX]; |
| 222 | 239 |
| 223 scoped_ptr<MockChunkDemuxerClient> client_; | 240 scoped_ptr<MockChunkDemuxerClient> client_; |
| 224 scoped_refptr<ChunkDemuxer> demuxer_; | 241 scoped_refptr<ChunkDemuxer> demuxer_; |
| 225 | 242 |
| 226 private: | 243 private: |
| 227 void SetupAVFormatContext(bool has_audio, bool has_video) { | 244 void SetupAVFormatContext(bool has_audio, bool has_video) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 292 | 309 |
| 293 EXPECT_CALL(*this, Checkpoint(2)); | 310 EXPECT_CALL(*this, Checkpoint(2)); |
| 294 | 311 |
| 295 ClusterBuilder cb; | 312 ClusterBuilder cb; |
| 296 cb.SetClusterTimecode(0); | 313 cb.SetClusterTimecode(0); |
| 297 AddSimpleBlock(&cb, kVideoTrackNum, 0); | 314 AddSimpleBlock(&cb, kVideoTrackNum, 0); |
| 298 scoped_ptr<Cluster> cluster(cb.Finish()); | 315 scoped_ptr<Cluster> cluster(cb.Finish()); |
| 299 | 316 |
| 300 Checkpoint(1); | 317 Checkpoint(1); |
| 301 | 318 |
| 302 EXPECT_TRUE(demuxer_->AppendData(cluster->data(), cluster->size())); | 319 AppendData(cluster->data(), cluster->size()); |
| 303 | 320 |
| 304 Checkpoint(2); | 321 Checkpoint(2); |
| 305 } | 322 } |
| 306 | 323 |
| 307 // Test the case where AppendData() is called before Init(). | 324 // Test the case where AppendData() is called before Init(). |
| 308 TEST_F(ChunkDemuxerTest, TestAppendDataBeforeInit) { | 325 TEST_F(ChunkDemuxerTest, TestAppendDataBeforeInit) { |
| 309 scoped_array<uint8> info_tracks; | 326 scoped_array<uint8> info_tracks; |
| 310 int info_tracks_size = 0; | 327 int info_tracks_size = 0; |
| 311 CreateInfoTracks(true, true, &info_tracks, &info_tracks_size); | 328 CreateInfoTracks(true, true, &info_tracks, &info_tracks_size); |
| 312 | 329 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 338 video->Read(base::Bind(&OnReadDone, | 355 video->Read(base::Bind(&OnReadDone, |
| 339 base::TimeDelta::FromMilliseconds(123), | 356 base::TimeDelta::FromMilliseconds(123), |
| 340 &video_read_done)); | 357 &video_read_done)); |
| 341 | 358 |
| 342 ClusterBuilder cb; | 359 ClusterBuilder cb; |
| 343 cb.SetClusterTimecode(0); | 360 cb.SetClusterTimecode(0); |
| 344 AddSimpleBlock(&cb, kAudioTrackNum, 32); | 361 AddSimpleBlock(&cb, kAudioTrackNum, 32); |
| 345 AddSimpleBlock(&cb, kVideoTrackNum, 123); | 362 AddSimpleBlock(&cb, kVideoTrackNum, 123); |
| 346 scoped_ptr<Cluster> cluster(cb.Finish()); | 363 scoped_ptr<Cluster> cluster(cb.Finish()); |
| 347 | 364 |
| 348 EXPECT_TRUE(demuxer_->AppendData(cluster->data(), cluster->size())); | 365 AppendData(cluster->data(), cluster->size()); |
| 349 | 366 |
| 350 EXPECT_TRUE(audio_read_done); | 367 EXPECT_TRUE(audio_read_done); |
| 351 EXPECT_TRUE(video_read_done); | 368 EXPECT_TRUE(video_read_done); |
| 352 } | 369 } |
| 353 | 370 |
| 354 TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) { | 371 TEST_F(ChunkDemuxerTest, TestOutOfOrderClusters) { |
| 355 InitDemuxer(true, true); | 372 InitDemuxer(true, true); |
| 356 | 373 |
| 357 ClusterBuilder cb; | 374 ClusterBuilder cb; |
| 358 | 375 |
| 359 cb.SetClusterTimecode(10); | 376 cb.SetClusterTimecode(10); |
| 360 AddSimpleBlock(&cb, kAudioTrackNum, 10); | 377 AddSimpleBlock(&cb, kAudioTrackNum, 10); |
| 361 AddSimpleBlock(&cb, kVideoTrackNum, 10); | 378 AddSimpleBlock(&cb, kVideoTrackNum, 10); |
| 362 AddSimpleBlock(&cb, kAudioTrackNum, 33); | 379 AddSimpleBlock(&cb, kAudioTrackNum, 33); |
| 363 AddSimpleBlock(&cb, kVideoTrackNum, 43); | 380 AddSimpleBlock(&cb, kVideoTrackNum, 43); |
| 364 scoped_ptr<Cluster> clusterA(cb.Finish()); | 381 scoped_ptr<Cluster> clusterA(cb.Finish()); |
| 365 | 382 |
| 366 EXPECT_TRUE(demuxer_->AppendData(clusterA->data(), clusterA->size())); | 383 AppendData(clusterA->data(), clusterA->size()); |
| 367 | 384 |
| 368 // Cluster B starts before clusterA and has data | 385 // Cluster B starts before clusterA and has data |
| 369 // that overlaps. | 386 // that overlaps. |
| 370 cb.SetClusterTimecode(5); | 387 cb.SetClusterTimecode(5); |
| 371 AddSimpleBlock(&cb, kAudioTrackNum, 5); | 388 AddSimpleBlock(&cb, kAudioTrackNum, 5); |
| 372 AddSimpleBlock(&cb, kVideoTrackNum, 7); | 389 AddSimpleBlock(&cb, kVideoTrackNum, 7); |
| 373 AddSimpleBlock(&cb, kAudioTrackNum, 28); | 390 AddSimpleBlock(&cb, kAudioTrackNum, 28); |
| 374 AddSimpleBlock(&cb, kVideoTrackNum, 40); | 391 AddSimpleBlock(&cb, kVideoTrackNum, 40); |
| 375 scoped_ptr<Cluster> clusterB(cb.Finish()); | 392 scoped_ptr<Cluster> clusterB(cb.Finish()); |
| 376 | 393 |
| 377 // Make sure that AppendData() fails because this cluster data | 394 // Make sure that AppendData() fails because this cluster data |
| 378 // is before previous data. | 395 // is before previous data. |
| 379 EXPECT_FALSE(demuxer_->AppendData(clusterB->data(), clusterB->size())); | 396 EXPECT_CALL(mock_filter_host_, SetError(PIPELINE_ERROR_DECODE)); |
| 397 AppendData(clusterB->data(), clusterB->size()); | |
| 380 | 398 |
| 381 // Cluster C starts after clusterA. | 399 // Verify that AppendData() doesn't accept more data now. |
| 382 cb.SetClusterTimecode(56); | 400 cb.SetClusterTimecode(45); |
| 383 AddSimpleBlock(&cb, kAudioTrackNum, 56); | 401 AddSimpleBlock(&cb, kAudioTrackNum, 45); |
| 384 AddSimpleBlock(&cb, kVideoTrackNum, 76); | 402 AddSimpleBlock(&cb, kVideoTrackNum, 45); |
| 385 AddSimpleBlock(&cb, kAudioTrackNum, 79); | |
| 386 AddSimpleBlock(&cb, kVideoTrackNum, 109); | |
| 387 scoped_ptr<Cluster> clusterC(cb.Finish()); | 403 scoped_ptr<Cluster> clusterC(cb.Finish()); |
| 388 | 404 EXPECT_FALSE(demuxer_->AppendData(clusterC->data(), clusterC->size())); |
| 389 // Verify that clusterC is accepted. | |
| 390 EXPECT_TRUE(demuxer_->AppendData(clusterC->data(), clusterC->size())); | |
| 391 | |
| 392 // Flush and try clusterB again. | |
| 393 demuxer_->FlushData(); | |
| 394 EXPECT_TRUE(demuxer_->AppendData(clusterB->data(), clusterB->size())); | |
| 395 | |
| 396 // Following that with clusterC should work too since it doesn't | |
| 397 // overlap with clusterB. | |
| 398 EXPECT_TRUE(demuxer_->AppendData(clusterC->data(), clusterC->size())); | |
| 399 } | 405 } |
| 400 | 406 |
| 401 TEST_F(ChunkDemuxerTest, TestInvalidBlockSequences) { | 407 TEST_F(ChunkDemuxerTest, TestNonMonotonicButAboveClusterTimecode) { |
| 402 InitDemuxer(true, true); | 408 InitDemuxer(true, true); |
| 403 | 409 |
| 404 ClusterBuilder cb; | 410 ClusterBuilder cb; |
| 405 | 411 |
| 406 // Test the case where timecode is not monotonically | 412 // Test the case where block timecodes are not monotonically |
| 407 // increasing but stays above the cluster timecode. | 413 // increasing but stay above the cluster timecode. |
| 408 cb.SetClusterTimecode(5); | 414 cb.SetClusterTimecode(5); |
| 409 AddSimpleBlock(&cb, kAudioTrackNum, 5); | 415 AddSimpleBlock(&cb, kAudioTrackNum, 5); |
| 410 AddSimpleBlock(&cb, kVideoTrackNum, 10); | 416 AddSimpleBlock(&cb, kVideoTrackNum, 10); |
| 411 AddSimpleBlock(&cb, kAudioTrackNum, 7); | 417 AddSimpleBlock(&cb, kAudioTrackNum, 7); |
| 412 AddSimpleBlock(&cb, kVideoTrackNum, 15); | 418 AddSimpleBlock(&cb, kVideoTrackNum, 15); |
| 413 scoped_ptr<Cluster> clusterA(cb.Finish()); | 419 scoped_ptr<Cluster> clusterA(cb.Finish()); |
| 414 | 420 |
| 415 EXPECT_FALSE(demuxer_->AppendData(clusterA->data(), clusterA->size())); | 421 EXPECT_CALL(mock_filter_host_, SetError(PIPELINE_ERROR_DECODE)); |
| 422 AppendData(clusterA->data(), clusterA->size()); | |
| 416 | 423 |
| 417 // Test timecodes going backwards before cluster timecode. | 424 // Verify that AppendData() doesn't accept more data now. |
| 425 cb.SetClusterTimecode(20); | |
| 426 AddSimpleBlock(&cb, kAudioTrackNum, 20); | |
| 427 AddSimpleBlock(&cb, kVideoTrackNum, 20); | |
| 428 scoped_ptr<Cluster> clusterB(cb.Finish()); | |
| 429 EXPECT_FALSE(demuxer_->AppendData(clusterB->data(), clusterB->size())); | |
| 430 } | |
| 431 | |
| 432 TEST_F(ChunkDemuxerTest, TestBackwardsAndBeforeClusterTimecode) { | |
| 433 InitDemuxer(true, true); | |
| 434 | |
| 435 ClusterBuilder cb; | |
| 436 | |
| 437 // Test timecodes going backwards and including values less than the cluster | |
| 438 // timecode. | |
| 418 cb.SetClusterTimecode(5); | 439 cb.SetClusterTimecode(5); |
| 419 AddSimpleBlock(&cb, kAudioTrackNum, 5); | 440 AddSimpleBlock(&cb, kAudioTrackNum, 5); |
| 420 AddSimpleBlock(&cb, kVideoTrackNum, 5); | 441 AddSimpleBlock(&cb, kVideoTrackNum, 5); |
| 421 AddSimpleBlock(&cb, kAudioTrackNum, 3); | 442 AddSimpleBlock(&cb, kAudioTrackNum, 3); |
| 422 AddSimpleBlock(&cb, kVideoTrackNum, 3); | 443 AddSimpleBlock(&cb, kVideoTrackNum, 3); |
| 444 scoped_ptr<Cluster> clusterA(cb.Finish()); | |
| 445 | |
| 446 EXPECT_CALL(mock_filter_host_, SetError(PIPELINE_ERROR_DECODE)); | |
| 447 AppendData(clusterA->data(), clusterA->size()); | |
| 448 | |
| 449 // Verify that AppendData() doesn't accept more data now. | |
| 450 cb.SetClusterTimecode(6); | |
| 451 AddSimpleBlock(&cb, kAudioTrackNum, 6); | |
| 452 AddSimpleBlock(&cb, kVideoTrackNum, 6); | |
| 423 scoped_ptr<Cluster> clusterB(cb.Finish()); | 453 scoped_ptr<Cluster> clusterB(cb.Finish()); |
| 454 EXPECT_FALSE(demuxer_->AppendData(clusterB->data(), clusterB->size())); | |
| 455 } | |
| 424 | 456 |
| 425 EXPECT_FALSE(demuxer_->AppendData(clusterB->data(), clusterB->size())); | 457 |
| 458 TEST_F(ChunkDemuxerTest, TestPerStreamMonotonicallyIncreasingTimestamps) { | |
| 459 InitDemuxer(true, true); | |
| 460 | |
| 461 ClusterBuilder cb; | |
| 426 | 462 |
| 427 // Test strict monotonic increasing timestamps on a per stream | 463 // Test strict monotonic increasing timestamps on a per stream |
| 428 // basis. | 464 // basis. |
| 429 cb.SetClusterTimecode(5); | 465 cb.SetClusterTimecode(5); |
| 430 AddSimpleBlock(&cb, kAudioTrackNum, 5); | 466 AddSimpleBlock(&cb, kAudioTrackNum, 5); |
| 431 AddSimpleBlock(&cb, kVideoTrackNum, 5); | 467 AddSimpleBlock(&cb, kVideoTrackNum, 5); |
| 432 AddSimpleBlock(&cb, kAudioTrackNum, 5); | 468 AddSimpleBlock(&cb, kAudioTrackNum, 5); |
| 433 AddSimpleBlock(&cb, kVideoTrackNum, 7); | 469 AddSimpleBlock(&cb, kVideoTrackNum, 7); |
| 434 scoped_ptr<Cluster> clusterC(cb.Finish()); | 470 scoped_ptr<Cluster> cluster(cb.Finish()); |
| 435 | 471 |
| 436 EXPECT_FALSE(demuxer_->AppendData(clusterC->data(), clusterC->size())); | 472 EXPECT_CALL(mock_filter_host_, SetError(PIPELINE_ERROR_DECODE)); |
| 473 AppendData(cluster->data(), cluster->size()); | |
| 474 } | |
| 475 | |
| 476 TEST_F(ChunkDemuxerTest, TestMonotonicallyIncreasingTimestampsAcrossClusters) { | |
| 477 InitDemuxer(true, true); | |
| 478 | |
| 479 ClusterBuilder cb; | |
| 437 | 480 |
| 438 // Test strict monotonic increasing timestamps on a per stream | 481 // Test strict monotonic increasing timestamps on a per stream |
| 439 // basis across clusters. | 482 // basis across clusters. |
| 440 cb.SetClusterTimecode(5); | 483 cb.SetClusterTimecode(5); |
| 441 AddSimpleBlock(&cb, kAudioTrackNum, 5); | 484 AddSimpleBlock(&cb, kAudioTrackNum, 5); |
| 442 AddSimpleBlock(&cb, kVideoTrackNum, 5); | 485 AddSimpleBlock(&cb, kVideoTrackNum, 5); |
| 443 scoped_ptr<Cluster> clusterD(cb.Finish()); | 486 scoped_ptr<Cluster> clusterA(cb.Finish()); |
| 444 | 487 |
| 445 EXPECT_TRUE(demuxer_->AppendData(clusterD->data(), clusterD->size())); | 488 AppendData(clusterA->data(), clusterA->size()); |
| 446 | 489 |
| 447 cb.SetClusterTimecode(5); | 490 cb.SetClusterTimecode(5); |
| 448 AddSimpleBlock(&cb, kAudioTrackNum, 5); | 491 AddSimpleBlock(&cb, kAudioTrackNum, 5); |
| 449 AddSimpleBlock(&cb, kVideoTrackNum, 7); | 492 AddSimpleBlock(&cb, kVideoTrackNum, 7); |
| 450 scoped_ptr<Cluster> clusterE(cb.Finish()); | 493 scoped_ptr<Cluster> clusterB(cb.Finish()); |
| 451 | 494 |
| 452 EXPECT_FALSE(demuxer_->AppendData(clusterE->data(), clusterE->size())); | 495 EXPECT_CALL(mock_filter_host_, SetError(PIPELINE_ERROR_DECODE)); |
| 496 AppendData(clusterB->data(), clusterB->size()); | |
| 497 | |
| 498 // Verify that AppendData() doesn't accept more data now. | |
| 499 cb.SetClusterTimecode(10); | |
| 500 AddSimpleBlock(&cb, kAudioTrackNum, 10); | |
| 501 AddSimpleBlock(&cb, kVideoTrackNum, 10); | |
| 502 scoped_ptr<Cluster> clusterC(cb.Finish()); | |
| 503 EXPECT_FALSE(demuxer_->AppendData(clusterC->data(), clusterC->size())); | |
| 453 } | 504 } |
| 454 | 505 |
| 455 // Test the case where a cluster is passed to AppendData() before | 506 // Test the case where a cluster is passed to AppendData() before |
| 456 // INFO & TRACKS data. | 507 // INFO & TRACKS data. |
| 457 TEST_F(ChunkDemuxerTest, TestClusterBeforeInfoTracks) { | 508 TEST_F(ChunkDemuxerTest, TestClusterBeforeInfoTracks) { |
| 458 EXPECT_CALL(*client_, DemuxerOpened(_)); | 509 EXPECT_CALL(*client_, DemuxerOpened(_)); |
| 459 demuxer_->Init(NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); | 510 demuxer_->Init(NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); |
| 460 | 511 |
| 461 ClusterBuilder cb; | 512 ClusterBuilder cb; |
| 462 cb.SetClusterTimecode(0); | 513 cb.SetClusterTimecode(0); |
| 463 AddSimpleBlock(&cb, kVideoTrackNum, 0); | 514 AddSimpleBlock(&cb, kVideoTrackNum, 0); |
| 464 scoped_ptr<Cluster> cluster(cb.Finish()); | 515 scoped_ptr<Cluster> cluster(cb.Finish()); |
| 465 | 516 |
| 466 EXPECT_FALSE(demuxer_->AppendData(cluster->data(), cluster->size())); | 517 AppendData(cluster->data(), cluster->size()); |
| 467 } | 518 } |
| 468 | 519 |
| 469 | |
| 470 // Test cases where we get an EndOfStream() call during initialization. | 520 // Test cases where we get an EndOfStream() call during initialization. |
| 471 TEST_F(ChunkDemuxerTest, TestEOSDuringInit) { | 521 TEST_F(ChunkDemuxerTest, TestEOSDuringInit) { |
| 472 EXPECT_CALL(*client_, DemuxerOpened(_)); | 522 EXPECT_CALL(*client_, DemuxerOpened(_)); |
| 473 demuxer_->Init(NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); | 523 demuxer_->Init(NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); |
| 474 demuxer_->EndOfStream(PIPELINE_OK); | 524 demuxer_->EndOfStream(PIPELINE_OK); |
| 475 } | 525 } |
| 526 | |
| 527 TEST_F(ChunkDemuxerTest, TestDecodeErrorEndOfStream) { | |
| 528 InitDemuxer(true, true); | |
| 529 | |
| 530 ClusterBuilder cb; | |
| 531 cb.SetClusterTimecode(0); | |
| 532 AddSimpleBlock(&cb, kAudioTrackNum, 0); | |
| 533 AddSimpleBlock(&cb, kVideoTrackNum, 0); | |
| 534 AddSimpleBlock(&cb, kAudioTrackNum, 23); | |
| 535 AddSimpleBlock(&cb, kVideoTrackNum, 33); | |
| 536 scoped_ptr<Cluster> cluster(cb.Finish()); | |
| 537 AppendData(cluster->data(), cluster->size()); | |
| 538 | |
| 539 EXPECT_CALL(mock_filter_host_, SetError(PIPELINE_ERROR_DECODE)); | |
| 540 demuxer_->EndOfStream(PIPELINE_ERROR_DECODE); | |
| 541 } | |
| 542 | |
| 543 TEST_F(ChunkDemuxerTest, TestNetworkErrorEndOfStream) { | |
| 544 InitDemuxer(true, true); | |
| 545 | |
| 546 ClusterBuilder cb; | |
| 547 cb.SetClusterTimecode(0); | |
| 548 AddSimpleBlock(&cb, kAudioTrackNum, 0); | |
| 549 AddSimpleBlock(&cb, kVideoTrackNum, 0); | |
| 550 AddSimpleBlock(&cb, kAudioTrackNum, 23); | |
| 551 AddSimpleBlock(&cb, kVideoTrackNum, 33); | |
| 552 scoped_ptr<Cluster> cluster(cb.Finish()); | |
| 553 AppendData(cluster->data(), cluster->size()); | |
| 554 | |
| 555 EXPECT_CALL(mock_filter_host_, SetError(PIPELINE_ERROR_NETWORK)); | |
| 556 demuxer_->EndOfStream(PIPELINE_ERROR_NETWORK); | |
| 557 } | |
| 558 | |
| 476 } // namespace media | 559 } // namespace media |
| OLD | NEW |