| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/webm/webm_cluster_parser.h" | 5 #include "media/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 "media/base/buffers.h" | 11 #include "media/base/buffers.h" |
| 11 #include "media/base/decrypt_config.h" | 12 #include "media/base/decrypt_config.h" |
| 12 #include "media/webm/webm_constants.h" | 13 #include "media/webm/webm_constants.h" |
| 13 #include "media/webm/webm_crypto_helpers.h" | 14 #include "media/webm/webm_crypto_helpers.h" |
| 14 | 15 |
| 15 namespace media { | 16 namespace media { |
| 16 | 17 |
| 17 WebMClusterParser::TextTrackIterator::TextTrackIterator( | 18 WebMClusterParser::TextTrackIterator::TextTrackIterator( |
| 18 const TextTrackMap& text_track_map) : | 19 const TextTrackMap& text_track_map) : |
| 19 iterator_(text_track_map.begin()), | 20 iterator_(text_track_map.begin()), |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 const std::string& video_encryption_key_id, | 55 const std::string& video_encryption_key_id, |
| 55 const LogCB& log_cb) | 56 const LogCB& log_cb) |
| 56 : timecode_multiplier_(timecode_scale / 1000.0), | 57 : timecode_multiplier_(timecode_scale / 1000.0), |
| 57 ignored_tracks_(ignored_tracks), | 58 ignored_tracks_(ignored_tracks), |
| 58 audio_encryption_key_id_(audio_encryption_key_id), | 59 audio_encryption_key_id_(audio_encryption_key_id), |
| 59 video_encryption_key_id_(video_encryption_key_id), | 60 video_encryption_key_id_(video_encryption_key_id), |
| 60 parser_(kWebMIdCluster, this), | 61 parser_(kWebMIdCluster, this), |
| 61 last_block_timecode_(-1), | 62 last_block_timecode_(-1), |
| 62 block_data_size_(-1), | 63 block_data_size_(-1), |
| 63 block_duration_(-1), | 64 block_duration_(-1), |
| 65 block_add_id_(-1), |
| 66 block_additional_data_size_(-1), |
| 64 cluster_timecode_(-1), | 67 cluster_timecode_(-1), |
| 65 cluster_start_time_(kNoTimestamp()), | 68 cluster_start_time_(kNoTimestamp()), |
| 66 cluster_ended_(false), | 69 cluster_ended_(false), |
| 67 audio_(audio_track_num, false), | 70 audio_(audio_track_num, false), |
| 68 video_(video_track_num, true), | 71 video_(video_track_num, true), |
| 69 log_cb_(log_cb) { | 72 log_cb_(log_cb) { |
| 70 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); | 73 for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin(); |
| 71 it != text_tracks.end(); | 74 it != text_tracks.end(); |
| 72 ++it) { | 75 ++it) { |
| 73 text_track_map_.insert(std::make_pair(it->first, Track(it->first, false))); | 76 text_track_map_.insert(std::make_pair(it->first, Track(it->first, false))); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 } | 130 } |
| 128 | 131 |
| 129 WebMParserClient* WebMClusterParser::OnListStart(int id) { | 132 WebMParserClient* WebMClusterParser::OnListStart(int id) { |
| 130 if (id == kWebMIdCluster) { | 133 if (id == kWebMIdCluster) { |
| 131 cluster_timecode_ = -1; | 134 cluster_timecode_ = -1; |
| 132 cluster_start_time_ = kNoTimestamp(); | 135 cluster_start_time_ = kNoTimestamp(); |
| 133 } else if (id == kWebMIdBlockGroup) { | 136 } else if (id == kWebMIdBlockGroup) { |
| 134 block_data_.reset(); | 137 block_data_.reset(); |
| 135 block_data_size_ = -1; | 138 block_data_size_ = -1; |
| 136 block_duration_ = -1; | 139 block_duration_ = -1; |
| 140 } else if (id == kWebMIdBlockAdditions) { |
| 141 block_add_id_ = -1; |
| 142 block_additional_data_.reset(); |
| 143 block_additional_data_size_ = -1; |
| 137 } | 144 } |
| 138 | 145 |
| 139 return this; | 146 return this; |
| 140 } | 147 } |
| 141 | 148 |
| 142 bool WebMClusterParser::OnListEnd(int id) { | 149 bool WebMClusterParser::OnListEnd(int id) { |
| 143 if (id != kWebMIdBlockGroup) | 150 if (id != kWebMIdBlockGroup) |
| 144 return true; | 151 return true; |
| 145 | 152 |
| 146 // Make sure the BlockGroup actually had a Block. | 153 // Make sure the BlockGroup actually had a Block. |
| 147 if (block_data_size_ == -1) { | 154 if (block_data_size_ == -1) { |
| 148 MEDIA_LOG(log_cb_) << "Block missing from BlockGroup."; | 155 MEDIA_LOG(log_cb_) << "Block missing from BlockGroup."; |
| 149 return false; | 156 return false; |
| 150 } | 157 } |
| 151 | 158 |
| 152 bool result = ParseBlock(false, block_data_.get(), block_data_size_, | 159 bool result = ParseBlock(false, block_data_.get(), block_data_size_, |
| 153 block_duration_); | 160 block_additional_data_.get(), |
| 161 block_additional_data_size_, block_duration_); |
| 154 block_data_.reset(); | 162 block_data_.reset(); |
| 155 block_data_size_ = -1; | 163 block_data_size_ = -1; |
| 156 block_duration_ = -1; | 164 block_duration_ = -1; |
| 165 block_add_id_ = -1; |
| 166 block_additional_data_.reset(); |
| 167 block_additional_data_size_ = -1; |
| 157 return result; | 168 return result; |
| 158 } | 169 } |
| 159 | 170 |
| 160 bool WebMClusterParser::OnUInt(int id, int64 val) { | 171 bool WebMClusterParser::OnUInt(int id, int64 val) { |
| 161 if (id == kWebMIdTimecode) { | 172 int64* dst; |
| 162 if (cluster_timecode_ != -1) | 173 switch (id) { |
| 163 return false; | 174 case kWebMIdTimecode: |
| 164 | 175 dst = &cluster_timecode_; |
| 165 cluster_timecode_ = val; | 176 break; |
| 166 } else if (id == kWebMIdBlockDuration) { | 177 case kWebMIdBlockDuration: |
| 167 if (block_duration_ != -1) | 178 dst = &block_duration_; |
| 168 return false; | 179 break; |
| 169 block_duration_ = val; | 180 case kWebMIdBlockAddID: |
| 181 dst = &block_add_id_; |
| 182 break; |
| 183 default: |
| 184 return true; |
| 170 } | 185 } |
| 171 | 186 if (*dst != -1) |
| 187 return false; |
| 188 *dst = val; |
| 172 return true; | 189 return true; |
| 173 } | 190 } |
| 174 | 191 |
| 175 bool WebMClusterParser::ParseBlock(bool is_simple_block, const uint8* buf, | 192 bool WebMClusterParser::ParseBlock(bool is_simple_block, const uint8* buf, |
| 176 int size, int duration) { | 193 int size, const uint8* additional, |
| 194 int additional_size, int duration) { |
| 177 if (size < 4) | 195 if (size < 4) |
| 178 return false; | 196 return false; |
| 179 | 197 |
| 180 // Return an error if the trackNum > 127. We just aren't | 198 // Return an error if the trackNum > 127. We just aren't |
| 181 // going to support large track numbers right now. | 199 // going to support large track numbers right now. |
| 182 if (!(buf[0] & 0x80)) { | 200 if (!(buf[0] & 0x80)) { |
| 183 MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported"; | 201 MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported"; |
| 184 return false; | 202 return false; |
| 185 } | 203 } |
| 186 | 204 |
| 187 int track_num = buf[0] & 0x7f; | 205 int track_num = buf[0] & 0x7f; |
| 188 int timecode = buf[1] << 8 | buf[2]; | 206 int timecode = buf[1] << 8 | buf[2]; |
| 189 int flags = buf[3] & 0xff; | 207 int flags = buf[3] & 0xff; |
| 190 int lacing = (flags >> 1) & 0x3; | 208 int lacing = (flags >> 1) & 0x3; |
| 191 | 209 |
| 192 if (lacing) { | 210 if (lacing) { |
| 193 MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet."; | 211 MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet."; |
| 194 return false; | 212 return false; |
| 195 } | 213 } |
| 196 | 214 |
| 197 // Sign extend negative timecode offsets. | 215 // Sign extend negative timecode offsets. |
| 198 if (timecode & 0x8000) | 216 if (timecode & 0x8000) |
| 199 timecode |= (-1 << 16); | 217 timecode |= (-1 << 16); |
| 200 | 218 |
| 201 const uint8* frame_data = buf + 4; | 219 const uint8* frame_data = buf + 4; |
| 202 int frame_size = size - (frame_data - buf); | 220 int frame_size = size - (frame_data - buf); |
| 203 return OnBlock(is_simple_block, track_num, timecode, duration, flags, | 221 return OnBlock(is_simple_block, track_num, timecode, duration, flags, |
| 204 frame_data, frame_size); | 222 frame_data, frame_size, additional, additional_size); |
| 205 } | 223 } |
| 206 | 224 |
| 207 bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) { | 225 bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) { |
| 208 if (id == kWebMIdSimpleBlock) | 226 switch (id) { |
| 209 return ParseBlock(true, data, size, -1); | 227 case kWebMIdSimpleBlock: |
| 228 return ParseBlock(true, data, size, NULL, -1, -1); |
| 210 | 229 |
| 211 if (id != kWebMIdBlock) | 230 case kWebMIdBlock: |
| 212 return true; | 231 if (block_data_) { |
| 232 MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not " |
| 233 "supported."; |
| 234 return false; |
| 235 } |
| 236 block_data_.reset(new uint8[size]); |
| 237 memcpy(block_data_.get(), data, size); |
| 238 block_data_size_ = size; |
| 239 return true; |
| 213 | 240 |
| 214 if (block_data_) { | 241 case kWebMIdBlockAdditional: { |
| 215 MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not supported."; | 242 uint64 block_add_id = base::HostToNet64(block_add_id_); |
| 216 return false; | 243 if (block_additional_data_) { |
| 244 // TODO(vigneshv): Technically, more than 1 BlockAdditional is allowed |
| 245 // as per matroska spec. But for now we don't have a use case to |
| 246 // support parsing of such files. Take a look at this again when such a |
| 247 // case arises. |
| 248 MEDIA_LOG(log_cb_) << "More than 1 BlockAdditional in a BlockGroup is " |
| 249 "not supported."; |
| 250 return false; |
| 251 } |
| 252 // First 8 bytes of side_data in DecoderBuffer is the BlockAddID |
| 253 // element's value in Big Endian format. This is done to mimic ffmpeg |
| 254 // demuxer's behavior. |
| 255 block_additional_data_size_ = size + sizeof(block_add_id); |
| 256 block_additional_data_.reset(new uint8[block_additional_data_size_]); |
| 257 memcpy(block_additional_data_.get(), &block_add_id, |
| 258 sizeof(block_add_id)); |
| 259 memcpy(block_additional_data_.get() + 8, data, size); |
| 260 return true; |
| 261 } |
| 262 |
| 263 default: |
| 264 return true; |
| 217 } | 265 } |
| 218 | |
| 219 block_data_.reset(new uint8[size]); | |
| 220 memcpy(block_data_.get(), data, size); | |
| 221 block_data_size_ = size; | |
| 222 return true; | |
| 223 } | 266 } |
| 224 | 267 |
| 225 bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num, | 268 bool WebMClusterParser::OnBlock(bool is_simple_block, int track_num, |
| 226 int timecode, | 269 int timecode, |
| 227 int block_duration, | 270 int block_duration, |
| 228 int flags, | 271 int flags, |
| 229 const uint8* data, int size) { | 272 const uint8* data, int size, |
| 273 const uint8* additional, int additional_size) { |
| 230 DCHECK_GE(size, 0); | 274 DCHECK_GE(size, 0); |
| 231 if (cluster_timecode_ == -1) { | 275 if (cluster_timecode_ == -1) { |
| 232 MEDIA_LOG(log_cb_) << "Got a block before cluster timecode."; | 276 MEDIA_LOG(log_cb_) << "Got a block before cluster timecode."; |
| 233 return false; | 277 return false; |
| 234 } | 278 } |
| 235 | 279 |
| 236 if (timecode < 0) { | 280 if (timecode < 0) { |
| 237 MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset " | 281 MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset " |
| 238 << timecode; | 282 << timecode; |
| 239 return false; | 283 return false; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 272 (cluster_timecode_ + timecode) * timecode_multiplier_); | 316 (cluster_timecode_ + timecode) * timecode_multiplier_); |
| 273 | 317 |
| 274 // The first bit of the flags is set when a SimpleBlock contains only | 318 // The first bit of the flags is set when a SimpleBlock contains only |
| 275 // keyframes. If this is a Block, then inspection of the payload is | 319 // keyframes. If this is a Block, then inspection of the payload is |
| 276 // necessary to determine whether it contains a keyframe or not. | 320 // necessary to determine whether it contains a keyframe or not. |
| 277 // http://www.matroska.org/technical/specs/index.html | 321 // http://www.matroska.org/technical/specs/index.html |
| 278 bool is_keyframe = | 322 bool is_keyframe = |
| 279 is_simple_block ? (flags & 0x80) != 0 : track->IsKeyframe(data, size); | 323 is_simple_block ? (flags & 0x80) != 0 : track->IsKeyframe(data, size); |
| 280 | 324 |
| 281 scoped_refptr<StreamParserBuffer> buffer = | 325 scoped_refptr<StreamParserBuffer> buffer = |
| 282 StreamParserBuffer::CopyFrom(data, size, is_keyframe); | 326 StreamParserBuffer::CopyFrom(data, size, additional, additional_size, |
| 327 is_keyframe); |
| 283 | 328 |
| 284 // Every encrypted Block has a signal byte and IV prepended to it. Current | 329 // Every encrypted Block has a signal byte and IV prepended to it. Current |
| 285 // encrypted WebM request for comments specification is here | 330 // encrypted WebM request for comments specification is here |
| 286 // http://wiki.webmproject.org/encryption/webm-encryption-rfc | 331 // http://wiki.webmproject.org/encryption/webm-encryption-rfc |
| 287 if (!encryption_key_id.empty()) { | 332 if (!encryption_key_id.empty()) { |
| 288 scoped_ptr<DecryptConfig> config(WebMCreateDecryptConfig( | 333 scoped_ptr<DecryptConfig> config(WebMCreateDecryptConfig( |
| 289 data, size, | 334 data, size, |
| 290 reinterpret_cast<const uint8*>(encryption_key_id.data()), | 335 reinterpret_cast<const uint8*>(encryption_key_id.data()), |
| 291 encryption_key_id.size())); | 336 encryption_key_id.size())); |
| 292 if (!config) | 337 if (!config) |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 WebMClusterParser::FindTextTrack(int track_num) { | 409 WebMClusterParser::FindTextTrack(int track_num) { |
| 365 const TextTrackMap::iterator it = text_track_map_.find(track_num); | 410 const TextTrackMap::iterator it = text_track_map_.find(track_num); |
| 366 | 411 |
| 367 if (it == text_track_map_.end()) | 412 if (it == text_track_map_.end()) |
| 368 return NULL; | 413 return NULL; |
| 369 | 414 |
| 370 return &it->second; | 415 return &it->second; |
| 371 } | 416 } |
| 372 | 417 |
| 373 } // namespace media | 418 } // namespace media |
| OLD | NEW |