1// Copyright 2013 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 "base/bind.h"
6#include "media/base/audio_decoder_config.h"
7#include "media/base/decoder_buffer.h"
8#include "media/base/stream_parser_buffer.h"
9#include "media/base/test_data_util.h"
10#include "media/base/text_track_config.h"
11#include "media/base/video_decoder_config.h"
12#include "media/mp3/mp3_stream_parser.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace media {
16
17class MP3StreamParserTest : public testing::Test {
18 public:
19  MP3StreamParserTest() {}
20
21 protected:
22  MP3StreamParser parser_;
23  std::stringstream results_stream_;
24
25  bool AppendData(const uint8* data, size_t length) {
26    return parser_.Parse(data, length);
27  }
28
29  bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) {
30    const uint8* start = data;
31    const uint8* end = data + length;
32    while (start < end) {
33      size_t append_size =
34          std::min(piece_size, static_cast<size_t>(end - start));
35      if (!AppendData(start, append_size))
36        return false;
37      start += append_size;
38    }
39    return true;
40  }
41
42  void OnInitDone(bool success, base::TimeDelta duration) {
43    DVLOG(1) << __FUNCTION__ << "(" << success << ", "
44             << duration.InMilliseconds() << ")";
45  }
46
47  bool OnNewConfig(const AudioDecoderConfig& audio_config,
48                   const VideoDecoderConfig& video_config,
49                   const StreamParser::TextTrackConfigMap& text_config) {
50    DVLOG(1) << __FUNCTION__ << "(" << audio_config.IsValidConfig() << ", "
51             << video_config.IsValidConfig() << ")";
52    EXPECT_TRUE(audio_config.IsValidConfig());
53    EXPECT_FALSE(video_config.IsValidConfig());
54    return true;
55  }
56
57  std::string BufferQueueToString(const StreamParser::BufferQueue& buffers) {
58    std::stringstream ss;
59
60    ss << "{";
61    for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
62         itr != buffers.end();
63         ++itr) {
64      ss << " " << (*itr)->timestamp().InMilliseconds();
65      if ((*itr)->IsKeyframe())
66        ss << "K";
67    }
68    ss << " }";
69
70    return ss.str();
71  }
72
73  bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
74                    const StreamParser::BufferQueue& video_buffers) {
75    EXPECT_FALSE(audio_buffers.empty());
76    EXPECT_TRUE(video_buffers.empty());
77
78    std::string buffers_str = BufferQueueToString(audio_buffers);
79    DVLOG(1) << __FUNCTION__ << " : " << buffers_str;
80    results_stream_ << buffers_str;
81    return true;
82  }
83
84  void OnKeyNeeded(const std::string& type,
85                   const std::vector<uint8>& init_data) {
86    DVLOG(1) << __FUNCTION__ << "(" << type << ", " << init_data.size() << ")";
87  }
88
89  void OnNewSegment() {
90    DVLOG(1) << __FUNCTION__;
91    results_stream_ << "NewSegment";
92  }
93
94  void OnEndOfSegment() {
95    DVLOG(1) << __FUNCTION__;
96    results_stream_ << "EndOfSegment";
97  }
98
99  void InitializeParser() {
100    parser_.Init(
101        base::Bind(&MP3StreamParserTest::OnInitDone, base::Unretained(this)),
102        base::Bind(&MP3StreamParserTest::OnNewConfig, base::Unretained(this)),
103        base::Bind(&MP3StreamParserTest::OnNewBuffers, base::Unretained(this)),
104        StreamParser::NewTextBuffersCB(),
105        base::Bind(&MP3StreamParserTest::OnKeyNeeded, base::Unretained(this)),
106        base::Bind(&MP3StreamParserTest::OnNewSegment, base::Unretained(this)),
107        base::Bind(&MP3StreamParserTest::OnEndOfSegment,
108                   base::Unretained(this)),
109        LogCB());
110  }
111
112  std::string ParseFile(const std::string& filename, int append_bytes) {
113    results_stream_.clear();
114    InitializeParser();
115
116    scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
117    EXPECT_TRUE(
118        AppendDataInPieces(buffer->data(), buffer->data_size(), append_bytes));
119    return results_stream_.str();
120  }
121};
122
123// Test parsing with small prime sized chunks to smoke out "power of
124// 2" field size assumptions.
125TEST_F(MP3StreamParserTest, UnalignedAppend) {
126  std::string expected =
127      "NewSegment"
128      "{ 0K }"
129      "{ 26K }"
130      "{ 52K }"
131      "{ 78K }"
132      "{ 104K }"
133      "{ 130K }"
134      "{ 156K }"
135      "{ 182K }"
136      "EndOfSegment"
137      "NewSegment"
138      "{ 208K }"
139      "{ 235K }"
140      "{ 261K }"
141      "EndOfSegment"
142      "NewSegment"
143      "{ 287K }"
144      "{ 313K }"
145      "EndOfSegment";
146  EXPECT_EQ(expected, ParseFile("sfx.mp3", 17));
147}
148
149// Test parsing with a larger piece size to verify that multiple buffers
150// are passed to |new_buffer_cb_|.
151TEST_F(MP3StreamParserTest, UnalignedAppend512) {
152  std::string expected =
153      "NewSegment"
154      "{ 0K }"
155      "{ 26K 52K 78K 104K }"
156      "EndOfSegment"
157      "NewSegment"
158      "{ 130K 156K 182K }"
159      "{ 208K 235K 261K 287K }"
160      "{ 313K }"
161      "EndOfSegment";
162  EXPECT_EQ(expected, ParseFile("sfx.mp3", 512));
163}
164
165}  // namespace media
166