Upstream version 5.34.104.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     : state_(UNINITIALIZED),
49       in_media_segment_(false),
50       start_code_mask_(start_code_mask),
51       audio_codec_(audio_codec) {}
52
53 MPEGAudioStreamParserBase::~MPEGAudioStreamParserBase() {}
54
55 void MPEGAudioStreamParserBase::Init(const InitCB& init_cb,
56                                      const NewConfigCB& config_cb,
57                                      const NewBuffersCB& new_buffers_cb,
58                                      bool ignore_text_tracks,
59                                      const NeedKeyCB& need_key_cb,
60                                      const NewMediaSegmentCB& new_segment_cb,
61                                      const base::Closure& end_of_segment_cb,
62                                      const LogCB& log_cb) {
63   DVLOG(1) << __FUNCTION__;
64   DCHECK_EQ(state_, UNINITIALIZED);
65   init_cb_ = init_cb;
66   config_cb_ = config_cb;
67   new_buffers_cb_ = new_buffers_cb;
68   new_segment_cb_ = new_segment_cb;
69   end_of_segment_cb_ = end_of_segment_cb;
70   log_cb_ = log_cb;
71
72   ChangeState(INITIALIZED);
73 }
74
75 void MPEGAudioStreamParserBase::Flush() {
76   DVLOG(1) << __FUNCTION__;
77   DCHECK_NE(state_, UNINITIALIZED);
78   queue_.Reset();
79   timestamp_helper_->SetBaseTimestamp(base::TimeDelta());
80   in_media_segment_ = false;
81 }
82
83 bool MPEGAudioStreamParserBase::Parse(const uint8* buf, int size) {
84   DVLOG(1) << __FUNCTION__ << "(" << size << ")";
85   DCHECK(buf);
86   DCHECK_GT(size, 0);
87   DCHECK_NE(state_, UNINITIALIZED);
88
89   if (state_ == PARSE_ERROR)
90     return false;
91
92   DCHECK_EQ(state_, INITIALIZED);
93
94   queue_.Push(buf, size);
95
96   bool end_of_segment = true;
97   BufferQueue buffers;
98   for (;;) {
99     const uint8* data;
100     int data_size;
101     queue_.Peek(&data, &data_size);
102
103     if (data_size < 4)
104       break;
105
106     uint32 start_code = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
107     int bytes_read = 0;
108     bool parsed_metadata = true;
109     if ((start_code & start_code_mask_) == start_code_mask_) {
110       bytes_read = ParseFrame(data, data_size, &buffers);
111
112       // Only allow the current segment to end if a full frame has been parsed.
113       end_of_segment = bytes_read > 0;
114       parsed_metadata = false;
115     } else if (start_code == kICYStartCode) {
116       bytes_read = ParseIcecastHeader(data, data_size);
117     } else if ((start_code & kID3StartCodeMask) == kID3v1StartCode) {
118       bytes_read = ParseID3v1(data, data_size);
119     } else if ((start_code & kID3StartCodeMask) == kID3v2StartCode) {
120       bytes_read = ParseID3v2(data, data_size);
121     } else {
122       bytes_read = FindNextValidStartCode(data, data_size);
123
124       if (bytes_read > 0) {
125         DVLOG(1) << "Unexpected start code 0x" << std::hex << start_code;
126         DVLOG(1) << "SKIPPING " << bytes_read << " bytes of garbage.";
127       }
128     }
129
130     CHECK_LE(bytes_read, data_size);
131
132     if (bytes_read < 0) {
133       ChangeState(PARSE_ERROR);
134       return false;
135     } else if (bytes_read == 0) {
136       // Need more data.
137       break;
138     }
139
140     // Send pending buffers if we have encountered metadata.
141     if (parsed_metadata && !buffers.empty() && !SendBuffers(&buffers, true))
142       return false;
143
144     queue_.Pop(bytes_read);
145     end_of_segment = true;
146   }
147
148   if (buffers.empty())
149     return true;
150
151   // Send buffers collected in this append that haven't been sent yet.
152   return SendBuffers(&buffers, end_of_segment);
153 }
154
155 void MPEGAudioStreamParserBase::ChangeState(State state) {
156   DVLOG(1) << __FUNCTION__ << "() : " << state_ << " -> " << state;
157   state_ = state;
158 }
159
160 int MPEGAudioStreamParserBase::ParseFrame(const uint8* data,
161                                           int size,
162                                           BufferQueue* buffers) {
163   DVLOG(2) << __FUNCTION__ << "(" << size << ")";
164
165   int sample_rate;
166   ChannelLayout channel_layout;
167   int frame_size;
168   int sample_count;
169   int bytes_read = ParseFrameHeader(
170       data, size, &frame_size, &sample_rate, &channel_layout, &sample_count);
171
172   if (bytes_read <= 0)
173     return bytes_read;
174
175   // Make sure data contains the entire frame.
176   if (size < frame_size)
177     return 0;
178
179   DVLOG(2) << " sample_rate " << sample_rate
180            << " channel_layout " << channel_layout
181            << " frame_size " << frame_size
182            << " sample_count " << sample_count;
183
184   if (config_.IsValidConfig() &&
185       (config_.samples_per_second() != sample_rate ||
186        config_.channel_layout() != channel_layout)) {
187     // Clear config data so that a config change is initiated.
188     config_ = AudioDecoderConfig();
189
190     // Send all buffers associated with the previous config.
191     if (!buffers->empty() && !SendBuffers(buffers, true))
192       return -1;
193   }
194
195   if (!config_.IsValidConfig()) {
196     config_.Initialize(audio_codec_, kSampleFormatF32, channel_layout,
197                        sample_rate, NULL, 0, false, false,
198                        base::TimeDelta(), base::TimeDelta());
199
200     base::TimeDelta base_timestamp;
201     if (timestamp_helper_)
202       base_timestamp = timestamp_helper_->GetTimestamp();
203
204     timestamp_helper_.reset(new AudioTimestampHelper(sample_rate));
205     timestamp_helper_->SetBaseTimestamp(base_timestamp);
206
207     VideoDecoderConfig video_config;
208     bool success = config_cb_.Run(config_, video_config, TextTrackConfigMap());
209
210     if (!init_cb_.is_null())
211       base::ResetAndReturn(&init_cb_).Run(success, kInfiniteDuration());
212
213     if (!success)
214       return -1;
215   }
216
217   // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
218   // type and allow multiple audio tracks, if applicable. See
219   // https://crbug.com/341581.
220   scoped_refptr<StreamParserBuffer> buffer =
221       StreamParserBuffer::CopyFrom(data, frame_size, true,
222                                    DemuxerStream::AUDIO, 0);
223   buffer->set_timestamp(timestamp_helper_->GetTimestamp());
224   buffer->set_duration(timestamp_helper_->GetFrameDuration(sample_count));
225   buffers->push_back(buffer);
226
227   timestamp_helper_->AddFrames(sample_count);
228
229   return frame_size;
230 }
231
232 int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8* data, int size) {
233   DVLOG(1) << __FUNCTION__ << "(" << size << ")";
234
235   if (size < 4)
236     return 0;
237
238   if (memcmp("ICY ", data, 4))
239     return -1;
240
241   int locate_size = std::min(size, kMaxIcecastHeaderSize);
242   int offset = LocateEndOfHeaders(data, locate_size, 4);
243   if (offset < 0) {
244     if (locate_size == kMaxIcecastHeaderSize) {
245       MEDIA_LOG(log_cb_) << "Icecast header is too large.";
246       return -1;
247     }
248
249     return 0;
250   }
251
252   return offset;
253 }
254
255 int MPEGAudioStreamParserBase::ParseID3v1(const uint8* data, int size) {
256   DVLOG(1) << __FUNCTION__ << "(" << size << ")";
257
258   if (size < kID3v1Size)
259     return 0;
260
261   // TODO(acolwell): Add code to actually validate ID3v1 data and
262   // expose it as a metadata text track.
263   return !memcmp(data, "TAG+", 4) ? kID3v1ExtendedSize : kID3v1Size;
264 }
265
266 int MPEGAudioStreamParserBase::ParseID3v2(const uint8* data, int size) {
267   DVLOG(1) << __FUNCTION__ << "(" << size << ")";
268
269   if (size < 10)
270     return 0;
271
272   BitReader reader(data, size);
273   int32 id;
274   int version;
275   uint8 flags;
276   int32 id3_size;
277
278   if (!reader.ReadBits(24, &id) ||
279       !reader.ReadBits(16, &version) ||
280       !reader.ReadBits(8, &flags) ||
281       !ParseSyncSafeInt(&reader, &id3_size)) {
282     return -1;
283   }
284
285   int32 actual_tag_size = 10 + id3_size;
286
287   // Increment size if 'Footer present' flag is set.
288   if (flags & 0x10)
289     actual_tag_size += 10;
290
291   // Make sure we have the entire tag.
292   if (size < actual_tag_size)
293     return 0;
294
295   // TODO(acolwell): Add code to actually validate ID3v2 data and
296   // expose it as a metadata text track.
297   return actual_tag_size;
298 }
299
300 bool MPEGAudioStreamParserBase::ParseSyncSafeInt(BitReader* reader,
301                                                  int32* value) {
302   *value = 0;
303   for (int i = 0; i < 4; ++i) {
304     uint8 tmp;
305     if (!reader->ReadBits(1, &tmp) || tmp != 0) {
306       MEDIA_LOG(log_cb_) << "ID3 syncsafe integer byte MSb is not 0!";
307       return false;
308     }
309
310     if (!reader->ReadBits(7, &tmp))
311       return false;
312
313     *value <<= 7;
314     *value += tmp;
315   }
316
317   return true;
318 }
319
320 int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8* data,
321                                                       int size) const {
322   const uint8* start = data;
323   const uint8* end = data + size;
324
325   while (start < end) {
326     int bytes_left = end - start;
327     const uint8* candidate_start_code =
328         static_cast<const uint8*>(memchr(start, 0xff, bytes_left));
329
330     if (!candidate_start_code)
331       return 0;
332
333     bool parse_header_failed = false;
334     const uint8* sync = candidate_start_code;
335     // Try to find 3 valid frames in a row. 3 was selected to decrease
336     // the probability of false positives.
337     for (int i = 0; i < 3; ++i) {
338       int sync_size = end - sync;
339       int frame_size;
340       int sync_bytes = ParseFrameHeader(
341           sync, sync_size, &frame_size, NULL, NULL, NULL);
342
343       if (sync_bytes == 0)
344         return 0;
345
346       if (sync_bytes > 0) {
347         DCHECK_LT(sync_bytes, sync_size);
348
349         // Skip over this frame so we can check the next one.
350         sync += frame_size;
351
352         // Make sure the next frame starts inside the buffer.
353         if (sync >= end)
354           return 0;
355       } else {
356         DVLOG(1) << "ParseFrameHeader() " << i << " failed @" << (sync - data);
357         parse_header_failed = true;
358         break;
359       }
360     }
361
362     if (parse_header_failed) {
363       // One of the frame header parses failed so |candidate_start_code|
364       // did not point to the start of a real frame. Move |start| forward
365       // so we can find the next candidate.
366       start = candidate_start_code + 1;
367       continue;
368     }
369
370     return candidate_start_code - data;
371   }
372
373   return 0;
374 }
375
376 bool MPEGAudioStreamParserBase::SendBuffers(BufferQueue* buffers,
377                                             bool end_of_segment) {
378   DCHECK(!buffers->empty());
379
380   if (!in_media_segment_) {
381     in_media_segment_ = true;
382     new_segment_cb_.Run();
383   }
384
385   BufferQueue empty_video_buffers;
386   TextBufferQueueMap empty_text_map;
387   if (!new_buffers_cb_.Run(*buffers, empty_video_buffers, empty_text_map))
388     return false;
389   buffers->clear();
390
391   if (end_of_segment) {
392     in_media_segment_ = false;
393     end_of_segment_cb_.Run();
394   }
395
396   return true;
397 }
398
399 }  // namespace media