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/mpeg/mpeg_audio_stream_parser_base.h" | 5 #include "media/formats/mpeg/mpeg_audio_stream_parser_base.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "media/base/stream_parser_buffer.h" | 10 #include "media/base/stream_parser_buffer.h" |
11 #include "media/base/text_track_config.h" | 11 #include "media/base/text_track_config.h" |
12 #include "media/base/timestamp_constants.h" | 12 #include "media/base/timestamp_constants.h" |
13 #include "media/base/video_decoder_config.h" | 13 #include "media/base/video_decoder_config.h" |
14 | 14 |
15 namespace media { | 15 namespace media { |
16 | 16 |
17 static const uint32 kICYStartCode = 0x49435920; // 'ICY ' | 17 static const uint32_t kICYStartCode = 0x49435920; // 'ICY ' |
18 | 18 |
19 // Arbitrary upper bound on the size of an IceCast header before it | 19 // Arbitrary upper bound on the size of an IceCast header before it |
20 // triggers an error. | 20 // triggers an error. |
21 static const int kMaxIcecastHeaderSize = 4096; | 21 static const int kMaxIcecastHeaderSize = 4096; |
22 | 22 |
23 static const uint32 kID3StartCodeMask = 0xffffff00; | 23 static const uint32_t kID3StartCodeMask = 0xffffff00; |
24 static const uint32 kID3v1StartCode = 0x54414700; // 'TAG\0' | 24 static const uint32_t kID3v1StartCode = 0x54414700; // 'TAG\0' |
25 static const int kID3v1Size = 128; | 25 static const int kID3v1Size = 128; |
26 static const int kID3v1ExtendedSize = 227; | 26 static const int kID3v1ExtendedSize = 227; |
27 static const uint32 kID3v2StartCode = 0x49443300; // 'ID3\0' | 27 static const uint32_t kID3v2StartCode = 0x49443300; // 'ID3\0' |
28 | 28 |
29 static int LocateEndOfHeaders(const uint8_t* buf, int buf_len, int i) { | 29 static int LocateEndOfHeaders(const uint8_t* buf, int buf_len, int i) { |
30 bool was_lf = false; | 30 bool was_lf = false; |
31 char last_c = '\0'; | 31 char last_c = '\0'; |
32 for (; i < buf_len; ++i) { | 32 for (; i < buf_len; ++i) { |
33 char c = buf[i]; | 33 char c = buf[i]; |
34 if (c == '\n') { | 34 if (c == '\n') { |
35 if (was_lf) | 35 if (was_lf) |
36 return i + 1; | 36 return i + 1; |
37 was_lf = true; | 37 was_lf = true; |
38 } else if (c != '\r' || last_c != '\n') { | 38 } else if (c != '\r' || last_c != '\n') { |
39 was_lf = false; | 39 was_lf = false; |
40 } | 40 } |
41 last_c = c; | 41 last_c = c; |
42 } | 42 } |
43 return -1; | 43 return -1; |
44 } | 44 } |
45 | 45 |
46 MPEGAudioStreamParserBase::MPEGAudioStreamParserBase(uint32 start_code_mask, | 46 MPEGAudioStreamParserBase::MPEGAudioStreamParserBase(uint32_t start_code_mask, |
47 AudioCodec audio_codec, | 47 AudioCodec audio_codec, |
48 int codec_delay) | 48 int codec_delay) |
49 : state_(UNINITIALIZED), | 49 : state_(UNINITIALIZED), |
50 in_media_segment_(false), | 50 in_media_segment_(false), |
51 start_code_mask_(start_code_mask), | 51 start_code_mask_(start_code_mask), |
52 audio_codec_(audio_codec), | 52 audio_codec_(audio_codec), |
53 codec_delay_(codec_delay) {} | 53 codec_delay_(codec_delay) {} |
54 | 54 |
55 MPEGAudioStreamParserBase::~MPEGAudioStreamParserBase() {} | 55 MPEGAudioStreamParserBase::~MPEGAudioStreamParserBase() {} |
56 | 56 |
(...skipping 20 matching lines...) Expand all Loading... |
77 | 77 |
78 void MPEGAudioStreamParserBase::Flush() { | 78 void MPEGAudioStreamParserBase::Flush() { |
79 DVLOG(1) << __FUNCTION__; | 79 DVLOG(1) << __FUNCTION__; |
80 DCHECK_NE(state_, UNINITIALIZED); | 80 DCHECK_NE(state_, UNINITIALIZED); |
81 queue_.Reset(); | 81 queue_.Reset(); |
82 if (timestamp_helper_) | 82 if (timestamp_helper_) |
83 timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); | 83 timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); |
84 in_media_segment_ = false; | 84 in_media_segment_ = false; |
85 } | 85 } |
86 | 86 |
87 bool MPEGAudioStreamParserBase::Parse(const uint8* buf, int size) { | 87 bool MPEGAudioStreamParserBase::Parse(const uint8_t* buf, int size) { |
88 DVLOG(1) << __FUNCTION__ << "(" << size << ")"; | 88 DVLOG(1) << __FUNCTION__ << "(" << size << ")"; |
89 DCHECK(buf); | 89 DCHECK(buf); |
90 DCHECK_GT(size, 0); | 90 DCHECK_GT(size, 0); |
91 DCHECK_NE(state_, UNINITIALIZED); | 91 DCHECK_NE(state_, UNINITIALIZED); |
92 | 92 |
93 if (state_ == PARSE_ERROR) | 93 if (state_ == PARSE_ERROR) |
94 return false; | 94 return false; |
95 | 95 |
96 DCHECK_EQ(state_, INITIALIZED); | 96 DCHECK_EQ(state_, INITIALIZED); |
97 | 97 |
98 queue_.Push(buf, size); | 98 queue_.Push(buf, size); |
99 | 99 |
100 bool end_of_segment = true; | 100 bool end_of_segment = true; |
101 BufferQueue buffers; | 101 BufferQueue buffers; |
102 for (;;) { | 102 for (;;) { |
103 const uint8* data; | 103 const uint8_t* data; |
104 int data_size; | 104 int data_size; |
105 queue_.Peek(&data, &data_size); | 105 queue_.Peek(&data, &data_size); |
106 | 106 |
107 if (data_size < 4) | 107 if (data_size < 4) |
108 break; | 108 break; |
109 | 109 |
110 uint32 start_code = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; | 110 uint32_t start_code = |
| 111 data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; |
111 int bytes_read = 0; | 112 int bytes_read = 0; |
112 bool parsed_metadata = true; | 113 bool parsed_metadata = true; |
113 if ((start_code & start_code_mask_) == start_code_mask_) { | 114 if ((start_code & start_code_mask_) == start_code_mask_) { |
114 bytes_read = ParseFrame(data, data_size, &buffers); | 115 bytes_read = ParseFrame(data, data_size, &buffers); |
115 | 116 |
116 // Only allow the current segment to end if a full frame has been parsed. | 117 // Only allow the current segment to end if a full frame has been parsed. |
117 end_of_segment = bytes_read > 0; | 118 end_of_segment = bytes_read > 0; |
118 parsed_metadata = false; | 119 parsed_metadata = false; |
119 } else if (start_code == kICYStartCode) { | 120 } else if (start_code == kICYStartCode) { |
120 bytes_read = ParseIcecastHeader(data, data_size); | 121 bytes_read = ParseIcecastHeader(data, data_size); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 | 155 |
155 // Send buffers collected in this append that haven't been sent yet. | 156 // Send buffers collected in this append that haven't been sent yet. |
156 return SendBuffers(&buffers, end_of_segment); | 157 return SendBuffers(&buffers, end_of_segment); |
157 } | 158 } |
158 | 159 |
159 void MPEGAudioStreamParserBase::ChangeState(State state) { | 160 void MPEGAudioStreamParserBase::ChangeState(State state) { |
160 DVLOG(1) << __FUNCTION__ << "() : " << state_ << " -> " << state; | 161 DVLOG(1) << __FUNCTION__ << "() : " << state_ << " -> " << state; |
161 state_ = state; | 162 state_ = state; |
162 } | 163 } |
163 | 164 |
164 int MPEGAudioStreamParserBase::ParseFrame(const uint8* data, | 165 int MPEGAudioStreamParserBase::ParseFrame(const uint8_t* data, |
165 int size, | 166 int size, |
166 BufferQueue* buffers) { | 167 BufferQueue* buffers) { |
167 DVLOG(2) << __FUNCTION__ << "(" << size << ")"; | 168 DVLOG(2) << __FUNCTION__ << "(" << size << ")"; |
168 | 169 |
169 int sample_rate; | 170 int sample_rate; |
170 ChannelLayout channel_layout; | 171 ChannelLayout channel_layout; |
171 int frame_size; | 172 int frame_size; |
172 int sample_count; | 173 int sample_count; |
173 bool metadata_frame = false; | 174 bool metadata_frame = false; |
174 int bytes_read = ParseFrameHeader(data, | 175 int bytes_read = ParseFrameHeader(data, |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 DemuxerStream::AUDIO, 0); | 242 DemuxerStream::AUDIO, 0); |
242 buffer->set_timestamp(timestamp_helper_->GetTimestamp()); | 243 buffer->set_timestamp(timestamp_helper_->GetTimestamp()); |
243 buffer->set_duration(timestamp_helper_->GetFrameDuration(sample_count)); | 244 buffer->set_duration(timestamp_helper_->GetFrameDuration(sample_count)); |
244 buffers->push_back(buffer); | 245 buffers->push_back(buffer); |
245 | 246 |
246 timestamp_helper_->AddFrames(sample_count); | 247 timestamp_helper_->AddFrames(sample_count); |
247 | 248 |
248 return frame_size; | 249 return frame_size; |
249 } | 250 } |
250 | 251 |
251 int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8* data, int size) { | 252 int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8_t* data, |
| 253 int size) { |
252 DVLOG(1) << __FUNCTION__ << "(" << size << ")"; | 254 DVLOG(1) << __FUNCTION__ << "(" << size << ")"; |
253 | 255 |
254 if (size < 4) | 256 if (size < 4) |
255 return 0; | 257 return 0; |
256 | 258 |
257 if (memcmp("ICY ", data, 4)) | 259 if (memcmp("ICY ", data, 4)) |
258 return -1; | 260 return -1; |
259 | 261 |
260 int locate_size = std::min(size, kMaxIcecastHeaderSize); | 262 int locate_size = std::min(size, kMaxIcecastHeaderSize); |
261 int offset = LocateEndOfHeaders(data, locate_size, 4); | 263 int offset = LocateEndOfHeaders(data, locate_size, 4); |
262 if (offset < 0) { | 264 if (offset < 0) { |
263 if (locate_size == kMaxIcecastHeaderSize) { | 265 if (locate_size == kMaxIcecastHeaderSize) { |
264 MEDIA_LOG(ERROR, media_log_) << "Icecast header is too large."; | 266 MEDIA_LOG(ERROR, media_log_) << "Icecast header is too large."; |
265 return -1; | 267 return -1; |
266 } | 268 } |
267 | 269 |
268 return 0; | 270 return 0; |
269 } | 271 } |
270 | 272 |
271 return offset; | 273 return offset; |
272 } | 274 } |
273 | 275 |
274 int MPEGAudioStreamParserBase::ParseID3v1(const uint8* data, int size) { | 276 int MPEGAudioStreamParserBase::ParseID3v1(const uint8_t* data, int size) { |
275 DVLOG(1) << __FUNCTION__ << "(" << size << ")"; | 277 DVLOG(1) << __FUNCTION__ << "(" << size << ")"; |
276 | 278 |
277 if (size < kID3v1Size) | 279 if (size < kID3v1Size) |
278 return 0; | 280 return 0; |
279 | 281 |
280 // TODO(acolwell): Add code to actually validate ID3v1 data and | 282 // TODO(acolwell): Add code to actually validate ID3v1 data and |
281 // expose it as a metadata text track. | 283 // expose it as a metadata text track. |
282 return !memcmp(data, "TAG+", 4) ? kID3v1ExtendedSize : kID3v1Size; | 284 return !memcmp(data, "TAG+", 4) ? kID3v1ExtendedSize : kID3v1Size; |
283 } | 285 } |
284 | 286 |
285 int MPEGAudioStreamParserBase::ParseID3v2(const uint8* data, int size) { | 287 int MPEGAudioStreamParserBase::ParseID3v2(const uint8_t* data, int size) { |
286 DVLOG(1) << __FUNCTION__ << "(" << size << ")"; | 288 DVLOG(1) << __FUNCTION__ << "(" << size << ")"; |
287 | 289 |
288 if (size < 10) | 290 if (size < 10) |
289 return 0; | 291 return 0; |
290 | 292 |
291 BitReader reader(data, size); | 293 BitReader reader(data, size); |
292 int32 id; | 294 int32_t id; |
293 int version; | 295 int version; |
294 uint8 flags; | 296 uint8_t flags; |
295 int32 id3_size; | 297 int32_t id3_size; |
296 | 298 |
297 if (!reader.ReadBits(24, &id) || | 299 if (!reader.ReadBits(24, &id) || |
298 !reader.ReadBits(16, &version) || | 300 !reader.ReadBits(16, &version) || |
299 !reader.ReadBits(8, &flags) || | 301 !reader.ReadBits(8, &flags) || |
300 !ParseSyncSafeInt(&reader, &id3_size)) { | 302 !ParseSyncSafeInt(&reader, &id3_size)) { |
301 return -1; | 303 return -1; |
302 } | 304 } |
303 | 305 |
304 int32 actual_tag_size = 10 + id3_size; | 306 int32_t actual_tag_size = 10 + id3_size; |
305 | 307 |
306 // Increment size if 'Footer present' flag is set. | 308 // Increment size if 'Footer present' flag is set. |
307 if (flags & 0x10) | 309 if (flags & 0x10) |
308 actual_tag_size += 10; | 310 actual_tag_size += 10; |
309 | 311 |
310 // Make sure we have the entire tag. | 312 // Make sure we have the entire tag. |
311 if (size < actual_tag_size) | 313 if (size < actual_tag_size) |
312 return 0; | 314 return 0; |
313 | 315 |
314 // TODO(acolwell): Add code to actually validate ID3v2 data and | 316 // TODO(acolwell): Add code to actually validate ID3v2 data and |
315 // expose it as a metadata text track. | 317 // expose it as a metadata text track. |
316 return actual_tag_size; | 318 return actual_tag_size; |
317 } | 319 } |
318 | 320 |
319 bool MPEGAudioStreamParserBase::ParseSyncSafeInt(BitReader* reader, | 321 bool MPEGAudioStreamParserBase::ParseSyncSafeInt(BitReader* reader, |
320 int32* value) { | 322 int32_t* value) { |
321 *value = 0; | 323 *value = 0; |
322 for (int i = 0; i < 4; ++i) { | 324 for (int i = 0; i < 4; ++i) { |
323 uint8 tmp; | 325 uint8_t tmp; |
324 if (!reader->ReadBits(1, &tmp) || tmp != 0) { | 326 if (!reader->ReadBits(1, &tmp) || tmp != 0) { |
325 MEDIA_LOG(ERROR, media_log_) << "ID3 syncsafe integer byte MSb is not 0!"; | 327 MEDIA_LOG(ERROR, media_log_) << "ID3 syncsafe integer byte MSb is not 0!"; |
326 return false; | 328 return false; |
327 } | 329 } |
328 | 330 |
329 if (!reader->ReadBits(7, &tmp)) | 331 if (!reader->ReadBits(7, &tmp)) |
330 return false; | 332 return false; |
331 | 333 |
332 *value <<= 7; | 334 *value <<= 7; |
333 *value += tmp; | 335 *value += tmp; |
334 } | 336 } |
335 | 337 |
336 return true; | 338 return true; |
337 } | 339 } |
338 | 340 |
339 int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8* data, | 341 int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8_t* data, |
340 int size) const { | 342 int size) const { |
341 const uint8* start = data; | 343 const uint8_t* start = data; |
342 const uint8* end = data + size; | 344 const uint8_t* end = data + size; |
343 | 345 |
344 while (start < end) { | 346 while (start < end) { |
345 int bytes_left = end - start; | 347 int bytes_left = end - start; |
346 const uint8* candidate_start_code = | 348 const uint8_t* candidate_start_code = |
347 static_cast<const uint8*>(memchr(start, 0xff, bytes_left)); | 349 static_cast<const uint8_t*>(memchr(start, 0xff, bytes_left)); |
348 | 350 |
349 if (!candidate_start_code) | 351 if (!candidate_start_code) |
350 return 0; | 352 return 0; |
351 | 353 |
352 bool parse_header_failed = false; | 354 bool parse_header_failed = false; |
353 const uint8* sync = candidate_start_code; | 355 const uint8_t* sync = candidate_start_code; |
354 // Try to find 3 valid frames in a row. 3 was selected to decrease | 356 // Try to find 3 valid frames in a row. 3 was selected to decrease |
355 // the probability of false positives. | 357 // the probability of false positives. |
356 for (int i = 0; i < 3; ++i) { | 358 for (int i = 0; i < 3; ++i) { |
357 int sync_size = end - sync; | 359 int sync_size = end - sync; |
358 int frame_size; | 360 int frame_size; |
359 int sync_bytes = ParseFrameHeader( | 361 int sync_bytes = ParseFrameHeader( |
360 sync, sync_size, &frame_size, NULL, NULL, NULL, NULL); | 362 sync, sync_size, &frame_size, NULL, NULL, NULL, NULL); |
361 | 363 |
362 if (sync_bytes == 0) | 364 if (sync_bytes == 0) |
363 return 0; | 365 return 0; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 if (end_of_segment) { | 412 if (end_of_segment) { |
411 in_media_segment_ = false; | 413 in_media_segment_ = false; |
412 end_of_segment_cb_.Run(); | 414 end_of_segment_cb_.Run(); |
413 } | 415 } |
414 | 416 |
415 timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); | 417 timestamp_helper_->SetBaseTimestamp(base::TimeDelta()); |
416 return true; | 418 return true; |
417 } | 419 } |
418 | 420 |
419 } // namespace media | 421 } // namespace media |
OLD | NEW |