OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <algorithm> | 5 #include <algorithm> |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
10 #include "base/strings/string_split.h" | 10 #include "base/strings/string_split.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 // The size of TrackEntry element in test file "webm_vp8_track_entry" starts at | 59 // The size of TrackEntry element in test file "webm_vp8_track_entry" starts at |
60 // index 1 and spans 8 bytes. | 60 // index 1 and spans 8 bytes. |
61 const int kVideoTrackSizeOffset = 1; | 61 const int kVideoTrackSizeOffset = 1; |
62 const int kVideoTrackSizeWidth = 8; | 62 const int kVideoTrackSizeWidth = 8; |
63 const int kVideoTrackEntryHeaderSize = | 63 const int kVideoTrackEntryHeaderSize = |
64 kVideoTrackSizeOffset + kVideoTrackSizeWidth; | 64 kVideoTrackSizeOffset + kVideoTrackSizeWidth; |
65 | 65 |
66 const int kVideoTrackNum = 1; | 66 const int kVideoTrackNum = 1; |
67 const int kAudioTrackNum = 2; | 67 const int kAudioTrackNum = 2; |
68 const int kTextTrackNum = 3; | 68 const int kTextTrackNum = 3; |
| 69 const int kAlternateTextTrackNum = 4; |
69 | 70 |
70 const int kAudioBlockDuration = 23; | 71 const int kAudioBlockDuration = 23; |
71 const int kVideoBlockDuration = 33; | 72 const int kVideoBlockDuration = 33; |
72 const int kTextBlockDuration = 100; | 73 const int kTextBlockDuration = 100; |
73 const int kBlockSize = 10; | 74 const int kBlockSize = 10; |
74 | 75 |
75 const char kSourceId[] = "SourceId"; | 76 const char kSourceId[] = "SourceId"; |
76 const char kDefaultFirstClusterRange[] = "{ [0,46) }"; | 77 const char kDefaultFirstClusterRange[] = "{ [0,46) }"; |
77 const int kDefaultFirstClusterEndTimestamp = 66; | 78 const int kDefaultFirstClusterEndTimestamp = 66; |
78 const int kDefaultSecondClusterEndTimestamp = 132; | 79 const int kDefaultSecondClusterEndTimestamp = 132; |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 base::Bind(&ChunkDemuxerTest::DemuxerNeedKey, base::Unretained(this)); | 172 base::Bind(&ChunkDemuxerTest::DemuxerNeedKey, base::Unretained(this)); |
172 demuxer_.reset( | 173 demuxer_.reset( |
173 new ChunkDemuxer(open_cb, need_key_cb, base::Bind(&LogFunc), true)); | 174 new ChunkDemuxer(open_cb, need_key_cb, base::Bind(&LogFunc), true)); |
174 } | 175 } |
175 | 176 |
176 virtual ~ChunkDemuxerTest() { | 177 virtual ~ChunkDemuxerTest() { |
177 ShutdownDemuxer(); | 178 ShutdownDemuxer(); |
178 } | 179 } |
179 | 180 |
180 void CreateInitSegment(int stream_flags, | 181 void CreateInitSegment(int stream_flags, |
181 bool is_audio_encrypted, bool is_video_encrypted, | 182 bool is_audio_encrypted, |
| 183 bool is_video_encrypted, |
182 scoped_ptr<uint8[]>* buffer, | 184 scoped_ptr<uint8[]>* buffer, |
183 int* size) { | 185 int* size) { |
| 186 CreateInitSegmentInternal( |
| 187 stream_flags, is_audio_encrypted, is_video_encrypted, buffer, false, |
| 188 size); |
| 189 } |
| 190 |
| 191 void CreateInitSegmentWithAlternateTextTrackNum(int stream_flags, |
| 192 bool is_audio_encrypted, |
| 193 bool is_video_encrypted, |
| 194 scoped_ptr<uint8[]>* buffer, |
| 195 int* size) { |
| 196 DCHECK(stream_flags & HAS_TEXT); |
| 197 CreateInitSegmentInternal( |
| 198 stream_flags, is_audio_encrypted, is_video_encrypted, buffer, true, |
| 199 size); |
| 200 } |
| 201 |
| 202 void CreateInitSegmentInternal(int stream_flags, |
| 203 bool is_audio_encrypted, |
| 204 bool is_video_encrypted, |
| 205 scoped_ptr<uint8[]>* buffer, |
| 206 bool use_alternate_text_track_id, |
| 207 int* size) { |
184 bool has_audio = (stream_flags & HAS_AUDIO) != 0; | 208 bool has_audio = (stream_flags & HAS_AUDIO) != 0; |
185 bool has_video = (stream_flags & HAS_VIDEO) != 0; | 209 bool has_video = (stream_flags & HAS_VIDEO) != 0; |
186 bool has_text = (stream_flags & HAS_TEXT) != 0; | 210 bool has_text = (stream_flags & HAS_TEXT) != 0; |
187 scoped_refptr<DecoderBuffer> ebml_header; | 211 scoped_refptr<DecoderBuffer> ebml_header; |
188 scoped_refptr<DecoderBuffer> info; | 212 scoped_refptr<DecoderBuffer> info; |
189 scoped_refptr<DecoderBuffer> audio_track_entry; | 213 scoped_refptr<DecoderBuffer> audio_track_entry; |
190 scoped_refptr<DecoderBuffer> video_track_entry; | 214 scoped_refptr<DecoderBuffer> video_track_entry; |
191 scoped_refptr<DecoderBuffer> audio_content_encodings; | 215 scoped_refptr<DecoderBuffer> audio_content_encodings; |
192 scoped_refptr<DecoderBuffer> video_content_encodings; | 216 scoped_refptr<DecoderBuffer> video_content_encodings; |
193 scoped_refptr<DecoderBuffer> text_track_entry; | 217 scoped_refptr<DecoderBuffer> text_track_entry; |
(...skipping 22 matching lines...) Expand all Loading... |
216 } | 240 } |
217 } | 241 } |
218 | 242 |
219 if (has_text) { | 243 if (has_text) { |
220 // TODO(matthewjheaney): create an abstraction to do | 244 // TODO(matthewjheaney): create an abstraction to do |
221 // this (http://crbug/321454). | 245 // this (http://crbug/321454). |
222 // We need it to also handle the creation of multiple text tracks. | 246 // We need it to also handle the creation of multiple text tracks. |
223 // | 247 // |
224 // This is the track entry for a text track, | 248 // This is the track entry for a text track, |
225 // TrackEntry [AE], size=30 | 249 // TrackEntry [AE], size=30 |
226 // TrackNum [D7], size=1, val=3 | 250 // TrackNum [D7], size=1, val=3 (or 4 if use_alternate_text_track_id) |
227 // TrackUID [73] [C5], size=1, value=3 | 251 // TrackUID [73] [C5], size=1, value=3 (must remain constant for same |
| 252 // track, even if TrackNum changes) |
228 // TrackType [83], size=1, val=0x11 | 253 // TrackType [83], size=1, val=0x11 |
229 // CodecId [86], size=18, val="D_WEBVTT/SUBTITLES" | 254 // CodecId [86], size=18, val="D_WEBVTT/SUBTITLES" |
230 const char str[] = "\xAE\x9E\xD7\x81\x03\x73\xC5\x81\x03" | 255 char str[] = "\xAE\x9E\xD7\x81\x03\x73\xC5\x81\x03" |
231 "\x83\x81\x11\x86\x92" | 256 "\x83\x81\x11\x86\x92" |
232 "D_WEBVTT/SUBTITLES"; | 257 "D_WEBVTT/SUBTITLES"; |
| 258 DCHECK_EQ(str[4], kTextTrackNum); |
| 259 if (use_alternate_text_track_id) |
| 260 str[4] = kAlternateTextTrackNum; |
| 261 |
233 const int len = strlen(str); | 262 const int len = strlen(str); |
234 DCHECK_EQ(len, 32); | 263 DCHECK_EQ(len, 32); |
235 const uint8* const buf = reinterpret_cast<const uint8*>(str); | 264 const uint8* const buf = reinterpret_cast<const uint8*>(str); |
236 text_track_entry = DecoderBuffer::CopyFrom(buf, len); | 265 text_track_entry = DecoderBuffer::CopyFrom(buf, len); |
237 tracks_element_size += text_track_entry->data_size(); | 266 tracks_element_size += text_track_entry->data_size(); |
238 } | 267 } |
239 | 268 |
240 *size = ebml_header->data_size() + info->data_size() + | 269 *size = ebml_header->data_size() + info->data_size() + |
241 kTracksHeaderSize + tracks_element_size; | 270 kTracksHeaderSize + tracks_element_size; |
242 | 271 |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 void AppendSingleStreamCluster(const std::string& source_id, int track_number, | 380 void AppendSingleStreamCluster(const std::string& source_id, int track_number, |
352 int timecode, int block_count) { | 381 int timecode, int block_count) { |
353 int block_duration = 0; | 382 int block_duration = 0; |
354 switch (track_number) { | 383 switch (track_number) { |
355 case kVideoTrackNum: | 384 case kVideoTrackNum: |
356 block_duration = kVideoBlockDuration; | 385 block_duration = kVideoBlockDuration; |
357 break; | 386 break; |
358 case kAudioTrackNum: | 387 case kAudioTrackNum: |
359 block_duration = kAudioBlockDuration; | 388 block_duration = kAudioBlockDuration; |
360 break; | 389 break; |
361 case kTextTrackNum: | 390 case kTextTrackNum: // Fall-through. |
| 391 case kAlternateTextTrackNum: |
362 block_duration = kTextBlockDuration; | 392 block_duration = kTextBlockDuration; |
363 break; | 393 break; |
364 } | 394 } |
365 ASSERT_NE(block_duration, 0); | 395 ASSERT_NE(block_duration, 0); |
366 int end_timecode = timecode + block_count * block_duration; | 396 int end_timecode = timecode + block_count * block_duration; |
367 AppendCluster(source_id, | 397 AppendCluster(source_id, |
368 GenerateSingleStreamCluster( | 398 GenerateSingleStreamCluster( |
369 timecode, end_timecode, track_number, block_duration)); | 399 timecode, end_timecode, track_number, block_duration)); |
370 } | 400 } |
371 | 401 |
(...skipping 17 matching lines...) Expand all Loading... |
389 block_flags = kWebMFlagKeyframe; | 419 block_flags = kWebMFlagKeyframe; |
390 // Remove the "K" off of the token. | 420 // Remove the "K" off of the token. |
391 timestamp_str = timestamp_str.substr(0, timestamps[i].length() - 1); | 421 timestamp_str = timestamp_str.substr(0, timestamps[i].length() - 1); |
392 } | 422 } |
393 int timestamp_in_ms; | 423 int timestamp_in_ms; |
394 CHECK(base::StringToInt(timestamp_str, ×tamp_in_ms)); | 424 CHECK(base::StringToInt(timestamp_str, ×tamp_in_ms)); |
395 | 425 |
396 if (i == 0) | 426 if (i == 0) |
397 cb.SetClusterTimecode(timestamp_in_ms); | 427 cb.SetClusterTimecode(timestamp_in_ms); |
398 | 428 |
399 if (track_number == kTextTrackNum) { | 429 if (track_number == kTextTrackNum || |
| 430 track_number == kAlternateTextTrackNum) { |
400 cb.AddBlockGroup(track_number, timestamp_in_ms, kTextBlockDuration, | 431 cb.AddBlockGroup(track_number, timestamp_in_ms, kTextBlockDuration, |
401 block_flags, &data[0], data.size()); | 432 block_flags, &data[0], data.size()); |
402 } else { | 433 } else { |
403 cb.AddSimpleBlock(track_number, timestamp_in_ms, block_flags, | 434 cb.AddSimpleBlock(track_number, timestamp_in_ms, block_flags, |
404 &data[0], data.size()); | 435 &data[0], data.size()); |
405 } | 436 } |
406 } | 437 } |
407 AppendCluster(source_id, cb.Finish()); | 438 AppendCluster(source_id, cb.Finish()); |
408 } | 439 } |
409 | 440 |
(...skipping 730 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1140 ->supports_partial_append_window_trimming()); | 1171 ->supports_partial_append_window_trimming()); |
1141 } else { | 1172 } else { |
1142 EXPECT_FALSE(video_stream); | 1173 EXPECT_FALSE(video_stream); |
1143 } | 1174 } |
1144 | 1175 |
1145 ShutdownDemuxer(); | 1176 ShutdownDemuxer(); |
1146 demuxer_.reset(); | 1177 demuxer_.reset(); |
1147 } | 1178 } |
1148 } | 1179 } |
1149 | 1180 |
| 1181 TEST_P(ChunkDemuxerTest, SingleTextTrackIdChange) { |
| 1182 // Test with 1 video stream, 1 audio, and 1 text stream. Send a second init |
| 1183 // segment in which the text track ID changes. Verify appended buffers before |
| 1184 // and after the second init segment map to the same underlying track buffers. |
| 1185 CreateNewDemuxer(); |
| 1186 DemuxerStream* text_stream = NULL; |
| 1187 TextTrackConfig text_config; |
| 1188 EXPECT_CALL(host_, AddTextStream(_, _)) |
| 1189 .WillOnce(DoAll(SaveArg<0>(&text_stream), |
| 1190 SaveArg<1>(&text_config))); |
| 1191 ASSERT_TRUE(InitDemuxerWithEncryptionInfo( |
| 1192 HAS_TEXT | HAS_AUDIO | HAS_VIDEO, false, false)); |
| 1193 DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO); |
| 1194 DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO); |
| 1195 ASSERT_TRUE(audio_stream); |
| 1196 ASSERT_TRUE(video_stream); |
| 1197 ASSERT_TRUE(text_stream); |
| 1198 |
| 1199 AppendSingleStreamCluster(kSourceId, kAudioTrackNum, "0K 23K"); |
| 1200 AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "0K 30"); |
| 1201 AppendSingleStreamCluster(kSourceId, kTextTrackNum, "10K"); |
| 1202 CheckExpectedRanges(kSourceId, "{ [0,46) }"); |
| 1203 |
| 1204 scoped_ptr<uint8[]> info_tracks; |
| 1205 int info_tracks_size = 0; |
| 1206 CreateInitSegmentWithAlternateTextTrackNum(HAS_TEXT | HAS_AUDIO | HAS_VIDEO, |
| 1207 false, false, |
| 1208 &info_tracks, &info_tracks_size); |
| 1209 demuxer_->AppendData(kSourceId, info_tracks.get(), info_tracks_size, |
| 1210 append_window_start_for_next_append_, |
| 1211 append_window_end_for_next_append_, |
| 1212 ×tamp_offset_map_[kSourceId]); |
| 1213 |
| 1214 AppendSingleStreamCluster(kSourceId, kAudioTrackNum, "46K 69K"); |
| 1215 AppendSingleStreamCluster(kSourceId, kVideoTrackNum, "60K"); |
| 1216 AppendSingleStreamCluster(kSourceId, kAlternateTextTrackNum, "45K"); |
| 1217 |
| 1218 CheckExpectedRanges(kSourceId, "{ [0,92) }"); |
| 1219 CheckExpectedBuffers(audio_stream, "0 23 46 69"); |
| 1220 CheckExpectedBuffers(video_stream, "0 30 60"); |
| 1221 CheckExpectedBuffers(text_stream, "10 45"); |
| 1222 |
| 1223 ShutdownDemuxer(); |
| 1224 } |
| 1225 |
1150 // Make sure that the demuxer reports an error if Shutdown() | 1226 // Make sure that the demuxer reports an error if Shutdown() |
1151 // is called before all the initialization segments are appended. | 1227 // is called before all the initialization segments are appended. |
1152 TEST_P(ChunkDemuxerTest, Shutdown_BeforeAllInitSegmentsAppended) { | 1228 TEST_P(ChunkDemuxerTest, Shutdown_BeforeAllInitSegmentsAppended) { |
1153 EXPECT_CALL(*this, DemuxerOpened()); | 1229 EXPECT_CALL(*this, DemuxerOpened()); |
1154 demuxer_->Initialize( | 1230 demuxer_->Initialize( |
1155 &host_, CreateInitDoneCB( | 1231 &host_, CreateInitDoneCB( |
1156 kDefaultDuration(), DEMUXER_ERROR_COULD_NOT_OPEN), true); | 1232 kDefaultDuration(), DEMUXER_ERROR_COULD_NOT_OPEN), true); |
1157 | 1233 |
1158 EXPECT_EQ(AddId("audio", HAS_AUDIO), ChunkDemuxer::kOk); | 1234 EXPECT_EQ(AddId("audio", HAS_AUDIO), ChunkDemuxer::kOk); |
1159 EXPECT_EQ(AddId("video", HAS_VIDEO), ChunkDemuxer::kOk); | 1235 EXPECT_EQ(AddId("video", HAS_VIDEO), ChunkDemuxer::kOk); |
(...skipping 2182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3342 CheckExpectedBuffers(audio_stream, "160 180"); | 3418 CheckExpectedBuffers(audio_stream, "160 180"); |
3343 CheckExpectedBuffers(video_stream, "180 210"); | 3419 CheckExpectedBuffers(video_stream, "180 210"); |
3344 } | 3420 } |
3345 | 3421 |
3346 // Generate two sets of tests: one using FrameProcessor, and one using | 3422 // Generate two sets of tests: one using FrameProcessor, and one using |
3347 // LegacyFrameProcessor. | 3423 // LegacyFrameProcessor. |
3348 INSTANTIATE_TEST_CASE_P(NewFrameProcessor, ChunkDemuxerTest, Values(false)); | 3424 INSTANTIATE_TEST_CASE_P(NewFrameProcessor, ChunkDemuxerTest, Values(false)); |
3349 INSTANTIATE_TEST_CASE_P(LegacyFrameProcessor, ChunkDemuxerTest, Values(true)); | 3425 INSTANTIATE_TEST_CASE_P(LegacyFrameProcessor, ChunkDemuxerTest, Values(true)); |
3350 | 3426 |
3351 } // namespace media | 3427 } // namespace media |
OLD | NEW |