This source file includes following definitions.
- IsAudio
- IsVideo
- IsText
- GenerateBuffers
- CountMatchingMergedBuffers
- GenerateAudioBuffers
- GenerateVideoBuffers
- GenerateTextBuffers
- MergedBufferQueueString
- VerifyMergeSuccess
- VerifyMergeFailure
- ClearQueuesAndTextMapButKeepAnyMergedBuffers
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include <algorithm>
#include <sstream>
#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 {
typedef StreamParser::TrackId TrackId;
typedef StreamParser::BufferQueue BufferQueue;
typedef StreamParser::TextBufferQueueMap TextBufferQueueMap;
const int kEnd = -1;
const uint8 kFakeData[] = { 0xFF };
const TrackId kAudioTrackId = 0;
const TrackId kVideoTrackId = 1;
const TrackId kTextTrackIdA = 2;
const TrackId kTextTrackIdB = 3;
static bool IsAudio(scoped_refptr<StreamParserBuffer> buffer) {
return buffer->type() == DemuxerStream::AUDIO;
}
static bool IsVideo(scoped_refptr<StreamParserBuffer> buffer) {
return buffer->type() == DemuxerStream::VIDEO;
}
static bool IsText(scoped_refptr<StreamParserBuffer> buffer) {
return buffer->type() == DemuxerStream::TEXT;
}
static void GenerateBuffers(const int* decode_timestamps,
StreamParserBuffer::Type type,
TrackId track_id,
BufferQueue* queue) {
DCHECK(decode_timestamps);
DCHECK(queue);
DCHECK_NE(type, DemuxerStream::UNKNOWN);
DCHECK_LT(type, DemuxerStream::NUM_TYPES);
for (int i = 0; decode_timestamps[i] != kEnd; ++i) {
scoped_refptr<StreamParserBuffer> buffer =
StreamParserBuffer::CopyFrom(kFakeData, sizeof(kFakeData),
true, type, track_id);
buffer->SetDecodeTimestamp(
base::TimeDelta::FromMicroseconds(decode_timestamps[i]));
queue->push_back(buffer);
}
}
class StreamParserTest : public testing::Test {
protected:
StreamParserTest() {}
size_t CountMatchingMergedBuffers(
bool (*predicate)(scoped_refptr<StreamParserBuffer> buffer)) {
return static_cast<size_t>(count_if(merged_buffers_.begin(),
merged_buffers_.end(),
predicate));
}
void GenerateAudioBuffers(const int* decode_timestamps) {
GenerateBuffers(decode_timestamps, DemuxerStream::AUDIO, kAudioTrackId,
&audio_buffers_);
}
void GenerateVideoBuffers(const int* decode_timestamps) {
GenerateBuffers(decode_timestamps, DemuxerStream::VIDEO, kVideoTrackId,
&video_buffers_);
}
void GenerateTextBuffers(const int* decode_timestamps_a,
const int* decode_timestamps_b) {
if (decode_timestamps_a) {
GenerateBuffers(decode_timestamps_a, DemuxerStream::TEXT, kTextTrackIdA,
&text_buffers_a_);
text_map_.insert(std::make_pair(kTextTrackIdA, text_buffers_a_));
}
if (decode_timestamps_b) {
GenerateBuffers(decode_timestamps_b, DemuxerStream::TEXT, kTextTrackIdB,
&text_buffers_b_);
text_map_.insert(std::make_pair(kTextTrackIdB, text_buffers_b_));
}
}
std::string MergedBufferQueueString(bool include_type_and_text_track) {
std::stringstream results_stream;
for (BufferQueue::const_iterator itr = merged_buffers_.begin();
itr != merged_buffers_.end();
++itr) {
if (itr != merged_buffers_.begin())
results_stream << " ";
const StreamParserBuffer& buffer = *(*itr);
if (include_type_and_text_track) {
switch (buffer.type()) {
case DemuxerStream::AUDIO:
results_stream << "A";
break;
case DemuxerStream::VIDEO:
results_stream << "V";
break;
case DemuxerStream::TEXT:
results_stream << "T";
break;
default:
NOTREACHED();
}
results_stream << buffer.track_id() << ":";
}
results_stream << buffer.GetDecodeTimestamp().InMicroseconds();
}
return results_stream.str();
}
void VerifyMergeSuccess(const std::string& expected,
bool verify_type_and_text_track_sequence) {
size_t original_audio_in_merged = CountMatchingMergedBuffers(IsAudio);
size_t original_video_in_merged = CountMatchingMergedBuffers(IsVideo);
size_t original_text_in_merged = CountMatchingMergedBuffers(IsText);
EXPECT_TRUE(MergeBufferQueues(audio_buffers_, video_buffers_, text_map_,
&merged_buffers_));
EXPECT_EQ(expected,
MergedBufferQueueString(verify_type_and_text_track_sequence));
size_t audio_in_merged = CountMatchingMergedBuffers(IsAudio);
size_t video_in_merged = CountMatchingMergedBuffers(IsVideo);
size_t text_in_merged = CountMatchingMergedBuffers(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 (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 VerifyMergeFailure() {
EXPECT_FALSE(MergeBufferQueues(audio_buffers_, video_buffers_, text_map_,
&merged_buffers_));
}
void ClearQueuesAndTextMapButKeepAnyMergedBuffers() {
audio_buffers_.clear();
video_buffers_.clear();
text_buffers_a_.clear();
text_buffers_b_.clear();
text_map_.clear();
}
private:
BufferQueue audio_buffers_;
BufferQueue video_buffers_;
BufferQueue text_buffers_a_;
BufferQueue text_buffers_b_;
BufferQueue merged_buffers_;
TextBufferQueueMap text_map_;
DISALLOW_COPY_AND_ASSIGN(StreamParserTest);
};
TEST_F(StreamParserTest, MergeBufferQueues_AllEmpty) {
std::string expected = "";
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_SingleAudioBuffer) {
std::string expected = "A0:100";
int audio_timestamps[] = { 100, kEnd };
GenerateAudioBuffers(audio_timestamps);
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_SingleVideoBuffer) {
std::string expected = "V1:100";
int video_timestamps[] = { 100, kEnd };
GenerateVideoBuffers(video_timestamps);
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_SingleTextBuffer) {
std::string expected = "T2:100";
int text_timestamps[] = { 100, kEnd };
GenerateTextBuffers(text_timestamps, NULL);
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_OverlappingAudioVideo) {
std::string expected = "A0:100 V1:101 V1:102 A0:103 A0:104 V1:105";
int audio_timestamps[] = { 100, 103, 104, kEnd };
GenerateAudioBuffers(audio_timestamps);
int video_timestamps[] = { 101, 102, 105, kEnd };
GenerateVideoBuffers(video_timestamps);
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_OverlappingMultipleText) {
std::string expected = "T2:100 T2:101 T3:103 T2:104 T3:105 T3:106";
int text_timestamps_a[] = { 100, 101, 104, kEnd };
int text_timestamps_b[] = { 103, 105, 106, kEnd };
GenerateTextBuffers(text_timestamps_a, text_timestamps_b);
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_OverlappingAudioVideoText) {
std::string expected = "A0:100 V1:101 T2:102 V1:103 T3:104 A0:105 V1:106 "
"T2:107";
int audio_timestamps[] = { 100, 105, kEnd };
GenerateAudioBuffers(audio_timestamps);
int video_timestamps[] = { 101, 103, 106, kEnd };
GenerateVideoBuffers(video_timestamps);
int text_timestamps_a[] = { 102, 107, kEnd };
int text_timestamps_b[] = { 104, kEnd };
GenerateTextBuffers(text_timestamps_a, text_timestamps_b);
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_NonDecreasingNoCrossMediaDuplicate) {
std::string expected = "A0:100 A0:100 A0:100 V1:101 V1:101 V1:101 A0:102 "
"V1:103 V1:103";
int audio_timestamps[] = { 100, 100, 100, 102, kEnd };
GenerateAudioBuffers(audio_timestamps);
int video_timestamps[] = { 101, 101, 101, 103, 103, kEnd };
GenerateVideoBuffers(video_timestamps);
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_CrossStreamDuplicates) {
std::string expected = "100 100 100 100 100 100 102 102 102 102 102 102 102";
int audio_timestamps[] = { 100, 100, 100, 102, kEnd };
GenerateAudioBuffers(audio_timestamps);
int video_timestamps[] = { 100, 100, 102, 102, 102, kEnd };
GenerateVideoBuffers(video_timestamps);
int text_timestamps[] = { 100, 102, 102, 102, kEnd };
GenerateTextBuffers(text_timestamps, NULL);
VerifyMergeSuccess(expected, false);
}
TEST_F(StreamParserTest, MergeBufferQueues_InvalidDecreasingSingleStream) {
int audio_timestamps[] = { 101, 102, 100, 103, kEnd };
GenerateAudioBuffers(audio_timestamps);
VerifyMergeFailure();
}
TEST_F(StreamParserTest, MergeBufferQueues_InvalidDecreasingMultipleStreams) {
int audio_timestamps[] = { 101, 102, 100, 103, kEnd };
GenerateAudioBuffers(audio_timestamps);
int video_timestamps[] = { 104, 100, kEnd };
GenerateVideoBuffers(video_timestamps);
VerifyMergeFailure();
}
TEST_F(StreamParserTest, MergeBufferQueues_ValidAppendToExistingMerge) {
std::string expected = "A0:100 V1:101 T2:102 V1:103 T3:104 A0:105 V1:106 "
"T2:107";
int audio_timestamps[] = { 100, 105, kEnd };
GenerateAudioBuffers(audio_timestamps);
int video_timestamps[] = { 101, 103, 106, kEnd };
GenerateVideoBuffers(video_timestamps);
int text_timestamps_a[] = { 102, 107, kEnd };
int text_timestamps_b[] = { 104, kEnd };
GenerateTextBuffers(text_timestamps_a, text_timestamps_b);
VerifyMergeSuccess(expected, true);
ClearQueuesAndTextMapButKeepAnyMergedBuffers();
expected = "A0:100 V1:101 T2:102 V1:103 T3:104 A0:105 V1:106 T2:107 "
"A0:107 V1:111 T2:112 V1:113 T3:114 A0:115 V1:116 T2:117";
int more_audio_timestamps[] = { 107, 115, kEnd };
GenerateAudioBuffers(more_audio_timestamps);
int more_video_timestamps[] = { 111, 113, 116, kEnd };
GenerateVideoBuffers(more_video_timestamps);
int more_text_timestamps_a[] = { 112, 117, kEnd };
int more_text_timestamps_b[] = { 114, kEnd };
GenerateTextBuffers(more_text_timestamps_a, more_text_timestamps_b);
VerifyMergeSuccess(expected, true);
}
TEST_F(StreamParserTest, MergeBufferQueues_InvalidAppendToExistingMerge) {
std::string expected = "A0:100 V1:101 T2:102 V1:103 T3:104 A0:105 V1:106 "
"T2:107";
int audio_timestamps[] = { 100, 105, kEnd };
GenerateAudioBuffers(audio_timestamps);
int video_timestamps[] = { 101, 103, 106, kEnd };
GenerateVideoBuffers(video_timestamps);
int text_timestamps_a[] = { 102, 107, kEnd };
int text_timestamps_b[] = { 104, kEnd };
GenerateTextBuffers(text_timestamps_a, text_timestamps_b);
VerifyMergeSuccess(expected, true);
ClearQueuesAndTextMapButKeepAnyMergedBuffers();
VerifyMergeSuccess(expected, true);
int more_audio_timestamps[] = { 106, kEnd };
GenerateAudioBuffers(more_audio_timestamps);
VerifyMergeFailure();
}
}