public unsafe static FlacSubFrameBase GetSubFrame(FlacBitReader reader, FlacSubFrameData data, FlacFrameHeader header, int bitsPerSample)
        {
            int wastedBits = 0, order;

            uint firstByte = reader.ReadBits(8);

            if ((firstByte & 0x80) != 0) //Zero bit padding, to prevent sync-fooling string of 1s
            {
                Debug.WriteLine("Flacdecoder subframe-header got no zero-bit padding.");
                return(null);
            }

            bool hasWastedBits = (firstByte & 1) != 0; //Wasted bits-per-sample' flag

            if (hasWastedBits)
            {
                int k = (int)reader.ReadUnary();
                wastedBits     = k + 1; //"k-1" follows -> add 1
                bitsPerSample -= wastedBits;
            }

            FlacSubFrameBase subFrame;
            var subframeType = (firstByte & 0x7E) >> 1; //0111 1110

            if (subframeType == 0)                      //000000
            {
                subFrame = new FlacSubFrameConstant(reader, header, data, bitsPerSample);
            }
            else if (subframeType == 1) //000001
            {
                subFrame = new FlacSubFrameVerbatim(reader, header, data, bitsPerSample);
            }
            else if ((subframeType & 0x20) != 0) //100000 = 0x20
            {
                order    = (int)(subframeType & 0x1F) + 1;
                subFrame = new FlacSubFrameLPC(reader, header, data, bitsPerSample, order);
            }
            else if ((subframeType & 0x08) != 0) //001000 = 0x08
            {
                order = (int)(subframeType & 0x07);
                if (order > 4)
                {
                    return(null);
                }
                subFrame = new FlacSubFrameFixed(reader, header, data, bitsPerSample, order);
            }
            else
            {
                Debug.WriteLine(String.Format("Invalid Flac-SubframeType. SubframeType: 0x{0:x}.", subframeType));
                return(null);
            }

            if (hasWastedBits)
            {
                int *destination = data.DestinationBuffer;
                for (int i = 0; i < header.BlockSize; i++)
                {
                    *(destination++) <<= wastedBits;
                }
            }

#if FLAC_DEBUG
            subFrame.WastedBits = wastedBits;
#endif
            return(subFrame);
        }
        private unsafe bool ParseHeader(ref byte *headerBuffer, FlacMetadataStreamInfo streamInfo)
        {
            const string loggerLocation = "FlacFrameHeader.ParseHeader(byte*, FlacMetadataStreamInfo)";
            int          val;

            if (headerBuffer[0] == 0xFF && headerBuffer[1] >> 1 == 0x7C) //sync bits
            {
                if ((headerBuffer[1] & 0x02) != 0)
                {
                    Error("Invalid FlacFrame. Reservedbit_0 is 1", loggerLocation);
                    return(false);
                }

                byte *        __headerbufferPtr = headerBuffer;
                FlacBitReader reader            = new FlacBitReader(__headerbufferPtr, 0);

                #region blocksize

                //blocksize
                val = headerBuffer[2] >> 4;
                int blocksize = -1;

                if (val == 0)
                {
                    Error("Invalid Blocksize value: 0", loggerLocation);
                    return(false);
                }
                if (val == 1)
                {
                    blocksize = 192;
                }
                else if (val >= 2 && val <= 5)
                {
                    blocksize = 576 << (val - 2);
                }
                else if (val == 6 || val == 7)
                {
                    _blocksizeHint = val;
                }
                else if (val >= 8 && val <= 15)
                {
                    blocksize = 256 << (val - 8);
                }
                else
                {
                    Error("Invalid Blocksize value: " + val, loggerLocation);
                    return(false);
                }
                BlockSize = blocksize;

                #endregion blocksize

                #region samplerate

                //samplerate
                val = headerBuffer[2] & 0x0F;
                int sampleRate = -1;

                if (val == 0)
                {
                    if (streamInfo != null)
                    {
                        sampleRate = streamInfo.SampleRate;
                    }
                    else
                    {
                        Error("Missing Samplerate. Samplerate Index = 0 && streamInfoMetaData == null.", loggerLocation);
                        return(false);
                    }
                }
                else if (val >= 1 && val <= 11)
                {
                    sampleRate = FlacConstant.SampleRateTable[val];
                }
                else if (val >= 12 && val <= 14)
                {
                    _sampleRateHint = val;
                }
                else
                {
                    Error("Invalid SampleRate value: " + val, loggerLocation);
                    return(false);
                }
                SampleRate = sampleRate;

                #endregion samplerate

                #region channels

                val = headerBuffer[3] >> 4; //cc: unsigned
                int channels;
                if ((val & 8) != 0)
                {
                    channels = 2;
                    if ((val & 7) > 2 || (val & 7) < 0)
                    {
                        Error("Invalid ChannelAssignment", loggerLocation);
                        return(false);
                    }
                    ChannelAssignment = (ChannelAssignment)((val & 7) + 1);
                }
                else
                {
                    channels          = val + 1;
                    ChannelAssignment = ChannelAssignment.Independent;
                }
                Channels = channels;

                #endregion channels

                #region bitspersample

                val = (headerBuffer[3] & 0x0E) >> 1;
                int bitsPerSample;
                if (val == 0)
                {
                    if (streamInfo != null)
                    {
                        bitsPerSample = streamInfo.BitsPerSample;
                    }
                    else
                    {
                        Error("Missing BitsPerSample. Index = 0 && streamInfoMetaData == null.", loggerLocation);
                        return(false);
                    }
                }
                else if (val == 3 || val >= 7 || val < 0)
                {
                    Error("Invalid BitsPerSampleIndex", loggerLocation);
                    return(false);
                }
                else
                {
                    bitsPerSample = FlacConstant.BitPerSampleTable[val];
                }

                BitsPerSample = bitsPerSample;

                #endregion bitspersample

                if ((headerBuffer[3] & 0x01) != 0) // reserved bit -> 0
                {
                    Error("Invalid FlacFrame. Reservedbit_1 is 1", loggerLocation);
                    return(false);
                }

                reader.ReadBits(32); //skip the first 4 bytes since they got already processed

                //BYTE 4

                #region utf8

                //variable blocksize
                if ((headerBuffer[1] & 0x01) != 0 ||
                    (streamInfo != null && streamInfo.MinBlockSize != streamInfo.MaxBlockSize))
                {
                    ulong samplenumber;
                    if (reader.ReadUTF8_64(out samplenumber) && samplenumber != ulong.MaxValue)
                    {
                        BlockingStrategy = BlockingStrategy.VariableBlockSize;
                        SampleNumber     = (long)samplenumber;
                    }
                    else
                    {
                        Error("Invalid UTF8 Samplenumber coding.", loggerLocation);
                        return(false);
                    }
                }
                else //fixed blocksize
                {
                    uint framenumber;

                    if (reader.ReadUTF8_32(out framenumber) && framenumber != uint.MaxValue)
                    {
                        BlockingStrategy = BlockingStrategy.FixedBlockSize;
                        FrameNumber      = (int)framenumber;
                    }
                    else
                    {
                        Error("Invalid UTF8 Framenumber coding.", loggerLocation);
                        return(false);
                    }
                }

                #endregion utf8

                #region read hints

                //blocksize am ende des frameheaders
                if (_blocksizeHint != 0)
                {
                    val = (int)reader.ReadBits(8);
                    if (_blocksizeHint == 7)
                    {
                        val = (val << 8) | (int)reader.ReadBits(8);
                    }
                    BlockSize = val + 1;
                }

                //samplerate
                if (_sampleRateHint != 0)
                {
                    val = (int)reader.ReadBits(8);
                    if (_sampleRateHint != 12)
                    {
                        val = (val << 8) | (int)reader.ReadBits(8);
                    }
                    if (_sampleRateHint == 12)
                    {
                        SampleRate = val * 1000;
                    }
                    else if (_sampleRateHint == 13)
                    {
                        SampleRate = val;
                    }
                    else
                    {
                        SampleRate = val * 10;
                    }
                }

                #endregion read hints

                if (DoCrc)
                {
                    var crc8 = Utils.CRC8.Instance.CalcCheckSum(reader.Buffer, 0, reader.Position);
                    Crc8 = (byte)reader.ReadBits(8);
                    if (Crc8 != crc8)
                    {
                        Error("CRC8 missmatch", loggerLocation);
                        return(false);
                    }
                }
                else
                {
                    Crc8 = (byte)reader.ReadBits(8);
                }

                headerBuffer += reader.Position;
                return(true);
            }

            Error("Invalid Syncbits", loggerLocation);
            return(false);
        }
