MPGVIDEO.H

//==========================================================================; 
//
// 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) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
//
/******************************Module*Header*******************************\
* Module Name: MpgVideo.h
*
* Prototype Mpeg Video codec
*
\**************************************************************************/
#ifndef _INC_MPGVIDEO_H
#define _INC_MPGVIDEO_H
#include <streams.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <stddef.h>
#include <string.h>

#include "Decoder.h"


// -------------------------------------------------------------------------
// Helper functions that can be used by audio and video codecs.
// -------------------------------------------------------------------------
//

/******************************Public*Routine******************************\
* ByteSwap
*
* Converts dwX from little endian to big endian and vice-versa.
*
\**************************************************************************/
__inline DWORD
ByteSwap(
DWORD dwX
)
{
#ifdef _X86_
_asm mov eax, dwX
_asm bswap eax
_asm mov dwX, eax

return dwX;
#else
return _lrotl(((dwX & 0xFF00FF00) >> 8) | ((dwX & 0x00FF00FF) << 8), 16);
#endif
}

LPBYTE SkipToPacketData(LPBYTE pSrc, long &LenLeftInPacket);



// -------------------------------------------------------------------------
// This structure is used to associate Pts time stamps with positions
// within the circular buffer. Each time we get a media sample with a Pts
// time stamp we add a TIMEPOSITION entry to a queue of time positions.
// Each time we decode an I frame we record the starting and ending position
// of the I frame picture within the circular buffer, this information is
// then used to find a suitable time stamp to associate with the frame. If
// a suitable time stamp cannot be found or the frame is not an I frame we
// calculate a suitable time code by extrapolation.
// -------------------------------------------------------------------------
//
class CTimePosition {
public:
CRefTime m_PtsTimeStamp;
LPBYTE m_BufferPosition;

CTimePosition(CRefTime *TimeStamp, LPBYTE lpPos)
: m_PtsTimeStamp(*TimeStamp), m_BufferPosition(lpPos) {}
};


// -------------------------------------------------------------------------
// Structure to hold the contents of an Mpeg 1 sequence header.
// -------------------------------------------------------------------------
struct SEQHDR_INFO {
LONG lWidth; // Native Width in pixels
LONG lHeight; // Native Height in pixels
LONG lvbv; // vbv
REFERENCE_TIME tPictureTime; // Time per picture in 100ns units
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
};


// -------------------------------------------------------------------------
// Quartz Mpeg video codec framework class
//
// -------------------------------------------------------------------------
//
class CMpegVideoOutputPin;
class CMpegVideoInpuPin;

class CMpegVideoCodec
: public CTransformFilter {

public:

//
// --- Com stuff ---
//
static CUnknown * WINAPI CreateInstance(LPUNKNOWN, HRESULT *);
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
DECLARE_IUNKNOWN;

//
// --- CTransform overrides ---
//
HRESULT Receive(IMediaSample *pSample);
HRESULT CheckInputType(const CMediaType* mtIn);
HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut);
HRESULT DecideBufferSize(IMemAllocator * pAllocator,
ALLOCATOR_PROPERTIES * pProperties);
HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
HRESULT StartStreaming(void);
HRESULT StopStreaming(void);
HRESULT EndOfStream(void);
HRESULT EndFlush(void);
HRESULT AlterQuality(Quality q);


CMpegVideoCodec(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *pHr);
~CMpegVideoCodec();


//
// Callback function from low-level deocoder to get an output
// buffer to draw into.
//
LPBYTE GetDecodeBufferAndFormat();

private:
LPBYTE m_pSample;
LONG m_LenLeftInPacket;

//
// Input buffer
//
int m_VBlockSize;
LPBYTE m_Buffer;
LPBYTE m_BufferStart;
LPBYTE m_BufferCurr;
LONG m_BufferFullness;
void UpdateBufferPosition(LPBYTE lpNewCurrent);


//
// Output buffer, for decode I and P frames.
//
LPBYTE m_pFrameBuff;


