nlsCppSdk/encoder/oggopusHeader.cpp (98 lines of code) (raw):
/*
* Copyright 2021 Alibaba Group Holding Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "oggopusHeader.h"
#include <stdio.h>
#include <string.h>
/* Header contents:
- "OpusHead" (64 bits)
- version number (8 bits)
- Channels C (8 bits)
- Pre-skip (16 bits)
- Sampling rate (32 bits)
- Gain in dB (16 bits, S7.8)
- Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping,
2..254: reserved, 255: multistream with no mapping)
- if (mapping != 0)
- N = total number of streams (8 bits)
- M = number of paired streams (8 bits)
- C times channel origin
- if (C<2*M)
- stream = byte/2
- if (byte&0x1 == 0)
- left
else
- right
- else
- stream = byte-M
*/
struct Packet {
unsigned char *data;
int maxlen;
int pos;
Packet() : data(NULL), maxlen(0), pos(0) {}
};
struct ROPacket {
const unsigned char *data;
int maxlen;
int pos;
ROPacket() : data(NULL), maxlen(0), pos(0) {}
};
static int write_uint32(Packet *p, ogg_uint32_t val) {
if (p->pos > p->maxlen - 4) return 0;
p->data[p->pos] = (val)&0xFF;
p->data[p->pos + 1] = (val >> 8) & 0xFF;
p->data[p->pos + 2] = (val >> 16) & 0xFF;
p->data[p->pos + 3] = (val >> 24) & 0xFF;
p->pos += 4;
return 1;
}
static int write_uint16(Packet *p, ogg_uint16_t val) {
if (p->pos > p->maxlen - 2) return 0;
p->data[p->pos] = (val)&0xFF;
p->data[p->pos + 1] = (val >> 8) & 0xFF;
p->pos += 2;
return 1;
}
static int write_chars(Packet *p, const unsigned char *str, int nb_chars) {
int i;
if (p->pos > p->maxlen - nb_chars) return 0;
for (i = 0; i < nb_chars; i++) p->data[p->pos++] = str[i];
return 1;
}
static int read_uint32(ROPacket *p, ogg_uint32_t *val) {
if (p->pos > p->maxlen - 4) return 0;
*val = (ogg_uint32_t)p->data[p->pos];
*val |= (ogg_uint32_t)p->data[p->pos + 1] << 8;
*val |= (ogg_uint32_t)p->data[p->pos + 2] << 16;
*val |= (ogg_uint32_t)p->data[p->pos + 3] << 24;
p->pos += 4;
return 1;
}
static int read_uint16(ROPacket *p, ogg_uint16_t *val) {
if (p->pos > p->maxlen - 2) return 0;
*val = (ogg_uint16_t)p->data[p->pos];
*val |= (ogg_uint16_t)p->data[p->pos + 1] << 8;
p->pos += 2;
return 1;
}
static int read_chars(ROPacket *p, unsigned char *str, int nb_chars) {
int i;
if (p->pos > p->maxlen - nb_chars) return 0;
for (i = 0; i < nb_chars; i++) str[i] = p->data[p->pos++];
return 1;
}
int OpusHeaderToPacket(const OpusHeader *h, unsigned char *packet, int len) {
Packet p;
unsigned char ch;
p.data = packet;
p.maxlen = len;
p.pos = 0;
if (len < 19) return 0;
if (!write_chars(&p, (const unsigned char *)"OpusHead", 8)) return 0;
/* Version is 1 */
ch = 1;
if (!write_chars(&p, &ch, 1)) return 0;
ch = h->channels;
if (!write_chars(&p, &ch, 1)) return 0;
if (!write_uint16(&p, h->preskip)) return 0;
if (!write_uint32(&p, h->input_sample_rate)) return 0;
if (!write_uint16(&p, h->gain)) return 0;
ch = h->channel_mapping;
if (!write_chars(&p, &ch, 1)) return 0;
if (h->channel_mapping != 0) {
ch = h->nb_streams;
if (!write_chars(&p, &ch, 1)) return 0;
ch = h->nb_coupled;
if (!write_chars(&p, &ch, 1)) return 0;
int i;
/* Multi-stream support */
for (i = 0; i < h->channels; i++) {
if (!write_chars(&p, &h->stream_map[i], 1)) return 0;
}
}
return p.pos;
}
/* This is just here because it's a convenient file linked by both opusenc and
opusdec (to guarantee this maps stays in sync). */
const int wav_permute_matrix[8][8] = {
{0}, /* 1.0 mono */
{0, 1}, /* 2.0 stereo */
{0, 2, 1}, /* 3.0 channel ('wide') stereo */
{0, 1, 2, 3}, /* 4.0 discrete quadraphonic */
{0, 2, 1, 3, 4}, /* 5.0 surround */
{0, 2, 1, 4, 5, 3}, /* 5.1 surround */
{0, 2, 1, 5, 6, 4, 3}, /* 6.1 surround */
{0, 2, 1, 6, 7, 4, 5, 3} /* 7.1 surround (classic theater 8-track) */
};