OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 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/mp2t/es_parser_adts.h" | |
6 | |
7 #include <list> | |
8 | |
9 #include "base/basictypes.h" | |
10 #include "base/logging.h" | |
11 #include "base/strings/string_number_conversions.h" | |
12 #include "media/base/audio_timestamp_helper.h" | |
13 #include "media/base/bit_reader.h" | |
14 #include "media/base/buffers.h" | |
15 #include "media/base/channel_layout.h" | |
16 #include "media/base/stream_parser_buffer.h" | |
17 #include "media/mp2t/mp2t_common.h" | |
18 | |
19 // Adts header is at least 7 bytes (can be 9 bytes). | |
20 static const int kAdtsHeaderMinSize = 7; | |
21 | |
22 static const int adts_frequency_table[16] = { | |
23 96000, | |
24 88200, | |
25 64000, | |
26 48000, | |
27 44100, | |
28 32000, | |
29 24000, | |
30 22050, | |
31 16000, | |
32 12000, | |
33 11025, | |
34 8000, | |
35 7350, | |
36 0, | |
37 0, | |
38 0, | |
39 }; | |
40 static const int kMaxSupportedFrequencyIndex = 12; | |
41 | |
42 static media::ChannelLayout adts_channel_layout[8] = { | |
43 media::CHANNEL_LAYOUT_NONE, | |
44 media::CHANNEL_LAYOUT_MONO, | |
45 media::CHANNEL_LAYOUT_STEREO, | |
46 media::CHANNEL_LAYOUT_SURROUND, | |
47 media::CHANNEL_LAYOUT_4_0, | |
48 media::CHANNEL_LAYOUT_5_0_BACK, | |
49 media::CHANNEL_LAYOUT_5_1_BACK, | |
50 media::CHANNEL_LAYOUT_7_1, | |
51 }; | |
52 | |
53 // Number of samples per frame. | |
54 static const int kNumberSamplesPerAACFrame = 1024; | |
55 | |
56 static int ExtractAdtsFrameSize(const uint8* adts_header) { | |
57 return ((static_cast<int>(adts_header[5]) >> 5) | | |
58 (static_cast<int>(adts_header[4]) << 3) | | |
59 ((static_cast<int>(adts_header[3]) & 0x3) << 11)); | |
60 } | |
61 | |
62 static int ExtractAdtsFrequencyIndex(const uint8* adts_header) { | |
63 return ((adts_header[2] >> 2) & 0xf); | |
64 } | |
65 | |
66 static int ExtractAdtsChannelConfig(const uint8* adts_header) { | |
67 return (((adts_header[3] >> 6) & 0x3) | | |
68 ((adts_header[2] & 0x1) << 2)); | |
69 } | |
70 | |
71 // Return true if buf corresponds to an ADTS syncword. | |
72 // |buf| size must be at least 2. | |
73 static bool isAdtsSyncWord(const uint8* buf) { | |
74 return (buf[0] == 0xff) && ((buf[1] & 0xf6) == 0xf0); | |
75 } | |
76 | |
77 // Look for an ADTS syncword. | |
78 // |new_pos| returns | |
79 // - either the byte position of the ADTS frame (if found) | |
80 // - or the byte position of 1st byte that was not processed (if not found). | |
81 // In every case, the returned value in |new_pos| is such that new_pos >= pos | |
82 // |frame_sz| returns the size of the ADTS frame (if found). | |
83 // Return whether a syncword was found. | |
84 static bool LookForSyncWord(const uint8* raw_es, int raw_es_size, | |
85 int pos, | |
86 int* new_pos, int* frame_sz) { | |
87 DCHECK_GE(pos, 0); | |
88 DCHECK_LE(pos, raw_es_size); | |
89 | |
90 int max_offset = raw_es_size - kAdtsHeaderMinSize; | |
91 if (pos >= max_offset) { | |
92 // Do not change the position if: | |
93 // - max_offset < 0: not enough bytes to get a full header | |
94 // Since pos >= 0, this is a subcase of the next condition. | |
95 // - pos >= max_offset: might be the case after reading one full frame, | |
96 // |pos| is then incremented by the frame size and might then point | |
97 // to the end of the buffer. | |
98 *new_pos = pos; | |
99 return false; | |
100 } | |
101 | |
102 for (int offset = pos; offset < max_offset; offset++) { | |
103 const uint8* cur_buf = &raw_es[offset]; | |
104 | |
105 if (!isAdtsSyncWord(cur_buf)) | |
106 // The first 12 bits must be 1. | |
107 // The layer field (2 bits) must be set to 0. | |
108 continue; | |
109 | |
110 int frame_size = ExtractAdtsFrameSize(cur_buf); | |
111 if (frame_size < kAdtsHeaderMinSize) | |
112 // Too short to be an ADTS frame. | |
113 continue; | |
acolwell GONE FROM CHROMIUM
2013/09/18 01:46:05
nit: Add {} since the comment makes this multi-lin
damienv1
2013/09/18 21:40:17
Done.
| |
114 | |
115 // Check whether there is another frame | |
116 // |size| apart from the current one. | |
117 int remaining_size = raw_es_size - offset; | |
118 if (remaining_size >= frame_size + 2 && | |
119 !isAdtsSyncWord(&cur_buf[frame_size])) { | |
120 continue; | |
121 } | |
122 | |
123 *new_pos = offset; | |
124 *frame_sz = frame_size; | |
125 return true; | |
126 } | |
127 | |
128 *new_pos = max_offset; | |
129 return false; | |
130 } | |
131 | |
132 namespace media { | |
133 namespace mp2t { | |
134 | |
135 EsParserAdts::EsParserAdts( | |
136 const NewAudioConfigCB& new_audio_config_cb, | |
137 const EmitBufferCB& emit_buffer_cb) | |
138 : new_audio_config_cb_(new_audio_config_cb), | |
139 emit_buffer_cb_(emit_buffer_cb) { | |
140 } | |
141 | |
142 EsParserAdts::~EsParserAdts() { | |
143 } | |
144 | |
145 bool EsParserAdts::Parse(const uint8* buf, int size, | |
146 base::TimeDelta pts, | |
147 base::TimeDelta dts) { | |
148 int raw_es_size; | |
149 const uint8* raw_es; | |
150 | |
151 // The incoming PTS applies to the access unit that comes just after | |
152 // the beginning of |buf|. | |
153 if (pts != kNoTimestamp()) { | |
154 es_byte_queue_.Peek(&raw_es, &raw_es_size); | |
155 pts_list_.push_back(EsPts(raw_es_size, pts)); | |
156 } | |
157 | |
158 // Copy the input data to the ES buffer. | |
159 es_byte_queue_.Push(buf, size); | |
160 es_byte_queue_.Peek(&raw_es, &raw_es_size); | |
161 | |
162 // Look for every ADTS frame in the ES buffer starting at offset = 0 | |
163 int es_position = 0; | |
164 int frame_size; | |
165 while (LookForSyncWord(raw_es, raw_es_size, es_position, | |
166 &es_position, &frame_size)) { | |
167 DVLOG(LOG_LEVEL_ES) << "ADTS syncword @ pos=" << es_position | |
168 << " frame_size=" << frame_size; | |
169 DVLOG(LOG_LEVEL_ES) << "ADTS header: " | |
170 << base::HexEncode(&raw_es[es_position], 7); | |
acolwell GONE FROM CHROMIUM
2013/09/18 01:46:05
nit: s/7/kAdtsHeaderMinSize/
damienv1
2013/09/18 21:40:17
Done.
| |
171 | |
172 // Do not process the frame if this one is a partial frame. | |
173 int remaining_size = raw_es_size - es_position; | |
174 if (frame_size > remaining_size) | |
175 break; | |
176 | |
177 // Update the audio configuration if needed. | |
178 DCHECK_GE(frame_size, kAdtsHeaderMinSize); | |
179 if (!UpdateAudioConfiguration(&raw_es[es_position])) | |
180 return false; | |
181 | |
182 // Get the PTS & the duration of this access unit. | |
183 while (!pts_list_.empty() && | |
184 pts_list_.front().first <= es_position) { | |
185 audio_timestamp_helper_->SetBaseTimestamp(pts_list_.front().second); | |
186 pts_list_.pop_front(); | |
187 } | |
188 | |
189 base::TimeDelta current_pts = audio_timestamp_helper_->GetTimestamp(); | |
190 base::TimeDelta frame_duration = | |
191 audio_timestamp_helper_->GetFrameDuration(kNumberSamplesPerAACFrame); | |
192 | |
193 // Emit an audio frame. | |
194 bool is_key_frame = true; | |
195 scoped_refptr<StreamParserBuffer> stream_parser_buffer = | |
196 StreamParserBuffer::CopyFrom( | |
197 &raw_es[es_position], | |
198 frame_size, | |
199 is_key_frame); | |
200 stream_parser_buffer->SetDecodeTimestamp(current_pts); | |
201 stream_parser_buffer->set_timestamp(current_pts); | |
202 stream_parser_buffer->set_duration(frame_duration); | |
203 emit_buffer_cb_.Run(stream_parser_buffer); | |
204 | |
205 // Update the PTS of the next frame. | |
206 audio_timestamp_helper_->AddFrames(kNumberSamplesPerAACFrame); | |
207 | |
208 // Skip the current frame. | |
209 es_position += frame_size; | |
210 } | |
211 | |
212 // Discard all the bytes that have been processed. | |
213 DiscardEs(es_position); | |
214 | |
215 return true; | |
216 } | |
217 | |
218 void EsParserAdts::Flush() { | |
219 } | |
220 | |
221 void EsParserAdts::Reset() { | |
222 es_byte_queue_.Reset(); | |
223 pts_list_.clear(); | |
224 last_audio_decoder_config_ = AudioDecoderConfig(); | |
225 } | |
226 | |
227 bool EsParserAdts::UpdateAudioConfiguration(const uint8* adts_header) { | |
228 int frequency_index = ExtractAdtsFrequencyIndex(adts_header); | |
229 if (frequency_index > kMaxSupportedFrequencyIndex) { | |
230 // Frequency index 13 & 14 are reserved | |
231 // while 15 means that the frequency is explicitly written | |
232 // (not supported). | |
233 return false; | |
234 } | |
235 | |
236 int channel_configuration = ExtractAdtsChannelConfig(adts_header); | |
237 if (channel_configuration == 0) { | |
238 // TODO(damienv): Add support for inband channel configuration. | |
239 return false; | |
240 } | |
241 | |
242 // TODO(damienv): support HE-AAC frequency doubling (SBR) | |
243 // based on the incoming ADTS profile. | |
244 int samples_per_second = adts_frequency_table[frequency_index]; | |
245 int adts_profile = (adts_header[2] >> 6) & 0x3; | |
246 | |
247 AudioDecoderConfig audio_decoder_config( | |
248 kCodecAAC, | |
249 kSampleFormatS16, | |
250 adts_channel_layout[channel_configuration], | |
251 samples_per_second, | |
252 NULL, 0, | |
253 false); | |
254 | |
255 if (!audio_decoder_config.Matches(last_audio_decoder_config_)) { | |
256 DVLOG(1) << "Sampling frequency: " << samples_per_second; | |
257 DVLOG(1) << "Channel config: " << channel_configuration; | |
258 DVLOG(1) << "Adts profile: " << adts_profile; | |
259 // Reset the timestamp helper to use a new time scale. | |
260 if (audio_timestamp_helper_) { | |
261 base::TimeDelta base_timestamp = audio_timestamp_helper_->GetTimestamp(); | |
262 audio_timestamp_helper_.reset( | |
263 new AudioTimestampHelper(samples_per_second)); | |
264 audio_timestamp_helper_->SetBaseTimestamp(base_timestamp); | |
265 } else { | |
266 audio_timestamp_helper_.reset( | |
267 new AudioTimestampHelper(samples_per_second)); | |
268 } | |
269 // Audio config notification. | |
270 last_audio_decoder_config_ = audio_decoder_config; | |
271 new_audio_config_cb_.Run(audio_decoder_config); | |
272 } | |
273 | |
274 return true; | |
275 } | |
276 | |
277 void EsParserAdts::DiscardEs(int nbytes) { | |
278 DCHECK_GE(nbytes, 0); | |
279 if (nbytes <= 0) | |
280 return; | |
281 | |
282 // Adjust the ES position of each PTS. | |
283 for (EsPtsList::iterator it = pts_list_.begin(); it != pts_list_.end(); ++it) | |
284 it->first -= nbytes; | |
285 | |
286 // Discard |nbytes| of ES. | |
287 es_byte_queue_.Pop(nbytes); | |
288 } | |
289 | |
290 } // namespace mp2t | |
291 } // namespace media | |
292 | |
OLD | NEW |