static int validate_encoder_layout(const ChannelLayout *layout) { int s; for (s=0;s<layout->nb_streams;s++) { if (s < layout->nb_coupled_streams) { if (get_left_channel(layout, s, -1)==-1) return 0; if (get_right_channel(layout, s, -1)==-1) return 0; } else { if (get_mono_channel(layout, s, -1)==-1) return 0; } } return 1; }
static int opus_multistream_decode_native( OpusMSDecoder *st, const unsigned char *data, opus_int32 len, void *pcm, opus_copy_channel_out_func copy_channel_out, int frame_size, int decode_fec, int soft_clip ) { opus_int32 Fs; int coupled_size; int mono_size; int s, c; char *ptr; int do_plc=0; VARDECL(opus_val16, buf); ALLOC_STACK; /* Limit frame_size to avoid excessive stack allocations. */ opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs)); frame_size = IMIN(frame_size, Fs/25*3); ALLOC(buf, 2*frame_size, opus_val16); ptr = (char*)st + align(sizeof(OpusMSDecoder)); coupled_size = opus_decoder_get_size(2); mono_size = opus_decoder_get_size(1); if (len==0) do_plc = 1; if (len < 0) return OPUS_BAD_ARG; if (!do_plc && len < 2*st->layout.nb_streams-1) return OPUS_INVALID_PACKET; for (s=0;s<st->layout.nb_streams;s++) { OpusDecoder *dec; int packet_offset, ret; dec = (OpusDecoder*)ptr; ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); if (!do_plc && len<=0) { RESTORE_STACK; return OPUS_INVALID_PACKET; } packet_offset = 0; ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); data += packet_offset; len -= packet_offset; if (ret > frame_size) { RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; } if (s>0 && ret != frame_size) { RESTORE_STACK; return OPUS_INVALID_PACKET; } if (ret <= 0) { RESTORE_STACK; return ret; } frame_size = ret; if (s < st->layout.nb_coupled_streams) { int chan, prev; prev = -1; /* Copy "left" audio to the channel(s) where it belongs */ while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) { (*copy_channel_out)(pcm, st->layout.nb_channels, chan, buf, 2, frame_size); prev = chan; } prev = -1; /* Copy "right" audio to the channel(s) where it belongs */ while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) { (*copy_channel_out)(pcm, st->layout.nb_channels, chan, buf+1, 2, frame_size); prev = chan; } } else { int chan, prev; prev = -1; /* Copy audio to the channel(s) where it belongs */ while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) { (*copy_channel_out)(pcm, st->layout.nb_channels, chan, buf, 1, frame_size); prev = chan; } } } /* Handle muted channels */ for (c=0;c<st->layout.nb_channels;c++) { if (st->layout.mapping[c] == 255) { (*copy_channel_out)(pcm, st->layout.nb_channels, c, NULL, 0, frame_size); } } RESTORE_STACK; return frame_size; }
static int opus_multistream_decode_native( OpusMSDecoder *st, const unsigned char *data, opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec ) { int coupled_size; int mono_size; int s, i, c; char *ptr; int do_plc=0; VARDECL(opus_val16, buf); ALLOC_STACK; ALLOC(buf, 2*frame_size, opus_val16); ptr = (char*)st + align(sizeof(OpusMSDecoder)); coupled_size = opus_decoder_get_size(2); mono_size = opus_decoder_get_size(1); if (len==0) do_plc = 1; if (len < 0) return OPUS_BAD_ARG; if (!do_plc && len < 2*st->layout.nb_streams-1) return OPUS_INVALID_PACKET; for (s=0;s<st->layout.nb_streams;s++) { OpusDecoder *dec; int packet_offset, ret; dec = (OpusDecoder*)ptr; ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); if (!do_plc && len<=0) { RESTORE_STACK; return OPUS_INVALID_PACKET; } packet_offset = 0; ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset); data += packet_offset; len -= packet_offset; if (ret > frame_size) { RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; } if (s>0 && ret != frame_size) { RESTORE_STACK; return OPUS_INVALID_PACKET; } if (ret <= 0) { RESTORE_STACK; return ret; } frame_size = ret; if (s < st->layout.nb_coupled_streams) { int chan, prev; prev = -1; /* Copy "left" audio to the channel(s) where it belongs */ while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) { for (i=0;i<frame_size;i++) pcm[st->layout.nb_channels*i+chan] = buf[2*i]; prev = chan; } prev = -1; /* Copy "right" audio to the channel(s) where it belongs */ while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) { for (i=0;i<frame_size;i++) pcm[st->layout.nb_channels*i+chan] = buf[2*i+1]; prev = chan; } } else { int chan, prev; prev = -1; /* Copy audio to the channel(s) where it belongs */ while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) { for (i=0;i<frame_size;i++) pcm[st->layout.nb_channels*i+chan] = buf[i]; prev = chan; } } } /* Handle muted channels */ for (c=0;c<st->layout.nb_channels;c++) { if (st->layout.mapping[c] == 255) { for (i=0;i<frame_size;i++) pcm[st->layout.nb_channels*i+c] = 0; } } RESTORE_STACK; return frame_size; }
int opus_multistream_encode_float( #endif OpusMSEncoder *st, const opus_val16 *pcm, int frame_size, unsigned char *data, opus_int32 max_data_bytes ) { int coupled_size; int mono_size; int s, i; char *ptr; int tot_size; VARDECL(opus_val16, buf); unsigned char tmp_data[MS_FRAME_TMP]; OpusRepacketizer rp; ALLOC_STACK; ALLOC(buf, 2*frame_size, opus_val16); ptr = (char*)st + align(sizeof(OpusMSEncoder)); coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); if (max_data_bytes < 4*st->layout.nb_streams-1) { RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; } /* Counting ToC */ tot_size = 0; for (s=0;s<st->layout.nb_streams;s++) { OpusEncoder *enc; int len; int curr_max; opus_repacketizer_init(&rp); enc = (OpusEncoder*)ptr; if (s < st->layout.nb_coupled_streams) { int left, right; left = get_left_channel(&st->layout, s, -1); right = get_right_channel(&st->layout, s, -1); for (i=0;i<frame_size;i++) { buf[2*i] = pcm[st->layout.nb_channels*i+left]; buf[2*i+1] = pcm[st->layout.nb_channels*i+right]; } ptr += align(coupled_size); } else { int chan = get_mono_channel(&st->layout, s, -1); for (i=0;i<frame_size;i++) buf[i] = pcm[st->layout.nb_channels*i+chan]; ptr += align(mono_size); } /* 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); if (len<0) { RESTORE_STACK; return len; } /* 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); 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); data += len; tot_size += len; } RESTORE_STACK; return tot_size; }