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
3 // found in the LICENSE file.
5 #include "media/formats/mpeg/mpeg_audio_stream_parser_base.h"
8 #include "base/callback_helpers.h"
9 #include "base/message_loop/message_loop.h"
10 #include "media/base/buffers.h"
11 #include "media/base/stream_parser_buffer.h"
12 #include "media/base/text_track_config.h"
13 #include "media/base/video_decoder_config.h"
17 static const uint32 kICYStartCode
= 0x49435920; // 'ICY '
19 // Arbitrary upper bound on the size of an IceCast header before it
21 static const int kMaxIcecastHeaderSize
= 4096;
23 static const uint32 kID3StartCodeMask
= 0xffffff00;
24 static const uint32 kID3v1StartCode
= 0x54414700; // 'TAG\0'
25 static const int kID3v1Size
= 128;
26 static const int kID3v1ExtendedSize
= 227;
27 static const uint32 kID3v2StartCode
= 0x49443300; // 'ID3\0'
29 static int LocateEndOfHeaders(const uint8_t* buf
, int buf_len
, int i
) {
32 for (; i
< buf_len
; ++i
) {
38 } else if (c
!= '\r' || last_c
!= '\n') {
46 MPEGAudioStreamParserBase::MPEGAudioStreamParserBase(uint32 start_code_mask
,
47 AudioCodec audio_codec
,
49 : state_(UNINITIALIZED
),
50 in_media_segment_(false),
51 start_code_mask_(start_code_mask
),
52 audio_codec_(audio_codec
),
53 codec_delay_(codec_delay
) {}
55 MPEGAudioStreamParserBase::~MPEGAudioStreamParserBase() {}
57 void MPEGAudioStreamParserBase::Init(const InitCB
& init_cb
,
58 const NewConfigCB
& config_cb
,
59 const NewBuffersCB
& new_buffers_cb
,
60 bool ignore_text_tracks
,
61 const NeedKeyCB
& need_key_cb
,
62 const NewMediaSegmentCB
& new_segment_cb
,
63 const base::Closure
& end_of_segment_cb
,
64 const LogCB
& log_cb
) {
65 DVLOG(1) << __FUNCTION__
;
66 DCHECK_EQ(state_
, UNINITIALIZED
);
68 config_cb_
= config_cb
;
69 new_buffers_cb_
= new_buffers_cb
;
70 new_segment_cb_
= new_segment_cb
;
71 end_of_segment_cb_
= end_of_segment_cb
;
74 ChangeState(INITIALIZED
);
77 void MPEGAudioStreamParserBase::Flush() {
78 DVLOG(1) << __FUNCTION__
;
79 DCHECK_NE(state_
, UNINITIALIZED
);
81 timestamp_helper_
->SetBaseTimestamp(base::TimeDelta());
82 in_media_segment_
= false;
85 bool MPEGAudioStreamParserBase::Parse(const uint8
* buf
, int size
) {
86 DVLOG(1) << __FUNCTION__
<< "(" << size
<< ")";
89 DCHECK_NE(state_
, UNINITIALIZED
);
91 if (state_
== PARSE_ERROR
)
94 DCHECK_EQ(state_
, INITIALIZED
);
96 queue_
.Push(buf
, size
);
98 bool end_of_segment
= true;
103 queue_
.Peek(&data
, &data_size
);
108 uint32 start_code
= data
[0] << 24 | data
[1] << 16 | data
[2] << 8 | data
[3];
110 bool parsed_metadata
= true;
111 if ((start_code
& start_code_mask_
) == start_code_mask_
) {
112 bytes_read
= ParseFrame(data
, data_size
, &buffers
);
114 // Only allow the current segment to end if a full frame has been parsed.
115 end_of_segment
= bytes_read
> 0;
116 parsed_metadata
= false;
117 } else if (start_code
== kICYStartCode
) {
118 bytes_read
= ParseIcecastHeader(data
, data_size
);
119 } else if ((start_code
& kID3StartCodeMask
) == kID3v1StartCode
) {
120 bytes_read
= ParseID3v1(data
, data_size
);
121 } else if ((start_code
& kID3StartCodeMask
) == kID3v2StartCode
) {
122 bytes_read
= ParseID3v2(data
, data_size
);
124 bytes_read
= FindNextValidStartCode(data
, data_size
);
126 if (bytes_read
> 0) {
127 DVLOG(1) << "Unexpected start code 0x" << std::hex
<< start_code
;
128 DVLOG(1) << "SKIPPING " << bytes_read
<< " bytes of garbage.";
132 CHECK_LE(bytes_read
, data_size
);
134 if (bytes_read
< 0) {
135 ChangeState(PARSE_ERROR
);
137 } else if (bytes_read
== 0) {
142 // Send pending buffers if we have encountered metadata.
143 if (parsed_metadata
&& !buffers
.empty() && !SendBuffers(&buffers
, true))
146 queue_
.Pop(bytes_read
);
147 end_of_segment
= true;
153 // Send buffers collected in this append that haven't been sent yet.
154 return SendBuffers(&buffers
, end_of_segment
);
157 void MPEGAudioStreamParserBase::ChangeState(State state
) {
158 DVLOG(1) << __FUNCTION__
<< "() : " << state_
<< " -> " << state
;
162 int MPEGAudioStreamParserBase::ParseFrame(const uint8
* data
,
164 BufferQueue
* buffers
) {
165 DVLOG(2) << __FUNCTION__
<< "(" << size
<< ")";
168 ChannelLayout channel_layout
;
171 bool metadata_frame
= false;
172 int bytes_read
= ParseFrameHeader(data
,
183 // Make sure data contains the entire frame.
184 if (size
< frame_size
)
187 DVLOG(2) << " sample_rate " << sample_rate
188 << " channel_layout " << channel_layout
189 << " frame_size " << frame_size
190 << " sample_count " << sample_count
;
192 if (config_
.IsValidConfig() &&
193 (config_
.samples_per_second() != sample_rate
||
194 config_
.channel_layout() != channel_layout
)) {
195 // Clear config data so that a config change is initiated.
196 config_
= AudioDecoderConfig();
198 // Send all buffers associated with the previous config.
199 if (!buffers
->empty() && !SendBuffers(buffers
, true))
203 if (!config_
.IsValidConfig()) {
204 config_
.Initialize(audio_codec_
,
215 base::TimeDelta base_timestamp
;
216 if (timestamp_helper_
)
217 base_timestamp
= timestamp_helper_
->GetTimestamp();
219 timestamp_helper_
.reset(new AudioTimestampHelper(sample_rate
));
220 timestamp_helper_
->SetBaseTimestamp(base_timestamp
);
222 VideoDecoderConfig video_config
;
223 bool success
= config_cb_
.Run(config_
, video_config
, TextTrackConfigMap());
225 if (!init_cb_
.is_null()) {
226 InitParameters
params(kInfiniteDuration());
227 params
.auto_update_timestamp_offset
= true;
228 base::ResetAndReturn(&init_cb_
).Run(success
, params
);
238 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
239 // type and allow multiple audio tracks, if applicable. See
240 // https://crbug.com/341581.
241 scoped_refptr
<StreamParserBuffer
> buffer
=
242 StreamParserBuffer::CopyFrom(data
, frame_size
, true,
243 DemuxerStream::AUDIO
, 0);
244 buffer
->set_timestamp(timestamp_helper_
->GetTimestamp());
245 buffer
->set_duration(timestamp_helper_
->GetFrameDuration(sample_count
));
246 buffers
->push_back(buffer
);
248 timestamp_helper_
->AddFrames(sample_count
);
253 int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8
* data
, int size
) {
254 DVLOG(1) << __FUNCTION__
<< "(" << size
<< ")";
259 if (memcmp("ICY ", data
, 4))
262 int locate_size
= std::min(size
, kMaxIcecastHeaderSize
);
263 int offset
= LocateEndOfHeaders(data
, locate_size
, 4);
265 if (locate_size
== kMaxIcecastHeaderSize
) {
266 MEDIA_LOG(log_cb_
) << "Icecast header is too large.";
276 int MPEGAudioStreamParserBase::ParseID3v1(const uint8
* data
, int size
) {
277 DVLOG(1) << __FUNCTION__
<< "(" << size
<< ")";
279 if (size
< kID3v1Size
)
282 // TODO(acolwell): Add code to actually validate ID3v1 data and
283 // expose it as a metadata text track.
284 return !memcmp(data
, "TAG+", 4) ? kID3v1ExtendedSize
: kID3v1Size
;
287 int MPEGAudioStreamParserBase::ParseID3v2(const uint8
* data
, int size
) {
288 DVLOG(1) << __FUNCTION__
<< "(" << size
<< ")";
293 BitReader
reader(data
, size
);
299 if (!reader
.ReadBits(24, &id
) ||
300 !reader
.ReadBits(16, &version
) ||
301 !reader
.ReadBits(8, &flags
) ||
302 !ParseSyncSafeInt(&reader
, &id3_size
)) {
306 int32 actual_tag_size
= 10 + id3_size
;
308 // Increment size if 'Footer present' flag is set.
310 actual_tag_size
+= 10;
312 // Make sure we have the entire tag.
313 if (size
< actual_tag_size
)
316 // TODO(acolwell): Add code to actually validate ID3v2 data and
317 // expose it as a metadata text track.
318 return actual_tag_size
;
321 bool MPEGAudioStreamParserBase::ParseSyncSafeInt(BitReader
* reader
,
324 for (int i
= 0; i
< 4; ++i
) {
326 if (!reader
->ReadBits(1, &tmp
) || tmp
!= 0) {
327 MEDIA_LOG(log_cb_
) << "ID3 syncsafe integer byte MSb is not 0!";
331 if (!reader
->ReadBits(7, &tmp
))
341 int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8
* data
,
343 const uint8
* start
= data
;
344 const uint8
* end
= data
+ size
;
346 while (start
< end
) {
347 int bytes_left
= end
- start
;
348 const uint8
* candidate_start_code
=
349 static_cast<const uint8
*>(memchr(start
, 0xff, bytes_left
));
351 if (!candidate_start_code
)
354 bool parse_header_failed
= false;
355 const uint8
* sync
= candidate_start_code
;
356 // Try to find 3 valid frames in a row. 3 was selected to decrease
357 // the probability of false positives.
358 for (int i
= 0; i
< 3; ++i
) {
359 int sync_size
= end
- sync
;
361 int sync_bytes
= ParseFrameHeader(
362 sync
, sync_size
, &frame_size
, NULL
, NULL
, NULL
, NULL
);
367 if (sync_bytes
> 0) {
368 DCHECK_LT(sync_bytes
, sync_size
);
370 // Skip over this frame so we can check the next one.
373 // Make sure the next frame starts inside the buffer.
377 DVLOG(1) << "ParseFrameHeader() " << i
<< " failed @" << (sync
- data
);
378 parse_header_failed
= true;
383 if (parse_header_failed
) {
384 // One of the frame header parses failed so |candidate_start_code|
385 // did not point to the start of a real frame. Move |start| forward
386 // so we can find the next candidate.
387 start
= candidate_start_code
+ 1;
391 return candidate_start_code
- data
;
397 bool MPEGAudioStreamParserBase::SendBuffers(BufferQueue
* buffers
,
398 bool end_of_segment
) {
399 DCHECK(!buffers
->empty());
401 if (!in_media_segment_
) {
402 in_media_segment_
= true;
403 new_segment_cb_
.Run();
406 BufferQueue empty_video_buffers
;
407 TextBufferQueueMap empty_text_map
;
408 if (!new_buffers_cb_
.Run(*buffers
, empty_video_buffers
, empty_text_map
))
412 if (end_of_segment
) {
413 in_media_segment_
= false;
414 end_of_segment_cb_
.Run();
417 timestamp_helper_
->SetBaseTimestamp(base::TimeDelta());