1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/source_buffer_state.h"
9 #include "base/functional/bind.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/memory/raw_ptr.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/test/gmock_callback_support.h"
14 #include "base/time/time.h"
15 #include "media/base/media_util.h"
16 #include "media/base/mock_filters.h"
17 #include "media/base/mock_media_log.h"
18 #include "media/base/stream_parser.h"
19 #include "media/base/test_helpers.h"
20 #include "media/filters/chunk_demuxer.h"
21 #include "media/filters/frame_processor.h"
22 #include "testing/gtest/include/gtest/gtest.h"
26 using base::test::RunClosure;
29 using testing::InvokeWithoutArgs;
30 using testing::Return;
31 using testing::SaveArg;
35 AudioDecoderConfig CreateAudioConfig(AudioCodec codec) {
36 return AudioDecoderConfig(codec, kSampleFormatPlanarF32,
37 CHANNEL_LAYOUT_STEREO, 1000, EmptyExtraData(),
38 EncryptionScheme::kUnencrypted);
41 VideoDecoderConfig CreateVideoConfig(VideoCodec codec, int w, int h) {
43 gfx::Rect visible_rect(size);
44 return VideoDecoderConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
45 VideoDecoderConfig::AlphaMode::kIsOpaque,
46 VideoColorSpace::REC709(), kNoTransformation, size,
47 visible_rect, size, EmptyExtraData(),
48 EncryptionScheme::kUnencrypted);
51 void AddAudioTrack(std::unique_ptr<MediaTracks>& t, AudioCodec codec, int id) {
52 t->AddAudioTrack(CreateAudioConfig(codec), id, MediaTrack::Kind(),
53 MediaTrack::Label(), MediaTrack::Language());
56 void AddVideoTrack(std::unique_ptr<MediaTracks>& t, VideoCodec codec, int id) {
57 t->AddVideoTrack(CreateVideoConfig(codec, 16, 16), id, MediaTrack::Kind(),
58 MediaTrack::Label(), MediaTrack::Language());
63 class SourceBufferStateTest : public ::testing::Test {
65 SourceBufferStateTest() : mock_stream_parser_(nullptr) {}
67 std::unique_ptr<SourceBufferState> CreateSourceBufferState() {
68 std::unique_ptr<FrameProcessor> frame_processor =
69 std::make_unique<FrameProcessor>(
70 base::BindRepeating(&SourceBufferStateTest::OnUpdateDuration,
71 base::Unretained(this)),
73 mock_stream_parser_ = new testing::StrictMock<MockStreamParser>();
74 return base::WrapUnique(new SourceBufferState(
75 base::WrapUnique(mock_stream_parser_.get()), std::move(frame_processor),
76 base::BindRepeating(&SourceBufferStateTest::CreateDemuxerStream,
77 base::Unretained(this)),
81 std::unique_ptr<SourceBufferState> CreateAndInitSourceBufferState(
82 const std::string& expected_codecs) {
83 std::unique_ptr<SourceBufferState> sbs = CreateSourceBufferState();
84 // Instead of using SaveArg<> to update |new_config_cb_| when mocked Init is
85 // called, we use a lambda because SaveArg<> doesn't work if any of the
86 // mocked method's arguments are move-only type.
87 EXPECT_CALL(*mock_stream_parser_, Init(_, _, _, _, _, _, _))
88 .WillOnce([&](auto init_cb, auto config_cb, auto new_buffers_cb,
89 auto encrypted_media_init_data_cb, auto new_segment_cb,
90 auto end_of_segment_cb,
91 auto media_log) { new_config_cb_ = config_cb; });
92 sbs->Init(base::BindOnce(&SourceBufferStateTest::SourceInitDone,
93 base::Unretained(this)),
96 &SourceBufferStateTest::StreamParserEncryptedInitData,
97 base::Unretained(this)));
99 sbs->SetTracksWatcher(base::BindRepeating(
100 &SourceBufferStateTest::OnMediaTracksUpdated, base::Unretained(this)));
102 // These tests are not expected to issue any parse warnings.
103 EXPECT_CALL(*this, OnParseWarningMock(_)).Times(0);
105 sbs->SetParseWarningCallback(base::BindRepeating(
106 &SourceBufferStateTest::OnParseWarningMock, base::Unretained(this)));
111 // Emulates appending and parsing some data to the SourceBufferState, since
112 // OnNewConfigs can only be invoked when parse is in progress.
113 bool AppendDataAndReportTracks(const std::unique_ptr<SourceBufferState>& sbs,
114 std::unique_ptr<MediaTracks> tracks) {
115 const uint8_t stream_data[] = "stream_data";
116 const int data_size = sizeof(stream_data);
119 // Ensure `stream_data` fits within one StreamParser::Parse() call.
120 CHECK_GT(StreamParser::kMaxPendingBytesPerParse, data_size);
122 bool new_configs_result = false;
124 EXPECT_CALL(*mock_stream_parser_,
125 AppendToParseBuffer(stream_data, data_size))
126 .WillOnce(Return(true));
127 EXPECT_CALL(*mock_stream_parser_,
128 Parse(StreamParser::kMaxPendingBytesPerParse))
130 DoAll(InvokeWithoutArgs([&] {
131 new_configs_result = new_config_cb_.Run(std::move(tracks));
133 /* Indicate successful parse with no uninspected data. */
134 Return(StreamParser::ParseStatus::kSuccess)));
136 EXPECT_TRUE(sbs->AppendToParseBuffer(stream_data, data_size));
137 EXPECT_EQ(StreamParser::ParseStatus::kSuccess,
138 sbs->RunSegmentParserLoop(t, t, &t));
140 return new_configs_result;
143 MOCK_METHOD1(OnParseWarningMock, void(const SourceBufferParseWarning));
144 MOCK_METHOD1(OnUpdateDuration, void(base::TimeDelta));
146 MOCK_METHOD1(SourceInitDone, void(const StreamParser::InitParameters&));
147 MOCK_METHOD2(StreamParserEncryptedInitData,
148 void(EmeInitDataType, const std::vector<uint8_t>&));
150 MOCK_METHOD1(MediaTracksUpdatedMock, void(std::unique_ptr<MediaTracks>&));
151 void OnMediaTracksUpdated(std::unique_ptr<MediaTracks> tracks) {
152 MediaTracksUpdatedMock(tracks);
155 ChunkDemuxerStream* CreateDemuxerStream(DemuxerStream::Type type) {
156 static unsigned track_id = 0;
157 demuxer_streams_.push_back(base::WrapUnique(new ChunkDemuxerStream(
158 type, MediaTrack::Id(base::NumberToString(++track_id)))));
159 return demuxer_streams_.back().get();
162 testing::StrictMock<MockMediaLog> media_log_;
163 std::vector<std::unique_ptr<ChunkDemuxerStream>> demuxer_streams_;
164 raw_ptr<MockStreamParser, DanglingUntriaged> mock_stream_parser_;
165 StreamParser::NewConfigCB new_config_cb_;
168 TEST_F(SourceBufferStateTest, InitSingleAudioTrack) {
169 std::unique_ptr<SourceBufferState> sbs =
170 CreateAndInitSourceBufferState("vorbis");
172 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
173 AddAudioTrack(tracks, AudioCodec::kVorbis, 1);
175 EXPECT_FOUND_CODEC_NAME(Audio, "vorbis");
176 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
177 EXPECT_TRUE(AppendDataAndReportTracks(sbs, std::move(tracks)));
180 TEST_F(SourceBufferStateTest, InitSingleVideoTrack) {
181 std::unique_ptr<SourceBufferState> sbs =
182 CreateAndInitSourceBufferState("vp8");
184 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
185 AddVideoTrack(tracks, VideoCodec::kVP8, 1);
187 EXPECT_FOUND_CODEC_NAME(Video, "vp8");
188 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
189 EXPECT_TRUE(AppendDataAndReportTracks(sbs, std::move(tracks)));
192 TEST_F(SourceBufferStateTest, InitMultipleTracks) {
193 std::unique_ptr<SourceBufferState> sbs =
194 CreateAndInitSourceBufferState("vorbis,vp8,opus,vp9");
196 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
197 AddAudioTrack(tracks, AudioCodec::kVorbis, 1);
198 AddAudioTrack(tracks, AudioCodec::kOpus, 2);
199 AddVideoTrack(tracks, VideoCodec::kVP8, 3);
200 AddVideoTrack(tracks, VideoCodec::kVP9, 4);
202 EXPECT_FOUND_CODEC_NAME(Audio, "vorbis");
203 EXPECT_FOUND_CODEC_NAME(Audio, "opus");
204 EXPECT_FOUND_CODEC_NAME(Video, "vp9");
205 EXPECT_FOUND_CODEC_NAME(Video, "vp8");
206 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
207 EXPECT_TRUE(AppendDataAndReportTracks(sbs, std::move(tracks)));
210 TEST_F(SourceBufferStateTest, AudioStreamMismatchesExpectedCodecs) {
211 std::unique_ptr<SourceBufferState> sbs =
212 CreateAndInitSourceBufferState("opus");
213 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
214 AddAudioTrack(tracks, AudioCodec::kVorbis, 1);
215 EXPECT_MEDIA_LOG(InitSegmentMismatchesMimeType("Audio", "vorbis"));
216 EXPECT_FALSE(AppendDataAndReportTracks(sbs, std::move(tracks)));
219 TEST_F(SourceBufferStateTest, VideoStreamMismatchesExpectedCodecs) {
220 std::unique_ptr<SourceBufferState> sbs =
221 CreateAndInitSourceBufferState("vp9");
222 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
223 AddVideoTrack(tracks, VideoCodec::kVP8, 1);
224 EXPECT_MEDIA_LOG(InitSegmentMismatchesMimeType("Video", "vp8"));
225 EXPECT_FALSE(AppendDataAndReportTracks(sbs, std::move(tracks)));
228 TEST_F(SourceBufferStateTest, MissingExpectedAudioStream) {
229 std::unique_ptr<SourceBufferState> sbs =
230 CreateAndInitSourceBufferState("opus,vp9");
231 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
232 AddVideoTrack(tracks, VideoCodec::kVP9, 1);
233 EXPECT_FOUND_CODEC_NAME(Video, "vp9");
234 EXPECT_MEDIA_LOG(InitSegmentMissesExpectedTrack("opus"));
235 EXPECT_FALSE(AppendDataAndReportTracks(sbs, std::move(tracks)));
238 TEST_F(SourceBufferStateTest, MissingExpectedVideoStream) {
239 std::unique_ptr<SourceBufferState> sbs =
240 CreateAndInitSourceBufferState("opus,vp9");
241 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
242 tracks->AddAudioTrack(CreateAudioConfig(AudioCodec::kOpus), 1,
243 MediaTrack::Kind(), MediaTrack::Label(),
244 MediaTrack::Language());
245 EXPECT_FOUND_CODEC_NAME(Audio, "opus");
246 EXPECT_MEDIA_LOG(InitSegmentMissesExpectedTrack("vp9"));
247 EXPECT_FALSE(AppendDataAndReportTracks(sbs, std::move(tracks)));
250 TEST_F(SourceBufferStateTest, TrackIdsChangeInSecondInitSegment) {
251 std::unique_ptr<SourceBufferState> sbs =
252 CreateAndInitSourceBufferState("opus,vp9");
254 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
255 AddAudioTrack(tracks, AudioCodec::kOpus, 1);
256 AddVideoTrack(tracks, VideoCodec::kVP9, 2);
257 EXPECT_FOUND_CODEC_NAME(Audio, "opus");
258 EXPECT_FOUND_CODEC_NAME(Video, "vp9");
259 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
260 AppendDataAndReportTracks(sbs, std::move(tracks));
262 // This second set of tracks have bytestream track ids that differ from the
263 // first init segment above (audio track id 1 -> 3, video track id 2 -> 4).
264 // Bytestream track ids are allowed to change when there is only a single
265 // track of each type.
266 std::unique_ptr<MediaTracks> tracks2(new MediaTracks());
267 AddAudioTrack(tracks2, AudioCodec::kOpus, 3);
268 AddVideoTrack(tracks2, VideoCodec::kVP9, 4);
269 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
270 AppendDataAndReportTracks(sbs, std::move(tracks2));
273 TEST_F(SourceBufferStateTest, TrackIdChangeWithTwoAudioTracks) {
274 std::unique_ptr<SourceBufferState> sbs =
275 CreateAndInitSourceBufferState("vorbis,opus");
277 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
278 AddAudioTrack(tracks, AudioCodec::kVorbis, 1);
279 AddAudioTrack(tracks, AudioCodec::kOpus, 2);
280 EXPECT_FOUND_CODEC_NAME(Audio, "vorbis");
281 EXPECT_FOUND_CODEC_NAME(Audio, "opus");
282 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
283 EXPECT_TRUE(AppendDataAndReportTracks(sbs, std::move(tracks)));
285 // Since we have two audio tracks, bytestream track ids must match the first
287 std::unique_ptr<MediaTracks> tracks2(new MediaTracks());
288 AddAudioTrack(tracks2, AudioCodec::kVorbis, 1);
289 AddAudioTrack(tracks2, AudioCodec::kOpus, 2);
290 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
291 EXPECT_TRUE(AppendDataAndReportTracks(sbs, std::move(tracks2)));
293 // Emulate the situation where bytestream track ids have changed in the third
294 // init segment. This must cause failure in the OnNewConfigs.
295 std::unique_ptr<MediaTracks> tracks3(new MediaTracks());
296 AddAudioTrack(tracks3, AudioCodec::kVorbis, 1);
297 AddAudioTrack(tracks3, AudioCodec::kOpus, 3);
298 EXPECT_MEDIA_LOG(UnexpectedTrack("audio", "3"));
299 EXPECT_FALSE(AppendDataAndReportTracks(sbs, std::move(tracks3)));
302 TEST_F(SourceBufferStateTest, TrackIdChangeWithTwoVideoTracks) {
303 std::unique_ptr<SourceBufferState> sbs =
304 CreateAndInitSourceBufferState("vp8,vp9");
306 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
307 AddVideoTrack(tracks, VideoCodec::kVP8, 1);
308 AddVideoTrack(tracks, VideoCodec::kVP9, 2);
309 EXPECT_FOUND_CODEC_NAME(Video, "vp8");
310 EXPECT_FOUND_CODEC_NAME(Video, "vp9");
311 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
312 EXPECT_TRUE(AppendDataAndReportTracks(sbs, std::move(tracks)));
314 // Since we have two video tracks, bytestream track ids must match the first
316 std::unique_ptr<MediaTracks> tracks2(new MediaTracks());
317 AddVideoTrack(tracks2, VideoCodec::kVP8, 1);
318 AddVideoTrack(tracks2, VideoCodec::kVP9, 2);
319 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
320 EXPECT_TRUE(AppendDataAndReportTracks(sbs, std::move(tracks2)));
322 // Emulate the situation where bytestream track ids have changed in the third
323 // init segment. This must cause failure in the OnNewConfigs.
324 std::unique_ptr<MediaTracks> tracks3(new MediaTracks());
325 AddVideoTrack(tracks3, VideoCodec::kVP8, 1);
326 AddVideoTrack(tracks3, VideoCodec::kVP9, 3);
327 EXPECT_MEDIA_LOG(UnexpectedTrack("video", "3"));
328 EXPECT_FALSE(AppendDataAndReportTracks(sbs, std::move(tracks3)));
331 TEST_F(SourceBufferStateTest, TrackIdsSwappedInSecondInitSegment) {
332 std::unique_ptr<SourceBufferState> sbs =
333 CreateAndInitSourceBufferState("opus,vp9");
335 std::unique_ptr<MediaTracks> tracks(new MediaTracks());
336 AddAudioTrack(tracks, AudioCodec::kOpus, 1);
337 AddVideoTrack(tracks, VideoCodec::kVP9, 2);
338 EXPECT_FOUND_CODEC_NAME(Audio, "opus");
339 EXPECT_FOUND_CODEC_NAME(Video, "vp9");
340 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
341 AppendDataAndReportTracks(sbs, std::move(tracks));
343 // Track ids are swapped in the second init segment.
344 std::unique_ptr<MediaTracks> tracks2(new MediaTracks());
345 AddAudioTrack(tracks2, AudioCodec::kOpus, 2);
346 AddVideoTrack(tracks2, VideoCodec::kVP9, 1);
347 EXPECT_CALL(*this, MediaTracksUpdatedMock(_));
348 AppendDataAndReportTracks(sbs, std::move(tracks2));