From 2b68ea9a116e52239f636eecddc9ac4e29e365fd Mon Sep 17 00:00:00 2001 From: Jean-Marc Valin Date: Tue, 1 Feb 2011 10:35:23 -0500 Subject: [PATCH] Merged Koen's encoder changes --- src/opus.h | 37 ++++++-- src/opus_enc.c | 3 - src/opus_encoder.c | 232 ++++++++++++++++++++++++++++++--------------- src/opus_encoder.h | 4 +- src/test_opus.c | 3 - 5 files changed, 191 insertions(+), 88 deletions(-) diff --git a/src/opus.h b/src/opus.h index 26f47250..f4a054b5 100644 --- a/src/opus.h +++ b/src/opus.h @@ -64,15 +64,40 @@ extern "C" { #define OPUS_GET_MODE_REQUEST 1 #define OPUS_GET_MODE(x) OPUS_GET_MODE_REQUEST, __check_int_ptr(x) -#define OPUS_SET_BANDWIDTH_REQUEST 2 +#define OPUS_SET_BITRATE_REQUEST 2 +#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __check_int(x) +#define OPUS_GET_BITRATE_REQUEST 3 +#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __check_int_ptr(x) + +#define OPUS_SET_VBR_FLAG_REQUEST 6 +#define OPUS_SET_VBR_FLAG(x) OPUS_SET_VBR_FLAG_REQUEST, __check_int(x) +#define OPUS_GET_VBR_FLAG_REQUEST 7 +#define OPUS_GET_VBR_FLAG(x) OPUS_GET_VBR_FLAG_REQUEST, __check_int_ptr(x) + +#define OPUS_SET_BANDWIDTH_REQUEST 8 #define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __check_int(x) -#define OPUS_GET_BANDWIDTH_REQUEST 3 +#define OPUS_GET_BANDWIDTH_REQUEST 9 #define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __check_int_ptr(x) -#define OPUS_SET_VBR_RATE_REQUEST 4 -#define OPUS_SET_VBR_RATE(x) OPUS_SET_VBR_RATE_REQUEST, __check_int(x) -#define OPUS_GET_VBR_RATE_REQUEST 5 -#define OPUS_GET_VBR_RATE(x) OPUS_GET_VBR_RATE_REQUEST, __check_int_ptr(x) +#define OPUS_SET_COMPLEXITY_REQUEST 10 +#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __check_int(x) +#define OPUS_GET_COMPLEXITY_REQUEST 11 +#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __check_int_ptr(x) + +#define OPUS_SET_INBAND_FEC_FLAG_REQUEST 12 +#define OPUS_SET_INBAND_FEC_FLAG(x) OPUS_SET_INBAND_FEC_FLAG_REQUEST, __check_int(x) +#define OPUS_GET_INBAND_FEC_FLAG_REQUEST 13 +#define OPUS_GET_INBAND_FEC_FLAG(x) OPUS_GET_INBAND_FEC_FLAG_REQUEST, __check_int_ptr(x) + +#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 14 +#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __check_int(x) +#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 15 +#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __check_int_ptr(x) + +#define OPUS_SET_DTX_FLAG_REQUEST 16 +#define OPUS_SET_DTX_FLAG(x) OPUS_SET_DTX_FLAG_REQUEST, __check_int(x) +#define OPUS_GET_DTX_FLAG_REQUEST 17 +#define OPUS_GET_DTX_FLAG(x) OPUS_GET_DTX_FLAG_REQUEST, __check_int_ptr(x) typedef struct OpusEncoder OpusEncoder; typedef struct OpusDecoder OpusDecoder; diff --git a/src/opus_enc.c b/src/opus_enc.c index 283a3cb0..ffd5ab1f 100644 --- a/src/opus_enc.c +++ b/src/opus_enc.c @@ -106,9 +106,6 @@ int main(int argc, char *argv[]) opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(BANDWIDTH_FULLBAND)); opus_encoder_ctl(enc, OPUS_SET_MODE(mode)); - if (vbr) - opus_encoder_ctl(enc, OPUS_SET_VBR_RATE(vbr)); - in = (short*)malloc(frame_size*channels*sizeof(short)); while (!stop) { diff --git a/src/opus_encoder.c b/src/opus_encoder.c index 0cfc30dc..41f2340b 100644 --- a/src/opus_encoder.c +++ b/src/opus_encoder.c @@ -46,7 +46,6 @@ OpusEncoder *opus_encoder_create(int Fs, int channels) char *raw_state; OpusEncoder *st; int ret, silkEncSizeBytes, celtEncSizeBytes; - SKP_SILK_SDK_EncControlStruct encControl; /* Create SILK encoder */ ret = SKP_Silk_SDK_Get_Encoder_Size( &silkEncSizeBytes ); @@ -62,29 +61,35 @@ OpusEncoder *opus_encoder_create(int Fs, int channels) st->Fs = Fs; - /*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 ); + ret = SKP_Silk_SDK_InitEncoder( st->silk_enc, &st->silk_mode ); if( ret ) { /* Handle error */ } + /* default SILK parameters */ + st->silk_mode.API_sampleRate = st->Fs; + st->silk_mode.maxInternalSampleRate = 16000; + st->silk_mode.minInternalSampleRate = 8000; + st->silk_mode.payloadSize_ms = 20; + st->silk_mode.packetLossPercentage = 0; + st->silk_mode.useInBandFEC = 0; + st->silk_mode.useDTX = 0; + st->silk_mode.complexity = 2; + /* Create CELT encoder */ /* Initialize CELT encoder */ st->celt_enc = celt_encoder_init(st->celt_enc, Fs, channels, NULL); st->mode = MODE_HYBRID; st->bandwidth = BANDWIDTH_FULLBAND; - st->vbr_rate = 0; + st->use_vbr = 0; + st->bitrate_bps = 32000; return st; } int opus_encode(OpusEncoder *st, const short *pcm, int frame_size, - unsigned char *data, int bytes_per_packet) + unsigned char *data, int max_data_bytes) { int i; int ret=0; @@ -93,64 +98,64 @@ int opus_encode(OpusEncoder *st, const short *pcm, int frame_size, ec_byte_buffer buf; SKP_SILK_SDK_EncControlStruct encControl; int framerate, period; + int silk_internal_bandwidth; + int bytes_target; + + bytes_target = st->bitrate_bps * frame_size / (st->Fs * 8) - 1; - bytes_per_packet -= 1; data += 1; - ec_byte_writeinit_buffer(&buf, data, bytes_per_packet); + ec_byte_writeinit_buffer(&buf, data, max_data_bytes-1); 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; + /* SILK processing */ + if (st->mode != MODE_CELT_ONLY) + { + st->silk_mode.bitRate = st->bitrate_bps - 8*st->Fs/frame_size; + if( st->mode == MODE_HYBRID ) { + /* FIXME: Tune this offset */ + st->silk_mode.bitRate = (st->silk_mode.bitRate + 12000) / 2; + /* FIXME: Adjust for 10 ms frames */ + } - 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.payloadSize_ms = 1000 * frame_size / st->Fs; + st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs; + if (st->bandwidth == BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->bandwidth == BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + SKP_assert( st->mode == MODE_HYBRID || st->bandwidth == BANDWIDTH_WIDEBAND ); + st->silk_mode.maxInternalSampleRate = 16000; + } + if( st->mode == MODE_HYBRID ) { + /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */ + st->silk_mode.minInternalSampleRate = st->silk_mode.maxInternalSampleRate ; + } - if (st->mode == MODE_HYBRID) - encControl.minInternalSampleRate = 16000; - else - encControl.minInternalSampleRate = 8000; + /* Call SILK encoder for the low band */ + nBytes = max_data_bytes-1; + ret = SKP_Silk_SDK_Encode( st->silk_enc, &st->silk_mode, pcm, frame_size, &enc, &nBytes ); + if( ret ) { + fprintf (stderr, "SILK encode error: %d\n", ret); + /* Handle error */ + } + /* Extract SILK internal bandwidth for signaling in first byte */ + if( st->mode == MODE_SILK_ONLY ) { + if( st->silk_mode.internalSampleRate == 8000 ) { + silk_internal_bandwidth = BANDWIDTH_NARROWBAND; + } else if( st->silk_mode.internalSampleRate == 12000 ) { + silk_internal_bandwidth = BANDWIDTH_MEDIUMBAND; + } else if( st->silk_mode.internalSampleRate == 16000 ) { + silk_internal_bandwidth = BANDWIDTH_WIDEBAND; + } + } + } - 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 %d\n", ret); - /* 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) + /* CELT processing */ + if (st->mode != MODE_SILK_ONLY) { int endband; short pcm_buf[960*2]; + int nb_compr_bytes; switch(st->bandwidth) { @@ -170,28 +175,37 @@ int opus_encode(OpusEncoder *st, const short *pcm, int frame_size, celt_encoder_ctl(st->celt_enc, CELT_SET_END_BAND(endband)); celt_encoder_ctl(st->celt_enc, CELT_SET_CHANNELS(st->stream_channels)); + if (st->mode == MODE_HYBRID) + { + int len; + celt_encoder_ctl(st->celt_enc, CELT_SET_START_BAND(17)); + + len = (ec_enc_tell(&enc, 0)+7)>>3; + if( st->use_vbr ) { + nb_compr_bytes = len + (st->bitrate_bps - 12000) * frame_size / (2 * 8 * st->Fs); + } else { + /* check if SILK used up too much */ + nb_compr_bytes = len > bytes_target ? len : bytes_target; + } + + } else { + celt_encoder_ctl(st->celt_enc, CELT_SET_START_BAND(0)); + nb_compr_bytes = bytes_target; + } + for (i=0;ichannels;i++) pcm_buf[i] = st->delay_buffer[i]; for (;ichannels;i++) pcm_buf[i] = pcm[i-ENCODER_DELAY_COMPENSATION*st->channels]; - celt_encoder_ctl(st->celt_enc, CELT_SET_PREDICTION(1)); + ec_byte_shrink(&buf, nb_compr_bytes); - if (st->vbr_rate != 0) - { - int tmp; - - tmp = (st->mode == MODE_HYBRID) ? (st->vbr_rate-6000)/2 : st->vbr_rate; - 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, frame_size, NULL, bytes_per_packet, &enc); + ret = celt_encode_with_ec(st->celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); for (i=0;ichannels;i++) st->delay_buffer[i] = pcm[frame_size*st->channels-ENCODER_DELAY_COMPENSATION*st->channels+i]; } else { + ret = (ec_enc_tell(&enc, 0)+7)>>3; ec_enc_done(&enc); } @@ -206,7 +220,7 @@ int opus_encode(OpusEncoder *st, const short *pcm, int frame_size, } if (st->mode == MODE_SILK_ONLY) { - data[0] = (st->bandwidth-BANDWIDTH_NARROWBAND)<<5; + data[0] = (silk_internal_bandwidth-BANDWIDTH_NARROWBAND)<<5; data[0] |= (period-2)<<3; } else if (st->mode == MODE_CELT_ONLY) { @@ -216,7 +230,7 @@ int opus_encode(OpusEncoder *st, const short *pcm, int frame_size, data[0] = 0x80; data[0] |= tmp << 5; data[0] |= period<<3; - } else /* Opus */ + } else /* Hybrid */ { data[0] = 0x60; data[0] |= (st->bandwidth-BANDWIDTH_SUPERWIDEBAND)<<4; @@ -248,10 +262,29 @@ void opus_encoder_ctl(OpusEncoder *st, int request, ...) *value = st->mode; } break; + case OPUS_SET_BITRATE_REQUEST: + { + int value = va_arg(ap, int); + st->bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + int *value = va_arg(ap, int*); + *value = st->bitrate_bps; + } + break; case OPUS_SET_BANDWIDTH_REQUEST: { int value = va_arg(ap, int); st->bandwidth = value; + if (st->bandwidth == BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->bandwidth == BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } } break; case OPUS_GET_BANDWIDTH_REQUEST: @@ -260,16 +293,65 @@ void opus_encoder_ctl(OpusEncoder *st, int request, ...) *value = st->bandwidth; } break; - case OPUS_SET_VBR_RATE_REQUEST: + case OPUS_SET_DTX_FLAG_REQUEST: { int value = va_arg(ap, int); - st->vbr_rate = value; + st->silk_mode.useDTX = value; } break; - case OPUS_GET_VBR_RATE_REQUEST: + case OPUS_GET_DTX_FLAG_REQUEST: { int *value = va_arg(ap, int*); - *value = st->vbr_rate; + *value = st->silk_mode.useDTX; + } + break; + case OPUS_SET_COMPLEXITY_REQUEST: + { + int value = va_arg(ap, int); + st->silk_mode.complexity = value; + } + break; + case OPUS_GET_COMPLEXITY_REQUEST: + { + int *value = va_arg(ap, int*); + *value = st->silk_mode.complexity; + } + break; + case OPUS_SET_INBAND_FEC_FLAG_REQUEST: + { + int value = va_arg(ap, int); + st->silk_mode.useInBandFEC = value; + } + break; + case OPUS_GET_INBAND_FEC_FLAG_REQUEST: + { + int *value = va_arg(ap, int*); + *value = st->silk_mode.useInBandFEC; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + int value = va_arg(ap, int); + st->silk_mode.packetLossPercentage = value; + } + break; + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + { + int *value = va_arg(ap, int*); + *value = st->silk_mode.packetLossPercentage; + } + break; + case OPUS_SET_VBR_FLAG_REQUEST: + { + int value = va_arg(ap, int); + st->use_vbr = value; + st->silk_mode.useCBR = 1-value; + } + break; + case OPUS_GET_VBR_FLAG_REQUEST: + { + int *value = va_arg(ap, int*); + *value = st->use_vbr; } break; default: diff --git a/src/opus_encoder.h b/src/opus_encoder.h index d6b21369..9636e2af 100644 --- a/src/opus_encoder.h +++ b/src/opus_encoder.h @@ -41,15 +41,17 @@ struct OpusEncoder { CELTEncoder *celt_enc; + SKP_SILK_SDK_EncControlStruct silk_mode; void *silk_enc; int channels; int stream_channels; int mode; int bandwidth; - int vbr_rate; /* Sampling rate (at the API level) */ int Fs; + int use_vbr; + int bitrate_bps; short delay_buffer[ENCODER_DELAY_COMPENSATION*2]; }; diff --git a/src/test_opus.c b/src/test_opus.c index c7d6cbbd..27664219 100644 --- a/src/test_opus.c +++ b/src/test_opus.c @@ -112,9 +112,6 @@ int main(int argc, char *argv[]) opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(BANDWIDTH_FULLBAND)); opus_encoder_ctl(enc, OPUS_SET_MODE(mode)); - if (vbr) - opus_encoder_ctl(enc, OPUS_SET_VBR_RATE(vbr)); - skip = 5*rate/1000 + 10; in = (short*)malloc(frame_size*channels*sizeof(short));