Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: media/formats/webm/webm_cluster_parser.cc

Issue 883403002: Parsing of encoded duration for unencrypted opus streams. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressing feedback, round 3. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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 if (audio_codec_ == kCodecOpus) {
161 return ReadOpusDuration(data, size);
162 }
163
164 // TODO(wolenetz/chcunningham): Implement duration reading for Vorbis. See
165 // motivations in http://crbug.com/396634.
166
167 return kNoTimestamp();
168 }
169
170 base::TimeDelta WebMClusterParser::ReadOpusDuration(const uint8_t* data,
171 int size) {
172 // Masks and constants for Opus packets. See
173 // https://tools.ietf.org/html/rfc6716#page-14
174 static const uint8_t kTocConfigMask = 0xf8;
175 static const uint8_t kTocFrameCountCodeMask = 0x03;
176 static const uint8_t kFrameCountMask = 0x3f;
177 static const base::TimeDelta kPacketDurationMax =
178 base::TimeDelta::FromMilliseconds(120);
179
180 if (size < 1) {
181 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs)
182 << "Invalid zero-byte Opus packet; demuxed block duration may be "
183 "imprecise.";
184 return kNoTimestamp();
185 }
186
187 // Frame count type described by last 2 bits of Opus TOC byte.
188 int frame_count_type = data[0] & kTocFrameCountCodeMask;
189
190 int frame_count = 0;
191 switch (frame_count_type) {
192 case 0:
193 frame_count = 1;
194 break;
195 case 1:
196 case 2:
197 frame_count = 2;
198 break;
199 case 3:
200 // Type 3 indicates an arbitrary frame count described in the next byte.
201 if (size < 2) {
202 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs)
203 << "Second byte missing from 'Code 3' Opus packet; demuxed block "
204 "duration may be imprecise.";
205 return kNoTimestamp();
206 }
207
208 frame_count = data[1] & kFrameCountMask;
209
210 if (frame_count == 0) {
211 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs)
212 << "Illegal 'Code 3' opus packet with frame count zero; demuxed "
wolenetz 2015/02/06 19:48:01 nit: s/opus/Opus/
chcunningham 2015/02/06 22:46:00 Done.
213 "block duration may be imprecise.";
214 return kNoTimestamp();
215 }
216
217 break;
218 default:
219 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs)
220 << "Unexpected Opus frame count type: " << frame_count_type << "; "
221 << "demuxed block duration may be imprecise.";
222 return kNoTimestamp();
223 }
224
225 int opusConfig = (data[0] & kTocConfigMask) >> 3;
226 CHECK_GE(opusConfig, 0);
227 CHECK_LT(opusConfig, static_cast<int>(arraysize(kOpusFrameDurationsMu)));
228
229 DCHECK_GT(frame_count, 0);
230 base::TimeDelta duration = base::TimeDelta::FromMicroseconds(
231 kOpusFrameDurationsMu[opusConfig] * frame_count);
232
233 if (duration > kPacketDurationMax) {
234 // Intentionally allowing packet to pass through for now. Decoder should
235 // either handle or fail gracefully. MEDIA_LOG as breadcrumbs in case
236 // things go sideways.
237 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs)
238 << "Warning, demuxed Opus packet with encoded duration: " << duration
239 << ". Should be no greater than " << kPacketDurationMax;
240 }
241
242 return duration;
243 }
244
143 WebMParserClient* WebMClusterParser::OnListStart(int id) { 245 WebMParserClient* WebMClusterParser::OnListStart(int id) {
144 if (id == kWebMIdCluster) { 246 if (id == kWebMIdCluster) {
145 cluster_timecode_ = -1; 247 cluster_timecode_ = -1;
146 cluster_start_time_ = kNoTimestamp(); 248 cluster_start_time_ = kNoTimestamp();
147 } else if (id == kWebMIdBlockGroup) { 249 } else if (id == kWebMIdBlockGroup) {
148 block_data_.reset(); 250 block_data_.reset();
149 block_data_size_ = -1; 251 block_data_size_ = -1;
150 block_duration_ = -1; 252 block_duration_ = -1;
151 discard_padding_ = -1; 253 discard_padding_ = -1;
152 discard_padding_set_ = false; 254 discard_padding_set_ = false;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 break; 300 break;
199 default: 301 default:
200 return true; 302 return true;
201 } 303 }
202 if (*dst != -1) 304 if (*dst != -1)
203 return false; 305 return false;
204 *dst = val; 306 *dst = val;
205 return true; 307 return true;
206 } 308 }
207 309
208 bool WebMClusterParser::ParseBlock(bool is_simple_block, const uint8* buf, 310 bool WebMClusterParser::ParseBlock(bool is_simple_block,
209 int size, const uint8* additional, 311 const uint8_t* buf,
210 int additional_size, int duration, 312 int size,
313 const uint8_t* additional,
314 int additional_size,
315 int duration,
211 int64 discard_padding) { 316 int64 discard_padding) {
212 if (size < 4) 317 if (size < 4)
213 return false; 318 return false;
214 319
215 // Return an error if the trackNum > 127. We just aren't 320 // Return an error if the trackNum > 127. We just aren't
216 // going to support large track numbers right now. 321 // going to support large track numbers right now.
217 if (!(buf[0] & 0x80)) { 322 if (!(buf[0] & 0x80)) {
218 MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported"; 323 MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported";
219 return false; 324 return false;
220 } 325 }
221 326
222 int track_num = buf[0] & 0x7f; 327 int track_num = buf[0] & 0x7f;
223 int timecode = buf[1] << 8 | buf[2]; 328 int timecode = buf[1] << 8 | buf[2];
224 int flags = buf[3] & 0xff; 329 int flags = buf[3] & 0xff;
225 int lacing = (flags >> 1) & 0x3; 330 int lacing = (flags >> 1) & 0x3;
226 331
227 if (lacing) { 332 if (lacing) {
228 MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet."; 333 MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet.";
229 return false; 334 return false;
230 } 335 }
231 336
232 // Sign extend negative timecode offsets. 337 // Sign extend negative timecode offsets.
233 if (timecode & 0x8000) 338 if (timecode & 0x8000)
234 timecode |= ~0xffff; 339 timecode |= ~0xffff;
235 340
236 const uint8* frame_data = buf + 4; 341 const uint8_t* frame_data = buf + 4;
237 int frame_size = size - (frame_data - buf); 342 int frame_size = size - (frame_data - buf);
238 return OnBlock(is_simple_block, track_num, timecode, duration, flags, 343 return OnBlock(is_simple_block, track_num, timecode, duration, flags,
239 frame_data, frame_size, additional, additional_size, 344 frame_data, frame_size, additional, additional_size,
240 discard_padding); 345 discard_padding);
241 } 346 }
242 347
243 bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) { 348 bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) {
244 switch (id) { 349 switch (id) {
245 case kWebMIdSimpleBlock: 350 case kWebMIdSimpleBlock:
246 return ParseBlock(true, data, size, NULL, 0, -1, 0); 351 return ParseBlock(true, data, size, NULL, 0, -1, 0);
247 352
248 case kWebMIdBlock: 353 case kWebMIdBlock:
249 if (block_data_) { 354 if (block_data_) {
250 MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not " 355 MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not "
251 "supported."; 356 "supported.";
252 return false; 357 return false;
253 } 358 }
254 block_data_.reset(new uint8[size]); 359 block_data_.reset(new uint8_t[size]);
255 memcpy(block_data_.get(), data, size); 360 memcpy(block_data_.get(), data, size);
256 block_data_size_ = size; 361 block_data_size_ = size;
257 return true; 362 return true;
258 363
259 case kWebMIdBlockAdditional: { 364 case kWebMIdBlockAdditional: {
260 uint64 block_add_id = base::HostToNet64(block_add_id_); 365 uint64 block_add_id = base::HostToNet64(block_add_id_);
261 if (block_additional_data_) { 366 if (block_additional_data_) {
262 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed 367 // 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 368 // 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 369 // support parsing of such files. Take a look at this again when such a
265 // case arises. 370 // case arises.
266 MEDIA_LOG(log_cb_) << "More than 1 BlockAdditional in a BlockGroup is " 371 MEDIA_LOG(log_cb_) << "More than 1 BlockAdditional in a BlockGroup is "
267 "not supported."; 372 "not supported.";
268 return false; 373 return false;
269 } 374 }
270 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID 375 // 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 376 // element's value in Big Endian format. This is done to mimic ffmpeg
272 // demuxer's behavior. 377 // demuxer's behavior.
273 block_additional_data_size_ = size + sizeof(block_add_id); 378 block_additional_data_size_ = size + sizeof(block_add_id);
274 block_additional_data_.reset(new uint8[block_additional_data_size_]); 379 block_additional_data_.reset(new uint8_t[block_additional_data_size_]);
275 memcpy(block_additional_data_.get(), &block_add_id, 380 memcpy(block_additional_data_.get(), &block_add_id,
276 sizeof(block_add_id)); 381 sizeof(block_add_id));
277 memcpy(block_additional_data_.get() + 8, data, size); 382 memcpy(block_additional_data_.get() + 8, data, size);
278 return true; 383 return true;
279 } 384 }
280 case kWebMIdDiscardPadding: { 385 case kWebMIdDiscardPadding: {
281 if (discard_padding_set_ || size <= 0 || size > 8) 386 if (discard_padding_set_ || size <= 0 || size > 8)
282 return false; 387 return false;
283 discard_padding_set_ = true; 388 discard_padding_set_ = true;
284 389
285 // Read in the big-endian integer. 390 // Read in the big-endian integer.
286 discard_padding_ = static_cast<int8>(data[0]); 391 discard_padding_ = static_cast<int8>(data[0]);
287 for (int i = 1; i < size; ++i) 392 for (int i = 1; i < size; ++i)
288 discard_padding_ = (discard_padding_ << 8) | data[i]; 393 discard_padding_ = (discard_padding_ << 8) | data[i];
289 394
290 return true; 395 return true;
291 } 396 }
292 default: 397 default:
293 return true; 398 return true;
294 } 399 }
295 } 400 }
296 401
297 bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num, 402 bool WebMClusterParser::OnBlock(bool is_simple_block,
403 int track_num,
298 int timecode, 404 int timecode,
299 int block_duration, 405 int block_duration,
300 int flags, 406 int flags,
301 const uint8* data, int size, 407 const uint8_t* data,
302 const uint8* additional, int additional_size, 408 int size,
409 const uint8_t* additional,
410 int additional_size,
303 int64 discard_padding) { 411 int64 discard_padding) {
304 DCHECK_GE(size, 0); 412 DCHECK_GE(size, 0);
305 if (cluster_timecode_ == -1) { 413 if (cluster_timecode_ == -1) {
306 MEDIA_LOG(log_cb_) << "Got a block before cluster timecode."; 414 MEDIA_LOG(log_cb_) << "Got a block before cluster timecode.";
307 return false; 415 return false;
308 } 416 }
309 417
310 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or 418 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or
311 // only when the absolute timecode is negative? See http://crbug.com/271794 419 // only when the absolute timecode is negative? See http://crbug.com/271794
312 if (timecode < 0) { 420 if (timecode < 0) {
313 MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset " 421 MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset "
314 << timecode; 422 << timecode;
315 return false; 423 return false;
316 } 424 }
317 425
318 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) { 426 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
319 MEDIA_LOG(log_cb_) 427 MEDIA_LOG(log_cb_)
320 << "Got a block with a timecode before the previous block."; 428 << "Got a block with a timecode before the previous block.";
321 return false; 429 return false;
322 } 430 }
323 431
324 Track* track = NULL; 432 Track* track = NULL;
325 StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO; 433 StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO;
326 std::string encryption_key_id; 434 std::string encryption_key_id;
435 base::TimeDelta encoded_duration = kNoTimestamp();
327 if (track_num == audio_.track_num()) { 436 if (track_num == audio_.track_num()) {
328 track = &audio_; 437 track = &audio_;
329 encryption_key_id = audio_encryption_key_id_; 438 encryption_key_id = audio_encryption_key_id_;
439 if (encryption_key_id.empty()) {
440 encoded_duration = TryGetEncodedAudioDuration(data, size);
441 }
330 } else if (track_num == video_.track_num()) { 442 } else if (track_num == video_.track_num()) {
331 track = &video_; 443 track = &video_;
332 encryption_key_id = video_encryption_key_id_; 444 encryption_key_id = video_encryption_key_id_;
333 buffer_type = DemuxerStream::VIDEO; 445 buffer_type = DemuxerStream::VIDEO;
334 } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) { 446 } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) {
335 return true; 447 return true;
336 } else if (Track* const text_track = FindTextTrack(track_num)) { 448 } else if (Track* const text_track = FindTextTrack(track_num)) {
337 if (is_simple_block) // BlockGroup is required for WebVTT cues 449 if (is_simple_block) // BlockGroup is required for WebVTT cues
338 return false; 450 return false;
339 if (block_duration < 0) // not specified 451 if (block_duration < 0) // not specified
(...skipping 20 matching lines...) Expand all
360 is_simple_block ? (flags & 0x80) != 0 : track->IsKeyframe(data, size); 472 is_simple_block ? (flags & 0x80) != 0 : track->IsKeyframe(data, size);
361 473
362 // Every encrypted Block has a signal byte and IV prepended to it. Current 474 // Every encrypted Block has a signal byte and IV prepended to it. Current
363 // encrypted WebM request for comments specification is here 475 // encrypted WebM request for comments specification is here
364 // http://wiki.webmproject.org/encryption/webm-encryption-rfc 476 // http://wiki.webmproject.org/encryption/webm-encryption-rfc
365 scoped_ptr<DecryptConfig> decrypt_config; 477 scoped_ptr<DecryptConfig> decrypt_config;
366 int data_offset = 0; 478 int data_offset = 0;
367 if (!encryption_key_id.empty() && 479 if (!encryption_key_id.empty() &&
368 !WebMCreateDecryptConfig( 480 !WebMCreateDecryptConfig(
369 data, size, 481 data, size,
370 reinterpret_cast<const uint8*>(encryption_key_id.data()), 482 reinterpret_cast<const uint8_t*>(encryption_key_id.data()),
371 encryption_key_id.size(), 483 encryption_key_id.size(),
372 &decrypt_config, &data_offset)) { 484 &decrypt_config, &data_offset)) {
373 return false; 485 return false;
374 } 486 }
375 487
376 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId 488 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
377 // type with remapped bytestream track numbers and allow multiple tracks as 489 // type with remapped bytestream track numbers and allow multiple tracks as
378 // applicable. See https://crbug.com/341581. 490 // applicable. See https://crbug.com/341581.
379 buffer = StreamParserBuffer::CopyFrom( 491 buffer = StreamParserBuffer::CopyFrom(
380 data + data_offset, size - data_offset, 492 data + data_offset, size - data_offset,
381 additional, additional_size, 493 additional, additional_size,
382 is_keyframe, buffer_type, track_num); 494 is_keyframe, buffer_type, track_num);
383 495
384 if (decrypt_config) 496 if (decrypt_config)
385 buffer->set_decrypt_config(decrypt_config.Pass()); 497 buffer->set_decrypt_config(decrypt_config.Pass());
386 } else { 498 } else {
387 std::string id, settings, content; 499 std::string id, settings, content;
388 WebMWebVTTParser::Parse(data, size, &id, &settings, &content); 500 WebMWebVTTParser::Parse(data, size, &id, &settings, &content);
389 501
390 std::vector<uint8> side_data; 502 std::vector<uint8_t> side_data;
391 MakeSideData(id.begin(), id.end(), 503 MakeSideData(id.begin(), id.end(),
392 settings.begin(), settings.end(), 504 settings.begin(), settings.end(),
393 &side_data); 505 &side_data);
394 506
395 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId 507 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
396 // type with remapped bytestream track numbers and allow multiple tracks as 508 // type with remapped bytestream track numbers and allow multiple tracks as
397 // applicable. See https://crbug.com/341581. 509 // applicable. See https://crbug.com/341581.
398 buffer = StreamParserBuffer::CopyFrom( 510 buffer = StreamParserBuffer::CopyFrom(
399 reinterpret_cast<const uint8*>(content.data()), 511 reinterpret_cast<const uint8_t*>(content.data()),
400 content.length(), 512 content.length(),
401 &side_data[0], 513 &side_data[0],
402 side_data.size(), 514 side_data.size(),
403 true, buffer_type, track_num); 515 true, buffer_type, track_num);
404 } 516 }
405 517
406 buffer->set_timestamp(timestamp); 518 buffer->set_timestamp(timestamp);
407 if (cluster_start_time_ == kNoTimestamp()) 519 if (cluster_start_time_ == kNoTimestamp())
408 cluster_start_time_ = timestamp; 520 cluster_start_time_ = timestamp;
409 521
522 base::TimeDelta block_duration_time_delta = kNoTimestamp();
410 if (block_duration >= 0) { 523 if (block_duration >= 0) {
411 buffer->set_duration(base::TimeDelta::FromMicroseconds( 524 block_duration_time_delta = base::TimeDelta::FromMicroseconds(
412 block_duration * timecode_multiplier_)); 525 block_duration * timecode_multiplier_);
526 }
527
528 // Prefer encoded duration over BlockGroup->BlockDuration or
529 // TrackEntry->DefaultDuration when available. This layering violation is a
530 // workaround for http://crbug.com/396634, decreasing the likelihood of
531 // fall-back to rough estimation techniques for Blocks that lack a
532 // BlockDuration at the end of a cluster. Cross cluster durations are not
533 // feasible given flexibility of cluster ordering and MSE APIs. Duration
534 // estimation may still apply in cases of encryption and codecs for which
535 // we do not extract encoded duration. Within a cluster, estimates are applied
536 // as Block Timecode deltas, or once the whole cluster is parsed in the case
537 // of the last Block in the cluster. See Track::AddBuffer and
538 // ApplyDurationEstimateIfNeeded().
539 if (encoded_duration != kNoTimestamp()) {
540 DCHECK(encoded_duration != kInfiniteDuration());
541 DCHECK(encoded_duration > base::TimeDelta());
542 buffer->set_duration(encoded_duration);
543
544 DVLOG(3) << __FUNCTION__ << " : "
545 << "Using encoded duration " << encoded_duration.InSecondsF();
546
547 if (block_duration_time_delta != kNoTimestamp()) {
548 base::TimeDelta duration_difference =
549 block_duration_time_delta - encoded_duration;
550
551 const auto kWarnDurationDiff =
552 base::TimeDelta::FromMicroseconds(timecode_multiplier_ * 2);
553 if (duration_difference.magnitude() > kWarnDurationDiff) {
554 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs)
555 << "BlockDuration "
556 << "(" << block_duration_time_delta << ") "
557 << "differs significantly from encoded duration "
558 << "(" << encoded_duration << ").";
559 }
560 }
561 } else if (block_duration_time_delta != kNoTimestamp()) {
562 buffer->set_duration(block_duration_time_delta);
413 } else { 563 } else {
414 DCHECK_NE(buffer_type, DemuxerStream::TEXT); 564 DCHECK_NE(buffer_type, DemuxerStream::TEXT);
415 buffer->set_duration(track->default_duration()); 565 buffer->set_duration(track->default_duration());
416 } 566 }
417 567
418 if (discard_padding != 0) { 568 if (discard_padding != 0) {
419 buffer->set_discard_padding(std::make_pair( 569 buffer->set_discard_padding(std::make_pair(
420 base::TimeDelta(), 570 base::TimeDelta(),
421 base::TimeDelta::FromMicroseconds(discard_padding / 1000))); 571 base::TimeDelta::FromMicroseconds(discard_padding / 1000)));
422 } 572 }
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 // reset here. 692 // reset here.
543 ready_buffers_.clear(); 693 ready_buffers_.clear();
544 } 694 }
545 695
546 void WebMClusterParser::Track::Reset() { 696 void WebMClusterParser::Track::Reset() {
547 ClearReadyBuffers(); 697 ClearReadyBuffers();
548 buffers_.clear(); 698 buffers_.clear();
549 last_added_buffer_missing_duration_ = NULL; 699 last_added_buffer_missing_duration_ = NULL;
550 } 700 }
551 701
552 bool WebMClusterParser::Track::IsKeyframe(const uint8* data, int size) const { 702 bool WebMClusterParser::Track::IsKeyframe(const uint8_t* data, int size) const {
553 // For now, assume that all blocks are keyframes for datatypes other than 703 // For now, assume that all blocks are keyframes for datatypes other than
554 // video. This is a valid assumption for Vorbis, WebVTT, & Opus. 704 // video. This is a valid assumption for Vorbis, WebVTT, & Opus.
555 if (!is_video_) 705 if (!is_video_)
556 return true; 706 return true;
557 707
558 // Make sure the block is big enough for the minimal keyframe header size. 708 // Make sure the block is big enough for the minimal keyframe header size.
559 if (size < 7) 709 if (size < 7)
560 return false; 710 return false;
561 711
562 // The LSb of the first byte must be a 0 for a keyframe. 712 // 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
678 WebMClusterParser::FindTextTrack(int track_num) { 828 WebMClusterParser::FindTextTrack(int track_num) {
679 const TextTrackMap::iterator it = text_track_map_.find(track_num); 829 const TextTrackMap::iterator it = text_track_map_.find(track_num);
680 830
681 if (it == text_track_map_.end()) 831 if (it == text_track_map_.end())
682 return NULL; 832 return NULL;
683 833
684 return &it->second; 834 return &it->second;
685 } 835 }
686 836
687 } // namespace media 837 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698