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(
58 const InitCB
& init_cb
,
59 const NewConfigCB
& config_cb
,
60 const NewBuffersCB
& new_buffers_cb
,
61 bool ignore_text_tracks
,
62 const EncryptedMediaInitDataCB
& encrypted_media_init_data_cb
,
63 const NewMediaSegmentCB
& new_segment_cb
,
64 const base::Closure
& end_of_segment_cb
,
65 const scoped_refptr
<MediaLog
>& media_log
) {
66 DVLOG(1) << __FUNCTION__
;
67 DCHECK_EQ(state_
, UNINITIALIZED
);
69 config_cb_
= config_cb
;
70 new_buffers_cb_
= new_buffers_cb
;
71 new_segment_cb_
= new_segment_cb
;
72 end_of_segment_cb_
= end_of_segment_cb
;
73 media_log_
= media_log
;
75 ChangeState(INITIALIZED
);
78 void MPEGAudioStreamParserBase::Flush() {
79 DVLOG(1) << __FUNCTION__
;
80 DCHECK_NE(state_
, UNINITIALIZED
);
82 timestamp_helper_
->SetBaseTimestamp(base::TimeDelta());
83 in_media_segment_
= false;
86 bool MPEGAudioStreamParserBase::Parse(const uint8
* buf
, int size
) {
87 DVLOG(1) << __FUNCTION__
<< "(" << size
<< ")";
90 DCHECK_NE(state_
, UNINITIALIZED
);
92 if (state_
== PARSE_ERROR
)
95 DCHECK_EQ(state_
, INITIALIZED
);
97 queue_
.Push(buf
, size
);
99 bool end_of_segment
= true;
104 queue_
.Peek(&data
, &data_size
);
109 uint32 start_code
= data
[0] << 24 | data
[1] << 16 | data
[2] << 8 | data
[3];
111 bool parsed_metadata
= true;
112 if ((start_code
& start_code_mask_
) == start_code_mask_
) {
113 bytes_read
= ParseFrame(data
, data_size
, &buffers
);
115 // Only allow the current segment to end if a full frame has been parsed.
116 end_of_segment
= bytes_read
> 0;
117 parsed_metadata
= false;
118 } else if (start_code
== kICYStartCode
) {
119 bytes_read
= ParseIcecastHeader(data
, data_size
);
120 } else if ((start_code
& kID3StartCodeMask
) == kID3v1StartCode
) {
121 bytes_read
= ParseID3v1(data
, data_size
);
122 } else if ((start_code
& kID3StartCodeMask
) == kID3v2StartCode
) {
123 bytes_read
= ParseID3v2(data
, data_size
);
125 bytes_read
= FindNextValidStartCode(data
, data_size
);
127 if (bytes_read
> 0) {
128 DVLOG(1) << "Unexpected start code 0x" << std::hex
<< start_code
;
129 DVLOG(1) << "SKIPPING " << bytes_read
<< " bytes of garbage.";
133 CHECK_LE(bytes_read
, data_size
);
135 if (bytes_read
< 0) {
136 ChangeState(PARSE_ERROR
);
138 } else if (bytes_read
== 0) {
143 // Send pending buffers if we have encountered metadata.
144 if (parsed_metadata
&& !buffers
.empty() && !SendBuffers(&buffers
, true))
147 queue_
.Pop(bytes_read
);
148 end_of_segment
= true;
154 // Send buffers collected in this append that haven't been sent yet.
155 return SendBuffers(&buffers
, end_of_segment
);
158 void MPEGAudioStreamParserBase::ChangeState(State state
) {
159 DVLOG(1) << __FUNCTION__
<< "() : " << state_
<< " -> " << state
;
163 int MPEGAudioStreamParserBase::ParseFrame(const uint8
* data
,
165 BufferQueue
* buffers
) {
166 DVLOG(2) << __FUNCTION__
<< "(" << size
<< ")";
169 ChannelLayout channel_layout
;
172 bool metadata_frame
= false;
173 int bytes_read
= ParseFrameHeader(data
,
184 // Make sure data contains the entire frame.
185 if (size
< frame_size
)
188 DVLOG(2) << " sample_rate " << sample_rate
189 << " channel_layout " << channel_layout
190 << " frame_size " << frame_size
191 << " sample_count " << sample_count
;
193 if (config_
.IsValidConfig() &&
194 (config_
.samples_per_second() != sample_rate
||
195 config_
.channel_layout() != channel_layout
)) {
196 // Clear config data so that a config change is initiated.
197 config_
= AudioDecoderConfig();
199 // Send all buffers associated with the previous config.
200 if (!buffers
->empty() && !SendBuffers(buffers
, true))
204 if (!config_
.IsValidConfig()) {
205 config_
.Initialize(audio_codec_
,
216 base::TimeDelta base_timestamp
;
217 if (timestamp_helper_
)
218 base_timestamp
= timestamp_helper_
->GetTimestamp();
220 timestamp_helper_
.reset(new AudioTimestampHelper(sample_rate
));
221 timestamp_helper_
->SetBaseTimestamp(base_timestamp
);
223 VideoDecoderConfig video_config
;
224 if (!config_cb_
.Run(config_
, video_config
, TextTrackConfigMap()))
227 if (!init_cb_
.is_null()) {
228 InitParameters
params(kInfiniteDuration());
229 params
.auto_update_timestamp_offset
= true;
230 base::ResetAndReturn(&init_cb_
).Run(params
);
237 // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
238 // type and allow multiple audio tracks, if applicable. See
239 // https://crbug.com/341581.
240 scoped_refptr
<StreamParserBuffer
> buffer
=
241 StreamParserBuffer::CopyFrom(data
, frame_size
, true,
242 DemuxerStream::AUDIO
, 0);
243 buffer
->set_timestamp(timestamp_helper_
->GetTimestamp());
244 buffer
->set_duration(timestamp_helper_
->GetFrameDuration(sample_count
));
245 buffers
->push_back(buffer
);
247 timestamp_helper_
->AddFrames(sample_count
);
252 int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8
* data
, int size
) {
253 DVLOG(1) << __FUNCTION__
<< "(" << size
<< ")";
258 if (memcmp("ICY ", data
, 4))
261 int locate_size
= std::min(size
, kMaxIcecastHeaderSize
);
262 int offset
= LocateEndOfHeaders(data
, locate_size
, 4);
264 if (locate_size
== kMaxIcecastHeaderSize
) {
265 MEDIA_LOG(ERROR
, media_log_
) << "Icecast header is too large.";
275 int MPEGAudioStreamParserBase::ParseID3v1(const uint8
* data
, int size
) {
276 DVLOG(1) << __FUNCTION__
<< "(" << size
<< ")";
278 if (size
< kID3v1Size
)
281 // TODO(acolwell): Add code to actually validate ID3v1 data and
282 // expose it as a metadata text track.
283 return !memcmp(data
, "TAG+", 4) ? kID3v1ExtendedSize
: kID3v1Size
;
286 int MPEGAudioStreamParserBase::ParseID3v2(const uint8
* data
, int size
) {
287 DVLOG(1) << __FUNCTION__
<< "(" << size
<< ")";
292 BitReader
reader(data
, size
);
298 if (!reader
.ReadBits(24, &id
) ||
299 !reader
.ReadBits(16, &version
) ||
300 !reader
.ReadBits(8, &flags
) ||
301 !ParseSyncSafeInt(&reader
, &id3_size
)) {
305 int32 actual_tag_size
= 10 + id3_size
;
307 // Increment size if 'Footer present' flag is set.
309 actual_tag_size
+= 10;
311 // Make sure we have the entire tag.
312 if (size
< actual_tag_size
)
315 // TODO(acolwell): Add code to actually validate ID3v2 data and
316 // expose it as a metadata text track.
317 return actual_tag_size
;
320 bool MPEGAudioStreamParserBase::ParseSyncSafeInt(BitReader
* reader
,
323 for (int i
= 0; i
< 4; ++i
) {
325 if (!reader
->ReadBits(1, &tmp
) || tmp
!= 0) {
326 MEDIA_LOG(ERROR
, media_log_
) << "ID3 syncsafe integer byte MSb is not 0!";
330 if (!reader
->ReadBits(7, &tmp
))
340 int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8
* data
,
342 const uint8
* start
= data
;
343 const uint8
* end
= data
+ size
;
345 while (start
< end
) {
346 int bytes_left
= end
- start
;
347 const uint8
* candidate_start_code
=
348 static_cast<const uint8
*>(memchr(start
, 0xff, bytes_left
));
350 if (!candidate_start_code
)
353 bool parse_header_failed
= false;
354 const uint8
* sync
= candidate_start_code
;
355 // Try to find 3 valid frames in a row. 3 was selected to decrease
356 // the probability of false positives.
357 for (int i
= 0; i
< 3; ++i
) {
358 int sync_size
= end
- sync
;
360 int sync_bytes
= ParseFrameHeader(
361 sync
, sync_size
, &frame_size
, NULL
, NULL
, NULL
, NULL
);
366 if (sync_bytes
> 0) {
367 DCHECK_LT(sync_bytes
, sync_size
);
369 // Skip over this frame so we can check the next one.
372 // Make sure the next frame starts inside the buffer.
376 DVLOG(1) << "ParseFrameHeader() " << i
<< " failed @" << (sync
- data
);
377 parse_header_failed
= true;
382 if (parse_header_failed
) {
383 // One of the frame header parses failed so |candidate_start_code|
384 // did not point to the start of a real frame. Move |start| forward
385 // so we can find the next candidate.
386 start
= candidate_start_code
+ 1;
390 return candidate_start_code
- data
;
396 bool MPEGAudioStreamParserBase::SendBuffers(BufferQueue
* buffers
,
397 bool end_of_segment
) {
398 DCHECK(!buffers
->empty());
400 if (!in_media_segment_
) {
401 in_media_segment_
= true;
402 new_segment_cb_
.Run();
405 BufferQueue empty_video_buffers
;
406 TextBufferQueueMap empty_text_map
;
407 if (!new_buffers_cb_
.Run(*buffers
, empty_video_buffers
, empty_text_map
))
411 if (end_of_segment
) {
412 in_media_segment_
= false;
413 end_of_segment_cb_
.Run();
416 timestamp_helper_
->SetBaseTimestamp(base::TimeDelta());