1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "OpusHeader"
19 #include <cstring>
20 #include <inttypes.h>
21 #include <stdint.h>
22
23 #include <log/log.h>
24
25 #include "OpusHeader.h"
26
27 namespace android {
28
29 // Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
30 // mappings for up to 8 channels. This information is part of the Vorbis I
31 // Specification:
32 // http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
33 constexpr int kMaxChannels = 8;
34
35 constexpr uint8_t kOpusChannelMap[kMaxChannels][kMaxChannels] = {
36 {0},
37 {0, 1},
38 {0, 2, 1},
39 {0, 1, 2, 3},
40 {0, 4, 1, 2, 3},
41 {0, 4, 1, 2, 3, 5},
42 {0, 4, 1, 2, 3, 5, 6},
43 {0, 6, 1, 2, 3, 4, 5, 7},
44 };
45
46 // Size of the Opus header excluding optional mapping information.
47 constexpr size_t kOpusHeaderSize = 19;
48 // Offset to magic string that starts Opus header.
49 constexpr size_t kOpusHeaderLabelOffset = 0;
50 // Offset to Opus version in the Opus header.
51 constexpr size_t kOpusHeaderVersionOffset = 8;
52 // Offset to the channel count byte in the Opus header.
53 constexpr size_t kOpusHeaderChannelsOffset = 9;
54 // Offset to the pre-skip value in the Opus header.
55 constexpr size_t kOpusHeaderSkipSamplesOffset = 10;
56 // Offset to sample rate in the Opus header.
57 constexpr size_t kOpusHeaderSampleRateOffset = 12;
58 // Offset to the gain value in the Opus header.
59 constexpr size_t kOpusHeaderGainOffset = 16;
60 // Offset to the channel mapping byte in the Opus header.
61 constexpr size_t kOpusHeaderChannelMappingOffset = 18;
62 // Opus Header contains a stream map. The mapping values are in the header
63 // beyond the always present |kOpusHeaderSize| bytes of data. The mapping
64 // data contains stream count, coupling information, and per channel mapping
65 // values:
66 // - Byte 0: Number of streams.
67 // - Byte 1: Number coupled.
68 // - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping
69 // values.
70 // Offset to the number of streams in the Opus header.
71 constexpr size_t kOpusHeaderNumStreamsOffset = 19;
72 // Offset to the number of streams that are coupled in the Opus header.
73 constexpr size_t kOpusHeaderNumCoupledStreamsOffset = 20;
74 // Offset to the stream to channel mapping in the Opus header.
75 constexpr size_t kOpusHeaderStreamMapOffset = 21;
76
77 // Default audio output channel layout. Used to initialize |stream_map| in
78 // OpusHeader, and passed to opus_multistream_decoder_create() when the header
79 // does not contain mapping information. The values are valid only for mono and
80 // stereo output: Opus streams with more than 2 channels require a stream map.
81 constexpr int kMaxChannelsWithDefaultLayout = 2;
82
ReadLE16(const uint8_t * data,size_t data_size,uint32_t read_offset)83 static uint16_t ReadLE16(const uint8_t* data, size_t data_size, uint32_t read_offset) {
84 // check whether the 2nd byte is within the buffer
85 if (read_offset + 1 >= data_size) return 0;
86 uint16_t val;
87 val = data[read_offset];
88 val |= data[read_offset + 1] << 8;
89 return val;
90 }
91
92 // Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
ParseOpusHeader(const uint8_t * data,size_t data_size,OpusHeader * header)93 bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header) {
94 if (data == NULL) {
95 return false;
96 }
97 if (data_size < kOpusHeaderSize) {
98 ALOGV("Header size is too small.");
99 return false;
100 }
101 header->channels = data[kOpusHeaderChannelsOffset];
102
103 if (header->channels < 1 || header->channels > kMaxChannels) {
104 ALOGV("Invalid Header, bad channel count: %d", header->channels);
105 return false;
106 }
107 header->skip_samples = ReadLE16(data, data_size, kOpusHeaderSkipSamplesOffset);
108 header->gain_db = static_cast<int16_t>(ReadLE16(data, data_size, kOpusHeaderGainOffset));
109 header->channel_mapping = data[kOpusHeaderChannelMappingOffset];
110 if (!header->channel_mapping) {
111 if (header->channels > kMaxChannelsWithDefaultLayout) {
112 ALOGV("Invalid Header, missing stream map.");
113 return false;
114 }
115 header->num_streams = 1;
116 header->num_coupled = header->channels > 1;
117 header->stream_map[0] = 0;
118 header->stream_map[1] = 1;
119 return true;
120 }
121 if (data_size < kOpusHeaderStreamMapOffset + header->channels) {
122 ALOGV("Invalid stream map; insufficient data for current channel "
123 "count: %d",
124 header->channels);
125 return false;
126 }
127 header->num_streams = data[kOpusHeaderNumStreamsOffset];
128 header->num_coupled = data[kOpusHeaderNumCoupledStreamsOffset];
129 if (header->num_streams + header->num_coupled != header->channels) {
130 ALOGV("Inconsistent channel mapping.");
131 return false;
132 }
133 for (int i = 0; i < header->channels; ++i)
134 header->stream_map[i] = data[kOpusHeaderStreamMapOffset + i];
135 return true;
136 }
137
WriteOpusHeader(const OpusHeader & header,int input_sample_rate,uint8_t * output,size_t output_size)138 int WriteOpusHeader(const OpusHeader &header, int input_sample_rate,
139 uint8_t* output, size_t output_size) {
140 // See https://wiki.xiph.org/OggOpus#ID_Header.
141 const size_t total_size = kOpusHeaderStreamMapOffset + header.channels;
142 if (output_size < total_size) {
143 ALOGE("Output buffer too small for header.");
144 return -1;
145 }
146
147 // ensure entire header is cleared, even though we overwrite much of it below
148 memset(output, 0, output_size);
149
150 // Set magic signature.
151 memcpy(output + kOpusHeaderLabelOffset, "OpusHead", 8);
152 // Set Opus version.
153 output[kOpusHeaderVersionOffset] = 1;
154 // Set channel count.
155 output[kOpusHeaderChannelsOffset] = (uint8_t)header.channels;
156 // Set pre-skip
157 memcpy(output + kOpusHeaderSkipSamplesOffset, &header.skip_samples, sizeof(uint16_t));
158 // Set original input sample rate in Hz.
159 memcpy(output + kOpusHeaderSampleRateOffset, &input_sample_rate, sizeof(uint32_t));
160 // Set output gain in dB.
161 memcpy(output + kOpusHeaderGainOffset, &header.gain_db, sizeof(uint16_t));
162
163 if (header.channels > 2) {
164 // Set channel mapping
165 output[kOpusHeaderChannelMappingOffset] = 1;
166 // Assuming no coupled streams. This should actually be
167 // channels() - |coupled_streams|.
168 output[kOpusHeaderNumStreamsOffset] = header.channels;
169 output[kOpusHeaderNumCoupledStreamsOffset] = 0;
170
171 // Set the actual stream map.
172 for (int i = 0; i < header.channels; ++i) {
173 output[kOpusHeaderStreamMapOffset + i] = kOpusChannelMap[header.channels - 1][i];
174 }
175 return kOpusHeaderStreamMapOffset + header.channels + 1;
176 } else {
177 output[kOpusHeaderChannelMappingOffset] = 0;
178 return kOpusHeaderChannelMappingOffset + 1;
179 }
180 }
181
WriteOpusHeaders(const OpusHeader & header,int inputSampleRate,uint8_t * output,size_t outputSize,uint64_t codecDelay,uint64_t seekPreRoll)182 int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
183 uint8_t* output, size_t outputSize, uint64_t codecDelay,
184 uint64_t seekPreRoll) {
185 if (outputSize < AOPUS_UNIFIED_CSD_MINSIZE) {
186 ALOGD("Buffer not large enough to hold unified OPUS CSD");
187 return -1;
188 }
189 int headerLen = 0;
190
191 // Add opus header
192 /*
193 Following is the CSD syntax for signalling OpusHeader
194 (http://wiki.xiph.org/OggOpus#ID_Header)
195
196 Marker (8 bytes) | Length (8 bytes) | OpusHeader
197
198 Markers supported:
199 AOPUS_CSD_OPUS_HEADER_MARKER - Signals Opus Header
200
201 Length should be a value within AOPUS_OPUSHEAD_MINSIZE and AOPUS_OPUSHEAD_MAXSIZE.
202 */
203
204 memcpy(output + headerLen, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
205 headerLen += AOPUS_MARKER_SIZE;
206
207 // Place holder for opusHeader Size
208 headerLen += AOPUS_LENGTH_SIZE;
209
210 int headerSize = WriteOpusHeader(header, inputSampleRate, output + headerLen,
211 outputSize - headerLen);
212 if (headerSize < 0) {
213 ALOGD("%s: WriteOpusHeader failed", __func__);
214 return -1;
215 }
216 headerLen += headerSize;
217
218 // Update opus headerSize after AOPUS_CSD_OPUS_HEADER_MARKER
219 uint64_t length = headerSize;
220 memcpy(output + AOPUS_MARKER_SIZE, &length, AOPUS_LENGTH_SIZE);
221
222 /*
223 Following is the CSD syntax for signalling codec delay and
224 seek pre-roll which is to be appended after OpusHeader
225
226 Marker (8 bytes) | Length (8 bytes) | Samples in ns (8 bytes)
227
228 Markers supported:
229 AOPUS_CSD_CODEC_DELAY_MARKER - codec delay as samples in ns, represented in 8 bytes
230 AOPUS_CSD_SEEK_PREROLL_MARKER - preroll adjustment as samples in ns, represented in 8 bytes
231
232 */
233 length = sizeof(codecDelay);
234 if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
235 ALOGD("Buffer not large enough to hold codec delay");
236 return -1;
237 }
238 // Add codec delay
239 memcpy(output + headerLen, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE);
240 headerLen += AOPUS_MARKER_SIZE;
241 memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
242 headerLen += AOPUS_LENGTH_SIZE;
243 memcpy(output + headerLen, &codecDelay, length);
244 headerLen += length;
245
246 length = sizeof(seekPreRoll);
247 if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
248 ALOGD("Buffer not large enough to hold seek pre roll");
249 return -1;
250 }
251 // Add skip pre roll
252 memcpy(output + headerLen, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE);
253 headerLen += AOPUS_MARKER_SIZE;
254 memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
255 headerLen += AOPUS_LENGTH_SIZE;
256 memcpy(output + headerLen, &seekPreRoll, length);
257 headerLen += length;
258
259 return headerLen;
260 }
261
IsOpusHeader(const uint8_t * data,size_t data_size)262 bool IsOpusHeader(const uint8_t *data, size_t data_size) {
263 if (data_size < AOPUS_MARKER_SIZE) {
264 return false;
265 }
266
267 return !memcmp(data, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
268 }
269
GetOpusHeaderBuffers(const uint8_t * data,size_t data_size,void ** opusHeadBuf,size_t * opusHeadSize,void ** codecDelayBuf,size_t * codecDelaySize,void ** seekPreRollBuf,size_t * seekPreRollSize)270 bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
271 void **opusHeadBuf, size_t *opusHeadSize,
272 void **codecDelayBuf, size_t *codecDelaySize,
273 void **seekPreRollBuf, size_t *seekPreRollSize) {
274 *codecDelayBuf = NULL;
275 *codecDelaySize = 0;
276 *seekPreRollBuf = NULL;
277 *seekPreRollSize = 0;
278 *opusHeadBuf = NULL;
279 *opusHeadSize = 0;
280
281 // AOPUS_MARKER_SIZE is 8 "OpusHead" is of size 8
282 if (data_size < 8)
283 return false;
284
285 // Check if the CSD is in legacy format
286 if (!memcmp("OpusHead", data, 8)) {
287 if (data_size < AOPUS_OPUSHEAD_MINSIZE || data_size > AOPUS_OPUSHEAD_MAXSIZE) {
288 ALOGD("Unexpected size for opusHeadSize %zu", data_size);
289 return false;
290 }
291 *opusHeadBuf = (void *)data;
292 *opusHeadSize = data_size;
293 return true;
294 } else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
295 size_t i = 0;
296 bool found = false;
297 while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
298 uint8_t *csdBuf = (uint8_t *)data + i;
299 if (!memcmp(csdBuf, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE)) {
300 uint64_t value;
301 memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
302 if (value < AOPUS_OPUSHEAD_MINSIZE || value > AOPUS_OPUSHEAD_MAXSIZE) {
303 ALOGD("Unexpected size for opusHeadSize %" PRIu64, value);
304 return false;
305 }
306 i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
307 if (i > data_size) {
308 ALOGD("Marker signals a header that is larger than input");
309 return false;
310 }
311 *opusHeadBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
312 *opusHeadSize = value;
313 found = true;
314 } else if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
315 uint64_t value;
316 memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
317 if (value != sizeof(uint64_t)) {
318 ALOGD("Unexpected size for codecDelay %" PRIu64, value);
319 return false;
320 }
321 i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
322 if (i > data_size) {
323 ALOGD("Marker signals a header that is larger than input");
324 return false;
325 }
326 *codecDelayBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
327 *codecDelaySize = value;
328 } else if (!memcmp(csdBuf, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE)) {
329 uint64_t value;
330 memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
331 if (value != sizeof(uint64_t)) {
332 ALOGD("Unexpected size for seekPreRollSize %" PRIu64, value);
333 return false;
334 }
335 i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
336 if (i > data_size) {
337 ALOGD("Marker signals a header that is larger than input");
338 return false;
339 }
340 *seekPreRollBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
341 *seekPreRollSize = value;
342 } else {
343 i++;
344 }
345 }
346 return found;
347 } else {
348 return false; // it isn't in either format
349 }
350 }
351
352 } // namespace android
353