OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 "media/formats/webm/webm_cluster_parser.h" | 5 #include "media/formats/webm/webm_cluster_parser.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/sys_byteorder.h" | 10 #include "base/sys_byteorder.h" |
11 #include "media/base/buffers.h" | 11 #include "media/base/buffers.h" |
12 #include "media/base/decrypt_config.h" | 12 #include "media/base/decrypt_config.h" |
13 #include "media/filters/webvtt_util.h" | 13 #include "media/filters/webvtt_util.h" |
14 #include "media/formats/webm/webm_constants.h" | 14 #include "media/formats/webm/webm_constants.h" |
15 #include "media/formats/webm/webm_crypto_helpers.h" | 15 #include "media/formats/webm/webm_crypto_helpers.h" |
16 #include "media/formats/webm/webm_webvtt_parser.h" | 16 #include "media/formats/webm/webm_webvtt_parser.h" |
17 | 17 |
18 namespace media { | 18 namespace media { |
19 | 19 |
| 20 const uint16_t WebMClusterParser::kOpusFrameDurationsMu[] = { |
| 21 10000, 20000, 40000, 60000, 10000, 20000, 40000, 60000, 10000, 20000, 40000, |
| 22 60000, 10000, 20000, 10000, 20000, 2500, 5000, 10000, 20000, 2500, 5000, |
| 23 10000, 20000, 2500, 5000, 10000, 20000, 2500, 5000, 10000, 20000}; |
| 24 |
| 25 enum { |
| 26 // Limits the number of MEDIA_LOG() calls in the path of reading encoded |
| 27 // duration to avoid spamming for corrupted data. |
| 28 kMaxDurationLogs = 10, |
| 29 }; |
| 30 |
20 WebMClusterParser::WebMClusterParser( | 31 WebMClusterParser::WebMClusterParser( |
21 int64 timecode_scale, | 32 int64 timecode_scale, |
22 int audio_track_num, | 33 int audio_track_num, |
23 base::TimeDelta audio_default_duration, | 34 base::TimeDelta audio_default_duration, |
24 int video_track_num, | 35 int video_track_num, |
25 base::TimeDelta video_default_duration, | 36 base::TimeDelta video_default_duration, |
26 const WebMTracksParser::TextTracks& text_tracks, | 37 const WebMTracksParser::TextTracks& text_tracks, |
27 const std::set<int64>& ignored_tracks, | 38 const std::set<int64>& ignored_tracks, |
28 const std::string& audio_encryption_key_id, | 39 const std::string& audio_encryption_key_id, |
29 const std::string& video_encryption_key_id, | 40 const std::string& video_encryption_key_id, |
| 41 const AudioCodec audio_codec, |
30 const LogCB& log_cb) | 42 const LogCB& log_cb) |
31 : timecode_multiplier_(timecode_scale / 1000.0), | 43 : num_duration_errors_(0), |
| 44 timecode_multiplier_(timecode_scale / 1000.0), |
32 ignored_tracks_(ignored_tracks), | 45 ignored_tracks_(ignored_tracks), |
33 audio_encryption_key_id_(audio_encryption_key_id), | 46 audio_encryption_key_id_(audio_encryption_key_id), |
34 video_encryption_key_id_(video_encryption_key_id), | 47 video_encryption_key_id_(video_encryption_key_id), |
| 48 audio_codec_(audio_codec), |
35 parser_(kWebMIdCluster, this), | 49 parser_(kWebMIdCluster, this), |
36 last_block_timecode_(-1), | 50 last_block_timecode_(-1), |
37 block_data_size_(-1), | 51 block_data_size_(-1), |
38 block_duration_(-1), | 52 block_duration_(-1), |
39 block_add_id_(-1), | 53 block_add_id_(-1), |
40 block_additional_data_size_(0), | 54 block_additional_data_size_(0), |
41 discard_padding_(-1), | 55 discard_padding_(-1), |
42 cluster_timecode_(-1), | 56 cluster_timecode_(-1), |
43 cluster_start_time_(kNoTimestamp()), | 57 cluster_start_time_(kNoTimestamp()), |
44 cluster_ended_(false), | 58 cluster_ended_(false), |
(...skipping 16 matching lines...) Expand all Loading... |
61 cluster_timecode_ = -1; | 75 cluster_timecode_ = -1; |
62 cluster_start_time_ = kNoTimestamp(); | 76 cluster_start_time_ = kNoTimestamp(); |
63 cluster_ended_ = false; | 77 cluster_ended_ = false; |
64 parser_.Reset(); | 78 parser_.Reset(); |
65 audio_.Reset(); | 79 audio_.Reset(); |
66 video_.Reset(); | 80 video_.Reset(); |
67 ResetTextTracks(); | 81 ResetTextTracks(); |
68 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); | 82 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); |
69 } | 83 } |
70 | 84 |
71 int WebMClusterParser::Parse(const uint8* buf, int size) { | 85 int WebMClusterParser::Parse(const uint8_t* buf, int size) { |
72 audio_.ClearReadyBuffers(); | 86 audio_.ClearReadyBuffers(); |
73 video_.ClearReadyBuffers(); | 87 video_.ClearReadyBuffers(); |
74 ClearTextTrackReadyBuffers(); | 88 ClearTextTrackReadyBuffers(); |
75 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); | 89 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); |
76 | 90 |
77 int result = parser_.Parse(buf, size); | 91 int result = parser_.Parse(buf, size); |
78 | 92 |
79 if (result < 0) { | 93 if (result < 0) { |
80 cluster_ended_ = false; | 94 cluster_ended_ = false; |
81 return result; | 95 return result; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 itr != text_track_map_.end(); | 147 itr != text_track_map_.end(); |
134 ++itr) { | 148 ++itr) { |
135 const BufferQueue& text_buffers = itr->second.ready_buffers(); | 149 const BufferQueue& text_buffers = itr->second.ready_buffers(); |
136 if (!text_buffers.empty()) | 150 if (!text_buffers.empty()) |
137 text_buffers_map_.insert(std::make_pair(itr->first, text_buffers)); | 151 text_buffers_map_.insert(std::make_pair(itr->first, text_buffers)); |
138 } | 152 } |
139 | 153 |
140 return text_buffers_map_; | 154 return text_buffers_map_; |
141 } | 155 } |
142 | 156 |
| 157 base::TimeDelta WebMClusterParser::TryGetEncodedAudioDuration( |
| 158 const uint8_t* data, |
| 159 int size) { |
| 160 |
| 161 // Duration is currently read assuming the *entire* stream is unencrypted. |
| 162 // The special "Signal Byte" prepended to Blocks in encrypted streams is |
| 163 // assumed to not be present. |
| 164 // TODO(chcunningham): Consider parsing "Signal Byte" for encrypted streams |
| 165 // to return duration for any unencrypted blocks. |
| 166 |
| 167 if (audio_codec_ == kCodecOpus) { |
| 168 return ReadOpusDuration(data, size); |
| 169 } |
| 170 |
| 171 // TODO(wolenetz/chcunningham): Implement duration reading for Vorbis. See |
| 172 // motivations in http://crbug.com/396634. |
| 173 |
| 174 return kNoTimestamp(); |
| 175 } |
| 176 |
| 177 base::TimeDelta WebMClusterParser::ReadOpusDuration(const uint8_t* data, |
| 178 int size) { |
| 179 // Masks and constants for Opus packets. See |
| 180 // https://tools.ietf.org/html/rfc6716#page-14 |
| 181 static const uint8_t kTocConfigMask = 0xf8; |
| 182 static const uint8_t kTocFrameCountCodeMask = 0x03; |
| 183 static const uint8_t kFrameCountMask = 0x3f; |
| 184 static const base::TimeDelta kPacketDurationMax = |
| 185 base::TimeDelta::FromMilliseconds(120); |
| 186 |
| 187 if (size < 1) { |
| 188 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) |
| 189 << "Invalid zero-byte Opus packet; demuxed block duration may be " |
| 190 "imprecise."; |
| 191 return kNoTimestamp(); |
| 192 } |
| 193 |
| 194 // Frame count type described by last 2 bits of Opus TOC byte. |
| 195 int frame_count_type = data[0] & kTocFrameCountCodeMask; |
| 196 |
| 197 int frame_count = 0; |
| 198 switch (frame_count_type) { |
| 199 case 0: |
| 200 frame_count = 1; |
| 201 break; |
| 202 case 1: |
| 203 case 2: |
| 204 frame_count = 2; |
| 205 break; |
| 206 case 3: |
| 207 // Type 3 indicates an arbitrary frame count described in the next byte. |
| 208 if (size < 2) { |
| 209 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) |
| 210 << "Second byte missing from 'Code 3' Opus packet; demuxed block " |
| 211 "duration may be imprecise."; |
| 212 return kNoTimestamp(); |
| 213 } |
| 214 |
| 215 frame_count = data[1] & kFrameCountMask; |
| 216 |
| 217 if (frame_count == 0) { |
| 218 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) |
| 219 << "Illegal 'Code 3' Opus packet with frame count zero; demuxed " |
| 220 "block duration may be imprecise."; |
| 221 return kNoTimestamp(); |
| 222 } |
| 223 |
| 224 break; |
| 225 default: |
| 226 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) |
| 227 << "Unexpected Opus frame count type: " << frame_count_type << "; " |
| 228 << "demuxed block duration may be imprecise."; |
| 229 return kNoTimestamp(); |
| 230 } |
| 231 |
| 232 int opusConfig = (data[0] & kTocConfigMask) >> 3; |
| 233 CHECK_GE(opusConfig, 0); |
| 234 CHECK_LT(opusConfig, static_cast<int>(arraysize(kOpusFrameDurationsMu))); |
| 235 |
| 236 DCHECK_GT(frame_count, 0); |
| 237 base::TimeDelta duration = base::TimeDelta::FromMicroseconds( |
| 238 kOpusFrameDurationsMu[opusConfig] * frame_count); |
| 239 |
| 240 if (duration > kPacketDurationMax) { |
| 241 // Intentionally allowing packet to pass through for now. Decoder should |
| 242 // either handle or fail gracefully. MEDIA_LOG as breadcrumbs in case |
| 243 // things go sideways. |
| 244 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) |
| 245 << "Warning, demuxed Opus packet with encoded duration: " << duration |
| 246 << ". Should be no greater than " << kPacketDurationMax; |
| 247 } |
| 248 |
| 249 return duration; |
| 250 } |
| 251 |
143 WebMParserClient* WebMClusterParser::OnListStart(int id) { | 252 WebMParserClient* WebMClusterParser::OnListStart(int id) { |
144 if (id == kWebMIdCluster) { | 253 if (id == kWebMIdCluster) { |
145 cluster_timecode_ = -1; | 254 cluster_timecode_ = -1; |
146 cluster_start_time_ = kNoTimestamp(); | 255 cluster_start_time_ = kNoTimestamp(); |
147 } else if (id == kWebMIdBlockGroup) { | 256 } else if (id == kWebMIdBlockGroup) { |
148 block_data_.reset(); | 257 block_data_.reset(); |
149 block_data_size_ = -1; | 258 block_data_size_ = -1; |
150 block_duration_ = -1; | 259 block_duration_ = -1; |
151 discard_padding_ = -1; | 260 discard_padding_ = -1; |
152 discard_padding_set_ = false; | 261 discard_padding_set_ = false; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 break; | 307 break; |
199 default: | 308 default: |
200 return true; | 309 return true; |
201 } | 310 } |
202 if (*dst != -1) | 311 if (*dst != -1) |
203 return false; | 312 return false; |
204 *dst = val; | 313 *dst = val; |
205 return true; | 314 return true; |
206 } | 315 } |
207 | 316 |
208 bool WebMClusterParser::ParseBlock(bool is_simple_block, const uint8* buf, | 317 bool WebMClusterParser::ParseBlock(bool is_simple_block, |
209 int size, const uint8* additional, | 318 const uint8_t* buf, |
210 int additional_size, int duration, | 319 int size, |
| 320 const uint8_t* additional, |
| 321 int additional_size, |
| 322 int duration, |
211 int64 discard_padding) { | 323 int64 discard_padding) { |
212 if (size < 4) | 324 if (size < 4) |
213 return false; | 325 return false; |
214 | 326 |
215 // Return an error if the trackNum > 127. We just aren't | 327 // Return an error if the trackNum > 127. We just aren't |
216 // going to support large track numbers right now. | 328 // going to support large track numbers right now. |
217 if (!(buf[0] & 0x80)) { | 329 if (!(buf[0] & 0x80)) { |
218 MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported"; | 330 MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported"; |
219 return false; | 331 return false; |
220 } | 332 } |
221 | 333 |
222 int track_num = buf[0] & 0x7f; | 334 int track_num = buf[0] & 0x7f; |
223 int timecode = buf[1] << 8 | buf[2]; | 335 int timecode = buf[1] << 8 | buf[2]; |
224 int flags = buf[3] & 0xff; | 336 int flags = buf[3] & 0xff; |
225 int lacing = (flags >> 1) & 0x3; | 337 int lacing = (flags >> 1) & 0x3; |
226 | 338 |
227 if (lacing) { | 339 if (lacing) { |
228 MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet."; | 340 MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet."; |
229 return false; | 341 return false; |
230 } | 342 } |
231 | 343 |
232 // Sign extend negative timecode offsets. | 344 // Sign extend negative timecode offsets. |
233 if (timecode & 0x8000) | 345 if (timecode & 0x8000) |
234 timecode |= ~0xffff; | 346 timecode |= ~0xffff; |
235 | 347 |
236 const uint8* frame_data = buf + 4; | 348 const uint8_t* frame_data = buf + 4; |
237 int frame_size = size - (frame_data - buf); | 349 int frame_size = size - (frame_data - buf); |
238 return OnBlock(is_simple_block, track_num, timecode, duration, flags, | 350 return OnBlock(is_simple_block, track_num, timecode, duration, flags, |
239 frame_data, frame_size, additional, additional_size, | 351 frame_data, frame_size, additional, additional_size, |
240 discard_padding); | 352 discard_padding); |
241 } | 353 } |
242 | 354 |
243 bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) { | 355 bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) { |
244 switch (id) { | 356 switch (id) { |
245 case kWebMIdSimpleBlock: | 357 case kWebMIdSimpleBlock: |
246 return ParseBlock(true, data, size, NULL, 0, -1, 0); | 358 return ParseBlock(true, data, size, NULL, 0, -1, 0); |
247 | 359 |
248 case kWebMIdBlock: | 360 case kWebMIdBlock: |
249 if (block_data_) { | 361 if (block_data_) { |
250 MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not " | 362 MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not " |
251 "supported."; | 363 "supported."; |
252 return false; | 364 return false; |
253 } | 365 } |
254 block_data_.reset(new uint8[size]); | 366 block_data_.reset(new uint8_t[size]); |
255 memcpy(block_data_.get(), data, size); | 367 memcpy(block_data_.get(), data, size); |
256 block_data_size_ = size; | 368 block_data_size_ = size; |
257 return true; | 369 return true; |
258 | 370 |
259 case kWebMIdBlockAdditional: { | 371 case kWebMIdBlockAdditional: { |
260 uint64 block_add_id = base::HostToNet64(block_add_id_); | 372 uint64 block_add_id = base::HostToNet64(block_add_id_); |
261 if (block_additional_data_) { | 373 if (block_additional_data_) { |
262 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed | 374 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed |
263 // as per matroska spec. But for now we don't have a use case to | 375 // as per matroska spec. But for now we don't have a use case to |
264 // support parsing of such files. Take a look at this again when such a | 376 // support parsing of such files. Take a look at this again when such a |
265 // case arises. | 377 // case arises. |
266 MEDIA_LOG(log_cb_) << "More than 1 BlockAdditional in a BlockGroup is " | 378 MEDIA_LOG(log_cb_) << "More than 1 BlockAdditional in a BlockGroup is " |
267 "not supported."; | 379 "not supported."; |
268 return false; | 380 return false; |
269 } | 381 } |
270 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID | 382 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID |
271 // element's value in Big Endian format. This is done to mimic ffmpeg | 383 // element's value in Big Endian format. This is done to mimic ffmpeg |
272 // demuxer's behavior. | 384 // demuxer's behavior. |
273 block_additional_data_size_ = size + sizeof(block_add_id); | 385 block_additional_data_size_ = size + sizeof(block_add_id); |
274 block_additional_data_.reset(new uint8[block_additional_data_size_]); | 386 block_additional_data_.reset(new uint8_t[block_additional_data_size_]); |
275 memcpy(block_additional_data_.get(), &block_add_id, | 387 memcpy(block_additional_data_.get(), &block_add_id, |
276 sizeof(block_add_id)); | 388 sizeof(block_add_id)); |
277 memcpy(block_additional_data_.get() + 8, data, size); | 389 memcpy(block_additional_data_.get() + 8, data, size); |
278 return true; | 390 return true; |
279 } | 391 } |
280 case kWebMIdDiscardPadding: { | 392 case kWebMIdDiscardPadding: { |
281 if (discard_padding_set_ || size <= 0 || size > 8) | 393 if (discard_padding_set_ || size <= 0 || size > 8) |
282 return false; | 394 return false; |
283 discard_padding_set_ = true; | 395 discard_padding_set_ = true; |
284 | 396 |
285 // Read in the big-endian integer. | 397 // Read in the big-endian integer. |
286 discard_padding_ = static_cast<int8>(data[0]); | 398 discard_padding_ = static_cast<int8>(data[0]); |
287 for (int i = 1; i < size; ++i) | 399 for (int i = 1; i < size; ++i) |
288 discard_padding_ = (discard_padding_ << 8) | data[i]; | 400 discard_padding_ = (discard_padding_ << 8) | data[i]; |
289 | 401 |
290 return true; | 402 return true; |
291 } | 403 } |
292 default: | 404 default: |
293 return true; | 405 return true; |
294 } | 406 } |
295 } | 407 } |
296 | 408 |
297 bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num, | 409 bool WebMClusterParser::OnBlock(bool is_simple_block, |
| 410 int track_num, |
298 int timecode, | 411 int timecode, |
299 int block_duration, | 412 int block_duration, |
300 int flags, | 413 int flags, |
301 const uint8* data, int size, | 414 const uint8_t* data, |
302 const uint8* additional, int additional_size, | 415 int size, |
| 416 const uint8_t* additional, |
| 417 int additional_size, |
303 int64 discard_padding) { | 418 int64 discard_padding) { |
304 DCHECK_GE(size, 0); | 419 DCHECK_GE(size, 0); |
305 if (cluster_timecode_ == -1) { | 420 if (cluster_timecode_ == -1) { |
306 MEDIA_LOG(log_cb_) << "Got a block before cluster timecode."; | 421 MEDIA_LOG(log_cb_) << "Got a block before cluster timecode."; |
307 return false; | 422 return false; |
308 } | 423 } |
309 | 424 |
310 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or | 425 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or |
311 // only when the absolute timecode is negative? See http://crbug.com/271794 | 426 // only when the absolute timecode is negative? See http://crbug.com/271794 |
312 if (timecode < 0) { | 427 if (timecode < 0) { |
313 MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset " | 428 MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset " |
314 << timecode; | 429 << timecode; |
315 return false; | 430 return false; |
316 } | 431 } |
317 | 432 |
318 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) { | 433 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) { |
319 MEDIA_LOG(log_cb_) | 434 MEDIA_LOG(log_cb_) |
320 << "Got a block with a timecode before the previous block."; | 435 << "Got a block with a timecode before the previous block."; |
321 return false; | 436 return false; |
322 } | 437 } |
323 | 438 |
324 Track* track = NULL; | 439 Track* track = NULL; |
325 StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO; | 440 StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO; |
326 std::string encryption_key_id; | 441 std::string encryption_key_id; |
| 442 base::TimeDelta encoded_duration = kNoTimestamp(); |
327 if (track_num == audio_.track_num()) { | 443 if (track_num == audio_.track_num()) { |
328 track = &audio_; | 444 track = &audio_; |
329 encryption_key_id = audio_encryption_key_id_; | 445 encryption_key_id = audio_encryption_key_id_; |
| 446 if (encryption_key_id.empty()) { |
| 447 encoded_duration = TryGetEncodedAudioDuration(data, size); |
| 448 } |
330 } else if (track_num == video_.track_num()) { | 449 } else if (track_num == video_.track_num()) { |
331 track = &video_; | 450 track = &video_; |
332 encryption_key_id = video_encryption_key_id_; | 451 encryption_key_id = video_encryption_key_id_; |
333 buffer_type = DemuxerStream::VIDEO; | 452 buffer_type = DemuxerStream::VIDEO; |
334 } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) { | 453 } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) { |
335 return true; | 454 return true; |
336 } else if (Track* const text_track = FindTextTrack(track_num)) { | 455 } else if (Track* const text_track = FindTextTrack(track_num)) { |
337 if (is_simple_block) // BlockGroup is required for WebVTT cues | 456 if (is_simple_block) // BlockGroup is required for WebVTT cues |
338 return false; | 457 return false; |
339 if (block_duration < 0) // not specified | 458 if (block_duration < 0) // not specified |
(...skipping 20 matching lines...) Expand all Loading... |
360 is_simple_block ? (flags & 0x80) != 0 : track->IsKeyframe(data, size); | 479 is_simple_block ? (flags & 0x80) != 0 : track->IsKeyframe(data, size); |
361 | 480 |
362 // Every encrypted Block has a signal byte and IV prepended to it. Current | 481 // Every encrypted Block has a signal byte and IV prepended to it. Current |
363 // encrypted WebM request for comments specification is here | 482 // encrypted WebM request for comments specification is here |
364 // http://wiki.webmproject.org/encryption/webm-encryption-rfc | 483 // http://wiki.webmproject.org/encryption/webm-encryption-rfc |
365 scoped_ptr<DecryptConfig> decrypt_config; | 484 scoped_ptr<DecryptConfig> decrypt_config; |
366 int data_offset = 0; | 485 int data_offset = 0; |
367 if (!encryption_key_id.empty() && | 486 if (!encryption_key_id.empty() && |
368 !WebMCreateDecryptConfig( | 487 !WebMCreateDecryptConfig( |
369 data, size, | 488 data, size, |
370 reinterpret_cast<const uint8*>(encryption_key_id.data()), | 489 reinterpret_cast<const uint8_t*>(encryption_key_id.data()), |
371 encryption_key_id.size(), | 490 encryption_key_id.size(), |
372 &decrypt_config, &data_offset)) { | 491 &decrypt_config, &data_offset)) { |
373 return false; | 492 return false; |
374 } | 493 } |
375 | 494 |
376 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId | 495 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId |
377 // type with remapped bytestream track numbers and allow multiple tracks as | 496 // type with remapped bytestream track numbers and allow multiple tracks as |
378 // applicable. See https://crbug.com/341581. | 497 // applicable. See https://crbug.com/341581. |
379 buffer = StreamParserBuffer::CopyFrom( | 498 buffer = StreamParserBuffer::CopyFrom( |
380 data + data_offset, size - data_offset, | 499 data + data_offset, size - data_offset, |
381 additional, additional_size, | 500 additional, additional_size, |
382 is_keyframe, buffer_type, track_num); | 501 is_keyframe, buffer_type, track_num); |
383 | 502 |
384 if (decrypt_config) | 503 if (decrypt_config) |
385 buffer->set_decrypt_config(decrypt_config.Pass()); | 504 buffer->set_decrypt_config(decrypt_config.Pass()); |
386 } else { | 505 } else { |
387 std::string id, settings, content; | 506 std::string id, settings, content; |
388 WebMWebVTTParser::Parse(data, size, &id, &settings, &content); | 507 WebMWebVTTParser::Parse(data, size, &id, &settings, &content); |
389 | 508 |
390 std::vector<uint8> side_data; | 509 std::vector<uint8_t> side_data; |
391 MakeSideData(id.begin(), id.end(), | 510 MakeSideData(id.begin(), id.end(), |
392 settings.begin(), settings.end(), | 511 settings.begin(), settings.end(), |
393 &side_data); | 512 &side_data); |
394 | 513 |
395 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId | 514 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId |
396 // type with remapped bytestream track numbers and allow multiple tracks as | 515 // type with remapped bytestream track numbers and allow multiple tracks as |
397 // applicable. See https://crbug.com/341581. | 516 // applicable. See https://crbug.com/341581. |
398 buffer = StreamParserBuffer::CopyFrom( | 517 buffer = StreamParserBuffer::CopyFrom( |
399 reinterpret_cast<const uint8*>(content.data()), | 518 reinterpret_cast<const uint8_t*>(content.data()), |
400 content.length(), | 519 content.length(), |
401 &side_data[0], | 520 &side_data[0], |
402 side_data.size(), | 521 side_data.size(), |
403 true, buffer_type, track_num); | 522 true, buffer_type, track_num); |
404 } | 523 } |
405 | 524 |
406 buffer->set_timestamp(timestamp); | 525 buffer->set_timestamp(timestamp); |
407 if (cluster_start_time_ == kNoTimestamp()) | 526 if (cluster_start_time_ == kNoTimestamp()) |
408 cluster_start_time_ = timestamp; | 527 cluster_start_time_ = timestamp; |
409 | 528 |
| 529 base::TimeDelta block_duration_time_delta = kNoTimestamp(); |
410 if (block_duration >= 0) { | 530 if (block_duration >= 0) { |
411 buffer->set_duration(base::TimeDelta::FromMicroseconds( | 531 block_duration_time_delta = base::TimeDelta::FromMicroseconds( |
412 block_duration * timecode_multiplier_)); | 532 block_duration * timecode_multiplier_); |
| 533 } |
| 534 |
| 535 // Prefer encoded duration over BlockGroup->BlockDuration or |
| 536 // TrackEntry->DefaultDuration when available. This layering violation is a |
| 537 // workaround for http://crbug.com/396634, decreasing the likelihood of |
| 538 // fall-back to rough estimation techniques for Blocks that lack a |
| 539 // BlockDuration at the end of a cluster. Cross cluster durations are not |
| 540 // feasible given flexibility of cluster ordering and MSE APIs. Duration |
| 541 // estimation may still apply in cases of encryption and codecs for which |
| 542 // we do not extract encoded duration. Within a cluster, estimates are applied |
| 543 // as Block Timecode deltas, or once the whole cluster is parsed in the case |
| 544 // of the last Block in the cluster. See Track::AddBuffer and |
| 545 // ApplyDurationEstimateIfNeeded(). |
| 546 if (encoded_duration != kNoTimestamp()) { |
| 547 DCHECK(encoded_duration != kInfiniteDuration()); |
| 548 DCHECK(encoded_duration > base::TimeDelta()); |
| 549 buffer->set_duration(encoded_duration); |
| 550 |
| 551 DVLOG(3) << __FUNCTION__ << " : " |
| 552 << "Using encoded duration " << encoded_duration.InSecondsF(); |
| 553 |
| 554 if (block_duration_time_delta != kNoTimestamp()) { |
| 555 base::TimeDelta duration_difference = |
| 556 block_duration_time_delta - encoded_duration; |
| 557 |
| 558 const auto kWarnDurationDiff = |
| 559 base::TimeDelta::FromMicroseconds(timecode_multiplier_ * 2); |
| 560 if (duration_difference.magnitude() > kWarnDurationDiff) { |
| 561 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) |
| 562 << "BlockDuration " |
| 563 << "(" << block_duration_time_delta << ") " |
| 564 << "differs significantly from encoded duration " |
| 565 << "(" << encoded_duration << ")."; |
| 566 } |
| 567 } |
| 568 } else if (block_duration_time_delta != kNoTimestamp()) { |
| 569 buffer->set_duration(block_duration_time_delta); |
413 } else { | 570 } else { |
414 DCHECK_NE(buffer_type, DemuxerStream::TEXT); | 571 DCHECK_NE(buffer_type, DemuxerStream::TEXT); |
415 buffer->set_duration(track->default_duration()); | 572 buffer->set_duration(track->default_duration()); |
416 } | 573 } |
417 | 574 |
418 if (discard_padding != 0) { | 575 if (discard_padding != 0) { |
419 buffer->set_discard_padding(std::make_pair( | 576 buffer->set_discard_padding(std::make_pair( |
420 base::TimeDelta(), | 577 base::TimeDelta(), |
421 base::TimeDelta::FromMicroseconds(discard_padding / 1000))); | 578 base::TimeDelta::FromMicroseconds(discard_padding / 1000))); |
422 } | 579 } |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 // reset here. | 699 // reset here. |
543 ready_buffers_.clear(); | 700 ready_buffers_.clear(); |
544 } | 701 } |
545 | 702 |
546 void WebMClusterParser::Track::Reset() { | 703 void WebMClusterParser::Track::Reset() { |
547 ClearReadyBuffers(); | 704 ClearReadyBuffers(); |
548 buffers_.clear(); | 705 buffers_.clear(); |
549 last_added_buffer_missing_duration_ = NULL; | 706 last_added_buffer_missing_duration_ = NULL; |
550 } | 707 } |
551 | 708 |
552 bool WebMClusterParser::Track::IsKeyframe(const uint8* data, int size) const { | 709 bool WebMClusterParser::Track::IsKeyframe(const uint8_t* data, int size) const { |
553 // For now, assume that all blocks are keyframes for datatypes other than | 710 // For now, assume that all blocks are keyframes for datatypes other than |
554 // video. This is a valid assumption for Vorbis, WebVTT, & Opus. | 711 // video. This is a valid assumption for Vorbis, WebVTT, & Opus. |
555 if (!is_video_) | 712 if (!is_video_) |
556 return true; | 713 return true; |
557 | 714 |
558 // Make sure the block is big enough for the minimal keyframe header size. | 715 // Make sure the block is big enough for the minimal keyframe header size. |
559 if (size < 7) | 716 if (size < 7) |
560 return false; | 717 return false; |
561 | 718 |
562 // The LSb of the first byte must be a 0 for a keyframe. | 719 // The LSb of the first byte must be a 0 for a keyframe. |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
678 WebMClusterParser::FindTextTrack(int track_num) { | 835 WebMClusterParser::FindTextTrack(int track_num) { |
679 const TextTrackMap::iterator it = text_track_map_.find(track_num); | 836 const TextTrackMap::iterator it = text_track_map_.find(track_num); |
680 | 837 |
681 if (it == text_track_map_.end()) | 838 if (it == text_track_map_.end()) |
682 return NULL; | 839 return NULL; |
683 | 840 |
684 return &it->second; | 841 return &it->second; |
685 } | 842 } |
686 | 843 |
687 } // namespace media | 844 } // namespace media |
OLD | NEW |