diff options
Diffstat (limited to 'thirdparty/opus/opus_multistream_encoder.c')
-rw-r--r-- | thirdparty/opus/opus_multistream_encoder.c | 183 |
1 files changed, 157 insertions, 26 deletions
diff --git a/thirdparty/opus/opus_multistream_encoder.c b/thirdparty/opus/opus_multistream_encoder.c index 9e85773573..e722e31ab8 100644 --- a/thirdparty/opus/opus_multistream_encoder.c +++ b/thirdparty/opus/opus_multistream_encoder.c @@ -70,13 +70,22 @@ typedef void (*opus_copy_channel_in_func)( int frame_size ); +typedef enum { + MAPPING_TYPE_NONE, + MAPPING_TYPE_SURROUND +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + , /* Do not include comma at end of enumerator list */ + MAPPING_TYPE_AMBISONICS +#endif +} MappingType; + struct OpusMSEncoder { ChannelLayout layout; int arch; int lfe_stream; int application; int variable_duration; - int surround; + MappingType mapping_type; opus_int32 bitrate_bps; float subframe_mem[3]; /* Encoder states go here */ @@ -242,6 +251,7 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b upsample = resampling_factor(rate); frame_size = len*upsample; + /* LM = log2(frame_size / 120) */ for (LM=0;LM<celt_mode->maxLM;LM++) if (celt_mode->shortMdctSize<<LM==frame_size) break; @@ -398,6 +408,12 @@ opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_ { nb_streams=channels; nb_coupled_streams=0; +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + } else if (mapping_family==254) + { + nb_streams=channels; + nb_coupled_streams=0; +#endif } else return 0; size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); @@ -408,7 +424,6 @@ opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_ return size; } - static int opus_multistream_encoder_init_impl( OpusMSEncoder *st, opus_int32 Fs, @@ -417,7 +432,7 @@ static int opus_multistream_encoder_init_impl( int coupled_streams, const unsigned char *mapping, int application, - int surround + MappingType mapping_type ) { int coupled_size; @@ -434,7 +449,7 @@ static int opus_multistream_encoder_init_impl( st->layout.nb_streams = streams; st->layout.nb_coupled_streams = coupled_streams; st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0; - if (!surround) + if (mapping_type != MAPPING_TYPE_SURROUND) st->lfe_stream = -1; st->bitrate_bps = OPUS_AUTO; st->application = application; @@ -463,12 +478,12 @@ static int opus_multistream_encoder_init_impl( if(ret!=OPUS_OK)return ret; ptr += align(mono_size); } - if (surround) + if (mapping_type == MAPPING_TYPE_SURROUND) { OPUS_CLEAR(ms_get_preemph_mem(st), channels); OPUS_CLEAR(ms_get_window_mem(st), channels*120); } - st->surround = surround; + st->mapping_type = mapping_type; return OPUS_OK; } @@ -482,7 +497,9 @@ int opus_multistream_encoder_init( int application ) { - return opus_multistream_encoder_init_impl(st, Fs, channels, streams, coupled_streams, mapping, application, 0); + return opus_multistream_encoder_init_impl(st, Fs, channels, streams, + coupled_streams, mapping, + application, MAPPING_TYPE_NONE); } int opus_multistream_surround_encoder_init( @@ -496,6 +513,8 @@ int opus_multistream_surround_encoder_init( int application ) { + MappingType mapping_type; + if ((channels>255) || (channels<1)) return OPUS_BAD_ARG; st->lfe_stream = -1; @@ -530,10 +549,32 @@ int opus_multistream_surround_encoder_init( *coupled_streams=0; for(i=0;i<channels;i++) mapping[i] = i; +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + } else if (mapping_family==254) + { + int i; + *streams=channels; + *coupled_streams=0; + for(i=0;i<channels;i++) + mapping[i] = i; +#endif } else return OPUS_UNIMPLEMENTED; - return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, *coupled_streams, - mapping, application, channels>2&&mapping_family==1); + + if (channels>2 && mapping_family==1) { + mapping_type = MAPPING_TYPE_SURROUND; +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + } else if (mapping_family==254) + { + mapping_type = MAPPING_TYPE_AMBISONICS; +#endif + } else + { + mapping_type = MAPPING_TYPE_NONE; + } + return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, + *coupled_streams, mapping, + application, mapping_type); } OpusMSEncoder *opus_multistream_encoder_create( @@ -618,24 +659,19 @@ OpusMSEncoder *opus_multistream_surround_encoder_create( return st; } -static opus_int32 surround_rate_allocation( +static void surround_rate_allocation( OpusMSEncoder *st, opus_int32 *rate, - int frame_size + int frame_size, + opus_int32 Fs ) { int i; opus_int32 channel_rate; - opus_int32 Fs; - char *ptr; int stream_offset; int lfe_offset; int coupled_ratio; /* Q8 */ int lfe_ratio; /* Q8 */ - opus_int32 rate_sum=0; - - ptr = (char*)st + align(sizeof(OpusMSEncoder)); - opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); if (st->bitrate_bps > st->layout.nb_channels*40000) stream_offset = 20000; @@ -688,6 +724,88 @@ static opus_int32 surround_rate_allocation( rate[i] = stream_offset+channel_rate; else rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8); + } +} + +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS +static void ambisonics_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + int non_mono_rate; + int total_rate; + + /* The mono channel gets (rate_ratio_num / rate_ratio_den) times as many bits + * as all other channels */ + const int rate_ratio_num = 4; + const int rate_ratio_den = 3; + const int num_channels = st->layout.nb_streams; + + if (st->bitrate_bps==OPUS_AUTO) + { + total_rate = num_channels * (20000 + st->layout.nb_streams*(Fs+60*Fs/frame_size)); + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + total_rate = num_channels * 320000; + } else { + total_rate = st->bitrate_bps; + } + + /* Let y be the non-mono rate and let p, q be integers such that the mono + * channel rate is (p/q) * y. + * Also let T be the total bitrate to allocate. Then + * (n - 1) y + (p/q) y = T + * y = (T q) / (qn - q + p) + */ + non_mono_rate = + total_rate * rate_ratio_den + / (rate_ratio_den*num_channels + rate_ratio_num - rate_ratio_den); + +#ifndef FIXED_POINT + if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50) + { + opus_int32 bonus = 60*(Fs/frame_size-50); + non_mono_rate += bonus; + } +#endif + + rate[0] = total_rate - (num_channels - 1) * non_mono_rate; + for (i=1;i<st->layout.nb_streams;i++) + { + rate[i] = non_mono_rate; + } +} +#endif /* ENABLE_EXPERIMENTAL_AMBISONICS */ + +static opus_int32 rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size + ) +{ + int i; + opus_int32 rate_sum=0; + opus_int32 Fs; + char *ptr; + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + ambisonics_rate_allocation(st, rate, frame_size, Fs); + } else +#endif + { + surround_rate_allocation(st, rate, frame_size, Fs); + } + + for (i=0;i<st->layout.nb_streams;i++) + { rate[i] = IMAX(rate[i], 500); rate_sum += rate[i]; } @@ -730,7 +848,7 @@ static int opus_multistream_encode_native opus_int32 smallest_packet; ALLOC_STACK; - if (st->surround) + if (st->mapping_type == MAPPING_TYPE_SURROUND) { preemph_mem = ms_get_preemph_mem(st); mem = ms_get_window_mem(st); @@ -784,13 +902,13 @@ static int opus_multistream_encode_native mono_size = opus_encoder_get_size(1); ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16); - if (st->surround) + if (st->mapping_type == MAPPING_TYPE_SURROUND) { surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in, st->arch); } /* Compute bitrate allocation between streams (this could be a lot better) */ - rate_sum = surround_rate_allocation(st, bitrates, frame_size); + rate_sum = rate_allocation(st, bitrates, frame_size); if (!vbr) { @@ -813,7 +931,7 @@ static int opus_multistream_encode_native else ptr += align(mono_size); opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s])); - if (st->surround) + if (st->mapping_type == MAPPING_TYPE_SURROUND) { opus_int32 equiv_rate; equiv_rate = st->bitrate_bps; @@ -834,6 +952,11 @@ static int opus_multistream_encode_native opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); } } +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + } +#endif } ptr = (char*)st + align(sizeof(OpusMSEncoder)); @@ -845,6 +968,7 @@ static int opus_multistream_encode_native int len; int curr_max; int c1, c2; + int ret; opus_repacketizer_init(&rp); enc = (OpusEncoder*)ptr; @@ -859,7 +983,7 @@ static int opus_multistream_encode_native (*copy_channel_in)(buf+1, 2, pcm, st->layout.nb_channels, right, frame_size); ptr += align(coupled_size); - if (st->surround) + if (st->mapping_type == MAPPING_TYPE_SURROUND) { for (i=0;i<21;i++) { @@ -875,7 +999,7 @@ static int opus_multistream_encode_native (*copy_channel_in)(buf, 1, pcm, st->layout.nb_channels, chan, frame_size); ptr += align(mono_size); - if (st->surround) + if (st->mapping_type == MAPPING_TYPE_SURROUND) { for (i=0;i<21;i++) bandLogE[i] = bandSMR[21*chan+i]; @@ -883,7 +1007,7 @@ static int opus_multistream_encode_native c1 = chan; c2 = -1; } - if (st->surround) + if (st->mapping_type == MAPPING_TYPE_SURROUND) opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE)); /* number of bytes left (+Toc) */ curr_max = max_data_bytes - tot_size; @@ -904,7 +1028,14 @@ static int opus_multistream_encode_native /* We need to use the repacketizer to add the self-delimiting lengths while taking into account the fact that the encoder can now return more than one frame at a time (e.g. 60 ms CELT-only) */ - opus_repacketizer_cat(&rp, tmp_data, len); + ret = opus_repacketizer_cat(&rp, tmp_data, len); + /* If the opus_repacketizer_cat() fails, then something's seriously wrong + with the encoder. */ + if (ret != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1); data += len; @@ -1183,7 +1314,7 @@ int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) { int s; st->subframe_mem[0] = st->subframe_mem[1] = st->subframe_mem[2] = 0; - if (st->surround) + if (st->mapping_type == MAPPING_TYPE_SURROUND) { OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels); OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120); |