| 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 |