Beispiel #1
0
        /// <summary>
        /// Try to read the blocksize from previous frame
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="headerStartPos"></param>
        /// <returns></returns>
        private ulong ReadPreviousFrameBlocksize(Stream stream, StreamInfo info, int headerStartPos)
        {
            ulong ret = 0;
            long strPos = stream.Position;
            stream.Position = headerStartPos;

            try
            {
                SyncronizeLeft(stream, info);

                ParseHeader(stream,info);

                ret = Blocksize;
            }
            catch (LostSynchronizationException)
            {

            }

            stream.Position = strPos;
            return ret;
        }
Beispiel #2
0
        public static Metadata Decode(Stream stream)
        {
            byte header;

            header = (byte) stream.ReadByte();

            bool lastBlock;

            lastBlock = (header & 0x80) == 0x80;

            if (lastBlock)
            {
                header ^= 0x80;
            }

            BlockType type = (BlockType) header;

            int buff;
            int len = 0;

            for (int i = 0; i < 3; i++)
            {
                len = len << 8;
                buff = stream.ReadByte();
                len |= buff;
            }

            byte[] payload = new byte[len];

            for (int i = 0; i < len; i++)
            {
                payload[i] = (byte) stream.ReadByte();
            }

            Metadata instance;

            switch (type) {
                case BlockType.STREAMINFO:
                    instance = new StreamInfo();
                    break;
                case BlockType.APPLICATION:
                    instance = new Application();
                    break;
                case BlockType.CUESHEET:
                    instance = new CueSheet();
                    break;
                case BlockType.PADDING:
                    instance = new Padding();
                    break;
                case BlockType.PICTURE:
                    instance = new Picture();
                    break;
                case BlockType.SEEKTABLE:
                    instance = new SeekTable();
                    break;
                case BlockType.UNKNOWN:
                    instance = new Unknown();
                    break;
                case BlockType.VORBIS_COMMENT:
                    instance = new VorbisComment();
                    break;
                default:
                    instance = new Reserved();
                    break;
            }

            instance.isLastBlock = lastBlock;
            instance.length = len;
            instance.type = type;
            instance.Parse(payload);

            return instance;
        }
