mirror of
https://github.com/xiph/opus.git
synced 2025-06-07 07:50:51 +00:00
Moving FEC decision to the Opus encoder level (from SILK level)
This commit is contained in:
parent
099fc05ebf
commit
2b011b64d8
6 changed files with 57 additions and 27 deletions
|
@ -77,6 +77,9 @@ typedef struct {
|
||||||
/* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */
|
/* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */
|
||||||
opus_int useInBandFEC;
|
opus_int useInBandFEC;
|
||||||
|
|
||||||
|
/* I: Flag to actually code in-band Forward Error Correction (FEC) in the current packet; 0/1 */
|
||||||
|
opus_int LBRR_coded;
|
||||||
|
|
||||||
/* I: Flag to enable discontinuous transmission (DTX); 0/1 */
|
/* I: Flag to enable discontinuous transmission (DTX); 0/1 */
|
||||||
opus_int useDTX;
|
opus_int useDTX;
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ static opus_int silk_setup_complexity(
|
||||||
|
|
||||||
static OPUS_INLINE opus_int silk_setup_LBRR(
|
static OPUS_INLINE opus_int silk_setup_LBRR(
|
||||||
silk_encoder_state *psEncC, /* I/O */
|
silk_encoder_state *psEncC, /* I/O */
|
||||||
const opus_int32 TargetRate_bps /* I */
|
const silk_EncControlStruct *encControl /* I */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +65,6 @@ static OPUS_INLINE opus_int silk_setup_LBRR(
|
||||||
opus_int silk_control_encoder(
|
opus_int silk_control_encoder(
|
||||||
silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
|
silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
|
||||||
silk_EncControlStruct *encControl, /* I Control structure */
|
silk_EncControlStruct *encControl, /* I Control structure */
|
||||||
const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
|
|
||||||
const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
|
const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
|
||||||
const opus_int channelNb, /* I Channel number */
|
const opus_int channelNb, /* I Channel number */
|
||||||
const opus_int force_fs_kHz
|
const opus_int force_fs_kHz
|
||||||
|
@ -125,7 +124,7 @@ opus_int silk_control_encoder(
|
||||||
/********************************************/
|
/********************************************/
|
||||||
/* Set LBRR usage */
|
/* Set LBRR usage */
|
||||||
/********************************************/
|
/********************************************/
|
||||||
ret += silk_setup_LBRR( &psEnc->sCmn, TargetRate_bps );
|
ret += silk_setup_LBRR( &psEnc->sCmn, encControl );
|
||||||
|
|
||||||
psEnc->sCmn.controlled_since_last_payload = 1;
|
psEnc->sCmn.controlled_since_last_payload = 1;
|
||||||
|
|
||||||
|
@ -403,25 +402,14 @@ static opus_int silk_setup_complexity(
|
||||||
|
|
||||||
static OPUS_INLINE opus_int silk_setup_LBRR(
|
static OPUS_INLINE opus_int silk_setup_LBRR(
|
||||||
silk_encoder_state *psEncC, /* I/O */
|
silk_encoder_state *psEncC, /* I/O */
|
||||||
const opus_int32 TargetRate_bps /* I */
|
const silk_EncControlStruct *encControl /* I */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR;
|
opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR;
|
||||||
opus_int32 LBRR_rate_thres_bps;
|
|
||||||
|
|
||||||
LBRR_in_previous_packet = psEncC->LBRR_enabled;
|
LBRR_in_previous_packet = psEncC->LBRR_enabled;
|
||||||
psEncC->LBRR_enabled = 0;
|
psEncC->LBRR_enabled = encControl->LBRR_coded;
|
||||||
if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) {
|
if( psEncC->LBRR_enabled ) {
|
||||||
if( psEncC->fs_kHz == 8 ) {
|
|
||||||
LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS;
|
|
||||||
} else if( psEncC->fs_kHz == 12 ) {
|
|
||||||
LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS;
|
|
||||||
} else {
|
|
||||||
LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS;
|
|
||||||
}
|
|
||||||
LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) );
|
|
||||||
|
|
||||||
if( TargetRate_bps > LBRR_rate_thres_bps ) {
|
|
||||||
/* Set gain increase for coding LBRR excitation */
|
/* Set gain increase for coding LBRR excitation */
|
||||||
if( LBRR_in_previous_packet == 0 ) {
|
if( LBRR_in_previous_packet == 0 ) {
|
||||||
/* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
|
/* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
|
||||||
|
@ -429,8 +417,6 @@ static OPUS_INLINE opus_int silk_setup_LBRR(
|
||||||
} else {
|
} else {
|
||||||
psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 );
|
psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 );
|
||||||
}
|
}
|
||||||
psEncC->LBRR_enabled = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -237,7 +237,7 @@ opus_int silk_Encode( /* O Returns error co
|
||||||
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
|
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
|
||||||
/* Force the side channel to the same rate as the mid */
|
/* Force the side channel to the same rate as the mid */
|
||||||
opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
|
opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
|
||||||
if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, TargetRate_bps, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
|
if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
|
||||||
silk_assert( 0 );
|
silk_assert( 0 );
|
||||||
RESTORE_STACK;
|
RESTORE_STACK;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -81,7 +81,6 @@ opus_int silk_init_encoder(
|
||||||
opus_int silk_control_encoder(
|
opus_int silk_control_encoder(
|
||||||
silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
|
silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
|
||||||
silk_EncControlStruct *encControl, /* I Control structure */
|
silk_EncControlStruct *encControl, /* I Control structure */
|
||||||
const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
|
|
||||||
const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
|
const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
|
||||||
const opus_int channelNb, /* I Channel number */
|
const opus_int channelNb, /* I Channel number */
|
||||||
const opus_int force_fs_kHz
|
const opus_int force_fs_kHz
|
||||||
|
|
|
@ -79,7 +79,6 @@ opus_int silk_init_encoder(
|
||||||
opus_int silk_control_encoder(
|
opus_int silk_control_encoder(
|
||||||
silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */
|
silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */
|
||||||
silk_EncControlStruct *encControl, /* I Control structure */
|
silk_EncControlStruct *encControl, /* I Control structure */
|
||||||
const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
|
|
||||||
const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
|
const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
|
||||||
const opus_int channelNb, /* I Channel number */
|
const opus_int channelNb, /* I Channel number */
|
||||||
const opus_int force_fs_kHz
|
const opus_int force_fs_kHz
|
||||||
|
|
|
@ -156,6 +156,14 @@ static const opus_int32 mode_thresholds[2][2] = {
|
||||||
{ 36000, 16000}, /* stereo */
|
{ 36000, 16000}, /* stereo */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const opus_int32 fec_thresholds[] = {
|
||||||
|
12000, 1000, /* NB */
|
||||||
|
14000, 1000, /* MB */
|
||||||
|
16000, 1000, /* WB */
|
||||||
|
20000, 1000, /* SWB */
|
||||||
|
22000, 1000, /* FB */
|
||||||
|
};
|
||||||
|
|
||||||
int opus_encoder_get_size(int channels)
|
int opus_encoder_get_size(int channels)
|
||||||
{
|
{
|
||||||
int silkEncSizeBytes, celtEncSizeBytes;
|
int silkEncSizeBytes, celtEncSizeBytes;
|
||||||
|
@ -943,6 +951,39 @@ opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int3
|
||||||
return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower)));
|
return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int decide_fec(int useInBandFEC, int PacketLoss_perc, int last_fec, int mode, int *bandwidth, opus_int32 rate)
|
||||||
|
{
|
||||||
|
int orig_bandwidth;
|
||||||
|
if (!useInBandFEC || PacketLoss_perc == 0 || mode == MODE_CELT_ONLY)
|
||||||
|
return 0;
|
||||||
|
orig_bandwidth = *bandwidth;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
opus_int32 hysteresis;
|
||||||
|
opus_int32 LBRR_rate_thres_bps;
|
||||||
|
/* Compute threshold for using FEC at the current bandwidth setting */
|
||||||
|
LBRR_rate_thres_bps = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND)];
|
||||||
|
hysteresis = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND) + 1];
|
||||||
|
if (last_fec == 1) LBRR_rate_thres_bps -= hysteresis;
|
||||||
|
if (last_fec == 0) LBRR_rate_thres_bps += hysteresis;
|
||||||
|
LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps,
|
||||||
|
125 - silk_min( PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) );
|
||||||
|
/* If loss <= 5%, we look at whether we have enough rate to enable FEC.
|
||||||
|
If loss > 5%, we decrease the bandwidth until we can enable FEC. */
|
||||||
|
if (rate > LBRR_rate_thres_bps)
|
||||||
|
return 1;
|
||||||
|
else if (PacketLoss_perc <= 5)
|
||||||
|
return 0;
|
||||||
|
else if (*bandwidth > OPUS_BANDWIDTH_NARROWBAND)
|
||||||
|
(*bandwidth)--;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Couldn't find any bandwidth to enable FEC, keep original bandwidth. */
|
||||||
|
*bandwidth = orig_bandwidth;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int compute_silk_rate_for_hybrid(int rate, int bandwidth, int frame20ms, int vbr) {
|
static int compute_silk_rate_for_hybrid(int rate, int bandwidth, int frame20ms, int vbr) {
|
||||||
int entry;
|
int entry;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1543,6 +1584,8 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
|
||||||
st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth);
|
st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
st->silk_mode.LBRR_coded = decide_fec(st->silk_mode.useInBandFEC, st->silk_mode.packetLossPercentage,
|
||||||
|
st->silk_mode.LBRR_coded, st->mode, &st->bandwidth, equiv_rate);
|
||||||
celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth));
|
celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth));
|
||||||
|
|
||||||
/* CELT mode doesn't support mediumband, use wideband instead */
|
/* CELT mode doesn't support mediumband, use wideband instead */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue