Ejemplo n.º 1
0
        /// <summary>
        /// Writes a buffer of PCM audio samples to the encoder and packetizer. Runs Opus encoding and potentially outputs one or more pages to the underlying Ogg stream.
        /// You can write any non-zero number of samples that you want here; there are no restrictions on length or packet boundaries
        /// </summary>
        /// <param name="data">The audio samples to write. If stereo, this will be interleaved</param>
        /// <param name="offset">The offset to use when reading data</param>
        /// <param name="count">The amount of PCM data to write</param>
        public void WriteSamples(short[] data, int offset, int count)
        {
            if (_finalized)
            {
                throw new InvalidOperationException("Cannot write new samples to Ogg file, the output stream is already closed!");
            }

            if ((data.Length - offset) < count)
            {
                // Check that caller isn't lying about its buffer sizes
                throw new ArgumentOutOfRangeException("The given audio buffer claims to have " + count + " samples, but it actually only has " + (data.Length - offset));
            }

            // Try and fill the opus frame
            // input cursor in RAW SAMPLES
            int inputCursor = 0;
            // output cursor in RAW SAMPLES
            int amountToWrite = Math.Min(_opusFrame.Length - _opusFrameIndex, count - inputCursor);

            while (amountToWrite > 0)
            {
                // Do we need to resample?
                if (_inputSampleRate != _encoderSampleRate)
                {
                    // Resample the input
                    // divide by channel count because these numbers are in samples-per-channel
                    int in_len  = (count - inputCursor) / _inputChannels;
                    int out_len = amountToWrite / _inputChannels;
                    _resampler.ProcessInterleaved(data, offset + inputCursor, ref in_len, _opusFrame, _opusFrameIndex, ref out_len);
                    inputCursor     += in_len * _inputChannels;
                    _opusFrameIndex += out_len * _inputChannels;
                }
                else
                {
                    // If no resampling, we can do a straight memcpy instead
                    Array.Copy(data, offset + inputCursor, _opusFrame, _opusFrameIndex, amountToWrite);
                    _opusFrameIndex += amountToWrite;
                    inputCursor     += amountToWrite;
                }


                if (_opusFrameIndex == _opusFrame.Length)
                {
                    int maxBlockSize = 0x1000;
                    if (_outputStream.Position < 0x1000)
                    {
                        maxBlockSize = 0x1000 - 0x200;
                    }

                    int pageFree           = maxBlockSize - _payloadIndex - _headerIndex;
                    int maxPayloadThisPage = (pageFree / 256) * 255 + (pageFree % 256) - 1;
                    int reconstructed      = (maxPayloadThisPage / 255) + 1 + maxPayloadThisPage;

                    /* when due to segment sizes we would end up with a 1 byte gap, make sure that the next run will have at least 64 byte.
                     * reason why this could happen is that "adding one byte" would require one segment more and thus occupies two byte more.
                     * if this would happen, just reduce the calculated free space such that there is room for another segment.
                     */
                    if (pageFree != reconstructed && maxPayloadThisPage > 64)
                    {
                        maxPayloadThisPage -= 64;
                    }
                    int lacingSpace = (255 - _lacingTableCount) * 255;
                    int maxOpusData = Math.Min(lacingSpace, maxPayloadThisPage);
                    int packetSize  = _encoder.Encode(_opusFrame, 0, _opusFrameSamples, _currentPayload, _payloadIndex, maxOpusData);

                    maxOpusData -= packetSize;

                    /* pad to full remaining size if we would leave just a few bytes behind. picked a random number that seemed enough for opus */
                    if (maxOpusData > 0 && maxOpusData < 43)
                    {
                        if (OpusRepacketizer.PadPacket(_currentPayload, _payloadIndex, packetSize, packetSize + maxOpusData) != Enums.OpusError.OPUS_OK)
                        {
                            Console.WriteLine("[ERROR] Padding failed at offset 0x" + _outputStream.Position.ToString("X8"));
                            throw new PaddingException("Failed to pad packet");
                        }
                        else
                        {
                            packetSize += maxOpusData;
                        }
                    }

                    _payloadIndex += packetSize;

                    // Opus granules are measured in 48Khz samples.
                    // Since the framesize is fixed (20ms) and the sample rate doesn't change, this is basically a constant value
                    _granulePosition += FRAME_SIZE_MS * 48;

                    // And update the lacing values in the header
                    int segmentLength = packetSize;
                    while (segmentLength >= 255)
                    {
                        segmentLength -= 255;
                        _currentHeader[_headerIndex++] = 0xFF;
                        _lacingTableCount++;
                    }

                    _currentHeader[_headerIndex++] = (byte)segmentLength;
                    _lacingTableCount++;

                    int remain = (maxBlockSize - _payloadIndex - _headerIndex);
                    /* check if there would be enough space for lacing and payload each */
                    if (_lacingTableCount >= 248 || remain < 16)
                    {
                        if (remain > 0)
                        {
                            Console.WriteLine("[ERROR] Ogg Page with just a few bytes remaining. Weird bit rate chosen?");
                            Console.WriteLine("[ERROR]   Offset 0x" + _outputStream.Position.ToString("X8"));
                            throw new Exception("Failed to finalize page");
                        }

                        FinalizePage();
                    }

                    _opusFrameIndex = 0;
                }

                amountToWrite = Math.Min(_opusFrame.Length - _opusFrameIndex, count - inputCursor);
            }
        }
