Example #1
0
 /// <summary>
 /// construct AudioFrame from supplied bytes
 /// </summary>
 /// <param name="frameBuffer"></param>
 /// <remarks>buffer is correct size, even for free bitrate files</remarks>
 public AudioFrame(byte[] frameBuffer)
 {
     // find and parse frame header, rewind stream to start, or throw.
     _header = new AudioFrameHeader(frameBuffer);
     _headerBytes = _header.HeaderSize;
     _frameBuffer = frameBuffer;
 }
        /// <summary>
        /// Creates Header
        /// </summary>
        /// <remarks>
        /// n.b. doesn't rewind the stream to the start of the frame.
        /// If the caller wants to read the entire frame in one block, they'll have to rewind it themselves.
        /// </remarks>
        /// <param name="stream"></param>
        /// <param name="remainingBytes"></param>
        /// <returns>valid audio header, or null</returns>
        static AudioFrameHeader CreateHeader(Stream stream, uint remainingBytes)
        {
            // save the start of the skip operation, for error messages
            long streamStartpos = stream.Position;
            int  framesSkipped  = 0;

            // apply an upper limit of 64k to the number of bytes it will skip,
            // to prevent it trying to read the whole of a corrupt 5meg file
            // (MPAHeaderInfo skips 3 frames but I think it's worth checking further than that)
            if (remainingBytes > 65536)
            {
                remainingBytes = 65536;
            }

            long endPos = streamStartpos + (long)remainingBytes;

            do
            {
                long remaining  = endPos - (uint)stream.Position;
                int  numskipped = Seek(stream, remaining);

                if (numskipped < 0)
                {
                    //throw new InvalidAudioFrameException(
                    //    string.Format("MPEG Audio Frame: No header found from offset {0} to the end", streamStartpos));
                    return(null);
                }
                //else if( numskipped > 0 )
                //    Trace.WriteLine( string.Format( "{0} bytes skipped to start of frame at offset {1}",
                //                                    numskipped, stream.Position - numskipped ) );

                // save the start of the real frame, i.e. after the rubbish is skipped
                long frameStartPos = stream.Position;

                AudioFrameHeader parsedHeader = new AudioFrameHeader(ReadHeader(stream));
                if (parsedHeader.Valid)
                {
                    if (frameStartPos > streamStartpos)
                    {
                        if (framesSkipped > 0)
                        {
                            Trace.WriteLine(string.Format("total {0} bytes and {1} invalid frame headers skipped to get to the start of a valid frame at stream offset {2}",
                                                          frameStartPos - streamStartpos, framesSkipped, frameStartPos));
                        }
                        else
                        {
                            Trace.WriteLine(string.Format("total {0} bytes skipped to get to the start of a valid frame at stream offset {1}",
                                                          frameStartPos - streamStartpos, frameStartPos));
                        }
                    }
                    return(parsedHeader);
                }

                // header is invalid mp3 frame, so skip a char and look again
                stream.Position = frameStartPos;
                ++framesSkipped;
                /*byte skipchar = (byte)*/ stream.ReadByte();
                //Trace.WriteLine(string.Format("  Invalid MP3 frame; skipping 0x{0:X} at {1}", skipchar, frameStartPos + 1));
            }while(true);
        }
        /// <summary>
        /// compare headers
        /// </summary>
        // return true if identical or related
        // return false if no similarities
        // (from an idea in CMPAHeader, http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx)

        bool IsCompatible(AudioFrameHeader destHeader)
        {
            // version change never possible
            if (destHeader.RawMpegVersion != RawMpegVersion)
            {
                return(false);
            }

            // layer change never possible
            if (destHeader.RawLayer != RawLayer)
            {
                return(false);
            }

            // sampling rate change never possible
            if (destHeader.RawSampleFreq != RawSampleFreq)
            {
                return(false);
            }

            // from mono to stereo never possible
            if (destHeader.IsMono != IsMono)
            {
                return(false);
            }

            if (destHeader.RawEmphasis != RawEmphasis)
            {
                return(false);
            }

            return(true);
        }
Example #4
0
 /// <summary>
 /// construct AudioFrame from supplied bytes
 /// </summary>
 /// <param name="frameBuffer"></param>
 /// <remarks>buffer is correct size, even for free bitrate files</remarks>
 public AudioFrame(byte[] frameBuffer)
 {
     // find and parse frame header, rewind stream to start, or throw.
     _header      = new AudioFrameHeader(frameBuffer);
     _headerBytes = _header.HeaderSize;
     _frameBuffer = frameBuffer;
 }
Example #5
0
        /// <summary>
        /// construct AudioFrame from a larger portion of the stream; don't rewind stream when done
        /// </summary>
        /// <param name="stream">source stream</param>
        /// <param name="header">parsed header</param>
        /// <param name="frameSize">size from header, or scanning for second frame of free bitrate file</param>
        /// <param name="remainingBytes">number of bytes in audio block, as reported by the caller</param>
        public AudioFrame(Stream stream, AudioFrameHeader header, uint frameSize, uint remainingBytes)
        {
            Debug.Assert(header != null);
            _header = header;

            _frameBuffer = new byte[frameSize];
            _headerBytes = _header.HeaderSize;

            int numgot = stream.Read(_frameBuffer, 0, (int)frameSize);
            if( numgot < (int)frameSize )
                throw new InvalidAudioFrameException(
                    string.Format("MPEG Audio AudioFrame: only {0} bytes of frame found when {1} bytes declared",
                                  numgot,
                                  frameSize));
        }
        /// <summary>
        /// seek and create derived type of AudioFrame from stream
        /// </summary>
        /// <param name="stream">source stream, advanced by length of the frame on read</param>
        /// <param name="remainingBytes">number of bytes in audio block, as reported by the caller</param>
        /// <returns>wrapper for derived type of AudioFrame</returns>
        static public AudioFrame CreateFrame(Stream stream, uint remainingBytes)
        {
            // find and parse frame header, then rewind stream back to start.
            // if reach the end of the file, return null
            // if any other error, throw
            long firstFrameStart = stream.Position;

            AudioFrameHeader header = CreateHeader(stream, remainingBytes);

            if (header == null)
            {
                return(null);
            }

            uint frameFullSize;

            // if free rate file, find the start of the next frame and use the difference as the frame size.
            // NB. This won't be very efficient!
            if (header.IsFreeBitRate)
            {
                uint firstFrameHdrSize = (uint)(stream.Position - firstFrameStart);
                frameFullSize = firstFrameHdrSize + GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));

                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
                //GetNextFrameOffset(stream, remainingBytes - (uint)(stream.Position - firstFrameStart));
            }
            else
            {
                uint?frameLengthInBytes = header.FrameLengthInBytes;
                Trace.Assert(frameLengthInBytes != null);
                frameFullSize = (uint)header.FrameLengthInBytes;
            }

            // rewind the stream to the start of the frame, so we can read it all in one chunk
            stream.Position = firstFrameStart;

            AudioFrame firstTry = new AudioFrame(stream, header, frameFullSize, remainingBytes);

            return(CreateSpecialisedHeaderFrame(firstTry));
        }
        /// <summary>
        /// skip to start of next frame
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="remainingBytes"></param>
        /// <returns>number of bytes skipped, not length of frame found!</returns>
        static private uint GetNextFrameOffset(Stream stream, uint remainingBytes)
        {
            long prevHeaderEnd = stream.Position;

            AudioFrameHeader header = CreateHeader(stream, remainingBytes);

            if (header == null)
            {
                return(0);
            }

            Trace.WriteLine(String.Format("next frame is {0} bytes further", stream.Position - prevHeaderEnd));
            Trace.WriteLine(header.DebugString);

            return((uint)(stream.Position - prevHeaderEnd));
        }
Example #8
0
        /// <summary>
        /// construct AudioFrame from a larger portion of the stream; don't rewind stream when done
        /// </summary>
        /// <param name="stream">source stream</param>
        /// <param name="header">parsed header</param>
        /// <param name="frameSize">size from header, or scanning for second frame of free bitrate file</param>
        /// <param name="remainingBytes">number of bytes in audio block, as reported by the caller</param>
        public AudioFrame(Stream stream, AudioFrameHeader header, uint frameSize, uint remainingBytes)
        {
            Debug.Assert(header != null);
            _header = header;

            _frameBuffer = new byte[frameSize];
            _headerBytes = _header.HeaderSize;

            int numgot = stream.Read(_frameBuffer, 0, (int)frameSize);

            if (numgot < (int)frameSize)
            {
                throw new InvalidAudioFrameException(
                          string.Format("MPEG Audio AudioFrame: only {0} bytes of frame found when {1} bytes declared",
                                        numgot,
                                        frameSize));
            }
        }
        /// <summary>
        /// compare headers
        /// </summary>
        // return true if identical or related
        // return false if no similarities
        // (from an idea in CMPAHeader, http://www.codeproject.com/KB/audio-video/mpegaudioinfo.aspx)
        bool IsCompatible( AudioFrameHeader destHeader )
        {
            // version change never possible
            if (destHeader.RawMpegVersion != RawMpegVersion)
                return false;

            // layer change never possible
            if (destHeader.RawLayer != RawLayer)
                return false;

            // sampling rate change never possible
            if (destHeader.RawSampleFreq != RawSampleFreq)
                return false;

            // from mono to stereo never possible
            if (destHeader.IsMono != IsMono)
                return false;

            if (destHeader.RawEmphasis != RawEmphasis)
                return false;

            return true;
        }
Example #10
0
 /// <summary>
 /// copy construct AudioFrame for derived classes
 /// </summary>
 /// <param name="other"></param>
 protected AudioFrame(AudioFrame other)
 {
     _frameBuffer = other._frameBuffer;
     _header = other._header;
     _headerBytes = other._headerBytes;
 }
        /// <summary>
        /// Creates Header
        /// </summary>
        /// <remarks>
        /// n.b. doesn't rewind the stream to the start of the frame.
        /// If the caller wants to read the entire frame in one block, they'll have to rewind it themselves.
        /// </remarks>
        /// <param name="stream"></param>
        /// <param name="remainingBytes"></param>
        /// <returns>valid audio header, or null</returns>
        static AudioFrameHeader CreateHeader( Stream stream, uint remainingBytes )
        {
            // save the start of the skip operation, for error messages
            long streamStartpos = stream.Position;
            int framesSkipped = 0;

            // apply an upper limit of 64k to the number of bytes it will skip,
            // to prevent it trying to read the whole of a corrupt 5meg file
            // (MPAHeaderInfo skips 3 frames but I think it's worth checking further than that)
            if( remainingBytes > 65536 )
                remainingBytes = 65536;

            long endPos = streamStartpos + (long)remainingBytes;

            do
            {
                long remaining = endPos - (uint)stream.Position;
                int numskipped = Seek( stream, remaining );

                if( numskipped < 0 )
                {
                    //throw new InvalidAudioFrameException(
                    //    string.Format("MPEG Audio Frame: No header found from offset {0} to the end", streamStartpos));
                    return null;
                }
                //else if( numskipped > 0 )
                //    Trace.WriteLine( string.Format( "{0} bytes skipped to start of frame at offset {1}",
                //                                    numskipped, stream.Position - numskipped ) );

                // save the start of the real frame, i.e. after the rubbish is skipped
                long frameStartPos = stream.Position;

                AudioFrameHeader parsedHeader = new AudioFrameHeader( ReadHeader( stream ) );
                if( parsedHeader.Valid )
                {
                    if( frameStartPos > streamStartpos )
                    {
                        if( framesSkipped > 0 )
                            Trace.WriteLine(string.Format("total {0} bytes and {1} invalid frame headers skipped to get to the start of a valid frame at stream offset {2}",
                                                            frameStartPos - streamStartpos, framesSkipped, frameStartPos));
                        else
                            Trace.WriteLine(string.Format("total {0} bytes skipped to get to the start of a valid frame at stream offset {1}",
                                                            frameStartPos - streamStartpos, frameStartPos));
                    }
                    return parsedHeader;
                }

                // header is invalid mp3 frame, so skip a char and look again
                stream.Position = frameStartPos;
                ++framesSkipped;
                /*byte skipchar = (byte)*/stream.ReadByte();
                //Trace.WriteLine(string.Format("  Invalid MP3 frame; skipping 0x{0:X} at {1}", skipchar, frameStartPos + 1));
            }
            while( true );
        }
Example #12
0
 /// <summary>
 /// copy construct AudioFrame for derived classes
 /// </summary>
 /// <param name="other"></param>
 protected AudioFrame(AudioFrame other)
 {
     _frameBuffer = other._frameBuffer;
     _header      = other._header;
     _headerBytes = other._headerBytes;
 }