//
// Sequence header of the video stream beging played.
//
SEQHDR_INFO m_seqInfo;



//
// Decode statistics, number of I, P, B and skipped frames.
//
DWORD m_dwFramesDecoded[4];
DWORD m_dwFramesSkipped[4];
int m_PerfDecode;
int m_QualMsg;
int m_FrameDrawn;
int m_FrameType;


//
// This is the low level mpeg video decoder that all the work
//
DWORD m_dwLateBy;
DWORD m_dwCtrl;
DWORD m_dwCtrlDefault;
DWORD m_dwQualDefault;
CVideoDecoder *m_pVideoDecoder;
VideoCtrl m_VideoControl;

//
// The decoder calls back to get the colour conversion format
// and a buffer to decode into. The callback is static because it
// does not have a "this" pointer. hrCallback is used to keep a record
// of any error that may have occurred during the callback.
//
void SetOutputPinMediaType(const CMediaType *pmt);
IMediaSample *m_pOutSample;
HRESULT hrCallback;



//
// If the input sample contains a sync point then its
// sample time is correct. I will use this time to resync my
// internal clock and reset the count of frames decoded
// since the previous sync point. Otherwise, if the sample
// is not a sync point I use the average time per frame and
// the count of frames since the last sync point to interpolate
// a suitable time for the newly decoded frame.
//
CRefTime m_TimeAtLastSyncPoint;
CRefTime m_TimeSinceLastSyncPoint;
CRefTime m_tStopPrev; // Previous stop time
CGenericList<CTimePosition> m_PtsQueue;


//
// IP Frame tracking class
//
class CNextIP
{
public:
CNextIP();
BOOL GotFirst();
void NextRef(DWORD dwTemporalReference);
BOOL GetTime(REFERENCE_TIME *pt);
BOOL TimeToDraw() const;
void Reset();
void Set(DWORD dwSkipFlag, BOOL bIFrame,
BOOL bTimeSet, REFERENCE_TIME t, DWORD dwTemporalReference);

private:
DWORD m_dwSkipFlag;
BOOL m_bGotFirst;
BOOL m_bTimeSet;
BOOL m_bTimeToDraw;
REFERENCE_TIME m_t;
DWORD m_dwTemporalReference;
};

CNextIP m_NextIP;


//
// Remember whether the media type specified packets or payload
//
BOOL m_bPayloadOnly;


//
// On 8 bit displays the user can select a gray scale palette
// alteranative to the default colour palette, this bypasses the
// colour space conversion code.
//
enum MEDIA_FORMATS {MM_411PK, MM_422PK, MM_422SPK, MM_RGB24_DIB,
MM_RGB24_DDB, MM_RGB565_DIB, MM_RGB565_DDB,
MM_RGB555_DIB, MM_RGB555_DDB, MM_RGB8_DIB,
MM_RGB8_DDB, MM_Y_DIB, MM_Y_DDB};

enum MEDIA_TYPES {MT_Y41P = 0, MT_YUY2, MT_UYVY, MT_RGB24, MT_RGB565,
MT_RGB555, MT_RGB8, MT_COUNT_OF_TYPES = MT_RGB8};

enum PALETTE_TYPE {COLOUR_PALETTE, GREY_PALETTE};

PALETTE_TYPE m_PaletteType;
BOOL m_IgnoreQualityMessage;
DWORD m_dwOutputFormatDib;
DWORD m_dwOutputFormatDdb;

HRESULT CopySampleToBuffer(IMediaSample *pSample);
BOOL UpdateTimeSyncPoint(LPBYTE lpPicStart, REFERENCE_TIME *Time);
ptrdiff_t BuffOffset(LPBYTE Offset);

HRESULT DecodeNextPicture();
void ResetVideoDecoder();
void DecodeUntilBufferEmpty();

void InitDestinationVideoInfo(VIDEOINFO *pVI, DWORD Comp, int n);
void InitDestinationPalette(VIDEOINFO *pVideoInfo);

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

//
// Stop time
//
CRefTime m_tStop;
};
#endif