Beispiel #3
0
        internal void ParseHeader(Stream stream, StreamInfo streamInfo)
        {
            ushort buffer;
            int b; //to check EOS

            int additionalBlockSize = 0; //number of additional bytes at the end of the header that represent its length

            int sampleRateBytes = 0; //number of additional bytes at the end of the header that store the sample rate
            int sampleRateMultiplicator = 1; //scale of the stored sample rate

            buffer = Org.Nflac.Flac.Util.StreamReader.ReadUShort(stream);

            byte[] rawHeader = new byte[16];
            byte headerLen = 2;

            rawHeader[0] = (byte)(buffer >> 8);
            rawHeader[1] = (byte)(buffer & 0xff);

            if ((buffer & 0xfff8) != 0xfff8)
            {
                throw new LostSynchronizationException();
                //TODO: desync
            }
            else
            {
                //Console.WriteLine("SYNC: " + (stream.Position-2));
            }

            if ((buffer & 0x4) != 0)
            {
                throw new MalformedFileException("Reserved bit at the header");
            }

            variableLength = (buffer & 0x1) == 0x1;

            byte size;

            buffer = Org.Nflac.Flac.Util.StreamReader.ReadUShort(stream);

            rawHeader[headerLen++] = (byte)(buffer >> 8);
            rawHeader[headerLen++] = (byte)(buffer & 0xff);

            size = (byte)((buffer & 0xF000) >> 12); //higher 4 bits

            if (size == 0x0)
            {
                //reserved block-size
                throw new MalformedFileException("Reserved blocksize detected");
            }
            else if (size == 0x1)
            {
                blocksize = 192;
            }
            else if ((size > 0x1) && (size < 0x6))
            {
                blocksize = (ulong)(576 << (size - 2));
            }
            else if (size == 0x6)
            {
                additionalBlockSize = 1; //get additional byte from the end of the header
            }
            else if (size == 0x7)
            {
                additionalBlockSize = 2; //get 2 bytes from the end of the header
            }
            else if ((size > 0x7) && (size < 0x11))
            {
                blocksize = (ulong)(256 << (size - 8));
            }
            else
            {
                //TODO: handle reserved blocksize value
                throw new MalformedFileException("Reserved blocksize value detected");
            }

            byte rateCoded;

            rateCoded = (byte)((buffer & 0x0F00) >> 8); //next 4 bits

            switch (rateCoded)
            {
                case 0:
                    //get from STREAMINFO
                    break;
                case 1:
                    sampleRate = 88200;
                    break;
                case 2:
                    sampleRate = 176400;
                    break;
                case 3:
                    sampleRate = 192000;
                    break;
                case 4:
                    sampleRate = 8000;
                    break;
                case 5:
                    sampleRate = 16000;
                    break;
                case 6:
                    sampleRate = 22050;
                    break;
                case 7:
                    sampleRate = 24000;
                    break;
                case 8:
                    sampleRate = 32000;
                    break;
                case 9:
                    sampleRate = 44100;
                    break;
                case 10:
                    sampleRate = 48000;
                    break;
                case 11:
                    sampleRate = 96000;
                    break;
                case 12:
                    sampleRate = 0;
                    sampleRateBytes = 1;
                    sampleRateMultiplicator = 1000;
                    break;
                case 13:
                    sampleRate = 0;
                    sampleRateBytes = 2;
                    sampleRateMultiplicator = 1;
                    break;
                case 14:
                    sampleRate = 0;
                    sampleRateBytes = 2;
                    sampleRateMultiplicator = 10;
                    break;
                case 15:
                    throw new MalformedFileException("Reserved sample rate value");
                //handle reserved sample rate value
            }

            byte channelSetupCoded;

            channelSetupCoded = (byte)((buffer & 0x00F0) >> 4); //next 4 bits

            if (channelSetupCoded < 8)
            {
                if ((channelSetupCoded == 6) || (channelSetupCoded == 7))
                {
                    //some specific code for 7- and 8- channel music might be needed (those do not have appropriate channel assignment in the standard)
                }

                channels = (byte)(channelSetupCoded + 1);
                channelSetup = (ChannelAssignment)channelSetupCoded;
            }
            else if ((channelSetupCoded > 7) && (channelSetupCoded < 11))
            {
                //stereo
                channels = 2;
                channelSetup = (ChannelAssignment)channelSetupCoded;
            }
            else
            {
                throw new MalformedFileException("Reserved channel assignment used");
                //TODO: handle reserved channel assignment values
            }

            byte sampleSizeCoded;

            sampleSizeCoded = (byte)((buffer & 0x000E) >> 1); //next 3 bits

            switch (sampleSizeCoded)
            {
                case 0:
                    //get from STREAMINFO
                    break;
                case 1:
                    sampleSize = 8;
                    break;
                case 2:
                    sampleSize = 12;
                    break;
                case 3:
                    throw new MalformedFileException("Reserved sample size");
                case 4:
                    sampleSize = 16;
                    break;
                case 5:
                    sampleSize = 20;
                    break;
                case 6:
                    sampleSize = 24;
                    break;
                case 7:
                    //reserved value 2 handling
                    throw new MalformedFileException("Reserved sample size detected");

            }

            byte mandatoryField2;

            mandatoryField2 = (byte)(buffer & 0x0001); //last 1 bit

            if (mandatoryField2 != 0)
            {
                //TODO: handle mandatory value 2 violation
                throw new MalformedFileException("Mandatory value violated");

            }

            //handle UTF-8-like number
            frameNumber = ReadUTF8Number(stream, rawHeader, ref headerLen);

            //handle additional bytes for blocksize
            for (int i = 0; i < additionalBlockSize; i++)
            {
                blocksize = (ulong)(blocksize << 8);
                buffer = (ushort)stream.ReadByte();
                rawHeader[headerLen++] = (byte)buffer;
                blocksize |= buffer;
            }

            if (!variableLength)
            {
                if (frameNumber * streamInfo.MaximumBlockSize + blocksize > streamInfo.TotalSamples)
                {
                    blocksize = (streamInfo.TotalSamples - frameNumber * streamInfo.MaximumBlockSize);
                }

                /* f*****g ugly hack, but spec gives no better way to detect the last frame */
                if (blocksize != streamInfo.MaximumBlockSize)
                {
                    firstSampleNumber = frameNumber * streamInfo.MaximumBlockSize;
                }
                else
                {
                    firstSampleNumber = frameNumber * blocksize;
                }

                lastSampleNumber = firstSampleNumber + blocksize - 1;
            }
            else
            {
                firstSampleNumber = frameNumber;
                lastSampleNumber = firstSampleNumber + blocksize - 1;
            }

            if (frameNumber == 32)
            {
                //debug breakpoint
            }

            //handle additional sample rate

            for (int i = 0; i < sampleRateBytes; i++)
            {
                sampleRate = (ulong)(sampleRate << 8);

                b = stream.ReadByte();

                if (b == -1)
                {
                    throw new UnexpectedEndOfStreamException();
                }

                buffer = (ushort)b;
                rawHeader[headerLen++] = (byte)buffer;
                sampleRate |= buffer;
            }

            sampleRate *= (ulong)sampleRateMultiplicator;

            b = stream.ReadByte();

            if (b == -1)
            {
                throw new UnexpectedEndOfStreamException();
            }

            headerCRC = (byte)b;

            headerVal = new byte[headerLen];

            for (int i = 0; i < headerLen; i++)
            {
                headerVal[i] = rawHeader[i];
            }

            if (headerCRC != CRC8.Instance.Checksum(headerVal))
            {
                //CRC-8 failed
                //Console.WriteLine(frameNumber + " CRC-8 failed");
                throw new MalformedFileException("Frame header checksum validation failed");
            }
            else
            {
                //Console.WriteLine(frameNumber + " CRC-8 passed");
            }
        }
