Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / media / formats / mpeg / mpeg_audio_stream_parser_base.cc
blobc79724d6fdc2490c631a14a24bb562559c76b12c
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"
7 #include "base/bind.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"
15 namespace media {
17 static const uint32 kICYStartCode = 0x49435920; // 'ICY '
19 // Arbitrary upper bound on the size of an IceCast header before it
20 // triggers an error.
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) {
30 bool was_lf = false;
31 char last_c = '\0';
32 for (; i < buf_len; ++i) {
33 char c = buf[i];
34 if (c == '\n') {
35 if (was_lf)
36 return i + 1;
37 was_lf = true;
38 } else if (c != '\r' || last_c != '\n') {
39 was_lf = false;
41 last_c = c;
43 return -1;
46 MPEGAudioStreamParserBase::MPEGAudioStreamParserBase(uint32 start_code_mask,
47 AudioCodec audio_codec,
48 int codec_delay)
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);
68 init_cb_ = init_cb;
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);
81 queue_.Reset();
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 << ")";
88 DCHECK(buf);
89 DCHECK_GT(size, 0);
90 DCHECK_NE(state_, UNINITIALIZED);
92 if (state_ == PARSE_ERROR)
93 return false;
95 DCHECK_EQ(state_, INITIALIZED);
97 queue_.Push(buf, size);
99 bool end_of_segment = true;
100 BufferQueue buffers;
101 for (;;) {
102 const uint8* data;
103 int data_size;
104 queue_.Peek(&data, &data_size);
106 if (data_size < 4)
107 break;
109 uint32 start_code = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
110 int bytes_read = 0;
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);
124 } else {
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);
137 return false;
138 } else if (bytes_read == 0) {
139 // Need more data.
140 break;
143 // Send pending buffers if we have encountered metadata.
144 if (parsed_metadata && !buffers.empty() && !SendBuffers(&buffers, true))
145 return false;
147 queue_.Pop(bytes_read);
148 end_of_segment = true;
151 if (buffers.empty())
152 return 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;
160 state_ = state;
163 int MPEGAudioStreamParserBase::ParseFrame(const uint8* data,
164 int size,
165 BufferQueue* buffers) {
166 DVLOG(2) << __FUNCTION__ << "(" << size << ")";
168 int sample_rate;
169 ChannelLayout channel_layout;
170 int frame_size;
171 int sample_count;
172 bool metadata_frame = false;
173 int bytes_read = ParseFrameHeader(data,
174 size,
175 &frame_size,
176 &sample_rate,
177 &channel_layout,
178 &sample_count,
179 &metadata_frame);
181 if (bytes_read <= 0)
182 return bytes_read;
184 // Make sure data contains the entire frame.
185 if (size < frame_size)
186 return 0;
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))
201 return -1;
204 if (!config_.IsValidConfig()) {
205 config_.Initialize(audio_codec_,
206 kSampleFormatF32,
207 channel_layout,
208 sample_rate,
209 NULL,
211 false,
212 false,
213 base::TimeDelta(),
214 codec_delay_);
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()))
225 return -1;
227 if (!init_cb_.is_null()) {
228 InitParameters params(kInfiniteDuration());
229 params.auto_update_timestamp_offset = true;
230 base::ResetAndReturn(&init_cb_).Run(params);
234 if (metadata_frame)
235 return frame_size;
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);
249 return frame_size;
252 int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8* data, int size) {
253 DVLOG(1) << __FUNCTION__ << "(" << size << ")";
255 if (size < 4)
256 return 0;
258 if (memcmp("ICY ", data, 4))
259 return -1;
261 int locate_size = std::min(size, kMaxIcecastHeaderSize);
262 int offset = LocateEndOfHeaders(data, locate_size, 4);
263 if (offset < 0) {
264 if (locate_size == kMaxIcecastHeaderSize) {
265 MEDIA_LOG(ERROR, media_log_) << "Icecast header is too large.";
266 return -1;
269 return 0;
272 return offset;
275 int MPEGAudioStreamParserBase::ParseID3v1(const uint8* data, int size) {
276 DVLOG(1) << __FUNCTION__ << "(" << size << ")";
278 if (size < kID3v1Size)
279 return 0;
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 << ")";
289 if (size < 10)
290 return 0;
292 BitReader reader(data, size);
293 int32 id;
294 int version;
295 uint8 flags;
296 int32 id3_size;
298 if (!reader.ReadBits(24, &id) ||
299 !reader.ReadBits(16, &version) ||
300 !reader.ReadBits(8, &flags) ||
301 !ParseSyncSafeInt(&reader, &id3_size)) {
302 return -1;
305 int32 actual_tag_size = 10 + id3_size;
307 // Increment size if 'Footer present' flag is set.
308 if (flags & 0x10)
309 actual_tag_size += 10;
311 // Make sure we have the entire tag.
312 if (size < actual_tag_size)
313 return 0;
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,
321 int32* value) {
322 *value = 0;
323 for (int i = 0; i < 4; ++i) {
324 uint8 tmp;
325 if (!reader->ReadBits(1, &tmp) || tmp != 0) {
326 MEDIA_LOG(ERROR, media_log_) << "ID3 syncsafe integer byte MSb is not 0!";
327 return false;
330 if (!reader->ReadBits(7, &tmp))
331 return false;
333 *value <<= 7;
334 *value += tmp;
337 return true;
340 int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8* data,
341 int size) const {
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)
351 return 0;
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;
359 int frame_size;
360 int sync_bytes = ParseFrameHeader(
361 sync, sync_size, &frame_size, NULL, NULL, NULL, NULL);
363 if (sync_bytes == 0)
364 return 0;
366 if (sync_bytes > 0) {
367 DCHECK_LT(sync_bytes, sync_size);
369 // Skip over this frame so we can check the next one.
370 sync += frame_size;
372 // Make sure the next frame starts inside the buffer.
373 if (sync >= end)
374 return 0;
375 } else {
376 DVLOG(1) << "ParseFrameHeader() " << i << " failed @" << (sync - data);
377 parse_header_failed = true;
378 break;
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;
387 continue;
390 return candidate_start_code - data;
393 return 0;
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))
408 return false;
409 buffers->clear();
411 if (end_of_segment) {
412 in_media_segment_ = false;
413 end_of_segment_cb_.Run();
416 timestamp_helper_->SetBaseTimestamp(base::TimeDelta());
417 return true;
420 } // namespace media