//==========================================================================;
//
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//  PURPOSE.
//
//  Copyright (c) 1996 - 1997  Microsoft Corporation.  All Rights Reserved.
//
//--------------------------------------------------------------------------;
/*  MPEG-2 utility functions */


/*  Packet header info */
typedef struct tag_MPEG_PACKET_DATA {
    DWORD    dwHeaderLen;
    DWORD    dwPacketLen;
    BOOL     bHasPts;
    LONGLONG llPts;
} MPEG_PACKET_DATA;

/*  Read an normal MPEG-1 style clock */
BOOL GetClock(const BYTE * pData, LONGLONG *Clock);

/*  Read an extended clock */
BOOL GetExtendedClock(const BYTE * pbData, LONGLONG *pllClock);

inline GetStartCode(const BYTE * pbData)
{
    return DWORD_SWAP(*(UNALIGNED DWORD *)pbData);
}


/*  Since dwCode is normally a constant just swap that instead */
inline BOOL IsStartCode(const BYTE * pbData, DWORD dwCode)
{
    return DWORD_SWAP(dwCode) == *(UNALIGNED DWORD *)pbData;
}

/*  Parse pack header

    Parameters :
        pbData - pointer to data containing the system header
        cbData - length of data

    Returns :
        Number of bytes processed (0 if the header doesn't fit
        in the data or 4 if the header is invalid)
        We will return 0 if we can't see the next start code to
        check whether it's a system header start code
*/

DWORD ParseMPEG2PackHeader(const BYTE * pbData, DWORD cbData);

/*  Length of pack header - returns 0 if < cbData */
inline DWORD MPEG2PackHeaderLength(const BYTE * pbData, DWORD cbData)
{
    /*  Need more data */
    if (cbData < 14) {
        return 0;
    } else {
        DWORD dwLen = 14 + (pbData[13] & 0x07);
        if (dwLen > cbData) {
            return 0;
        } else {
            return dwLen;
        }
    }
}

/*  Parse system header

    Parameters :
        pbData - pointer to data containing the system header
        cbData - length of data

    Returns :
        Number of bytes processed (0 if the header doesn't fit
        in the data or 4 if the header is invalid)
*/

LONG ParseSystemHeader(const BYTE * pbData, DWORD cbData);


/*  Parse an MPEG2 packet and extract information */
DWORD ParseMPEG2Packet(
    const BYTE * pbData,
    DWORD cbData,
    MPEG_PACKET_DATA *pPacketData
);

/*  Parse an MPEG1 packet and extract information */
DWORD ParseMPEG1Packet(
    const BYTE * pbData,
    DWORD cbData,
    MPEG_PACKET_DATA *pPacketData
);

BOOL ParseMPEG2PacketHeader(
    const BYTE * pbData,
    DWORD dwLen,
    MPEG_PACKET_DATA *pPacketData
);

/*  Inlines to get PTSs from MPEG2 packets */
inline BOOL MPEG2PacketHasPTS(const BYTE * pbPacket)
{
    /*  Just check if the PTS_DTS_flags are 10 or 11 (ie the first
        bit is one
    */
    return 0 != (pbPacket[7] & 0x80);
}

/*  Get the PTS from an MPEG2 packet */
LONGLONG MPEG2PacketPTS(const BYTE * pbPacket);


typedef struct {
    DWORD          dwProfile;          //  Profile - MPEG2 only
    DWORD          dwLevel;            //  Level - MPEG2 only
    LONG           lWidth;             //  Native Width in pixels
    LONG           lHeight;            //  Native Height in pixels
    LONG           lvbv;               //  vbv
    REFERENCE_TIME  tPictureTime;      //  Time per picture in 100ns units
    float          fPictureRate;       //  In frames per second
    LONG           lTimePerFrame;      //  Time per picture in MPEG units
    LONG           dwBitRate;          //  Bits per second
    LONG           lXPelsPerMeter;     //  Pel aspect ratio
    LONG           lYPelsPerMeter;     //  Pel aspect ratio
    DWORD          dwStartTimeCode;    //  First GOP time code (or -1)
    LONG           lActualHeaderLen;   //  Length of valid bytes in raw seq hdr
    BYTE           RawHeader[140];     //  The real sequence header
} SEQHDR_INFO;

/*  MPEG2 stuff */
typedef struct {
    BOOL           bExtensionPresent;
    BOOL           bDisplayExtensionPresent;
    BOOL           bScalableExtensionPresent;
    SEQHDR_INFO    seqhdrInfo;

} MPEG2_SEQHDR_INFO;

/*  Helper */
int inline SequenceHeaderSize(const BYTE *pb)
{
    /*  No quantization matrices ? */
    if ((pb[11] & 0x03) == 0x00) {
        return 12;
    }
    /*  Just non-intra quantization matrix ? */
    if ((pb[11] & 0x03) == 0x01) {
        return 12 + 64;
    }
    /*  Intra found - is there a non-intra ? */
    if (pb[11 + 64] & 0x01) {
        return 12 + 64 + 64;
    } else {
        return 12 + 64;
    }
}

/*  Extract info from video sequence header

    Returns FALSE if the sequence header is invalid
*/

BOOL ParseSequenceHeader(const BYTE *pbData, LONG lData, SEQHDR_INFO *hdrInfo);

BOOL ParseAudioHeader(const BYTE * pbData, MPEG1WAVEFORMAT *pFormat);

/*  Construct a media type from the video info */
HRESULT GetVideoMediaType(CMediaType *cmt, BOOL bPayload, const SEQHDR_INFO *pInfo);

/*  Find the next start code */
BOOL NextStartCode(const BYTE * *ppbData, DWORD *pdwLeft);

/*  Parse AC3 header */
BOOL ParseAC3Header(const BYTE * pbData, DOLBYAC3WAVEFORMAT *pwf);
