• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_coupled > header->num_streams ||
130         header->num_streams + header->num_coupled != header->channels) {
131         ALOGV("Inconsistent channel mapping, streams: %d coupled: %d channels: %d",
132         header->num_streams, header->num_coupled, header->channels);
133         return false;
134     }
135     for (int i = 0; i < header->channels; ++i) {
136         uint8_t value = data[kOpusHeaderStreamMapOffset + i];
137         if (value != 255 && value >= header->channels) {
138             ALOGV("Invalid channel mapping for index %i : %d", i, value);
139             return false;
140         }
141         header->stream_map[i] = value;
142     }
143     return true;
144 }
145 
WriteOpusHeader(const OpusHeader & header,int input_sample_rate,uint8_t * output,size_t output_size)146 int WriteOpusHeader(const OpusHeader &header, int input_sample_rate,
147                     uint8_t* output, size_t output_size) {
148     // See https://wiki.xiph.org/OggOpus#ID_Header.
149     if (header.channels < 1 || header.channels > kMaxChannels) {
150         ALOGE("Invalid channel count: %d", header.channels);
151         return -1;
152     }
153     const size_t total_size = kOpusHeaderStreamMapOffset + header.channels;
154     if (output_size < total_size) {
155         ALOGE("Output buffer too small for header.");
156         return -1;
157     }
158 
159     // ensure entire header is cleared, even though we overwrite much of it below
160     memset(output, 0, output_size);
161 
162     // Set magic signature.
163     memcpy(output + kOpusHeaderLabelOffset, "OpusHead", 8);
164     // Set Opus version.
165     output[kOpusHeaderVersionOffset] = 1;
166     // Set channel count.
167     output[kOpusHeaderChannelsOffset] = (uint8_t)header.channels;
168     // Set pre-skip
169     memcpy(output + kOpusHeaderSkipSamplesOffset, &header.skip_samples, sizeof(uint16_t));
170     // Set original input sample rate in Hz.
171     memcpy(output + kOpusHeaderSampleRateOffset, &input_sample_rate, sizeof(uint32_t));
172     // Set output gain in dB.
173     memcpy(output + kOpusHeaderGainOffset, &header.gain_db, sizeof(uint16_t));
174 
175     if (header.channels > 2) {
176         // Set channel mapping
177         output[kOpusHeaderChannelMappingOffset] = 1;
178         // Assuming no coupled streams. This should actually be
179         // channels() - |coupled_streams|.
180         output[kOpusHeaderNumStreamsOffset] = header.channels;
181         output[kOpusHeaderNumCoupledStreamsOffset] = 0;
182 
183         // Set the actual stream map.
184         for (int i = 0; i < header.channels; ++i) {
185             output[kOpusHeaderStreamMapOffset + i] = kOpusChannelMap[header.channels - 1][i];
186         }
187         return kOpusHeaderStreamMapOffset + header.channels + 1;
188     } else {
189         output[kOpusHeaderChannelMappingOffset] = 0;
190         return kOpusHeaderChannelMappingOffset + 1;
191     }
192 }
193 
WriteOpusHeaders(const OpusHeader & header,int inputSampleRate,uint8_t * output,size_t outputSize,uint64_t codecDelay,uint64_t seekPreRoll)194 int WriteOpusHeaders(const OpusHeader &header, int inputSampleRate,
195                      uint8_t* output, size_t outputSize, uint64_t codecDelay,
196                      uint64_t seekPreRoll) {
197     if (outputSize < AOPUS_UNIFIED_CSD_MINSIZE) {
198         ALOGD("Buffer not large enough to hold unified OPUS CSD");
199         return -1;
200     }
201     int headerLen = 0;
202 
203     // Add opus header
204     /*
205       Following is the CSD syntax for signalling OpusHeader
206       (http://wiki.xiph.org/OggOpus#ID_Header)
207 
208       Marker (8 bytes) | Length (8 bytes) | OpusHeader
209 
210       Markers supported:
211       AOPUS_CSD_OPUS_HEADER_MARKER - Signals Opus Header
212 
213       Length should be a value within AOPUS_OPUSHEAD_MINSIZE and AOPUS_OPUSHEAD_MAXSIZE.
214     */
215 
216     memcpy(output + headerLen, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
217     headerLen += AOPUS_MARKER_SIZE;
218 
219     // Place holder for opusHeader Size
220     headerLen += AOPUS_LENGTH_SIZE;
221 
222     int headerSize = WriteOpusHeader(header, inputSampleRate, output + headerLen,
223         outputSize - headerLen);
224     if (headerSize < 0) {
225         ALOGD("%s: WriteOpusHeader failed", __func__);
226         return -1;
227     }
228     headerLen += headerSize;
229 
230     // Update opus headerSize after AOPUS_CSD_OPUS_HEADER_MARKER
231     uint64_t length = headerSize;
232     memcpy(output + AOPUS_MARKER_SIZE, &length, AOPUS_LENGTH_SIZE);
233 
234     /*
235       Following is the CSD syntax for signalling codec delay and
236       seek pre-roll which is to be appended after OpusHeader
237 
238       Marker (8 bytes) | Length (8 bytes) | Samples in ns (8 bytes)
239 
240       Markers supported:
241       AOPUS_CSD_CODEC_DELAY_MARKER - codec delay as samples in ns, represented in 8 bytes
242       AOPUS_CSD_SEEK_PREROLL_MARKER - preroll adjustment as samples in ns, represented in 8 bytes
243 
244     */
245     length = sizeof(codecDelay);
246     if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
247         ALOGD("Buffer not large enough to hold codec delay");
248         return -1;
249     }
250     // Add codec delay
251     memcpy(output + headerLen, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE);
252     headerLen += AOPUS_MARKER_SIZE;
253     memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
254     headerLen += AOPUS_LENGTH_SIZE;
255     memcpy(output + headerLen, &codecDelay, length);
256     headerLen += length;
257 
258     length = sizeof(seekPreRoll);
259     if (headerLen > (outputSize - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE - length)) {
260         ALOGD("Buffer not large enough to hold seek pre roll");
261         return -1;
262     }
263     // Add skip pre roll
264     memcpy(output + headerLen, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE);
265     headerLen += AOPUS_MARKER_SIZE;
266     memcpy(output + headerLen, &length, AOPUS_LENGTH_SIZE);
267     headerLen += AOPUS_LENGTH_SIZE;
268     memcpy(output + headerLen, &seekPreRoll, length);
269     headerLen += length;
270 
271     return headerLen;
272 }
273 
IsOpusHeader(const uint8_t * data,size_t data_size)274 bool IsOpusHeader(const uint8_t *data, size_t data_size) {
275     if (data_size < AOPUS_MARKER_SIZE) {
276         return false;
277     }
278 
279     return !memcmp(data, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE);
280 }
281 
GetOpusHeaderBuffers(const uint8_t * data,size_t data_size,void ** opusHeadBuf,size_t * opusHeadSize,void ** codecDelayBuf,size_t * codecDelaySize,void ** seekPreRollBuf,size_t * seekPreRollSize)282 bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size,
283                           void **opusHeadBuf, size_t *opusHeadSize,
284                           void **codecDelayBuf, size_t *codecDelaySize,
285                           void **seekPreRollBuf, size_t *seekPreRollSize) {
286     *codecDelayBuf = NULL;
287     *codecDelaySize = 0;
288     *seekPreRollBuf = NULL;
289     *seekPreRollSize = 0;
290     *opusHeadBuf = NULL;
291     *opusHeadSize = 0;
292 
293     // AOPUS_MARKER_SIZE is 8 "OpusHead" is of size 8
294     if (data_size < 8)
295         return false;
296 
297     // Check if the CSD is in legacy format
298     if (!memcmp("OpusHead", data, 8)) {
299         if (data_size < AOPUS_OPUSHEAD_MINSIZE || data_size > AOPUS_OPUSHEAD_MAXSIZE) {
300             ALOGD("Unexpected size for opusHeadSize %zu", data_size);
301             return false;
302         }
303         *opusHeadBuf = (void *)data;
304         *opusHeadSize = data_size;
305         return true;
306     } else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
307         if (data_size < AOPUS_UNIFIED_CSD_MINSIZE || data_size > AOPUS_UNIFIED_CSD_MAXSIZE) {
308             ALOGD("Unexpected size for unified opus csd %zu", data_size);
309             return false;
310         }
311         size_t i = 0;
312         bool found = false;
313         while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
314             uint8_t *csdBuf = (uint8_t *)data + i;
315             if (!memcmp(csdBuf, AOPUS_CSD_OPUS_HEADER_MARKER, AOPUS_MARKER_SIZE)) {
316                 uint64_t value;
317                 memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
318                 if (value < AOPUS_OPUSHEAD_MINSIZE || value > AOPUS_OPUSHEAD_MAXSIZE) {
319                     ALOGD("Unexpected size for opusHeadSize %" PRIu64, value);
320                     return false;
321                 }
322                 i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
323                 if (i > data_size) {
324                     ALOGD("Marker signals a header that is larger than input");
325                     return false;
326                 }
327                 *opusHeadBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
328                 *opusHeadSize = value;
329                 found = true;
330             } else if (!memcmp(csdBuf, AOPUS_CSD_CODEC_DELAY_MARKER, AOPUS_MARKER_SIZE)) {
331                 uint64_t value;
332                 memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
333                 if (value != sizeof(uint64_t)) {
334                     ALOGD("Unexpected size for codecDelay %" PRIu64, value);
335                     return false;
336                 }
337                 i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
338                 if (i > data_size) {
339                     ALOGD("Marker signals a header that is larger than input");
340                     return false;
341                 }
342                 *codecDelayBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
343                 *codecDelaySize = value;
344             } else if (!memcmp(csdBuf, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE)) {
345                 uint64_t value;
346                 memcpy(&value, csdBuf + AOPUS_MARKER_SIZE, sizeof(value));
347                 if (value != sizeof(uint64_t)) {
348                     ALOGD("Unexpected size for seekPreRollSize %" PRIu64, value);
349                     return false;
350                 }
351                 i += AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE + value;
352                 if (i > data_size) {
353                     ALOGD("Marker signals a header that is larger than input");
354                     return false;
355                 }
356                 *seekPreRollBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE;
357                 *seekPreRollSize = value;
358             } else {
359                 i++;
360             }
361         }
362         return found;
363     } else {
364         return false;  // it isn't in either format
365     }
366 }
367 
368 }  // namespace android
369