#include <stdarg.h>
#include "float_cast.h"
#include "os_support.h"
-#include "analysis.h"
+#include "mathops.h"
+#include "mdct.h"
+#include "modes.h"
+#include "bands.h"
+#include "quant_bands.h"
typedef struct {
int nb_streams;
{5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */
};
+typedef void (*opus_copy_channel_in_func)(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+);
+
struct OpusMSEncoder {
- TonalityAnalysisState analysis;
ChannelLayout layout;
int lfe_stream;
+ int application;
int variable_duration;
int surround;
opus_int32 bitrate_bps;
- opus_val32 subframe_mem[3];
+ float subframe_mem[3];
/* Encoder states go here */
+ /* then opus_val32 window_mem[channels*120]; */
+ /* then opus_val32 preemph_mem[channels]; */
};
+static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st)
+{
+ int s;
+ char *ptr;
+ int coupled_size, mono_size;
+
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ return (opus_val32*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32));
+}
+
+static opus_val32 *ms_get_window_mem(OpusMSEncoder *st)
+{
+ int s;
+ char *ptr;
+ int coupled_size, mono_size;
+
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ return (opus_val32*)ptr;
+}
static int validate_encoder_layout(const ChannelLayout *layout)
{
return 1;
}
+static void channel_pos(int channels, int pos[8])
+{
+ /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */
+ if (channels==4)
+ {
+ pos[0]=1;
+ pos[1]=3;
+ pos[2]=1;
+ pos[3]=3;
+ } else if (channels==3||channels==5||channels==6)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=0;
+ } else if (channels==7)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=2;
+ pos[6]=0;
+ } else if (channels==8)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=1;
+ pos[6]=3;
+ pos[7]=0;
+ }
+}
+
+#if 1
+/* Computes a rough approximation of log2(2^a + 2^b) */
+static opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+ opus_val16 max;
+ opus_val32 diff;
+ opus_val16 frac;
+ static const opus_val16 diff_table[17] = {
+ QCONST16(0.5000000f, DB_SHIFT), QCONST16(0.2924813f, DB_SHIFT), QCONST16(0.1609640f, DB_SHIFT), QCONST16(0.0849625f, DB_SHIFT),
+ QCONST16(0.0437314f, DB_SHIFT), QCONST16(0.0221971f, DB_SHIFT), QCONST16(0.0111839f, DB_SHIFT), QCONST16(0.0056136f, DB_SHIFT),
+ QCONST16(0.0028123f, DB_SHIFT)
+ };
+ int low;
+ if (a>b)
+ {
+ max = a;
+ diff = SUB32(EXTEND32(a),EXTEND32(b));
+ } else {
+ max = b;
+ diff = SUB32(EXTEND32(b),EXTEND32(a));
+ }
+ if (diff >= QCONST16(8.f, DB_SHIFT))
+ return max;
+#ifdef FIXED_POINT
+ low = SHR32(diff, DB_SHIFT-1);
+ frac = SHL16(diff - SHL16(low, DB_SHIFT-1), 16-DB_SHIFT);
+#else
+ low = (int)floor(2*diff);
+ frac = 2*diff - low;
+#endif
+ return max + diff_table[low] + MULT16_16_Q15(frac, SUB16(diff_table[low+1], diff_table[low]));
+}
+#else
+opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+ return log2(pow(4, a)+ pow(4, b))/2;
+}
+#endif
+
+void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem,
+ int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in
+)
+{
+ int c;
+ int i;
+ int LM;
+ int pos[8] = {0};
+ int upsample;
+ int frame_size;
+ opus_val16 channel_offset;
+ opus_val32 bandE[21];
+ opus_val16 maskLogE[3][21];
+ VARDECL(opus_val32, in);
+ VARDECL(opus_val16, x);
+ VARDECL(opus_val32, freq);
+ SAVE_STACK;
+
+ upsample = resampling_factor(rate);
+ frame_size = len*upsample;
+
+ for (LM=0;LM<celt_mode->maxLM;LM++)
+ if (celt_mode->shortMdctSize<<LM==frame_size)
+ break;
+
+ ALLOC(in, frame_size+overlap, opus_val32);
+ ALLOC(x, len, opus_val16);
+ ALLOC(freq, frame_size, opus_val32);
+
+ channel_pos(channels, pos);
+
+ for (c=0;c<3;c++)
+ for (i=0;i<21;i++)
+ maskLogE[c][i] = -QCONST16(28.f, DB_SHIFT);
+
+ for (c=0;c<channels;c++)
+ {
+ OPUS_COPY(in, mem+c*overlap, overlap);
+ (*copy_channel_in)(x, 1, pcm, channels, c, len);
+ celt_preemphasis(x, in+overlap, frame_size, 1, upsample, celt_mode->preemph, preemph_mem+c, 0);
+ clt_mdct_forward(&celt_mode->mdct, in, freq, celt_mode->window, overlap, celt_mode->maxLM-LM, 1);
+ if (upsample != 1)
+ {
+ int bound = len;
+ for (i=0;i<bound;i++)
+ freq[i] *= upsample;
+ for (;i<frame_size;i++)
+ freq[i] = 0;
+ }
+
+ compute_band_energies(celt_mode, freq, bandE, 21, 1, 1<<LM);
+ amp2Log2(celt_mode, 21, 21, bandE, bandLogE+21*c, 1);
+ /* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */
+ for (i=1;i<21;i++)
+ bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i-1]-QCONST16(1.f, DB_SHIFT));
+ for (i=19;i>=0;i--)
+ bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i+1]-QCONST16(2.f, DB_SHIFT));
+ if (pos[c]==1)
+ {
+ for (i=0;i<21;i++)
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]);
+ } else if (pos[c]==3)
+ {
+ for (i=0;i<21;i++)
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]);
+ } else if (pos[c]==2)
+ {
+ for (i=0;i<21;i++)
+ {
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT));
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT));
+ }
+ }
+#if 0
+ for (i=0;i<21;i++)
+ printf("%f ", bandLogE[21*c+i]);
+ float sum=0;
+ for (i=0;i<21;i++)
+ sum += bandLogE[21*c+i];
+ printf("%f ", sum/21);
+#endif
+ OPUS_COPY(mem+c*overlap, in+frame_size, overlap);
+ }
+ for (i=0;i<21;i++)
+ maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]);
+ channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1)));
+ for (c=0;c<3;c++)
+ for (i=0;i<21;i++)
+ maskLogE[c][i] += channel_offset;
+#if 0
+ for (c=0;c<3;c++)
+ {
+ for (i=0;i<21;i++)
+ printf("%f ", maskLogE[c][i]);
+ }
+#endif
+ for (c=0;c<channels;c++)
+ {
+ opus_val16 *mask;
+ if (pos[c]!=0)
+ {
+ mask = &maskLogE[pos[c]-1][0];
+ for (i=0;i<21;i++)
+ bandLogE[21*c+i] = bandLogE[21*c+i] - mask[i];
+ } else {
+ for (i=0;i<21;i++)
+ bandLogE[21*c+i] = 0;
+ }
+#if 0
+ for (i=0;i<21;i++)
+ printf("%f ", bandLogE[21*c+i]);
+ printf("\n");
+#endif
+#if 0
+ float sum=0;
+ for (i=0;i<21;i++)
+ sum += bandLogE[21*c+i];
+ printf("%f ", sum/(float)QCONST32(21.f, DB_SHIFT));
+ printf("\n");
+#endif
+ }
+ RESTORE_STACK;
+}
opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
{
return 0;
size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
if (channels>2)
- size += align(opus_encoder_get_size(2));
+ {
+ size += channels*(120*sizeof(opus_val32) + sizeof(opus_val32));
+ }
return size;
}
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;
- OPUS_CLEAR(&st->analysis,1);
if (!surround)
st->lfe_stream = -1;
st->bitrate_bps = OPUS_AUTO;
+ st->application = application;
st->variable_duration = OPUS_FRAMESIZE_ARG;
for (i=0;i<st->layout.nb_channels;i++)
st->layout.mapping[i] = mapping[i];
if(ret!=OPUS_OK)return ret;
ptr += align(mono_size);
}
- if (surround && st->layout.nb_channels>2)
+ if (surround)
{
- OpusEncoder *downmix_enc;
- downmix_enc = (OpusEncoder*)ptr;
- ret = opus_encoder_init(downmix_enc, Fs, 2, OPUS_APPLICATION_AUDIO);
- if(ret!=OPUS_OK)return ret;
+ OPUS_CLEAR(ms_get_preemph_mem(st), channels);
+ OPUS_CLEAR(ms_get_window_mem(st), channels*120);
}
st->surround = surround;
return OPUS_OK;
int application
)
{
+ if ((channels>255) || (channels<1))
+ return OPUS_BAD_ARG;
st->lfe_stream = -1;
if (mapping_family==0)
{
mapping[i] = i;
} else
return OPUS_UNIMPLEMENTED;
- opus_multistream_encoder_init_impl(st, Fs, channels, *streams, *coupled_streams, mapping, application, 1);
- return OPUS_OK;
+ return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, *coupled_streams,
+ mapping, application, channels>2&&mapping_family==1);
}
OpusMSEncoder *opus_multistream_encoder_create(
return st;
}
-typedef void (*opus_copy_channel_in_func)(
- opus_val16 *dst,
- int dst_stride,
- const void *src,
- int src_stride,
- int src_channel,
- int frame_size
-);
-
-typedef void (*opus_surround_downmix_funct)(
- opus_val16 *dst,
- const void *src,
- int channels,
- int frame_size
-);
-
static void surround_rate_allocation(
OpusMSEncoder *st,
opus_int32 *rate,
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;
+ else
+ stream_offset = st->bitrate_bps/st->layout.nb_channels/2;
+ stream_offset += 60*(Fs/frame_size-50);
/* We start by giving each stream (coupled or uncoupled) the same bitrate.
This models the main saving of coupled channels over uncoupled. */
- stream_offset = 20000;
/* The LFE stream is an exception to the above and gets fewer bits. */
- lfe_offset = 3500;
+ lfe_offset = 3500 + 60*(Fs/frame_size-50);
/* Coupled streams get twice the mono rate after the first 20 kb/s. */
coupled_ratio = 512;
/* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
OpusMSEncoder *st,
opus_copy_channel_in_func copy_channel_in,
const void *pcm,
- int frame_size,
+ int analysis_frame_size,
unsigned char *data,
opus_int32 max_data_bytes,
int lsb_depth,
- opus_surround_downmix_funct surround_downmix
-#ifndef FIXED_POINT
- , downmix_func downmix
- , const void *pcm_analysis
-#endif
+ downmix_func downmix
)
{
opus_int32 Fs;
char *ptr;
int tot_size;
VARDECL(opus_val16, buf);
+ VARDECL(opus_val16, bandSMR);
unsigned char tmp_data[MS_FRAME_TMP];
OpusRepacketizer rp;
- opus_int32 complexity;
- AnalysisInfo analysis_info;
+ opus_int32 vbr;
const CELTMode *celt_mode;
opus_int32 bitrates[256];
opus_val16 bandLogE[42];
- opus_val16 bandLogE_mono[21];
+ opus_val32 *mem = NULL;
+ opus_val32 *preemph_mem=NULL;
+ int frame_size;
ALLOC_STACK;
+ if (st->surround)
+ {
+ preemph_mem = ms_get_preemph_mem(st);
+ mem = ms_get_window_mem(st);
+ }
+
ptr = (char*)st + align(sizeof(OpusMSEncoder));
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
- opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_COMPLEXITY(&complexity));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr));
opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
- if (400*frame_size < Fs)
- {
- RESTORE_STACK;
- return OPUS_BAD_ARG;
- }
-#ifndef FIXED_POINT
- analysis_info.valid = 0;
- if (complexity >= 7 && Fs==48000)
{
opus_int32 delay_compensation;
int channels;
channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
delay_compensation -= Fs/400;
-
- frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm_analysis,
- frame_size, st->variable_duration, channels, Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix, &analysis_info);
- } else
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, channels, Fs, st->bitrate_bps,
+ delay_compensation, downmix
+#ifndef DISABLE_FLOAT_API
+ , st->subframe_mem
#endif
+ );
+ }
+
+ if (400*frame_size < Fs)
{
- frame_size = frame_size_select(frame_size, st->variable_duration, Fs);
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
}
/* Validate frame_size before using it to allocate stack space.
This mirrors the checks in opus_encode[_float](). */
coupled_size = opus_encoder_get_size(2);
mono_size = opus_encoder_get_size(1);
- if (st->surround && st->layout.nb_channels>2)
+ ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16);
+ if (st->surround)
{
- int i;
- unsigned char dummy[512];
- /* Temporary kludge -- remove */
- OpusEncoder *downmix_enc;
-
- ptr = (char*)st + align(sizeof(OpusMSEncoder));
- for (s=0;s<st->layout.nb_streams;s++)
- {
- if (s < st->layout.nb_coupled_streams)
- ptr += align(coupled_size);
- else
- ptr += align(mono_size);
- }
- downmix_enc = (OpusEncoder*)ptr;
- surround_downmix(buf, pcm, st->layout.nb_channels, frame_size);
- opus_encoder_ctl(downmix_enc, OPUS_SET_ENERGY_SAVE(bandLogE));
- opus_encoder_ctl(downmix_enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
- opus_encoder_ctl(downmix_enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
- opus_encoder_ctl(downmix_enc, OPUS_SET_FORCE_CHANNELS(2));
- opus_encode_native(downmix_enc, buf, frame_size, dummy, 512, lsb_depth
-#ifndef FIXED_POINT
- , &analysis_info
-#endif
- );
- for(i=0;i<21;i++)
- bandLogE_mono[i] = MAX16(bandLogE[i], bandLogE[21+i]);
+ surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in);
}
if (max_data_bytes < 4*st->layout.nb_streams-1)
/* Compute bitrate allocation between streams (this could be a lot better) */
surround_rate_allocation(st, bitrates, frame_size);
+ if (!vbr)
+ max_data_bytes = IMIN(max_data_bytes, 3*st->bitrate_bps/(3*8*Fs/frame_size));
+
ptr = (char*)st + align(sizeof(OpusMSEncoder));
for (s=0;s<st->layout.nb_streams;s++)
{
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s]));
if (st->surround)
{
- opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
- opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
+ opus_int32 equiv_rate;
+ equiv_rate = st->bitrate_bps;
+ if (frame_size*50 < Fs)
+ equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels;
+ if (equiv_rate > 10000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
+ else if (equiv_rate > 7000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
+ else if (equiv_rate > 5000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
+ else
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
if (s < st->layout.nb_coupled_streams)
+ {
+ /* To preserve the spatial image, force stereo CELT on coupled streams */
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2));
+ }
}
}
OpusEncoder *enc;
int len;
int curr_max;
+ int c1, c2;
opus_repacketizer_init(&rp);
enc = (OpusEncoder*)ptr;
if (s < st->layout.nb_coupled_streams)
{
+ int i;
int left, right;
left = get_left_channel(&st->layout, s, -1);
right = get_right_channel(&st->layout, s, -1);
(*copy_channel_in)(buf+1, 2,
pcm, st->layout.nb_channels, right, frame_size);
ptr += align(coupled_size);
- /* FIXME: This isn't correct for the coupled center channels in
- 6.1 surround configuration */
if (st->surround)
- opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
+ {
+ for (i=0;i<21;i++)
+ {
+ bandLogE[i] = bandSMR[21*left+i];
+ bandLogE[21+i] = bandSMR[21*right+i];
+ }
+ }
+ c1 = left;
+ c2 = right;
} else {
+ int i;
int chan = get_mono_channel(&st->layout, s, -1);
(*copy_channel_in)(buf, 1,
pcm, st->layout.nb_channels, chan, frame_size);
ptr += align(mono_size);
if (st->surround)
- opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE_mono));
+ {
+ for (i=0;i<21;i++)
+ bandLogE[i] = bandSMR[21*chan+i];
+ }
+ c1 = chan;
+ c2 = -1;
}
+ if (st->surround)
+ opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
/* number of bytes left (+Toc) */
curr_max = max_data_bytes - tot_size;
/* Reserve three bytes for the last stream and four for the others */
curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1);
curr_max = IMIN(curr_max,MS_FRAME_TMP);
- len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth
-#ifndef FIXED_POINT
- , &analysis_info
-#endif
- );
+ if (!vbr && s == st->layout.nb_streams-1)
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size)));
+ len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth,
+ pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix);
if (len<0)
{
RESTORE_STACK;
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);
- 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);
+ 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;
tot_size += len;
}
+ /*printf("\n");*/
RESTORE_STACK;
return tot_size;
-
}
#if !defined(DISABLE_FLOAT_API)
dst[i*dst_stride] = float_src[i*src_stride+src_channel];
#endif
}
-
-static void channel_pos(int channels, int pos[8])
-{
- /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */
- if (channels==4)
- {
- pos[0]=1;
- pos[1]=3;
- pos[2]=1;
- pos[3]=3;
- } else if (channels==3||channels==5||channels==6)
- {
- pos[0]=1;
- pos[1]=2;
- pos[2]=3;
- pos[3]=1;
- pos[4]=3;
- pos[5]=0;
- } else if (channels==7)
- {
- pos[0]=1;
- pos[1]=2;
- pos[2]=3;
- pos[3]=1;
- pos[4]=3;
- pos[5]=2;
- pos[6]=0;
- } else if (channels==8)
- {
- pos[0]=1;
- pos[1]=2;
- pos[2]=3;
- pos[3]=1;
- pos[4]=3;
- pos[5]=1;
- pos[6]=3;
- pos[7]=0;
- }
-}
-
-static void opus_surround_downmix_float(
- opus_val16 *dst,
- const void *src,
- int channels,
- int frame_size
-)
-{
- const float *float_src;
- opus_int32 i;
- int pos[8] = {0};
- int c;
- float_src = (const float *)src;
-
- channel_pos(channels, pos);
- for (i=0;i<2*frame_size;i++)
- dst[i]=0;
-
- for (c=0;c<channels;c++)
- {
- if (pos[c]==1||pos[c]==2)
- {
- for (i=0;i<frame_size;i++)
-#if defined(FIXED_POINT)
- dst[2*i] += SHR16(FLOAT2INT16(float_src[i*channels+c]),3);
-#else
- dst[2*i] += float_src[i*channels+c];
-#endif
- }
- if (pos[c]==2||pos[c]==3)
- {
- for (i=0;i<frame_size;i++)
-#if defined(FIXED_POINT)
- dst[2*i+1] += SHR16(FLOAT2INT16(float_src[i*channels+c]),3);
-#else
- dst[2*i+1] += float_src[i*channels+c];
-#endif
- }
- }
-}
#endif
static void opus_copy_channel_in_short(
#endif
}
-static void opus_surround_downmix_short(
- opus_val16 *dst,
- const void *src,
- int channels,
- int frame_size
-)
-{
- const opus_int16 *short_src;
- opus_int32 i;
- int pos[8] = {0};
- int c;
- short_src = (const opus_int16 *)src;
-
- channel_pos(channels, pos);
- for (i=0;i<2*frame_size;i++)
- dst[i]=0;
-
- for (c=0;c<channels;c++)
- {
- if (pos[c]==1||pos[c]==2)
- {
- for (i=0;i<frame_size;i++)
-#if defined(FIXED_POINT)
- dst[2*i] += SHR16(short_src[i*channels+c],3);
-#else
- dst[2*i] += (1/32768.f)*short_src[i*channels+c];
-#endif
- }
- if (pos[c]==2||pos[c]==3)
- {
- for (i=0;i<frame_size;i++)
-#if defined(FIXED_POINT)
- dst[2*i+1] += SHR16(short_src[i*channels+c],3);
-#else
- dst[2*i+1] += (1/32768.f)*short_src[i*channels+c];
-#endif
- }
- }
-}
-
#ifdef FIXED_POINT
int opus_multistream_encode(
)
{
return opus_multistream_encode_native(st, opus_copy_channel_in_short,
- pcm, frame_size, data, max_data_bytes, 16, opus_surround_downmix_float);
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int);
}
#ifndef DISABLE_FLOAT_API
)
{
return opus_multistream_encode_native(st, opus_copy_channel_in_float,
- pcm, frame_size, data, max_data_bytes, 16, opus_surround_downmix_short);
+ pcm, frame_size, data, max_data_bytes, 16, downmix_float);
}
#endif
opus_int32 max_data_bytes
)
{
- int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
return opus_multistream_encode_native(st, opus_copy_channel_in_float,
- pcm, frame_size, data, max_data_bytes, 24, opus_surround_downmix_float, downmix_float, pcm+channels*st->analysis.analysis_offset);
+ pcm, frame_size, data, max_data_bytes, 24, downmix_float);
}
int opus_multistream_encode(
opus_int32 max_data_bytes
)
{
- int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
return opus_multistream_encode_native(st, opus_copy_channel_in_short,
- pcm, frame_size, data, max_data_bytes, 16, opus_surround_downmix_short, downmix_int, pcm+channels*st->analysis.analysis_offset);
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int);
}
#endif
{
opus_int32 value = va_arg(ap, opus_int32);
if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX)
+ {
goto bad_arg;
+ }
st->bitrate_bps = value;
}
break;
{
int s;
opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
*value = 0;
for (s=0;s<st->layout.nb_streams;s++)
{
case OPUS_GET_SAMPLE_RATE_REQUEST:
case OPUS_GET_INBAND_FEC_REQUEST:
case OPUS_GET_FORCE_CHANNELS_REQUEST:
+ case OPUS_GET_PREDICTION_DISABLED_REQUEST:
{
OpusEncoder *enc;
/* For int32* GET params, just query the first stream */
int s;
opus_uint32 *value = va_arg(ap, opus_uint32*);
opus_uint32 tmp;
+ if (!value)
+ {
+ goto bad_arg;
+ }
*value=0;
for (s=0;s<st->layout.nb_streams;s++)
{
case OPUS_SET_COMPLEXITY_REQUEST:
case OPUS_SET_VBR_REQUEST:
case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ case OPUS_SET_MAX_BANDWIDTH_REQUEST:
case OPUS_SET_BANDWIDTH_REQUEST:
case OPUS_SET_SIGNAL_REQUEST:
case OPUS_SET_APPLICATION_REQUEST:
case OPUS_SET_DTX_REQUEST:
case OPUS_SET_FORCE_MODE_REQUEST:
case OPUS_SET_FORCE_CHANNELS_REQUEST:
+ case OPUS_SET_PREDICTION_DISABLED_REQUEST:
{
int s;
/* This works for int32 params */
if (stream_id<0 || stream_id >= st->layout.nb_streams)
ret = OPUS_BAD_ARG;
value = va_arg(ap, OpusEncoder**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
for (s=0;s<stream_id;s++)
{
if (s < st->layout.nb_coupled_streams)
case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
{
opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
*value = st->variable_duration;
}
break;
+ case OPUS_RESET_STATE:
+ {
+ int s;
+ st->subframe_mem[0] = st->subframe_mem[1] = st->subframe_mem[2] = 0;
+ if (st->surround)
+ {
+ OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels);
+ OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120);
+ }
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, OPUS_RESET_STATE);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
default:
ret = OPUS_UNIMPLEMENTED;
break;
{
opus_free(st);
}
-
-