Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / media / formats / mpeg / mpeg_audio_stream_parser_base.cc
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.
4
5 #include "media/formats/mpeg/mpeg_audio_stream_parser_base.h"
6
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"
14
15 namespace media {
16
17 static const uint32 kICYStartCode = 0x49435920; // 'ICY '
18
19 // Arbitrary upper bound on the size of an IceCast header before it
20 // triggers an error.
21 static const int kMaxIcecastHeaderSize = 4096;
22
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'
28
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;
40     }
41     last_c = c;
42   }
43   return -1;
44 }
45
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) {}
54
55 MPEGAudioStreamParserBase::~MPEGAudioStreamParserBase() {}
56
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);
67   init_cb_ = init_cb;
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;
72   log_cb_ = log_cb;
73
74   ChangeState(INITIALIZED);
75 }
76
77 void MPEGAudioStreamParserBase::Flush() {
78   DVLOG(1) << __FUNCTION__;
79   DCHECK_NE(state_, UNINITIALIZED);
80   queue_.Reset();
81   timestamp_helper_->SetBaseTimestamp(base::TimeDelta());
82   in_media_segment_ = false;
83 }
84
85 bool MPEGAudioStreamParserBase::Parse(const uint8* buf, int size) {
86   DVLOG(1) << __FUNCTION__ << "(" << size << ")";
87   DCHECK(buf);
88   DCHECK_GT(size, 0);
89   DCHECK_NE(state_, UNINITIALIZED);
90
91   if (state_ == PARSE_ERROR)
92     return false;
93
94   DCHECK_EQ(state_, INITIALIZED);
95
96   queue_.Push(buf, size);
97
98   bool end_of_segment = true;
99   BufferQueue buffers;
100   for (;;) {
101     const uint8* data;
102     int data_size;
103     queue_.Peek(&data, &data_size);
104
105     if (data_size < 4)
106       break;
107
108     uint32 start_code = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
109     int bytes_read = 0;
110     bool parsed_metadata = true;
111     if ((start_code & start_code_mask_) == start_code_mask_) {
112       bytes_read = ParseFrame(data, data_size, &buffers);
113
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);
123     } else {
124       bytes_read = FindNextValidStartCode(data, data_size);
125
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.";
129       }
130     }
131
132     CHECK_LE(bytes_read, data_size);
133
134     if (bytes_read < 0) {
135       ChangeState(PARSE_ERROR);
136       return false;
137     } else if (bytes_read == 0) {
138       // Need more data.
139       break;
140     }
141
142     // Send pending buffers if we have encountered metadata.
143     if (parsed_metadata && !buffers.empty() && !SendBuffers(&buffers, true))
144       return false;
145
146     queue_.Pop(bytes_read);
147     end_of_segment = true;
148   }
149
150   if (buffers.empty())
151     return true;
152
153   // Send buffers collected in this append that haven't been sent yet.
154   return SendBuffers(&buffers, end_of_segment);
155 }
156
157 void MPEGAudioStreamParserBase::ChangeState(State state) {
158   DVLOG(1) << __FUNCTION__ << "() : " << state_ << " -> " << state;
159   state_ = state;
160 }
161
162 int MPEGAudioStreamParserBase::ParseFrame(const uint8* data,
163                                           int size,
164                                           BufferQueue* buffers) {
165   DVLOG(2) << __FUNCTION__ << "(" << size << ")";
166
167   int sample_rate;
168   ChannelLayout channel_layout;
169   int frame_size;
170   int sample_count;
171   bool metadata_frame = false;
172   int bytes_read = ParseFrameHeader(data,
173                                     size,
174                                     &frame_size,
175                                     &sample_rate,
176                                     &channel_layout,
177                                     &sample_count,
178                                     &metadata_frame);
179
180   if (bytes_read <= 0)
181     return bytes_read;
182
183   // Make sure data contains the entire frame.
184   if (size < frame_size)
185     return 0;
186
187   DVLOG(2) << " sample_rate " << sample_rate
188            << " channel_layout " << channel_layout
189            << " frame_size " << frame_size
190            << " sample_count " << sample_count;
191
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();
197
198     // Send all buffers associated with the previous config.
199     if (!buffers->empty() && !SendBuffers(buffers, true))
200       return -1;
201   }
202
203   if (!config_.IsValidConfig()) {
204     config_.Initialize(audio_codec_,
205                        kSampleFormatF32,
206                        channel_layout,
207                        sample_rate,
208                        NULL,
209                        0,
210                        false,
211                        false,
212                        base::TimeDelta(),
213                        codec_delay_);
214
215     base::TimeDelta base_timestamp;
216     if (timestamp_helper_)
217       base_timestamp = timestamp_helper_->GetTimestamp();
218
219     timestamp_helper_.reset(new AudioTimestampHelper(sample_rate));
220     timestamp_helper_->SetBaseTimestamp(base_timestamp);
221
222     VideoDecoderConfig video_config;
223     bool success = config_cb_.Run(config_, video_config, TextTrackConfigMap());
224
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);
229     }
230
231     if (!success)
232       return -1;
233   }
234
235   if (metadata_frame)
236     return frame_size;
237
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);
247
248   timestamp_helper_->AddFrames(sample_count);
249
250   return frame_size;
251 }
252
253 int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8* data, int size) {
254   DVLOG(1) << __FUNCTION__ << "(" << size << ")";
255
256   if (size < 4)
257     return 0;
258
259   if (memcmp("ICY ", data, 4))
260     return -1;
261
262   int locate_size = std::min(size, kMaxIcecastHeaderSize);
263   int offset = LocateEndOfHeaders(data, locate_size, 4);
264   if (offset < 0) {
265     if (locate_size == kMaxIcecastHeaderSize) {
266       MEDIA_LOG(log_cb_) << "Icecast header is too large.";
267       return -1;
268     }
269
270     return 0;
271   }
272
273   return offset;
274 }
275
276 int MPEGAudioStreamParserBase::ParseID3v1(const uint8* data, int size) {
277   DVLOG(1) << __FUNCTION__ << "(" << size << ")";
278
279   if (size < kID3v1Size)
280     return 0;
281
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;
285 }
286
287 int MPEGAudioStreamParserBase::ParseID3v2(const uint8* data, int size) {
288   DVLOG(1) << __FUNCTION__ << "(" << size << ")";
289
290   if (size < 10)
291     return 0;
292
293   BitReader reader(data, size);
294   int32 id;
295   int version;
296   uint8 flags;
297   int32 id3_size;
298
299   if (!reader.ReadBits(24, &id) ||
300       !reader.ReadBits(16, &version) ||
301       !reader.ReadBits(8, &flags) ||
302       !ParseSyncSafeInt(&reader, &id3_size)) {
303     return -1;
304   }
305
306   int32 actual_tag_size = 10 + id3_size;
307
308   // Increment size if 'Footer present' flag is set.
309   if (flags & 0x10)
310     actual_tag_size += 10;
311
312   // Make sure we have the entire tag.
313   if (size < actual_tag_size)
314     return 0;
315
316   // TODO(acolwell): Add code to actually validate ID3v2 data and
317   // expose it as a metadata text track.
318   return actual_tag_size;
319 }
320
321 bool MPEGAudioStreamParserBase::ParseSyncSafeInt(BitReader* reader,
322                                                  int32* value) {
323   *value = 0;
324   for (int i = 0; i < 4; ++i) {
325     uint8 tmp;
326     if (!reader->ReadBits(1, &tmp) || tmp != 0) {
327       MEDIA_LOG(log_cb_) << "ID3 syncsafe integer byte MSb is not 0!";
328       return false;
329     }
330
331     if (!reader->ReadBits(7, &tmp))
332       return false;
333
334     *value <<= 7;
335     *value += tmp;
336   }
337
338   return true;
339 }
340
341 int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8* data,
342                                                       int size) const {
343   const uint8* start = data;
344   const uint8* end = data + size;
345
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));
350
351     if (!candidate_start_code)
352       return 0;
353
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;
360       int frame_size;
361       int sync_bytes = ParseFrameHeader(
362           sync, sync_size, &frame_size, NULL, NULL, NULL, NULL);
363
364       if (sync_bytes == 0)
365         return 0;
366
367       if (sync_bytes > 0) {
368         DCHECK_LT(sync_bytes, sync_size);
369
370         // Skip over this frame so we can check the next one.
371         sync += frame_size;
372
373         // Make sure the next frame starts inside the buffer.
374         if (sync >= end)
375           return 0;
376       } else {
377         DVLOG(1) << "ParseFrameHeader() " << i << " failed @" << (sync - data);
378         parse_header_failed = true;
379         break;
380       }
381     }
382
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;
388       continue;
389     }
390
391     return candidate_start_code - data;
392   }
393
394   return 0;
395 }
396
397 bool MPEGAudioStreamParserBase::SendBuffers(BufferQueue* buffers,
398                                             bool end_of_segment) {
399   DCHECK(!buffers->empty());
400
401   if (!in_media_segment_) {
402     in_media_segment_ = true;
403     new_segment_cb_.Run();
404   }
405
406   BufferQueue empty_video_buffers;
407   TextBufferQueueMap empty_text_map;
408   if (!new_buffers_cb_.Run(*buffers, empty_video_buffers, empty_text_map))
409     return false;
410   buffers->clear();
411
412   if (end_of_segment) {
413     in_media_segment_ = false;
414     end_of_segment_cb_.Run();
415   }
416
417   timestamp_helper_->SetBaseTimestamp(base::TimeDelta());
418   return true;
419 }
420
421 }  // namespace media