OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "media/filters/media_source_state.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/memory/ptr_util.h" | |
11 #include "base/strings/string_number_conversions.h" | |
12 #include "media/base/gmock_callback_support.h" | |
13 #include "media/base/media_util.h" | |
14 #include "media/base/mock_filters.h" | |
15 #include "media/base/mock_media_log.h" | |
16 #include "media/base/test_helpers.h" | |
17 #include "media/filters/frame_processor.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 | |
20 namespace media { | |
21 | |
22 using testing::_; | |
23 using testing::SaveArg; | |
24 | |
25 namespace { | |
26 | |
27 AudioDecoderConfig CreateAudioConfig(AudioCodec codec) { | |
28 return AudioDecoderConfig(codec, kSampleFormatPlanarF32, | |
29 CHANNEL_LAYOUT_STEREO, 1000, EmptyExtraData(), | |
30 Unencrypted()); | |
31 } | |
32 | |
33 VideoDecoderConfig CreateVideoConfig(VideoCodec codec, int w, int h) { | |
34 gfx::Size size(w, h); | |
35 gfx::Rect visible_rect(size); | |
36 return VideoDecoderConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, | |
37 PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709, size, | |
38 visible_rect, size, EmptyExtraData(), | |
39 Unencrypted()); | |
40 } | |
41 | |
42 void AddAudioTrack(std::unique_ptr<MediaTracks>& t, AudioCodec codec, int id) { | |
43 t->AddAudioTrack(CreateAudioConfig(codec), id, "", "", ""); | |
44 } | |
45 | |
46 void AddVideoTrack(std::unique_ptr<MediaTracks>& t, VideoCodec codec, int id) { | |
47 t->AddVideoTrack(CreateVideoConfig(codec, 16, 16), id, "", "", ""); | |
48 } | |
49 | |
50 void InvokeCbAndSaveResult(const base::Callback<bool()>& cb, bool* result) { | |
51 DCHECK(result); | |
52 *result = cb.Run(); | |
53 } | |
54 } | |
55 | |
56 class MediaSourceStateTest : public ::testing::Test { | |
57 public: | |
58 MediaSourceStateTest() | |
59 : media_log_(new testing::StrictMock<MockMediaLog>()), | |
60 mock_stream_parser_(nullptr) {} | |
61 | |
62 std::unique_ptr<MediaSourceState> CreateMediaSourceState() { | |
63 std::unique_ptr<FrameProcessor> frame_processor = base::WrapUnique( | |
64 new FrameProcessor(base::Bind(&MediaSourceStateTest::OnUpdateDuration, | |
65 base::Unretained(this)), | |
66 media_log_)); | |
67 mock_stream_parser_ = new testing::StrictMock<MockStreamParser>(); | |
68 return base::WrapUnique(new MediaSourceState( | |
69 base::WrapUnique(mock_stream_parser_), std::move(frame_processor), | |
70 base::Bind(&MediaSourceStateTest::CreateDemuxerStream, | |
71 base::Unretained(this)), | |
72 media_log_)); | |
73 } | |
74 | |
75 std::unique_ptr<MediaSourceState> CreateAndInitMediaSourceState( | |
76 const std::string& expected_codecs) { | |
77 std::unique_ptr<MediaSourceState> mss = CreateMediaSourceState(); | |
78 EXPECT_CALL(*mock_stream_parser_, Init(_, _, _, _, _, _, _, _)) | |
79 .WillOnce(SaveArg<1>(&new_config_cb_)); | |
80 mss->Init(base::Bind(&MediaSourceStateTest::SourceInitDone, | |
81 base::Unretained(this)), | |
82 expected_codecs, | |
83 base::Bind(&MediaSourceStateTest::StreamParserEncryptedInitData, | |
84 base::Unretained(this)), | |
85 base::Bind(&MediaSourceStateTest::StreamParserNewTextTrack, | |
86 base::Unretained(this))); | |
87 | |
88 mss->SetTracksWatcher(base::Bind( | |
89 &MediaSourceStateTest::OnMediaTracksUpdated, base::Unretained(this))); | |
90 return mss; | |
91 } | |
92 | |
93 // Emulates appending some data to the MediaSourceState, since OnNewConfigs | |
94 // can only be invoked when append is in progress. | |
95 bool AppendDataAndReportTracks(const std::unique_ptr<MediaSourceState>& mss, | |
96 std::unique_ptr<MediaTracks> tracks) { | |
97 const uint8_t stream_data[] = "stream_data"; | |
98 const int data_size = sizeof(stream_data); | |
99 base::TimeDelta t; | |
100 StreamParser::TextTrackConfigMap text_track_config_map; | |
101 | |
102 bool new_configs_result = false; | |
103 base::Closure new_configs_closure = | |
104 base::Bind(InvokeCbAndSaveResult, | |
105 base::Bind(new_config_cb_, base::Passed(std::move(tracks)), | |
106 text_track_config_map), | |
107 &new_configs_result); | |
108 EXPECT_CALL(*mock_stream_parser_, Parse(stream_data, data_size)) | |
109 .WillOnce(testing::DoAll(RunClosure(new_configs_closure), | |
110 testing::Return(true))); | |
111 mss->Append(stream_data, data_size, t, t, &t); | |
112 return new_configs_result; | |
113 } | |
114 | |
115 MOCK_METHOD1(OnUpdateDuration, void(base::TimeDelta)); | |
116 | |
117 MOCK_METHOD1(SourceInitDone, void(const StreamParser::InitParameters&)); | |
118 MOCK_METHOD2(StreamParserEncryptedInitData, | |
119 void(EmeInitDataType, const std::vector<uint8_t>&)); | |
120 MOCK_METHOD2(StreamParserNewTextTrack, | |
121 void(ChunkDemuxerStream*, const TextTrackConfig&)); | |
122 | |
123 MOCK_METHOD1(MediaTracksUpdatedMock, void(std::unique_ptr<MediaTracks>&)); | |
124 void OnMediaTracksUpdated(std::unique_ptr<MediaTracks> tracks) { | |
125 MediaTracksUpdatedMock(tracks); | |
126 } | |
127 | |
128 ChunkDemuxerStream* CreateDemuxerStream(DemuxerStream::Type type) { | |
129 static unsigned track_id = 0; | |
130 demuxer_streams_.push_back(base::WrapUnique( | |
131 new ChunkDemuxerStream(type, false, base::UintToString(++track_id)))); | |
132 return demuxer_streams_.back().get(); | |
133 } | |
134 | |
135 scoped_refptr<testing::StrictMock<MockMediaLog>> media_log_; | |
136 std::vector<std::unique_ptr<ChunkDemuxerStream>> demuxer_streams_; | |
137 MockStreamParser* mock_stream_parser_; | |
138 StreamParser::NewConfigCB new_config_cb_; | |
139 }; | |
140 | |
141 TEST_F(MediaSourceStateTest, InitSingleAudioTrack) { | |
142 std::unique_ptr<MediaSourceState> mss = | |
143 CreateAndInitMediaSourceState("vorbis"); | |
144 | |
145 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
146 AddAudioTrack(tracks, kCodecVorbis, 1); | |
147 | |
148 EXPECT_MEDIA_LOG(FoundStream("audio")); | |
149 EXPECT_MEDIA_LOG(CodecName("audio", "vorbis")); | |
150 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
151 EXPECT_TRUE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
152 } | |
153 | |
154 TEST_F(MediaSourceStateTest, InitSingleVideoTrack) { | |
155 std::unique_ptr<MediaSourceState> mss = CreateAndInitMediaSourceState("vp8"); | |
156 | |
157 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
158 AddVideoTrack(tracks, kCodecVP8, 1); | |
159 | |
160 EXPECT_MEDIA_LOG(FoundStream("video")); | |
161 EXPECT_MEDIA_LOG(CodecName("video", "vp8")); | |
162 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
163 EXPECT_TRUE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
164 } | |
165 | |
166 TEST_F(MediaSourceStateTest, InitMultipleTracks) { | |
167 std::unique_ptr<MediaSourceState> mss = | |
168 CreateAndInitMediaSourceState("vorbis,vp8,opus,vp9"); | |
169 | |
170 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
171 AddAudioTrack(tracks, kCodecVorbis, 1); | |
172 AddAudioTrack(tracks, kCodecOpus, 2); | |
173 AddVideoTrack(tracks, kCodecVP8, 3); | |
174 AddVideoTrack(tracks, kCodecVP9, 4); | |
175 | |
176 EXPECT_MEDIA_LOG(FoundStream("audio")).Times(2); | |
177 EXPECT_MEDIA_LOG(CodecName("audio", "vorbis")); | |
178 EXPECT_MEDIA_LOG(CodecName("audio", "opus")); | |
179 EXPECT_MEDIA_LOG(FoundStream("video")).Times(2); | |
180 EXPECT_MEDIA_LOG(CodecName("video", "vp8")); | |
181 EXPECT_MEDIA_LOG(CodecName("video", "vp9")); | |
182 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
183 EXPECT_TRUE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
184 } | |
185 | |
186 TEST_F(MediaSourceStateTest, AudioStreamMismatchesExpectedCodecs) { | |
187 std::unique_ptr<MediaSourceState> mss = CreateAndInitMediaSourceState("opus"); | |
188 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
189 AddAudioTrack(tracks, kCodecVorbis, 1); | |
190 EXPECT_MEDIA_LOG(InitSegmentMismatchesMimeType("Audio", "vorbis")); | |
191 EXPECT_FALSE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
192 } | |
193 | |
194 TEST_F(MediaSourceStateTest, VideoStreamMismatchesExpectedCodecs) { | |
195 std::unique_ptr<MediaSourceState> mss = CreateAndInitMediaSourceState("vp9"); | |
196 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
197 AddVideoTrack(tracks, kCodecVP8, 1); | |
198 EXPECT_MEDIA_LOG(InitSegmentMismatchesMimeType("Video", "vp8")); | |
199 EXPECT_FALSE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
200 } | |
201 | |
202 TEST_F(MediaSourceStateTest, MissingExpectedAudioStream) { | |
203 std::unique_ptr<MediaSourceState> mss = | |
204 CreateAndInitMediaSourceState("opus,vp9"); | |
205 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
206 AddVideoTrack(tracks, kCodecVP9, 1); | |
207 EXPECT_MEDIA_LOG(FoundStream("video")); | |
208 EXPECT_MEDIA_LOG(CodecName("video", "vp9")); | |
209 EXPECT_MEDIA_LOG(InitSegmentMissesExpectedTrack("opus")); | |
210 EXPECT_FALSE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
211 } | |
212 | |
213 TEST_F(MediaSourceStateTest, MissingExpectedVideoStream) { | |
214 std::unique_ptr<MediaSourceState> mss = | |
215 CreateAndInitMediaSourceState("opus,vp9"); | |
216 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
217 tracks->AddAudioTrack(CreateAudioConfig(kCodecOpus), 1, "", "", ""); | |
218 EXPECT_MEDIA_LOG(FoundStream("audio")); | |
219 EXPECT_MEDIA_LOG(CodecName("audio", "opus")); | |
220 EXPECT_MEDIA_LOG(InitSegmentMissesExpectedTrack("vp9")); | |
221 EXPECT_FALSE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
222 } | |
223 | |
224 TEST_F(MediaSourceStateTest, TrackIdsChangeInSecondInitSegment) { | |
225 std::unique_ptr<MediaSourceState> mss = | |
226 CreateAndInitMediaSourceState("opus,vp9"); | |
227 | |
228 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
229 AddAudioTrack(tracks, kCodecOpus, 1); | |
230 AddVideoTrack(tracks, kCodecVP9, 2); | |
231 EXPECT_MEDIA_LOG(FoundStream("audio")); | |
232 EXPECT_MEDIA_LOG(CodecName("audio", "opus")); | |
233 EXPECT_MEDIA_LOG(FoundStream("video")); | |
234 EXPECT_MEDIA_LOG(CodecName("video", "vp9")); | |
235 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
236 AppendDataAndReportTracks(mss, std::move(tracks)); | |
237 | |
238 // This second set of tracks have bytestream track ids that differ from the | |
239 // first init segment above (audio track id 1 -> 3, video track id 2 -> 4). | |
240 // Bytestream track ids are allowed to change when there is only a single | |
241 // track of each type. | |
242 std::unique_ptr<MediaTracks> tracks2(new MediaTracks()); | |
243 AddAudioTrack(tracks2, kCodecOpus, 3); | |
244 AddVideoTrack(tracks2, kCodecVP9, 4); | |
245 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
246 AppendDataAndReportTracks(mss, std::move(tracks2)); | |
247 } | |
248 | |
249 TEST_F(MediaSourceStateTest, TrackIdChangeWithTwoAudioTracks) { | |
250 std::unique_ptr<MediaSourceState> mss = | |
251 CreateAndInitMediaSourceState("vorbis,opus"); | |
252 | |
253 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
254 AddAudioTrack(tracks, kCodecVorbis, 1); | |
255 AddAudioTrack(tracks, kCodecOpus, 2); | |
256 EXPECT_MEDIA_LOG(FoundStream("audio")).Times(2); | |
257 EXPECT_MEDIA_LOG(CodecName("audio", "vorbis")); | |
258 EXPECT_MEDIA_LOG(CodecName("audio", "opus")); | |
259 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
260 EXPECT_TRUE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
261 | |
262 // Since we have two audio tracks, bytestream track ids must match the first | |
263 // init segment. | |
264 std::unique_ptr<MediaTracks> tracks2(new MediaTracks()); | |
265 AddAudioTrack(tracks2, kCodecVorbis, 1); | |
266 AddAudioTrack(tracks2, kCodecOpus, 2); | |
267 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
268 EXPECT_TRUE(AppendDataAndReportTracks(mss, std::move(tracks2))); | |
269 | |
270 // Emulate the situation where bytestream track ids have changed in the third | |
271 // init segment. This must cause failure in the OnNewConfigs. | |
272 std::unique_ptr<MediaTracks> tracks3(new MediaTracks()); | |
273 AddAudioTrack(tracks3, kCodecVorbis, 1); | |
274 AddAudioTrack(tracks3, kCodecOpus, 3); | |
275 EXPECT_MEDIA_LOG(UnexpectedTrack("audio", "3")); | |
276 EXPECT_FALSE(AppendDataAndReportTracks(mss, std::move(tracks3))); | |
277 } | |
278 | |
279 TEST_F(MediaSourceStateTest, TrackIdChangeWithTwoVideoTracks) { | |
280 std::unique_ptr<MediaSourceState> mss = | |
281 CreateAndInitMediaSourceState("vp8,vp9"); | |
282 | |
283 std::unique_ptr<MediaTracks> tracks(new MediaTracks()); | |
284 AddVideoTrack(tracks, kCodecVP8, 1); | |
285 AddVideoTrack(tracks, kCodecVP9, 2); | |
286 EXPECT_MEDIA_LOG(FoundStream("video")).Times(2); | |
287 EXPECT_MEDIA_LOG(CodecName("video", "vp8")); | |
288 EXPECT_MEDIA_LOG(CodecName("video", "vp9")); | |
289 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
290 EXPECT_TRUE(AppendDataAndReportTracks(mss, std::move(tracks))); | |
291 | |
292 // Since we have two video tracks, bytestream track ids must match the first | |
293 // init segment. | |
294 std::unique_ptr<MediaTracks> tracks2(new MediaTracks()); | |
295 AddVideoTrack(tracks2, kCodecVP8, 1); | |
296 AddVideoTrack(tracks2, kCodecVP9, 2); | |
297 EXPECT_CALL(*this, MediaTracksUpdatedMock(_)); | |
298 EXPECT_TRUE(AppendDataAndReportTracks(mss, std::move(tracks2))); | |
299 | |
300 // Emulate the situation where bytestream track ids have changed in the third | |
301 // init segment. This must cause failure in the OnNewConfigs. | |
302 std::unique_ptr<MediaTracks> tracks3(new MediaTracks()); | |
303 AddVideoTrack(tracks3, kCodecVP8, 1); | |
304 AddVideoTrack(tracks3, kCodecVP9, 3); | |
305 EXPECT_MEDIA_LOG(UnexpectedTrack("video", "3")); | |
306 EXPECT_FALSE(AppendDataAndReportTracks(mss, std::move(tracks3))); | |
307 } | |
308 | |
309 } // namespace media | |
OLD | NEW |