Beispiel #4
0
        /// <summary>
        /// Syncronize the stream to the start of the next frame
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="streamInfo"></param>
        public void SyncronizeRight(Stream stream, StreamInfo streamInfo)
        {
            for (; ; )
            {
                SeekSynchRight(stream);

                var streamPos = stream.Position;

                try
                {
                    ParseHeader(stream, streamInfo);
                }
                catch(MalformedFileException ex)
                {
                    //not frame header, keep on synch
                    continue;
                }

                stream.Position = streamPos;

                break;
            }
        }
Beispiel #5
0
        /// <summary>
        /// Reads the frame header from the stream.
        /// 
        /// Format description: http://flac.sourceforge.net/format.html#frame_header
        /// </summary>
        /// <param name="stream">The stream to read frame header from</param>
        public void Decode(Stream stream, StreamInfo streamInfo)
        {
            ParseHeader(stream, streamInfo);

            Subframe subfr = new Subframe();
            BitReader br = new BitReader(stream);

            br.IsRecording = true;

            for (int i = 0; i < headerVal.Length; i++)
            {
                br.RememberStream.WriteByte(headerVal[i]);
            }

            br.RememberStream.WriteByte(headerCRC);

            double timeStart, timeEnd;
            SubframeType ch1Type = SubframeType.LPC, ch2Type = SubframeType.LPC;

            timeStart = ((double)(frameNumber * blocksize)) / (double)sampleRate;
            timeEnd = timeStart + ((double)blocksize / (double)sampleRate);

            for (int i = 0; i < channels; i++)
            {
                int bitsPerSampleSubfr = sampleSize;

                switch (channelSetup)
                {
                    case ChannelAssignment.MID_SIDE:
                        if (i == 1)
                        {
                            bitsPerSampleSubfr++;
                        }
                        break;
                    case ChannelAssignment.LEFT_SIDE:
                        if (i == 1)
                        {
                            bitsPerSampleSubfr++;
                        }
                        break;
                    case ChannelAssignment.RIGHT_SIDE:
                        if (i == 0)
                        {
                            bitsPerSampleSubfr++;
                        }
                        break;
                }

                subfr.Decode(this, streamInfo, br, bitsPerSampleSubfr, i);
                if (i == 0)
                {
                    ch1Type = subfr.Type;
                }
                else if (i == 1)
                {
                    ch2Type = subfr.Type;
                }

                //Console.WriteLine(subfr);
                switch(subfr.Type)
                {
                    case SubframeType.Constant:
                        subFrameConst++;
                        break;
                    case SubframeType.Verbatim:
                        subFrameVerbatim++;
                        break;
                    case SubframeType.LPC:
                        subFrameLPC++;
                        break;
                    case SubframeType.Fixed:
                        subFrameFixed++;
                        break;
                }

            }

            //Console.WriteLine("[{0:00.0000}-{1:00.0000}] setup: {2} 1ch: {3}, 2ch: {4}", timeStart, timeEnd, channelSetup, ch1Type, ch2Type);

            //decode channels if needed
            switch (channelSetup)
            {
                case ChannelAssignment.MID_SIDE:
                    for (ulong i = 0; i < blocksize; i++)
                    {
                        int mid = (int)output[0,i];
             	                    int side = (int) output[1,i];
             	                    mid <<= 1;
             	                    mid |= (side & 1);
             	                    output[0,i] = (mid + side) >> 1;
             	                    output[1,i] = (mid - side) >> 1;
                    }
                    break;
                case ChannelAssignment.LEFT_SIDE:
                    for (ulong i = 0; i < blocksize; i++)
                    {
                        if (i == 264)
                        {
                            //degug breakpoint
                        }
                        output[1, i] = output[0, i] - output[1, i];
                    }

                    break;
                case ChannelAssignment.RIGHT_SIDE:
                    for (ulong i = 0; i < blocksize; i++)
                    {
                        output[0, i] = output[1, i] + output[0, i];
                    }
                    break;

            }

            br.IsRecording = false;

            ushort crc16 = (ushort)Org.Nflac.Flac.Util.StreamReader.ReadUShort(stream);

            ushort crc16_calc = CRC16.Instance.Checksum(br.RememberStream);

            if (crc16 == crc16_calc)
            {
                //CRC-16 failed
                throw new MalformedFileException("Frame CRC-16 data checksum validation failed");
                //Console.WriteLine(frameNumber + " CRC-16 failed");
            }
            else
            {
                //Console.WriteLine(frameNumber + " CRC-16 passed");
            }
        }
