Ejemplo n.º 1
0
        /** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
         * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
         *                                                   packet to pad.
         * @param len <tt>opus_int32</tt>: The size of the packet.
         *                                 This must be at least 1.
         * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
         *                                 This must be at least as large as len.
         * @returns an error code
         * @retval #OPUS_OK \a on success.
         * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
         * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
         */
        public static int PadPacket(byte[] data, int data_offset, int len, int new_len)
        {
            OpusRepacketizer rp = new OpusRepacketizer();
            int ret;

            if (len < 1)
            {
                return(OpusError.OPUS_BAD_ARG);
            }
            if (len == new_len)
            {
                return(OpusError.OPUS_OK);
            }
            else if (len > new_len)
            {
                return(OpusError.OPUS_BAD_ARG);
            }
            rp.Reset();
            /* Moving payload to the end of the packet so we can do in-place padding */
            Arrays.MemMove <byte>(data, data_offset, data_offset + new_len - len, len);
            //data.MemMoveTo(data.Point(new_len - len), len);
            rp.AddPacket(data, data_offset + new_len - len, len);
            ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, data_offset, new_len, 0, 1);
            if (ret > 0)
            {
                return(OpusError.OPUS_OK);
            }
            else
            {
                return(ret);
            }
        }
Ejemplo n.º 2
0
        // FIXME THIS METHOD FAILS IN TEST_OPUS_ENCODE

        /** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
         * minimize space usage.
         * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
         *                                                   packet to strip.
         * @param len <tt>opus_int32</tt>: The size of the packet.
         *                                 This must be at least 1.
         * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
         *                                 This must be at least 1.
         * @returns The new size of the output packet on success, or an error code
         *          on failure.
         * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
         * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
         */
        public static int UnpadMultistreamPacket(byte[] data, int data_offset, int len, int nb_streams)
        {
            int  s;
            byte dummy_toc;

            short[]          size = new short[48];
            int              packet_offset;
            int              dummy_offset;
            OpusRepacketizer rp = new OpusRepacketizer();
            int              dst;
            int              dst_len;

            if (len < 1)
            {
                return(OpusError.OPUS_BAD_ARG);
            }
            dst     = data_offset;
            dst_len = 0;
            /* Unpad all frames */
            for (s = 0; s < nb_streams; s++)
            {
                int ret;
                int self_delimited = ((s != nb_streams) ? 1 : 0) - 1;
                if (len <= 0)
                {
                    return(OpusError.OPUS_INVALID_PACKET);
                }
                rp.Reset();
                ret = OpusPacketInfo.opus_packet_parse_impl(data, data_offset, len, self_delimited, out dummy_toc, null, null, 0,
                                                            size, 0, out dummy_offset, out packet_offset);
                if (ret < 0)
                {
                    return(ret);
                }
                ret = rp.opus_repacketizer_cat_impl(data, data_offset, packet_offset, self_delimited);
                if (ret < 0)
                {
                    return(ret);
                }
                ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, dst, len, self_delimited, 0);
                if (ret < 0)
                {
                    return(ret);
                }
                else
                {
                    dst_len += ret;
                }
                dst         += ret;
                data_offset += packet_offset;
                len         -= packet_offset;
            }
            return(dst_len);
        }
Ejemplo n.º 3
0
        /** Remove all padding from a given Opus packet and rewrite the TOC sequence to
         * minimize space usage.
         * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
         *                                                   packet to strip.
         * @param len <tt>opus_int32</tt>: The size of the packet.
         *                                 This must be at least 1.
         * @returns The new size of the output packet on success, or an error code
         *          on failure.
         * @retval #OPUS_BAD_ARG \a len was less than 1.
         * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
         */
        public static int UnpadPacket(byte[] data, int data_offset, int len)
        {
            int ret;

            if (len < 1)
            {
                return(OpusError.OPUS_BAD_ARG);
            }

            OpusRepacketizer rp = new OpusRepacketizer();

            rp.Reset();
            ret = rp.AddPacket(data, data_offset, len);
            if (ret < 0)
            {
                return(ret);
            }
            ret = rp.opus_repacketizer_out_range_impl(0, rp.nb_frames, data, data_offset, len, 0, 0);
            Inlines.OpusAssert(ret > 0 && ret <= len);

            return(ret);
        }
Ejemplo n.º 4
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);
        }