any link or good idea for reading mpeg4 header in c#??

Recommended Answers

All 4 Replies

I hear that quicktime has a COM api that allows for automatic parsing of file headers. But it's unconfirmed. Its just an idea. there is a Mpeg 1/2 class floating around.

This link might help It has a good amount of information about the mpeg-4 file format.

Parsing a header is complicated, especially with video headers as the container file has a header, and each stream has a header. So even with the most simple video there are actually 3 headers to parse. The container header, the video header, and the audio header. Its a serious task and not something you will throw together very quickly, But good luck.

Hi Diamonddrake, Thanks for your reply

Yes, it's a bit serious thing. Actually i want to know my video file resolution, bitrate,audio channel, compression used .. etc.
I already have some code which can read .mp3 file format. but i really don't know about .mp4 .
will get on mpeg1/2 .--

I found this for mpeg 1/2

public class MPEGInfo

{

    #region index structures from mpgtx source

    int[, ,] BitRateIndex = new int[2, 3, 16]

            {

                { // MPEG 1

                    {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, // layer 1

                    {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, // layer 2

                    {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}  // layer 3

                },

                {// MPEG 2 or 2.5

                    {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, // layer 1

                    {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0}, // layer 2

                    {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0}  // layer 3

                }

            };

 

    int[,] SamplingIndex = new int[3, 4]

            {

                {44100,48000,32000,0}, // mpeg 1

                {22050,24000,16000,0}, // mpeg 2

                {11025,12000, 8000,0}  // mpeg 2.5

            };

 

    double[] FrameRateIndex = new double[9]

        {

            0d, 24000d/1001d, 24d, 25d,

            30000d/1001d, 30d, 50d,

            60000d/1001d, 60d

        };

 

    string[] AspectRatioIndex = new string[5]

            {

                "Invalid",

                "1/1 (VGA)",

                "4/3 (TV)",

                "16/9 (Large TV)",

                "2.21/1 (Cinema)"

            };

 

    public string[] ModeIndex = new string[4] // these can change anytime specs change so be careful

            {

                "Stereo",

                "Joint Stereo",

                "Dual Channel",

                "Mono",

            };

 

    public string[] EmphasisIndex = new string[4] // same as above

            {

                "No Emphasis",

                "50/15 Micro seconds",

                "Unknown",

                "CCITT J 17",

            };

    #endregion

 

    #region properties

 

    public class Video

    {

        public int GopHeaders;

        public int Height; // px

        public int Width;

        public double FrameRate; // fps

        public int AspectRatioCode;

        public string AspectRatio;

        public int BitRate;

        public double Duration; // seconds

        public double MuxRate;

        public int ChromaFormat;

        public string ChromaFormatText;

        public int Format;

        public string FormatText;

        public int Frames;

        public int Version = 1; // by default its 1

    }

    public Video VideoInfo;

 

    public class Audio

    {

        public double Version;

        public int Layer;

        public bool Protected;

        public int BitRate;

        public float ByteRate;

        public int SamplingRate;

        public bool Padding;

        public int ModeCode;

        public int ModeXt;

        public bool Copyright;

        public int EmphasisIndex;

        public bool Original;

        public int FrameLength;

        // seconds; duration = file size / bit rate but from what i understand there is a timestamp

        // for initial and one for when video ends, so accurate duration = timestamp end - timestamp start

        public double Duration;

        public int Frames;

    }

    public Audio AudioInfo;

    #endregion

 

    public bool EnableTrace; // debugging purposes

 

    const byte PADDING_PACKET = 0xBE; // use these to compare instead of bytes every time

    const byte VIDEO_PACKET = 0xE0;

    const byte AUDIO_PACKET = 0xC0;

    const byte SYSTEM_PACKET = 0xBB;

 

    const double FLOAT_0x10000 = (double)((UInt32)1 << 16); // unsigned long in c++ is UInt32 in c#

    const UInt32 STD_SYSTEM_CLOCK_FREQ = (UInt32)90000;

 

    const int BUFFER_SIZE = 8192; // 8K buffer

 

    int _mpegVersion = 1;

    long _fileSize;

    double _initialTS; // needed to fix video/audio duration

    bool _mpeg2Found; // switch needed to fix video duration

 

    byte[] _backwardBuffer;

    byte[] _forwardBuffer;

 

    FileStream _fs;

    BinaryReader _br;

 

    public MPEGInfo(string file)

    {

        if (!File.Exists(file))

        {

            return;

        }

        _fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

        _br = new BinaryReader(_fs);

    }

 

    public void Parse()

    {

        if (_br != null)

        {

            _backwardBuffer = new byte[BUFFER_SIZE];

            _forwardBuffer = new byte[BUFFER_SIZE];

            _fileSize = _fs.Length;

            VideoInfo = new Video();

            AudioInfo = new Audio();

 

            ParseVideo(0);

            //_br.BaseStream.Seek(0, SeekOrigin.Begin); // go back to the start (redundant now)

            ParseAudio();

            //_br.BaseStream.Seek(0, SeekOrigin.Begin); // go back to the start

            ParseSystem(0);

        }

        _br.Close();

        _fs.Close();

    }

 

    int _backwardBufferStart = 0;

    int _backwardBufferEnd = 0;

 

    byte GetByteBackwards(int offset)

    {

        int pos = -1;

        if (offset >= _backwardBufferEnd || offset < _backwardBufferStart) // need new buffer

        {

            //Trace(string.Format("-debug- new buffer needed; offset: {0}, buffer start: {1}, buffer end: {2}", offset,

            //    _backwardBufferStart, _backwardBufferEnd));

 

            pos = offset - BUFFER_SIZE + 1;

            if (pos < 0) { pos = 0; }

 

            //Trace(string.Format("-debug- position: {0}", pos));

 

            _backwardBufferStart = pos;

            _backwardBufferEnd = offset;

 

            //Trace(string.Format("-debug- buffer start: {0}, buffer end: {1}",

            //    _backwardBufferStart, _backwardBufferEnd));

 

            _br.BaseStream.Seek(pos, SeekOrigin.Begin);

            _br.Read(_backwardBuffer, 0, BUFFER_SIZE);

        }

 

        //Trace(string.Format("-debug- offset: {0}, buffer start: {1}",

        //        offset, _backwardBufferStart));

 

        // got new buffer or still  in range

        return _backwardBuffer[offset - _backwardBufferStart];

    }

 

    int _forwardBufferStart = 0;

    int _forwardBufferEnd = 0;

 

    byte GetByte(int offset)

    {

        int pos = -1;

        if (offset >= _forwardBufferEnd || offset < _forwardBufferStart) // need new buffer

        {

            //Trace(string.Format("-debug- new f buffer needed; offset: {0}, buffer start: {1}, buffer end: {2}", offset,

            //    _forwardBufferStart, _forwardBufferEnd));

 

            pos = offset + BUFFER_SIZE;

            if (pos > _fileSize) { pos = (int)_fileSize; }

 

            //Trace(string.Format("-debug- f position: {0}", pos));

 

            _forwardBufferStart = offset;

            _forwardBufferEnd = pos;

 

            //Trace(string.Format("-debug- f buffer start: {0}, buffer end: {1}",

            //    _forwardBufferStart, _forwardBufferEnd));

 

            _br.BaseStream.Seek(offset, SeekOrigin.Begin);

            _br.Read(_forwardBuffer, 0, BUFFER_SIZE);

        }

 

        //Trace(string.Format("-debug- f offset after creating/if statements: {0}, buffer start: {1}",

        //        offset, _forwardBufferStart));

 

        // got new buffer or still  in range

        return _forwardBuffer[offset - _forwardBufferStart];

    }

 

    int GetSize(int offset)

    {

        return GetByte(offset) * 256 + GetByte(offset + 1);

    }

 

    /// <summary>

    /// Find the specified marker given a starting position

    /// </summary>

    /// <param name="offset">Position to start searching from</param>

    /// <param name="marker">Marker to search for</param>

    /// <returns>True and the offset if the maker is found</returns>

    bool EnsureMPEG(out int offset, byte marker)

    {

        offset = 0;

        for (int i = 0; i < _fileSize - 4; i++)

        {

            if (GetByte(i) == 0x00

                && GetByte(i + 1) == 0x00

                && GetByte(i + 2) == 0x01

                && GetByte(i + 3) == marker)

            {

                offset = i;

                return true;

            }

        }

        return false;

    }

 

    /// <summary>

    /// Find a specific marker by going through the file in reverse

    /// TODO: Improve this (GetByte() is slow when using this method because it seeks from the start

    /// </summary>

    /// <param name="offset">Position to start searching from</param>

    /// <param name="marker">Marker to search for</param>

    /// <returns>Position of the marker</returns>

    int FindMarkerBackwards(int offset, byte marker)

    {

 

        for (int i = offset; i > 0; i--)

        {

            if (GetByteBackwards(i) == 0x00

                && GetByteBackwards(i + 1) == 0x00

                && GetByteBackwards(i + 2) == 0x01

                && GetByteBackwards(i + 3) == marker)

            {

                return i;

            }

        }

        return -1;

    }

 

    bool MarkerExistsAt(out int offset, byte marker, int from) // self explanatory / see above

    {

        offset = -1;

        for (int i = from; i < _fileSize - 4; i++)

        {

            if (GetByte(i) == 0x00

                && GetByte(i + 1) == 0x00

                && GetByte(i + 2) == 0x01

                && GetByte(i + 3) == marker)

            {

                offset = i;

                return true;

            }

        }

        return false;

    }

 

    int FindNextMarker(int from, byte marker) // overloaded method / see above

    {

        int offset = from;

        while (from >= 0 && from < _fileSize - 4)

        {

            offset = FindNextMarker(from);

 

            if (offset == -1)

            {

                return -1;

            }

            else if (MarkerExistsAt(out offset, marker, from))

            {

                return offset;

            }

            else

            {

                from++;

            }

        }

        return -1;

    }

 

    int FindNextMarker(int from, ref byte marker) // see above

    {

        int offset = FindNextMarker(from);

        if (offset > -1)

        {

            marker = GetByte(offset + 3);

            return offset;

        }

        return -1;

    }

 

    int FindNextMarker(int from) // see above

    {

        int offset;

        for (offset = from; offset < (_fileSize - 4); offset++)

        {

            if (

                (GetByte(offset + 0) == 0x00) &&

                (GetByte(offset + 1) == 0x00) &&

                (GetByte(offset + 2) == 0x01))

            {

                return offset;

            }

        }

        return -1;

    }

 

    bool hasAudio = false;

    void ParseSystem(int offset)

    {

        bool keepGoing = true;

        byte mark = 0x00;

 

        if (EnsureMPEG(out offset, 0xBA)) // make sure we'r parsing a mpeg header

        {

            //FindMuxRate(offset + 4);

 

            int packLength = 0;

            int packetSize = 0;

            byte packetType = new byte();

 

            while (keepGoing)

            {

                offset = FindNextMarker(offset, ref mark);

 

                if (offset == -1)

                {

                    break; // valid marker not found

                }

 

                if (mark == VIDEO_PACKET || mark == AUDIO_PACKET)

                {

                    break; // end of system header

                }

 

                if (mark == PADDING_PACKET)

                {

                    offset += GetSize(offset + 4);

                    continue;

                }

 

                if (mark == 0xBA)

                {

                    FindMuxRate(offset + 4);

                    offset += 12;

                    continue;

                }

 

                if (mark != SYSTEM_PACKET)

                {

                    offset += 4;

                    continue;

                }

 

                int startOfPack = FindNextMarker(offset, 0xBA);

                if (startOfPack != -1)

                {

                    if ((GetByte(startOfPack + 4) & 0xF0) == 0x20)

                    {

                        packLength = 12; // mpeg 1

                    }

                    else

                    {

                        if ((GetByte(startOfPack + 4) & 0xC0) == 0x40)

                        {

                            // mpeg 2 pack + stuffing

                            packLength = 14 + (GetByte(startOfPack + 13) & 0x07);

                        }

                        else

                        {

                            packLength = 12; // somethings not right

                        }

                    }

                }

 

                if (startOfPack == -1 || (startOfPack + packLength != offset))

                {

                    //Trace(string.Format("-debug- startOfPack: {0}, packLength: {1}, offset: {2}",

                    //   startOfPack, packLength, offset));

 

                    startOfPack = offset;

                    //return; keep going anyway

                }

 

                // TODO: Implement ParseSystemPacket

 

                packetSize = GetSize(offset + 4);

                packetType = GetByte(offset + 12);

 

                //Trace(string.Format("-debug- packetSize: {0}, packetType: {1}, packLength: {2}, offset: {3}",

                //    packetSize, packetType, packLength, offset));

 

                if (GetByte(offset + 15) == AUDIO_PACKET || GetByte(offset + 15) == VIDEO_PACKET)

                {

                    packetType = VIDEO_PACKET;

                }

 

                if (packetType == AUDIO_PACKET)

                {

                    // TODO: Implement this if needed

                }

                else if (packetType == VIDEO_PACKET)

                {

                    // here we are finally!, this part will fix up the durations

                    if (packLength == 12)

                    {

                        _initialTS = ReadTS(offset - packLength); // find the initial timestamp

                        _mpeg2Found = false; // pack 12 so its not mpeg 2

                    }

                    else

                    {

                        _initialTS = ReadTSMpeg2(offset - packLength);

                        _mpeg2Found = true;

                    }

 

                    //Trace(string.Format("-debug- initial ts: {0}", _initialTS));

                }

                offset += 4; // keep going

            }

        }

 

        /* hopefully it gets to here without crashing :P

        * start searching from the end of the file and -12 because a pack is usually 12 bytes long

        */

        int lastPack = FindMarkerBackwards((int)_fileSize - 13, 0xBA);

 

        //Trace(string.Format("-debug- lastPack: {0}", lastPack));

 

        double duration;

        if ((GetByte(lastPack + 4) & 0xF0) == 0x20)

        {

            duration = ReadTS(lastPack + 4); // mpeg 1

        }

        else

        {

            lastPack = FindMarkerBackwards((int)_fileSize - 8, 0xB8);

 

            //Trace(string.Format("-debug- lastPack 2: {0}", lastPack));

 

            if (((GetByte(lastPack + 4) & 0xC0) == 0x40) || _mpeg2Found)

            {

                lastPack = FindMarkerBackwards((int)_fileSize - 8, 0xBA);

 

                //Trace(string.Format("-debug- lastPack 3: {0}", lastPack));

 

                duration = ReadTSMpeg2(lastPack + 4);

            }

            else

            {

                duration = ReadTSMpeg2(lastPack + 4);

            }

        }

 

        //Trace(string.Format("-debug- duration before: {0}", duration));

        duration -= _initialTS; // fix up the duration

        //Trace(string.Format("-debug- duration after: {0}", duration));

 

        if (this.VideoInfo.Duration > 0)

        {

            if (this.VideoInfo.Duration > duration)

            {

                this.VideoInfo.Duration = duration; // only update if existing is more than current

            }

        }

 

        //Trace(string.Format("-debug- video duration: {0}", SecondsToHMS(this.VideoInfo.Duration)));

    }

 

    double ReadTS(int offset)

    {

        byte highBit;

        UInt32 low4Bytes; // needs to be UInt32 otherwise won't work

        double ts;

 

        highBit = (byte)((GetByte(offset) >> 3) & 0x01);

 

        low4Bytes = (UInt32)(((GetByte(offset) >> 1) & 0x03) << 30);

        low4Bytes |= (UInt32)(GetByte(offset + 1) << 22);

        low4Bytes |= (UInt32)((GetByte(offset + 2) >> 1) << 15);

        low4Bytes |= (UInt32)(GetByte(offset + 3) << 7);

        low4Bytes |= (UInt32)(GetByte(offset + 4) >> 1);

 

        ts = (double)(highBit * FLOAT_0x10000 * FLOAT_0x10000);

        ts += (double)(low4Bytes);

        ts /= (double)STD_SYSTEM_CLOCK_FREQ;

 

        return ts;

    }

 

    double ReadTSMpeg2(int offset)

    {

        byte highBit;

        UInt32 low4Bytes;

        UInt32 sysClockRef;

        double ts;

 

        highBit = (byte)((GetByte(offset) & 0x20) >> 5);

 

        low4Bytes = (UInt32)(((GetByte(offset) & 0x18) >> 3) << 30);

        low4Bytes |= (UInt32)((GetByte(offset) & 0x03) << 28);

        low4Bytes |= (UInt32)(GetByte(offset + 1) << 20);

        low4Bytes |= (UInt32)((GetByte(offset + 2) & 0xF8) << 12);

        low4Bytes |= (UInt32)((GetByte(offset + 2) & 0x03) << 13);

        low4Bytes |= (UInt32)(GetByte(offset + 3) << 5);

        low4Bytes |= (UInt32)(GetByte(offset + 4) >> 3);

 

        sysClockRef = (UInt32)((GetByte(offset + 4) & 0x3) << 7);

        sysClockRef |= (UInt32)((GetByte(offset + 5) >> 1));

 

        ts = (double)(highBit * FLOAT_0x10000 * FLOAT_0x10000);

        ts += (double)low4Bytes;

 

        // TODO: fix this up (confirm with mpgtx first)

        if (sysClockRef == 0)

        {

            ts /= (double)STD_SYSTEM_CLOCK_FREQ;

        }

        else

        {

            ts /= (double)STD_SYSTEM_CLOCK_FREQ;

        }

 

        return ts;

    }

 

    void FindMuxRate(int offset)

    {

        int muxrate = 0;

        if ((GetByte(offset) & 0xC0) == 0x40)

        {

            muxrate = GetByte(offset + 6) << 14;

            muxrate |= GetByte(offset + 7) << 6;

            muxrate |= GetByte(offset + 8) >> 2;

 

        }

        else

        {

            if ((GetByte(offset) & 0xF0) != 0x20)

            {

                //Trace("-debug- invalid offset for mux rate");

            }

            muxrate = (GetByte(offset + 5) & 0x7F) << 15;

            muxrate |= (GetByte(offset + 6) << 7);

            muxrate |= (GetByte(offset + 7) >> 1);

        }

        muxrate *= 50;

        this.VideoInfo.MuxRate = (double)((muxrate * 8.0) / 1000000.0);

 

        //Trace(string.Format("system mux rate: {0} mbps", this.VideoInfo.MuxRate.ToString("n2")));

    }

 

    void ParseAudio()

    {

        int offset = 0;

        hasAudio = false;

 

        //            Trace("starting to parse audio");

 

        offset = FindNextMarker(0, 0xC0); // find the audio marker

 

        if (offset <= -1)

        {

            return;

        }

 

        if (offset > -1)

        {

            offset += 13;

        }

 

        //            Trace(string.Format("offset of audio: {0}", offset));

 

        if (!ParseAudio(offset))

        {

            //                Trace("failed to parse audio");

 

            while ((offset < _fileSize - 10) && !hasAudio) // go through the file until we find an audio marker

            {

                //                    Trace(string.Format("looping to find audio offset: {0}", offset));

 

                if ((GetByte(offset) == 0xFF) && (GetByte(offset + 1) & 0xF0) == 0xF0) // found the proper sequence

                {

                    if (ParseAudio(offset))

                    {

                        //                            Trace("found audio");

                        //this.AudioInfo.Frames++; this doesn't work right

                        hasAudio = true;

                    }

                }

                offset++; // try next offset

            }

        }

 

        //            Trace(string.Format("-debug- audio frames: {0}", this.AudioInfo.Frames));

    }

 

    bool ParseAudio(int offset)

    {

        hasAudio = false;

 

        bool mpeg25 = false;

        if ((GetByte(offset + 0) != 0xFF) || ((GetByte(offset + 1) & 0xF0) != 0xF0)) // see if this has mpeg 2.5

        {

            if ((GetByte(offset + 0) != 0xFF) || ((GetByte(offset + 1) & 0xE0) != 0xE0))

            {

                return false; // invalid sequence exit and try a different offset

            }

            else

            {

                mpeg25 = true;

            }

        }

 

        //            Trace(string.Format("-debug- offset: {0}", offset));

        //            Trace(string.Format("-debug- mpeg25: {0}", mpeg25));

 

        if (Convert.ToBoolean((GetByte(offset + 1) & 0x08)))

        {

            if (!mpeg25)

            {

                this.AudioInfo.Version = 1.0d;

            }

            else

            {

                //                    Trace(string.Format("-debug- invalid 01"));

                return false; // invalid version exit and try a different offset

            }

        }

        else

        {

            if (!mpeg25)

            {

                this.AudioInfo.Version = 2.0d;

            }

            else

            {

                this.AudioInfo.Version = 3.0d; // for 2.5

            }

        }

 

        //            Trace(string.Format("-debug- audio version: {0}", this.AudioInfo.Version));

 

        this.AudioInfo.Layer = (GetByte(offset + 1) & 0x06) >> 1;

 

        switch (this.AudioInfo.Layer)

        {

            case 0:

                this.AudioInfo.Layer = -1;

                return false; // invalid layer exit and try a different offset

                break;

            case 1:

                this.AudioInfo.Layer = 3;

                break;

            case 2:

                this.AudioInfo.Layer = 2;

                break;

            case 3:

                this.AudioInfo.Layer = 1;

                break;

            default:

                this.AudioInfo.Layer = -1;

                return false;

                break;

        }

 

        //            Trace(string.Format("-debug- audio layer: {0}", this.AudioInfo.Layer));

 

        // TODO: confirm if 0 is true or 1 is true, mpgtx has 0 is false and 1 is true?

        this.AudioInfo.Protected = Convert.ToBoolean(GetByte(offset + 1) & 0x01);

 

        //            Trace(string.Format("-debug- audio protection: {0}", this.AudioInfo.Protected));

 

        int bitrateIndex = GetByte(offset + 2) >> 4;

        int samplingIndex = (GetByte(offset + 2) & 0x0F) >> 2;

 

        if (samplingIndex >= 3) { return false; } // invalid indexes, try another offset

        if (bitrateIndex == 15) { return false; }

 

        this.AudioInfo.BitRate = BitRateIndex[(int)this.AudioInfo.Version - 1, this.AudioInfo.Layer - 1, bitrateIndex];

        this.AudioInfo.ByteRate = (float)((this.AudioInfo.BitRate * 1000) / 8.0d);

        this.AudioInfo.SamplingRate = SamplingIndex[(int)this.AudioInfo.Version - 1, samplingIndex];

 

        if (this.AudioInfo.BitRate <= 0

            || this.AudioInfo.ByteRate <= 0

            || this.AudioInfo.SamplingRate <= 0) { return false; }

 

        //Trace(string.Format("-debug- audio bit rate: {0}", this.AudioInfo.BitRate));

        //Trace(string.Format("-debug- audio byte rate: {0}", this.AudioInfo.ByteRate));

        //Trace(string.Format("-debug- audio sampling rate: {0}", this.AudioInfo.SamplingRate));

 

        if (Convert.ToBoolean(GetByte(offset + 2) & 0x02))

        {

            this.AudioInfo.Padding = true;

        }

        else

        {

            this.AudioInfo.Padding = false;

        }

 

        //            Trace(string.Format("-debug- audio padding: {0}", this.AudioInfo.Padding));

 

        this.AudioInfo.ModeCode = GetByte(offset + 3) >> 6;

 

        //            Trace(string.Format("-debug- audio mode: {0}", ModeIndex[this.AudioInfo.ModeCode]));

 

        //TODO: add matching mode extension text

        int modeExt = (GetByte(offset + 3) >> 4) & 0x03;

 

        //Trace(string.Format("-debug- audio modeext: {0}", modeExt));

 

        if (Convert.ToBoolean(GetByte(offset + 3) & 0x08))

        {

            this.AudioInfo.Copyright = true;

        }

        else

        {

            this.AudioInfo.Copyright = false;

        }

 

        //Trace(string.Format("-debug- audio copyright: {0}", this.AudioInfo.Copyright));

 

        if (Convert.ToBoolean(GetByte(offset + 3) & 0x04))

        {

            this.AudioInfo.Original = true;

        }

        else

        {

            this.AudioInfo.Original = false;

        }

 

        //            Trace(string.Format("-debug- audio original: {0}", this.AudioInfo.Original));

 

        this.AudioInfo.EmphasisIndex = GetByte(offset + 3) & 0x03;

 

        //            Trace(string.Format("-debug- audio emphasis index: {0}",

        //EmphasisIndex[this.AudioInfo.EmphasisIndex]));

 

        if (this.AudioInfo.Version == 1)

        {

            if (this.AudioInfo.Layer == 1)

            {

                this.AudioInfo.FrameLength =

                    ((48000 * this.AudioInfo.BitRate) / this.AudioInfo.SamplingRate)

                + 4 * Convert.ToInt32(this.AudioInfo.Padding);

            }

            else

            {

                this.AudioInfo.FrameLength =

                   ((144000 * this.AudioInfo.BitRate) / this.AudioInfo.SamplingRate)

               + Convert.ToInt32(this.AudioInfo.Padding);

            }

        }

        else if (this.AudioInfo.Version == 2)

        {

            if (this.AudioInfo.Layer == 1)

            {

                this.AudioInfo.FrameLength =

                    ((24000 * this.AudioInfo.BitRate) / this.AudioInfo.SamplingRate)

                + 4 * Convert.ToInt32(this.AudioInfo.Padding);

            }

            else

            {

                this.AudioInfo.FrameLength =

                   ((72000 * this.AudioInfo.BitRate) / this.AudioInfo.SamplingRate)

               + Convert.ToInt32(this.AudioInfo.Padding);

            }

        }

        else

        {

            //                Trace(string.Format("-debug- audio layer is invalid"));

            return false;

        }

 

        if (this.AudioInfo.Protected)

        {

            // frame length sometimes gets offset by +- 2, got to find out why its happening, most likely its the protection switch (see above)

            this.AudioInfo.FrameLength += 2;

        }

 

        //            Trace(string.Format("-debug- audio frame length: {0}", this.AudioInfo.FrameLength));

 

        this.AudioInfo.Duration = ((_fileSize * 1.0d) / this.AudioInfo.BitRate) * 0.008d;

 

        //            Trace(string.Format("-debug- audio duration: {0}", SecondsToHMS(this.AudioInfo.Duration)));

 

        //CountAudioFrames();

 

        hasAudio = true;

        return hasAudio;

    }

 

    bool ParseVideo(int offset)

    {

        bool foundVideo = false;

 

        //            Trace(string.Format("-debug- file size: {0}", _fileSize));

 

        if (EnsureMPEG(out offset, 0xB3))

        {

            foundVideo = true;

        }

 

        if (foundVideo)

        {

            //                Trace(string.Format("-debug- offset: {0}", offset));

            offset += 4; // move to the header location

 

            this.VideoInfo.Width = GetSize(offset) >> 4;

            this.VideoInfo.Height = GetSize(offset + 1) & 0x0FFF;

 

            //                Trace(string.Format("-debug- video height: {0}", this.VideoInfo.Height));

            //                Trace(string.Format("-debug- video width: {0}", this.VideoInfo.Width));

 

            offset += 3;

            int frameRateIndex = GetByte(offset) & 0x0F;

            if (frameRateIndex > 8)

            {

                this.VideoInfo.FrameRate = 0.0d;

            }

            else

            {

                this.VideoInfo.FrameRate = FrameRateIndex[frameRateIndex];

            }

 

            //                Trace(string.Format("-debug- video frame rate: {0}", this.VideoInfo.FrameRate));

 

            this.VideoInfo.AspectRatioCode = (GetByte(offset) & 0xF0) >> 4;

            if (this.VideoInfo.AspectRatioCode <= 4)

            {

                this.VideoInfo.AspectRatio = AspectRatioIndex[this.VideoInfo.AspectRatioCode];

            }

            else

            {

                this.VideoInfo.AspectRatio = "Unknown";

            }

 

            //                Trace(string.Format("-debug- video aspect ratio code: {0}, string: {1}",

            //this.VideoInfo.AspectRatioCode, this.VideoInfo.AspectRatio));

 

 

            offset += 1;

 

            this.VideoInfo.BitRate = GetSize(offset);

            //Trace(string.Format("-debug- video bit rate: {0}", this.VideoInfo.BitRate));

            this.VideoInfo.BitRate <<= 2;

            //Trace(string.Format("-debug- video bit rate: {0}", this.VideoInfo.BitRate));

            byte lastTwo = GetByte(offset + 2);

            //Trace(string.Format("-debug- video lastTwo: {0}", lastTwo));

            lastTwo >>= 6;

            //Trace(string.Format("-debug- video lastTwo: {0}", lastTwo));

            this.VideoInfo.BitRate |= lastTwo;

 

            //Trace(string.Format("-debug- video bit rate: {0}", this.VideoInfo.BitRate));

 

            this.VideoInfo.Duration = (_fileSize) /

                ((this.VideoInfo.BitRate * 400) / 8.0); // this gets fixed later when ParseSystem runs

 

            //Trace(string.Format("-debug- video duration: {0}", SecondsToHMS(this.VideoInfo.Duration)));

 

            //Trace(string.Format("-debug- video speed: {0} Mbps",

            //(this.VideoInfo.BitRate / 2500).ToString("n2"))); // always 15mb/s?

 

            // this part is needed to find video format and chroma format

            byte mark = new byte();

            while (true)

            {

                offset = FindNextMarker(offset, ref mark);

                if (offset > -1)

                {

                    if (mark == 0xB8) { break; }

                    switch (GetByte(offset + 3))

                    {

                        case 0xB5:

                            ParseExtension(offset);

                            break;

                        default:

                            break;

                    }

                }

                else

                {

                    //Trace(string.Format("-debug- video offset is -1"));

                    break;

                }

                offset++;

            }

 

            switch (this.VideoInfo.ChromaFormat)

            {

                case 1:

                    this.VideoInfo.ChromaFormatText = "4:2:0";

                    break;

                case 2:

                    this.VideoInfo.ChromaFormatText = "4:2:2";

                    break;

                case 3:

                    this.VideoInfo.ChromaFormatText = "4:4:4";

                    break;

                default:

                    this.VideoInfo.ChromaFormatText = "Unknown";

                    break;

            }

 

            switch (this.VideoInfo.Format)

            {

                case 0:

                    this.VideoInfo.FormatText = "Component";

                    break;

                case 1:

                    this.VideoInfo.FormatText = "PAL";

                    break;

                case 2:

                    this.VideoInfo.FormatText = "NTSC";

                    break;

                case 3:

                    this.VideoInfo.FormatText = "SECAM";

                    break;

                case 4:

                    this.VideoInfo.FormatText = "MAC";

                    break;

                case 5:

                    this.VideoInfo.FormatText = "Unspecified";

                    break;

                default:

                    this.VideoInfo.FormatText = "Unknown";

                    break;

            }

 

            //Trace(string.Format("-debug- video chroma format: {0} is {1}",

            //    this.VideoInfo.ChromaFormat, this.VideoInfo.ChromaFormatText));

            //Trace(string.Format("-debug- video format: {0} is {1}",

            //    this.VideoInfo.Format, this.VideoInfo.FormatText));

 

            //CountVideoFrames();// slows down the routine

 

            // Trace(string.Format("-debug- video frames: {0}", this.VideoInfo.Frames));

        }

 

        return true;

    }

 

    // remove this and use TimeSpan

    string SecondsToHMS(double duration)

    {

        int hours = (int)(duration / 3600);

        int mins = (int)((duration / 60) - (hours * 60));

        double seconds = duration - 60 * mins - 3600 * hours;

 

        if (hours != 0)

        {

            return string.Format("{0:n0}h {1:n0}m {2:n2}s", hours, mins, seconds);

        }

        if (mins != 0)

        {

            return string.Format("{0:n0}m {1:n2}s", mins, seconds);

        }

        return string.Format("{0:n2}s", seconds);

    }

 

    void CountVideoFrames() // slow, find a better way of doing this

    {

        byte[] buffer = new byte[4];

        _br.BaseStream.Seek(0, SeekOrigin.Begin);

 

        int read = 0;

        while ((read = _br.Read(buffer, 0, 4)) != 0)

        {

            if (buffer[0] == 0x00

                && buffer[1] == 0x00

                && buffer[2] == 0x01

                && buffer[3] == 0x00)

            {

                this.VideoInfo.Frames++;

            }

        }

    }

 

    void CountVideoGopHeaders() // slow, find a better way of doing this

    {

        byte[] buffer = new byte[4];

        _br.BaseStream.Seek(0, SeekOrigin.Begin);

 

        int read = 0;

        while ((read = _br.Read(buffer, 0, 4)) != 0)

        {

            if (buffer[0] == 0x00

                && buffer[1] == 0x00

                && buffer[2] == 0x01

                && buffer[3] == 0xB8)

            {

                this.VideoInfo.GopHeaders++;

            }

        }

    }

 

    void ParseExtension(int offset)

    {

        offset += 4;

        switch (GetByte(offset) >> 4)

        {

            case 1: ParseSequenceExt(offset);

                break;

            case 2:

                ParseSequenceDisplayExt(offset);

                break;

            default:

                break;

        }

    }

 

    void ParseSequenceExt(int offset)

    {

        _mpegVersion = 2;

        this.VideoInfo.Version = 2;

        this.VideoInfo.ChromaFormat = (GetByte(offset + 1) & 0x06) >> 1;

    }

 

    void ParseSequenceDisplayExt(int offset)

    {

        this.VideoInfo.Format = (GetByte(offset) & 0x0E) >> 1;

    }

 

    int SkipPacketHeader(int offset)

    {

        byte mark = new byte();

        if (_mpegVersion == 1)

        {

            offset += 6;

            mark = GetByte(offset);

            while (Convert.ToBoolean(mark & 0x80))

            {

                mark = GetByte(++offset);

            }

 

            if ((mark & 0xC0) == 0x40)

            {

                offset += 2;

            }

 

            mark = GetByte(offset);

            if ((mark & 0xF0) == 0x20) { offset += 5; }

            else if ((mark & 0xF0) == 0x30) { offset += 10; }

            else offset++;

 

            return offset;

        }

        else if (_mpegVersion == 2)

        {

            return (offset + 9 + GetByte(offset + 8));

        }

        else return (offset + 10);

    }

 

    void Trace(string msg)

    {

        if (this.EnableTrace)

        {

            Console.WriteLine(msg);

        }

    }

}

Thanks a lot Diamonddrake :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.