| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 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 |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 18 | #define LOG_TAG "OpusHeader" |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 19 | #include <cstring> |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 20 | #include <inttypes.h> |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 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 | |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 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; |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 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; |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 82 | |
| 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 |
| 93 | bool ParseOpusHeader(const uint8_t* data, size_t data_size, OpusHeader* header) { |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 94 | if (data == NULL) { |
| 95 | return false; |
| 96 | } |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 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]; |
| Harish Mahendrakar | fb844da | 2020-02-27 14:33:30 -0800 | [diff] [blame] | 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); |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 133 | return false; |
| 134 | } |
| Harish Mahendrakar | fb844da | 2020-02-27 14:33:30 -0800 | [diff] [blame] | 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 | } |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 143 | return true; |
| 144 | } |
| 145 | |
| 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. |
| Rakesh Kumar | 9a37b24 | 2021-03-30 20:26:26 +0530 | [diff] [blame] | 149 | if (header.channels < 1 || header.channels > kMaxChannels) { |
| 150 | ALOGE("Invalid channel count: %d", header.channels); |
| 151 | return -1; |
| 152 | } |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 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 | |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 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 | } |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 201 | int headerLen = 0; |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 202 | |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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, |
| Harish Mahendrakar | 7ec4784 | 2019-05-14 16:54:54 -0700 | [diff] [blame] | 223 | outputSize - headerLen); |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 224 | if (headerSize < 0) { |
| 225 | ALOGD("%s: WriteOpusHeader failed", __func__); |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 226 | return -1; |
| 227 | } |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 228 | headerLen += headerSize; |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 229 | |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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); |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 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 | |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 238 | Marker (8 bytes) | Length (8 bytes) | Samples in ns (8 bytes) |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 239 | |
| 240 | Markers supported: |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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 |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 243 | |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 244 | */ |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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 | } |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 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; |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 255 | memcpy(output + headerLen, &codecDelay, length); |
| 256 | headerLen += length; |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 257 | |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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 | } |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 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; |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 268 | memcpy(output + headerLen, &seekPreRoll, length); |
| 269 | headerLen += length; |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 270 | |
| 271 | return headerLen; |
| 272 | } |
| 273 | |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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 | |
| 282 | bool GetOpusHeaderBuffers(const uint8_t *data, size_t data_size, |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 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; |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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) { |
| Harish Mahendrakar | 3473d55 | 2019-10-21 14:43:26 -0700 | [diff] [blame] | 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 | } |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 311 | size_t i = 0; |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 312 | bool found = false; |
| 313 | while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) { |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 314 | uint8_t *csdBuf = (uint8_t *)data + i; |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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 | } |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 342 | *codecDelayBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE; |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 343 | *codecDelaySize = value; |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 344 | } else if (!memcmp(csdBuf, AOPUS_CSD_SEEK_PREROLL_MARKER, AOPUS_MARKER_SIZE)) { |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 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 | } |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 356 | *seekPreRollBuf = csdBuf + AOPUS_MARKER_SIZE + AOPUS_LENGTH_SIZE; |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 357 | *seekPreRollSize = value; |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 358 | } else { |
| 359 | i++; |
| 360 | } |
| 361 | } |
| Harish Mahendrakar | 6c95530 | 2019-01-25 09:15:51 -0800 | [diff] [blame] | 362 | return found; |
| 363 | } else { |
| 364 | return false; // it isn't in either format |
| Harish Mahendrakar | ad69acb | 2019-01-15 11:58:29 -0800 | [diff] [blame] | 365 | } |
| 366 | } |
| 367 | |
| Ray Essick | df27b04 | 2018-11-27 18:55:09 -0800 | [diff] [blame] | 368 | } // namespace android |