| 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 |