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" |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 int size) { | 178 int size) { |
179 // Masks and constants for Opus packets. See | 179 // Masks and constants for Opus packets. See |
180 // https://tools.ietf.org/html/rfc6716#page-14 | 180 // https://tools.ietf.org/html/rfc6716#page-14 |
181 static const uint8_t kTocConfigMask = 0xf8; | 181 static const uint8_t kTocConfigMask = 0xf8; |
182 static const uint8_t kTocFrameCountCodeMask = 0x03; | 182 static const uint8_t kTocFrameCountCodeMask = 0x03; |
183 static const uint8_t kFrameCountMask = 0x3f; | 183 static const uint8_t kFrameCountMask = 0x3f; |
184 static const base::TimeDelta kPacketDurationMax = | 184 static const base::TimeDelta kPacketDurationMax = |
185 base::TimeDelta::FromMilliseconds(120); | 185 base::TimeDelta::FromMilliseconds(120); |
186 | 186 |
187 if (size < 1) { | 187 if (size < 1) { |
188 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) | 188 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, kMaxDurationLogs) |
189 << "Invalid zero-byte Opus packet; demuxed block duration may be " | 189 << "Invalid zero-byte Opus packet; demuxed block duration may be " |
190 "imprecise."; | 190 "imprecise."; |
191 return kNoTimestamp(); | 191 return kNoTimestamp(); |
192 } | 192 } |
193 | 193 |
194 // Frame count type described by last 2 bits of Opus TOC byte. | 194 // Frame count type described by last 2 bits of Opus TOC byte. |
195 int frame_count_type = data[0] & kTocFrameCountCodeMask; | 195 int frame_count_type = data[0] & kTocFrameCountCodeMask; |
196 | 196 |
197 int frame_count = 0; | 197 int frame_count = 0; |
198 switch (frame_count_type) { | 198 switch (frame_count_type) { |
199 case 0: | 199 case 0: |
200 frame_count = 1; | 200 frame_count = 1; |
201 break; | 201 break; |
202 case 1: | 202 case 1: |
203 case 2: | 203 case 2: |
204 frame_count = 2; | 204 frame_count = 2; |
205 break; | 205 break; |
206 case 3: | 206 case 3: |
207 // Type 3 indicates an arbitrary frame count described in the next byte. | 207 // Type 3 indicates an arbitrary frame count described in the next byte. |
208 if (size < 2) { | 208 if (size < 2) { |
209 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) | 209 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
| 210 kMaxDurationLogs) |
210 << "Second byte missing from 'Code 3' Opus packet; demuxed block " | 211 << "Second byte missing from 'Code 3' Opus packet; demuxed block " |
211 "duration may be imprecise."; | 212 "duration may be imprecise."; |
212 return kNoTimestamp(); | 213 return kNoTimestamp(); |
213 } | 214 } |
214 | 215 |
215 frame_count = data[1] & kFrameCountMask; | 216 frame_count = data[1] & kFrameCountMask; |
216 | 217 |
217 if (frame_count == 0) { | 218 if (frame_count == 0) { |
218 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) | 219 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
| 220 kMaxDurationLogs) |
219 << "Illegal 'Code 3' Opus packet with frame count zero; demuxed " | 221 << "Illegal 'Code 3' Opus packet with frame count zero; demuxed " |
220 "block duration may be imprecise."; | 222 "block duration may be imprecise."; |
221 return kNoTimestamp(); | 223 return kNoTimestamp(); |
222 } | 224 } |
223 | 225 |
224 break; | 226 break; |
225 default: | 227 default: |
226 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) | 228 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, kMaxDurationLogs) |
227 << "Unexpected Opus frame count type: " << frame_count_type << "; " | 229 << "Unexpected Opus frame count type: " << frame_count_type << "; " |
228 << "demuxed block duration may be imprecise."; | 230 << "demuxed block duration may be imprecise."; |
229 return kNoTimestamp(); | 231 return kNoTimestamp(); |
230 } | 232 } |
231 | 233 |
232 int opusConfig = (data[0] & kTocConfigMask) >> 3; | 234 int opusConfig = (data[0] & kTocConfigMask) >> 3; |
233 CHECK_GE(opusConfig, 0); | 235 CHECK_GE(opusConfig, 0); |
234 CHECK_LT(opusConfig, static_cast<int>(arraysize(kOpusFrameDurationsMu))); | 236 CHECK_LT(opusConfig, static_cast<int>(arraysize(kOpusFrameDurationsMu))); |
235 | 237 |
236 DCHECK_GT(frame_count, 0); | 238 DCHECK_GT(frame_count, 0); |
237 base::TimeDelta duration = base::TimeDelta::FromMicroseconds( | 239 base::TimeDelta duration = base::TimeDelta::FromMicroseconds( |
238 kOpusFrameDurationsMu[opusConfig] * frame_count); | 240 kOpusFrameDurationsMu[opusConfig] * frame_count); |
239 | 241 |
240 if (duration > kPacketDurationMax) { | 242 if (duration > kPacketDurationMax) { |
241 // Intentionally allowing packet to pass through for now. Decoder should | 243 // Intentionally allowing packet to pass through for now. Decoder should |
242 // either handle or fail gracefully. MEDIA_LOG as breadcrumbs in case | 244 // either handle or fail gracefully. MEDIA_LOG as breadcrumbs in case |
243 // things go sideways. | 245 // things go sideways. |
244 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) | 246 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, kMaxDurationLogs) |
245 << "Warning, demuxed Opus packet with encoded duration: " << duration | 247 << "Warning, demuxed Opus packet with encoded duration: " << duration |
246 << ". Should be no greater than " << kPacketDurationMax; | 248 << ". Should be no greater than " << kPacketDurationMax; |
247 } | 249 } |
248 | 250 |
249 return duration; | 251 return duration; |
250 } | 252 } |
251 | 253 |
252 WebMParserClient* WebMClusterParser::OnListStart(int id) { | 254 WebMParserClient* WebMClusterParser::OnListStart(int id) { |
253 if (id == kWebMIdCluster) { | 255 if (id == kWebMIdCluster) { |
254 cluster_timecode_ = -1; | 256 cluster_timecode_ = -1; |
(...skipping 12 matching lines...) Expand all Loading... |
267 | 269 |
268 return this; | 270 return this; |
269 } | 271 } |
270 | 272 |
271 bool WebMClusterParser::OnListEnd(int id) { | 273 bool WebMClusterParser::OnListEnd(int id) { |
272 if (id != kWebMIdBlockGroup) | 274 if (id != kWebMIdBlockGroup) |
273 return true; | 275 return true; |
274 | 276 |
275 // Make sure the BlockGroup actually had a Block. | 277 // Make sure the BlockGroup actually had a Block. |
276 if (block_data_size_ == -1) { | 278 if (block_data_size_ == -1) { |
277 MEDIA_LOG(log_cb_) << "Block missing from BlockGroup."; | 279 MEDIA_LOG(ERROR, log_cb_) << "Block missing from BlockGroup."; |
278 return false; | 280 return false; |
279 } | 281 } |
280 | 282 |
281 bool result = ParseBlock(false, block_data_.get(), block_data_size_, | 283 bool result = ParseBlock(false, block_data_.get(), block_data_size_, |
282 block_additional_data_.get(), | 284 block_additional_data_.get(), |
283 block_additional_data_size_, block_duration_, | 285 block_additional_data_size_, block_duration_, |
284 discard_padding_set_ ? discard_padding_ : 0); | 286 discard_padding_set_ ? discard_padding_ : 0); |
285 block_data_.reset(); | 287 block_data_.reset(); |
286 block_data_size_ = -1; | 288 block_data_size_ = -1; |
287 block_duration_ = -1; | 289 block_duration_ = -1; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 const uint8_t* additional, | 322 const uint8_t* additional, |
321 int additional_size, | 323 int additional_size, |
322 int duration, | 324 int duration, |
323 int64 discard_padding) { | 325 int64 discard_padding) { |
324 if (size < 4) | 326 if (size < 4) |
325 return false; | 327 return false; |
326 | 328 |
327 // Return an error if the trackNum > 127. We just aren't | 329 // Return an error if the trackNum > 127. We just aren't |
328 // going to support large track numbers right now. | 330 // going to support large track numbers right now. |
329 if (!(buf[0] & 0x80)) { | 331 if (!(buf[0] & 0x80)) { |
330 MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported"; | 332 MEDIA_LOG(ERROR, log_cb_) << "TrackNumber over 127 not supported"; |
331 return false; | 333 return false; |
332 } | 334 } |
333 | 335 |
334 int track_num = buf[0] & 0x7f; | 336 int track_num = buf[0] & 0x7f; |
335 int timecode = buf[1] << 8 | buf[2]; | 337 int timecode = buf[1] << 8 | buf[2]; |
336 int flags = buf[3] & 0xff; | 338 int flags = buf[3] & 0xff; |
337 int lacing = (flags >> 1) & 0x3; | 339 int lacing = (flags >> 1) & 0x3; |
338 | 340 |
339 if (lacing) { | 341 if (lacing) { |
340 MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet."; | 342 MEDIA_LOG(ERROR, log_cb_) << "Lacing " << lacing |
| 343 << " is not supported yet."; |
341 return false; | 344 return false; |
342 } | 345 } |
343 | 346 |
344 // Sign extend negative timecode offsets. | 347 // Sign extend negative timecode offsets. |
345 if (timecode & 0x8000) | 348 if (timecode & 0x8000) |
346 timecode |= ~0xffff; | 349 timecode |= ~0xffff; |
347 | 350 |
348 const uint8_t* frame_data = buf + 4; | 351 const uint8_t* frame_data = buf + 4; |
349 int frame_size = size - (frame_data - buf); | 352 int frame_size = size - (frame_data - buf); |
350 return OnBlock(is_simple_block, track_num, timecode, duration, flags, | 353 return OnBlock(is_simple_block, track_num, timecode, duration, flags, |
351 frame_data, frame_size, additional, additional_size, | 354 frame_data, frame_size, additional, additional_size, |
352 discard_padding); | 355 discard_padding); |
353 } | 356 } |
354 | 357 |
355 bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) { | 358 bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) { |
356 switch (id) { | 359 switch (id) { |
357 case kWebMIdSimpleBlock: | 360 case kWebMIdSimpleBlock: |
358 return ParseBlock(true, data, size, NULL, 0, -1, 0); | 361 return ParseBlock(true, data, size, NULL, 0, -1, 0); |
359 | 362 |
360 case kWebMIdBlock: | 363 case kWebMIdBlock: |
361 if (block_data_) { | 364 if (block_data_) { |
362 MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not " | 365 MEDIA_LOG(ERROR, log_cb_) << "More than 1 Block in a BlockGroup is not " |
363 "supported."; | 366 "supported."; |
364 return false; | 367 return false; |
365 } | 368 } |
366 block_data_.reset(new uint8_t[size]); | 369 block_data_.reset(new uint8_t[size]); |
367 memcpy(block_data_.get(), data, size); | 370 memcpy(block_data_.get(), data, size); |
368 block_data_size_ = size; | 371 block_data_size_ = size; |
369 return true; | 372 return true; |
370 | 373 |
371 case kWebMIdBlockAdditional: { | 374 case kWebMIdBlockAdditional: { |
372 uint64 block_add_id = base::HostToNet64(block_add_id_); | 375 uint64 block_add_id = base::HostToNet64(block_add_id_); |
373 if (block_additional_data_) { | 376 if (block_additional_data_) { |
374 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed | 377 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed |
375 // as per matroska spec. But for now we don't have a use case to | 378 // as per matroska spec. But for now we don't have a use case to |
376 // support parsing of such files. Take a look at this again when such a | 379 // support parsing of such files. Take a look at this again when such a |
377 // case arises. | 380 // case arises. |
378 MEDIA_LOG(log_cb_) << "More than 1 BlockAdditional in a BlockGroup is " | 381 MEDIA_LOG(ERROR, log_cb_) << "More than 1 BlockAdditional in a " |
379 "not supported."; | 382 "BlockGroup is not supported."; |
380 return false; | 383 return false; |
381 } | 384 } |
382 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID | 385 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID |
383 // element's value in Big Endian format. This is done to mimic ffmpeg | 386 // element's value in Big Endian format. This is done to mimic ffmpeg |
384 // demuxer's behavior. | 387 // demuxer's behavior. |
385 block_additional_data_size_ = size + sizeof(block_add_id); | 388 block_additional_data_size_ = size + sizeof(block_add_id); |
386 block_additional_data_.reset(new uint8_t[block_additional_data_size_]); | 389 block_additional_data_.reset(new uint8_t[block_additional_data_size_]); |
387 memcpy(block_additional_data_.get(), &block_add_id, | 390 memcpy(block_additional_data_.get(), &block_add_id, |
388 sizeof(block_add_id)); | 391 sizeof(block_add_id)); |
389 memcpy(block_additional_data_.get() + 8, data, size); | 392 memcpy(block_additional_data_.get() + 8, data, size); |
(...skipping 21 matching lines...) Expand all Loading... |
411 int timecode, | 414 int timecode, |
412 int block_duration, | 415 int block_duration, |
413 int flags, | 416 int flags, |
414 const uint8_t* data, | 417 const uint8_t* data, |
415 int size, | 418 int size, |
416 const uint8_t* additional, | 419 const uint8_t* additional, |
417 int additional_size, | 420 int additional_size, |
418 int64 discard_padding) { | 421 int64 discard_padding) { |
419 DCHECK_GE(size, 0); | 422 DCHECK_GE(size, 0); |
420 if (cluster_timecode_ == -1) { | 423 if (cluster_timecode_ == -1) { |
421 MEDIA_LOG(log_cb_) << "Got a block before cluster timecode."; | 424 MEDIA_LOG(ERROR, log_cb_) << "Got a block before cluster timecode."; |
422 return false; | 425 return false; |
423 } | 426 } |
424 | 427 |
425 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or | 428 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or |
426 // only when the absolute timecode is negative? See http://crbug.com/271794 | 429 // only when the absolute timecode is negative? See http://crbug.com/271794 |
427 if (timecode < 0) { | 430 if (timecode < 0) { |
428 MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset " | 431 MEDIA_LOG(ERROR, log_cb_) << "Got a block with negative timecode offset " |
429 << timecode; | 432 << timecode; |
430 return false; | 433 return false; |
431 } | 434 } |
432 | 435 |
433 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) { | 436 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) { |
434 MEDIA_LOG(log_cb_) | 437 MEDIA_LOG(ERROR, log_cb_) |
435 << "Got a block with a timecode before the previous block."; | 438 << "Got a block with a timecode before the previous block."; |
436 return false; | 439 return false; |
437 } | 440 } |
438 | 441 |
439 Track* track = NULL; | 442 Track* track = NULL; |
440 StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO; | 443 StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO; |
441 std::string encryption_key_id; | 444 std::string encryption_key_id; |
442 base::TimeDelta encoded_duration = kNoTimestamp(); | 445 base::TimeDelta encoded_duration = kNoTimestamp(); |
443 if (track_num == audio_.track_num()) { | 446 if (track_num == audio_.track_num()) { |
444 track = &audio_; | 447 track = &audio_; |
445 encryption_key_id = audio_encryption_key_id_; | 448 encryption_key_id = audio_encryption_key_id_; |
446 if (encryption_key_id.empty()) { | 449 if (encryption_key_id.empty()) { |
447 encoded_duration = TryGetEncodedAudioDuration(data, size); | 450 encoded_duration = TryGetEncodedAudioDuration(data, size); |
448 } | 451 } |
449 } else if (track_num == video_.track_num()) { | 452 } else if (track_num == video_.track_num()) { |
450 track = &video_; | 453 track = &video_; |
451 encryption_key_id = video_encryption_key_id_; | 454 encryption_key_id = video_encryption_key_id_; |
452 buffer_type = DemuxerStream::VIDEO; | 455 buffer_type = DemuxerStream::VIDEO; |
453 } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) { | 456 } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) { |
454 return true; | 457 return true; |
455 } else if (Track* const text_track = FindTextTrack(track_num)) { | 458 } else if (Track* const text_track = FindTextTrack(track_num)) { |
456 if (is_simple_block) // BlockGroup is required for WebVTT cues | 459 if (is_simple_block) // BlockGroup is required for WebVTT cues |
457 return false; | 460 return false; |
458 if (block_duration < 0) // not specified | 461 if (block_duration < 0) // not specified |
459 return false; | 462 return false; |
460 track = text_track; | 463 track = text_track; |
461 buffer_type = DemuxerStream::TEXT; | 464 buffer_type = DemuxerStream::TEXT; |
462 } else { | 465 } else { |
463 MEDIA_LOG(log_cb_) << "Unexpected track number " << track_num; | 466 MEDIA_LOG(ERROR, log_cb_) << "Unexpected track number " << track_num; |
464 return false; | 467 return false; |
465 } | 468 } |
466 | 469 |
467 last_block_timecode_ = timecode; | 470 last_block_timecode_ = timecode; |
468 | 471 |
469 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( | 472 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( |
470 (cluster_timecode_ + timecode) * timecode_multiplier_); | 473 (cluster_timecode_ + timecode) * timecode_multiplier_); |
471 | 474 |
472 scoped_refptr<StreamParserBuffer> buffer; | 475 scoped_refptr<StreamParserBuffer> buffer; |
473 if (buffer_type != DemuxerStream::TEXT) { | 476 if (buffer_type != DemuxerStream::TEXT) { |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 DVLOG(3) << __FUNCTION__ << " : " | 554 DVLOG(3) << __FUNCTION__ << " : " |
552 << "Using encoded duration " << encoded_duration.InSecondsF(); | 555 << "Using encoded duration " << encoded_duration.InSecondsF(); |
553 | 556 |
554 if (block_duration_time_delta != kNoTimestamp()) { | 557 if (block_duration_time_delta != kNoTimestamp()) { |
555 base::TimeDelta duration_difference = | 558 base::TimeDelta duration_difference = |
556 block_duration_time_delta - encoded_duration; | 559 block_duration_time_delta - encoded_duration; |
557 | 560 |
558 const auto kWarnDurationDiff = | 561 const auto kWarnDurationDiff = |
559 base::TimeDelta::FromMicroseconds(timecode_multiplier_ * 2); | 562 base::TimeDelta::FromMicroseconds(timecode_multiplier_ * 2); |
560 if (duration_difference.magnitude() > kWarnDurationDiff) { | 563 if (duration_difference.magnitude() > kWarnDurationDiff) { |
561 LIMITED_MEDIA_LOG(log_cb_, num_duration_errors_, kMaxDurationLogs) | 564 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, |
| 565 kMaxDurationLogs) |
562 << "BlockDuration " | 566 << "BlockDuration " |
563 << "(" << block_duration_time_delta << ") " | 567 << "(" << block_duration_time_delta << ") " |
564 << "differs significantly from encoded duration " | 568 << "differs significantly from encoded duration " |
565 << "(" << encoded_duration << ")."; | 569 << "(" << encoded_duration << ")."; |
566 } | 570 } |
567 } | 571 } |
568 } else if (block_duration_time_delta != kNoTimestamp()) { | 572 } else if (block_duration_time_delta != kNoTimestamp()) { |
569 buffer->set_duration(block_duration_time_delta); | 573 buffer->set_duration(block_duration_time_delta); |
570 } else { | 574 } else { |
571 DCHECK_NE(buffer_type, DemuxerStream::TEXT); | 575 DCHECK_NE(buffer_type, DemuxerStream::TEXT); |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
735 | 739 |
736 // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing | 740 // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing |
737 // block timecode detection within a cluster. Therefore, we should not see | 741 // block timecode detection within a cluster. Therefore, we should not see |
738 // those here. | 742 // those here. |
739 DecodeTimestamp previous_buffers_timestamp = buffers_.empty() ? | 743 DecodeTimestamp previous_buffers_timestamp = buffers_.empty() ? |
740 DecodeTimestamp() : buffers_.back()->GetDecodeTimestamp(); | 744 DecodeTimestamp() : buffers_.back()->GetDecodeTimestamp(); |
741 CHECK(previous_buffers_timestamp <= buffer->GetDecodeTimestamp()); | 745 CHECK(previous_buffers_timestamp <= buffer->GetDecodeTimestamp()); |
742 | 746 |
743 base::TimeDelta duration = buffer->duration(); | 747 base::TimeDelta duration = buffer->duration(); |
744 if (duration < base::TimeDelta() || duration == kNoTimestamp()) { | 748 if (duration < base::TimeDelta() || duration == kNoTimestamp()) { |
745 MEDIA_LOG(log_cb_) << "Invalid buffer duration: " << duration.InSecondsF(); | 749 MEDIA_LOG(ERROR, log_cb_) |
| 750 << "Invalid buffer duration: " << duration.InSecondsF(); |
746 return false; | 751 return false; |
747 } | 752 } |
748 | 753 |
749 // The estimated frame duration is the minimum non-zero duration since the | 754 // The estimated frame duration is the minimum non-zero duration since the |
750 // last initialization segment. The minimum is used to ensure frame durations | 755 // last initialization segment. The minimum is used to ensure frame durations |
751 // aren't overestimated. | 756 // aren't overestimated. |
752 if (duration > base::TimeDelta()) { | 757 if (duration > base::TimeDelta()) { |
753 if (estimated_next_frame_duration_ == kNoTimestamp()) { | 758 if (estimated_next_frame_duration_ == kNoTimestamp()) { |
754 estimated_next_frame_duration_ = duration; | 759 estimated_next_frame_duration_ = duration; |
755 } else { | 760 } else { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
835 WebMClusterParser::FindTextTrack(int track_num) { | 840 WebMClusterParser::FindTextTrack(int track_num) { |
836 const TextTrackMap::iterator it = text_track_map_.find(track_num); | 841 const TextTrackMap::iterator it = text_track_map_.find(track_num); |
837 | 842 |
838 if (it == text_track_map_.end()) | 843 if (it == text_track_map_.end()) |
839 return NULL; | 844 return NULL; |
840 | 845 |
841 return &it->second; | 846 return &it->second; |
842 } | 847 } |
843 | 848 |
844 } // namespace media | 849 } // namespace media |
OLD | NEW |