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

Side by Side Diff: media/webm/webm_cluster_parser.cc

Issue 11471006: Log MediaSource parsing errors to the MediaLog so they can appear in chrome:media-internals. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix nit. Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/webm/webm_cluster_parser.h ('k') | media/webm/webm_cluster_parser_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "media/base/data_buffer.h" 10 #include "media/base/data_buffer.h"
11 #include "media/base/decrypt_config.h" 11 #include "media/base/decrypt_config.h"
12 #include "media/webm/webm_constants.h" 12 #include "media/webm/webm_constants.h"
13 13
14 namespace media { 14 namespace media {
15 15
16 // Generates a 16 byte CTR counter block. The CTR counter block format is a 16 // Generates a 16 byte CTR counter block. The CTR counter block format is a
17 // CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV. 17 // CTR IV appended with a CTR block counter. |iv| is an 8 byte CTR IV.
18 // |iv_size| is the size of |iv| in btyes. Returns a string of 18 // |iv_size| is the size of |iv| in btyes. Returns a string of
19 // kDecryptionKeySize bytes. 19 // kDecryptionKeySize bytes.
20 static std::string GenerateCounterBlock(const uint8* iv, int iv_size) { 20 static std::string GenerateCounterBlock(const uint8* iv, int iv_size) {
21 std::string counter_block(reinterpret_cast<const char*>(iv), iv_size); 21 std::string counter_block(reinterpret_cast<const char*>(iv), iv_size);
22 counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0); 22 counter_block.append(DecryptConfig::kDecryptionKeySize - iv_size, 0);
23 return counter_block; 23 return counter_block;
24 } 24 }
25 25
26 WebMClusterParser::WebMClusterParser(int64 timecode_scale, 26 WebMClusterParser::WebMClusterParser(
27 int audio_track_num, 27 int64 timecode_scale, int audio_track_num, int video_track_num,
28 int video_track_num, 28 const std::string& audio_encryption_key_id,
29 const std::string& audio_encryption_key_id, 29 const std::string& video_encryption_key_id,
30 const std::string& video_encryption_key_id) 30 const LogCB& log_cb)
31 : timecode_multiplier_(timecode_scale / 1000.0), 31 : timecode_multiplier_(timecode_scale / 1000.0),
32 audio_encryption_key_id_(audio_encryption_key_id), 32 audio_encryption_key_id_(audio_encryption_key_id),
33 video_encryption_key_id_(video_encryption_key_id), 33 video_encryption_key_id_(video_encryption_key_id),
34 parser_(kWebMIdCluster, this), 34 parser_(kWebMIdCluster, this),
35 last_block_timecode_(-1), 35 last_block_timecode_(-1),
36 block_data_size_(-1), 36 block_data_size_(-1),
37 block_duration_(-1), 37 block_duration_(-1),
38 cluster_timecode_(-1), 38 cluster_timecode_(-1),
39 cluster_start_time_(kNoTimestamp()), 39 cluster_start_time_(kNoTimestamp()),
40 cluster_ended_(false), 40 cluster_ended_(false),
41 audio_(audio_track_num), 41 audio_(audio_track_num),
42 video_(video_track_num) { 42 video_(video_track_num),
43 log_cb_(log_cb) {
43 } 44 }
44 45
45 WebMClusterParser::~WebMClusterParser() {} 46 WebMClusterParser::~WebMClusterParser() {}
46 47
47 void WebMClusterParser::Reset() { 48 void WebMClusterParser::Reset() {
48 last_block_timecode_ = -1; 49 last_block_timecode_ = -1;
49 cluster_timecode_ = -1; 50 cluster_timecode_ = -1;
50 cluster_start_time_ = kNoTimestamp(); 51 cluster_start_time_ = kNoTimestamp();
51 cluster_ended_ = false; 52 cluster_ended_ = false;
52 parser_.Reset(); 53 parser_.Reset();
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 100
100 return this; 101 return this;
101 } 102 }
102 103
103 bool WebMClusterParser::OnListEnd(int id) { 104 bool WebMClusterParser::OnListEnd(int id) {
104 if (id != kWebMIdBlockGroup) 105 if (id != kWebMIdBlockGroup)
105 return true; 106 return true;
106 107
107 // Make sure the BlockGroup actually had a Block. 108 // Make sure the BlockGroup actually had a Block.
108 if (block_data_size_ == -1) { 109 if (block_data_size_ == -1) {
109 DVLOG(1) << "Block missing from BlockGroup."; 110 MEDIA_LOG(log_cb_) << "Block missing from BlockGroup.";
110 return false; 111 return false;
111 } 112 }
112 113
113 bool result = ParseBlock(block_data_.get(), block_data_size_, 114 bool result = ParseBlock(block_data_.get(), block_data_size_,
114 block_duration_); 115 block_duration_);
115 block_data_.reset(); 116 block_data_.reset();
116 block_data_size_ = -1; 117 block_data_size_ = -1;
117 block_duration_ = -1; 118 block_duration_ = -1;
118 return result; 119 return result;
119 } 120 }
(...skipping 13 matching lines...) Expand all
133 return true; 134 return true;
134 } 135 }
135 136
136 bool WebMClusterParser::ParseBlock(const uint8* buf, int size, int duration) { 137 bool WebMClusterParser::ParseBlock(const uint8* buf, int size, int duration) {
137 if (size < 4) 138 if (size < 4)
138 return false; 139 return false;
139 140
140 // Return an error if the trackNum > 127. We just aren't 141 // Return an error if the trackNum > 127. We just aren't
141 // going to support large track numbers right now. 142 // going to support large track numbers right now.
142 if (!(buf[0] & 0x80)) { 143 if (!(buf[0] & 0x80)) {
143 DVLOG(1) << "TrackNumber over 127 not supported"; 144 MEDIA_LOG(log_cb_) << "TrackNumber over 127 not supported";
144 return false; 145 return false;
145 } 146 }
146 147
147 int track_num = buf[0] & 0x7f; 148 int track_num = buf[0] & 0x7f;
148 int timecode = buf[1] << 8 | buf[2]; 149 int timecode = buf[1] << 8 | buf[2];
149 int flags = buf[3] & 0xff; 150 int flags = buf[3] & 0xff;
150 int lacing = (flags >> 1) & 0x3; 151 int lacing = (flags >> 1) & 0x3;
151 152
152 if (lacing) { 153 if (lacing) {
153 DVLOG(1) << "Lacing " << lacing << " not supported yet."; 154 MEDIA_LOG(log_cb_) << "Lacing " << lacing << " is not supported yet.";
154 return false; 155 return false;
155 } 156 }
156 157
157 // Sign extend negative timecode offsets. 158 // Sign extend negative timecode offsets.
158 if (timecode & 0x8000) 159 if (timecode & 0x8000)
159 timecode |= (-1 << 16); 160 timecode |= (-1 << 16);
160 161
161 const uint8* frame_data = buf + 4; 162 const uint8* frame_data = buf + 4;
162 int frame_size = size - (frame_data - buf); 163 int frame_size = size - (frame_data - buf);
163 return OnBlock(track_num, timecode, duration, flags, frame_data, frame_size); 164 return OnBlock(track_num, timecode, duration, flags, frame_data, frame_size);
164 } 165 }
165 166
166 bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) { 167 bool WebMClusterParser::OnBinary(int id, const uint8* data, int size) {
167 if (id == kWebMIdSimpleBlock) 168 if (id == kWebMIdSimpleBlock)
168 return ParseBlock(data, size, -1); 169 return ParseBlock(data, size, -1);
169 170
170 if (id != kWebMIdBlock) 171 if (id != kWebMIdBlock)
171 return true; 172 return true;
172 173
173 if (block_data_.get()) { 174 if (block_data_.get()) {
174 DVLOG(1) << "More than 1 Block in a BlockGroup is not supported."; 175 MEDIA_LOG(log_cb_) << "More than 1 Block in a BlockGroup is not supported.";
175 return false; 176 return false;
176 } 177 }
177 178
178 block_data_.reset(new uint8[size]); 179 block_data_.reset(new uint8[size]);
179 memcpy(block_data_.get(), data, size); 180 memcpy(block_data_.get(), data, size);
180 block_data_size_ = size; 181 block_data_size_ = size;
181 return true; 182 return true;
182 } 183 }
183 184
184 bool WebMClusterParser::OnBlock(int track_num, int timecode, 185 bool WebMClusterParser::OnBlock(int track_num, int timecode,
185 int block_duration, 186 int block_duration,
186 int flags, 187 int flags,
187 const uint8* data, int size) { 188 const uint8* data, int size) {
188 DCHECK_GE(size, 0); 189 DCHECK_GE(size, 0);
189 if (cluster_timecode_ == -1) { 190 if (cluster_timecode_ == -1) {
190 DVLOG(1) << "Got a block before cluster timecode."; 191 MEDIA_LOG(log_cb_) << "Got a block before cluster timecode.";
191 return false; 192 return false;
192 } 193 }
193 194
194 if (timecode < 0) { 195 if (timecode < 0) {
195 DVLOG(1) << "Got a block with negative timecode offset " << timecode; 196 MEDIA_LOG(log_cb_) << "Got a block with negative timecode offset "
197 << timecode;
196 return false; 198 return false;
197 } 199 }
198 200
199 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) { 201 if (last_block_timecode_ != -1 && timecode < last_block_timecode_) {
200 DVLOG(1) << "Got a block with a timecode before the previous block."; 202 MEDIA_LOG(log_cb_)
203 << "Got a block with a timecode before the previous block.";
201 return false; 204 return false;
202 } 205 }
203 206
204 Track* track = NULL; 207 Track* track = NULL;
205 std::string encryption_key_id; 208 std::string encryption_key_id;
206 if (track_num == audio_.track_num()) { 209 if (track_num == audio_.track_num()) {
207 track = &audio_; 210 track = &audio_;
208 encryption_key_id = audio_encryption_key_id_; 211 encryption_key_id = audio_encryption_key_id_;
209 } else if (track_num == video_.track_num()) { 212 } else if (track_num == video_.track_num()) {
210 track = &video_; 213 track = &video_;
211 encryption_key_id = video_encryption_key_id_; 214 encryption_key_id = video_encryption_key_id_;
212 } else { 215 } else {
213 DVLOG(1) << "Unexpected track number " << track_num; 216 MEDIA_LOG(log_cb_) << "Unexpected track number " << track_num;
214 return false; 217 return false;
215 } 218 }
216 219
217 last_block_timecode_ = timecode; 220 last_block_timecode_ = timecode;
218 221
219 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds( 222 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
220 (cluster_timecode_ + timecode) * timecode_multiplier_); 223 (cluster_timecode_ + timecode) * timecode_multiplier_);
221 224
222 // The first bit of the flags is set when the block contains only keyframes. 225 // The first bit of the flags is set when the block contains only keyframes.
223 // http://www.matroska.org/technical/specs/index.html 226 // http://www.matroska.org/technical/specs/index.html
224 bool is_keyframe = (flags & 0x80) != 0; 227 bool is_keyframe = (flags & 0x80) != 0;
225 scoped_refptr<StreamParserBuffer> buffer = 228 scoped_refptr<StreamParserBuffer> buffer =
226 StreamParserBuffer::CopyFrom(data, size, is_keyframe); 229 StreamParserBuffer::CopyFrom(data, size, is_keyframe);
227 230
228 // Every encrypted Block has a signal byte and IV prepended to it. Current 231 // Every encrypted Block has a signal byte and IV prepended to it. Current
229 // encrypted WebM request for comments specification is here 232 // encrypted WebM request for comments specification is here
230 // http://wiki.webmproject.org/encryption/webm-encryption-rfc 233 // http://wiki.webmproject.org/encryption/webm-encryption-rfc
231 if (!encryption_key_id.empty()) { 234 if (!encryption_key_id.empty()) {
232 DCHECK_EQ(kWebMSignalByteSize, 1); 235 DCHECK_EQ(kWebMSignalByteSize, 1);
233 if (size < kWebMSignalByteSize) { 236 if (size < kWebMSignalByteSize) {
234 DVLOG(1) << "Got a block from an encrypted stream with no data."; 237 MEDIA_LOG(log_cb_)
238 << "Got a block from an encrypted stream with no data.";
235 return false; 239 return false;
236 } 240 }
237 uint8 signal_byte = data[0]; 241 uint8 signal_byte = data[0];
238 int data_offset = sizeof(signal_byte); 242 int data_offset = sizeof(signal_byte);
239 243
240 // Setting the DecryptConfig object of the buffer while leaving the 244 // Setting the DecryptConfig object of the buffer while leaving the
241 // initialization vector empty will tell the decryptor that the frame is 245 // initialization vector empty will tell the decryptor that the frame is
242 // unencrypted. 246 // unencrypted.
243 std::string counter_block; 247 std::string counter_block;
244 248
245 if (signal_byte & kWebMFlagEncryptedFrame) { 249 if (signal_byte & kWebMFlagEncryptedFrame) {
246 if (size < kWebMSignalByteSize + kWebMIvSize) { 250 if (size < kWebMSignalByteSize + kWebMIvSize) {
247 DVLOG(1) << "Got an encrypted block with not enough data " << size; 251 MEDIA_LOG(log_cb_) << "Got an encrypted block with not enough data "
252 << size;
248 return false; 253 return false;
249 } 254 }
250 counter_block = GenerateCounterBlock(data + data_offset, kWebMIvSize); 255 counter_block = GenerateCounterBlock(data + data_offset, kWebMIvSize);
251 data_offset += kWebMIvSize; 256 data_offset += kWebMIvSize;
252 } 257 }
253 258
254 // TODO(fgalligan): Revisit if DecryptConfig needs to be set on unencrypted 259 // TODO(fgalligan): Revisit if DecryptConfig needs to be set on unencrypted
255 // frames after the CDM API is finalized. 260 // frames after the CDM API is finalized.
256 // Unencrypted frames of potentially encrypted streams currently set 261 // Unencrypted frames of potentially encrypted streams currently set
257 // DecryptConfig. 262 // DecryptConfig.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 295
291 buffers_.push_back(buffer); 296 buffers_.push_back(buffer);
292 return true; 297 return true;
293 } 298 }
294 299
295 void WebMClusterParser::Track::Reset() { 300 void WebMClusterParser::Track::Reset() {
296 buffers_.clear(); 301 buffers_.clear();
297 } 302 }
298 303
299 } // namespace media 304 } // namespace media
OLDNEW
« no previous file with comments | « media/webm/webm_cluster_parser.h ('k') | media/webm/webm_cluster_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698