| Index: media/formats/webm/webm_cluster_parser_unittest.cc
|
| diff --git a/media/formats/webm/webm_cluster_parser_unittest.cc b/media/formats/webm/webm_cluster_parser_unittest.cc
|
| index 7364878dfdc2d38d8bca27d12f8e95926a12adcf..55dc791c2ce5bc7e75916ad458f6aeb292abd023 100644
|
| --- a/media/formats/webm/webm_cluster_parser_unittest.cc
|
| +++ b/media/formats/webm/webm_cluster_parser_unittest.cc
|
| @@ -117,6 +117,14 @@ static bool VerifyBuffers(const WebMClusterParser::BufferQueue& audio_buffers,
|
| const WebMClusterParser::BufferQueue& text_buffers,
|
| const BlockInfo* block_info,
|
| int block_count) {
|
| + int buffer_count = audio_buffers.size() + video_buffers.size() +
|
| + text_buffers.size();
|
| + if (block_count != buffer_count) {
|
| + DVLOG(1) << __FUNCTION__ << " : block_count (" << block_count
|
| + << ") mismatches buffer_count (" << buffer_count << ")";
|
| + return false;
|
| + }
|
| +
|
| size_t audio_offset = 0;
|
| size_t video_offset = 0;
|
| size_t text_offset = 0;
|
| @@ -142,8 +150,12 @@ static bool VerifyBuffers(const WebMClusterParser::BufferQueue& audio_buffers,
|
| return false;
|
| }
|
|
|
| - if (*offset >= buffers->size())
|
| + if (*offset >= buffers->size()) {
|
| + DVLOG(1) << __FUNCTION__ << " : Too few buffers (" << buffers->size()
|
| + << ") for track_num (" << block_info[i].track_num
|
| + << "), expected at least " << *offset + 1 << " buffers";
|
| return false;
|
| + }
|
|
|
| scoped_refptr<StreamParserBuffer> buffer = (*buffers)[(*offset)++];
|
|
|
| @@ -267,6 +279,96 @@ class WebMClusterParserTest : public testing::Test {
|
| DISALLOW_COPY_AND_ASSIGN(WebMClusterParserTest);
|
| };
|
|
|
| +TEST_F(WebMClusterParserTest, HeldBackBufferHoldsBackAllTracks) {
|
| + // If a buffer is missing duration and is being held back, then all other
|
| + // tracks' buffers that have same or higher (decode) timestamp should be held
|
| + // back too to keep the timestamps emitted for a cluster monotonically
|
| + // non-decreasing and in same order as parsed.
|
| + InSequence s;
|
| +
|
| + // Reset the parser to have 3 tracks: text, video (no default frame duration),
|
| + // and audio (with a default frame duration).
|
| + TextTracks text_tracks;
|
| + text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum),
|
| + TextTrackConfig(kTextSubtitles, "", "",
|
| + "")));
|
| + base::TimeDelta default_audio_duration =
|
| + base::TimeDelta::FromMilliseconds(kTestAudioFrameDefaultDurationInMs);
|
| + ASSERT_GE(default_audio_duration, base::TimeDelta());
|
| + ASSERT_NE(kNoTimestamp(), default_audio_duration);
|
| + parser_.reset(new WebMClusterParser(kTimecodeScale,
|
| + kAudioTrackNum,
|
| + default_audio_duration,
|
| + kVideoTrackNum,
|
| + kNoTimestamp(),
|
| + text_tracks,
|
| + std::set<int64>(),
|
| + std::string(),
|
| + std::string(),
|
| + LogCB()));
|
| +
|
| + const BlockInfo kBlockInfo[] = {
|
| + { kVideoTrackNum, 0, 33, true },
|
| + { kAudioTrackNum, 0, 23, false },
|
| + { kTextTrackNum, 10, 42, false },
|
| + { kAudioTrackNum, 23, kTestAudioFrameDefaultDurationInMs, true },
|
| + { kVideoTrackNum, 33, 33, true },
|
| + { kAudioTrackNum, 36, kTestAudioFrameDefaultDurationInMs, true },
|
| + { kVideoTrackNum, 66, 33, true },
|
| + { kAudioTrackNum, 70, kTestAudioFrameDefaultDurationInMs, true },
|
| + { kAudioTrackNum, 83, kTestAudioFrameDefaultDurationInMs, true },
|
| + };
|
| +
|
| + const int kExpectedBuffersOnPartialCluster[] = {
|
| + 0, // Video simple block without DefaultDuration should be held back
|
| + 0, // Audio buffer ready, but not emitted because its TS >= held back video
|
| + 0, // Text buffer ready, but not emitted because its TS >= held back video
|
| + 0, // 2nd audio buffer ready, also not emitted for same reason as first
|
| + 4, // All previous buffers emitted, 2nd video held back with no duration
|
| + 4, // 2nd video still has no duration, 3rd audio ready but not emitted
|
| + 6, // All previous buffers emitted, 3rd video held back with no duration
|
| + 6, // 3rd video still has no duration, 4th audio ready but not emitted
|
| + 9, // Cluster end emits all buffers and 3rd video's duration is estimated
|
| + };
|
| +
|
| + ASSERT_EQ(arraysize(kBlockInfo), arraysize(kExpectedBuffersOnPartialCluster));
|
| + int block_count = arraysize(kBlockInfo);
|
| +
|
| + // Iteratively create a cluster containing the first N+1 blocks and parse all
|
| + // but the last byte of the cluster (except when N==|block_count|, just parse
|
| + // the whole cluster). Verify that the corresponding entry in
|
| + // |kExpectedBuffersOnPartialCluster| identifies the exact subset of
|
| + // |kBlockInfo| returned by the parser.
|
| + for (int i = 0; i < block_count; ++i) {
|
| + if (i > 0)
|
| + parser_->Reset();
|
| + // Since we don't know exactly the offsets of each block in the full
|
| + // cluster, build a cluster with exactly one additional block so that
|
| + // parse of all but one byte should deterministically parse all but the
|
| + // last full block. Don't |exceed block_count| blocks though.
|
| + int blocks_in_cluster = std::min(i + 2, block_count);
|
| + scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo,
|
| + blocks_in_cluster));
|
| + // Parse all but the last byte unless we need to parse the full cluster.
|
| + bool parse_full_cluster = i == (block_count - 1);
|
| + int result = parser_->Parse(cluster->data(), parse_full_cluster ?
|
| + cluster->size() : cluster->size() - 1);
|
| + if (parse_full_cluster) {
|
| + DVLOG(1) << "Verifying parse result of full cluster of "
|
| + << blocks_in_cluster << " blocks";
|
| + EXPECT_EQ(cluster->size(), result);
|
| + } else {
|
| + DVLOG(1) << "Verifying parse result of cluster of "
|
| + << blocks_in_cluster << " blocks with last block incomplete";
|
| + EXPECT_GT(cluster->size(), result);
|
| + EXPECT_LT(0, result);
|
| + }
|
| +
|
| + EXPECT_TRUE(VerifyBuffers(parser_, kBlockInfo,
|
| + kExpectedBuffersOnPartialCluster[i]));
|
| + }
|
| +}
|
| +
|
| TEST_F(WebMClusterParserTest, Reset) {
|
| InSequence s;
|
|
|
|
|