Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(287)

Unified Diff: media/base/stream_parser_unittest.cc

Issue 149153002: MSE: Add StreamParser buffer remuxing utility and tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Attempt windows stream_parser_unittests compilation fix Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/base/stream_parser_unittest.cc
diff --git a/media/base/stream_parser_unittest.cc b/media/base/stream_parser_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..53eeff3b26f20147e03f1e5c7b0e9c3e08e31d9b
--- /dev/null
+++ b/media/base/stream_parser_unittest.cc
@@ -0,0 +1,391 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "media/base/stream_parser.h"
+#include "media/base/stream_parser_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+const int kEnd = -1;
+const uint8 kFakeData[] = { 0xFF };
+
+bool IsAudio(scoped_refptr<StreamParserBuffer> buffer) {
xhwang 2014/01/29 08:04:50 should these functions be static?
wolenetz 2014/02/05 02:49:53 Done.
+ if (buffer->type() == StreamParserBuffer::kAudio)
+ return true;
+ return false;
xhwang 2014/01/29 08:04:50 return buffer->type() == StreamParserBuffer::kAudi
wolenetz 2014/02/05 02:49:53 Done.
+}
+
+bool IsVideo(scoped_refptr<StreamParserBuffer> buffer) {
+ if (buffer->type() == StreamParserBuffer::kVideo)
+ return true;
+ return false;
xhwang 2014/01/29 08:04:50 ditto
wolenetz 2014/02/05 02:49:53 Done.
+}
+
+bool IsText(scoped_refptr<StreamParserBuffer> buffer) {
+ if (buffer->type() == StreamParserBuffer::kText)
+ return true;
+ return false;
xhwang 2014/01/29 08:04:50 ditto
wolenetz 2014/02/05 02:49:53 Done.
+}
+
+class StreamParserTest : public testing::Test {
+ protected:
+ StreamParserTest() {}
+
xhwang 2014/01/29 08:04:50 remove extra empty line
wolenetz 2014/02/05 02:49:53 Done.
+
+ void GenerateBuffers(StreamParser::BufferQueue* queue,
xhwang 2014/01/29 08:04:50 add doc about what this function do
wolenetz 2014/02/05 02:49:53 Done, and also made it a static nonmember.
+ int decode_timestamps[],
+ StreamParserBuffer::Type type,
+ int text_track_number) {
xhwang 2014/01/29 08:04:50 reorder parameters: we usually put input before ou
wolenetz 2014/02/05 02:49:53 Done.
+ DCHECK(queue);
+ for (int i = 0; decode_timestamps[i] != kEnd; i++) {
xhwang 2014/01/29 08:04:50 nit: ++i
wolenetz 2014/02/05 02:49:53 Done.
+ scoped_refptr<StreamParserBuffer> buffer =
+ StreamParserBuffer::CopyFrom(kFakeData, sizeof(kFakeData),
+ true, type);
+ if (type == StreamParserBuffer::kText)
+ buffer->set_text_track_number(text_track_number);
+ buffer->SetDecodeTimestamp(
+ base::TimeDelta::FromMicroseconds(decode_timestamps[i]));
+ queue->push_back(buffer);
+ }
+ }
+
+ void GenerateBuffers(StreamParser::BufferQueue* queue,
xhwang 2014/01/29 08:04:50 Usually we don't like function overloading. How ab
wolenetz 2014/02/05 02:49:53 Done, also saving the |queue| parameter by using w
+ int decode_timestamps[],
+ StreamParserBuffer::Type type) {
+ DCHECK_NE(type, StreamParserBuffer::kText); // Needs a text track number.
+ GenerateBuffers(queue, decode_timestamps, type, -1);
+ }
+
+ void GenerateTextBuffers(StreamParser::BufferQueue* queue,
+ int decode_timestamps[],
+ int text_track_number) {
+ GenerateBuffers(queue, decode_timestamps, StreamParserBuffer::kText,
+ text_track_number);
+ }
+
+ std::string BufferQueueToString(const StreamParser::BufferQueue* queue,
xhwang 2014/01/29 08:04:50 pass as const-ref?
xhwang 2014/01/29 08:04:50 We use StreamParser::BufferQueue a lot in this tes
xhwang 2014/01/29 08:04:50 doc about the output string format
wolenetz 2014/02/05 02:49:53 Changed to just use well-defined member |merged_bu
wolenetz 2014/02/05 02:49:53 Done and ditto for TextBufferQueueMap.
wolenetz 2014/02/05 02:49:53 Done.
+ bool include_type_and_text_track) {
+ std::stringstream results_stream;
xhwang 2014/01/29 08:04:50 add #include <sstream> for this
wolenetz 2014/02/05 02:49:53 Done.
+ for (StreamParser::BufferQueue::const_iterator itr = queue->begin();
+ itr != queue->end();
+ ++itr) {
+ if (itr != queue->begin())
+ results_stream << " ";
+ scoped_refptr<StreamParserBuffer> buffer = *itr;
xhwang 2014/01/29 08:04:50 nit: you can avoid increment/decrement the ref cou
wolenetz 2014/02/05 02:49:53 Nice :) Done.
+ if (include_type_and_text_track) {
+ switch (buffer->type()) {
+ case StreamParserBuffer::kAudio:
+ results_stream << "A";
+ break;
+ case StreamParserBuffer::kVideo:
+ results_stream << "V";
+ break;
+ case StreamParserBuffer::kText:
+ results_stream << "T";
+ results_stream << buffer->text_track_number() << ":";
+ break;
+ }
+ }
+ results_stream << buffer->GetDecodeTimestamp().InMicroseconds();
+ }
+
+ return results_stream.str();
+ }
+
+
+ void VerifySuccessfulMerge(const StreamParser::BufferQueue& audio_buffers,
+ const StreamParser::BufferQueue& video_buffers,
+ const StreamParser::TextBufferQueueMap& text_map,
+ const std::string expected,
xhwang 2014/01/29 08:04:50 pass by const-ref
wolenetz 2014/02/05 02:49:53 Changed to just use well-defined members |audio_bu
+ bool verify_type_and_text_track_sequence,
+ StreamParser::BufferQueue* merged_buffers) {
xhwang 2014/01/29 08:04:50 Add a doc. It's not obvious that |merged_buffers|
wolenetz 2014/02/05 02:49:53 Done.
+ // |merged_buffers| may already have some buffers. Count them by type for
+ // later inclusion in verification.
+ size_t original_audio_in_merged =
+ static_cast<size_t>(count_if(merged_buffers->begin(),
xhwang 2014/01/29 08:04:50 s/count_if/std::count_if add #include <algorithm>
wolenetz 2014/02/05 02:49:53 Done.
+ merged_buffers->end(), IsAudio));
+ size_t original_video_in_merged =
+ static_cast<size_t>(count_if(merged_buffers->begin(),
+ merged_buffers->end(), IsVideo));
+ size_t original_text_in_merged =
+ static_cast<size_t>(count_if(merged_buffers->begin(),
+ merged_buffers->end(), IsText));
+
+ EXPECT_TRUE(StreamParser::MergeBufferQueues(audio_buffers, video_buffers,
+ text_map, merged_buffers));
+
+ // Verify resulting contents of |merged_buffers| matches |expected|.
+ EXPECT_EQ(expected,
+ BufferQueueToString(merged_buffers,
+ verify_type_and_text_track_sequence));
+
+ // If not verifying the sequence of types, at least still verify that the
+ // correct number of each type of buffer is in the merge result.
+ size_t audio_in_merged =
+ static_cast<size_t>(count_if(merged_buffers->begin(),
+ merged_buffers->end(), IsAudio));
+ size_t video_in_merged =
+ static_cast<size_t>(count_if(merged_buffers->begin(),
+ merged_buffers->end(), IsVideo));
+ size_t text_in_merged =
+ static_cast<size_t>(count_if(merged_buffers->begin(),
+ merged_buffers->end(), IsText));
+ EXPECT_GE(audio_in_merged, original_audio_in_merged);
+ EXPECT_GE(video_in_merged, original_video_in_merged);
+ EXPECT_GE(text_in_merged, original_text_in_merged);
+
+ EXPECT_EQ(audio_buffers.size(), audio_in_merged - original_audio_in_merged);
+ EXPECT_EQ(video_buffers.size(), video_in_merged - original_video_in_merged);
+
+ size_t expected_text_buffer_count = 0;
+ for (StreamParser::TextBufferQueueMap::const_iterator itr =
+ text_map.begin();
+ itr != text_map.end();
+ ++itr) {
+ expected_text_buffer_count += itr->second.size();
+ }
+ EXPECT_EQ(expected_text_buffer_count,
+ text_in_merged - original_text_in_merged);
+ }
+
+ void VerifySuccessfulMerge(const StreamParser::BufferQueue& audio_buffers,
+ const StreamParser::BufferQueue& video_buffers,
+ const StreamParser::TextBufferQueueMap& text_map,
+ const std::string expected,
+ bool verify_type_and_text_track_sequence) {
+ StreamParser::BufferQueue merged_buffers;
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected,
+ verify_type_and_text_track_sequence, &merged_buffers);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StreamParserTest);
+};
+
+TEST_F(StreamParserTest, MergeBufferQueues_AllEmpty) {
+ StreamParser::BufferQueue audio_buffers, video_buffers;
+ StreamParser::TextBufferQueueMap text_map;
xhwang 2014/01/29 08:04:50 these are used in all tests, may be you can just d
wolenetz 2014/02/05 02:49:53 Done. Saves spending a lot of lines: thank you!
+
+ std::string expected = "";
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_SingleAudioBuffer) {
+ StreamParser::BufferQueue audio_buffers, video_buffers;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "A100";
+ int audio_timestamps[] = { 100, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_SingleVideoBuffer) {
+ StreamParser::BufferQueue audio_buffers, video_buffers;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "V100";
+ int video_timestamps[] = { 100, kEnd };
+ GenerateBuffers(&video_buffers, video_timestamps, StreamParserBuffer::kVideo);
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_SingleTextBuffer) {
+ StreamParser::BufferQueue audio_buffers, video_buffers, text_buffers;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "T12:100";
+ int text_timestamps[] = { 100, kEnd };
+ GenerateTextBuffers(&text_buffers, text_timestamps, 12);
+ text_map.insert(std::make_pair(3141593, text_buffers)); // Immaterial index.
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_OverlappingAudioVideo) {
+ StreamParser::BufferQueue audio_buffers, video_buffers;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "A100 V101 V102 A103 A104 V105";
+ int audio_timestamps[] = { 100, 103, 104, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+ int video_timestamps[] = { 101, 102, 105, kEnd };
+ GenerateBuffers(&video_buffers, video_timestamps, StreamParserBuffer::kVideo);
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_OverlappingMultipleText) {
+ StreamParser::BufferQueue audio_buffers, video_buffers, text_1, text_2;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "T1:100 T1:101 T2:103 T1:104 T2:105 T2:106";
xhwang 2014/01/29 08:04:50 We are using ":" for text because it has text trac
wolenetz 2014/02/05 02:49:53 Done (T1:100 A:100).
+ int text_timestamps_1[] = { 100, 101, 104, kEnd };
+ GenerateTextBuffers(&text_1, text_timestamps_1, 1);
+ int text_timestamps_2[] = { 103, 105, 106, kEnd };
+ GenerateTextBuffers(&text_2, text_timestamps_2, 2);
+ text_map.insert(std::make_pair(50, text_1)); // Immaterial index.
+ text_map.insert(std::make_pair(51, text_2)); // Immaterial index.
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_OverlappingAudioVideoText) {
+ StreamParser::BufferQueue audio_buffers, video_buffers, text_1, text_2;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "A100 V101 T1:102 V103 T2:104 A105 V106 T1:107";
+ int audio_timestamps[] = { 100, 105, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+ int video_timestamps[] = { 101, 103, 106, kEnd };
+ GenerateBuffers(&video_buffers, video_timestamps, StreamParserBuffer::kVideo);
+ int text_timestamps_1[] = { 102, 107, kEnd };
+ GenerateTextBuffers(&text_1, text_timestamps_1, 1);
+ int text_timestamps_2[] = { 104, kEnd };
+ GenerateTextBuffers(&text_2, text_timestamps_2, 2);
+ text_map.insert(std::make_pair(50, text_1)); // Immaterial index.
+ text_map.insert(std::make_pair(51, text_2)); // Immaterial index.
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_NonDecreasingNoCrossMediaDuplicate) {
+ StreamParser::BufferQueue audio_buffers, video_buffers;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "A100 A100 A100 V101 V101 V101 A102 V103 V103";
+ int audio_timestamps[] = { 100, 100, 100, 102, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+ int video_timestamps[] = { 101, 101, 101, 103, 103, kEnd };
+ GenerateBuffers(&video_buffers, video_timestamps, StreamParserBuffer::kVideo);
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_CrossStreamDuplicates) {
+ // Interface keeps the choice undefined of which stream's buffer wins the
+ // selection when timestamps are tied. Verify at least the right number of
+ // each kind of buffer results, and that buffers are in nondecreasing order.
+ StreamParser::BufferQueue audio_buffers, video_buffers, text_buffers;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "100 100 100 100 100 100 102 102 102 102 102 102 102";
+ int audio_timestamps[] = { 100, 100, 100, 102, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+ int video_timestamps[] = { 100, 100, 102, 102, 102, kEnd };
+ GenerateBuffers(&video_buffers, video_timestamps, StreamParserBuffer::kVideo);
+ int text_timestamps[] = { 100, 102, 102, 102, kEnd };
+ GenerateTextBuffers(&text_buffers, text_timestamps, 1);
+ text_map.insert(std::make_pair(50, text_buffers)); // Immaterial index.
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected,
+ false);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_InvalidDecreasingSingleStream) {
+ StreamParser::BufferQueue audio_buffers, video_buffers;
+ StreamParser::TextBufferQueueMap text_map;
+
+ int audio_timestamps[] = { 101, 102, 100, 103, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+
+ StreamParser::BufferQueue merged_buffers;
+ EXPECT_FALSE(StreamParser::MergeBufferQueues(audio_buffers, video_buffers,
+ text_map, &merged_buffers));
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_InvalidDecreasingMultipleStreams) {
+ StreamParser::BufferQueue audio_buffers, video_buffers;
+ StreamParser::TextBufferQueueMap text_map;
+
+ int audio_timestamps[] = { 101, 102, 100, 103, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+ int video_timestamps[] = { 104, 100, kEnd };
+ GenerateBuffers(&video_buffers, video_timestamps, StreamParserBuffer::kVideo);
+
+ StreamParser::BufferQueue merged_buffers;
+ EXPECT_FALSE(StreamParser::MergeBufferQueues(audio_buffers, video_buffers,
+ text_map, &merged_buffers));
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_ValidAppendToExistingMerge) {
+ StreamParser::BufferQueue audio_buffers, video_buffers, text_1, text_2;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "A100 V101 T1:102 V103 T2:104 A105 V106 T1:107";
+ int audio_timestamps[] = { 100, 105, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+ int video_timestamps[] = { 101, 103, 106, kEnd };
+ GenerateBuffers(&video_buffers, video_timestamps, StreamParserBuffer::kVideo);
+ int text_timestamps_1[] = { 102, 107, kEnd };
+ GenerateTextBuffers(&text_1, text_timestamps_1, 1);
+ int text_timestamps_2[] = { 104, kEnd };
+ GenerateTextBuffers(&text_2, text_timestamps_2, 2);
+ text_map.insert(std::make_pair(50, text_1)); // Immaterial index.
+ text_map.insert(std::make_pair(51, text_2)); // Immaterial index.
+ StreamParser::BufferQueue merged_buffers;
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true,
+ &merged_buffers);
+
+ audio_buffers.clear();
+ video_buffers.clear();
+ text_1.clear();
+ text_2.clear();
+ text_map.clear();
+
+ expected = "A100 V101 T1:102 V103 T2:104 A105 V106 T1:107 "
+ "A107 V111 T1:112 V113 T2:114 A115 V116 T1:117";
+ int more_audio_timestamps[] = { 107, 115, kEnd };
+ GenerateBuffers(&audio_buffers, more_audio_timestamps,
+ StreamParserBuffer::kAudio);
+ int more_video_timestamps[] = { 111, 113, 116, kEnd };
+ GenerateBuffers(&video_buffers, more_video_timestamps,
+ StreamParserBuffer::kVideo);
+ int more_text_timestamps_1[] = { 112, 117, kEnd };
+ GenerateTextBuffers(&text_1, more_text_timestamps_1, 1);
+ int more_text_timestamps_2[] = { 114, kEnd };
+ GenerateTextBuffers(&text_2, more_text_timestamps_2, 2);
+ text_map.insert(std::make_pair(50, text_1)); // Immaterial index.
+ text_map.insert(std::make_pair(51, text_2)); // Immaterial index.
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true,
+ &merged_buffers);
+}
+
+TEST_F(StreamParserTest, MergeBufferQueues_InvalidAppendToExistingMerge) {
+ StreamParser::BufferQueue audio_buffers, video_buffers, text_1, text_2;
+ StreamParser::TextBufferQueueMap text_map;
+
+ std::string expected = "A100 V101 T1:102 V103 T2:104 A105 V106 T1:107";
+ int audio_timestamps[] = { 100, 105, kEnd };
+ GenerateBuffers(&audio_buffers, audio_timestamps, StreamParserBuffer::kAudio);
+ int video_timestamps[] = { 101, 103, 106, kEnd };
+ GenerateBuffers(&video_buffers, video_timestamps, StreamParserBuffer::kVideo);
+ int text_timestamps_1[] = { 102, 107, kEnd };
+ GenerateTextBuffers(&text_1, text_timestamps_1, 1);
+ int text_timestamps_2[] = { 104, kEnd };
+ GenerateTextBuffers(&text_2, text_timestamps_2, 2);
+ text_map.insert(std::make_pair(50, text_1)); // Immaterial index.
+ text_map.insert(std::make_pair(51, text_2)); // Immaterial index.
+ StreamParser::BufferQueue merged_buffers;
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true,
+ &merged_buffers);
+
+ audio_buffers.clear();
+ video_buffers.clear();
+ text_1.clear();
+ text_2.clear();
+ text_map.clear();
+
+ // Appending empty buffers to pre-existing merge result should succeed and not
+ // change the existing result.
+ VerifySuccessfulMerge(audio_buffers, video_buffers, text_map, expected, true,
+ &merged_buffers);
+
+ // But appending something with a lower timestamp than the last timestamp
+ // in the pre-existing merge result should fail.
+ int more_audio_timestamps[] = { 106, kEnd };
+ GenerateBuffers(&audio_buffers, more_audio_timestamps,
+ StreamParserBuffer::kAudio);
+ EXPECT_FALSE(StreamParser::MergeBufferQueues(audio_buffers, video_buffers,
+ text_map, &merged_buffers));
+}
+
+} // namespace media
+

Powered by Google App Engine
This is Rietveld 408576698