API renamed to Opus
This commit is contained in:
parent
4e777532ee
commit
05dd36a1b3
10 changed files with 93 additions and 93 deletions
270
src/opus_encoder.c
Normal file
270
src/opus_encoder.c
Normal file
|
@ -0,0 +1,270 @@
|
|||
/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited
|
||||
Written by Jean-Marc Valin and Koen Vos */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Xiph.org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "opus_encoder.h"
|
||||
#include "entenc.h"
|
||||
#include "modes.h"
|
||||
#include "SKP_Silk_SDK_API.h"
|
||||
|
||||
OpusEncoder *opus_encoder_create(int Fs)
|
||||
{
|
||||
char *raw_state;
|
||||
CELTMode *celtMode;
|
||||
OpusEncoder *st;
|
||||
int ret, silkEncSizeBytes, celtEncSizeBytes;
|
||||
SKP_SILK_SDK_EncControlStruct encControl;
|
||||
|
||||
/* We should not have to create a CELT mode for each encoder state */
|
||||
celtMode = celt_mode_create(Fs, Fs/50, NULL);
|
||||
|
||||
/* Create SILK encoder */
|
||||
ret = SKP_Silk_SDK_Get_Encoder_Size( &silkEncSizeBytes );
|
||||
if( ret ) {
|
||||
/* Handle error */
|
||||
}
|
||||
celtEncSizeBytes = celt_encoder_get_size(celtMode, 1);
|
||||
raw_state = calloc(sizeof(OpusEncoder)+silkEncSizeBytes+celtEncSizeBytes, 1);
|
||||
st = (OpusEncoder*)raw_state;
|
||||
st->silk_enc = (void*)(raw_state+sizeof(OpusEncoder));
|
||||
st->celt_enc = (CELTEncoder*)(raw_state+sizeof(OpusEncoder)+silkEncSizeBytes);
|
||||
|
||||
st->Fs = Fs;
|
||||
st->celt_mode = celtMode;
|
||||
|
||||
/*encControl.API_sampleRate = st->Fs;
|
||||
encControl.packetLossPercentage = 0;
|
||||
encControl.useInBandFEC = 0;
|
||||
encControl.useDTX = 0;
|
||||
encControl.complexity = 2;*/
|
||||
ret = SKP_Silk_SDK_InitEncoder( st->silk_enc, &encControl );
|
||||
if( ret ) {
|
||||
/* Handle error */
|
||||
}
|
||||
|
||||
/* Create CELT encoder */
|
||||
/* Initialize CELT encoder */
|
||||
st->celt_enc = celt_encoder_init(st->celt_enc, st->celt_mode, 1, NULL);
|
||||
|
||||
st->mode = MODE_HYBRID;
|
||||
st->bandwidth = BANDWIDTH_FULLBAND;
|
||||
st->vbr_rate = 0;
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
int opus_encode(OpusEncoder *st, const short *pcm, int frame_size,
|
||||
unsigned char *data, int bytes_per_packet)
|
||||
{
|
||||
int i;
|
||||
int ret=0;
|
||||
SKP_int16 nBytes;
|
||||
ec_enc enc;
|
||||
ec_byte_buffer buf;
|
||||
SKP_SILK_SDK_EncControlStruct encControl;
|
||||
int framerate, period;
|
||||
|
||||
bytes_per_packet -= 1;
|
||||
data += 1;
|
||||
ec_byte_writeinit_buffer(&buf, data, bytes_per_packet);
|
||||
ec_enc_init(&enc,&buf);
|
||||
|
||||
if (st->mode != MODE_CELT_ONLY)
|
||||
{
|
||||
/* Set Encoder parameters */
|
||||
encControl.API_sampleRate = st->Fs;
|
||||
encControl.packetLossPercentage = 2;
|
||||
encControl.useInBandFEC = 0;
|
||||
encControl.useDTX = 0;
|
||||
encControl.complexity = 2;
|
||||
|
||||
if (st->vbr_rate != 0)
|
||||
encControl.bitRate = (st->vbr_rate+6000)/2;
|
||||
else {
|
||||
encControl.bitRate = (bytes_per_packet*8*(celt_int32)st->Fs/frame_size+6000)/2;
|
||||
if (st->Fs == 100 * frame_size)
|
||||
encControl.bitRate -= 5000;
|
||||
}
|
||||
encControl.packetSize = frame_size;
|
||||
|
||||
if (st->bandwidth == BANDWIDTH_NARROWBAND)
|
||||
encControl.maxInternalSampleRate = 8000;
|
||||
else if (st->bandwidth == BANDWIDTH_MEDIUMBAND)
|
||||
encControl.maxInternalSampleRate = 12000;
|
||||
else
|
||||
encControl.maxInternalSampleRate = 16000;
|
||||
|
||||
/* Call SILK encoder for the low band */
|
||||
nBytes = bytes_per_packet;
|
||||
ret = SKP_Silk_SDK_Encode( st->silk_enc, &encControl, pcm, frame_size, &enc, &nBytes );
|
||||
if( ret ) {
|
||||
fprintf (stderr, "SILK encode error\n");
|
||||
/* Handle error */
|
||||
}
|
||||
ret = (ec_enc_tell(&enc, 0)+7)>>3;
|
||||
}
|
||||
|
||||
if (st->mode == MODE_HYBRID)
|
||||
{
|
||||
/* This should be adjusted based on the SILK bandwidth */
|
||||
celt_encoder_ctl(st->celt_enc, CELT_SET_START_BAND(17));
|
||||
} else {
|
||||
celt_encoder_ctl(st->celt_enc, CELT_SET_START_BAND(0));
|
||||
}
|
||||
|
||||
if (st->mode != MODE_SILK_ONLY && st->bandwidth > BANDWIDTH_WIDEBAND)
|
||||
{
|
||||
short pcm_buf[960];
|
||||
|
||||
if (st->bandwidth == BANDWIDTH_SUPERWIDEBAND)
|
||||
celt_encoder_ctl(st->celt_enc, CELT_SET_END_BAND(20));
|
||||
else
|
||||
celt_encoder_ctl(st->celt_enc, CELT_SET_END_BAND(21));
|
||||
|
||||
for (i=0;i<ENCODER_DELAY_COMPENSATION;i++)
|
||||
pcm_buf[i] = st->delay_buffer[i];
|
||||
for (;i<frame_size;i++)
|
||||
pcm_buf[i] = pcm[i-ENCODER_DELAY_COMPENSATION];
|
||||
|
||||
celt_encoder_ctl(st->celt_enc, CELT_SET_PREDICTION(1));
|
||||
|
||||
if (st->vbr_rate != 0)
|
||||
{
|
||||
int tmp = (st->vbr_rate-6000)/2;
|
||||
tmp = ((ec_enc_tell(&enc, 0)+4)>>3) + tmp * frame_size/(8*st->Fs);
|
||||
if (tmp <= bytes_per_packet)
|
||||
bytes_per_packet = tmp;
|
||||
ec_byte_shrink(&buf, bytes_per_packet);
|
||||
}
|
||||
/* Encode high band with CELT */
|
||||
ret = celt_encode_with_ec(st->celt_enc, pcm_buf, NULL, frame_size, NULL, bytes_per_packet, &enc);
|
||||
for (i=0;i<ENCODER_DELAY_COMPENSATION;i++)
|
||||
st->delay_buffer[i] = pcm[frame_size-ENCODER_DELAY_COMPENSATION+i];
|
||||
} else {
|
||||
ec_enc_done(&enc);
|
||||
}
|
||||
|
||||
/* Signalling the mode in the first byte */
|
||||
data--;
|
||||
framerate = st->Fs/frame_size;
|
||||
period = 0;
|
||||
while (framerate < 400)
|
||||
{
|
||||
framerate <<= 1;
|
||||
period++;
|
||||
}
|
||||
if (st->mode == MODE_SILK_ONLY)
|
||||
{
|
||||
data[0] = (st->bandwidth-BANDWIDTH_NARROWBAND)<<5;
|
||||
data[0] |= (period-2)<<3;
|
||||
} else if (st->mode == MODE_CELT_ONLY)
|
||||
{
|
||||
int tmp = st->bandwidth-BANDWIDTH_MEDIUMBAND;
|
||||
if (tmp < 0)
|
||||
tmp = 0;
|
||||
data[0] = 0x80;
|
||||
data[0] |= tmp << 5;
|
||||
data[0] |= period<<3;
|
||||
} else /* Opus */
|
||||
{
|
||||
data[0] = 0x60;
|
||||
data[0] |= (st->bandwidth-BANDWIDTH_SUPERWIDEBAND)<<4;
|
||||
data[0] |= (period-2)<<3;
|
||||
}
|
||||
/*printf ("%x\n", (int)data[0]);*/
|
||||
|
||||
return ret+1;
|
||||
}
|
||||
|
||||
void opus_encoder_ctl(OpusEncoder *st, int request, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, request);
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case OPUS_SET_MODE_REQUEST:
|
||||
{
|
||||
int value = va_arg(ap, int);
|
||||
st->mode = value;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_MODE_REQUEST:
|
||||
{
|
||||
int *value = va_arg(ap, int*);
|
||||
*value = st->mode;
|
||||
}
|
||||
break;
|
||||
case OPUS_SET_BANDWIDTH_REQUEST:
|
||||
{
|
||||
int value = va_arg(ap, int);
|
||||
st->bandwidth = value;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_BANDWIDTH_REQUEST:
|
||||
{
|
||||
int *value = va_arg(ap, int*);
|
||||
*value = st->bandwidth;
|
||||
}
|
||||
break;
|
||||
case OPUS_SET_VBR_RATE_REQUEST:
|
||||
{
|
||||
int value = va_arg(ap, int);
|
||||
st->vbr_rate = value;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_VBR_RATE_REQUEST:
|
||||
{
|
||||
int *value = va_arg(ap, int*);
|
||||
*value = st->vbr_rate;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void opus_encoder_destroy(OpusEncoder *st)
|
||||
{
|
||||
celt_mode_destroy(st->celt_mode);
|
||||
free(st);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue