Пример #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="VbriHeader"/> class.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <param name="firstFrameBuffer">The first frame buffer.</param>
        /// <param name="offset">The offset.</param>
        public VbriHeader(MpaFrame firstFrame, StreamBuffer firstFrameBuffer, long offset)
            : base(firstFrame, firstFrameBuffer, offset, VbrHeaderType.Vbri)
        {
            /*
            FhG VBRI Header
            size    description
            4       'VBRI' (ID)
            2       version
            2       delay
            2       quality
            4       # bytes
            4       # frames
            2       table size (for TOC)
            2       table scale (for TOC)
            2       size of a table entry (max. size = 4 byte (must be stored in an integer))
            2       frames per table entry
            ??      dynamic table consisting out of frames with size 1-4 whole length in table size! (for TOC)
            */

            // name
            Name = firstFrameBuffer.ReadString(4);

            // version
            Version = (short)firstFrameBuffer.ReadBigEndianInt16();

            // delay
            _delay = firstFrameBuffer.ReadBigEndianInt16();

            // quality
            Quality = firstFrameBuffer.ReadBigEndianInt16();

            // size of the file, in bytes, of all the data
            FileSize = firstFrameBuffer.ReadBigEndianInt32();

            // amount of frames
            FrameCount = firstFrameBuffer.ReadBigEndianInt32();

            // number of entries in the table (for TOC)
            TableEntries = (short)firstFrameBuffer.ReadBigEndianInt16();

            // table scale (for TOC)
            TableScale = (short)firstFrameBuffer.ReadBigEndianInt16();

            // size of a table entry (in bytes)
            TableEntrySize = (short)firstFrameBuffer.ReadBigEndianInt16();

            // frames per table entry
            FramesPerTableEntry = (short)firstFrameBuffer.ReadBigEndianInt16();

            // dynamic table consisting out of frames
            TableLength = TableEntries * TableEntrySize;
            Toc = new int[TableEntries + 1];
            for (int i = 0; i <= TableEntries; i++)
            {
                int value = firstFrameBuffer.ReadBigEndianInt(TableEntrySize);
                Toc[i] = value * TableScale;
            }
            _totalLengthMilliseconds = firstFrame.AudioLength * FrameCount;
        }
Пример #2
0
        ////------------------------------------------------------------------------------------------------------------------------------
        /// <summary>
        /// Reads a <see cref="MpaFrame"/> from a <see cref="Stream"/>.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <returns>
        /// true if found; otherwise, null.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">Thrown if stream is null.</exception>
        public static MpaFrame ReadFrame(Stream stream)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            MpaFrame frame = new MpaFrame();
            return frame.ReadFrame(stream as StreamBuffer ?? new StreamBuffer(stream)) ? frame : null;
        }
Пример #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="XingHeader"/> class.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <param name="firstFrameBuffer">The first frame buffer.</param>
        /// <param name="offset">The offset.</param>
        public XingHeader(MpaFrame firstFrame, StreamBuffer firstFrameBuffer, long offset)
            : base(firstFrame, firstFrameBuffer, offset, VbrHeaderType.Xing)
        {
            /*
            XING VBR-Header
            size    description
            4       'Xing' or 'Info'
            4       flags (indicates which fields are used)
            4       frames (optional)
            4       bytes (optional)
            100     toc (optional)
            4       a VBR quality indicator: 0=best 100=worst (optional)
            --------- +
            120 bytes
            *
            * NOTE: the frames (frameCount) in the XING header does not include its own frame.
            * So the total frames is actually XING framecount + 1
            */

            // name of the tag as found in the file
            Name = firstFrameBuffer.ReadString(4);

            // The flags indicate which fields are used in the XING header
            Flags = firstFrameBuffer.ReadBigEndianInt32();

            // Extract total frames in the file (XING header excludes it's own frame)
            if ((Flags & XingHeaderFlags.FrameCountFlag) != 0)
                FrameCount = firstFrameBuffer.ReadBigEndianInt32();

            // Extract size of the file, in bytes
            if ((Flags & XingHeaderFlags.FileSizeFlag) != 0)
                FileSize = firstFrameBuffer.ReadBigEndianInt32();

            // Extract TOC (Table of Contents) for more accurate seeking
            if ((Flags & XingHeaderFlags.TocFlag) != 0)
            {
                Toc = new int[100];
                for (int i = 0; i < 100; i++)
                    Toc[i] = firstFrameBuffer.ReadByte();
            }

            if ((Flags & XingHeaderFlags.VbrScaleFlag) != 0)
                Quality = firstFrameBuffer.ReadBigEndianInt32();

            // The LAME tag is always 120 bytes after the XING header - regardless of which fields are used
            LameTag = LameTag.FindTag(firstFrameBuffer, offset + 120);
        }
Пример #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="VbrHeader"/> class.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <param name="firstFrameBuffer">The first frame buffer.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="headerType">Type of the header.</param>
        protected VbrHeader(MpaFrame firstFrame, StreamBuffer firstFrameBuffer, long offset, VbrHeaderType headerType)
        {
            if (firstFrame == null)
                throw new ArgumentNullException("firstFrame");

            if (firstFrameBuffer == null)
                throw new ArgumentNullException("firstFrameBuffer");

            ////if (headerType == null)
            ////throw new ArgumentNullException("headerType");

            // first frame contains the vbr header
            FirstFrame = firstFrame;

            // Offset of this header in the first frame.
            Offset = offset;

            // VBR Header type, currently only XING and VBRI
            HeaderType = headerType;
        }