Ejemplo n.º 2
0
        internal static int RunTest1(bool no_fuzz)
        {
            byte[]        mapping /*[256]*/ = { 0, 1, 255 };
            byte[]        db62 = new byte[36];
            int           i;
            int           rc, j;
            BoxedValueInt err = new BoxedValueInt();
            OpusEncoder   enc;
            OpusDecoder   dec;

            OpusDecoder[]   dec_err = new OpusDecoder[10];
            Pointer <short> inbuf;
            Pointer <short> outbuf;
            Pointer <short> out2buf;
            //int bitrate_bps;
            Pointer <byte> packet = Pointer.Malloc <byte>(MAX_PACKET + 257);
            uint           enc_final_range;
            uint           dec_final_range;
            //int fswitch;
            //int fsize;
            int count;

            /*FIXME: encoder api tests, fs!=48k, mono, VBR*/

            Console.WriteLine("  Encode+Decode tests.");

            enc = OpusEncoder.Create(48000, 2, OpusApplication.VOIP);
            if (err.Val != OpusError.OPUS_OK || enc == null)
            {
                TestFailed();
            }

            dec = OpusDecoder.Create(48000, 2);
            if (err.Val != OpusError.OPUS_OK || dec == null)
            {
                TestFailed();
            }

            // fixme: this tests assign() performed on a decoder struct, which doesn't exist
            //dec_err[0] = (OpusDecoder*)malloc(OpusDecoder_get_size(2));
            //memcpy(dec_err[0], dec, OpusDecoder_get_size(2));
            dec_err[0] = OpusDecoder.Create(48000, 2);
            dec_err[1] = OpusDecoder.Create(48000, 1);
            dec_err[2] = OpusDecoder.Create(24000, 2);
            dec_err[3] = OpusDecoder.Create(24000, 1);
            dec_err[4] = OpusDecoder.Create(16000, 2);
            dec_err[5] = OpusDecoder.Create(16000, 1);
            dec_err[6] = OpusDecoder.Create(12000, 2);
            dec_err[7] = OpusDecoder.Create(12000, 1);
            dec_err[8] = OpusDecoder.Create(8000, 2);
            dec_err[9] = OpusDecoder.Create(8000, 1);
            for (i = 1; i < 10; i++)
            {
                if (dec_err[i] == null)
                {
                    TestFailed();
                }
            }

            //{
            //    OpusEncoder* enccpy;
            //    /*The opus state structures contain no pointers and can be freely copied*/
            //    enccpy = (OpusEncoder*)malloc(opus_encoder_get_size(2));
            //    memcpy(enccpy, enc, opus_encoder_get_size(2));
            //    memset(enc, 255, opus_encoder_get_size(2));
            //    opus_encoder_destroy(enc);
            //    enc = enccpy;
            //}

            inbuf   = Pointer.Malloc <short>(SAMPLES * 2);
            outbuf  = Pointer.Malloc <short>(SAMPLES * 2);
            out2buf = Pointer.Malloc <short>(MAX_FRAME_SAMP * 3);
            if (inbuf == null || outbuf == null || out2buf == null)
            {
                TestFailed();
            }

            GenerateMusic(inbuf, SAMPLES);

            ///*   FILE *foo;
            //foo = fopen("foo.sw", "wb+");
            //fwrite(inbuf, 1, SAMPLES*2*2, foo);
            //fclose(foo);*/

            enc.Bandwidth = (OpusBandwidth.OPUS_BANDWIDTH_AUTO);

            for (rc = 0; rc < 3; rc++)
            {
                enc.UseVBR            = (rc < 2);
                enc.UseConstrainedVBR = (rc == 1);
                enc.UseInbandFEC      = (rc == 0);

                int[] modes = { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2 };
                int[] rates = { 6000, 12000, 48000, 16000, 32000, 48000, 64000, 512000, 13000, 24000, 48000, 64000, 96000 };
                int[] frame = { 960 * 2, 960, 480, 960, 960, 960, 480, 960 * 3, 960 * 3, 960, 480, 240, 120 };

                for (j = 0; j < modes.Length; j++)
                {
                    int rate;
                    rate  = rates[j] + (int)FastRand() % rates[j];
                    count = i = 0;
                    do
                    {
                        OpusBandwidth bw;
                        int           len, out_samples, frame_size;
                        frame_size = frame[j];
                        if ((FastRand() & 255) == 0)
                        {
                            enc.ResetState();
                            dec.ResetState();

                            if ((FastRand() & 1) != 0)
                            {
                                dec_err[FastRand() & 1].ResetState();
                            }
                        }

                        if ((FastRand() & 127) == 0)
                        {
                            dec_err[FastRand() & 1].ResetState();
                        }

                        if (FastRand() % 10 == 0)
                        {
                            int complex = (int)(FastRand() % 11);
                            enc.Complexity = (complex);
                        }

                        if (FastRand() % 50 == 0)
                        {
                            dec.ResetState();
                        }

                        enc.UseInbandFEC      = (rc == 0);
                        enc.ForceMode         = (OpusMode.MODE_SILK_ONLY + modes[j]);
                        enc.UseDTX            = ((FastRand() & 1) != 0);
                        enc.Bitrate           = (rate);
                        enc.ForceChannels     = (rates[j] >= 64000 ? 2 : 1);
                        enc.Complexity        = ((count >> 2) % 11);
                        enc.PacketLossPercent = ((int)((FastRand() & 15) & (FastRand() % 15)));

                        bw = modes[j] == 0 ? OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND + (int)(FastRand() % 3) :
                             modes[j] == 1 ? OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND + (int)(FastRand() & 1) :
                             OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND + (int)(FastRand() % 5);

                        if (modes[j] == 2 && bw == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND)
                        {
                            bw += 3;
                        }
                        enc.Bandwidth = (bw);
                        len           = enc.Encode(inbuf.Data, i << 1, frame_size, packet.Data, 0, MAX_PACKET);
                        if (len < 0 || len > MAX_PACKET)
                        {
                            TestFailed();
                        }
                        enc_final_range = enc.FinalRange;
                        if ((FastRand() & 3) == 0)
                        {
                            if (OpusRepacketizer.PadPacket(packet.Data, packet.Offset, len, len + 1) != OpusError.OPUS_OK)
                            {
                                TestFailed();
                            }
                            len++;
                        }
                        if ((FastRand() & 7) == 0)
                        {
                            if (OpusRepacketizer.PadPacket(packet.Data, packet.Offset, len, len + 256) != OpusError.OPUS_OK)
                            {
                                TestFailed();
                            }
                            len += 256;
                        }
                        if ((FastRand() & 3) == 0)
                        {
                            len = OpusRepacketizer.UnpadPacket(packet.Data, packet.Offset, len);
                            if (len < 1)
                            {
                                TestFailed();
                            }
                        }
                        out_samples = dec.Decode(packet.Data, 0, len, outbuf.Data, i << 1, MAX_FRAME_SAMP, false);
                        if (out_samples != frame_size)
                        {
                            TestFailed();
                        }
                        dec_final_range = dec.FinalRange;
                        if (enc_final_range != dec_final_range)
                        {
                            TestFailed();
                        }
                        /*LBRR decode*/
                        out_samples = dec_err[0].Decode(packet.Data, 0, len, out2buf.Data, 0, frame_size, ((int)FastRand() & 3) != 0);
                        if (out_samples != frame_size)
                        {
                            TestFailed();
                        }
                        out_samples = dec_err[1].Decode(packet.Data, 0, (FastRand() & 3) == 0 ? 0 : len, out2buf.Data, 0, /*MAX_FRAME_SAMP*/ frame_size, ((int)FastRand() & 7) != 0);
                        if (out_samples < 120)
                        {
                            TestFailed();
                        }
                        i += frame_size;
                        count++;
                    } while (i < (SSAMPLES - MAX_FRAME_SAMP));
                    Console.WriteLine("    Mode {0} FB encode {1}, {2} bps OK.", mstrings[modes[j]], rc == 0 ? " VBR" : rc == 1 ? "CVBR" : " CBR", rate);
                }
            }

            //if (opus_encoder_ctl(enc, OPUS_RESET_STATE) != OpusError.OPUS_OK) test_failed();
            //opus_encoder_destroy(enc);
            //if (opus_multistream_encoder_ctl(MSenc, OPUS_RESET_STATE) != OpusError.OPUS_OK) test_failed();
            //opus_multistream_encoder_destroy(MSenc);
            //if (OpusDecoder_ctl(dec, OPUS_RESET_STATE) != OpusError.OPUS_OK) test_failed();
            //OpusDecoder_destroy(dec);
            //if (opus_multistream_decoder_ctl(MSdec, OPUS_RESET_STATE) != OpusError.OPUS_OK) test_failed();

            return(0);
        }