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

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

Powered by Google App Engine
This is Rietveld 408576698