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
13 using ::testing::InSequence;
14 using ::testing::Return;
15 using ::testing::_;
16
17 namespace media {
18
19 static const double kDefaultTimecodeScaleInUs = 1000.0; // 1 ms resolution
20
21 class WebMTracksParserTest : public testing::Test {
22 public:
WebMTracksParserTest()23 WebMTracksParserTest() {}
24 };
25
VerifyTextTrackInfo(const uint8 * buffer,int buffer_size,TextKind text_kind,const std::string & name,const std::string & language)26 static 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
TEST_F(WebMTracksParserTest,SubtitleNoNameNoLang)49 TEST_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
TEST_F(WebMTracksParserTest,SubtitleYesNameNoLang)59 TEST_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
TEST_F(WebMTracksParserTest,SubtitleNoNameYesLang)69 TEST_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
TEST_F(WebMTracksParserTest,SubtitleYesNameYesLang)79 TEST_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
TEST_F(WebMTracksParserTest,IgnoringTextTracks)89 TEST_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
TEST_F(WebMTracksParserTest,AudioVideoDefaultDurationUnset)119 TEST_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
TEST_F(WebMTracksParserTest,AudioVideoDefaultDurationSet)151 TEST_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
TEST_F(WebMTracksParserTest,InvalidZeroDefaultDurationSet)175 TEST_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
TEST_F(WebMTracksParserTest,HighTrackUID)185 TEST_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