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 "base/logging.h"
6#include "media/base/channel_layout.h"
7#include "media/formats/webm/tracks_builder.h"
8#include "media/formats/webm/webm_constants.h"
9#include "media/formats/webm/webm_tracks_parser.h"
10#include "testing/gmock/include/gmock/gmock.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13using ::testing::InSequence;
14using ::testing::Return;
15using ::testing::_;
16
17namespace media {
18
19static const double kDefaultTimecodeScaleInUs = 1000.0;  // 1 ms resolution
20
21class WebMTracksParserTest : public testing::Test {
22 public:
23  WebMTracksParserTest() {}
24};
25
26static void VerifyTextTrackInfo(const uint8* buffer,
27                                int buffer_size,
28                                TextKind text_kind,
29                                const std::string& name,
30                                const std::string& language) {
31  scoped_ptr<WebMTracksParser> parser(new WebMTracksParser(LogCB(), false));
32
33  int result = parser->Parse(buffer, buffer_size);
34  EXPECT_GT(result, 0);
35  EXPECT_EQ(result, buffer_size);
36
37  const WebMTracksParser::TextTracks& text_tracks = parser->text_tracks();
38  EXPECT_EQ(text_tracks.size(), WebMTracksParser::TextTracks::size_type(1));
39
40  const WebMTracksParser::TextTracks::const_iterator itr = text_tracks.begin();
41  EXPECT_EQ(itr->first, 1);  // track num
42
43  const TextTrackConfig& config = itr->second;
44  EXPECT_EQ(config.kind(), text_kind);
45  EXPECT_TRUE(config.label() == name);
46  EXPECT_TRUE(config.language() == language);
47}
48
49TEST_F(WebMTracksParserTest, SubtitleNoNameNoLang) {
50  InSequence s;
51
52  TracksBuilder tb;
53  tb.AddTextTrack(1, 1, kWebMCodecSubtitles, "", "");
54
55  const std::vector<uint8> buf = tb.Finish();
56  VerifyTextTrackInfo(&buf[0], buf.size(), kTextSubtitles, "", "");
57}
58
59TEST_F(WebMTracksParserTest, SubtitleYesNameNoLang) {
60  InSequence s;
61
62  TracksBuilder tb;
63  tb.AddTextTrack(1, 1, kWebMCodecSubtitles, "Spock", "");
64
65  const std::vector<uint8> buf = tb.Finish();
66  VerifyTextTrackInfo(&buf[0], buf.size(), kTextSubtitles, "Spock", "");
67}
68
69TEST_F(WebMTracksParserTest, SubtitleNoNameYesLang) {
70  InSequence s;
71
72  TracksBuilder tb;
73  tb.AddTextTrack(1, 1, kWebMCodecSubtitles, "", "eng");
74
75  const std::vector<uint8> buf = tb.Finish();
76  VerifyTextTrackInfo(&buf[0], buf.size(), kTextSubtitles, "", "eng");
77}
78
79TEST_F(WebMTracksParserTest, SubtitleYesNameYesLang) {
80  InSequence s;
81
82  TracksBuilder tb;
83  tb.AddTextTrack(1, 1, kWebMCodecSubtitles, "Picard", "fre");
84
85  const std::vector<uint8> buf = tb.Finish();
86  VerifyTextTrackInfo(&buf[0], buf.size(), kTextSubtitles, "Picard", "fre");
87}
88
89TEST_F(WebMTracksParserTest, IgnoringTextTracks) {
90  InSequence s;
91
92  TracksBuilder tb;
93  tb.AddTextTrack(1, 1, kWebMCodecSubtitles, "Subtitles", "fre");
94  tb.AddTextTrack(2, 2, kWebMCodecSubtitles, "Commentary", "fre");
95
96  const std::vector<uint8> buf = tb.Finish();
97  scoped_ptr<WebMTracksParser> parser(new WebMTracksParser(LogCB(), true));
98
99  int result = parser->Parse(&buf[0], buf.size());
100  EXPECT_GT(result, 0);
101  EXPECT_EQ(result, static_cast<int>(buf.size()));
102
103  EXPECT_EQ(parser->text_tracks().size(), 0u);
104
105  const std::set<int64>& ignored_tracks = parser->ignored_tracks();
106  EXPECT_TRUE(ignored_tracks.find(1) != ignored_tracks.end());
107  EXPECT_TRUE(ignored_tracks.find(2) != ignored_tracks.end());
108
109  // Test again w/o ignoring the test tracks.
110  parser.reset(new WebMTracksParser(LogCB(), false));
111
112  result = parser->Parse(&buf[0], buf.size());
113  EXPECT_GT(result, 0);
114
115  EXPECT_EQ(parser->ignored_tracks().size(), 0u);
116  EXPECT_EQ(parser->text_tracks().size(), 2u);
117}
118
119TEST_F(WebMTracksParserTest, AudioVideoDefaultDurationUnset) {
120  // Other audio/video decoder config fields are necessary in the test
121  // audio/video TrackEntry configurations. This method does only very minimal
122  // verification of their inclusion and parsing; the goal is to confirm
123  // TrackEntry DefaultDuration defaults to -1 if not included in audio or
124  // video TrackEntry.
125  TracksBuilder tb;
126  tb.AddAudioTrack(1, 1, "A_VORBIS", "audio", "", -1, 2, 8000);
127  tb.AddVideoTrack(2, 2, "V_VP8", "video", "", -1, 320, 240);
128  const std::vector<uint8> buf = tb.Finish();
129
130  scoped_ptr<WebMTracksParser> parser(new WebMTracksParser(LogCB(), true));
131  int result = parser->Parse(&buf[0], buf.size());
132  EXPECT_LE(0, result);
133  EXPECT_EQ(static_cast<int>(buf.size()), result);
134
135  EXPECT_EQ(kNoTimestamp(),
136            parser->GetAudioDefaultDuration(kDefaultTimecodeScaleInUs));
137  EXPECT_EQ(kNoTimestamp(),
138            parser->GetVideoDefaultDuration(kDefaultTimecodeScaleInUs));
139
140  const VideoDecoderConfig& video_config = parser->video_decoder_config();
141  EXPECT_TRUE(video_config.IsValidConfig());
142  EXPECT_EQ(320, video_config.coded_size().width());
143  EXPECT_EQ(240, video_config.coded_size().height());
144
145  const AudioDecoderConfig& audio_config = parser->audio_decoder_config();
146  EXPECT_TRUE(audio_config.IsValidConfig());
147  EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout());
148  EXPECT_EQ(8000, audio_config.samples_per_second());
149}
150
151TEST_F(WebMTracksParserTest, AudioVideoDefaultDurationSet) {
152  // Confirm audio or video TrackEntry DefaultDuration values are parsed, if
153  // present.
154  TracksBuilder tb;
155  tb.AddAudioTrack(1, 1, "A_VORBIS", "audio", "", 12345678, 2, 8000);
156  tb.AddVideoTrack(2, 2, "V_VP8", "video", "", 987654321, 320, 240);
157  const std::vector<uint8> buf = tb.Finish();
158
159  scoped_ptr<WebMTracksParser> parser(new WebMTracksParser(LogCB(), true));
160  int result = parser->Parse(&buf[0], buf.size());
161  EXPECT_LE(0, result);
162  EXPECT_EQ(static_cast<int>(buf.size()), result);
163
164  EXPECT_EQ(base::TimeDelta::FromMicroseconds(12000),
165            parser->GetAudioDefaultDuration(kDefaultTimecodeScaleInUs));
166  EXPECT_EQ(base::TimeDelta::FromMicroseconds(985000),
167            parser->GetVideoDefaultDuration(5000.0));  // 5 ms resolution
168  EXPECT_EQ(kNoTimestamp(), parser->GetAudioDefaultDuration(12346.0));
169  EXPECT_EQ(base::TimeDelta::FromMicroseconds(12345),
170            parser->GetAudioDefaultDuration(12345.0));
171  EXPECT_EQ(base::TimeDelta::FromMicroseconds(12003),
172            parser->GetAudioDefaultDuration(1000.3));  // 1.0003 ms resolution
173}
174
175TEST_F(WebMTracksParserTest, InvalidZeroDefaultDurationSet) {
176  // Confirm parse error if TrackEntry DefaultDuration is present, but is 0ns.
177  TracksBuilder tb(true);
178  tb.AddAudioTrack(1, 1, "A_VORBIS", "audio", "", 0, 2, 8000);
179  const std::vector<uint8> buf = tb.Finish();
180
181  scoped_ptr<WebMTracksParser> parser(new WebMTracksParser(LogCB(), true));
182  EXPECT_EQ(-1, parser->Parse(&buf[0], buf.size()));
183}
184
185TEST_F(WebMTracksParserTest, HighTrackUID) {
186  // Confirm no parse error if TrackEntry TrackUID has MSb set
187  // (http://crbug.com/397067).
188  TracksBuilder tb(true);
189  tb.AddAudioTrack(1, 1ULL << 31, "A_VORBIS", "audio", "", 40, 2, 8000);
190  const std::vector<uint8> buf = tb.Finish();
191
192  scoped_ptr<WebMTracksParser> parser(new WebMTracksParser(LogCB(), true));
193  EXPECT_GT(parser->Parse(&buf[0], buf.size()),0);
194}
195
196}  // namespace media
197