You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
405 lines
16 KiB
405 lines
16 KiB
//
|
|
// Copyright (c) 1996 - 1998 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// ActiveMovie Line 21 Decoder filter
|
|
//
|
|
|
|
extern const AMOVIESETUP_FILTER sudLine21Dec ;
|
|
|
|
#ifndef _INC_L21DFILT_H
|
|
#define _INC_L21DFILT_H
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
//
|
|
// DVD Line21 data come as a user data packet from the GOP header.
|
|
// A struct for per frame/field based data and a valid flag definition.
|
|
//
|
|
// From DVD specifications...
|
|
#define AM_L21_GOPUD_HDR_STARTCODE 0x000001B2
|
|
#define AM_L21_GOPUD_HDR_INDICATOR 0x4343
|
|
#define AM_L21_GOPUD_HDR_RESERVED 0x01F8
|
|
#define AM_L21_GOPUD_HDR_TOPFIELD_FLAG 0x1
|
|
#define AM_L21_GOPUD_ELEM_MARKERBITS 0x7F
|
|
#define AM_L21_GOPUD_ELEM_VALIDFLAG 0x1
|
|
// There can be max 63 frames/fields' worth data per packet as there are
|
|
// 6 bits to represent this number in the packet.
|
|
#define AM_L21_GOPUD_ELEMENT_MAX 63
|
|
|
|
typedef struct _AM_L21_GOPUD_ELEMENT {
|
|
BYTE bMarker_Switch ;
|
|
BYTE chFirst ;
|
|
BYTE chSecond ;
|
|
} AM_L21_GOPUD_ELEMENT, *PAM_L21_GOPUD_ELEMENT ;
|
|
|
|
typedef struct _AM_L21_GOPUD_HEADER {
|
|
BYTE abL21StartCode[4] ;
|
|
BYTE abL21Indicator[2] ;
|
|
BYTE abL21Reserved[2] ;
|
|
BYTE bTopField_Rsrvd_NumElems ;
|
|
} AM_L21_GOPUD_HEADER, *PAM_L21_GOPUD_HEADER ;
|
|
|
|
typedef struct _AM_L21_GOPUD_PACKET {
|
|
AM_L21_GOPUD_HEADER Header ;
|
|
AM_L21_GOPUD_ELEMENT aElements[AM_L21_GOPUD_ELEMENT_MAX] ;
|
|
} AM_L21_GOPUD_PACKET, *PAM_L21_GOPUD_PACKET ;
|
|
|
|
#define GETGOPUD_NUMELEMENTS(pGOPUDPacket) ((pGOPUDPacket)->Header.bTopField_Rsrvd_NumElems & 0x3F)
|
|
#define GETGOPUD_PACKETSIZE(pGOPUDPacket) (LONG)(sizeof(AM_L21_GOPUD_HEADER) + GETGOPUD_NUMELEMENTS(pGOPUDPacket) * sizeof(AM_L21_GOPUD_ELEMENT))
|
|
#define GETGOPUDPACKET_ELEMENT(pGOPUDPacket, i) ((pGOPUDPacket)->aElements[i])
|
|
#define GETGOPUD_ELEM_MARKERBITS(Elem) ((((Elem).bMarker_Switch & 0xFE) >> 1) & 0x7F)
|
|
#define GETGOPUD_ELEM_SWITCHBITS(Elem) ((Elem).bMarker_Switch & 0x01)
|
|
|
|
#define GETGOPUD_L21STARTCODE(Header) \
|
|
( (DWORD)((Header).abL21StartCode[0]) << 24 | \
|
|
(DWORD)((Header).abL21StartCode[1]) << 16 | \
|
|
(DWORD)((Header).abL21StartCode[2]) << 8 | \
|
|
(DWORD)((Header).abL21StartCode[3]) )
|
|
#define GETGOPUD_L21INDICATOR(Header) \
|
|
( (DWORD)((Header).abL21Indicator[0]) << 8 | \
|
|
(DWORD)((Header).abL21Indicator[1]) )
|
|
#define GETGOPUD_L21RESERVED(Header) \
|
|
( (DWORD)((Header).abL21Reserved[0]) << 8 | \
|
|
(DWORD)((Header).abL21Reserved[1]) )
|
|
|
|
#define GOPUD_HEADERLENGTH (4+2+2+1)
|
|
#define GETGOPUD_ELEMENT(pGOPUDPkt, i) (pGOPUDPkt + GOPUD_HEADERLENGTH + sizeof(AM_L21_GOPUD_ELEMENT) * i)
|
|
#define ISGOPUD_TOPFIELDFIRST(pGOPUDPacket) ((pGOPUDPacket)->Header.bTopField_Rsrvd_NumElems & 0x80)
|
|
|
|
|
|
//
|
|
// ATSC Line21 data come as a user data packet from the GOP header.
|
|
// A struct for per frame/field based data and a valid flag definition.
|
|
//
|
|
// From ATSC Standards for Coding 25/50Hz Video (A/63) specifications...
|
|
#define AM_L21_ATSCUD_HDR_STARTCODE 0x000001B2
|
|
#define AM_L21_ATSCUD_HDR_IDENTIFIER 0x47413934
|
|
#define AM_L21_ATSCUD_HDR_TYPECODE_EIA 0x03
|
|
#define AM_L21_ATSCUD_HDR_EM_DATA_FLAG 0x80
|
|
#define AM_L21_ATSCUD_HDR_CC_DATA_FLAG 0x40
|
|
#define AM_L21_ATSCUD_HDR_ADDL_DATA_FLAG 0x20
|
|
#define AM_L21_ATSCUD_HDR_CC_COUNT_MASK 0x1F
|
|
#define AM_L21_ATSCUD_HDR_NEXTBITS_ON 0x01
|
|
#define AM_L21_ATSCUD_ELEM_MARKERBITS 0xF8
|
|
#define AM_L21_ATSCUD_ELEM_VALID_FLAG 0x04
|
|
#define AM_L21_ATSCUD_ELEM_TYPE_FLAG 0x03
|
|
#define AM_L21_ATSCUD_MARKERBITS 0xFF
|
|
#define AM_L21_ATSCUD_HDR_NEXTBITS_FLAG 0x00000100
|
|
// There can be max 31 frames/fields' worth data per packet as there are
|
|
// 5 bits to represent this number in the packet.
|
|
#define AM_L21_ATSCUD_ELEMENT_MAX 31
|
|
|
|
typedef struct _AM_L21_ATSCUD_ELEMENT {
|
|
BYTE bCCMarker_Valid_Type ;
|
|
BYTE chFirst ;
|
|
BYTE chSecond ;
|
|
} AM_L21_ATSCUD_ELEMENT, *PAM_L21_ATSCUD_ELEMENT ;
|
|
|
|
typedef struct _AM_L21_ATSCUD_HEADER {
|
|
BYTE abL21StartCode[4] ;
|
|
BYTE abL21Identifier[4] ;
|
|
BYTE bL21UDTypeCode ;
|
|
BYTE bL21DataFlags_Count ;
|
|
BYTE bL21EMData ;
|
|
} AM_L21_ATSCUD_HEADER, *PAM_L21_ATSCUD_HEADER ;
|
|
|
|
typedef struct _AM_L21_ATSCUD_PACKET {
|
|
AM_L21_ATSCUD_HEADER Header ;
|
|
AM_L21_ATSCUD_ELEMENT aElements[AM_L21_ATSCUD_ELEMENT_MAX] ;
|
|
BYTE bMarkerBits ;
|
|
} AM_L21_ATSCUD_PACKET, *PAM_L21_ATSCUD_PACKET ;
|
|
|
|
#define GETATSCUD_NUMELEMENTS(pATSCUDPacket) ((pATSCUDPacket)->Header.bL21DataFlags_Count & AM_L21_ATSCUD_HDR_CC_COUNT_MASK)
|
|
#define GETATSCUD_PACKETSIZE(pATSCUDPacket) (LONG)(sizeof(AM_L21_ATSCUD_HEADER) + \
|
|
GETATSCUD_NUMELEMENTS(pATSCUDPacket) * sizeof(AM_L21_ATSCUD_ELEMENT) + \
|
|
sizeof(BYTE))
|
|
#define GETATSCUDPACKET_ELEMENT(pATSCUDPacket, i) ((pATSCUDPacket)->aElements[i])
|
|
#define GETATSCUD_ELEM_MARKERBITS(Elem) (((Elem).bCCMarker_Valid_Type & AM_L21_ATSCUD_ELEM_MARKERBITS) >> 3)
|
|
|
|
#define GETATSCUD_STARTCODE(Header) \
|
|
( (DWORD)((Header).abL21StartCode[0]) << 24 | \
|
|
(DWORD)((Header).abL21StartCode[1]) << 16 | \
|
|
(DWORD)((Header).abL21StartCode[2]) << 8 | \
|
|
(DWORD)((Header).abL21StartCode[3]) )
|
|
#define GETATSCUD_IDENTIFIER(Header) \
|
|
( (DWORD)((Header).abL21Identifier[0]) << 24 | \
|
|
(DWORD)((Header).abL21Identifier[1]) << 16 | \
|
|
(DWORD)((Header).abL21Identifier[2]) << 8 | \
|
|
(DWORD)((Header).abL21Identifier[3]) )
|
|
#define GETATSCUD_TYPECODE(Header) (DWORD)((Header).bL21UDTypeCode)
|
|
#define ISATSCUD_TYPE_EIA(pATSCUDPacket) (AM_L21_ATSCUD_HDR_TYPECODE_EIA == \
|
|
((pATSCUDPacket)->Header.bL21UDTypeCode & 0xFF))
|
|
#define ISATSCUD_EM_DATA(pATSCUDPacket) (AM_L21_ATSCUD_HDR_EM_DATA_FLAG == \
|
|
((pATSCUDPacket)->Header.bL21DataFlags_Count & AM_L21_ATSCUD_HDR_EM_DATA_FLAG))
|
|
#define ISATSCUD_CC_DATA(pATSCUDPacket) (AM_L21_ATSCUD_HDR_CC_DATA_FLAG == \
|
|
((pATSCUDPacket)->Header.bL21DataFlags_Count & AM_L21_ATSCUD_HDR_CC_DATA_FLAG))
|
|
#define ISATSCUD_ADDL_DATA(pATSCUDPacket) (AM_L21_ATSCUD_HDR_ADDL_DATA_FLAG == \
|
|
((pATSCUDPacket)->Header.bL21DataFlags_Count & AM_L21_ATSCUD_HDR_ADDL_DATA_FLAG))
|
|
#define GETATSCUD_EM_DATA(pATSCUDPacket) ((pATSCUDPacket)->Header.bL21EMData)
|
|
#define ISATSCUD_ELEM_MARKERBITS_VALID(Elem) (AM_L21_ATSCUD_ELEM_MARKERBITS == \
|
|
((Elem).bCCMarker_Valid_Type & AM_L21_ATSCUD_ELEM_MARKERBITS))
|
|
#define ISATSCUD_ELEM_CCVALID(Elem) (AM_L21_ATSCUD_ELEM_VALID_FLAG == \
|
|
((Elem).bCCMarker_Valid_Type & AM_L21_ATSCUD_ELEM_VALID_FLAG))
|
|
#define GETATSCUD_ELEM_CCTYPE(Elem) (DWORD)((Elem).bCCMarker_Valid_Type & AM_L21_ATSCUD_ELEM_TYPE_FLAG))
|
|
#define GETATSCUD_MARKERBITS(pATSCUDPacket) (DWORD)((pATSCUDPacket)->bMarkerBits)
|
|
#define ISATSCUD_MARKER_BITSVALID(pATSCUDPacket) (AM_L21_ATSCUD_MARKERBITS == \
|
|
((pATSCUDPacket)->bMarkerBits & AM_L21_ATSCUD_MARKERBITS))
|
|
|
|
// Header = StartCode + Id + TypeCode + (EM_CC_Addl_Data + CCCount) + EM_Data
|
|
#define ATSCUD_HEADERLENGTH (4+4+1+1+1)
|
|
#define GETATSCUD_ELEMENT(pATSCUDPkt, i) ((BYTE)(pATSCUDPkt) + ATSCUD_HEADERLENGTH + \
|
|
sizeof(AM_L21_ATSCUD_ELEMENT) * i)
|
|
|
|
|
|
// CC type in GOP packet
|
|
typedef enum {
|
|
GOP_CCTYPE_Unknown = 0, // Invalid
|
|
GOP_CCTYPE_None, // all 0 -- filler packet
|
|
GOP_CCTYPE_DVD, // DVD CC packets
|
|
GOP_CCTYPE_ATSC, // ATSC CC packets
|
|
} GOPPACKET_CCTYPE ;
|
|
|
|
|
|
// Some more flag, struct and macro definitions...
|
|
#define AM_L21_INFO_FIELDBASED 0x0001
|
|
#define AM_L21_INFO_TOPFIELDFIRST 0x0003
|
|
#define AM_L21_INFO_BOTTOMFIELDFIRST 0x0005
|
|
|
|
typedef struct _AM_LINE21INFO {
|
|
DWORD dwFieldFlags ;
|
|
UINT uWidth ;
|
|
UINT uHeight ;
|
|
UINT uBitDepth ;
|
|
DWORD dwAvgMSecPerSample ;
|
|
} AM_LINE21INFO, *PAM_LINE21INFO ;
|
|
|
|
|
|
//
|
|
// Message Window class (for handling WM_TIMER messages) definition
|
|
//
|
|
class CMessageWindow
|
|
{
|
|
public:
|
|
CMessageWindow() ;
|
|
~CMessageWindow() ;
|
|
|
|
HWND GetHandle() {
|
|
return m_hWnd ;
|
|
} ;
|
|
int AddCount() {
|
|
m_iCount++ ;
|
|
return m_iCount ;
|
|
} ;
|
|
int ReleaseCount() {
|
|
if (GetHandle() == NULL) // something wrong -- get out of here
|
|
return 0 ;
|
|
|
|
m_iCount-- ;
|
|
ASSERT(m_iCount >= 0) ;
|
|
if (m_iCount < 0) // paranoia!!!
|
|
m_iCount = 0 ;
|
|
return m_iCount ;
|
|
} ;
|
|
|
|
private:
|
|
HWND m_hWnd ;
|
|
int m_iCount ;
|
|
|
|
static LRESULT CALLBACK MsgWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ;
|
|
} ;
|
|
|
|
|
|
#define ISRECTEQUAL(r1, r2) (r1.top == r2.top && r1.left == r2.left && r1.right == r2.right && r1.bottom == r2.bottom)
|
|
|
|
|
|
//
|
|
// Line 21 Decoder class definition
|
|
//
|
|
class CLine21DecFilter : public CTransformFilter,
|
|
// public ISpecifyPropertyPages, -- WILL DO LATER
|
|
public IAMLine21Decoder
|
|
{
|
|
friend class CMessageWindow ;
|
|
|
|
private:
|
|
static CMessageWindow *m_pMsgWnd ; // hidden window to process WM_TIMER messages
|
|
|
|
public:
|
|
|
|
//
|
|
// Constructor and destructor
|
|
//
|
|
CLine21DecFilter(TCHAR *, LPUNKNOWN, HRESULT *) ;
|
|
~CLine21DecFilter() ;
|
|
|
|
//
|
|
// Standard COM stuff
|
|
//
|
|
// this goes in the factory template table to create new instances
|
|
static CUnknown * CreateInstance(LPUNKNOWN, HRESULT *) ;
|
|
static void InitClass(BOOL, const CLSID *) ;
|
|
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv) ;
|
|
DECLARE_IUNKNOWN ;
|
|
|
|
//
|
|
// CTranformFilter overrides
|
|
//
|
|
// I must override it
|
|
HRESULT Transform(IMediaSample * pIn, IMediaSample * pOut) ;
|
|
|
|
// Real stuff is in here...
|
|
HRESULT Receive(IMediaSample * pIn) ;
|
|
|
|
// check if you can support mtIn
|
|
HRESULT CheckInputType(const CMediaType* mtIn) ;
|
|
|
|
// check if you can support the transform from this input to
|
|
// this output
|
|
HRESULT CheckTransform(const CMediaType* mtIn,
|
|
const CMediaType* mtOut) ;
|
|
|
|
// called from CBaseOutputPin to prepare the allocator's count
|
|
// of buffers and sizes
|
|
HRESULT DecideBufferSize(IMemAllocator * pAllocator,
|
|
ALLOCATOR_PROPERTIES *pProperties) ;
|
|
|
|
// overriden to know when the media type is set
|
|
HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt) ;
|
|
|
|
// overriden to suggest OUTPUT pin media types
|
|
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) ;
|
|
|
|
HRESULT EndOfStream(void) ;
|
|
HRESULT BeginFlush(void) ;
|
|
HRESULT EndFlush(void) ;
|
|
STDMETHODIMP GetState(DWORD dwMSecs, FILTER_STATE *State) ;
|
|
|
|
// overridden to know when we're starting/stopping the decoding
|
|
STDMETHODIMP Stop(void) ;
|
|
STDMETHODIMP Pause(void) ;
|
|
|
|
// overridden to know when connections are completed, so that we can get
|
|
// the media type (actualy format) info for caching
|
|
HRESULT CompleteConnect(PIN_DIRECTION dir, IPin *pReceivePin) ;
|
|
|
|
// Override to know when we disconnect from in/output side to not use
|
|
// any specified output format any more.
|
|
HRESULT BreakConnect(PIN_DIRECTION dir) ;
|
|
|
|
#if 0 // no QM for now
|
|
// We also override this one as we handle the quality management messages
|
|
HRESULT AlterQuality(Quality q) ;
|
|
#endif // #if 0
|
|
|
|
//
|
|
// ISpecifyPropertyPages method
|
|
//
|
|
// STDMETHODIMP GetPages(CAUUID *pPages) ;
|
|
|
|
//
|
|
// IAMLine21Decoder interface methods
|
|
//
|
|
STDMETHODIMP GetDecoderLevel(AM_LINE21_CCLEVEL *lpLevel) ;
|
|
STDMETHODIMP GetCurrentService(AM_LINE21_CCSERVICE *lpService) ;
|
|
STDMETHODIMP SetCurrentService(AM_LINE21_CCSERVICE Service) ;
|
|
STDMETHODIMP GetServiceState(AM_LINE21_CCSTATE *lpState) ;
|
|
STDMETHODIMP SetServiceState(AM_LINE21_CCSTATE State) ;
|
|
STDMETHODIMP GetOutputFormat(LPBITMAPINFOHEADER lpbmih) ;
|
|
STDMETHODIMP SetOutputFormat(LPBITMAPINFO lpbmi) ;
|
|
STDMETHODIMP GetBackgroundColor(DWORD *pdwPhysColor) ;
|
|
STDMETHODIMP SetBackgroundColor(DWORD dwPhysColor) ;
|
|
STDMETHODIMP GetRedrawAlways(LPBOOL lpbOption) ;
|
|
STDMETHODIMP SetRedrawAlways(BOOL bOption) ;
|
|
STDMETHODIMP GetDrawBackgroundMode(AM_LINE21_DRAWBGMODE *lpMode) ;
|
|
STDMETHODIMP SetDrawBackgroundMode(AM_LINE21_DRAWBGMODE Mode) ;
|
|
|
|
private: // data
|
|
|
|
// Pointer to output buffer (cacheing for efficiency)
|
|
LPBYTE m_pbOutBuffer ;
|
|
|
|
// Line21 Data Decoder class that takes 2 bytes and converts to a bitmap
|
|
CLine21DataDecoder m_L21Dec ;
|
|
|
|
// What input format type is being used (better to use an integer flag)
|
|
AM_LINE21_CCSUBTYPEID m_eSubTypeIDIn ;
|
|
|
|
GOPPACKET_CCTYPE m_eGOP_CCType ; // if GOPPackets used, what type data (DVD/ATSC/...)
|
|
|
|
REFERENCE_TIME m_rtTimePerSample ; // (in 100 nSec) interval per byte pair from a packet (for GOP packet type)
|
|
REFERENCE_TIME m_rtStart ; // start time for an output sample
|
|
REFERENCE_TIME m_rtStop ; // stop time for an out output sample
|
|
REFERENCE_TIME m_rtLastSample ; // start time of last delivered sample
|
|
LONGLONG m_llMediaStart ; // media time start (rarely used, but...)
|
|
REFERENCE_TIME m_llMediaStop ; // media time stop (rarely used, but...)
|
|
|
|
// flag to detect if we must send an output sample
|
|
BOOL m_bMustOutput ;
|
|
|
|
// flag to remember if the last input sample was a discontiuity sample
|
|
BOOL m_bDiscontLast ;
|
|
|
|
// If the upstream filter doesn't specify any format type, use one from
|
|
// our internal defaults
|
|
VIDEOINFO *m_pviDefFmt ;
|
|
DWORD m_dwDefFmtSize ;
|
|
|
|
// Keep a copy of last output sample's bounding rect
|
|
RECT m_rectLastOutput ;
|
|
IPin *m_pPinDown ; // downstream pin connected to our output
|
|
|
|
CMediaType m_mtOutput ; // current output mediatype (cached)
|
|
//
|
|
// For timer arrangement to complete any scrolling in roll-up mode
|
|
// or to clear old CC (only in byte pair mode as DVD doesn't need it),
|
|
// if input data flow stops in the middle.
|
|
//
|
|
UINT_PTR m_uTimerID ; // timer id
|
|
UINT m_uTimerCount ; // count of how many times TimerProc() was entered;
|
|
// used for timing out CC in byte pair mode.
|
|
BOOL m_bTimerClearReqd ; // timer reqd for clearing old CC
|
|
|
|
//
|
|
// Data for Blending Param operation on the OverlayMixer's in pin
|
|
//
|
|
DWORD m_dwBlendParam ; // blend param from Get..() call
|
|
BOOL m_bBlendingState ; // CC blending state last set
|
|
|
|
#if 0 // no QM for now
|
|
// number of samples to skip between every output CC sample for QM handling
|
|
int m_iSkipSamples ;
|
|
#endif // #if 0
|
|
|
|
#ifdef PERF
|
|
int m_idDelvWait ;
|
|
#endif // PERF
|
|
|
|
private: // functions
|
|
void GetActualColorKey(void) ;
|
|
AM_LINE21_CCSUBTYPEID MapGUIDToID(const GUID *pFormatIn) ;
|
|
BOOL VerifyGOPUDPacketData(PAM_L21_GOPUD_PACKET pGOPUDPacket) ;
|
|
BOOL VerifyATSCUDPacketData(PAM_L21_ATSCUD_PACKET pATSCUDPacket) ;
|
|
BOOL IsFillerPacket(BYTE *pGOPPacket) ;
|
|
DWORD GetOwnPalette(int iNumEntries, PALETTEENTRY *ppe) ;
|
|
HRESULT GetDefaultFormatInfo(void) ;
|
|
BOOL IsValidFormat(BYTE *pbFormat) ;
|
|
HRESULT SendOutputSample(IMediaSample *pIn,
|
|
REFERENCE_TIME *prtStart, REFERENCE_TIME *prtStop) ;
|
|
void SetBlendingState(BOOL bState) ;
|
|
void SetupTimerIfReqd(BOOL bTimerClearReqd) ;
|
|
void FreeTimer(void) ;
|
|
static void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT_PTR uID, DWORD dwTime) ;
|
|
|
|
GOPPACKET_CCTYPE DetectGOPPacketDataType(BYTE *pGOPPacket) ;
|
|
HRESULT ProcessGOPPacket_DVD(IMediaSample *pIn) ;
|
|
HRESULT ProcessGOPPacket_ATSC(IMediaSample *pIn) ;
|
|
|
|
#if 0 // no QM for now
|
|
inline int GetSkipSamples(void) { return m_iSkipSamples ; }
|
|
inline void ResetSkipSamples(void) { m_iSkipSamples = 0 ; } ;
|
|
#endif // #if 0
|
|
} ;
|
|
|
|
#pragma pack(pop)
|
|
|
|
#endif // _INC_L21DFILT_H
|