OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include <algorithm> | |
6 #include <sstream> | |
7 | |
8 #include "base/basictypes.h" | |
9 #include "media/base/stream_parser.h" | |
10 #include "media/base/stream_parser_buffer.h" | |
11 #include "testing/gtest/include/gtest/gtest.h" | |
12 | |
13 namespace media { | |
14 | |
15 typedef StreamParser::BufferQueue BufferQueue; | |
16 typedef StreamParser::TextBufferQueueMap TextBufferQueueMap; | |
17 | |
18 const int kEnd = -1; | |
19 const uint8 kFakeData[] = { 0xFF }; | |
20 | |
21 static bool IsAudio(scoped_refptr<StreamParserBuffer> buffer) { | |
22 return buffer->type() == DemuxerStream::AUDIO; | |
23 } | |
24 | |
25 static bool IsVideo(scoped_refptr<StreamParserBuffer> buffer) { | |
26 return buffer->type() == DemuxerStream::VIDEO; | |
27 } | |
28 | |
29 static bool IsText(scoped_refptr<StreamParserBuffer> buffer) { | |
30 return buffer->type() == DemuxerStream::TEXT; | |
31 } | |
32 | |
33 // Creates and appends a sequence of StreamParserBuffers to the provided | |
34 // |queue|. |decode_timestamps| determines the number of appended buffers and | |
35 // their sequence of decode timestamps; a |kEnd| timestamp indicates the | |
36 // end of the sequence and no buffer is appended for it. Each new buffer's | |
37 // type will be |type|, and if text, its text track number will be set to | |
38 // |text_track_number|. | |
39 static void GenerateBuffers(const int* decode_timestamps, | |
40 StreamParserBuffer::Type type, | |
41 int text_track_number, | |
42 BufferQueue* queue) { | |
43 DCHECK(decode_timestamps); | |
44 DCHECK(queue); | |
45 DCHECK_NE(type, DemuxerStream::UNKNOWN); | |
46 DCHECK_LT(type, DemuxerStream::NUM_TYPES); | |
47 for (int i = 0; decode_timestamps[i] != kEnd; ++i) { | |
48 scoped_refptr<StreamParserBuffer> buffer = | |
49 StreamParserBuffer::CopyFrom(kFakeData, sizeof(kFakeData), | |
50 true, type); | |
51 if (type == DemuxerStream::TEXT) | |
52 buffer->set_text_track_number(text_track_number); | |
53 buffer->SetDecodeTimestamp( | |
54 base::TimeDelta::FromMicroseconds(decode_timestamps[i])); | |
55 queue->push_back(buffer); | |
56 } | |
57 } | |
58 | |
59 class StreamParserTest : public testing::Test { | |
60 protected: | |
61 StreamParserTest() {} | |
62 | |
63 // Returns the number of buffers in |merged_buffers_| for which |predicate| | |
64 // returns true. | |
65 size_t CountMatchingMergedBuffers( | |
66 bool (*predicate)(scoped_refptr<StreamParserBuffer> buffer)) { | |
67 return static_cast<size_t>(count_if(merged_buffers_.begin(), | |
68 merged_buffers_.end(), | |
69 predicate)); | |
70 } | |
71 | |
72 // Appends test audio buffers in the sequence described by |decode_timestamps| | |
73 // to |audio_buffers_|. See GenerateBuffers() for |decode_timestamps| format. | |
74 void GenerateAudioBuffers(const int* decode_timestamps) { | |
75 GenerateBuffers(decode_timestamps, DemuxerStream::AUDIO, -1, | |
76 &audio_buffers_); | |
77 } | |
78 | |
79 // Appends test video buffers in the sequence described by |decode_timestamps| | |
80 // to |video_buffers_|. See GenerateBuffers() for |decode_timestamps| format. | |
81 void GenerateVideoBuffers(const int* decode_timestamps) { | |
82 GenerateBuffers(decode_timestamps, DemuxerStream::VIDEO, -1, | |
83 &video_buffers_); | |
84 } | |
85 | |
86 // Current tests only need up to two distinct text BufferQueues. This helper | |
87 // conditionally appends buffers to the underlying |text_buffers_a_| and | |
88 // |text_buffers_b_| and conditionally inserts these BufferQueues into | |
89 // |text_map_| keyed by the respective |text_track_number_{a,b}|. If | |
90 // |decode_timestamps_{a,b}| is NULL, then the corresponding BufferQueue is | |
91 // neither appended to nor inserted into |text_map_| (though it may previously | |
92 // have been inserted under either the same or different key). Note that | |
93 // key collision on map insertion does not replace the previous value. | |
94 void GenerateTextBuffers(const int* decode_timestamps_a, | |
95 int text_track_number_a, | |
96 const int* decode_timestamps_b, | |
97 int text_track_number_b) { | |
98 if (decode_timestamps_a) { | |
99 GenerateBuffers(decode_timestamps_a, DemuxerStream::TEXT, | |
100 text_track_number_a, &text_buffers_a_); | |
101 text_map_.insert(std::make_pair(text_track_number_a, text_buffers_a_)); | |
102 } | |
103 | |
104 if (decode_timestamps_b) { | |
105 GenerateBuffers(decode_timestamps_b, DemuxerStream::TEXT, | |
106 text_track_number_b, &text_buffers_b_); | |
107 text_map_.insert(std::make_pair(text_track_number_b, text_buffers_b_)); | |
108 } | |
109 } | |
110 | |
111 // Returns a string that describes the sequence of buffers in | |
112 // |merged_buffers_|. The string is a concatenation of space-delimited buffer | |
113 // descriptors in the same sequence as |merged_buffers_|. Each descriptor is | |
114 // the concatenation of | |
115 // 1) a single character that describes the buffer's type(), e.g. A, V, or T | |
116 // for audio, video, or text, respectively | |
117 // 2) if text, the buffer's text_track_number(), otherwise nothing | |
118 // 3) ":" | |
119 // 4) the buffer's decode timestamp. | |
120 // If |include_type_and_text_track| is false, then items 1, 2, and 3 are | |
121 // not included in descriptors. This is useful when buffers with different | |
122 // media types but the same decode timestamp are expected, and the exact | |
123 // sequence of media types for the tying timestamps is not subject to | |
124 // verification. | |
125 std::string MergedBufferQueueString(bool include_type_and_text_track) { | |
126 std::stringstream results_stream; | |
127 for (BufferQueue::const_iterator itr = merged_buffers_.begin(); | |
128 itr != merged_buffers_.end(); | |
129 ++itr) { | |
130 if (itr != merged_buffers_.begin()) | |
131 results_stream << " "; | |
132 const StreamParserBuffer& buffer = *(*itr); | |
133 if (include_type_and_text_track) { | |
134 switch (buffer.type()) { | |
135 case DemuxerStream::AUDIO: | |
136 results_stream << "A"; | |
137 break; | |
138 case DemuxerStream::VIDEO: | |
139 results_stream << "V"; | |
140 break; | |
141 case DemuxerStream::TEXT: | |
142 results_stream << "T"; | |
143 results_stream << buffer.text_track_number(); | |
144 break; | |
145 default: | |
146 NOTREACHED(); | |
147 } | |
148 results_stream << ":"; | |
149 } | |
150 results_stream << buffer.GetDecodeTimestamp().InMicroseconds(); | |
151 } | |
152 | |
153 return results_stream.str(); | |
154 } | |
155 | |
156 // Verifies that MergeBufferQueues() of the current |audio_buffers_|, | |
157 // |video_buffers_|, |text_map_|, and |merged_buffers_| returns true and | |
158 // results in an updated |merged_buffers_| that matches expectation. The | |
159 // expectation, specified in |expected|, is compared to the string resulting | |
160 // from MergedBufferQueueString() (see comments for that method) with | |
161 // |verify_type_and_text_track_sequence| passed. |merged_buffers_| is appended | |
162 // to by the merge, and may be setup by the caller to have some pre-existing | |
163 // buffers; it is both an input and output of this method. | |
164 // Regardless of |verify_type_and_text_track_sequence|, the marginal number | |
165 // of buffers of each type (audio, video, text) resulting from the merge is | |
166 // also verified to match the number of buffers in |audio_buffers_|, | |
167 // |video_buffers_|, and |text_map_|, respectively. | |
168 void VerifyMergeSuccess(const std::string& expected, | |
169 bool verify_type_and_text_track_sequence) { | |
170 // |merged_buffers| may already have some buffers. Count them by type for | |
171 // later inclusion in verification. | |
172 size_t original_audio_in_merged = CountMatchingMergedBuffers(IsAudio); | |
173 size_t original_video_in_merged = CountMatchingMergedBuffers(IsVideo); | |
174 size_t original_text_in_merged = CountMatchingMergedBuffers(IsText); | |
175 | |
176 EXPECT_TRUE(MergeBufferQueues(audio_buffers_, video_buffers_, text_map_, | |
177 &merged_buffers_)); | |
178 | |
179 // Verify resulting contents of |merged_buffers| matches |expected|. | |
180 EXPECT_EQ(expected, | |
181 MergedBufferQueueString(verify_type_and_text_track_sequence)); | |
182 | |
183 // Verify that the correct number of each type of buffer is in the merge | |
184 // result. | |
185 size_t audio_in_merged = CountMatchingMergedBuffers(IsAudio); | |
186 size_t video_in_merged = CountMatchingMergedBuffers(IsVideo); | |
187 size_t text_in_merged = CountMatchingMergedBuffers(IsText); | |
188 | |
189 EXPECT_GE(audio_in_merged, original_audio_in_merged); | |
190 EXPECT_GE(video_in_merged, original_video_in_merged); | |
191 EXPECT_GE(text_in_merged, original_text_in_merged); | |
192 | |
193 EXPECT_EQ(audio_buffers_.size(), | |
194 audio_in_merged - original_audio_in_merged); | |
195 EXPECT_EQ(video_buffers_.size(), | |
196 video_in_merged - original_video_in_merged); | |
197 | |
198 size_t expected_text_buffer_count = 0; | |
199 for (TextBufferQueueMap::const_iterator itr = text_map_.begin(); | |
200 itr != text_map_.end(); | |
201 ++itr) { | |
202 expected_text_buffer_count += itr->second.size(); | |
203 } | |
204 EXPECT_EQ(expected_text_buffer_count, | |
205 text_in_merged - original_text_in_merged); | |
206 } | |
207 | |
208 // Verifies that MergeBufferQueues() of the current |audio_buffers_|, | |
209 // |video_buffers_|, |text_map_|, and |merged_buffers_| returns false. | |
210 void VerifyMergeFailure() { | |
211 EXPECT_FALSE(MergeBufferQueues(audio_buffers_, video_buffers_, text_map_, | |
212 &merged_buffers_)); | |
213 } | |
214 | |
215 // Helper to allow tests to clear all the input BufferQueues (except | |
216 // |merged_buffers_|) and the TextBufferQueueMap that are used in | |
217 // VerifyMerge{Success/Failure}(). | |
218 void ClearQueuesAndTextMapButKeepAnyMergedBuffers() { | |
219 audio_buffers_.clear(); | |
220 video_buffers_.clear(); | |
221 text_buffers_a_.clear(); | |
222 text_buffers_b_.clear(); | |
223 text_map_.clear(); | |
224 } | |
225 | |
226 private: | |
227 BufferQueue audio_buffers_, video_buffers_, text_buffers_a_, text_buffers_b_; | |
xhwang
2014/02/06 00:36:32
I don't find a rule against this, but I rarely see
wolenetz
2014/02/06 23:56:03
Done.
| |
228 BufferQueue merged_buffers_; | |
229 TextBufferQueueMap text_map_; | |
230 | |
231 DISALLOW_COPY_AND_ASSIGN(StreamParserTest); | |
232 }; | |
233 | |
234 TEST_F(StreamParserTest, MergeBufferQueues_AllEmpty) { | |
235 std::string expected = ""; | |
236 VerifyMergeSuccess(expected, true); | |
237 } | |
238 | |
239 TEST_F(StreamParserTest, MergeBufferQueues_SingleAudioBuffer) { | |
240 std::string expected = "A:100"; | |
241 int audio_timestamps[] = { 100, kEnd }; | |
242 GenerateAudioBuffers(audio_timestamps); | |
243 VerifyMergeSuccess(expected, true); | |
244 } | |
245 | |
246 TEST_F(StreamParserTest, MergeBufferQueues_SingleVideoBuffer) { | |
247 std::string expected = "V:100"; | |
248 int video_timestamps[] = { 100, kEnd }; | |
249 GenerateVideoBuffers(video_timestamps); | |
250 VerifyMergeSuccess(expected, true); | |
251 } | |
252 | |
253 TEST_F(StreamParserTest, MergeBufferQueues_SingleTextBuffer) { | |
254 std::string expected = "T12:100"; | |
255 int text_timestamps[] = { 100, kEnd }; | |
256 GenerateTextBuffers(text_timestamps, 12, NULL, -1); | |
257 VerifyMergeSuccess(expected, true); | |
258 } | |
259 | |
260 TEST_F(StreamParserTest, MergeBufferQueues_OverlappingAudioVideo) { | |
261 std::string expected = "A:100 V:101 V:102 A:103 A:104 V:105"; | |
262 int audio_timestamps[] = { 100, 103, 104, kEnd }; | |
263 GenerateAudioBuffers(audio_timestamps); | |
264 int video_timestamps[] = { 101, 102, 105, kEnd }; | |
265 GenerateVideoBuffers(video_timestamps); | |
266 VerifyMergeSuccess(expected, true); | |
267 } | |
268 | |
269 TEST_F(StreamParserTest, MergeBufferQueues_OverlappingMultipleText) { | |
270 std::string expected = "T1:100 T1:101 T2:103 T1:104 T2:105 T2:106"; | |
271 int text_timestamps_1[] = { 100, 101, 104, kEnd }; | |
272 int text_timestamps_2[] = { 103, 105, 106, kEnd }; | |
273 GenerateTextBuffers(text_timestamps_1, 1, text_timestamps_2, 2); | |
274 VerifyMergeSuccess(expected, true); | |
275 } | |
276 | |
277 TEST_F(StreamParserTest, MergeBufferQueues_OverlappingAudioVideoText) { | |
278 std::string expected = "A:100 V:101 T1:102 V:103 T2:104 A:105 V:106 T1:107"; | |
279 int audio_timestamps[] = { 100, 105, kEnd }; | |
280 GenerateAudioBuffers(audio_timestamps); | |
281 int video_timestamps[] = { 101, 103, 106, kEnd }; | |
282 GenerateVideoBuffers(video_timestamps); | |
283 int text_timestamps_1[] = { 102, 107, kEnd }; | |
284 int text_timestamps_2[] = { 104, kEnd }; | |
285 GenerateTextBuffers(text_timestamps_1, 1, text_timestamps_2, 2); | |
286 VerifyMergeSuccess(expected, true); | |
287 } | |
288 | |
289 TEST_F(StreamParserTest, MergeBufferQueues_NonDecreasingNoCrossMediaDuplicate) { | |
290 std::string expected = "A:100 A:100 A:100 V:101 V:101 V:101 A:102 V:103 " | |
291 "V:103"; | |
292 int audio_timestamps[] = { 100, 100, 100, 102, kEnd }; | |
293 GenerateAudioBuffers(audio_timestamps); | |
294 int video_timestamps[] = { 101, 101, 101, 103, 103, kEnd }; | |
295 GenerateVideoBuffers(video_timestamps); | |
296 VerifyMergeSuccess(expected, true); | |
297 } | |
298 | |
299 TEST_F(StreamParserTest, MergeBufferQueues_CrossStreamDuplicates) { | |
300 // Interface keeps the choice undefined of which stream's buffer wins the | |
301 // selection when timestamps are tied. Verify at least the right number of | |
302 // each kind of buffer results, and that buffers are in nondecreasing order. | |
303 std::string expected = "100 100 100 100 100 100 102 102 102 102 102 102 102"; | |
304 int audio_timestamps[] = { 100, 100, 100, 102, kEnd }; | |
305 GenerateAudioBuffers(audio_timestamps); | |
306 int video_timestamps[] = { 100, 100, 102, 102, 102, kEnd }; | |
307 GenerateVideoBuffers(video_timestamps); | |
308 int text_timestamps[] = { 100, 102, 102, 102, kEnd }; | |
309 GenerateTextBuffers(text_timestamps, 1, NULL, -1); | |
310 VerifyMergeSuccess(expected, false); | |
311 } | |
312 | |
313 TEST_F(StreamParserTest, MergeBufferQueues_InvalidDecreasingSingleStream) { | |
314 int audio_timestamps[] = { 101, 102, 100, 103, kEnd }; | |
315 GenerateAudioBuffers(audio_timestamps); | |
316 VerifyMergeFailure(); | |
317 } | |
318 | |
319 TEST_F(StreamParserTest, MergeBufferQueues_InvalidDecreasingMultipleStreams) { | |
320 int audio_timestamps[] = { 101, 102, 100, 103, kEnd }; | |
321 GenerateAudioBuffers(audio_timestamps); | |
322 int video_timestamps[] = { 104, 100, kEnd }; | |
323 GenerateVideoBuffers(video_timestamps); | |
324 VerifyMergeFailure(); | |
325 } | |
326 | |
327 TEST_F(StreamParserTest, MergeBufferQueues_ValidAppendToExistingMerge) { | |
328 std::string expected = "A:100 V:101 T1:102 V:103 T2:104 A:105 V:106 T1:107"; | |
329 int audio_timestamps[] = { 100, 105, kEnd }; | |
330 GenerateAudioBuffers(audio_timestamps); | |
331 int video_timestamps[] = { 101, 103, 106, kEnd }; | |
332 GenerateVideoBuffers(video_timestamps); | |
333 int text_timestamps_1[] = { 102, 107, kEnd }; | |
334 int text_timestamps_2[] = { 104, kEnd }; | |
335 GenerateTextBuffers(text_timestamps_1, 1, text_timestamps_2, 2); | |
336 VerifyMergeSuccess(expected, true); | |
337 | |
338 ClearQueuesAndTextMapButKeepAnyMergedBuffers(); | |
339 | |
340 expected = "A:100 V:101 T1:102 V:103 T2:104 A:105 V:106 T1:107 " | |
341 "A:107 V:111 T1:112 V:113 T2:114 A:115 V:116 T1:117"; | |
342 int more_audio_timestamps[] = { 107, 115, kEnd }; | |
343 GenerateAudioBuffers(more_audio_timestamps); | |
344 int more_video_timestamps[] = { 111, 113, 116, kEnd }; | |
345 GenerateVideoBuffers(more_video_timestamps); | |
346 int more_text_timestamps_1[] = { 112, 117, kEnd }; | |
347 int more_text_timestamps_2[] = { 114, kEnd }; | |
348 GenerateTextBuffers(more_text_timestamps_1, 1, more_text_timestamps_2, 2); | |
349 VerifyMergeSuccess(expected, true); | |
350 } | |
351 | |
352 TEST_F(StreamParserTest, MergeBufferQueues_InvalidAppendToExistingMerge) { | |
353 std::string expected = "A:100 V:101 T1:102 V:103 T2:104 A:105 V:106 T1:107"; | |
354 int audio_timestamps[] = { 100, 105, kEnd }; | |
355 GenerateAudioBuffers(audio_timestamps); | |
356 int video_timestamps[] = { 101, 103, 106, kEnd }; | |
357 GenerateVideoBuffers(video_timestamps); | |
358 int text_timestamps_1[] = { 102, 107, kEnd }; | |
359 int text_timestamps_2[] = { 104, kEnd }; | |
360 GenerateTextBuffers(text_timestamps_1, 1, text_timestamps_2, 2); | |
361 VerifyMergeSuccess(expected, true); | |
362 | |
363 // Appending empty buffers to pre-existing merge result should succeed and not | |
364 // change the existing result. | |
365 ClearQueuesAndTextMapButKeepAnyMergedBuffers(); | |
366 VerifyMergeSuccess(expected, true); | |
367 | |
368 // But appending something with a lower timestamp than the last timestamp | |
369 // in the pre-existing merge result should fail. | |
370 int more_audio_timestamps[] = { 106, kEnd }; | |
371 GenerateAudioBuffers(more_audio_timestamps); | |
372 VerifyMergeFailure(); | |
373 } | |
374 | |
375 } // namespace media | |
376 | |
OLD | NEW |