| 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 24 matching lines...) Expand all Loading... |
| 35 int64 timecode_scale, | 35 int64 timecode_scale, |
| 36 int audio_track_num, | 36 int audio_track_num, |
| 37 base::TimeDelta audio_default_duration, | 37 base::TimeDelta audio_default_duration, |
| 38 int video_track_num, | 38 int video_track_num, |
| 39 base::TimeDelta video_default_duration, | 39 base::TimeDelta video_default_duration, |
| 40 const WebMTracksParser::TextTracks& text_tracks, | 40 const WebMTracksParser::TextTracks& text_tracks, |
| 41 const std::set<int64>& ignored_tracks, | 41 const std::set<int64>& ignored_tracks, |
| 42 const std::string& audio_encryption_key_id, | 42 const std::string& audio_encryption_key_id, |
| 43 const std::string& video_encryption_key_id, | 43 const std::string& video_encryption_key_id, |
| 44 const AudioCodec audio_codec, | 44 const AudioCodec audio_codec, |
| 45 const LogCB& log_cb) | 45 const scoped_refptr<MediaLog>& media_log) |
| 46 : num_duration_errors_(0), | 46 : num_duration_errors_(0), |
| 47 timecode_multiplier_(timecode_scale / 1000.0), | 47 timecode_multiplier_(timecode_scale / 1000.0), |
| 48 ignored_tracks_(ignored_tracks), | 48 ignored_tracks_(ignored_tracks), |
| 49 audio_encryption_key_id_(audio_encryption_key_id), | 49 audio_encryption_key_id_(audio_encryption_key_id), |
| 50 video_encryption_key_id_(video_encryption_key_id), | 50 video_encryption_key_id_(video_encryption_key_id), |
| 51 audio_codec_(audio_codec), | 51 audio_codec_(audio_codec), |
| 52 parser_(kWebMIdCluster, this), | 52 parser_(kWebMIdCluster, this), |
| 53 last_block_timecode_(-1), | 53 last_block_timecode_(-1), |
| 54 block_data_size_(-1), | 54 block_data_size_(-1), |
| 55 block_duration_(-1), | 55 block_duration_(-1), |
| 56 block_add_id_(-1), | 56 block_add_id_(-1), |
| 57 block_additional_data_size_(0), | 57 block_additional_data_size_(0), |
| 58 discard_padding_(-1), | 58 discard_padding_(-1), |
| 59 cluster_timecode_(-1), | 59 cluster_timecode_(-1), |
| 60 cluster_start_time_(kNoTimestamp()), | 60 cluster_start_time_(kNoTimestamp()), |
| 61 cluster_ended_(false), | 61 cluster_ended_(false), |
| 62 audio_(audio_track_num, false, audio_default_duration, log_cb), | 62 audio_(audio_track_num, false, audio_default_duration, media_log), |
| 63 video_(video_track_num, true, video_default_duration, log_cb), | 63 video_(video_track_num, true, video_default_duration, media_log), |
| 64 ready_buffer_upper_bound_(kNoDecodeTimestamp()), | 64 ready_buffer_upper_bound_(kNoDecodeTimestamp()), |
| 65 log_cb_(log_cb) { | 65 media_log_(media_log) { |
| 66 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); | 66 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); |
| 67 it != text_tracks.end(); | 67 it != text_tracks.end(); |
| 68 ++it) { | 68 ++it) { |
| 69 text_track_map_.insert(std::make_pair( | 69 text_track_map_.insert(std::make_pair( |
| 70 it->first, Track(it->first, false, kNoTimestamp(), log_cb_))); | 70 it->first, Track(it->first, false, kNoTimestamp(), media_log_))); |
| 71 } | 71 } |
| 72 } | 72 } |
| 73 | 73 |
| 74 WebMClusterParser::~WebMClusterParser() {} | 74 WebMClusterParser::~WebMClusterParser() {} |
| 75 | 75 |
| 76 void WebMClusterParser::Reset() { | 76 void WebMClusterParser::Reset() { |
| 77 last_block_timecode_ = -1; | 77 last_block_timecode_ = -1; |
| 78 cluster_timecode_ = -1; | 78 cluster_timecode_ = -1; |
| 79 cluster_start_time_ = kNoTimestamp(); | 79 cluster_start_time_ = kNoTimestamp(); |
| 80 cluster_ended_ = false; | 80 cluster_ended_ = false; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 int size) { | 181 int size) { |
| 182 // Masks and constants for Opus packets. See | 182 // Masks and constants for Opus packets. See |
| 183 // https://tools.ietf.org/html/rfc6716#page-14 | 183 // https://tools.ietf.org/html/rfc6716#page-14 |
| 184 static const uint8_t kTocConfigMask = 0xf8; | 184 static const uint8_t kTocConfigMask = 0xf8; |
| 185 static const uint8_t kTocFrameCountCodeMask = 0x03; | 185 static const uint8_t kTocFrameCountCodeMask = 0x03; |
| 186 static const uint8_t kFrameCountMask = 0x3f; | 186 static const uint8_t kFrameCountMask = 0x3f; |
| 187 static const base::TimeDelta kPacketDurationMax = | 187 static const base::TimeDelta kPacketDurationMax = |
| 188 base::TimeDelta::FromMilliseconds(120); | 188 base::TimeDelta::FromMilliseconds(120); |
| 189 | 189 |
| 190 if (size < 1) { | 190 if (size < 1) { |
| 191 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, | 191 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_duration_errors_, |
| 192 kMaxDurationErrorLogs) | 192 kMaxDurationErrorLogs) |
| 193 << "Invalid zero-byte Opus packet; demuxed block duration may be " | 193 << "Invalid zero-byte Opus packet; demuxed block duration may be " |
| 194 "imprecise."; | 194 "imprecise."; |
| 195 return kNoTimestamp(); | 195 return kNoTimestamp(); |
| 196 } | 196 } |
| 197 | 197 |
| 198 // Frame count type described by last 2 bits of Opus TOC byte. | 198 // Frame count type described by last 2 bits of Opus TOC byte. |
| 199 int frame_count_type = data[0] & kTocFrameCountCodeMask; | 199 int frame_count_type = data[0] & kTocFrameCountCodeMask; |
| 200 | 200 |
| 201 int frame_count = 0; | 201 int frame_count = 0; |
| 202 switch (frame_count_type) { | 202 switch (frame_count_type) { |
| 203 case 0: | 203 case 0: |
| 204 frame_count = 1; | 204 frame_count = 1; |
| 205 break; | 205 break; |
| 206 case 1: | 206 case 1: |
| 207 case 2: | 207 case 2: |
| 208 frame_count = 2; | 208 frame_count = 2; |
| 209 break; | 209 break; |
| 210 case 3: | 210 case 3: |
| 211 // Type 3 indicates an arbitrary frame count described in the next byte. | 211 // Type 3 indicates an arbitrary frame count described in the next byte. |
| 212 if (size < 2) { | 212 if (size < 2) { |
| 213 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, | 213 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_duration_errors_, |
| 214 kMaxDurationErrorLogs) | 214 kMaxDurationErrorLogs) |
| 215 << "Second byte missing from 'Code 3' Opus packet; demuxed block " | 215 << "Second byte missing from 'Code 3' Opus packet; demuxed block " |
| 216 "duration may be imprecise."; | 216 "duration may be imprecise."; |
| 217 return kNoTimestamp(); | 217 return kNoTimestamp(); |
| 218 } | 218 } |
| 219 | 219 |
| 220 frame_count = data[1] & kFrameCountMask; | 220 frame_count = data[1] & kFrameCountMask; |
| 221 | 221 |
| 222 if (frame_count == 0) { | 222 if (frame_count == 0) { |
| 223 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, | 223 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_duration_errors_, |
| 224 kMaxDurationErrorLogs) | 224 kMaxDurationErrorLogs) |
| 225 << "Illegal 'Code 3' Opus packet with frame count zero; demuxed " | 225 << "Illegal 'Code 3' Opus packet with frame count zero; demuxed " |
| 226 "block duration may be imprecise."; | 226 "block duration may be imprecise."; |
| 227 return kNoTimestamp(); | 227 return kNoTimestamp(); |
| 228 } | 228 } |
| 229 | 229 |
| 230 break; | 230 break; |
| 231 default: | 231 default: |
| 232 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, | 232 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_duration_errors_, |
| 233 kMaxDurationErrorLogs) | 233 kMaxDurationErrorLogs) |
| 234 << "Unexpected Opus frame count type: " << frame_count_type << "; " | 234 << "Unexpected Opus frame count type: " << frame_count_type << "; " |
| 235 << "demuxed block duration may be imprecise."; | 235 << "demuxed block duration may be imprecise."; |
| 236 return kNoTimestamp(); | 236 return kNoTimestamp(); |
| 237 } | 237 } |
| 238 | 238 |
| 239 int opusConfig = (data[0] & kTocConfigMask) >> 3; | 239 int opusConfig = (data[0] & kTocConfigMask) >> 3; |
| 240 CHECK_GE(opusConfig, 0); | 240 CHECK_GE(opusConfig, 0); |
| 241 CHECK_LT(opusConfig, static_cast<int>(arraysize(kOpusFrameDurationsMu))); | 241 CHECK_LT(opusConfig, static_cast<int>(arraysize(kOpusFrameDurationsMu))); |
| 242 | 242 |
| 243 DCHECK_GT(frame_count, 0); | 243 DCHECK_GT(frame_count, 0); |
| 244 base::TimeDelta duration = base::TimeDelta::FromMicroseconds( | 244 base::TimeDelta duration = base::TimeDelta::FromMicroseconds( |
| 245 kOpusFrameDurationsMu[opusConfig] * frame_count); | 245 kOpusFrameDurationsMu[opusConfig] * frame_count); |
| 246 | 246 |
| 247 if (duration > kPacketDurationMax) { | 247 if (duration > kPacketDurationMax) { |
| 248 // Intentionally allowing packet to pass through for now. Decoder should | 248 // Intentionally allowing packet to pass through for now. Decoder should |
| 249 // either handle or fail gracefully. MEDIA_LOG as breadcrumbs in case | 249 // either handle or fail gracefully. MEDIA_LOG as breadcrumbs in case |
| 250 // things go sideways. | 250 // things go sideways. |
| 251 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, | 251 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_duration_errors_, |
| 252 kMaxDurationErrorLogs) | 252 kMaxDurationErrorLogs) |
| 253 << "Warning, demuxed Opus packet with encoded duration: " << duration | 253 << "Warning, demuxed Opus packet with encoded duration: " << duration |
| 254 << ". Should be no greater than " << kPacketDurationMax; | 254 << ". Should be no greater than " << kPacketDurationMax; |
| 255 } | 255 } |
| 256 | 256 |
| 257 return duration; | 257 return duration; |
| 258 } | 258 } |
| 259 | 259 |
| 260 WebMParserClient* WebMClusterParser::OnListStart(int id) { | 260 WebMParserClient* WebMClusterParser::OnListStart(int id) { |
| 261 if (id == kWebMIdCluster) { | 261 if (id == kWebMIdCluster) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 275 | 275 |
| 276 return this; | 276 return this; |
| 277 } | 277 } |
| 278 | 278 |
| 279 bool WebMClusterParser::OnListEnd(int id) { | 279 bool WebMClusterParser::OnListEnd(int id) { |
| 280 if (id != kWebMIdBlockGroup) | 280 if (id != kWebMIdBlockGroup) |
| 281 return true; | 281 return true; |
| 282 | 282 |
| 283 // Make sure the BlockGroup actually had a Block. | 283 // Make sure the BlockGroup actually had a Block. |
| 284 if (block_data_size_ == -1) { | 284 if (block_data_size_ == -1) { |
| 285 MEDIA_LOG(ERROR, log_cb_) << "Block missing from BlockGroup."; | 285 MEDIA_LOG(ERROR, media_log_) << "Block missing from BlockGroup."; |
| 286 return false; | 286 return false; |
| 287 } | 287 } |
| 288 | 288 |
| 289 bool result = ParseBlock(false, block_data_.get(), block_data_size_, | 289 bool result = ParseBlock(false, block_data_.get(), block_data_size_, |
| 290 block_additional_data_.get(), | 290 block_additional_data_.get(), |
| 291 block_additional_data_size_, block_duration_, | 291 block_additional_data_size_, block_duration_, |
| 292 discard_padding_set_ ? discard_padding_ : 0); | 292 discard_padding_set_ ? discard_padding_ : 0); |
| 293 block_data_.reset(); | 293 block_data_.reset(); |
| 294 block_data_size_ = -1; | 294 block_data_size_ = -1; |
| 295 block_duration_ = -1; | 295 block_duration_ = -1; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 const uint8_t* additional, | 328 const uint8_t* additional, |
| 329 int additional_size, | 329 int additional_size, |
| 330 int duration, | 330 int duration, |
| 331 int64 discard_padding) { | 331 int64 discard_padding) { |
| 332 if (size < 4) | 332 if (size < 4) |
| 333 return false; | 333 return false; |
| 334 | 334 |
| 335 // Return an error if the trackNum > 127. We just aren't | 335 // Return an error if the trackNum > 127. We just aren't |
| 336 // going to support large track numbers right now. | 336 // going to support large track numbers right now. |
| 337 if (!(buf[0] & 0x80)) { | 337 if (!(buf[0] & 0x80)) { |
| 338 MEDIA_LOG(ERROR, log_cb_) << "TrackNumber over 127 not supported"; | 338 MEDIA_LOG(ERROR, media_log_) << "TrackNumber over 127 not supported"; |
| 339 return false; | 339 return false; |
| 340 } | 340 } |
| 341 | 341 |
| 342 int track_num = buf[0] & 0x7f; | 342 int track_num = buf[0] & 0x7f; |
| 343 int timecode = buf[1] << 8 | buf[2]; | 343 int timecode = buf[1] << 8 | buf[2]; |
| 344 int flags = buf[3] & 0xff; | 344 int flags = buf[3] & 0xff; |
| 345 int lacing = (flags >> 1) & 0x3; | 345 int lacing = (flags >> 1) & 0x3; |
| 346 | 346 |
| 347 if (lacing) { | 347 if (lacing) { |
| 348 MEDIA_LOG(ERROR, log_cb_) << "Lacing " << lacing | 348 MEDIA_LOG(ERROR, media_log_) << "Lacing " << lacing |
| 349 << " is not supported yet."; | 349 << " is not supported yet."; |
| 350 return false; | 350 return false; |
| 351 } | 351 } |
| 352 | 352 |
| 353 // Sign extend negative timecode offsets. | 353 // Sign extend negative timecode offsets. |
| 354 if (timecode & 0x8000) | 354 if (timecode & 0x8000) |
| 355 timecode |= ~0xffff; | 355 timecode |= ~0xffff; |
| 356 | 356 |
| 357 const uint8_t* frame_data = buf + 4; | 357 const uint8_t* frame_data = buf + 4; |
| 358 int frame_size = size - (frame_data - buf); | 358 int frame_size = size - (frame_data - buf); |
| 359 return OnBlock(is_simple_block, track_num, timecode, duration, flags, | 359 return OnBlock(is_simple_block, track_num, timecode, duration, flags, |
| 360 frame_data, frame_size, additional, additional_size, | 360 frame_data, frame_size, additional, additional_size, |
| 361 discard_padding); | 361 discard_padding); |
| 362 } | 362 } |
| 363 | 363 |
| 364 bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) { | 364 bool WebMClusterParser::OnBinary(int id, const uint8_t* data, int size) { |
| 365 switch (id) { | 365 switch (id) { |
| 366 case kWebMIdSimpleBlock: | 366 case kWebMIdSimpleBlock: |
| 367 return ParseBlock(true, data, size, NULL, 0, -1, 0); | 367 return ParseBlock(true, data, size, NULL, 0, -1, 0); |
| 368 | 368 |
| 369 case kWebMIdBlock: | 369 case kWebMIdBlock: |
| 370 if (block_data_) { | 370 if (block_data_) { |
| 371 MEDIA_LOG(ERROR, log_cb_) << "More than 1 Block in a BlockGroup is not " | 371 MEDIA_LOG(ERROR, media_log_) |
| 372 "supported."; | 372 << "More than 1 Block in a BlockGroup is not " |
| 373 "supported."; |
| 373 return false; | 374 return false; |
| 374 } | 375 } |
| 375 block_data_.reset(new uint8_t[size]); | 376 block_data_.reset(new uint8_t[size]); |
| 376 memcpy(block_data_.get(), data, size); | 377 memcpy(block_data_.get(), data, size); |
| 377 block_data_size_ = size; | 378 block_data_size_ = size; |
| 378 return true; | 379 return true; |
| 379 | 380 |
| 380 case kWebMIdBlockAdditional: { | 381 case kWebMIdBlockAdditional: { |
| 381 uint64 block_add_id = base::HostToNet64(block_add_id_); | 382 uint64 block_add_id = base::HostToNet64(block_add_id_); |
| 382 if (block_additional_data_) { | 383 if (block_additional_data_) { |
| 383 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed | 384 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed |
| 384 // as per matroska spec. But for now we don't have a use case to | 385 // as per matroska spec. But for now we don't have a use case to |
| 385 // support parsing of such files. Take a look at this again when such a | 386 // support parsing of such files. Take a look at this again when such a |
| 386 // case arises. | 387 // case arises. |
| 387 MEDIA_LOG(ERROR, log_cb_) << "More than 1 BlockAdditional in a " | 388 MEDIA_LOG(ERROR, media_log_) << "More than 1 BlockAdditional in a " |
| 388 "BlockGroup is not supported."; | 389 "BlockGroup is not supported."; |
| 389 return false; | 390 return false; |
| 390 } | 391 } |
| 391 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID | 392 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID |
| 392 // element's value in Big Endian format. This is done to mimic ffmpeg | 393 // element's value in Big Endian format. This is done to mimic ffmpeg |
| 393 // demuxer's behavior. | 394 // demuxer's behavior. |
| 394 block_additional_data_size_ = size + sizeof(block_add_id); | 395 block_additional_data_size_ = size + sizeof(block_add_id); |
| 395 block_additional_data_.reset(new uint8_t[block_additional_data_size_]); | 396 block_additional_data_.reset(new uint8_t[block_additional_data_size_]); |
| 396 memcpy(block_additional_data_.get(), &block_add_id, | 397 memcpy(block_additional_data_.get(), &block_add_id, |
| 397 sizeof(block_add_id)); | 398 sizeof(block_add_id)); |
| 398 memcpy(block_additional_data_.get() + 8, data, size); | 399 memcpy(block_additional_data_.get() + 8, data, size); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 420 int timecode, | 421 int timecode, |
| 421 int block_duration, | 422 int block_duration, |
| 422 int flags, | 423 int flags, |
| 423 const uint8_t* data, | 424 const uint8_t* data, |
| 424 int size, | 425 int size, |
| 425 const uint8_t* additional, | 426 const uint8_t* additional, |
| 426 int additional_size, | 427 int additional_size, |
| 427 int64 discard_padding) { | 428 int64 discard_padding) { |
| 428 DCHECK_GE(size, 0); | 429 DCHECK_GE(size, 0); |
| 429 if (cluster_timecode_ == -1) { | 430 if (cluster_timecode_ == -1) { |
| 430 MEDIA_LOG(ERROR, log_cb_) << "Got a block before cluster timecode."; | 431 MEDIA_LOG(ERROR, media_log_) << "Got a block before cluster timecode."; |
| 431 return false; | 432 return false; |
| 432 } | 433 } |
| 433 | 434 |
| 434 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or | 435 // TODO(acolwell): Should relative negative timecode offsets be rejected? Or |
| 435 // only when the absolute timecode is negative? See http://crbug.com/271794 | 436 // only when the absolute timecode is negative? See http://crbug.com/271794 |
| 436 if (timecode < 0) { | 437 if (timecode < 0) { |
| 437 MEDIA_LOG(ERROR, log_cb_) << "Got a block with negative timecode offset " | 438 MEDIA_LOG(ERROR, media_log_) << "Got a block with negative timecode offset " |
| 438 << timecode; | 439 << timecode; |
| 439 return false; | 440 return false; |
| 440 } | 441 } |
| 441 | 442 |
| 442 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) { | 443 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) { |
| 443 MEDIA_LOG(ERROR, log_cb_) | 444 MEDIA_LOG(ERROR, media_log_) |
| 444 << "Got a block with a timecode before the previous block."; | 445 << "Got a block with a timecode before the previous block."; |
| 445 return false; | 446 return false; |
| 446 } | 447 } |
| 447 | 448 |
| 448 Track* track = NULL; | 449 Track* track = NULL; |
| 449 StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO; | 450 StreamParserBuffer::Type buffer_type = DemuxerStream::AUDIO; |
| 450 std::string encryption_key_id; | 451 std::string encryption_key_id; |
| 451 base::TimeDelta encoded_duration = kNoTimestamp(); | 452 base::TimeDelta encoded_duration = kNoTimestamp(); |
| 452 if (track_num == audio_.track_num()) { | 453 if (track_num == audio_.track_num()) { |
| 453 track = &audio_; | 454 track = &audio_; |
| 454 encryption_key_id = audio_encryption_key_id_; | 455 encryption_key_id = audio_encryption_key_id_; |
| 455 if (encryption_key_id.empty()) { | 456 if (encryption_key_id.empty()) { |
| 456 encoded_duration = TryGetEncodedAudioDuration(data, size); | 457 encoded_duration = TryGetEncodedAudioDuration(data, size); |
| 457 } | 458 } |
| 458 } else if (track_num == video_.track_num()) { | 459 } else if (track_num == video_.track_num()) { |
| 459 track = &video_; | 460 track = &video_; |
| 460 encryption_key_id = video_encryption_key_id_; | 461 encryption_key_id = video_encryption_key_id_; |
| 461 buffer_type = DemuxerStream::VIDEO; | 462 buffer_type = DemuxerStream::VIDEO; |
| 462 } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) { | 463 } else if (ignored_tracks_.find(track_num) != ignored_tracks_.end()) { |
| 463 return true; | 464 return true; |
| 464 } else if (Track* const text_track = FindTextTrack(track_num)) { | 465 } else if (Track* const text_track = FindTextTrack(track_num)) { |
| 465 if (is_simple_block) // BlockGroup is required for WebVTT cues | 466 if (is_simple_block) // BlockGroup is required for WebVTT cues |
| 466 return false; | 467 return false; |
| 467 if (block_duration < 0) // not specified | 468 if (block_duration < 0) // not specified |
| 468 return false; | 469 return false; |
| 469 track = text_track; | 470 track = text_track; |
| 470 buffer_type = DemuxerStream::TEXT; | 471 buffer_type = DemuxerStream::TEXT; |
| 471 } else { | 472 } else { |
| 472 MEDIA_LOG(ERROR, log_cb_) << "Unexpected track number " << track_num; | 473 MEDIA_LOG(ERROR, media_log_) << "Unexpected track number " << track_num; |
| 473 return false; | 474 return false; |
| 474 } | 475 } |
| 475 | 476 |
| 476 last_block_timecode_ = timecode; | 477 last_block_timecode_ = timecode; |
| 477 | 478 |
| 478 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( | 479 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( |
| 479 (cluster_timecode_ + timecode) * timecode_multiplier_); | 480 (cluster_timecode_ + timecode) * timecode_multiplier_); |
| 480 | 481 |
| 481 scoped_refptr<StreamParserBuffer> buffer; | 482 scoped_refptr<StreamParserBuffer> buffer; |
| 482 if (buffer_type != DemuxerStream::TEXT) { | 483 if (buffer_type != DemuxerStream::TEXT) { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 560 DVLOG(3) << __FUNCTION__ << " : " | 561 DVLOG(3) << __FUNCTION__ << " : " |
| 561 << "Using encoded duration " << encoded_duration.InSecondsF(); | 562 << "Using encoded duration " << encoded_duration.InSecondsF(); |
| 562 | 563 |
| 563 if (block_duration_time_delta != kNoTimestamp()) { | 564 if (block_duration_time_delta != kNoTimestamp()) { |
| 564 base::TimeDelta duration_difference = | 565 base::TimeDelta duration_difference = |
| 565 block_duration_time_delta - encoded_duration; | 566 block_duration_time_delta - encoded_duration; |
| 566 | 567 |
| 567 const auto kWarnDurationDiff = | 568 const auto kWarnDurationDiff = |
| 568 base::TimeDelta::FromMicroseconds(timecode_multiplier_ * 2); | 569 base::TimeDelta::FromMicroseconds(timecode_multiplier_ * 2); |
| 569 if (duration_difference.magnitude() > kWarnDurationDiff) { | 570 if (duration_difference.magnitude() > kWarnDurationDiff) { |
| 570 LIMITED_MEDIA_LOG(DEBUG, log_cb_, num_duration_errors_, | 571 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_duration_errors_, |
| 571 kMaxDurationErrorLogs) | 572 kMaxDurationErrorLogs) |
| 572 << "BlockDuration " | 573 << "BlockDuration " |
| 573 << "(" << block_duration_time_delta << ") " | 574 << "(" << block_duration_time_delta << ") " |
| 574 << "differs significantly from encoded duration " | 575 << "differs significantly from encoded duration " |
| 575 << "(" << encoded_duration << ")."; | 576 << "(" << encoded_duration << ")."; |
| 576 } | 577 } |
| 577 } | 578 } |
| 578 } else if (block_duration_time_delta != kNoTimestamp()) { | 579 } else if (block_duration_time_delta != kNoTimestamp()) { |
| 579 buffer->set_duration(block_duration_time_delta); | 580 buffer->set_duration(block_duration_time_delta); |
| 580 } else { | 581 } else { |
| 581 DCHECK_NE(buffer_type, DemuxerStream::TEXT); | 582 DCHECK_NE(buffer_type, DemuxerStream::TEXT); |
| 582 buffer->set_duration(track->default_duration()); | 583 buffer->set_duration(track->default_duration()); |
| 583 } | 584 } |
| 584 | 585 |
| 585 if (discard_padding != 0) { | 586 if (discard_padding != 0) { |
| 586 buffer->set_discard_padding(std::make_pair( | 587 buffer->set_discard_padding(std::make_pair( |
| 587 base::TimeDelta(), | 588 base::TimeDelta(), |
| 588 base::TimeDelta::FromMicroseconds(discard_padding / 1000))); | 589 base::TimeDelta::FromMicroseconds(discard_padding / 1000))); |
| 589 } | 590 } |
| 590 | 591 |
| 591 return track->AddBuffer(buffer); | 592 return track->AddBuffer(buffer); |
| 592 } | 593 } |
| 593 | 594 |
| 594 WebMClusterParser::Track::Track(int track_num, | 595 WebMClusterParser::Track::Track(int track_num, |
| 595 bool is_video, | 596 bool is_video, |
| 596 base::TimeDelta default_duration, | 597 base::TimeDelta default_duration, |
| 597 const LogCB& log_cb) | 598 const scoped_refptr<MediaLog>& media_log) |
| 598 : num_duration_estimates_(0), | 599 : num_duration_estimates_(0), |
| 599 track_num_(track_num), | 600 track_num_(track_num), |
| 600 is_video_(is_video), | 601 is_video_(is_video), |
| 601 default_duration_(default_duration), | 602 default_duration_(default_duration), |
| 602 estimated_next_frame_duration_(kNoTimestamp()), | 603 estimated_next_frame_duration_(kNoTimestamp()), |
| 603 log_cb_(log_cb) { | 604 media_log_(media_log) { |
| 604 DCHECK(default_duration_ == kNoTimestamp() || | 605 DCHECK(default_duration_ == kNoTimestamp() || |
| 605 default_duration_ > base::TimeDelta()); | 606 default_duration_ > base::TimeDelta()); |
| 606 } | 607 } |
| 607 | 608 |
| 608 WebMClusterParser::Track::~Track() {} | 609 WebMClusterParser::Track::~Track() {} |
| 609 | 610 |
| 610 DecodeTimestamp WebMClusterParser::Track::GetReadyUpperBound() { | 611 DecodeTimestamp WebMClusterParser::Track::GetReadyUpperBound() { |
| 611 DCHECK(ready_buffers_.empty()); | 612 DCHECK(ready_buffers_.empty()); |
| 612 if (last_added_buffer_missing_duration_.get()) | 613 if (last_added_buffer_missing_duration_.get()) |
| 613 return last_added_buffer_missing_duration_->GetDecodeTimestamp(); | 614 return last_added_buffer_missing_duration_->GetDecodeTimestamp(); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 693 last_added_buffer_missing_duration_->set_duration(estimated_duration); | 694 last_added_buffer_missing_duration_->set_duration(estimated_duration); |
| 694 | 695 |
| 695 if (is_video_) { | 696 if (is_video_) { |
| 696 // Exposing estimation so splicing/overlap frame processing can make | 697 // Exposing estimation so splicing/overlap frame processing can make |
| 697 // informed decisions downstream. | 698 // informed decisions downstream. |
| 698 // TODO(chcunningham): Set this for audio as well in later change where | 699 // TODO(chcunningham): Set this for audio as well in later change where |
| 699 // audio is switched to max estimation and splicing is disabled. | 700 // audio is switched to max estimation and splicing is disabled. |
| 700 last_added_buffer_missing_duration_->set_is_duration_estimated(true); | 701 last_added_buffer_missing_duration_->set_is_duration_estimated(true); |
| 701 } | 702 } |
| 702 | 703 |
| 703 LIMITED_MEDIA_LOG(INFO, log_cb_, num_duration_estimates_, | 704 LIMITED_MEDIA_LOG(INFO, media_log_, num_duration_estimates_, |
| 704 kMaxDurationEstimateLogs) | 705 kMaxDurationEstimateLogs) |
| 705 << "Estimating WebM block duration to be " << estimated_duration << " " | 706 << "Estimating WebM block duration to be " << estimated_duration << " " |
| 706 << "for the last (Simple)Block in the Cluster for this Track. Use " | 707 << "for the last (Simple)Block in the Cluster for this Track. Use " |
| 707 << "BlockGroups with BlockDurations at the end of each Track in a " | 708 << "BlockGroups with BlockDurations at the end of each Track in a " |
| 708 << "Cluster to avoid estimation."; | 709 << "Cluster to avoid estimation."; |
| 709 | 710 |
| 710 DVLOG(2) << __FUNCTION__ << " new dur : ts " | 711 DVLOG(2) << __FUNCTION__ << " new dur : ts " |
| 711 << last_added_buffer_missing_duration_->timestamp().InSecondsF() | 712 << last_added_buffer_missing_duration_->timestamp().InSecondsF() |
| 712 << " dur " | 713 << " dur " |
| 713 << last_added_buffer_missing_duration_->duration().InSecondsF() | 714 << last_added_buffer_missing_duration_->duration().InSecondsF() |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 | 762 |
| 762 // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing | 763 // WebMClusterParser::OnBlock() gives MEDIA_LOG and parse error on decreasing |
| 763 // block timecode detection within a cluster. Therefore, we should not see | 764 // block timecode detection within a cluster. Therefore, we should not see |
| 764 // those here. | 765 // those here. |
| 765 DecodeTimestamp previous_buffers_timestamp = buffers_.empty() ? | 766 DecodeTimestamp previous_buffers_timestamp = buffers_.empty() ? |
| 766 DecodeTimestamp() : buffers_.back()->GetDecodeTimestamp(); | 767 DecodeTimestamp() : buffers_.back()->GetDecodeTimestamp(); |
| 767 CHECK(previous_buffers_timestamp <= buffer->GetDecodeTimestamp()); | 768 CHECK(previous_buffers_timestamp <= buffer->GetDecodeTimestamp()); |
| 768 | 769 |
| 769 base::TimeDelta duration = buffer->duration(); | 770 base::TimeDelta duration = buffer->duration(); |
| 770 if (duration < base::TimeDelta() || duration == kNoTimestamp()) { | 771 if (duration < base::TimeDelta() || duration == kNoTimestamp()) { |
| 771 MEDIA_LOG(ERROR, log_cb_) | 772 MEDIA_LOG(ERROR, media_log_) |
| 772 << "Invalid buffer duration: " << duration.InSecondsF(); | 773 << "Invalid buffer duration: " << duration.InSecondsF(); |
| 773 return false; | 774 return false; |
| 774 } | 775 } |
| 775 | 776 |
| 776 // The estimated frame duration is the minimum (for audio) or the maximum | 777 // The estimated frame duration is the minimum (for audio) or the maximum |
| 777 // (for video) non-zero duration since the last initialization segment. The | 778 // (for video) non-zero duration since the last initialization segment. The |
| 778 // minimum is used for audio to ensure frame durations aren't overestimated, | 779 // minimum is used for audio to ensure frame durations aren't overestimated, |
| 779 // triggering unnecessary frame splicing. For video, splicing does not apply, | 780 // triggering unnecessary frame splicing. For video, splicing does not apply, |
| 780 // so maximum is used and overlap is simply resolved by showing the | 781 // so maximum is used and overlap is simply resolved by showing the |
| 781 // later of the overlapping frames at its given PTS, effectively trimming down | 782 // later of the overlapping frames at its given PTS, effectively trimming down |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 WebMClusterParser::FindTextTrack(int track_num) { | 882 WebMClusterParser::FindTextTrack(int track_num) { |
| 882 const TextTrackMap::iterator it = text_track_map_.find(track_num); | 883 const TextTrackMap::iterator it = text_track_map_.find(track_num); |
| 883 | 884 |
| 884 if (it == text_track_map_.end()) | 885 if (it == text_track_map_.end()) |
| 885 return NULL; | 886 return NULL; |
| 886 | 887 |
| 887 return &it->second; | 888 return &it->second; |
| 888 } | 889 } |
| 889 | 890 |
| 890 } // namespace media | 891 } // namespace media |
| OLD | NEW |