OLD | NEW |
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 <algorithm> | 5 #include <algorithm> |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/string_split.h" |
| 11 #include "base/strings/string_util.h" |
9 #include "media/base/audio_decoder_config.h" | 12 #include "media/base/audio_decoder_config.h" |
10 #include "media/base/decoder_buffer.h" | 13 #include "media/base/decoder_buffer.h" |
11 #include "media/base/decrypt_config.h" | 14 #include "media/base/decrypt_config.h" |
12 #include "media/base/mock_demuxer_host.h" | 15 #include "media/base/mock_demuxer_host.h" |
13 #include "media/base/test_data_util.h" | 16 #include "media/base/test_data_util.h" |
14 #include "media/base/test_helpers.h" | 17 #include "media/base/test_helpers.h" |
15 #include "media/filters/chunk_demuxer.h" | 18 #include "media/filters/chunk_demuxer.h" |
16 #include "media/webm/cluster_builder.h" | 19 #include "media/webm/cluster_builder.h" |
17 #include "media/webm/webm_constants.h" | 20 #include "media/webm/webm_constants.h" |
18 #include "media/webm/webm_crypto_helpers.h" | 21 #include "media/webm/webm_crypto_helpers.h" |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 AppendData(kSourceId, data, length); | 285 AppendData(kSourceId, data, length); |
283 } | 286 } |
284 | 287 |
285 void AppendCluster(int timecode, int block_count) { | 288 void AppendCluster(int timecode, int block_count) { |
286 scoped_ptr<Cluster> cluster(GenerateCluster(timecode, block_count)); | 289 scoped_ptr<Cluster> cluster(GenerateCluster(timecode, block_count)); |
287 AppendData(kSourceId, cluster->data(), cluster->size()); | 290 AppendData(kSourceId, cluster->data(), cluster->size()); |
288 } | 291 } |
289 | 292 |
290 void AppendSingleStreamCluster(const std::string& source_id, int track_number, | 293 void AppendSingleStreamCluster(const std::string& source_id, int track_number, |
291 int timecode, int block_count) { | 294 int timecode, int block_count) { |
292 static const int kVideoTrackNum = 1; | |
293 static const int kAudioTrackNum = 2; | |
294 | |
295 static const int kAudioBlockDuration = 23; | |
296 static const int kVideoBlockDuration = 33; | |
297 | |
298 int block_duration = 0; | 295 int block_duration = 0; |
299 switch(track_number) { | 296 switch(track_number) { |
300 case kVideoTrackNum: | 297 case kVideoTrackNum: |
301 block_duration = kVideoBlockDuration; | 298 block_duration = kVideoBlockDuration; |
302 break; | 299 break; |
303 case kAudioTrackNum: | 300 case kAudioTrackNum: |
304 block_duration = kAudioBlockDuration; | 301 block_duration = kAudioBlockDuration; |
305 break; | 302 break; |
306 } | 303 } |
307 ASSERT_NE(block_duration, 0); | 304 ASSERT_NE(block_duration, 0); |
308 int end_timecode = timecode + block_count * block_duration; | 305 int end_timecode = timecode + block_count * block_duration; |
309 scoped_ptr<Cluster> cluster(GenerateSingleStreamCluster( | 306 scoped_ptr<Cluster> cluster(GenerateSingleStreamCluster( |
310 timecode, end_timecode, track_number, block_duration)); | 307 timecode, end_timecode, track_number, block_duration)); |
311 AppendData(source_id, cluster->data(), cluster->size()); | 308 AppendData(source_id, cluster->data(), cluster->size()); |
312 } | 309 } |
313 | 310 |
| 311 void AppendSingleStreamCluster(const std::string& source_id, int track_number, |
| 312 const std::string& cluster_description) { |
| 313 std::vector<std::string> timestamps; |
| 314 base::SplitString(cluster_description, ' ', ×tamps); |
| 315 |
| 316 ClusterBuilder cb; |
| 317 std::vector<uint8> data(10); |
| 318 for (size_t i = 0; i < timestamps.size(); ++i) { |
| 319 std::string timestamp_str = timestamps[i]; |
| 320 int block_flags = 0; |
| 321 if (EndsWith(timestamp_str, "K", true)) { |
| 322 block_flags = kWebMFlagKeyframe; |
| 323 // Remove the "K" off of the token. |
| 324 timestamp_str = timestamp_str.substr(0, timestamps[i].length() - 1); |
| 325 } |
| 326 int timestamp_in_ms; |
| 327 CHECK(base::StringToInt(timestamp_str, ×tamp_in_ms)); |
| 328 |
| 329 if (i == 0) |
| 330 cb.SetClusterTimecode(timestamp_in_ms); |
| 331 |
| 332 cb.AddSimpleBlock(track_number, timestamp_in_ms, block_flags, |
| 333 &data[0], data.size()); |
| 334 } |
| 335 scoped_ptr<Cluster> cluster(cb.Finish()); |
| 336 AppendData(source_id, cluster->data(), cluster->size()); |
| 337 } |
314 | 338 |
315 void AppendData(const std::string& source_id, | 339 void AppendData(const std::string& source_id, |
316 const uint8* data, size_t length) { | 340 const uint8* data, size_t length) { |
317 EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber()); | 341 EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber()); |
318 demuxer_->AppendData(source_id, data, length); | 342 demuxer_->AppendData(source_id, data, length); |
319 } | 343 } |
320 | 344 |
321 void AppendDataInPieces(const uint8* data, size_t length) { | 345 void AppendDataInPieces(const uint8* data, size_t length) { |
322 AppendDataInPieces(data, length, 7); | 346 AppendDataInPieces(data, length, 7); |
323 } | 347 } |
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 message_loop_.RunUntilIdle(); | 750 message_loop_.RunUntilIdle(); |
727 } | 751 } |
728 | 752 |
729 void ExpectConfigChanged(DemuxerStream::Type type) { | 753 void ExpectConfigChanged(DemuxerStream::Type type) { |
730 EXPECT_CALL(*this, ReadDone(DemuxerStream::kConfigChanged, _)); | 754 EXPECT_CALL(*this, ReadDone(DemuxerStream::kConfigChanged, _)); |
731 demuxer_->GetStream(type)->Read(base::Bind( | 755 demuxer_->GetStream(type)->Read(base::Bind( |
732 &ChunkDemuxerTest::ReadDone, base::Unretained(this))); | 756 &ChunkDemuxerTest::ReadDone, base::Unretained(this))); |
733 message_loop_.RunUntilIdle(); | 757 message_loop_.RunUntilIdle(); |
734 } | 758 } |
735 | 759 |
| 760 void CheckExpectedBuffers(DemuxerStream* stream, |
| 761 const std::string& expected) { |
| 762 std::vector<std::string> timestamps; |
| 763 base::SplitString(expected, ' ', ×tamps); |
| 764 std::stringstream ss; |
| 765 for (size_t i = 0; i < timestamps.size(); ++i) { |
| 766 DemuxerStream::Status status; |
| 767 scoped_refptr<DecoderBuffer> buffer; |
| 768 stream->Read(base::Bind(&ChunkDemuxerTest::StoreStatusAndBuffer, |
| 769 base::Unretained(this), &status, &buffer)); |
| 770 base::MessageLoop::current()->RunUntilIdle(); |
| 771 if (status != DemuxerStream::kOk || buffer->end_of_stream()) |
| 772 break; |
| 773 |
| 774 if (i > 0) |
| 775 ss << " "; |
| 776 ss << buffer->timestamp().InMilliseconds(); |
| 777 } |
| 778 EXPECT_EQ(expected, ss.str()); |
| 779 } |
| 780 |
736 MOCK_METHOD1(Checkpoint, void(int id)); | 781 MOCK_METHOD1(Checkpoint, void(int id)); |
737 | 782 |
738 struct BufferTimestamps { | 783 struct BufferTimestamps { |
739 int video_time_ms; | 784 int video_time_ms; |
740 int audio_time_ms; | 785 int audio_time_ms; |
741 }; | 786 }; |
742 static const int kSkip = -1; | 787 static const int kSkip = -1; |
743 | 788 |
744 // Test parsing a WebM file. | 789 // Test parsing a WebM file. |
745 // |filename| - The name of the file in media/test/data to parse. | 790 // |filename| - The name of the file in media/test/data to parse. |
(...skipping 1917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2663 EXPECT_CALL(*this, DemuxerOpened()); | 2708 EXPECT_CALL(*this, DemuxerOpened()); |
2664 demuxer_->Initialize( | 2709 demuxer_->Initialize( |
2665 &host_, CreateInitDoneCB(kNoTimestamp(), PIPELINE_OK)); | 2710 &host_, CreateInitDoneCB(kNoTimestamp(), PIPELINE_OK)); |
2666 | 2711 |
2667 EXPECT_EQ(ChunkDemuxer::kOk, AddId(kSourceId, true, true)); | 2712 EXPECT_EQ(ChunkDemuxer::kOk, AddId(kSourceId, true, true)); |
2668 | 2713 |
2669 demuxer_->Remove(kSourceId, base::TimeDelta::FromMilliseconds(0), | 2714 demuxer_->Remove(kSourceId, base::TimeDelta::FromMilliseconds(0), |
2670 base::TimeDelta::FromMilliseconds(1)); | 2715 base::TimeDelta::FromMilliseconds(1)); |
2671 } | 2716 } |
2672 | 2717 |
| 2718 TEST_F(ChunkDemuxerTest, AppendWindow) { |
| 2719 ASSERT_TRUE(InitDemuxer(false, true)); |
| 2720 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
| 2721 |
| 2722 // Set the append window to [20,280). |
| 2723 demuxer_->SetAppendWindowStart(kSourceId, |
| 2724 base::TimeDelta::FromMilliseconds(20)); |
| 2725 demuxer_->SetAppendWindowEnd(kSourceId, |
| 2726 base::TimeDelta::FromMilliseconds(280)); |
| 2727 |
| 2728 // Append a cluster that starts before and ends after the append window. |
| 2729 AppendSingleStreamCluster(kSourceId, kVideoTrackNum, |
| 2730 "0K 30 60 90 120K 150 180 210 240K 270 300 330K"); |
| 2731 |
| 2732 // Verify that GOPs that start outside the window are not included |
| 2733 // in the buffer. Also verify that buffers that extend beyond the |
| 2734 // window are not included. |
| 2735 CheckExpectedRanges(kSourceId, "{ [120,300) }"); |
| 2736 CheckExpectedBuffers(stream, "120 150 180 210 240 270"); |
| 2737 |
| 2738 // Extend the append window to [20,650). |
| 2739 demuxer_->SetAppendWindowEnd(kSourceId, |
| 2740 base::TimeDelta::FromMilliseconds(650)); |
| 2741 |
| 2742 // Append more data and verify that adding buffers start at the next |
| 2743 // keyframe. |
| 2744 AppendSingleStreamCluster(kSourceId, kVideoTrackNum, |
| 2745 "360 390 420K 450 480 510 540K 570 600 630K"); |
| 2746 CheckExpectedRanges(kSourceId, "{ [120,300) [420,660) }"); |
| 2747 } |
| 2748 |
2673 } // namespace media | 2749 } // namespace media |
OLD | NEW |