Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/formats/webm/webm_cluster_parser.h" | 5 #include "media/formats/webm/webm_cluster_parser.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/sys_byteorder.h" | 10 #include "base/sys_byteorder.h" |
| 11 #include "media/base/buffers.h" | 11 #include "media/base/buffers.h" |
| 12 #include "media/base/decrypt_config.h" | 12 #include "media/base/decrypt_config.h" |
| 13 #include "media/filters/webvtt_util.h" | 13 #include "media/filters/webvtt_util.h" |
| 14 #include "media/formats/webm/webm_constants.h" | 14 #include "media/formats/webm/webm_constants.h" |
| 15 #include "media/formats/webm/webm_crypto_helpers.h" | 15 #include "media/formats/webm/webm_crypto_helpers.h" |
| 16 #include "media/formats/webm/webm_webvtt_parser.h" | 16 #include "media/formats/webm/webm_webvtt_parser.h" |
| 17 | 17 |
| 18 namespace media { | 18 namespace media { |
| 19 | 19 |
| 20 const uint16_t WebMClusterParser::kOpusFrameDurationsMu[] = { | |
| 21 10000, 20000, 40000, 60000, 10000, 20000, 40000, 60000, 10000, 20000, 40000, | |
| 22 60000, 10000, 20000, 10000, 20000, 2500, 5000, 10000, 20000, 2500, 5000, | |
| 23 10000, 20000, 2500, 5000, 10000, 20000, 2500, 5000, 10000, 20000}; | |
| 24 | |
| 25 enum { | |
| 26 // Limits the number of MEDIA_LOG() calls in the path of reading encoded | |
| 27 // duration to avoid spamming for corrupted data. | |
| 28 kMaxDurationLogs = 10, | |
| 29 }; | |
| 30 | |
| 20 WebMClusterParser::WebMClusterParser( | 31 WebMClusterParser::WebMClusterParser( |
| 21 int64 timecode_scale, | 32 int64 timecode_scale, |
| 22 int audio_track_num, | 33 int audio_track_num, |
| 23 base::TimeDelta audio_default_duration, | 34 base::TimeDelta audio_default_duration, |
| 24 int video_track_num, | 35 int video_track_num, |
| 25 base::TimeDelta video_default_duration, | 36 base::TimeDelta video_default_duration, |
| 26 const WebMTracksParser::TextTracks& text_tracks, | 37 const WebMTracksParser::TextTracks& text_tracks, |
| 27 const std::set<int64>& ignored_tracks, | 38 const std::set<int64>& ignored_tracks, |
| 28 const std::string& audio_encryption_key_id, | 39 const std::string& audio_encryption_key_id, |
| 29 const std::string& video_encryption_key_id, | 40 const std::string& video_encryption_key_id, |
| 41 const AudioCodec audio_codec, | |
| 30 const LogCB& log_cb) | 42 const LogCB& log_cb) |
| 31 : timecode_multiplier_(timecode_scale / 1000.0), | 43 : num_duration_errors_(0), |
| 44 timecode_multiplier_(timecode_scale / 1000.0), | |
| 32 ignored_tracks_(ignored_tracks), | 45 ignored_tracks_(ignored_tracks), |
| 33 audio_encryption_key_id_(audio_encryption_key_id), | 46 audio_encryption_key_id_(audio_encryption_key_id), |
| 34 video_encryption_key_id_(video_encryption_key_id), | 47 video_encryption_key_id_(video_encryption_key_id), |
| 48 audio_codec_(audio_codec), | |
| 35 parser_(kWebMIdCluster, this), | 49 parser_(kWebMIdCluster, this), |
| 36 last_block_timecode_(-1), | 50 last_block_timecode_(-1), |
| 37 block_data_size_(-1), | 51 block_data_size_(-1), |
| 38 block_duration_(-1), | 52 block_duration_(-1), |
| 39 block_add_id_(-1), | 53 block_add_id_(-1), |
| 40 block_additional_data_size_(0), | 54 block_additional_data_size_(0), |
| 41 discard_padding_(-1), | 55 discard_padding_(-1), |
| 42 cluster_timecode_(-1), | 56 cluster_timecode_(-1), |
| 43 cluster_start_time_(kNoTimestamp()), | 57 cluster_start_time_(kNoTimestamp()), |
| 44 cluster_ended_(false), | 58 cluster_ended_(false), |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 61 cluster_timecode_ = -1; | 75 cluster_timecode_ = -1; |
| 62 cluster_start_time_ = kNoTimestamp(); | 76 cluster_start_time_ = kNoTimestamp(); |
| 63 cluster_ended_ = false; | 77 cluster_ended_ = false; |
| 64 parser_.Reset(); | 78 parser_.Reset(); |
| 65 audio_.Reset(); | 79 audio_.Reset(); |
| 66 video_.Reset(); | 80 video_.Reset(); |
| 67 ResetTextTracks(); | 81 ResetTextTracks(); |
| 68 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); | 82 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); |
| 69 } | 83 } |
| 70 | 84 |
| 71 int WebMClusterParser::Parse(const uint8* buf, int size) { | 85 int WebMClusterParser::Parse(const uint8_t* buf, int size) { |
| 72 audio_.ClearReadyBuffers(); | 86 audio_.ClearReadyBuffers(); |
| 73 video_.ClearReadyBuffers(); | 87 video_.ClearReadyBuffers(); |
| 74 ClearTextTrackReadyBuffers(); | 88 ClearTextTrackReadyBuffers(); |
| 75 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); | 89 ready_buffer_upper_bound_ = kNoDecodeTimestamp(); |
| 76 | 90 |
| 77 int result = parser_.Parse(buf, size); | 91 int result = parser_.Parse(buf, size); |
| 78 | 92 |
| 79 if (result < 0) { | 93 if (result < 0) { |
| 80 cluster_ended_ = false; | 94 cluster_ended_ = false; |
| 81 return result; | 95 return result; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 itr != text_track_map_.end(); | 147 itr != text_track_map_.end(); |
| 134 ++itr) { | 148 ++itr) { |
| 135 const BufferQueue& text_buffers = itr->second.ready_buffers(); | 149 const BufferQueue& text_buffers = itr->second.ready_buffers(); |
| 136 if (!text_buffers.empty()) | 150 if (!text_buffers.empty()) |
| 137 text_buffers_map_.insert(std::make_pair(itr->first, text_buffers)); | 151 text_buffers_map_.insert(std::make_pair(itr->first, text_buffers)); |
| 138 } | 152 } |
| 139 | 153 |
| 140 return text_buffers_map_; | 154 return text_buffers_map_; |
| 141 } | 155 } |
| 142 | 156 |
| 157 base::TimeDelta WebMClusterParser::TryGetEncodedAudioDuration( | |
| 158 const uint8_t* data, | |
| 159 int size) { | |
| 160 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |