예제 #1
0
        internal static int validate_encoder_layout(ChannelLayout layout)
        {
            int s;

            for (s = 0; s < layout.nb_streams; s++)
            {
                if (s < layout.nb_coupled_streams)
                {
                    if (OpusMultistream.get_left_channel(layout, s, -1) == -1)
                    {
                        return(0);
                    }
                    if (OpusMultistream.get_right_channel(layout, s, -1) == -1)
                    {
                        return(0);
                    }
                }
                else
                {
                    if (OpusMultistream.get_mono_channel(layout, s, -1) == -1)
                    {
                        return(0);
                    }
                }
            }
            return(1);
        }
예제 #2
0
        internal int opus_multistream_decode_native <T>(
            byte[] data,
            int data_ptr,
            int len,
            T[] pcm,
            int pcm_ptr,
            opus_copy_channel_out_func <T> copy_channel_out,
            int frame_size,
            int decode_fec,
            int soft_clip
            )
        {
            int Fs;
            int s, c;
            int decoder_ptr;
            int do_plc = 0;

            short[] buf;

            /* Limit frame_size to avoid excessive stack allocations. */
            Fs          = this.SampleRate;
            frame_size  = Inlines.IMIN(frame_size, Fs / 25 * 3);
            buf         = new short[2 * frame_size];
            decoder_ptr = 0;

            if (len == 0)
            {
                do_plc = 1;
            }
            if (len < 0)
            {
                return(OpusError.OPUS_BAD_ARG);
            }
            if (do_plc == 0 && len < 2 * this.layout.nb_streams - 1)
            {
                return(OpusError.OPUS_INVALID_PACKET);
            }
            if (do_plc == 0)
            {
                int ret = opus_multistream_packet_validate(data, data_ptr, len, this.layout.nb_streams, Fs);
                if (ret < 0)
                {
                    return(ret);
                }
                else if (ret > frame_size)
                {
                    return(OpusError.OPUS_BUFFER_TOO_SMALL);
                }
            }
            for (s = 0; s < this.layout.nb_streams; s++)
            {
                OpusDecoder dec;
                int         ret;

                dec = this.decoders[decoder_ptr++];

                if (do_plc == 0 && len <= 0)
                {
                    return(OpusError.OPUS_INTERNAL_ERROR);
                }
                int packet_offset;
                ret = dec.opus_decode_native(
                    data, data_ptr, len, buf, 0, frame_size, decode_fec,
                    (s != this.layout.nb_streams - 1) ? 1 : 0, out packet_offset, soft_clip);
                data_ptr += packet_offset;
                len      -= packet_offset;
                if (ret <= 0)
                {
                    return(ret);
                }
                frame_size = ret;
                if (s < this.layout.nb_coupled_streams)
                {
                    int chan, prev;
                    prev = -1;
                    /* Copy "left" audio to the channel(s) where it belongs */
                    while ((chan = OpusMultistream.get_left_channel(this.layout, s, prev)) != -1)
                    {
                        copy_channel_out(pcm, pcm_ptr, this.layout.nb_channels, chan,
                                         buf, 0, 2, frame_size);
                        prev = chan;
                    }
                    prev = -1;
                    /* Copy "right" audio to the channel(s) where it belongs */
                    while ((chan = OpusMultistream.get_right_channel(this.layout, s, prev)) != -1)
                    {
                        copy_channel_out(pcm, pcm_ptr, this.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 = OpusMultistream.get_mono_channel(this.layout, s, prev)) != -1)
                    {
                        copy_channel_out(pcm, pcm_ptr, this.layout.nb_channels, chan,
                                         buf, 0, 1, frame_size);
                        prev = chan;
                    }
                }
            }
            /* Handle muted channels */
            for (c = 0; c < this.layout.nb_channels; c++)
            {
                if (this.layout.mapping[c] == 255)
                {
                    copy_channel_out(pcm, pcm_ptr, this.layout.nb_channels, c,
                                     null, 0, 0, frame_size);
                }
            }

            return(frame_size);
        }
예제 #3
0
        internal int opus_multistream_encode_native <T>
        (
            opus_copy_channel_in_func <T> copy_channel_in,
            T[] pcm,
            int pcm_ptr,
            int analysis_frame_size,
            byte[] data,
            int data_ptr,
            int max_data_bytes,
            int lsb_depth,
            Downmix.downmix_func <T> downmix,
            int float_api
        )
        {
            int Fs;
            int s;
            int encoder_ptr;
            int tot_size;

            short[]          buf;
            int[]            bandSMR;
            byte[]           tmp_data = new byte[MS_FRAME_TMP];
            OpusRepacketizer rp       = new OpusRepacketizer();
            int      vbr;
            CeltMode celt_mode;

            int[] bitrates    = new int[256];
            int[] bandLogE    = new int[42];
            int[] mem         = null;
            int[] preemph_mem = null;
            int   frame_size;
            int   rate_sum;
            int   smallest_packet;

            if (this.surround != 0)
            {
                preemph_mem = this.preemph_mem;
                mem         = this.window_mem;
            }

            encoder_ptr = 0;
            Fs          = this.encoders[encoder_ptr].SampleRate;
            vbr         = this.encoders[encoder_ptr].UseVBR ? 1 : 0;
            celt_mode   = this.encoders[encoder_ptr].GetCeltMode();

            {
                int delay_compensation;
                int channels;

                channels            = this.layout.nb_streams + this.layout.nb_coupled_streams;
                delay_compensation  = this.encoders[encoder_ptr].Lookahead;
                delay_compensation -= Fs / 400;
                frame_size          = CodecHelpers.compute_frame_size(pcm, pcm_ptr, analysis_frame_size,
                                                                      this.variable_duration, channels, Fs, this.bitrate_bps,
                                                                      delay_compensation, downmix, this.subframe_mem, this.encoders[encoder_ptr].analysis.enabled);
            }

            if (400 * frame_size < Fs)
            {
                return(OpusError.OPUS_BAD_ARG);
            }

            /* Validate frame_size before using it to allocate stack space.
             * This mirrors the checks in opus_encode[_float](). */
            if (400 * frame_size != Fs && 200 * frame_size != Fs &&
                100 * frame_size != Fs && 50 * frame_size != Fs &&
                25 * frame_size != Fs && 50 * frame_size != 3 * Fs)
            {
                return(OpusError.OPUS_BAD_ARG);
            }

            /* Smallest packet the encoder can produce. */
            smallest_packet = this.layout.nb_streams * 2 - 1;
            if (max_data_bytes < smallest_packet)
            {
                return(OpusError.OPUS_BUFFER_TOO_SMALL);
            }
            buf = new short[2 * frame_size];

            bandSMR = new int[21 * this.layout.nb_channels];
            if (this.surround != 0)
            {
                surround_analysis(celt_mode, pcm, pcm_ptr, bandSMR, mem, preemph_mem, frame_size, 120, this.layout.nb_channels, Fs, copy_channel_in);
            }

            /* Compute bitrate allocation between streams (this could be a lot better) */
            rate_sum = surround_rate_allocation(bitrates, frame_size);

            if (vbr == 0)
            {
                if (this.bitrate_bps == OpusConstants.OPUS_AUTO)
                {
                    max_data_bytes = Inlines.IMIN(max_data_bytes, 3 * rate_sum / (3 * 8 * Fs / frame_size));
                }
                else if (this.bitrate_bps != OpusConstants.OPUS_BITRATE_MAX)
                {
                    max_data_bytes = Inlines.IMIN(max_data_bytes, Inlines.IMAX(smallest_packet,
                                                                               3 * this.bitrate_bps / (3 * 8 * Fs / frame_size)));
                }
            }

            for (s = 0; s < this.layout.nb_streams; s++)
            {
                OpusEncoder enc = this.encoders[encoder_ptr];
                encoder_ptr += 1;
                enc.Bitrate  = (bitrates[s]);
                if (this.surround != 0)
                {
                    int equiv_rate;
                    equiv_rate = this.bitrate_bps;
                    if (frame_size * 50 < Fs)
                    {
                        equiv_rate -= 60 * (Fs / frame_size - 50) * this.layout.nb_channels;
                    }
                    if (equiv_rate > 10000 * this.layout.nb_channels)
                    {
                        enc.Bandwidth = (OpusBandwidth.OPUS_BANDWIDTH_FULLBAND);
                    }
                    else if (equiv_rate > 7000 * this.layout.nb_channels)
                    {
                        enc.Bandwidth = (OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND);
                    }
                    else if (equiv_rate > 5000 * this.layout.nb_channels)
                    {
                        enc.Bandwidth = (OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND);
                    }
                    else
                    {
                        enc.Bandwidth = (OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND);
                    }
                    if (s < this.layout.nb_coupled_streams)
                    {
                        /* To preserve the spatial image, force stereo CELT on coupled streams */
                        enc.ForceMode     = (OpusMode.MODE_CELT_ONLY);
                        enc.ForceChannels = (2);
                    }
                }
            }

            encoder_ptr = 0;
            /* Counting ToC */
            tot_size = 0;
            for (s = 0; s < this.layout.nb_streams; s++)
            {
                OpusEncoder enc;
                int         len;
                int         curr_max;
                int         c1, c2;

                rp.Reset();
                enc = this.encoders[encoder_ptr];
                if (s < this.layout.nb_coupled_streams)
                {
                    int i;
                    int left, right;
                    left  = OpusMultistream.get_left_channel(this.layout, s, -1);
                    right = OpusMultistream.get_right_channel(this.layout, s, -1);
                    copy_channel_in(buf, 0, 2,
                                    pcm, pcm_ptr, this.layout.nb_channels, left, frame_size);
                    copy_channel_in(buf, 1, 2,
                                    pcm, pcm_ptr, this.layout.nb_channels, right, frame_size);
                    encoder_ptr += 1;
                    if (this.surround != 0)
                    {
                        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 = OpusMultistream.get_mono_channel(this.layout, s, -1);
                    copy_channel_in(buf, 0, 1,
                                    pcm, pcm_ptr, this.layout.nb_channels, chan, frame_size);
                    encoder_ptr += 1;
                    if (this.surround != 0)
                    {
                        for (i = 0; i < 21; i++)
                        {
                            bandLogE[i] = bandSMR[21 * chan + i];
                        }
                    }
                    c1 = chan;
                    c2 = -1;
                }
                if (this.surround != 0)
                {
                    enc.SetEnergyMask(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 -= Inlines.IMAX(0, 2 * (this.layout.nb_streams - s - 1) - 1);
                curr_max  = Inlines.IMIN(curr_max, MS_FRAME_TMP);
                /* Repacketizer will add one or two bytes for self-delimited frames */
                if (s != this.layout.nb_streams - 1)
                {
                    curr_max -= curr_max > 253 ? 2 : 1;
                }
                if (vbr == 0 && s == this.layout.nb_streams - 1)
                {
                    enc.Bitrate = (curr_max * (8 * Fs / frame_size));
                }
                len = enc.opus_encode_native(buf, 0, frame_size, tmp_data, 0, curr_max, lsb_depth,
                                             pcm, pcm_ptr, analysis_frame_size, c1, c2, this.layout.nb_channels, downmix, float_api);
                if (len < 0)
                {
                    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) */
                rp.AddPacket(tmp_data, 0, len);
                len = rp.opus_repacketizer_out_range_impl(0, rp.GetNumFrames(),
                                                          data, data_ptr, max_data_bytes - tot_size, (s != this.layout.nb_streams - 1) ? 1 : 0, (vbr == 0 && s == this.layout.nb_streams - 1) ? 1 : 0);
                data_ptr += len;
                tot_size += len;
            }

            return(tot_size);
        }