| 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 <stddef.h> | 5 #include <stddef.h> |
| 6 #include <stdint.h> | 6 #include <stdint.h> |
| 7 | 7 |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <map> |
| 9 #include <sstream> | 10 #include <sstream> |
| 10 | 11 |
| 11 #include "base/macros.h" | 12 #include "base/macros.h" |
| 12 #include "media/base/stream_parser.h" | 13 #include "media/base/stream_parser.h" |
| 13 #include "media/base/stream_parser_buffer.h" | 14 #include "media/base/stream_parser_buffer.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 15 | 16 |
| 16 namespace media { | 17 namespace media { |
| 17 | 18 |
| 18 typedef StreamParser::TrackId TrackId; | 19 typedef StreamParser::TrackId TrackId; |
| 19 typedef StreamParser::BufferQueue BufferQueue; | 20 typedef StreamParser::BufferQueue BufferQueue; |
| 20 typedef StreamParser::TextBufferQueueMap TextBufferQueueMap; | |
| 21 | 21 |
| 22 const int kEnd = -1; | 22 const int kEnd = -1; |
| 23 const uint8_t kFakeData[] = {0xFF}; | 23 const uint8_t kFakeData[] = {0xFF}; |
| 24 const TrackId kAudioTrackId = 0; | 24 const TrackId kAudioTrackId = 0; |
| 25 const TrackId kVideoTrackId = 1; | 25 const TrackId kVideoTrackId = 1; |
| 26 const TrackId kTextTrackIdA = 2; | 26 const TrackId kTextTrackIdA = 2; |
| 27 const TrackId kTextTrackIdB = 3; | 27 const TrackId kTextTrackIdB = 3; |
| 28 | 28 |
| 29 static bool IsAudio(scoped_refptr<StreamParserBuffer> buffer) { | 29 static bool IsAudio(scoped_refptr<StreamParserBuffer> buffer) { |
| 30 return buffer->type() == DemuxerStream::AUDIO; | 30 return buffer->type() == DemuxerStream::AUDIO; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 bool (*predicate)(scoped_refptr<StreamParserBuffer> buffer)) { | 71 bool (*predicate)(scoped_refptr<StreamParserBuffer> buffer)) { |
| 72 return static_cast<size_t>(count_if(merged_buffers_.begin(), | 72 return static_cast<size_t>(count_if(merged_buffers_.begin(), |
| 73 merged_buffers_.end(), | 73 merged_buffers_.end(), |
| 74 predicate)); | 74 predicate)); |
| 75 } | 75 } |
| 76 | 76 |
| 77 // Appends test audio buffers in the sequence described by |decode_timestamps| | 77 // Appends test audio buffers in the sequence described by |decode_timestamps| |
| 78 // to |audio_buffers_|. See GenerateBuffers() for |decode_timestamps| format. | 78 // to |audio_buffers_|. See GenerateBuffers() for |decode_timestamps| format. |
| 79 void GenerateAudioBuffers(const int* decode_timestamps) { | 79 void GenerateAudioBuffers(const int* decode_timestamps) { |
| 80 GenerateBuffers(decode_timestamps, DemuxerStream::AUDIO, kAudioTrackId, | 80 GenerateBuffers(decode_timestamps, DemuxerStream::AUDIO, kAudioTrackId, |
| 81 &audio_buffers_); | 81 &buffer_queue_map_[kAudioTrackId]); |
| 82 } | 82 } |
| 83 | 83 |
| 84 // Appends test video buffers in the sequence described by |decode_timestamps| | 84 // Appends test video buffers in the sequence described by |decode_timestamps| |
| 85 // to |video_buffers_|. See GenerateBuffers() for |decode_timestamps| format. | 85 // to |video_buffers_|. See GenerateBuffers() for |decode_timestamps| format. |
| 86 void GenerateVideoBuffers(const int* decode_timestamps) { | 86 void GenerateVideoBuffers(const int* decode_timestamps) { |
| 87 GenerateBuffers(decode_timestamps, DemuxerStream::VIDEO, kVideoTrackId, | 87 GenerateBuffers(decode_timestamps, DemuxerStream::VIDEO, kVideoTrackId, |
| 88 &video_buffers_); | 88 &buffer_queue_map_[kVideoTrackId]); |
| 89 } | 89 } |
| 90 | 90 |
| 91 // Current tests only need up to two distinct text BufferQueues. This helper | 91 // Current tests only need up to two distinct text BufferQueues. This helper |
| 92 // conditionally appends buffers to the underlying |text_buffers_a_| and | 92 // conditionally appends buffers to the underlying |buffer_queue_map_| keyed |
| 93 // |text_buffers_b_| and conditionally inserts these BufferQueues into | 93 // by the respective track ID. If |decode_timestamps_{a,b}| |
| 94 // |text_map_| keyed by the respective track ID. If |decode_timestamps_{a,b}| | 94 // is NULL, then the corresponding BufferQueue is not changed at all. |
| 95 // is NULL, then the corresponding BufferQueue is neither appended to nor | |
| 96 // inserted into |text_map_| (though it may previously have been inserted). | |
| 97 // Note that key collision on map insertion does not replace the previous | 95 // Note that key collision on map insertion does not replace the previous |
| 98 // value. | 96 // value. |
| 99 void GenerateTextBuffers(const int* decode_timestamps_a, | 97 void GenerateTextBuffers(const int* decode_timestamps_a, |
| 100 const int* decode_timestamps_b) { | 98 const int* decode_timestamps_b) { |
| 101 if (decode_timestamps_a) { | 99 if (decode_timestamps_a) { |
| 102 GenerateBuffers(decode_timestamps_a, DemuxerStream::TEXT, kTextTrackIdA, | 100 GenerateBuffers(decode_timestamps_a, DemuxerStream::TEXT, kTextTrackIdA, |
| 103 &text_buffers_a_); | 101 &buffer_queue_map_[kTextTrackIdA]); |
| 104 text_map_.insert(std::make_pair(kTextTrackIdA, text_buffers_a_)); | |
| 105 } | 102 } |
| 106 | 103 |
| 107 if (decode_timestamps_b) { | 104 if (decode_timestamps_b) { |
| 108 GenerateBuffers(decode_timestamps_b, DemuxerStream::TEXT, kTextTrackIdB, | 105 GenerateBuffers(decode_timestamps_b, DemuxerStream::TEXT, kTextTrackIdB, |
| 109 &text_buffers_b_); | 106 &buffer_queue_map_[kTextTrackIdB]); |
| 110 text_map_.insert(std::make_pair(kTextTrackIdB, text_buffers_b_)); | |
| 111 } | 107 } |
| 112 } | 108 } |
| 113 | 109 |
| 114 // Returns a string that describes the sequence of buffers in | 110 // Returns a string that describes the sequence of buffers in |
| 115 // |merged_buffers_|. The string is a concatenation of space-delimited buffer | 111 // |merged_buffers_|. The string is a concatenation of space-delimited buffer |
| 116 // descriptors in the same sequence as |merged_buffers_|. Each descriptor is | 112 // descriptors in the same sequence as |merged_buffers_|. Each descriptor is |
| 117 // the concatenation of | 113 // the concatenation of |
| 118 // 1) a single character that describes the buffer's type(), e.g. A, V, or T | 114 // 1) a single character that describes the buffer's type(), e.g. A, V, or T |
| 119 // for audio, video, or text, respectively | 115 // for audio, video, or text, respectively |
| 120 // 2) the buffer's track_id() | 116 // 2) the buffer's track_id() |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 // also verified to match the number of buffers in |audio_buffers_|, | 165 // also verified to match the number of buffers in |audio_buffers_|, |
| 170 // |video_buffers_|, and |text_map_|, respectively. | 166 // |video_buffers_|, and |text_map_|, respectively. |
| 171 void VerifyMergeSuccess(const std::string& expected, | 167 void VerifyMergeSuccess(const std::string& expected, |
| 172 bool verify_type_and_text_track_sequence) { | 168 bool verify_type_and_text_track_sequence) { |
| 173 // |merged_buffers| may already have some buffers. Count them by type for | 169 // |merged_buffers| may already have some buffers. Count them by type for |
| 174 // later inclusion in verification. | 170 // later inclusion in verification. |
| 175 size_t original_audio_in_merged = CountMatchingMergedBuffers(IsAudio); | 171 size_t original_audio_in_merged = CountMatchingMergedBuffers(IsAudio); |
| 176 size_t original_video_in_merged = CountMatchingMergedBuffers(IsVideo); | 172 size_t original_video_in_merged = CountMatchingMergedBuffers(IsVideo); |
| 177 size_t original_text_in_merged = CountMatchingMergedBuffers(IsText); | 173 size_t original_text_in_merged = CountMatchingMergedBuffers(IsText); |
| 178 | 174 |
| 179 EXPECT_TRUE(MergeBufferQueues(audio_buffers_, video_buffers_, text_map_, | 175 EXPECT_TRUE(MergeBufferQueues(buffer_queue_map_, &merged_buffers_)); |
| 180 &merged_buffers_)); | |
| 181 | 176 |
| 182 // Verify resulting contents of |merged_buffers| matches |expected|. | 177 // Verify resulting contents of |merged_buffers| matches |expected|. |
| 183 EXPECT_EQ(expected, | 178 EXPECT_EQ(expected, |
| 184 MergedBufferQueueString(verify_type_and_text_track_sequence)); | 179 MergedBufferQueueString(verify_type_and_text_track_sequence)); |
| 185 | 180 |
| 186 // Verify that the correct number of each type of buffer is in the merge | 181 // Verify that the correct number of each type of buffer is in the merge |
| 187 // result. | 182 // result. |
| 188 size_t audio_in_merged = CountMatchingMergedBuffers(IsAudio); | 183 size_t audio_in_merged = CountMatchingMergedBuffers(IsAudio); |
| 189 size_t video_in_merged = CountMatchingMergedBuffers(IsVideo); | 184 size_t video_in_merged = CountMatchingMergedBuffers(IsVideo); |
| 190 size_t text_in_merged = CountMatchingMergedBuffers(IsText); | 185 size_t text_in_merged = CountMatchingMergedBuffers(IsText); |
| 191 | 186 |
| 192 EXPECT_GE(audio_in_merged, original_audio_in_merged); | 187 EXPECT_GE(audio_in_merged, original_audio_in_merged); |
| 193 EXPECT_GE(video_in_merged, original_video_in_merged); | 188 EXPECT_GE(video_in_merged, original_video_in_merged); |
| 194 EXPECT_GE(text_in_merged, original_text_in_merged); | 189 EXPECT_GE(text_in_merged, original_text_in_merged); |
| 195 | 190 |
| 196 EXPECT_EQ(audio_buffers_.size(), | 191 EXPECT_EQ(buffer_queue_map_[kAudioTrackId].size(), |
| 197 audio_in_merged - original_audio_in_merged); | 192 audio_in_merged - original_audio_in_merged); |
| 198 EXPECT_EQ(video_buffers_.size(), | 193 if (buffer_queue_map_[kAudioTrackId].empty()) |
| 194 buffer_queue_map_.erase(kAudioTrackId); |
| 195 EXPECT_EQ(buffer_queue_map_[kVideoTrackId].size(), |
| 199 video_in_merged - original_video_in_merged); | 196 video_in_merged - original_video_in_merged); |
| 197 if (buffer_queue_map_[kVideoTrackId].empty()) |
| 198 buffer_queue_map_.erase(kVideoTrackId); |
| 200 | 199 |
| 201 size_t expected_text_buffer_count = 0; | 200 size_t expected_text_buffer_count = 0; |
| 202 for (TextBufferQueueMap::const_iterator itr = text_map_.begin(); | 201 expected_text_buffer_count += buffer_queue_map_[kTextTrackIdA].size(); |
| 203 itr != text_map_.end(); | 202 if (buffer_queue_map_[kTextTrackIdA].empty()) |
| 204 ++itr) { | 203 buffer_queue_map_.erase(kTextTrackIdA); |
| 205 expected_text_buffer_count += itr->second.size(); | 204 expected_text_buffer_count += buffer_queue_map_[kTextTrackIdB].size(); |
| 206 } | 205 if (buffer_queue_map_[kTextTrackIdB].empty()) |
| 206 buffer_queue_map_.erase(kTextTrackIdB); |
| 207 EXPECT_EQ(expected_text_buffer_count, | 207 EXPECT_EQ(expected_text_buffer_count, |
| 208 text_in_merged - original_text_in_merged); | 208 text_in_merged - original_text_in_merged); |
| 209 } | 209 } |
| 210 | 210 |
| 211 // Verifies that MergeBufferQueues() of the current |audio_buffers_|, | 211 // Verifies that MergeBufferQueues() of the current |buffer_queue_map_| and |
| 212 // |video_buffers_|, |text_map_|, and |merged_buffers_| returns false. | 212 // |merged_buffers_| returns false. |
| 213 void VerifyMergeFailure() { | 213 void VerifyMergeFailure() { |
| 214 EXPECT_FALSE(MergeBufferQueues(audio_buffers_, video_buffers_, text_map_, | 214 EXPECT_FALSE(MergeBufferQueues(buffer_queue_map_, &merged_buffers_)); |
| 215 &merged_buffers_)); | |
| 216 } | 215 } |
| 217 | 216 |
| 218 // Helper to allow tests to clear all the input BufferQueues (except | 217 // Helper to allow tests to clear all the input BufferQueues (except |
| 219 // |merged_buffers_|) and the TextBufferQueueMap that are used in | 218 // |merged_buffers_|) and the BufferQueueMap that are used in |
| 220 // VerifyMerge{Success/Failure}(). | 219 // VerifyMerge{Success/Failure}(). |
| 221 void ClearQueuesAndTextMapButKeepAnyMergedBuffers() { | 220 void ClearBufferQueuesButKeepAnyMergedBuffers() { buffer_queue_map_.clear(); } |
| 222 audio_buffers_.clear(); | |
| 223 video_buffers_.clear(); | |
| 224 text_buffers_a_.clear(); | |
| 225 text_buffers_b_.clear(); | |
| 226 text_map_.clear(); | |
| 227 } | |
| 228 | 221 |
| 229 private: | 222 private: |
| 230 BufferQueue audio_buffers_; | 223 StreamParser::BufferQueueMap buffer_queue_map_; |
| 231 BufferQueue video_buffers_; | |
| 232 BufferQueue text_buffers_a_; | |
| 233 BufferQueue text_buffers_b_; | |
| 234 BufferQueue merged_buffers_; | 224 BufferQueue merged_buffers_; |
| 235 TextBufferQueueMap text_map_; | |
| 236 | 225 |
| 237 DISALLOW_COPY_AND_ASSIGN(StreamParserTest); | 226 DISALLOW_COPY_AND_ASSIGN(StreamParserTest); |
| 238 }; | 227 }; |
| 239 | 228 |
| 240 TEST_F(StreamParserTest, MergeBufferQueues_AllEmpty) { | 229 TEST_F(StreamParserTest, MergeBufferQueues_AllEmpty) { |
| 241 std::string expected = ""; | 230 std::string expected = ""; |
| 242 VerifyMergeSuccess(expected, true); | 231 VerifyMergeSuccess(expected, true); |
| 243 } | 232 } |
| 244 | 233 |
| 245 TEST_F(StreamParserTest, MergeBufferQueues_SingleAudioBuffer) { | 234 TEST_F(StreamParserTest, MergeBufferQueues_SingleAudioBuffer) { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 "T2:107"; | 325 "T2:107"; |
| 337 int audio_timestamps[] = { 100, 105, kEnd }; | 326 int audio_timestamps[] = { 100, 105, kEnd }; |
| 338 GenerateAudioBuffers(audio_timestamps); | 327 GenerateAudioBuffers(audio_timestamps); |
| 339 int video_timestamps[] = { 101, 103, 106, kEnd }; | 328 int video_timestamps[] = { 101, 103, 106, kEnd }; |
| 340 GenerateVideoBuffers(video_timestamps); | 329 GenerateVideoBuffers(video_timestamps); |
| 341 int text_timestamps_a[] = { 102, 107, kEnd }; | 330 int text_timestamps_a[] = { 102, 107, kEnd }; |
| 342 int text_timestamps_b[] = { 104, kEnd }; | 331 int text_timestamps_b[] = { 104, kEnd }; |
| 343 GenerateTextBuffers(text_timestamps_a, text_timestamps_b); | 332 GenerateTextBuffers(text_timestamps_a, text_timestamps_b); |
| 344 VerifyMergeSuccess(expected, true); | 333 VerifyMergeSuccess(expected, true); |
| 345 | 334 |
| 346 ClearQueuesAndTextMapButKeepAnyMergedBuffers(); | 335 ClearBufferQueuesButKeepAnyMergedBuffers(); |
| 347 | 336 |
| 348 expected = "A0:100 V1:101 T2:102 V1:103 T3:104 A0:105 V1:106 T2:107 " | 337 expected = "A0:100 V1:101 T2:102 V1:103 T3:104 A0:105 V1:106 T2:107 " |
| 349 "A0:107 V1:111 T2:112 V1:113 T3:114 A0:115 V1:116 T2:117"; | 338 "A0:107 V1:111 T2:112 V1:113 T3:114 A0:115 V1:116 T2:117"; |
| 350 int more_audio_timestamps[] = { 107, 115, kEnd }; | 339 int more_audio_timestamps[] = { 107, 115, kEnd }; |
| 351 GenerateAudioBuffers(more_audio_timestamps); | 340 GenerateAudioBuffers(more_audio_timestamps); |
| 352 int more_video_timestamps[] = { 111, 113, 116, kEnd }; | 341 int more_video_timestamps[] = { 111, 113, 116, kEnd }; |
| 353 GenerateVideoBuffers(more_video_timestamps); | 342 GenerateVideoBuffers(more_video_timestamps); |
| 354 int more_text_timestamps_a[] = { 112, 117, kEnd }; | 343 int more_text_timestamps_a[] = { 112, 117, kEnd }; |
| 355 int more_text_timestamps_b[] = { 114, kEnd }; | 344 int more_text_timestamps_b[] = { 114, kEnd }; |
| 356 GenerateTextBuffers(more_text_timestamps_a, more_text_timestamps_b); | 345 GenerateTextBuffers(more_text_timestamps_a, more_text_timestamps_b); |
| 357 VerifyMergeSuccess(expected, true); | 346 VerifyMergeSuccess(expected, true); |
| 358 } | 347 } |
| 359 | 348 |
| 360 TEST_F(StreamParserTest, MergeBufferQueues_InvalidAppendToExistingMerge) { | 349 TEST_F(StreamParserTest, MergeBufferQueues_InvalidAppendToExistingMerge) { |
| 361 std::string expected = "A0:100 V1:101 T2:102 V1:103 T3:104 A0:105 V1:106 " | 350 std::string expected = "A0:100 V1:101 T2:102 V1:103 T3:104 A0:105 V1:106 " |
| 362 "T2:107"; | 351 "T2:107"; |
| 363 int audio_timestamps[] = { 100, 105, kEnd }; | 352 int audio_timestamps[] = { 100, 105, kEnd }; |
| 364 GenerateAudioBuffers(audio_timestamps); | 353 GenerateAudioBuffers(audio_timestamps); |
| 365 int video_timestamps[] = { 101, 103, 106, kEnd }; | 354 int video_timestamps[] = { 101, 103, 106, kEnd }; |
| 366 GenerateVideoBuffers(video_timestamps); | 355 GenerateVideoBuffers(video_timestamps); |
| 367 int text_timestamps_a[] = { 102, 107, kEnd }; | 356 int text_timestamps_a[] = { 102, 107, kEnd }; |
| 368 int text_timestamps_b[] = { 104, kEnd }; | 357 int text_timestamps_b[] = { 104, kEnd }; |
| 369 GenerateTextBuffers(text_timestamps_a, text_timestamps_b); | 358 GenerateTextBuffers(text_timestamps_a, text_timestamps_b); |
| 370 VerifyMergeSuccess(expected, true); | 359 VerifyMergeSuccess(expected, true); |
| 371 | 360 |
| 372 // Appending empty buffers to pre-existing merge result should succeed and not | 361 // Appending empty buffers to pre-existing merge result should succeed and not |
| 373 // change the existing result. | 362 // change the existing result. |
| 374 ClearQueuesAndTextMapButKeepAnyMergedBuffers(); | 363 ClearBufferQueuesButKeepAnyMergedBuffers(); |
| 375 VerifyMergeSuccess(expected, true); | 364 VerifyMergeSuccess(expected, true); |
| 376 | 365 |
| 377 // But appending something with a lower timestamp than the last timestamp | 366 // But appending something with a lower timestamp than the last timestamp |
| 378 // in the pre-existing merge result should fail. | 367 // in the pre-existing merge result should fail. |
| 379 int more_audio_timestamps[] = { 106, kEnd }; | 368 int more_audio_timestamps[] = { 106, kEnd }; |
| 380 GenerateAudioBuffers(more_audio_timestamps); | 369 GenerateAudioBuffers(more_audio_timestamps); |
| 381 VerifyMergeFailure(); | 370 VerifyMergeFailure(); |
| 382 } | 371 } |
| 383 | 372 |
| 384 } // namespace media | 373 } // namespace media |
| OLD | NEW |