Beispiel #6
0
        private void ParseHeaders()
        {
            Metadata block = null;

            do
            {
                block = Metadata.Decode(physicalStream);

                if (block is Org.Nflac.Flac.Metaheaders.StreamInfo)
                {
                    flacStreamInfo = (Org.Nflac.Flac.Metaheaders.StreamInfo)block;
                    streamInfo = new FLACNFlacInfo(flacStreamInfo);
                }

                headers.Add(block);
            } while (block.IsLastBlock == false);
        }
Beispiel #7
0
        public void Decode(Frame fr, StreamInfo streamInfo, BitReader str, int bitsPerSample, int channelNum)
        {
            byte header;

            this.channelNum = channelNum;

            header = (byte) str.ReadByte();

            if ((header & 0x80) != 0)
            {
                //TODO: handle corrupt bit
                return;
            }

            byte subtype = (byte)((header & 0x7E) >> 1);

            if (subtype == 0)
            {
                type = SubframeType.Constant;
            }
            else if (subtype == 1)
            {
                type = SubframeType.Verbatim;
            }
            else if ((subtype >= 8)&&(subtype<=12))
            {
                type = SubframeType.Fixed;
                order = (uint)(subtype & 0x7);
            }
            else if ((subtype & 0x20) != 0)
            {
                type = SubframeType.LPC;
                order = (uint)(subtype & 0x1F) + 1;
            }
            else
            {
                //TODO: handle reserved frame types
                return;
            }

            wastedBits = 0;

            if ((header & 0x1) != 0)
            {
                int buff = 0;

                do
                {
                    str.ReadBit(ref buff);
                    wastedBits++;
                } while (buff == 0);
            }

            numSamples = 0;
            numResiduals = 0;

            switch (type)
            {
                case SubframeType.Constant:
                    ProcessConstant(fr, str, bitsPerSample);
                    break;
                case SubframeType.Verbatim:
                    ProcessVerbatim(fr, str, bitsPerSample);
                    break;
                case SubframeType.Fixed:
                    ProcessFixed(fr, str, bitsPerSample);
                    break;
                case SubframeType.LPC:
                    ProcessLPC(fr, str, bitsPerSample);
                    break;

            }
        }