/* Copyright (c) 2011 Xiph.Org Foundation
Written by Jean-Marc Valin */ /* Redistributionanduseinsourceandbinaryforms,withorwithout modification,arepermittedprovidedthatthefollowingconditions aremet:
staticint validate_ambisonics(int nb_channels, int *nb_streams, int *nb_coupled_streams)
{ int order_plus_one; int acn_channels; int nondiegetic_channels;
if (nb_channels < 1 || nb_channels > 227) return0;
#if1 /* Computes a rough approximation of log2(2^a + 2^b) */ static opus_val16 logSum(celt_glog a, celt_glog b)
{
celt_glog max;
celt_glog diff;
celt_glog frac; staticconst celt_glog diff_table[17] = {
GCONST(0.5000000f), GCONST(0.2924813f), GCONST(0.1609640f), GCONST(0.0849625f),
GCONST(0.0437314f), GCONST(0.0221971f), GCONST(0.0111839f), GCONST(0.0056136f),
GCONST(0.0028123f)
}; int low; if (a>b)
{
max = a;
diff = SUB32(a,b);
} else {
max = b;
diff = SUB32(b,a);
} if (!(diff < GCONST(8.f))) /* inverted to catch NaNs */ return max; #ifdef FIXED_POINT
low = SHR32(diff, DB_SHIFT-1);
frac = VSHR32(diff - SHL32(low, DB_SHIFT-1), DB_SHIFT-16); #else
low = (int)floor(2*diff);
frac = 2*diff - low; #endif return max + diff_table[low] + MULT16_32_Q15(frac, SUB32(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, constvoid *pcm, celt_glog *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 arch
)
{ int c; int i; int LM; int pos[8] = {0}; int upsample; int frame_size; int freq_size;
opus_val16 channel_offset;
opus_val32 bandE[21];
celt_glog maskLogE[3][21];
VARDECL(opus_val32, in);
VARDECL(opus_res, x);
VARDECL(opus_val32, freq);
SAVE_STACK;
staticint opus_multistream_encoder_init_impl(
OpusMSEncoder *st,
opus_int32 Fs, int channels, int streams, int coupled_streams, constunsignedchar *mapping, int application,
MappingType mapping_type
)
{ int coupled_size; int mono_size; int i, ret; char *ptr;
st->arch = opus_select_arch();
st->layout.nb_channels = channels;
st->layout.nb_streams = streams;
st->layout.nb_coupled_streams = coupled_streams; if (mapping_type != MAPPING_TYPE_SURROUND)
st->lfe_stream = -1;
st->bitrate_bps = OPUS_AUTO;
st->application = application;
st->Fs = Fs;
st->variable_duration = OPUS_FRAMESIZE_ARG; for (i=0;i<st->layout.nb_channels;i++)
st->layout.mapping[i] = mapping[i]; if (!validate_layout(&st->layout)) return OPUS_BAD_ARG; if (!validate_encoder_layout(&st->layout)) return OPUS_BAD_ARG; if (mapping_type == MAPPING_TYPE_AMBISONICS &&
!validate_ambisonics(st->layout.nb_channels, NULL, NULL)) return OPUS_BAD_ARG;
ptr = (char*)st + align(sizeof(OpusMSEncoder)); for (i=0;i<st->layout.nb_coupled_streams;i++)
{
ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); if(ret!=OPUS_OK)return ret; if (i==st->lfe_stream)
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
ptr += align(coupled_size);
} for (;i<st->layout.nb_streams;i++)
{
ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); if(ret!=OPUS_OK)return ret; if (i==st->lfe_stream)
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
ptr += align(mono_size);
} if (mapping_type == MAPPING_TYPE_SURROUND)
{
OPUS_CLEAR(ms_get_preemph_mem(st), channels);
OPUS_CLEAR(ms_get_window_mem(st), channels*MAX_OVERLAP);
}
st->mapping_type = mapping_type; return OPUS_OK;
}
int opus_multistream_encoder_init(
OpusMSEncoder *st,
opus_int32 Fs, int channels, int streams, int coupled_streams, constunsignedchar *mapping, int application
)
{ return opus_multistream_encoder_init_impl(st, Fs, channels, streams,
coupled_streams, mapping,
application, MAPPING_TYPE_NONE);
}
int opus_multistream_surround_encoder_init(
OpusMSEncoder *st,
opus_int32 Fs, int channels, int mapping_family, int *streams, int *coupled_streams, unsignedchar *mapping, int application
)
{
MappingType mapping_type; int lfe_stream;
if ((channels>255) || (channels<1)) return OPUS_BAD_ARG;
lfe_stream = -1; if (mapping_family==0)
{ if (channels==1)
{
*streams=1;
*coupled_streams=0;
mapping[0]=0;
} elseif (channels==2)
{
*streams=1;
*coupled_streams=1;
mapping[0]=0;
mapping[1]=1;
} else return OPUS_UNIMPLEMENTED;
} elseif (mapping_family==1 && channels<=8 && channels>=1)
{ int i;
*streams=vorbis_mappings[channels-1].nb_streams;
*coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; for (i=0;i<channels;i++)
mapping[i] = vorbis_mappings[channels-1].mapping[i]; if (channels>=6)
lfe_stream = *streams-1;
} elseif (mapping_family==255)
{ int i;
*streams=channels;
*coupled_streams=0; for(i=0;i<channels;i++)
mapping[i] = i;
} elseif (mapping_family==2)
{ int i; if (!validate_ambisonics(channels, streams, coupled_streams)) return OPUS_BAD_ARG; for(i = 0; i < (*streams - *coupled_streams); i++)
mapping[i] = i + (*coupled_streams * 2); for(i = 0; i < *coupled_streams * 2; i++)
mapping[i + (*streams - *coupled_streams)] = i;
} else return OPUS_UNIMPLEMENTED;
OpusMSEncoder *opus_multistream_encoder_create(
opus_int32 Fs, int channels, int streams, int coupled_streams, constunsignedchar *mapping, int application, int *error
)
{ int ret;
OpusMSEncoder *st;
opus_int32 size; if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
(streams<1) || (coupled_streams<0) || (streams>255-coupled_streams) ||
(streams+coupled_streams>channels))
{ if (error)
*error = OPUS_BAD_ARG; return NULL;
}
size = opus_multistream_encoder_init(NULL, Fs, channels, streams, coupled_streams, mapping, application); if (size < 0)
{ if (error)
*error = size; return NULL;
}
st = (OpusMSEncoder *)opus_alloc(size); if (st==NULL)
{ if (error)
*error = OPUS_ALLOC_FAIL; return NULL;
}
ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application); if (ret != OPUS_OK)
{
opus_free(st);
st = NULL;
} if (error)
*error = ret; return st;
}
OpusMSEncoder *opus_multistream_surround_encoder_create(
opus_int32 Fs, int channels, int mapping_family, int *streams, int *coupled_streams, unsignedchar *mapping, int application, int *error
)
{ int ret;
opus_int32 size;
OpusMSEncoder *st; if ((channels>255) || (channels<1))
{ if (error)
*error = OPUS_BAD_ARG; return NULL;
}
size = opus_multistream_surround_encoder_init(NULL, Fs, channels, mapping_family, streams, coupled_streams, mapping, application); if (size < 0)
{ if (error)
*error = size; return NULL;
}
st = (OpusMSEncoder *)opus_alloc(size); if (st==NULL)
{ if (error)
*error = OPUS_ALLOC_FAIL; return NULL;
}
ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application); if (ret != OPUS_OK)
{
opus_free(st);
st = NULL;
} if (error)
*error = ret; return st;
}
staticvoid surround_rate_allocation(
OpusMSEncoder *st,
opus_int32 *rate, int frame_size,
opus_int32 Fs
)
{ int i;
opus_int32 channel_rate; int stream_offset; int lfe_offset; int coupled_ratio; /* Q8 */ int lfe_ratio; /* Q8 */ int nb_lfe; int nb_uncoupled; int nb_coupled; int nb_normal;
opus_int32 channel_offset;
opus_int32 bitrate; int total;
/* Give LFE some basic stream_channel allocation but never exceed 1/20 of the
total rate for the non-energy part to avoid problems at really low rate. */
lfe_offset = IMIN(bitrate/20, 3000) + 15*IMAX(50, Fs/frame_size);
/* We give each stream (coupled or uncoupled) a starting bitrate.
This models the main saving of coupled channels over uncoupled. */
stream_offset = (bitrate - channel_offset*nb_normal - lfe_offset*nb_lfe)/nb_normal/2;
stream_offset = IMAX(0, IMIN(20000, stream_offset));
/* Coupled streams get twice the mono rate after the offset is allocated. */
coupled_ratio = 512; /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
lfe_ratio = 32;
/* Allocate equal number of bits to Ambisonic (uncoupled) and non-diegetic
* (coupled) streams */
per_stream_rate = total_rate / st->layout.nb_streams; for (i = 0; i < st->layout.nb_streams; i++)
{
rate[i] = per_stream_rate;
}
}
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;
/* Max size in case the encoder decides to return six frames (6 x 20 ms = 120 ms) */ #ifdef ENABLE_QEXT #define MS_FRAME_TMP (6*QEXT_PACKET_SIZE_CAP+12) #else #define MS_FRAME_TMP (6*1275+12) #endif
int opus_multistream_encode_native
(
OpusMSEncoder *st,
opus_copy_channel_in_func copy_channel_in, constvoid *pcm, int analysis_frame_size, unsignedchar *data,
opus_int32 max_data_bytes, int lsb_depth,
downmix_func downmix, int float_api, void *user_data
)
{
opus_int32 Fs; int coupled_size; int mono_size; int s; char *ptr; int tot_size;
VARDECL(opus_res, buf);
VARDECL(celt_glog, bandSMR); unsignedchar tmp_data[MS_FRAME_TMP];
OpusRepacketizer rp;
opus_int32 vbr; const CELTMode *celt_mode=NULL;
opus_int32 bitrates[256];
celt_glog bandLogE[42];
opus_val32 *mem = NULL;
opus_val32 *preemph_mem=NULL; int frame_size;
opus_int32 rate_sum;
opus_int32 smallest_packet;
ALLOC_STACK;
if (st->mapping_type == MAPPING_TYPE_SURROUND)
{
preemph_mem = ms_get_preemph_mem(st);
mem = ms_get_window_mem(st);
}
/* Compute bitrate allocation between streams (this could be a lot better) */
rate_sum = rate_allocation(st, bitrates, frame_size);
if (!vbr)
{ if (st->bitrate_bps == OPUS_AUTO)
{
max_data_bytes = IMIN(max_data_bytes, (bitrate_to_bits(rate_sum, Fs, frame_size)+4)/8);
} elseif (st->bitrate_bps != OPUS_BITRATE_MAX)
{
max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet,
(bitrate_to_bits(st->bitrate_bps, Fs, frame_size)+4)/8));
}
}
ptr = (char*)st + align(sizeof(OpusMSEncoder)); 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);
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s])); if (st->mapping_type == MAPPING_TYPE_SURROUND)
{
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)); elseif (equiv_rate > 7000*st->layout.nb_channels)
opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); elseif (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));
}
} elseif (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
}
}
ptr = (char*)st + align(sizeof(OpusMSEncoder)); /* Counting ToC */
tot_size = 0; for (s=0;s<st->layout.nb_streams;s++)
{
OpusEncoder *enc; int len; int curr_max; int c1, c2; int ret;
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, 2,
pcm, st->layout.nb_channels, left, frame_size, user_data);
(*copy_channel_in)(buf+1, 2,
pcm, st->layout.nb_channels, right, frame_size, user_data);
ptr += align(coupled_size); if (st->mapping_type == MAPPING_TYPE_SURROUND && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
{ 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, user_data);
ptr += align(mono_size); if (st->mapping_type == MAPPING_TYPE_SURROUND && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
{ for (i=0;i<21;i++)
bandLogE[i] = bandSMR[21*chan+i];
}
c1 = chan;
c2 = -1;
} if (st->mapping_type == MAPPING_TYPE_SURROUND && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE)); /* number of bytes left (+Toc) */
curr_max = max_data_bytes - tot_size; /* Reserve one byte for the last stream and two for the others */
curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1); /* For 100 ms, reserve an extra byte per stream for the ToC */ if (Fs/frame_size == 10)
curr_max -= st->layout.nb_streams-s-1;
curr_max = IMIN(curr_max,MS_FRAME_TMP); /* Repacketizer will add one or two bytes for self-delimited frames */ if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1; if (!vbr && s == st->layout.nb_streams-1)
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bits_to_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, float_api); if (len<0)
{
RESTORE_STACK; return len;
} /* We need to use the repacketizer to add the self-delimiting lengths whiletakingintoaccountthefactthattheencodercannowreturn
more than one frame at a time (e.g. 60 ms CELT-only) */
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, NULL, 0);
data += len;
tot_size += len;
} /*printf("\n");*/
RESTORE_STACK; return tot_size;
}
#if !defined(DISABLE_FLOAT_API) staticvoid opus_copy_channel_in_float(
opus_res *dst, int dst_stride, constvoid *src, int src_stride, int src_channel, int frame_size, void *user_data
)
{ constfloat *float_src;
opus_int32 i;
(void)user_data;
float_src = (constfloat *)src; for (i=0;i<frame_size;i++)
dst[i*dst_stride] = FLOAT2RES(float_src[i*src_stride+src_channel]);
} #endif
staticvoid opus_copy_channel_in_short(
opus_res *dst, int dst_stride, constvoid *src, int src_stride, int src_channel, int frame_size, void *user_data
)
{ const opus_int16 *short_src;
opus_int32 i;
(void)user_data;
short_src = (const opus_int16 *)src; for (i=0;i<frame_size;i++)
dst[i*dst_stride] = INT16TORES(short_src[i*src_stride+src_channel]);
}
staticvoid opus_copy_channel_in_int24(
opus_res *dst, int dst_stride, constvoid *src, int src_stride, int src_channel, int frame_size, void *user_data
)
{ const opus_int32 *short_src;
opus_int32 i;
(void)user_data;
short_src = (const opus_int32 *)src; for (i=0;i<frame_size;i++)
dst[i*dst_stride] = INT24TORES(short_src[i*src_stride+src_channel]);
}
int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request,
va_list ap)
{ int coupled_size, mono_size; char *ptr; int ret = OPUS_OK;
coupled_size = opus_encoder_init(NULL, st->Fs, 2, st->application);
mono_size = opus_encoder_init(NULL, st->Fs, 1, st->application);
ptr = (char*)st + align(sizeof(OpusMSEncoder)); switch (request)
{ case OPUS_SET_BITRATE_REQUEST:
{
opus_int32 value = va_arg(ap, opus_int32); if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX)
{ if (value <= 0) goto bad_arg;
value = IMIN(750000*st->layout.nb_channels, IMAX(500*st->layout.nb_channels, value));
}
st->bitrate_bps = value;
} break; case OPUS_GET_BITRATE_REQUEST:
{ 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++)
{
opus_int32 rate;
OpusEncoder *enc;
enc = (OpusEncoder*)ptr; if (s < st->layout.nb_coupled_streams)
ptr += align(coupled_size); else
ptr += align(mono_size);
opus_encoder_ctl(enc, request, &rate);
*value += rate;
}
} break; case OPUS_GET_LSB_DEPTH_REQUEST: case OPUS_GET_VBR_REQUEST: case OPUS_GET_APPLICATION_REQUEST: case OPUS_GET_BANDWIDTH_REQUEST: case OPUS_GET_COMPLEXITY_REQUEST: case OPUS_GET_PACKET_LOSS_PERC_REQUEST: case OPUS_GET_DTX_REQUEST: case OPUS_GET_VOICE_RATIO_REQUEST: case OPUS_GET_VBR_CONSTRAINT_REQUEST: case OPUS_GET_SIGNAL_REQUEST: case OPUS_GET_LOOKAHEAD_REQUEST: case OPUS_GET_SAMPLE_RATE_REQUEST: case OPUS_GET_INBAND_FEC_REQUEST: case OPUS_GET_FORCE_CHANNELS_REQUEST: case OPUS_GET_PREDICTION_DISABLED_REQUEST: case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: case OPUS_GET_QEXT_REQUEST:
{
OpusEncoder *enc; /* For int32* GET params, just query the first stream */
opus_int32 *value = va_arg(ap, opus_int32*);
enc = (OpusEncoder*)ptr;
ret = opus_encoder_ctl(enc, request, value);
} break; case OPUS_GET_FINAL_RANGE_REQUEST:
{ 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++)
{
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, request, &tmp); if (ret != OPUS_OK) break;
*value ^= tmp;
}
} break; case OPUS_SET_LSB_DEPTH_REQUEST: 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_INBAND_FEC_REQUEST: case OPUS_SET_PACKET_LOSS_PERC_REQUEST: case OPUS_SET_DTX_REQUEST: case OPUS_SET_FORCE_MODE_REQUEST: case OPUS_SET_FORCE_CHANNELS_REQUEST: case OPUS_SET_PREDICTION_DISABLED_REQUEST: case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: case OPUS_SET_QEXT_REQUEST:
{ int s; /* This works for int32 params */
opus_int32 value = va_arg(ap, opus_int32); 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, request, value); if (ret != OPUS_OK) break;
}
} break; case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
{ int s;
opus_int32 stream_id;
OpusEncoder **value;
stream_id = va_arg(ap, opus_int32); if (stream_id<0 || stream_id >= st->layout.nb_streams) goto 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)
ptr += align(coupled_size); else
ptr += align(mono_size);
}
*value = (OpusEncoder*)ptr;
} break; case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
{
opus_int32 value = va_arg(ap, opus_int32);
st->variable_duration = value;
} break; 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; 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*MAX_OVERLAP);
} 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;
} return ret;
bad_arg: return OPUS_BAD_ARG;
}
int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
{ int ret;
va_list ap;
va_start(ap, request);
ret = opus_multistream_encoder_ctl_va_list(st, request, ap);
va_end(ap); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.