Exemple #3
0
        public unsafe FlacSubFrameLPC(FlacBitReader reader, FlacFrameHeader header, FlacSubFrameData data, int bitsPerSample, int order)
            : base(header)
        {
            var warmup = new int[order];

            for (int i = 0; i < order; i++)
            {
                warmup[i] = data.ResidualBuffer[i] = reader.ReadBitsSigned(bitsPerSample);
            }

            int coefPrecision = (int)reader.ReadBits(4);

            if (coefPrecision == 0x0F)
            {
                throw new FlacException("Invalid \"quantized linear predictor coefficients' precision in bits\" was invalid. Must not be 0x0F.",
                                        FlacLayer.SubFrame);
            }
            coefPrecision += 1;

            int shiftNeeded = reader.ReadBitsSigned(5);

            if (shiftNeeded < 0)
            {
                throw new FlacException("'\"Quantized linear predictor coefficient shift needed in bits\" was negative.", FlacLayer.SubFrame);
            }

            var q = new int[order];

            for (int i = 0; i < order; i++)
            {
                q[i] = reader.ReadBitsSigned(coefPrecision);
            }

            //decode the residual
            var residual = new FlacResidual(reader, header, data, order);

            for (int i = 0; i < order; i++)
            {
                data.DestinationBuffer[i] = data.ResidualBuffer[i];
            }

            int *residualBuffer0    = data.ResidualBuffer + order;
            int *destinationBuffer0 = data.DestinationBuffer + order;
            int  blockSizeToProcess = header.BlockSize - order;

            if (bitsPerSample + coefPrecision + Log2(order) <= 32)
            {
                RestoreLPCSignal32(residualBuffer0, destinationBuffer0, blockSizeToProcess, order, q, shiftNeeded);
            }
            else
            {
                RestoreLPCSignal64(residualBuffer0, destinationBuffer0, blockSizeToProcess, order, q, shiftNeeded);
            }

#if FLAC_DEBUG
            QLPCoeffPrecision = coefPrecision;
            LPCShiftNeeded    = shiftNeeded;
            Warmup            = warmup;
            Residual          = residual;
            QLPCoeffs         = q;
#endif
        }