Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 #include <cstdlib> | 6 #include <cstdlib> |
| 7 | 7 |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "media/base/decrypt_config.h" | 10 #include "media/base/decrypt_config.h" |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 cb.SetClusterTimecode(0); | 110 cb.SetClusterTimecode(0); |
| 111 cb.AddSimpleBlock(kVideoTrackNum, 0, 0, kEncryptedFrame, bytes_to_write); | 111 cb.AddSimpleBlock(kVideoTrackNum, 0, 0, kEncryptedFrame, bytes_to_write); |
| 112 return cb.Finish(); | 112 return cb.Finish(); |
| 113 } | 113 } |
| 114 | 114 |
| 115 static bool VerifyBuffers(const WebMClusterParser::BufferQueue& audio_buffers, | 115 static bool VerifyBuffers(const WebMClusterParser::BufferQueue& audio_buffers, |
| 116 const WebMClusterParser::BufferQueue& video_buffers, | 116 const WebMClusterParser::BufferQueue& video_buffers, |
| 117 const WebMClusterParser::BufferQueue& text_buffers, | 117 const WebMClusterParser::BufferQueue& text_buffers, |
| 118 const BlockInfo* block_info, | 118 const BlockInfo* block_info, |
| 119 int block_count) { | 119 int block_count) { |
| 120 int buffer_count = audio_buffers.size() + video_buffers.size() + | |
| 121 text_buffers.size(); | |
| 122 EXPECT_EQ(block_count, buffer_count); | |
|
acolwell GONE FROM CHROMIUM
2014/04/23 22:36:39
nit: put this in a DVLOG below since this conditio
wolenetz
2014/04/25 20:04:21
Done.
| |
| 123 if (block_count != buffer_count) | |
| 124 return false; | |
| 125 | |
| 120 size_t audio_offset = 0; | 126 size_t audio_offset = 0; |
| 121 size_t video_offset = 0; | 127 size_t video_offset = 0; |
| 122 size_t text_offset = 0; | 128 size_t text_offset = 0; |
| 123 for (int i = 0; i < block_count; i++) { | 129 for (int i = 0; i < block_count; i++) { |
| 124 const WebMClusterParser::BufferQueue* buffers = NULL; | 130 const WebMClusterParser::BufferQueue* buffers = NULL; |
| 125 size_t* offset; | 131 size_t* offset; |
| 126 StreamParserBuffer::Type expected_type = DemuxerStream::UNKNOWN; | 132 StreamParserBuffer::Type expected_type = DemuxerStream::UNKNOWN; |
| 127 | 133 |
| 128 if (block_info[i].track_num == kAudioTrackNum) { | 134 if (block_info[i].track_num == kAudioTrackNum) { |
| 129 buffers = &audio_buffers; | 135 buffers = &audio_buffers; |
| 130 offset = &audio_offset; | 136 offset = &audio_offset; |
| 131 expected_type = DemuxerStream::AUDIO; | 137 expected_type = DemuxerStream::AUDIO; |
| 132 } else if (block_info[i].track_num == kVideoTrackNum) { | 138 } else if (block_info[i].track_num == kVideoTrackNum) { |
| 133 buffers = &video_buffers; | 139 buffers = &video_buffers; |
| 134 offset = &video_offset; | 140 offset = &video_offset; |
| 135 expected_type = DemuxerStream::VIDEO; | 141 expected_type = DemuxerStream::VIDEO; |
| 136 } else if (block_info[i].track_num == kTextTrackNum) { | 142 } else if (block_info[i].track_num == kTextTrackNum) { |
| 137 buffers = &text_buffers; | 143 buffers = &text_buffers; |
| 138 offset = &text_offset; | 144 offset = &text_offset; |
| 139 expected_type = DemuxerStream::TEXT; | 145 expected_type = DemuxerStream::TEXT; |
| 140 } else { | 146 } else { |
| 141 LOG(ERROR) << "Unexpected track number " << block_info[i].track_num; | 147 LOG(ERROR) << "Unexpected track number " << block_info[i].track_num; |
| 142 return false; | 148 return false; |
| 143 } | 149 } |
| 144 | 150 |
| 151 EXPECT_LT(*offset, buffers->size()); | |
|
acolwell GONE FROM CHROMIUM
2014/04/23 22:36:39
ditto
wolenetz
2014/04/25 20:04:21
Done.
| |
| 145 if (*offset >= buffers->size()) | 152 if (*offset >= buffers->size()) |
| 146 return false; | 153 return false; |
| 147 | 154 |
| 148 scoped_refptr<StreamParserBuffer> buffer = (*buffers)[(*offset)++]; | 155 scoped_refptr<StreamParserBuffer> buffer = (*buffers)[(*offset)++]; |
| 149 | 156 |
| 150 EXPECT_EQ(block_info[i].timestamp, buffer->timestamp().InMilliseconds()); | 157 EXPECT_EQ(block_info[i].timestamp, buffer->timestamp().InMilliseconds()); |
| 151 EXPECT_EQ(std::abs(block_info[i].duration), | 158 EXPECT_EQ(std::abs(block_info[i].duration), |
| 152 buffer->duration().InMilliseconds()); | 159 buffer->duration().InMilliseconds()); |
| 153 EXPECT_EQ(expected_type, buffer->type()); | 160 EXPECT_EQ(expected_type, buffer->type()); |
| 154 EXPECT_EQ(block_info[i].track_num, buffer->track_id()); | 161 EXPECT_EQ(block_info[i].track_num, buffer->track_id()); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 260 std::string(), | 267 std::string(), |
| 261 LogCB())); | 268 LogCB())); |
| 262 } | 269 } |
| 263 | 270 |
| 264 scoped_ptr<WebMClusterParser> parser_; | 271 scoped_ptr<WebMClusterParser> parser_; |
| 265 | 272 |
| 266 private: | 273 private: |
| 267 DISALLOW_COPY_AND_ASSIGN(WebMClusterParserTest); | 274 DISALLOW_COPY_AND_ASSIGN(WebMClusterParserTest); |
| 268 }; | 275 }; |
| 269 | 276 |
| 277 TEST_F(WebMClusterParserTest, HeldBackBufferHoldsBackAllTracks) { | |
| 278 // If a buffer is missing duration and is being held back, then all other | |
| 279 // tracks' buffers that have same or higher (decode) timestamp should be held | |
| 280 // back too to keep the timestamps emitted for a cluster monotonically | |
| 281 // non-decreasing and in same order as parsed. | |
| 282 InSequence s; | |
| 283 | |
| 284 // Reset the parser to have 3 tracks: text, video (no default frame duration), | |
| 285 // and audio (with a default frame duration). | |
| 286 TextTracks text_tracks; | |
| 287 text_tracks.insert(std::make_pair(TextTracks::key_type(kTextTrackNum), | |
| 288 TextTrackConfig(kTextSubtitles, "", "", | |
| 289 ""))); | |
| 290 base::TimeDelta default_audio_duration = | |
| 291 base::TimeDelta::FromMilliseconds(kTestAudioFrameDefaultDurationInMs); | |
| 292 ASSERT_GE(default_audio_duration, base::TimeDelta()); | |
| 293 ASSERT_NE(kNoTimestamp(), default_audio_duration); | |
| 294 parser_.reset(new WebMClusterParser(kTimecodeScale, | |
| 295 kAudioTrackNum, | |
| 296 default_audio_duration, | |
| 297 kVideoTrackNum, | |
| 298 kNoTimestamp(), | |
| 299 text_tracks, | |
| 300 std::set<int64>(), | |
| 301 std::string(), | |
| 302 std::string(), | |
| 303 LogCB())); | |
| 304 | |
| 305 const BlockInfo kBlockInfo[] = { | |
| 306 { kVideoTrackNum, 0, 33, true }, | |
| 307 { kAudioTrackNum, 0, 23, false }, | |
| 308 { kTextTrackNum, 10, 42, false }, | |
| 309 { kAudioTrackNum, 23, kTestAudioFrameDefaultDurationInMs, true }, | |
| 310 { kVideoTrackNum, 33, 33, true }, | |
| 311 { kAudioTrackNum, 36, kTestAudioFrameDefaultDurationInMs, true }, | |
| 312 { kVideoTrackNum, 66, 33, true }, | |
| 313 { kAudioTrackNum, 70, kTestAudioFrameDefaultDurationInMs, true }, | |
| 314 { kAudioTrackNum, 83, kTestAudioFrameDefaultDurationInMs, true }, | |
| 315 }; | |
| 316 | |
| 317 const int kExpectedBuffersOnPartialCluster[] = { | |
| 318 0, // Video simple block without DefaultDuration should be held back | |
| 319 0, // Audio buffer ready, but not emitted because its TS >= held back video | |
| 320 0, // Text buffer ready, but not emitted because its TS >= held back video | |
| 321 0, // 2nd audio buffer ready, also not emitted for same reason as first | |
| 322 4, // All previous buffers emitted, 2nd video held back with no duration | |
| 323 4, // 2nd video still has no duration, 3rd audio ready but not emitted | |
| 324 6, // All previous buffers emitted, 3rd video held back with no duration | |
| 325 6, // 3rd video still has no duration, 4th audio ready but not emitted | |
| 326 9, // Cluster end emits all buffers and 3rd video's duration is estimated | |
| 327 }; | |
| 328 | |
| 329 ASSERT_EQ(arraysize(kBlockInfo), arraysize(kExpectedBuffersOnPartialCluster)); | |
| 330 int block_count = arraysize(kBlockInfo); | |
| 331 | |
| 332 // Iteratively create a cluster containing the first N+1 blocks and parse all | |
| 333 // but the last byte of the cluster (except when N==|block_count|, just parse | |
| 334 // the whole cluster). Verify that the corresponding entry in | |
| 335 // |kExpectedBuffersOnPartialCluster| identifies the exact subset of | |
| 336 // |kBlockInfo| returned by the parser. | |
| 337 for (int i = 0; i < block_count; ++i) { | |
| 338 if (i > 0) | |
| 339 parser_->Reset(); | |
| 340 // Since we don't know exactly the offsets of each block in the full | |
| 341 // cluster, build a cluster with exactly one additional block so that | |
| 342 // parse of all but one byte should deterministically parse all but the | |
| 343 // last full block. Don't |exceed block_count| blocks though. | |
| 344 int blocks_in_cluster = std::min(i + 2, block_count); | |
| 345 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, | |
| 346 blocks_in_cluster)); | |
| 347 // Parse all but the last byte unless we need to parse the full cluster. | |
| 348 bool parse_full_cluster = i == (block_count - 1); | |
| 349 int result = parser_->Parse(cluster->data(), parse_full_cluster ? | |
| 350 cluster->size() : cluster->size() - 1); | |
| 351 if (parse_full_cluster) { | |
| 352 DVLOG(1) << "Verifying parse result of full cluster of " | |
| 353 << blocks_in_cluster << " blocks"; | |
| 354 EXPECT_EQ(cluster->size(), result); | |
| 355 } else { | |
| 356 DVLOG(1) << "Verifying parse result of cluster of " | |
| 357 << blocks_in_cluster << " blocks with last block incomplete"; | |
| 358 EXPECT_GT(cluster->size(), result); | |
| 359 EXPECT_LT(0, result); | |
| 360 } | |
| 361 | |
| 362 EXPECT_TRUE(VerifyBuffers(parser_, kBlockInfo, | |
| 363 kExpectedBuffersOnPartialCluster[i])); | |
| 364 } | |
| 365 } | |
| 366 | |
| 270 TEST_F(WebMClusterParserTest, Reset) { | 367 TEST_F(WebMClusterParserTest, Reset) { |
| 271 InSequence s; | 368 InSequence s; |
| 272 | 369 |
| 273 int block_count = arraysize(kDefaultBlockInfo); | 370 int block_count = arraysize(kDefaultBlockInfo); |
| 274 scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count)); | 371 scoped_ptr<Cluster> cluster(CreateCluster(0, kDefaultBlockInfo, block_count)); |
| 275 | 372 |
| 276 // Send slightly less than the full cluster so all but the last block is | 373 // Send slightly less than the full cluster so all but the last block is |
| 277 // parsed. | 374 // parsed. |
| 278 int result = parser_->Parse(cluster->data(), cluster->size() - 1); | 375 int result = parser_->Parse(cluster->data(), cluster->size() - 1); |
| 279 EXPECT_GT(result, 0); | 376 EXPECT_GT(result, 0); |
| (...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 846 }; | 943 }; |
| 847 | 944 |
| 848 int block_count = arraysize(kBlockInfo); | 945 int block_count = arraysize(kBlockInfo); |
| 849 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count)); | 946 scoped_ptr<Cluster> cluster(CreateCluster(0, kBlockInfo, block_count)); |
| 850 int result = parser_->Parse(cluster->data(), cluster->size()); | 947 int result = parser_->Parse(cluster->data(), cluster->size()); |
| 851 EXPECT_EQ(cluster->size(), result); | 948 EXPECT_EQ(cluster->size(), result); |
| 852 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count)); | 949 ASSERT_TRUE(VerifyBuffers(parser_, kBlockInfo, block_count)); |
| 853 } | 950 } |
| 854 | 951 |
| 855 } // namespace media | 952 } // namespace media |
| OLD | NEW |