Пример #5
0
        /// <summary>
        /// Finds the <see cref="VbriHeader"/> header within the <paramref name="firstFrame"/>.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <returns>The VBRI header if found; otherwise, null.</returns>
        /// <remarks>
        /// The VBRI header is located exactly 32 bytes after the end of the first MPEG audio header in the file.
        /// It will compare the first 4 bytes against the <see cref="HeaderIndicator"/> 
        /// to see if the header contains a <see cref="VbriHeader"/> or not.
        /// </remarks>
        public static new VbriHeader FindHeader(MpaFrame firstFrame)
        {
            if (firstFrame == null)
                throw new ArgumentNullException("firstFrame");

            using (StreamBuffer buffer = new StreamBuffer())
            {
                byte[] data = firstFrame.ToByteArray();
                buffer.Write(data);

                // 32 bytes = data indicating silence
                const long Offset = MpaFrame.FrameHeaderSize + SilenceDataSize;
                buffer.Seek(Offset, SeekOrigin.Begin);
                string tagName = buffer.ReadString(4, false, false);
                return String.Compare(tagName, HeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0
                           ? new VbriHeader(firstFrame, buffer, Offset)
                           : null;
            }
        }
Пример #6
0
        /// <summary>
        /// Finds the <see cref="VbriHeader"/> header within the <paramref name="firstFrame"/>.
        /// </summary>
        /// <param name="firstFrame">The first frame.</param>
        /// <returns>The VBRI header if found; otherwise, null.</returns>
        /// <remarks>
        /// The XING header is located after the side information in Layer III in the first MPEG audio header in the file.
        /// It will compare the first 4 bytes against the <see cref="VbrHeaderIndicator"/> 
        /// to see if the header contains a <see cref="XingHeader"/> or not.
        /// </remarks>
        public static new XingHeader FindHeader(MpaFrame firstFrame)
        {
            if (firstFrame == null)
                throw new ArgumentNullException("firstFrame");

            long offset = MpaFrame.FrameHeaderSize + firstFrame.SideInfoSize;
            using (StreamBuffer buffer = new StreamBuffer())
            {
                byte[] data = firstFrame.ToByteArray();
                buffer.Write(data);

                buffer.Seek(offset, SeekOrigin.Begin);
                string tagName = buffer.ReadString(4, false, false);
                if ((String.Compare(tagName, VbrHeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0)
                    || (String.Compare(tagName, CbrHeaderIndicator, StringComparison.OrdinalIgnoreCase) == 0))
                    return new XingHeader(firstFrame, buffer, offset);
            }
            return null;
        }
Пример #7
0
        ////------------------------------------------------------------------------------------------------------------------------------
        private static bool IsValidFirstFrame(MpaFrame firstFrame, MpaFrame secondFrame)
        {
            // The free bitrate must remain constant
            // We need to calculate the bitrate manually to see if its constant
            // (If VBR is used, the bitrate can be different for each frame, this check is only for free bitrate frames)
            if (secondFrame.Bitrate == 0)
                return (firstFrame.Bitrate == secondFrame.Bitrate);

            // See if the next frame is directly after the current frame
            // FrameLength is calculated using the bitrate as a calculation factor
            // This will fail if free bitrate is used as its not implemented yet
            ////if ((curFrame.GetOffset() + curFrame.GetFrameLength() != nextFrame.GetOffset()) && (curFrameHeader.BitrateIndex != 0))
            ////{
            ////curFrame = nextFrame;
            ////nextFrame = GetNextFrame(curFrame);
            ////continue;
            ////}

            // Check the values of the next header, some have to be the same as the previous:
            // ** version
            // ** layer
            // ** samples (per sec)
            // ** channel type (can only be mono or stereo)
            // ** emphasis
            return ((secondFrame.AudioVersion == firstFrame.AudioVersion) && (secondFrame.LayerVersion == firstFrame.LayerVersion)
                    && (secondFrame.SamplingRate == firstFrame.SamplingRate) && (secondFrame.IsMono == firstFrame.IsMono)
                    && (secondFrame.Emphasis == firstFrame.Emphasis));
        }
Пример #8
0
        /// <summary>
        /// Find a <see cref="VbrHeader"/> in the supplied frame.
        /// A <see cref="VbrHeader"/> could follow the MPA header in the first frame.
        /// </summary>
        /// <remarks>
        /// Only the first frame can contain a <see cref="VbrHeader"/>.
        /// Possible VBR headers could be <see cref="XingHeader"/> or <see cref="VbriHeader"/>.
        /// </remarks>
        /// <param name="firstFrame">The first frame.</param>
        /// <returns>A VBR header if found; otherwise null.</returns>
        public static VbrHeader FindHeader(MpaFrame firstFrame)
        {
            if (firstFrame == null)
                throw new ArgumentNullException("firstFrame");

            return XingHeader.FindHeader(firstFrame) ?? (VbrHeader)VbriHeader.FindHeader(firstFrame);
        }