Line endings...be normalized!
This commit is contained in:
+111
-111
@@ -1,111 +1,111 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMExtra.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements CRenderedInputPin class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h> // DirectShow base class definitions
|
||||
#include <mmsystem.h> // Needed for definition of timeGetTime
|
||||
#include <limits.h> // Standard data type limit definitions
|
||||
#include <measure.h> // Used for time critical log functions
|
||||
|
||||
#include "amextra.h"
|
||||
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
// Implements CRenderedInputPin class
|
||||
|
||||
CRenderedInputPin::CRenderedInputPin(TCHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName) :
|
||||
CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
|
||||
m_bAtEndOfStream(FALSE),
|
||||
m_bCompleteNotified(FALSE)
|
||||
{
|
||||
}
|
||||
#ifdef UNICODE
|
||||
CRenderedInputPin::CRenderedInputPin(CHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName) :
|
||||
CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
|
||||
m_bAtEndOfStream(FALSE),
|
||||
m_bCompleteNotified(FALSE)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flush end of stream condition - caller should do any
|
||||
// necessary stream level locking before calling this
|
||||
|
||||
STDMETHODIMP CRenderedInputPin::EndOfStream()
|
||||
{
|
||||
HRESULT hr = CheckStreaming();
|
||||
|
||||
// Do EC_COMPLETE handling for rendered pins
|
||||
if (S_OK == hr && !m_bAtEndOfStream) {
|
||||
m_bAtEndOfStream = TRUE;
|
||||
FILTER_STATE fs;
|
||||
EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs)));
|
||||
if (fs == State_Running) {
|
||||
DoCompleteHandling();
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Called to complete the flush
|
||||
|
||||
STDMETHODIMP CRenderedInputPin::EndFlush()
|
||||
{
|
||||
CAutoLock lck(m_pLock);
|
||||
|
||||
// Clean up renderer state
|
||||
m_bAtEndOfStream = FALSE;
|
||||
m_bCompleteNotified = FALSE;
|
||||
|
||||
return CBaseInputPin::EndFlush();
|
||||
}
|
||||
|
||||
|
||||
// Notify of Run() from filter
|
||||
|
||||
HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(tStart);
|
||||
m_bCompleteNotified = FALSE;
|
||||
if (m_bAtEndOfStream) {
|
||||
DoCompleteHandling();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Clear status on going into paused state
|
||||
|
||||
HRESULT CRenderedInputPin::Active()
|
||||
{
|
||||
m_bAtEndOfStream = FALSE;
|
||||
m_bCompleteNotified = FALSE;
|
||||
return CBaseInputPin::Active();
|
||||
}
|
||||
|
||||
|
||||
// Do stuff to deliver end of stream
|
||||
|
||||
void CRenderedInputPin::DoCompleteHandling()
|
||||
{
|
||||
ASSERT(m_bAtEndOfStream);
|
||||
if (!m_bCompleteNotified) {
|
||||
m_bCompleteNotified = TRUE;
|
||||
m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMExtra.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements CRenderedInputPin class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h> // DirectShow base class definitions
|
||||
#include <mmsystem.h> // Needed for definition of timeGetTime
|
||||
#include <limits.h> // Standard data type limit definitions
|
||||
#include <measure.h> // Used for time critical log functions
|
||||
|
||||
#include "amextra.h"
|
||||
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
// Implements CRenderedInputPin class
|
||||
|
||||
CRenderedInputPin::CRenderedInputPin(TCHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName) :
|
||||
CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
|
||||
m_bAtEndOfStream(FALSE),
|
||||
m_bCompleteNotified(FALSE)
|
||||
{
|
||||
}
|
||||
#ifdef UNICODE
|
||||
CRenderedInputPin::CRenderedInputPin(CHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName) :
|
||||
CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
|
||||
m_bAtEndOfStream(FALSE),
|
||||
m_bCompleteNotified(FALSE)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flush end of stream condition - caller should do any
|
||||
// necessary stream level locking before calling this
|
||||
|
||||
STDMETHODIMP CRenderedInputPin::EndOfStream()
|
||||
{
|
||||
HRESULT hr = CheckStreaming();
|
||||
|
||||
// Do EC_COMPLETE handling for rendered pins
|
||||
if (S_OK == hr && !m_bAtEndOfStream) {
|
||||
m_bAtEndOfStream = TRUE;
|
||||
FILTER_STATE fs;
|
||||
EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs)));
|
||||
if (fs == State_Running) {
|
||||
DoCompleteHandling();
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Called to complete the flush
|
||||
|
||||
STDMETHODIMP CRenderedInputPin::EndFlush()
|
||||
{
|
||||
CAutoLock lck(m_pLock);
|
||||
|
||||
// Clean up renderer state
|
||||
m_bAtEndOfStream = FALSE;
|
||||
m_bCompleteNotified = FALSE;
|
||||
|
||||
return CBaseInputPin::EndFlush();
|
||||
}
|
||||
|
||||
|
||||
// Notify of Run() from filter
|
||||
|
||||
HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(tStart);
|
||||
m_bCompleteNotified = FALSE;
|
||||
if (m_bAtEndOfStream) {
|
||||
DoCompleteHandling();
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Clear status on going into paused state
|
||||
|
||||
HRESULT CRenderedInputPin::Active()
|
||||
{
|
||||
m_bAtEndOfStream = FALSE;
|
||||
m_bCompleteNotified = FALSE;
|
||||
return CBaseInputPin::Active();
|
||||
}
|
||||
|
||||
|
||||
// Do stuff to deliver end of stream
|
||||
|
||||
void CRenderedInputPin::DoCompleteHandling()
|
||||
{
|
||||
ASSERT(m_bAtEndOfStream);
|
||||
if (!m_bCompleteNotified) {
|
||||
m_bCompleteNotified = TRUE;
|
||||
m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+56
-56
@@ -1,56 +1,56 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMExtra.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __AMEXTRA__
|
||||
#define __AMEXTRA__
|
||||
|
||||
// Simple rendered input pin
|
||||
//
|
||||
// NOTE if your filter queues stuff before rendering then it may not be
|
||||
// appropriate to use this class
|
||||
//
|
||||
// In that case queue the end of stream condition until the last sample
|
||||
// is actually rendered and flush the condition appropriately
|
||||
|
||||
class CRenderedInputPin : public CBaseInputPin
|
||||
{
|
||||
public:
|
||||
|
||||
CRenderedInputPin(TCHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CRenderedInputPin(CHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
|
||||
// Override methods to track end of stream state
|
||||
STDMETHODIMP EndOfStream();
|
||||
STDMETHODIMP EndFlush();
|
||||
|
||||
HRESULT Active();
|
||||
HRESULT Run(REFERENCE_TIME tStart);
|
||||
|
||||
protected:
|
||||
|
||||
// Member variables to track state
|
||||
BOOL m_bAtEndOfStream; // Set by EndOfStream
|
||||
BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE
|
||||
|
||||
private:
|
||||
void DoCompleteHandling();
|
||||
};
|
||||
|
||||
#endif // __AMEXTRA__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMExtra.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __AMEXTRA__
|
||||
#define __AMEXTRA__
|
||||
|
||||
// Simple rendered input pin
|
||||
//
|
||||
// NOTE if your filter queues stuff before rendering then it may not be
|
||||
// appropriate to use this class
|
||||
//
|
||||
// In that case queue the end of stream condition until the last sample
|
||||
// is actually rendered and flush the condition appropriately
|
||||
|
||||
class CRenderedInputPin : public CBaseInputPin
|
||||
{
|
||||
public:
|
||||
|
||||
CRenderedInputPin(TCHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CRenderedInputPin(CHAR *pObjectName,
|
||||
CBaseFilter *pFilter,
|
||||
CCritSec *pLock,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
|
||||
// Override methods to track end of stream state
|
||||
STDMETHODIMP EndOfStream();
|
||||
STDMETHODIMP EndFlush();
|
||||
|
||||
HRESULT Active();
|
||||
HRESULT Run(REFERENCE_TIME tStart);
|
||||
|
||||
protected:
|
||||
|
||||
// Member variables to track state
|
||||
BOOL m_bAtEndOfStream; // Set by EndOfStream
|
||||
BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE
|
||||
|
||||
private:
|
||||
void DoCompleteHandling();
|
||||
};
|
||||
|
||||
#endif // __AMEXTRA__
|
||||
|
||||
|
||||
+5207
-5207
File diff suppressed because it is too large
Load Diff
+1589
-1589
File diff suppressed because it is too large
Load Diff
+275
-275
@@ -1,275 +1,275 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMVideo.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements helper functions for
|
||||
// bitmap formats.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
// These are bit field masks for true colour devices
|
||||
|
||||
const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F};
|
||||
const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F};
|
||||
const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF};
|
||||
|
||||
// This maps bitmap subtypes into a bits per pixel value and also a
|
||||
// name. unicode and ansi versions are stored because we have to
|
||||
// return a pointer to a static string.
|
||||
const struct {
|
||||
const GUID *pSubtype;
|
||||
WORD BitCount;
|
||||
CHAR *pName;
|
||||
WCHAR *wszName;
|
||||
} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome",
|
||||
&MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA",
|
||||
&MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8",
|
||||
&MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)",
|
||||
&MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)",
|
||||
&MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24",
|
||||
&MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32",
|
||||
&MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32",
|
||||
&MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay",
|
||||
&GUID_NULL, 0, "UNKNOWN", L"UNKNOWN"
|
||||
};
|
||||
|
||||
// Return the size of the bitmap as defined by this header
|
||||
|
||||
STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader)
|
||||
{
|
||||
return DIBSIZE(*pHeader);
|
||||
}
|
||||
|
||||
|
||||
// This is called if the header has a 16 bit colour depth and needs to work
|
||||
// out the detailed type from the bit fields (either RGB 565 or RGB 555)
|
||||
|
||||
STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader)
|
||||
{
|
||||
BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader;
|
||||
ASSERT(pbmiHeader->biBitCount == 16);
|
||||
|
||||
// If its BI_RGB then it's RGB 555 by default
|
||||
|
||||
if (pbmiHeader->biCompression == BI_RGB) {
|
||||
return MEDIASUBTYPE_RGB555;
|
||||
}
|
||||
|
||||
// Compare the bit fields with RGB 555
|
||||
|
||||
DWORD *pMask = (DWORD *) pbmInfo->bmiColors;
|
||||
if (pMask[0] == bits555[0]) {
|
||||
if (pMask[1] == bits555[1]) {
|
||||
if (pMask[2] == bits555[2]) {
|
||||
return MEDIASUBTYPE_RGB555;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compare the bit fields with RGB 565
|
||||
|
||||
pMask = (DWORD *) pbmInfo->bmiColors;
|
||||
if (pMask[0] == bits565[0]) {
|
||||
if (pMask[1] == bits565[1]) {
|
||||
if (pMask[2] == bits565[2]) {
|
||||
return MEDIASUBTYPE_RGB565;
|
||||
}
|
||||
}
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
||||
|
||||
// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is
|
||||
// used to describe it in format negotiations. For example a video codec fills
|
||||
// in the format block with a VIDEOINFO structure, it also fills in the major
|
||||
// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit
|
||||
// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8
|
||||
|
||||
STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader)
|
||||
{
|
||||
ASSERT(pbmiHeader);
|
||||
|
||||
// If it's not RGB then create a GUID from the compression type
|
||||
|
||||
if (pbmiHeader->biCompression != BI_RGB) {
|
||||
if (pbmiHeader->biCompression != BI_BITFIELDS) {
|
||||
FOURCCMap FourCCMap(pbmiHeader->biCompression);
|
||||
return (const GUID) FourCCMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Map the RGB DIB bit depth to a image GUID
|
||||
|
||||
switch(pbmiHeader->biBitCount) {
|
||||
case 1 : return MEDIASUBTYPE_RGB1;
|
||||
case 4 : return MEDIASUBTYPE_RGB4;
|
||||
case 8 : return MEDIASUBTYPE_RGB8;
|
||||
case 16 : return GetTrueColorType(pbmiHeader);
|
||||
case 24 : return MEDIASUBTYPE_RGB24;
|
||||
case 32 : return MEDIASUBTYPE_RGB32;
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
||||
|
||||
// Given a video bitmap subtype we return the number of bits per pixel it uses
|
||||
// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the
|
||||
// GUID subtype is not found in the table we return an invalid USHRT_MAX
|
||||
|
||||
STDAPI_(WORD) GetBitCount(const GUID *pSubtype)
|
||||
{
|
||||
ASSERT(pSubtype);
|
||||
const GUID *pMediaSubtype;
|
||||
INT iPosition = 0;
|
||||
|
||||
// Scan the mapping list seeing if the source GUID matches any known
|
||||
// bitmap subtypes, the list is terminated by a GUID_NULL entry
|
||||
|
||||
while (TRUE) {
|
||||
pMediaSubtype = BitCountMap[iPosition].pSubtype;
|
||||
if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) {
|
||||
return USHRT_MAX;
|
||||
}
|
||||
if (IsEqualGUID(*pMediaSubtype,*pSubtype)) {
|
||||
return BitCountMap[iPosition].BitCount;
|
||||
}
|
||||
iPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Given a bitmap subtype we return a description name that can be used for
|
||||
// debug purposes. In a retail build this function still returns the names
|
||||
// If the subtype isn't found in the lookup table we return string UNKNOWN
|
||||
|
||||
int LocateSubtype(const GUID *pSubtype)
|
||||
{
|
||||
ASSERT(pSubtype);
|
||||
const GUID *pMediaSubtype;
|
||||
INT iPosition = 0;
|
||||
|
||||
// Scan the mapping list seeing if the source GUID matches any known
|
||||
// bitmap subtypes, the list is terminated by a GUID_NULL entry
|
||||
|
||||
while (TRUE) {
|
||||
pMediaSubtype = BitCountMap[iPosition].pSubtype;
|
||||
if (IsEqualGUID(*pMediaSubtype,*pSubtype) ||
|
||||
IsEqualGUID(*pMediaSubtype,GUID_NULL)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
iPosition++;
|
||||
}
|
||||
|
||||
return iPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype)
|
||||
{
|
||||
return BitCountMap[LocateSubtype(pSubtype)].wszName;
|
||||
}
|
||||
|
||||
STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype)
|
||||
{
|
||||
return BitCountMap[LocateSubtype(pSubtype)].pName;
|
||||
}
|
||||
|
||||
#ifndef GetSubtypeName
|
||||
#error wxutil.h should have defined GetSubtypeName
|
||||
#endif
|
||||
#undef GetSubtypeName
|
||||
|
||||
// this is here for people that linked to it directly; most people
|
||||
// would use the header file that picks the A or W version.
|
||||
STDAPI_(CHAR *) GetSubtypeName(const GUID *pSubtype)
|
||||
{
|
||||
return GetSubtypeNameA(pSubtype);
|
||||
}
|
||||
|
||||
|
||||
// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER
|
||||
// This is really messy to deal with because it invariably has fields that
|
||||
// follow it holding bit fields, palettes and the rest. This function gives
|
||||
// the number of bytes required to hold a VIDEOINFO that represents it. This
|
||||
// count includes the prefix information (like the rcSource rectangle) the
|
||||
// BITMAPINFOHEADER field, and any other colour information on the end.
|
||||
//
|
||||
// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make
|
||||
// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't
|
||||
// right at the start of the VIDEOINFO (there are a number of other fields),
|
||||
//
|
||||
// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER));
|
||||
//
|
||||
|
||||
STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader)
|
||||
{
|
||||
// Everyone has this to start with this
|
||||
LONG Size = SIZE_PREHEADER + pHeader->biSize;
|
||||
|
||||
ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER));
|
||||
|
||||
// Does this format use a palette, if the number of colours actually used
|
||||
// is zero then it is set to the maximum that are allowed for that colour
|
||||
// depth (an example is 256 for eight bits). Truecolour formats may also
|
||||
// pass a palette with them in which case the used count is non zero
|
||||
|
||||
// This would scare me.
|
||||
ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0);
|
||||
|
||||
if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) {
|
||||
LONG Entries = (DWORD) 1 << pHeader->biBitCount;
|
||||
if (pHeader->biClrUsed) {
|
||||
Entries = pHeader->biClrUsed;
|
||||
}
|
||||
Size += Entries * sizeof(RGBQUAD);
|
||||
}
|
||||
|
||||
// Truecolour formats may have a BI_BITFIELDS specifier for compression
|
||||
// type which means that room for three DWORDs should be allocated that
|
||||
// specify where in each pixel the RGB colour components may be found
|
||||
|
||||
if (pHeader->biCompression == BI_BITFIELDS) {
|
||||
Size += SIZE_MASKS;
|
||||
}
|
||||
|
||||
// A BITMAPINFO for a palettised image may also contain a palette map that
|
||||
// provides the information to map from a source palette to a destination
|
||||
// palette during a BitBlt for example, because this information is only
|
||||
// ever processed during drawing you don't normally store the palette map
|
||||
// nor have any way of knowing if it is present in the data structure
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
// Returns TRUE if the VIDEOINFO contains a palette
|
||||
|
||||
STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo)
|
||||
{
|
||||
if (PALETTISED(pVideoInfo) == FALSE) {
|
||||
if (pVideoInfo->bmiHeader.biClrUsed == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Return a pointer to the first entry in a palette
|
||||
|
||||
STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo)
|
||||
{
|
||||
if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) {
|
||||
return TRUECOLOR(pVideoInfo)->bmiColors;
|
||||
}
|
||||
return COLORS(pVideoInfo);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// File: AMVideo.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements helper functions for
|
||||
// bitmap formats.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
// These are bit field masks for true colour devices
|
||||
|
||||
const DWORD bits555[] = {0x007C00,0x0003E0,0x00001F};
|
||||
const DWORD bits565[] = {0x00F800,0x0007E0,0x00001F};
|
||||
const DWORD bits888[] = {0xFF0000,0x00FF00,0x0000FF};
|
||||
|
||||
// This maps bitmap subtypes into a bits per pixel value and also a
|
||||
// name. unicode and ansi versions are stored because we have to
|
||||
// return a pointer to a static string.
|
||||
const struct {
|
||||
const GUID *pSubtype;
|
||||
WORD BitCount;
|
||||
CHAR *pName;
|
||||
WCHAR *wszName;
|
||||
} BitCountMap[] = { &MEDIASUBTYPE_RGB1, 1, "RGB Monochrome", L"RGB Monochrome",
|
||||
&MEDIASUBTYPE_RGB4, 4, "RGB VGA", L"RGB VGA",
|
||||
&MEDIASUBTYPE_RGB8, 8, "RGB 8", L"RGB 8",
|
||||
&MEDIASUBTYPE_RGB565, 16, "RGB 565 (16 bit)", L"RGB 565 (16 bit)",
|
||||
&MEDIASUBTYPE_RGB555, 16, "RGB 555 (16 bit)", L"RGB 555 (16 bit)",
|
||||
&MEDIASUBTYPE_RGB24, 24, "RGB 24", L"RGB 24",
|
||||
&MEDIASUBTYPE_RGB32, 32, "RGB 32", L"RGB 32",
|
||||
&MEDIASUBTYPE_ARGB32, 32, "ARGB 32", L"ARGB 32",
|
||||
&MEDIASUBTYPE_Overlay, 0, "Overlay", L"Overlay",
|
||||
&GUID_NULL, 0, "UNKNOWN", L"UNKNOWN"
|
||||
};
|
||||
|
||||
// Return the size of the bitmap as defined by this header
|
||||
|
||||
STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader)
|
||||
{
|
||||
return DIBSIZE(*pHeader);
|
||||
}
|
||||
|
||||
|
||||
// This is called if the header has a 16 bit colour depth and needs to work
|
||||
// out the detailed type from the bit fields (either RGB 565 or RGB 555)
|
||||
|
||||
STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader)
|
||||
{
|
||||
BITMAPINFO *pbmInfo = (BITMAPINFO *) pbmiHeader;
|
||||
ASSERT(pbmiHeader->biBitCount == 16);
|
||||
|
||||
// If its BI_RGB then it's RGB 555 by default
|
||||
|
||||
if (pbmiHeader->biCompression == BI_RGB) {
|
||||
return MEDIASUBTYPE_RGB555;
|
||||
}
|
||||
|
||||
// Compare the bit fields with RGB 555
|
||||
|
||||
DWORD *pMask = (DWORD *) pbmInfo->bmiColors;
|
||||
if (pMask[0] == bits555[0]) {
|
||||
if (pMask[1] == bits555[1]) {
|
||||
if (pMask[2] == bits555[2]) {
|
||||
return MEDIASUBTYPE_RGB555;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compare the bit fields with RGB 565
|
||||
|
||||
pMask = (DWORD *) pbmInfo->bmiColors;
|
||||
if (pMask[0] == bits565[0]) {
|
||||
if (pMask[1] == bits565[1]) {
|
||||
if (pMask[2] == bits565[2]) {
|
||||
return MEDIASUBTYPE_RGB565;
|
||||
}
|
||||
}
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
||||
|
||||
// Given a BITMAPINFOHEADER structure this returns the GUID sub type that is
|
||||
// used to describe it in format negotiations. For example a video codec fills
|
||||
// in the format block with a VIDEOINFO structure, it also fills in the major
|
||||
// type with MEDIATYPE_VIDEO and the subtype with a GUID that matches the bit
|
||||
// count, for example if it is an eight bit image then MEDIASUBTYPE_RGB8
|
||||
|
||||
STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader)
|
||||
{
|
||||
ASSERT(pbmiHeader);
|
||||
|
||||
// If it's not RGB then create a GUID from the compression type
|
||||
|
||||
if (pbmiHeader->biCompression != BI_RGB) {
|
||||
if (pbmiHeader->biCompression != BI_BITFIELDS) {
|
||||
FOURCCMap FourCCMap(pbmiHeader->biCompression);
|
||||
return (const GUID) FourCCMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Map the RGB DIB bit depth to a image GUID
|
||||
|
||||
switch(pbmiHeader->biBitCount) {
|
||||
case 1 : return MEDIASUBTYPE_RGB1;
|
||||
case 4 : return MEDIASUBTYPE_RGB4;
|
||||
case 8 : return MEDIASUBTYPE_RGB8;
|
||||
case 16 : return GetTrueColorType(pbmiHeader);
|
||||
case 24 : return MEDIASUBTYPE_RGB24;
|
||||
case 32 : return MEDIASUBTYPE_RGB32;
|
||||
}
|
||||
return GUID_NULL;
|
||||
}
|
||||
|
||||
|
||||
// Given a video bitmap subtype we return the number of bits per pixel it uses
|
||||
// We return a WORD bit count as thats what the BITMAPINFOHEADER uses. If the
|
||||
// GUID subtype is not found in the table we return an invalid USHRT_MAX
|
||||
|
||||
STDAPI_(WORD) GetBitCount(const GUID *pSubtype)
|
||||
{
|
||||
ASSERT(pSubtype);
|
||||
const GUID *pMediaSubtype;
|
||||
INT iPosition = 0;
|
||||
|
||||
// Scan the mapping list seeing if the source GUID matches any known
|
||||
// bitmap subtypes, the list is terminated by a GUID_NULL entry
|
||||
|
||||
while (TRUE) {
|
||||
pMediaSubtype = BitCountMap[iPosition].pSubtype;
|
||||
if (IsEqualGUID(*pMediaSubtype,GUID_NULL)) {
|
||||
return USHRT_MAX;
|
||||
}
|
||||
if (IsEqualGUID(*pMediaSubtype,*pSubtype)) {
|
||||
return BitCountMap[iPosition].BitCount;
|
||||
}
|
||||
iPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Given a bitmap subtype we return a description name that can be used for
|
||||
// debug purposes. In a retail build this function still returns the names
|
||||
// If the subtype isn't found in the lookup table we return string UNKNOWN
|
||||
|
||||
int LocateSubtype(const GUID *pSubtype)
|
||||
{
|
||||
ASSERT(pSubtype);
|
||||
const GUID *pMediaSubtype;
|
||||
INT iPosition = 0;
|
||||
|
||||
// Scan the mapping list seeing if the source GUID matches any known
|
||||
// bitmap subtypes, the list is terminated by a GUID_NULL entry
|
||||
|
||||
while (TRUE) {
|
||||
pMediaSubtype = BitCountMap[iPosition].pSubtype;
|
||||
if (IsEqualGUID(*pMediaSubtype,*pSubtype) ||
|
||||
IsEqualGUID(*pMediaSubtype,GUID_NULL)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
iPosition++;
|
||||
}
|
||||
|
||||
return iPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype)
|
||||
{
|
||||
return BitCountMap[LocateSubtype(pSubtype)].wszName;
|
||||
}
|
||||
|
||||
STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype)
|
||||
{
|
||||
return BitCountMap[LocateSubtype(pSubtype)].pName;
|
||||
}
|
||||
|
||||
#ifndef GetSubtypeName
|
||||
#error wxutil.h should have defined GetSubtypeName
|
||||
#endif
|
||||
#undef GetSubtypeName
|
||||
|
||||
// this is here for people that linked to it directly; most people
|
||||
// would use the header file that picks the A or W version.
|
||||
STDAPI_(CHAR *) GetSubtypeName(const GUID *pSubtype)
|
||||
{
|
||||
return GetSubtypeNameA(pSubtype);
|
||||
}
|
||||
|
||||
|
||||
// The mechanism for describing a bitmap format is with the BITMAPINFOHEADER
|
||||
// This is really messy to deal with because it invariably has fields that
|
||||
// follow it holding bit fields, palettes and the rest. This function gives
|
||||
// the number of bytes required to hold a VIDEOINFO that represents it. This
|
||||
// count includes the prefix information (like the rcSource rectangle) the
|
||||
// BITMAPINFOHEADER field, and any other colour information on the end.
|
||||
//
|
||||
// WARNING If you want to copy a BITMAPINFOHEADER into a VIDEOINFO always make
|
||||
// sure that you use the HEADER macro because the BITMAPINFOHEADER field isn't
|
||||
// right at the start of the VIDEOINFO (there are a number of other fields),
|
||||
//
|
||||
// CopyMemory(HEADER(pVideoInfo),pbmi,sizeof(BITMAPINFOHEADER));
|
||||
//
|
||||
|
||||
STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader)
|
||||
{
|
||||
// Everyone has this to start with this
|
||||
LONG Size = SIZE_PREHEADER + pHeader->biSize;
|
||||
|
||||
ASSERT(pHeader->biSize >= sizeof(BITMAPINFOHEADER));
|
||||
|
||||
// Does this format use a palette, if the number of colours actually used
|
||||
// is zero then it is set to the maximum that are allowed for that colour
|
||||
// depth (an example is 256 for eight bits). Truecolour formats may also
|
||||
// pass a palette with them in which case the used count is non zero
|
||||
|
||||
// This would scare me.
|
||||
ASSERT(pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed == 0);
|
||||
|
||||
if (pHeader->biBitCount <= iPALETTE || pHeader->biClrUsed) {
|
||||
LONG Entries = (DWORD) 1 << pHeader->biBitCount;
|
||||
if (pHeader->biClrUsed) {
|
||||
Entries = pHeader->biClrUsed;
|
||||
}
|
||||
Size += Entries * sizeof(RGBQUAD);
|
||||
}
|
||||
|
||||
// Truecolour formats may have a BI_BITFIELDS specifier for compression
|
||||
// type which means that room for three DWORDs should be allocated that
|
||||
// specify where in each pixel the RGB colour components may be found
|
||||
|
||||
if (pHeader->biCompression == BI_BITFIELDS) {
|
||||
Size += SIZE_MASKS;
|
||||
}
|
||||
|
||||
// A BITMAPINFO for a palettised image may also contain a palette map that
|
||||
// provides the information to map from a source palette to a destination
|
||||
// palette during a BitBlt for example, because this information is only
|
||||
// ever processed during drawing you don't normally store the palette map
|
||||
// nor have any way of knowing if it is present in the data structure
|
||||
|
||||
return Size;
|
||||
}
|
||||
|
||||
|
||||
// Returns TRUE if the VIDEOINFO contains a palette
|
||||
|
||||
STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo)
|
||||
{
|
||||
if (PALETTISED(pVideoInfo) == FALSE) {
|
||||
if (pVideoInfo->bmiHeader.biClrUsed == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Return a pointer to the first entry in a palette
|
||||
|
||||
STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo)
|
||||
{
|
||||
if (pVideoInfo->bmiHeader.biCompression == BI_BITFIELDS) {
|
||||
return TRUECOLOR(pVideoInfo)->bmiColors;
|
||||
}
|
||||
return COLORS(pVideoInfo);
|
||||
}
|
||||
|
||||
+74
-74
@@ -1,74 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Cache.h
|
||||
//
|
||||
// Desc: DirectShow base classes - efines a non-MFC generic cache class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/* This class implements a simple cache. A cache object is instantiated
|
||||
with the number of items it is to hold. An item is a pointer to an
|
||||
object derived from CBaseObject (helps reduce memory leaks). The cache
|
||||
can then have objects added to it and removed from it. The cache size
|
||||
is fixed at construction time and may therefore run out or be flooded.
|
||||
If it runs out it returns a NULL pointer, if it fills up it also returns
|
||||
a NULL pointer instead of a pointer to the object just inserted */
|
||||
|
||||
/* Making these classes inherit from CBaseObject does nothing for their
|
||||
functionality but it allows us to check there are no memory leaks */
|
||||
|
||||
/* WARNING Be very careful when using this class, what it lets you do is
|
||||
store and retrieve objects so that you can minimise object creation
|
||||
which in turns improves efficiency. However the object you store is
|
||||
exactly the same as the object you get back which means that it short
|
||||
circuits the constructor initialisation phase. This means any class
|
||||
variables the object has (eg pointers) are highly likely to be invalid.
|
||||
Therefore ensure you reinitialise the object before using it again */
|
||||
|
||||
|
||||
#ifndef __CACHE__
|
||||
#define __CACHE__
|
||||
|
||||
|
||||
class CCache : CBaseObject {
|
||||
|
||||
/* Make copy constructor and assignment operator inaccessible */
|
||||
|
||||
CCache(const CCache &refCache);
|
||||
CCache &operator=(const CCache &refCache);
|
||||
|
||||
private:
|
||||
|
||||
/* These are initialised in the constructor. The first variable points to
|
||||
an array of pointers, each of which points to a CBaseObject derived
|
||||
object. The m_iCacheSize is the static fixed size for the cache and the
|
||||
m_iUsed defines the number of places filled with objects at any time.
|
||||
We fill the array of pointers from the start (ie m_ppObjects[0] first)
|
||||
and then only add and remove objects from the end position, so in this
|
||||
respect the array of object pointers should be treated as a stack */
|
||||
|
||||
CBaseObject **m_ppObjects;
|
||||
const INT m_iCacheSize;
|
||||
INT m_iUsed;
|
||||
|
||||
public:
|
||||
|
||||
CCache(TCHAR *pName,INT iItems);
|
||||
virtual ~CCache();
|
||||
|
||||
/* Add an item to the cache */
|
||||
CBaseObject *AddToCache(CBaseObject *pObject);
|
||||
|
||||
/* Remove an item from the cache */
|
||||
CBaseObject *RemoveFromCache();
|
||||
|
||||
/* Delete all the objects held in the cache */
|
||||
void RemoveAll(void);
|
||||
|
||||
/* Return the cache size which is set during construction */
|
||||
INT GetCacheSize(void) const {return m_iCacheSize;};
|
||||
};
|
||||
|
||||
#endif /* __CACHE__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Cache.h
|
||||
//
|
||||
// Desc: DirectShow base classes - efines a non-MFC generic cache class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/* This class implements a simple cache. A cache object is instantiated
|
||||
with the number of items it is to hold. An item is a pointer to an
|
||||
object derived from CBaseObject (helps reduce memory leaks). The cache
|
||||
can then have objects added to it and removed from it. The cache size
|
||||
is fixed at construction time and may therefore run out or be flooded.
|
||||
If it runs out it returns a NULL pointer, if it fills up it also returns
|
||||
a NULL pointer instead of a pointer to the object just inserted */
|
||||
|
||||
/* Making these classes inherit from CBaseObject does nothing for their
|
||||
functionality but it allows us to check there are no memory leaks */
|
||||
|
||||
/* WARNING Be very careful when using this class, what it lets you do is
|
||||
store and retrieve objects so that you can minimise object creation
|
||||
which in turns improves efficiency. However the object you store is
|
||||
exactly the same as the object you get back which means that it short
|
||||
circuits the constructor initialisation phase. This means any class
|
||||
variables the object has (eg pointers) are highly likely to be invalid.
|
||||
Therefore ensure you reinitialise the object before using it again */
|
||||
|
||||
|
||||
#ifndef __CACHE__
|
||||
#define __CACHE__
|
||||
|
||||
|
||||
class CCache : CBaseObject {
|
||||
|
||||
/* Make copy constructor and assignment operator inaccessible */
|
||||
|
||||
CCache(const CCache &refCache);
|
||||
CCache &operator=(const CCache &refCache);
|
||||
|
||||
private:
|
||||
|
||||
/* These are initialised in the constructor. The first variable points to
|
||||
an array of pointers, each of which points to a CBaseObject derived
|
||||
object. The m_iCacheSize is the static fixed size for the cache and the
|
||||
m_iUsed defines the number of places filled with objects at any time.
|
||||
We fill the array of pointers from the start (ie m_ppObjects[0] first)
|
||||
and then only add and remove objects from the end position, so in this
|
||||
respect the array of object pointers should be treated as a stack */
|
||||
|
||||
CBaseObject **m_ppObjects;
|
||||
const INT m_iCacheSize;
|
||||
INT m_iUsed;
|
||||
|
||||
public:
|
||||
|
||||
CCache(TCHAR *pName,INT iItems);
|
||||
virtual ~CCache();
|
||||
|
||||
/* Add an item to the cache */
|
||||
CBaseObject *AddToCache(CBaseObject *pObject);
|
||||
|
||||
/* Remove an item from the cache */
|
||||
CBaseObject *RemoveFromCache();
|
||||
|
||||
/* Delete all the objects held in the cache */
|
||||
void RemoveAll(void);
|
||||
|
||||
/* Return the cache size which is set during construction */
|
||||
INT GetCacheSize(void) const {return m_iCacheSize;};
|
||||
};
|
||||
|
||||
#endif /* __CACHE__ */
|
||||
|
||||
|
||||
+254
-254
@@ -1,254 +1,254 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: ComBase.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements class hierarchy for creating
|
||||
// COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions
|
||||
|
||||
|
||||
/* Define the static member variable */
|
||||
|
||||
LONG CBaseObject::m_cObjects = 0;
|
||||
|
||||
|
||||
/* Constructor */
|
||||
|
||||
CBaseObject::CBaseObject(const TCHAR *pName)
|
||||
{
|
||||
/* Increment the number of active objects */
|
||||
InterlockedIncrement(&m_cObjects);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifdef UNICODE
|
||||
m_dwCookie = DbgRegisterObjectCreation(0, pName);
|
||||
#else
|
||||
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CBaseObject::CBaseObject(const char *pName)
|
||||
{
|
||||
/* Increment the number of active objects */
|
||||
InterlockedIncrement(&m_cObjects);
|
||||
|
||||
#ifdef DEBUG
|
||||
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
HINSTANCE hlibOLEAut32;
|
||||
|
||||
/* Destructor */
|
||||
|
||||
CBaseObject::~CBaseObject()
|
||||
{
|
||||
/* Decrement the number of objects active */
|
||||
if (InterlockedDecrement(&m_cObjects) == 0) {
|
||||
if (hlibOLEAut32) {
|
||||
FreeLibrary(hlibOLEAut32);
|
||||
hlibOLEAut32 = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
DbgRegisterObjectDestruction(m_dwCookie);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll");
|
||||
|
||||
HINSTANCE LoadOLEAut32()
|
||||
{
|
||||
if (hlibOLEAut32 == 0) {
|
||||
hlibOLEAut32 = LoadLibrary(szOle32Aut);
|
||||
}
|
||||
|
||||
return hlibOLEAut32;
|
||||
}
|
||||
|
||||
|
||||
/* Constructor */
|
||||
|
||||
// We know we use "this" in the initialization list, we also know we don't modify *phr.
|
||||
#pragma warning( disable : 4355 4100 )
|
||||
CUnknown::CUnknown(const TCHAR *pName, LPUNKNOWN pUnk)
|
||||
: CBaseObject(pName)
|
||||
/* Start the object with a reference count of zero - when the */
|
||||
/* object is queried for it's first interface this may be */
|
||||
/* incremented depending on whether or not this object is */
|
||||
/* currently being aggregated upon */
|
||||
, m_cRef(0)
|
||||
/* Set our pointer to our IUnknown interface. */
|
||||
/* If we have an outer, use its, otherwise use ours. */
|
||||
/* This pointer effectivly points to the owner of */
|
||||
/* this object and can be accessed by the GetOwner() method. */
|
||||
, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
/* Why the double cast? Well, the inner cast is a type-safe cast */
|
||||
/* to pointer to a type from which we inherit. The second is */
|
||||
/* type-unsafe but works because INonDelegatingUnknown "behaves */
|
||||
/* like" IUnknown. (Only the names on the methods change.) */
|
||||
{
|
||||
// Everything we need to do has been done in the initializer list
|
||||
}
|
||||
|
||||
// This does the same as above except it has a useless HRESULT argument
|
||||
// use the previous constructor, this is just left for compatibility...
|
||||
CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseObject(pName),
|
||||
m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CUnknown::CUnknown(const CHAR *pName, LPUNKNOWN pUnk)
|
||||
: CBaseObject(pName), m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{ }
|
||||
|
||||
CUnknown::CUnknown(CHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseObject(pName), m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{ }
|
||||
|
||||
#endif
|
||||
|
||||
#pragma warning( default : 4355 4100 )
|
||||
|
||||
|
||||
/* QueryInterface */
|
||||
|
||||
STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
CheckPointer(ppv,E_POINTER);
|
||||
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
||||
|
||||
/* We know only about IUnknown */
|
||||
|
||||
if (riid == IID_IUnknown) {
|
||||
GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv);
|
||||
return NOERROR;
|
||||
} else {
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have to ensure that we DON'T use a max macro, since these will typically */
|
||||
/* lead to one of the parameters being evaluated twice. Since we are worried */
|
||||
/* about concurrency, we can't afford to access the m_cRef twice since we can't */
|
||||
/* afford to run the risk that its value having changed between accesses. */
|
||||
|
||||
template<class T> inline static T ourmax( const T & a, const T & b )
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/* AddRef */
|
||||
|
||||
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement( &m_cRef );
|
||||
ASSERT(lRef > 0);
|
||||
DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"),
|
||||
m_dwCookie, m_cRef));
|
||||
return ourmax(ULONG(m_cRef), 1ul);
|
||||
}
|
||||
|
||||
|
||||
/* Release */
|
||||
|
||||
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease()
|
||||
{
|
||||
/* If the reference count drops to zero delete ourselves */
|
||||
|
||||
LONG lRef = InterlockedDecrement( &m_cRef );
|
||||
ASSERT(lRef >= 0);
|
||||
|
||||
DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"),
|
||||
m_dwCookie, m_cRef));
|
||||
if (lRef == 0) {
|
||||
|
||||
// COM rules say we must protect against re-entrancy.
|
||||
// If we are an aggregator and we hold our own interfaces
|
||||
// on the aggregatee, the QI for these interfaces will
|
||||
// addref ourselves. So after doing the QI we must release
|
||||
// a ref count on ourselves. Then, before releasing the
|
||||
// private interface, we must addref ourselves. When we do
|
||||
// this from the destructor here it will result in the ref
|
||||
// count going to 1 and then back to 0 causing us to
|
||||
// re-enter the destructor. Hence we add an extra refcount here
|
||||
// once we know we will delete the object.
|
||||
// for an example aggregator see filgraph\distrib.cpp.
|
||||
|
||||
m_cRef++;
|
||||
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
} else {
|
||||
return ourmax(ULONG(m_cRef), 1ul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return an interface pointer to a requesting client
|
||||
performing a thread safe AddRef as necessary */
|
||||
|
||||
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv)
|
||||
{
|
||||
CheckPointer(ppv, E_POINTER);
|
||||
*ppv = pUnk;
|
||||
pUnk->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Compares two interfaces and returns TRUE if they are on the same object */
|
||||
|
||||
BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond)
|
||||
{
|
||||
/* Different objects can't have the same interface pointer for
|
||||
any interface
|
||||
*/
|
||||
if (pFirst == pSecond) {
|
||||
return TRUE;
|
||||
}
|
||||
/* OK - do it the hard way - check if they have the same
|
||||
IUnknown pointers - a single object can only have one of these
|
||||
*/
|
||||
LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface
|
||||
LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface
|
||||
HRESULT hr; // General OLE return code
|
||||
|
||||
ASSERT(pFirst);
|
||||
ASSERT(pSecond);
|
||||
|
||||
/* See if the IUnknown pointers match */
|
||||
|
||||
hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1);
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
ASSERT(pUnknown1);
|
||||
|
||||
hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2);
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
ASSERT(pUnknown2);
|
||||
|
||||
/* Release the extra interfaces we hold */
|
||||
|
||||
pUnknown1->Release();
|
||||
pUnknown2->Release();
|
||||
return (pUnknown1 == pUnknown2);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: ComBase.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements class hierarchy for creating
|
||||
// COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions
|
||||
|
||||
|
||||
/* Define the static member variable */
|
||||
|
||||
LONG CBaseObject::m_cObjects = 0;
|
||||
|
||||
|
||||
/* Constructor */
|
||||
|
||||
CBaseObject::CBaseObject(const TCHAR *pName)
|
||||
{
|
||||
/* Increment the number of active objects */
|
||||
InterlockedIncrement(&m_cObjects);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifdef UNICODE
|
||||
m_dwCookie = DbgRegisterObjectCreation(0, pName);
|
||||
#else
|
||||
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CBaseObject::CBaseObject(const char *pName)
|
||||
{
|
||||
/* Increment the number of active objects */
|
||||
InterlockedIncrement(&m_cObjects);
|
||||
|
||||
#ifdef DEBUG
|
||||
m_dwCookie = DbgRegisterObjectCreation(pName, 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
HINSTANCE hlibOLEAut32;
|
||||
|
||||
/* Destructor */
|
||||
|
||||
CBaseObject::~CBaseObject()
|
||||
{
|
||||
/* Decrement the number of objects active */
|
||||
if (InterlockedDecrement(&m_cObjects) == 0) {
|
||||
if (hlibOLEAut32) {
|
||||
FreeLibrary(hlibOLEAut32);
|
||||
hlibOLEAut32 = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
DbgRegisterObjectDestruction(m_dwCookie);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const TCHAR szOle32Aut[] = TEXT("OleAut32.dll");
|
||||
|
||||
HINSTANCE LoadOLEAut32()
|
||||
{
|
||||
if (hlibOLEAut32 == 0) {
|
||||
hlibOLEAut32 = LoadLibrary(szOle32Aut);
|
||||
}
|
||||
|
||||
return hlibOLEAut32;
|
||||
}
|
||||
|
||||
|
||||
/* Constructor */
|
||||
|
||||
// We know we use "this" in the initialization list, we also know we don't modify *phr.
|
||||
#pragma warning( disable : 4355 4100 )
|
||||
CUnknown::CUnknown(const TCHAR *pName, LPUNKNOWN pUnk)
|
||||
: CBaseObject(pName)
|
||||
/* Start the object with a reference count of zero - when the */
|
||||
/* object is queried for it's first interface this may be */
|
||||
/* incremented depending on whether or not this object is */
|
||||
/* currently being aggregated upon */
|
||||
, m_cRef(0)
|
||||
/* Set our pointer to our IUnknown interface. */
|
||||
/* If we have an outer, use its, otherwise use ours. */
|
||||
/* This pointer effectivly points to the owner of */
|
||||
/* this object and can be accessed by the GetOwner() method. */
|
||||
, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
/* Why the double cast? Well, the inner cast is a type-safe cast */
|
||||
/* to pointer to a type from which we inherit. The second is */
|
||||
/* type-unsafe but works because INonDelegatingUnknown "behaves */
|
||||
/* like" IUnknown. (Only the names on the methods change.) */
|
||||
{
|
||||
// Everything we need to do has been done in the initializer list
|
||||
}
|
||||
|
||||
// This does the same as above except it has a useless HRESULT argument
|
||||
// use the previous constructor, this is just left for compatibility...
|
||||
CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseObject(pName),
|
||||
m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CUnknown::CUnknown(const CHAR *pName, LPUNKNOWN pUnk)
|
||||
: CBaseObject(pName), m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{ }
|
||||
|
||||
CUnknown::CUnknown(CHAR *pName, LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseObject(pName), m_cRef(0),
|
||||
m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast<LPUNKNOWN>( static_cast<PNDUNKNOWN>(this) ) )
|
||||
{ }
|
||||
|
||||
#endif
|
||||
|
||||
#pragma warning( default : 4355 4100 )
|
||||
|
||||
|
||||
/* QueryInterface */
|
||||
|
||||
STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
CheckPointer(ppv,E_POINTER);
|
||||
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
||||
|
||||
/* We know only about IUnknown */
|
||||
|
||||
if (riid == IID_IUnknown) {
|
||||
GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv);
|
||||
return NOERROR;
|
||||
} else {
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have to ensure that we DON'T use a max macro, since these will typically */
|
||||
/* lead to one of the parameters being evaluated twice. Since we are worried */
|
||||
/* about concurrency, we can't afford to access the m_cRef twice since we can't */
|
||||
/* afford to run the risk that its value having changed between accesses. */
|
||||
|
||||
template<class T> inline static T ourmax( const T & a, const T & b )
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
/* AddRef */
|
||||
|
||||
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement( &m_cRef );
|
||||
ASSERT(lRef > 0);
|
||||
DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"),
|
||||
m_dwCookie, m_cRef));
|
||||
return ourmax(ULONG(m_cRef), 1ul);
|
||||
}
|
||||
|
||||
|
||||
/* Release */
|
||||
|
||||
STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease()
|
||||
{
|
||||
/* If the reference count drops to zero delete ourselves */
|
||||
|
||||
LONG lRef = InterlockedDecrement( &m_cRef );
|
||||
ASSERT(lRef >= 0);
|
||||
|
||||
DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"),
|
||||
m_dwCookie, m_cRef));
|
||||
if (lRef == 0) {
|
||||
|
||||
// COM rules say we must protect against re-entrancy.
|
||||
// If we are an aggregator and we hold our own interfaces
|
||||
// on the aggregatee, the QI for these interfaces will
|
||||
// addref ourselves. So after doing the QI we must release
|
||||
// a ref count on ourselves. Then, before releasing the
|
||||
// private interface, we must addref ourselves. When we do
|
||||
// this from the destructor here it will result in the ref
|
||||
// count going to 1 and then back to 0 causing us to
|
||||
// re-enter the destructor. Hence we add an extra refcount here
|
||||
// once we know we will delete the object.
|
||||
// for an example aggregator see filgraph\distrib.cpp.
|
||||
|
||||
m_cRef++;
|
||||
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
} else {
|
||||
return ourmax(ULONG(m_cRef), 1ul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Return an interface pointer to a requesting client
|
||||
performing a thread safe AddRef as necessary */
|
||||
|
||||
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv)
|
||||
{
|
||||
CheckPointer(ppv, E_POINTER);
|
||||
*ppv = pUnk;
|
||||
pUnk->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Compares two interfaces and returns TRUE if they are on the same object */
|
||||
|
||||
BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond)
|
||||
{
|
||||
/* Different objects can't have the same interface pointer for
|
||||
any interface
|
||||
*/
|
||||
if (pFirst == pSecond) {
|
||||
return TRUE;
|
||||
}
|
||||
/* OK - do it the hard way - check if they have the same
|
||||
IUnknown pointers - a single object can only have one of these
|
||||
*/
|
||||
LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface
|
||||
LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface
|
||||
HRESULT hr; // General OLE return code
|
||||
|
||||
ASSERT(pFirst);
|
||||
ASSERT(pSecond);
|
||||
|
||||
/* See if the IUnknown pointers match */
|
||||
|
||||
hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1);
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
ASSERT(pUnknown1);
|
||||
|
||||
hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2);
|
||||
ASSERT(SUCCEEDED(hr));
|
||||
ASSERT(pUnknown2);
|
||||
|
||||
/* Release the extra interfaces we hold */
|
||||
|
||||
pUnknown1->Release();
|
||||
pUnknown2->Release();
|
||||
return (pUnknown1 == pUnknown2);
|
||||
}
|
||||
|
||||
|
||||
+319
-319
@@ -1,319 +1,319 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: ComBase.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class hierarchy for creating
|
||||
// COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
|
||||
a. Derive your COM object from CUnknown
|
||||
|
||||
b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT *
|
||||
and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls
|
||||
to. The HRESULT * allows error codes to be passed around constructors and
|
||||
the TCHAR * is a descriptive name that can be printed on the debugger.
|
||||
|
||||
It is important that constructors only change the HRESULT * if they have
|
||||
to set an ERROR code, if it was successful then leave it alone or you may
|
||||
overwrite an error code from an object previously created.
|
||||
|
||||
When you call a constructor the descriptive name should be in static store
|
||||
as we do not copy the string. To stop large amounts of memory being used
|
||||
in retail builds by all these static strings use the NAME macro,
|
||||
|
||||
CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class
|
||||
knows not to do anything with objects that don't have a name.
|
||||
|
||||
c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and
|
||||
TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an
|
||||
error, or just simply pass it through to the constructor.
|
||||
|
||||
The object creation will fail in the class factory if the HRESULT indicates
|
||||
an error (ie FAILED(HRESULT) == TRUE)
|
||||
|
||||
d. Create a FactoryTemplate with your object's class id and CreateInstance
|
||||
function.
|
||||
|
||||
Then (for each interface) either
|
||||
|
||||
Multiple inheritance
|
||||
|
||||
1. Also derive it from ISomeInterface
|
||||
2. Include DECLARE_IUNKNOWN in your class definition to declare
|
||||
implementations of QueryInterface, AddRef and Release that
|
||||
call the outer unknown
|
||||
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
|
||||
code something like
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return GetInterface((ISomeInterface *) this, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
4. Declare and implement the member functions of ISomeInterface.
|
||||
|
||||
or: Nested interfaces
|
||||
|
||||
1. Declare a class derived from CUnknown
|
||||
2. Include DECLARE_IUNKNOWN in your class definition
|
||||
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
|
||||
code something like
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return GetInterface((ISomeInterface *) this, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
4. Implement the member functions of ISomeInterface. Use GetOwner() to
|
||||
access the COM object class.
|
||||
|
||||
And in your COM object class:
|
||||
|
||||
5. Make the nested class a friend of the COM object class, and declare
|
||||
an instance of the nested class as a member of the COM object class.
|
||||
|
||||
NOTE that because you must always pass the outer unknown and an hResult
|
||||
to the CUnknown constructor you cannot use a default constructor, in
|
||||
other words you will have to make the member variable a pointer to the
|
||||
class and make a NEW call in your constructor to actually create it.
|
||||
|
||||
6. override the NonDelegatingQueryInterface with code like this:
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return m_pImplFilter->
|
||||
NonDelegatingQueryInterface(IID_ISomeInterface, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
You can have mixed classes which support some interfaces via multiple
|
||||
inheritance and some via nested classes
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __COMBASE__
|
||||
#define __COMBASE__
|
||||
|
||||
// Filter Setup data structures no defined in axextend.idl
|
||||
|
||||
typedef REGPINTYPES
|
||||
AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE;
|
||||
|
||||
typedef REGFILTERPINS
|
||||
AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN;
|
||||
|
||||
typedef struct _AMOVIESETUP_FILTER
|
||||
{
|
||||
const CLSID * clsID;
|
||||
const WCHAR * strName;
|
||||
DWORD dwMerit;
|
||||
UINT nPins;
|
||||
const AMOVIESETUP_PIN * lpPin;
|
||||
}
|
||||
AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER;
|
||||
|
||||
/* The DLLENTRY module initialises the module handle on loading */
|
||||
|
||||
extern HINSTANCE g_hInst;
|
||||
|
||||
/* On DLL load remember which platform we are running on */
|
||||
|
||||
extern DWORD g_amPlatform;
|
||||
extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx
|
||||
|
||||
/* Version of IUnknown that is renamed to allow a class to support both
|
||||
non delegating and delegating IUnknowns in the same COM object */
|
||||
|
||||
#ifndef INONDELEGATINGUNKNOWN_DEFINED
|
||||
DECLARE_INTERFACE(INonDelegatingUnknown)
|
||||
{
|
||||
STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
|
||||
STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE;
|
||||
};
|
||||
#define INONDELEGATINGUNKNOWN_DEFINED
|
||||
#endif
|
||||
|
||||
typedef INonDelegatingUnknown *PNDUNKNOWN;
|
||||
|
||||
|
||||
/* This is the base object class that supports active object counting. As
|
||||
part of the debug facilities we trace every time a C++ object is created
|
||||
or destroyed. The name of the object has to be passed up through the class
|
||||
derivation list during construction as you cannot call virtual functions
|
||||
in the constructor. The downside of all this is that every single object
|
||||
constructor has to take an object name parameter that describes it */
|
||||
|
||||
class CBaseObject
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// Disable the copy constructor and assignment by default so you will get
|
||||
// compiler errors instead of unexpected behaviour if you pass objects
|
||||
// by value or assign objects.
|
||||
CBaseObject(const CBaseObject& objectSrc); // no implementation
|
||||
void operator=(const CBaseObject& objectSrc); // no implementation
|
||||
|
||||
private:
|
||||
static LONG m_cObjects; /* Total number of objects active */
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
DWORD m_dwCookie; /* Cookie identifying this object */
|
||||
#endif
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* These increment and decrement the number of active objects */
|
||||
|
||||
CBaseObject(const TCHAR *pName);
|
||||
#ifdef UNICODE
|
||||
CBaseObject(const char *pName);
|
||||
#endif
|
||||
~CBaseObject();
|
||||
|
||||
/* Call this to find if there are any CUnknown derived objects active */
|
||||
|
||||
static LONG ObjectsActive() {
|
||||
return m_cObjects;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* An object that supports one or more COM interfaces will be based on
|
||||
this class. It supports counting of total objects for DLLCanUnloadNow
|
||||
support, and an implementation of the core non delegating IUnknown */
|
||||
|
||||
class AM_NOVTABLE CUnknown : public INonDelegatingUnknown,
|
||||
public CBaseObject
|
||||
{
|
||||
private:
|
||||
const LPUNKNOWN m_pUnknown; /* Owner of this object */
|
||||
|
||||
protected: /* So we can override NonDelegatingRelease() */
|
||||
volatile LONG m_cRef; /* Number of reference counts */
|
||||
|
||||
public:
|
||||
|
||||
CUnknown(const TCHAR *pName, LPUNKNOWN pUnk);
|
||||
virtual ~CUnknown() {};
|
||||
|
||||
// This is redundant, just use the other constructor
|
||||
// as we never touch the HRESULT in this anyway
|
||||
CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr);
|
||||
#ifdef UNICODE
|
||||
CUnknown(const char *pName, LPUNKNOWN pUnk);
|
||||
CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr);
|
||||
#endif
|
||||
|
||||
/* Return the owner of this object */
|
||||
|
||||
LPUNKNOWN GetOwner() const {
|
||||
return m_pUnknown;
|
||||
};
|
||||
|
||||
/* Called from the class factory to create a new instance, it is
|
||||
pure virtual so it must be overriden in your derived class */
|
||||
|
||||
/* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */
|
||||
|
||||
/* Non delegating unknown implementation */
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
};
|
||||
|
||||
#if (_MSC_VER <= 1200)
|
||||
#pragma warning(disable:4211)
|
||||
|
||||
/* The standard InterlockedXXX functions won't take volatiles */
|
||||
static inline LONG WINAPI InterlockedIncrement( volatile LONG * plong )
|
||||
{ return InterlockedIncrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
static inline LONG WINAPI InterlockedDecrement( volatile LONG * plong )
|
||||
{ return InterlockedDecrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
#pragma warning(default:4211)
|
||||
#endif
|
||||
|
||||
|
||||
/* Return an interface pointer to a requesting client
|
||||
performing a thread safe AddRef as necessary */
|
||||
|
||||
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv);
|
||||
|
||||
/* A function that can create a new COM object */
|
||||
|
||||
typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
|
||||
|
||||
/* A function (can be NULL) which is called from the DLL entrypoint
|
||||
routine for each factory template:
|
||||
|
||||
bLoading - TRUE on DLL load, FALSE on DLL unload
|
||||
rclsid - the m_ClsID of the entry
|
||||
*/
|
||||
typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
|
||||
|
||||
/* Create one of these per object class in an array so that
|
||||
the default class factory code can create new instances */
|
||||
|
||||
class CFactoryTemplate {
|
||||
|
||||
public:
|
||||
|
||||
const WCHAR * m_Name;
|
||||
const CLSID * m_ClsID;
|
||||
LPFNNewCOMObject m_lpfnNew;
|
||||
LPFNInitRoutine m_lpfnInit;
|
||||
const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter;
|
||||
|
||||
BOOL IsClassID(REFCLSID rclsid) const {
|
||||
return (IsEqualCLSID(*m_ClsID,rclsid));
|
||||
};
|
||||
|
||||
CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const {
|
||||
CheckPointer(phr,NULL);
|
||||
return m_lpfnNew(pUnk, phr);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* You must override the (pure virtual) NonDelegatingQueryInterface to return
|
||||
interface pointers (using GetInterface) to the interfaces your derived
|
||||
class supports (the default implementation only supports IUnknown) */
|
||||
|
||||
#define DECLARE_IUNKNOWN \
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \
|
||||
return GetOwner()->QueryInterface(riid,ppv); \
|
||||
}; \
|
||||
STDMETHODIMP_(ULONG) AddRef() { \
|
||||
return GetOwner()->AddRef(); \
|
||||
}; \
|
||||
STDMETHODIMP_(ULONG) Release() { \
|
||||
return GetOwner()->Release(); \
|
||||
};
|
||||
|
||||
|
||||
|
||||
HINSTANCE LoadOLEAut32();
|
||||
|
||||
|
||||
#endif /* __COMBASE__ */
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: ComBase.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class hierarchy for creating
|
||||
// COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
|
||||
a. Derive your COM object from CUnknown
|
||||
|
||||
b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT *
|
||||
and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls
|
||||
to. The HRESULT * allows error codes to be passed around constructors and
|
||||
the TCHAR * is a descriptive name that can be printed on the debugger.
|
||||
|
||||
It is important that constructors only change the HRESULT * if they have
|
||||
to set an ERROR code, if it was successful then leave it alone or you may
|
||||
overwrite an error code from an object previously created.
|
||||
|
||||
When you call a constructor the descriptive name should be in static store
|
||||
as we do not copy the string. To stop large amounts of memory being used
|
||||
in retail builds by all these static strings use the NAME macro,
|
||||
|
||||
CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class
|
||||
knows not to do anything with objects that don't have a name.
|
||||
|
||||
c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and
|
||||
TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an
|
||||
error, or just simply pass it through to the constructor.
|
||||
|
||||
The object creation will fail in the class factory if the HRESULT indicates
|
||||
an error (ie FAILED(HRESULT) == TRUE)
|
||||
|
||||
d. Create a FactoryTemplate with your object's class id and CreateInstance
|
||||
function.
|
||||
|
||||
Then (for each interface) either
|
||||
|
||||
Multiple inheritance
|
||||
|
||||
1. Also derive it from ISomeInterface
|
||||
2. Include DECLARE_IUNKNOWN in your class definition to declare
|
||||
implementations of QueryInterface, AddRef and Release that
|
||||
call the outer unknown
|
||||
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
|
||||
code something like
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return GetInterface((ISomeInterface *) this, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
4. Declare and implement the member functions of ISomeInterface.
|
||||
|
||||
or: Nested interfaces
|
||||
|
||||
1. Declare a class derived from CUnknown
|
||||
2. Include DECLARE_IUNKNOWN in your class definition
|
||||
3. Override NonDelegatingQueryInterface to expose ISomeInterface by
|
||||
code something like
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return GetInterface((ISomeInterface *) this, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
4. Implement the member functions of ISomeInterface. Use GetOwner() to
|
||||
access the COM object class.
|
||||
|
||||
And in your COM object class:
|
||||
|
||||
5. Make the nested class a friend of the COM object class, and declare
|
||||
an instance of the nested class as a member of the COM object class.
|
||||
|
||||
NOTE that because you must always pass the outer unknown and an hResult
|
||||
to the CUnknown constructor you cannot use a default constructor, in
|
||||
other words you will have to make the member variable a pointer to the
|
||||
class and make a NEW call in your constructor to actually create it.
|
||||
|
||||
6. override the NonDelegatingQueryInterface with code like this:
|
||||
|
||||
if (riid == IID_ISomeInterface) {
|
||||
return m_pImplFilter->
|
||||
NonDelegatingQueryInterface(IID_ISomeInterface, ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
|
||||
You can have mixed classes which support some interfaces via multiple
|
||||
inheritance and some via nested classes
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __COMBASE__
|
||||
#define __COMBASE__
|
||||
|
||||
// Filter Setup data structures no defined in axextend.idl
|
||||
|
||||
typedef REGPINTYPES
|
||||
AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE;
|
||||
|
||||
typedef REGFILTERPINS
|
||||
AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN;
|
||||
|
||||
typedef struct _AMOVIESETUP_FILTER
|
||||
{
|
||||
const CLSID * clsID;
|
||||
const WCHAR * strName;
|
||||
DWORD dwMerit;
|
||||
UINT nPins;
|
||||
const AMOVIESETUP_PIN * lpPin;
|
||||
}
|
||||
AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER;
|
||||
|
||||
/* The DLLENTRY module initialises the module handle on loading */
|
||||
|
||||
extern HINSTANCE g_hInst;
|
||||
|
||||
/* On DLL load remember which platform we are running on */
|
||||
|
||||
extern DWORD g_amPlatform;
|
||||
extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx
|
||||
|
||||
/* Version of IUnknown that is renamed to allow a class to support both
|
||||
non delegating and delegating IUnknowns in the same COM object */
|
||||
|
||||
#ifndef INONDELEGATINGUNKNOWN_DEFINED
|
||||
DECLARE_INTERFACE(INonDelegatingUnknown)
|
||||
{
|
||||
STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE;
|
||||
STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE;
|
||||
};
|
||||
#define INONDELEGATINGUNKNOWN_DEFINED
|
||||
#endif
|
||||
|
||||
typedef INonDelegatingUnknown *PNDUNKNOWN;
|
||||
|
||||
|
||||
/* This is the base object class that supports active object counting. As
|
||||
part of the debug facilities we trace every time a C++ object is created
|
||||
or destroyed. The name of the object has to be passed up through the class
|
||||
derivation list during construction as you cannot call virtual functions
|
||||
in the constructor. The downside of all this is that every single object
|
||||
constructor has to take an object name parameter that describes it */
|
||||
|
||||
class CBaseObject
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// Disable the copy constructor and assignment by default so you will get
|
||||
// compiler errors instead of unexpected behaviour if you pass objects
|
||||
// by value or assign objects.
|
||||
CBaseObject(const CBaseObject& objectSrc); // no implementation
|
||||
void operator=(const CBaseObject& objectSrc); // no implementation
|
||||
|
||||
private:
|
||||
static LONG m_cObjects; /* Total number of objects active */
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
DWORD m_dwCookie; /* Cookie identifying this object */
|
||||
#endif
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/* These increment and decrement the number of active objects */
|
||||
|
||||
CBaseObject(const TCHAR *pName);
|
||||
#ifdef UNICODE
|
||||
CBaseObject(const char *pName);
|
||||
#endif
|
||||
~CBaseObject();
|
||||
|
||||
/* Call this to find if there are any CUnknown derived objects active */
|
||||
|
||||
static LONG ObjectsActive() {
|
||||
return m_cObjects;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* An object that supports one or more COM interfaces will be based on
|
||||
this class. It supports counting of total objects for DLLCanUnloadNow
|
||||
support, and an implementation of the core non delegating IUnknown */
|
||||
|
||||
class AM_NOVTABLE CUnknown : public INonDelegatingUnknown,
|
||||
public CBaseObject
|
||||
{
|
||||
private:
|
||||
const LPUNKNOWN m_pUnknown; /* Owner of this object */
|
||||
|
||||
protected: /* So we can override NonDelegatingRelease() */
|
||||
volatile LONG m_cRef; /* Number of reference counts */
|
||||
|
||||
public:
|
||||
|
||||
CUnknown(const TCHAR *pName, LPUNKNOWN pUnk);
|
||||
virtual ~CUnknown() {};
|
||||
|
||||
// This is redundant, just use the other constructor
|
||||
// as we never touch the HRESULT in this anyway
|
||||
CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr);
|
||||
#ifdef UNICODE
|
||||
CUnknown(const char *pName, LPUNKNOWN pUnk);
|
||||
CUnknown(char *pName, LPUNKNOWN pUnk,HRESULT *phr);
|
||||
#endif
|
||||
|
||||
/* Return the owner of this object */
|
||||
|
||||
LPUNKNOWN GetOwner() const {
|
||||
return m_pUnknown;
|
||||
};
|
||||
|
||||
/* Called from the class factory to create a new instance, it is
|
||||
pure virtual so it must be overriden in your derived class */
|
||||
|
||||
/* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */
|
||||
|
||||
/* Non delegating unknown implementation */
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
};
|
||||
|
||||
#if (_MSC_VER <= 1200)
|
||||
#pragma warning(disable:4211)
|
||||
|
||||
/* The standard InterlockedXXX functions won't take volatiles */
|
||||
static inline LONG WINAPI InterlockedIncrement( volatile LONG * plong )
|
||||
{ return InterlockedIncrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
static inline LONG WINAPI InterlockedDecrement( volatile LONG * plong )
|
||||
{ return InterlockedDecrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
#pragma warning(default:4211)
|
||||
#endif
|
||||
|
||||
|
||||
/* Return an interface pointer to a requesting client
|
||||
performing a thread safe AddRef as necessary */
|
||||
|
||||
STDAPI GetInterface(LPUNKNOWN pUnk, void **ppv);
|
||||
|
||||
/* A function that can create a new COM object */
|
||||
|
||||
typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
|
||||
|
||||
/* A function (can be NULL) which is called from the DLL entrypoint
|
||||
routine for each factory template:
|
||||
|
||||
bLoading - TRUE on DLL load, FALSE on DLL unload
|
||||
rclsid - the m_ClsID of the entry
|
||||
*/
|
||||
typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);
|
||||
|
||||
/* Create one of these per object class in an array so that
|
||||
the default class factory code can create new instances */
|
||||
|
||||
class CFactoryTemplate {
|
||||
|
||||
public:
|
||||
|
||||
const WCHAR * m_Name;
|
||||
const CLSID * m_ClsID;
|
||||
LPFNNewCOMObject m_lpfnNew;
|
||||
LPFNInitRoutine m_lpfnInit;
|
||||
const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter;
|
||||
|
||||
BOOL IsClassID(REFCLSID rclsid) const {
|
||||
return (IsEqualCLSID(*m_ClsID,rclsid));
|
||||
};
|
||||
|
||||
CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const {
|
||||
CheckPointer(phr,NULL);
|
||||
return m_lpfnNew(pUnk, phr);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* You must override the (pure virtual) NonDelegatingQueryInterface to return
|
||||
interface pointers (using GetInterface) to the interfaces your derived
|
||||
class supports (the default implementation only supports IUnknown) */
|
||||
|
||||
#define DECLARE_IUNKNOWN \
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \
|
||||
return GetOwner()->QueryInterface(riid,ppv); \
|
||||
}; \
|
||||
STDMETHODIMP_(ULONG) AddRef() { \
|
||||
return GetOwner()->AddRef(); \
|
||||
}; \
|
||||
STDMETHODIMP_(ULONG) Release() { \
|
||||
return GetOwner()->Release(); \
|
||||
};
|
||||
|
||||
|
||||
|
||||
HINSTANCE LoadOLEAut32();
|
||||
|
||||
|
||||
#endif /* __COMBASE__ */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+380
-380
@@ -1,380 +1,380 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: CProp.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements CBasePropertyPage class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
// Constructor for the base property page class. As described in the header
|
||||
// file we must be initialised with dialog and title resource identifiers.
|
||||
// The class supports IPropertyPage and overrides AddRef and Release calls
|
||||
// to keep track of the reference counts. When the last count is released
|
||||
// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces
|
||||
// previously obtained by the property page when it had SetObjects called
|
||||
|
||||
CBasePropertyPage::CBasePropertyPage(TCHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId) : // To get tital
|
||||
CUnknown(pName,pUnk),
|
||||
m_DialogId(DialogId),
|
||||
m_TitleId(TitleId),
|
||||
m_hwnd(NULL),
|
||||
m_Dlg(NULL),
|
||||
m_pPageSite(NULL),
|
||||
m_bObjectSet(FALSE),
|
||||
m_bDirty(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CBasePropertyPage::CBasePropertyPage(CHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId) : // To get tital
|
||||
CUnknown(pName,pUnk),
|
||||
m_DialogId(DialogId),
|
||||
m_TitleId(TitleId),
|
||||
m_hwnd(NULL),
|
||||
m_Dlg(NULL),
|
||||
m_pPageSite(NULL),
|
||||
m_bObjectSet(FALSE),
|
||||
m_bDirty(FALSE)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// Increment our reference count
|
||||
|
||||
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement(&m_cRef);
|
||||
ASSERT(lRef > 0);
|
||||
return max(ULONG(m_cRef),1ul);
|
||||
}
|
||||
|
||||
|
||||
// Release a reference count and protect against reentrancy
|
||||
|
||||
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease()
|
||||
{
|
||||
// If the reference count drops to zero delete ourselves
|
||||
|
||||
if (InterlockedDecrement(&m_cRef) == 0) {
|
||||
m_cRef++;
|
||||
SetPageSite(NULL);
|
||||
SetObjects(0,NULL);
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
} else {
|
||||
return max(ULONG(m_cRef),1ul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Expose our IPropertyPage interface
|
||||
|
||||
STDMETHODIMP
|
||||
CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,void **ppv)
|
||||
{
|
||||
if (riid == IID_IPropertyPage) {
|
||||
return GetInterface((IPropertyPage *)this,ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid,ppv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the page info so that the page site can size itself
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::GetPageInfo(LPPROPPAGEINFO pPageInfo)
|
||||
{
|
||||
CheckPointer(pPageInfo,E_POINTER);
|
||||
WCHAR wszTitle[STR_MAX_LENGTH];
|
||||
WideStringFromResource(wszTitle,m_TitleId);
|
||||
|
||||
// Allocate dynamic memory for the property page title
|
||||
|
||||
LPOLESTR pszTitle;
|
||||
HRESULT hr = AMGetWideString(wszTitle, &pszTitle);
|
||||
if (FAILED(hr)) {
|
||||
NOTE("No caption memory");
|
||||
return hr;
|
||||
}
|
||||
|
||||
pPageInfo->cb = sizeof(PROPPAGEINFO);
|
||||
pPageInfo->pszTitle = pszTitle;
|
||||
pPageInfo->pszDocString = NULL;
|
||||
pPageInfo->pszHelpFile = NULL;
|
||||
pPageInfo->dwHelpContext = 0;
|
||||
|
||||
// Set defaults in case GetDialogSize fails
|
||||
pPageInfo->size.cx = 340;
|
||||
pPageInfo->size.cy = 150;
|
||||
|
||||
GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Handles the messages for our property window
|
||||
|
||||
INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
CBasePropertyPage *pPropertyPage;
|
||||
|
||||
switch (uMsg) {
|
||||
|
||||
case WM_INITDIALOG:
|
||||
|
||||
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
|
||||
|
||||
// This pointer may be NULL when calculating size
|
||||
|
||||
pPropertyPage = (CBasePropertyPage *) lParam;
|
||||
if (pPropertyPage == NULL) {
|
||||
return (LRESULT) 1;
|
||||
}
|
||||
pPropertyPage->m_Dlg = hwnd;
|
||||
}
|
||||
|
||||
// This pointer may be NULL when calculating size
|
||||
|
||||
pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
|
||||
if (pPropertyPage == NULL) {
|
||||
return (LRESULT) 1;
|
||||
}
|
||||
return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
|
||||
// Tells us the object that should be informed of the property changes
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,LPUNKNOWN *ppUnk)
|
||||
{
|
||||
if (cObjects == 1) {
|
||||
|
||||
if ((ppUnk == NULL) || (*ppUnk == NULL)) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// Set a flag to say that we have set the Object
|
||||
m_bObjectSet = TRUE ;
|
||||
return OnConnect(*ppUnk);
|
||||
|
||||
} else if (cObjects == 0) {
|
||||
|
||||
// Set a flag to say that we have not set the Object for the page
|
||||
m_bObjectSet = FALSE ;
|
||||
return OnDisconnect();
|
||||
}
|
||||
|
||||
DbgBreak("No support for more than one object");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
// Create the window we will use to edit properties
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent,
|
||||
LPCRECT pRect,
|
||||
BOOL fModal)
|
||||
{
|
||||
CheckPointer(pRect,E_POINTER);
|
||||
|
||||
// Return failure if SetObject has not been called.
|
||||
if (m_bObjectSet == FALSE) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (m_hwnd) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_hwnd = CreateDialogParam(g_hInst,
|
||||
MAKEINTRESOURCE(m_DialogId),
|
||||
hwndParent,
|
||||
DialogProc,
|
||||
(LPARAM) this);
|
||||
if (m_hwnd == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
OnActivate();
|
||||
Move(pRect);
|
||||
return Show(SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
|
||||
// Set the position of the property page
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect)
|
||||
{
|
||||
CheckPointer(pRect,E_POINTER);
|
||||
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
MoveWindow(m_hwnd, // Property page handle
|
||||
pRect->left, // x coordinate
|
||||
pRect->top, // y coordinate
|
||||
WIDTH(pRect), // Overall window width
|
||||
HEIGHT(pRect), // And likewise height
|
||||
TRUE); // Should we repaint it
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Display the property dialog
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow)
|
||||
{
|
||||
// Have we been activated yet
|
||||
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Ignore wrong show flags
|
||||
|
||||
if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
ShowWindow(m_hwnd,nCmdShow);
|
||||
InvalidateRect(m_hwnd,NULL,TRUE);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Destroy the property page dialog
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Deactivate(void)
|
||||
{
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Remove WS_EX_CONTROLPARENT before DestroyWindow call
|
||||
|
||||
DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE);
|
||||
dwStyle = dwStyle & (~WS_EX_CONTROLPARENT);
|
||||
|
||||
// Set m_hwnd to be NULL temporarily so the message handler
|
||||
// for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT
|
||||
// style back in
|
||||
HWND hwnd = m_hwnd;
|
||||
m_hwnd = NULL;
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle);
|
||||
m_hwnd = hwnd;
|
||||
|
||||
OnDeactivate();
|
||||
|
||||
// Destroy the dialog window
|
||||
|
||||
DestroyWindow(m_hwnd);
|
||||
m_hwnd = NULL;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Tells the application property page site
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::SetPageSite(LPPROPERTYPAGESITE pPageSite)
|
||||
{
|
||||
if (pPageSite) {
|
||||
|
||||
if (m_pPageSite) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_pPageSite = pPageSite;
|
||||
m_pPageSite->AddRef();
|
||||
|
||||
} else {
|
||||
|
||||
if (m_pPageSite == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_pPageSite->Release();
|
||||
m_pPageSite = NULL;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Apply any changes so far made
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Apply()
|
||||
{
|
||||
// In ActiveMovie 1.0 we used to check whether we had been activated or
|
||||
// not. This is too constrictive. Apply should be allowed as long as
|
||||
// SetObject was called to set an object. So we will no longer check to
|
||||
// see if we have been activated (ie., m_hWnd != NULL), but instead
|
||||
// make sure that m_bObjectSet is TRUE (ie., SetObject has been called).
|
||||
|
||||
if (m_bObjectSet == FALSE) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Must have had a site set
|
||||
|
||||
if (m_pPageSite == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Has anything changed
|
||||
|
||||
if (m_bDirty == FALSE) {
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Commit derived class changes
|
||||
|
||||
HRESULT hr = OnApplyChanges();
|
||||
if (SUCCEEDED(hr)) {
|
||||
m_bDirty = FALSE;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Base class definition for message handling
|
||||
|
||||
INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
// we would like the TAB key to move around the tab stops in our property
|
||||
// page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT
|
||||
// style behind our back, so we need to switch it back on now behind its
|
||||
// back. Otherwise the tab key will be useless in every page.
|
||||
//
|
||||
|
||||
CBasePropertyPage *pPropertyPage;
|
||||
{
|
||||
pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
|
||||
if (pPropertyPage->m_hwnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
switch (uMsg) {
|
||||
case WM_STYLECHANGING:
|
||||
if (wParam == GWL_EXSTYLE) {
|
||||
LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam;
|
||||
lpss->styleNew |= WS_EX_CONTROLPARENT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: CProp.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements CBasePropertyPage class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
// Constructor for the base property page class. As described in the header
|
||||
// file we must be initialised with dialog and title resource identifiers.
|
||||
// The class supports IPropertyPage and overrides AddRef and Release calls
|
||||
// to keep track of the reference counts. When the last count is released
|
||||
// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces
|
||||
// previously obtained by the property page when it had SetObjects called
|
||||
|
||||
CBasePropertyPage::CBasePropertyPage(TCHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId) : // To get tital
|
||||
CUnknown(pName,pUnk),
|
||||
m_DialogId(DialogId),
|
||||
m_TitleId(TitleId),
|
||||
m_hwnd(NULL),
|
||||
m_Dlg(NULL),
|
||||
m_pPageSite(NULL),
|
||||
m_bObjectSet(FALSE),
|
||||
m_bDirty(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
CBasePropertyPage::CBasePropertyPage(CHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId) : // To get tital
|
||||
CUnknown(pName,pUnk),
|
||||
m_DialogId(DialogId),
|
||||
m_TitleId(TitleId),
|
||||
m_hwnd(NULL),
|
||||
m_Dlg(NULL),
|
||||
m_pPageSite(NULL),
|
||||
m_bObjectSet(FALSE),
|
||||
m_bDirty(FALSE)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
// Increment our reference count
|
||||
|
||||
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef()
|
||||
{
|
||||
LONG lRef = InterlockedIncrement(&m_cRef);
|
||||
ASSERT(lRef > 0);
|
||||
return max(ULONG(m_cRef),1ul);
|
||||
}
|
||||
|
||||
|
||||
// Release a reference count and protect against reentrancy
|
||||
|
||||
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease()
|
||||
{
|
||||
// If the reference count drops to zero delete ourselves
|
||||
|
||||
if (InterlockedDecrement(&m_cRef) == 0) {
|
||||
m_cRef++;
|
||||
SetPageSite(NULL);
|
||||
SetObjects(0,NULL);
|
||||
delete this;
|
||||
return ULONG(0);
|
||||
} else {
|
||||
return max(ULONG(m_cRef),1ul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Expose our IPropertyPage interface
|
||||
|
||||
STDMETHODIMP
|
||||
CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,void **ppv)
|
||||
{
|
||||
if (riid == IID_IPropertyPage) {
|
||||
return GetInterface((IPropertyPage *)this,ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid,ppv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the page info so that the page site can size itself
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::GetPageInfo(LPPROPPAGEINFO pPageInfo)
|
||||
{
|
||||
CheckPointer(pPageInfo,E_POINTER);
|
||||
WCHAR wszTitle[STR_MAX_LENGTH];
|
||||
WideStringFromResource(wszTitle,m_TitleId);
|
||||
|
||||
// Allocate dynamic memory for the property page title
|
||||
|
||||
LPOLESTR pszTitle;
|
||||
HRESULT hr = AMGetWideString(wszTitle, &pszTitle);
|
||||
if (FAILED(hr)) {
|
||||
NOTE("No caption memory");
|
||||
return hr;
|
||||
}
|
||||
|
||||
pPageInfo->cb = sizeof(PROPPAGEINFO);
|
||||
pPageInfo->pszTitle = pszTitle;
|
||||
pPageInfo->pszDocString = NULL;
|
||||
pPageInfo->pszHelpFile = NULL;
|
||||
pPageInfo->dwHelpContext = 0;
|
||||
|
||||
// Set defaults in case GetDialogSize fails
|
||||
pPageInfo->size.cx = 340;
|
||||
pPageInfo->size.cy = 150;
|
||||
|
||||
GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Handles the messages for our property window
|
||||
|
||||
INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
CBasePropertyPage *pPropertyPage;
|
||||
|
||||
switch (uMsg) {
|
||||
|
||||
case WM_INITDIALOG:
|
||||
|
||||
SetWindowLongPtr(hwnd, DWLP_USER, lParam);
|
||||
|
||||
// This pointer may be NULL when calculating size
|
||||
|
||||
pPropertyPage = (CBasePropertyPage *) lParam;
|
||||
if (pPropertyPage == NULL) {
|
||||
return (LRESULT) 1;
|
||||
}
|
||||
pPropertyPage->m_Dlg = hwnd;
|
||||
}
|
||||
|
||||
// This pointer may be NULL when calculating size
|
||||
|
||||
pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
|
||||
if (pPropertyPage == NULL) {
|
||||
return (LRESULT) 1;
|
||||
}
|
||||
return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
|
||||
// Tells us the object that should be informed of the property changes
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,LPUNKNOWN *ppUnk)
|
||||
{
|
||||
if (cObjects == 1) {
|
||||
|
||||
if ((ppUnk == NULL) || (*ppUnk == NULL)) {
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// Set a flag to say that we have set the Object
|
||||
m_bObjectSet = TRUE ;
|
||||
return OnConnect(*ppUnk);
|
||||
|
||||
} else if (cObjects == 0) {
|
||||
|
||||
// Set a flag to say that we have not set the Object for the page
|
||||
m_bObjectSet = FALSE ;
|
||||
return OnDisconnect();
|
||||
}
|
||||
|
||||
DbgBreak("No support for more than one object");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
// Create the window we will use to edit properties
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent,
|
||||
LPCRECT pRect,
|
||||
BOOL fModal)
|
||||
{
|
||||
CheckPointer(pRect,E_POINTER);
|
||||
|
||||
// Return failure if SetObject has not been called.
|
||||
if (m_bObjectSet == FALSE) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (m_hwnd) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_hwnd = CreateDialogParam(g_hInst,
|
||||
MAKEINTRESOURCE(m_DialogId),
|
||||
hwndParent,
|
||||
DialogProc,
|
||||
(LPARAM) this);
|
||||
if (m_hwnd == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
OnActivate();
|
||||
Move(pRect);
|
||||
return Show(SW_SHOWNORMAL);
|
||||
}
|
||||
|
||||
|
||||
// Set the position of the property page
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect)
|
||||
{
|
||||
CheckPointer(pRect,E_POINTER);
|
||||
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
MoveWindow(m_hwnd, // Property page handle
|
||||
pRect->left, // x coordinate
|
||||
pRect->top, // y coordinate
|
||||
WIDTH(pRect), // Overall window width
|
||||
HEIGHT(pRect), // And likewise height
|
||||
TRUE); // Should we repaint it
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Display the property dialog
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow)
|
||||
{
|
||||
// Have we been activated yet
|
||||
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Ignore wrong show flags
|
||||
|
||||
if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) {
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
ShowWindow(m_hwnd,nCmdShow);
|
||||
InvalidateRect(m_hwnd,NULL,TRUE);
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Destroy the property page dialog
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Deactivate(void)
|
||||
{
|
||||
if (m_hwnd == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Remove WS_EX_CONTROLPARENT before DestroyWindow call
|
||||
|
||||
DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE);
|
||||
dwStyle = dwStyle & (~WS_EX_CONTROLPARENT);
|
||||
|
||||
// Set m_hwnd to be NULL temporarily so the message handler
|
||||
// for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT
|
||||
// style back in
|
||||
HWND hwnd = m_hwnd;
|
||||
m_hwnd = NULL;
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle);
|
||||
m_hwnd = hwnd;
|
||||
|
||||
OnDeactivate();
|
||||
|
||||
// Destroy the dialog window
|
||||
|
||||
DestroyWindow(m_hwnd);
|
||||
m_hwnd = NULL;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Tells the application property page site
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::SetPageSite(LPPROPERTYPAGESITE pPageSite)
|
||||
{
|
||||
if (pPageSite) {
|
||||
|
||||
if (m_pPageSite) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_pPageSite = pPageSite;
|
||||
m_pPageSite->AddRef();
|
||||
|
||||
} else {
|
||||
|
||||
if (m_pPageSite == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
m_pPageSite->Release();
|
||||
m_pPageSite = NULL;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Apply any changes so far made
|
||||
|
||||
STDMETHODIMP CBasePropertyPage::Apply()
|
||||
{
|
||||
// In ActiveMovie 1.0 we used to check whether we had been activated or
|
||||
// not. This is too constrictive. Apply should be allowed as long as
|
||||
// SetObject was called to set an object. So we will no longer check to
|
||||
// see if we have been activated (ie., m_hWnd != NULL), but instead
|
||||
// make sure that m_bObjectSet is TRUE (ie., SetObject has been called).
|
||||
|
||||
if (m_bObjectSet == FALSE) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Must have had a site set
|
||||
|
||||
if (m_pPageSite == NULL) {
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Has anything changed
|
||||
|
||||
if (m_bDirty == FALSE) {
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Commit derived class changes
|
||||
|
||||
HRESULT hr = OnApplyChanges();
|
||||
if (SUCCEEDED(hr)) {
|
||||
m_bDirty = FALSE;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Base class definition for message handling
|
||||
|
||||
INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
// we would like the TAB key to move around the tab stops in our property
|
||||
// page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT
|
||||
// style behind our back, so we need to switch it back on now behind its
|
||||
// back. Otherwise the tab key will be useless in every page.
|
||||
//
|
||||
|
||||
CBasePropertyPage *pPropertyPage;
|
||||
{
|
||||
pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
|
||||
if (pPropertyPage->m_hwnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
switch (uMsg) {
|
||||
case WM_STYLECHANGING:
|
||||
if (wParam == GWL_EXSTYLE) {
|
||||
LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam;
|
||||
lpss->styleNew |= WS_EX_CONTROLPARENT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
|
||||
+95
-95
@@ -1,95 +1,95 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: CProp.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __CPROP__
|
||||
#define __CPROP__
|
||||
|
||||
// Base property page class. Filters typically expose custom properties by
|
||||
// implementing special control interfaces, examples are IDirectDrawVideo
|
||||
// and IQualProp on renderers. This allows property pages to be built that
|
||||
// use the given interface. Applications such as the ActiveMovie OCX query
|
||||
// filters for the property pages they support and expose them to the user
|
||||
//
|
||||
// This class provides all the framework for a property page. A property
|
||||
// page is a COM object that supports IPropertyPage. We should be created
|
||||
// with a resource ID for the dialog which we will load when required. We
|
||||
// should also be given in the constructor a resource ID for a title string
|
||||
// we will load from the DLLs STRINGTABLE. The property page titles must be
|
||||
// stored in resource files so that they can be easily internationalised
|
||||
//
|
||||
// We have a number of virtual methods (not PURE) that may be overriden in
|
||||
// derived classes to query for interfaces and so on. These functions have
|
||||
// simple implementations here that just return NOERROR. Derived classes
|
||||
// will almost definately have to override the message handler method called
|
||||
// OnReceiveMessage. We have a static dialog procedure that calls the method
|
||||
// so that derived classes don't have to fiddle around with the this pointer
|
||||
|
||||
class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPPROPERTYPAGESITE m_pPageSite; // Details for our property site
|
||||
HWND m_hwnd; // Window handle for the page
|
||||
HWND m_Dlg; // Actual dialog window handle
|
||||
BOOL m_bDirty; // Has anything been changed
|
||||
int m_TitleId; // Resource identifier for title
|
||||
int m_DialogId; // Dialog resource identifier
|
||||
|
||||
static INT_PTR CALLBACK DialogProc(HWND hwnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
private:
|
||||
BOOL m_bObjectSet ; // SetObject has been called or not.
|
||||
public:
|
||||
|
||||
CBasePropertyPage(TCHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId); // To get tital
|
||||
|
||||
#ifdef UNICODE
|
||||
CBasePropertyPage(CHAR *pName,
|
||||
LPUNKNOWN pUnk,
|
||||
int DialogId,
|
||||
int TitleId);
|
||||
#endif
|
||||
virtual ~CBasePropertyPage() { };
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
// Override these virtual methods
|
||||
|
||||
virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; };
|
||||
virtual HRESULT OnDisconnect() { return NOERROR; };
|
||||
virtual HRESULT OnActivate() { return NOERROR; };
|
||||
virtual HRESULT OnDeactivate() { return NOERROR; };
|
||||
virtual HRESULT OnApplyChanges() { return NOERROR; };
|
||||
virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
||||
|
||||
// These implement an IPropertyPage interface
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP SetPageSite(LPPROPERTYPAGESITE pPageSite);
|
||||
STDMETHODIMP Activate(HWND hwndParent,LPCRECT prect,BOOL fModal);
|
||||
STDMETHODIMP Deactivate(void);
|
||||
STDMETHODIMP GetPageInfo(LPPROPPAGEINFO pPageInfo);
|
||||
STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN *ppUnk);
|
||||
STDMETHODIMP Show(UINT nCmdShow);
|
||||
STDMETHODIMP Move(LPCRECT prect);
|
||||
STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; }
|
||||
STDMETHODIMP Apply(void);
|
||||
STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; }
|
||||
STDMETHODIMP TranslateAccelerator(LPMSG lpMsg) { return E_NOTIMPL; }
|
||||
};
|
||||
|
||||
#endif // __CPROP__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: CProp.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __CPROP__
|
||||
#define __CPROP__
|
||||
|
||||
// Base property page class. Filters typically expose custom properties by
|
||||
// implementing special control interfaces, examples are IDirectDrawVideo
|
||||
// and IQualProp on renderers. This allows property pages to be built that
|
||||
// use the given interface. Applications such as the ActiveMovie OCX query
|
||||
// filters for the property pages they support and expose them to the user
|
||||
//
|
||||
// This class provides all the framework for a property page. A property
|
||||
// page is a COM object that supports IPropertyPage. We should be created
|
||||
// with a resource ID for the dialog which we will load when required. We
|
||||
// should also be given in the constructor a resource ID for a title string
|
||||
// we will load from the DLLs STRINGTABLE. The property page titles must be
|
||||
// stored in resource files so that they can be easily internationalised
|
||||
//
|
||||
// We have a number of virtual methods (not PURE) that may be overriden in
|
||||
// derived classes to query for interfaces and so on. These functions have
|
||||
// simple implementations here that just return NOERROR. Derived classes
|
||||
// will almost definately have to override the message handler method called
|
||||
// OnReceiveMessage. We have a static dialog procedure that calls the method
|
||||
// so that derived classes don't have to fiddle around with the this pointer
|
||||
|
||||
class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPPROPERTYPAGESITE m_pPageSite; // Details for our property site
|
||||
HWND m_hwnd; // Window handle for the page
|
||||
HWND m_Dlg; // Actual dialog window handle
|
||||
BOOL m_bDirty; // Has anything been changed
|
||||
int m_TitleId; // Resource identifier for title
|
||||
int m_DialogId; // Dialog resource identifier
|
||||
|
||||
static INT_PTR CALLBACK DialogProc(HWND hwnd,
|
||||
UINT uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
private:
|
||||
BOOL m_bObjectSet ; // SetObject has been called or not.
|
||||
public:
|
||||
|
||||
CBasePropertyPage(TCHAR *pName, // Debug only name
|
||||
LPUNKNOWN pUnk, // COM Delegator
|
||||
int DialogId, // Resource ID
|
||||
int TitleId); // To get tital
|
||||
|
||||
#ifdef UNICODE
|
||||
CBasePropertyPage(CHAR *pName,
|
||||
LPUNKNOWN pUnk,
|
||||
int DialogId,
|
||||
int TitleId);
|
||||
#endif
|
||||
virtual ~CBasePropertyPage() { };
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
// Override these virtual methods
|
||||
|
||||
virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; };
|
||||
virtual HRESULT OnDisconnect() { return NOERROR; };
|
||||
virtual HRESULT OnActivate() { return NOERROR; };
|
||||
virtual HRESULT OnDeactivate() { return NOERROR; };
|
||||
virtual HRESULT OnApplyChanges() { return NOERROR; };
|
||||
virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
||||
|
||||
// These implement an IPropertyPage interface
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP SetPageSite(LPPROPERTYPAGESITE pPageSite);
|
||||
STDMETHODIMP Activate(HWND hwndParent,LPCRECT prect,BOOL fModal);
|
||||
STDMETHODIMP Deactivate(void);
|
||||
STDMETHODIMP GetPageInfo(LPPROPPAGEINFO pPageInfo);
|
||||
STDMETHODIMP SetObjects(ULONG cObjects, LPUNKNOWN *ppUnk);
|
||||
STDMETHODIMP Show(UINT nCmdShow);
|
||||
STDMETHODIMP Move(LPCRECT prect);
|
||||
STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; }
|
||||
STDMETHODIMP Apply(void);
|
||||
STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; }
|
||||
STDMETHODIMP TranslateAccelerator(LPMSG lpMsg) { return E_NOTIMPL; }
|
||||
};
|
||||
|
||||
#endif // __CPROP__
|
||||
|
||||
|
||||
+2378
-2378
File diff suppressed because it is too large
Load Diff
+919
-919
File diff suppressed because it is too large
Load Diff
+126
-126
@@ -1,126 +1,126 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDMM.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements routines for using DirectDraw
|
||||
// on a multimonitor system.
|
||||
//
|
||||
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <ddraw.h>
|
||||
#include "ddmm.h"
|
||||
|
||||
/*
|
||||
* FindDeviceCallback
|
||||
*/
|
||||
typedef struct {
|
||||
LPSTR szDevice;
|
||||
GUID* lpGUID;
|
||||
GUID GUID;
|
||||
BOOL fFound;
|
||||
} FindDeviceData;
|
||||
|
||||
BOOL CALLBACK FindDeviceCallback(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam) {
|
||||
FindDeviceData *p = (FindDeviceData*)lParam;
|
||||
|
||||
if(lstrcmpiA(p->szDevice, szDevice) == 0) {
|
||||
if(lpGUID) {
|
||||
p->GUID = *lpGUID;
|
||||
p->lpGUID = &p->GUID;
|
||||
}
|
||||
else {
|
||||
p->lpGUID = NULL;
|
||||
}
|
||||
p->fFound = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL CALLBACK FindDeviceCallbackEx(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam, HMONITOR hMonitor) {
|
||||
FindDeviceData *p = (FindDeviceData*)lParam;
|
||||
|
||||
if(lstrcmpiA(p->szDevice, szDevice) == 0) {
|
||||
if(lpGUID) {
|
||||
p->GUID = *lpGUID;
|
||||
p->lpGUID = &p->GUID;
|
||||
}
|
||||
else {
|
||||
p->lpGUID = NULL;
|
||||
}
|
||||
p->fFound = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DirectDrawCreateFromDevice
|
||||
*
|
||||
* create a DirectDraw object for a particular device
|
||||
*/
|
||||
IDirectDraw * DirectDrawCreateFromDevice(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) {
|
||||
IDirectDraw* pdd = NULL;
|
||||
FindDeviceData find;
|
||||
|
||||
if(szDevice == NULL) {
|
||||
DirectDrawCreateP(NULL, &pdd, NULL);
|
||||
return pdd;
|
||||
}
|
||||
|
||||
find.szDevice = szDevice;
|
||||
find.fFound = FALSE;
|
||||
DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find);
|
||||
|
||||
if(find.fFound) {
|
||||
//
|
||||
// In 4bpp mode the following DDraw call causes a message box to be popped
|
||||
// up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
|
||||
// make sure it doesn't happen.
|
||||
//
|
||||
UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
DirectDrawCreateP(find.lpGUID, &pdd, NULL);
|
||||
SetErrorMode(ErrorMode);
|
||||
}
|
||||
|
||||
return pdd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DirectDrawCreateFromDeviceEx
|
||||
*
|
||||
* create a DirectDraw object for a particular device
|
||||
*/
|
||||
IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) {
|
||||
IDirectDraw* pdd = NULL;
|
||||
FindDeviceData find;
|
||||
|
||||
if(szDevice == NULL) {
|
||||
DirectDrawCreateP(NULL, &pdd, NULL);
|
||||
return pdd;
|
||||
}
|
||||
|
||||
find.szDevice = szDevice;
|
||||
find.fFound = FALSE;
|
||||
DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find,
|
||||
DDENUM_ATTACHEDSECONDARYDEVICES);
|
||||
|
||||
if(find.fFound) {
|
||||
//
|
||||
// In 4bpp mode the following DDraw call causes a message box to be popped
|
||||
// up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
|
||||
// make sure it doesn't happen.
|
||||
//
|
||||
UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
DirectDrawCreateP(find.lpGUID, &pdd, NULL);
|
||||
SetErrorMode(ErrorMode);
|
||||
}
|
||||
|
||||
return pdd;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDMM.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements routines for using DirectDraw
|
||||
// on a multimonitor system.
|
||||
//
|
||||
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <ddraw.h>
|
||||
#include "ddmm.h"
|
||||
|
||||
/*
|
||||
* FindDeviceCallback
|
||||
*/
|
||||
typedef struct {
|
||||
LPSTR szDevice;
|
||||
GUID* lpGUID;
|
||||
GUID GUID;
|
||||
BOOL fFound;
|
||||
} FindDeviceData;
|
||||
|
||||
BOOL CALLBACK FindDeviceCallback(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam) {
|
||||
FindDeviceData *p = (FindDeviceData*)lParam;
|
||||
|
||||
if(lstrcmpiA(p->szDevice, szDevice) == 0) {
|
||||
if(lpGUID) {
|
||||
p->GUID = *lpGUID;
|
||||
p->lpGUID = &p->GUID;
|
||||
}
|
||||
else {
|
||||
p->lpGUID = NULL;
|
||||
}
|
||||
p->fFound = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL CALLBACK FindDeviceCallbackEx(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam, HMONITOR hMonitor) {
|
||||
FindDeviceData *p = (FindDeviceData*)lParam;
|
||||
|
||||
if(lstrcmpiA(p->szDevice, szDevice) == 0) {
|
||||
if(lpGUID) {
|
||||
p->GUID = *lpGUID;
|
||||
p->lpGUID = &p->GUID;
|
||||
}
|
||||
else {
|
||||
p->lpGUID = NULL;
|
||||
}
|
||||
p->fFound = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DirectDrawCreateFromDevice
|
||||
*
|
||||
* create a DirectDraw object for a particular device
|
||||
*/
|
||||
IDirectDraw * DirectDrawCreateFromDevice(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) {
|
||||
IDirectDraw* pdd = NULL;
|
||||
FindDeviceData find;
|
||||
|
||||
if(szDevice == NULL) {
|
||||
DirectDrawCreateP(NULL, &pdd, NULL);
|
||||
return pdd;
|
||||
}
|
||||
|
||||
find.szDevice = szDevice;
|
||||
find.fFound = FALSE;
|
||||
DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find);
|
||||
|
||||
if(find.fFound) {
|
||||
//
|
||||
// In 4bpp mode the following DDraw call causes a message box to be popped
|
||||
// up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
|
||||
// make sure it doesn't happen.
|
||||
//
|
||||
UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
DirectDrawCreateP(find.lpGUID, &pdd, NULL);
|
||||
SetErrorMode(ErrorMode);
|
||||
}
|
||||
|
||||
return pdd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DirectDrawCreateFromDeviceEx
|
||||
*
|
||||
* create a DirectDraw object for a particular device
|
||||
*/
|
||||
IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) {
|
||||
IDirectDraw* pdd = NULL;
|
||||
FindDeviceData find;
|
||||
|
||||
if(szDevice == NULL) {
|
||||
DirectDrawCreateP(NULL, &pdd, NULL);
|
||||
return pdd;
|
||||
}
|
||||
|
||||
find.szDevice = szDevice;
|
||||
find.fFound = FALSE;
|
||||
DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find,
|
||||
DDENUM_ATTACHEDSECONDARYDEVICES);
|
||||
|
||||
if(find.fFound) {
|
||||
//
|
||||
// In 4bpp mode the following DDraw call causes a message box to be popped
|
||||
// up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
|
||||
// make sure it doesn't happen.
|
||||
//
|
||||
UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
DirectDrawCreateP(find.lpGUID, &pdd, NULL);
|
||||
SetErrorMode(ErrorMode);
|
||||
}
|
||||
|
||||
return pdd;
|
||||
}
|
||||
|
||||
|
||||
+28
-28
@@ -1,28 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDMM.h
|
||||
//
|
||||
// Desc: DirectShow base classes - efines routines for using DirectDraw
|
||||
// on a multimonitor system.
|
||||
//
|
||||
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Assume C declarations for C++ */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// DDRAW.H might not include these
|
||||
#ifndef DDENUM_ATTACHEDSECONDARYDEVICES
|
||||
#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L
|
||||
#endif
|
||||
|
||||
typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN);
|
||||
typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID);
|
||||
|
||||
IDirectDraw * DirectDrawCreateFromDevice(LPSTR, PDRAWCREATE, PDRAWENUM);
|
||||
IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DDMM.h
|
||||
//
|
||||
// Desc: DirectShow base classes - efines routines for using DirectDraw
|
||||
// on a multimonitor system.
|
||||
//
|
||||
// Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { /* Assume C declarations for C++ */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// DDRAW.H might not include these
|
||||
#ifndef DDENUM_ATTACHEDSECONDARYDEVICES
|
||||
#define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L
|
||||
#endif
|
||||
|
||||
typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN);
|
||||
typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID);
|
||||
|
||||
IDirectDraw * DirectDrawCreateFromDevice(LPSTR, PDRAWCREATE, PDRAWENUM);
|
||||
IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
+332
-332
@@ -1,332 +1,332 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DllEntry.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements classes used to support dll
|
||||
// entry points for COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <initguid.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef UNICODE
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif // _UNICODE
|
||||
#endif // UNICODE
|
||||
|
||||
#include <tchar.h>
|
||||
#endif // DEBUG
|
||||
|
||||
extern CFactoryTemplate g_Templates[];
|
||||
extern int g_cTemplates;
|
||||
|
||||
HINSTANCE g_hInst;
|
||||
DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
|
||||
OSVERSIONINFO g_osInfo;
|
||||
|
||||
//
|
||||
// an instance of this is created by the DLLGetClassObject entrypoint
|
||||
// it uses the CFactoryTemplate object it is given to support the
|
||||
// IClassFactory interface
|
||||
|
||||
class CClassFactory : public IClassFactory, public CBaseObject {
|
||||
|
||||
private:
|
||||
const CFactoryTemplate *const m_pTemplate;
|
||||
|
||||
ULONG m_cRef;
|
||||
|
||||
static int m_cLocked;
|
||||
public:
|
||||
CClassFactory(const CFactoryTemplate *);
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
|
||||
STDMETHODIMP_(ULONG)AddRef();
|
||||
STDMETHODIMP_(ULONG)Release();
|
||||
|
||||
// IClassFactory
|
||||
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv);
|
||||
STDMETHODIMP LockServer(BOOL fLock);
|
||||
|
||||
// allow DLLGetClassObject to know about global server lock status
|
||||
static BOOL IsLocked() {
|
||||
return (m_cLocked > 0);
|
||||
};
|
||||
};
|
||||
|
||||
// process-wide dll locked state
|
||||
int CClassFactory::m_cLocked = 0;
|
||||
|
||||
CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
|
||||
: CBaseObject(NAME("Class Factory"))
|
||||
, m_cRef(0)
|
||||
, m_pTemplate(pTemplate) {
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::QueryInterface(REFIID riid,void **ppv) {
|
||||
CheckPointer(ppv,E_POINTER)
|
||||
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
||||
*ppv = NULL;
|
||||
|
||||
// any interface on this object is the object pointer.
|
||||
if((riid == IID_IUnknown) || (riid == IID_IClassFactory)) {
|
||||
*ppv = (LPVOID) this;
|
||||
// AddRef returned interface pointer
|
||||
((LPUNKNOWN) *ppv)->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
return ResultFromScode(E_NOINTERFACE);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CClassFactory::AddRef() {
|
||||
return ++m_cRef;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CClassFactory::Release() {
|
||||
if(--m_cRef == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return m_cRef;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::CreateInstance(
|
||||
LPUNKNOWN pUnkOuter,
|
||||
REFIID riid,
|
||||
void **pv) {
|
||||
CheckPointer(pv,E_POINTER)
|
||||
ValidateReadWritePtr(pv,sizeof(void *));
|
||||
|
||||
/* Enforce the normal OLE rules regarding interfaces and delegation */
|
||||
|
||||
if(pUnkOuter != NULL) {
|
||||
if(IsEqualIID(riid,IID_IUnknown) == FALSE) {
|
||||
return ResultFromScode(E_NOINTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the new object through the derived class's create function */
|
||||
|
||||
HRESULT hr = NOERROR;
|
||||
CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
|
||||
|
||||
if(pObj == NULL) {
|
||||
if(SUCCEEDED(hr)) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Delete the object if we got a construction error */
|
||||
|
||||
if(FAILED(hr)) {
|
||||
delete pObj;
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Get a reference counted interface on the object */
|
||||
|
||||
/* We wrap the non-delegating QI with NDAddRef & NDRelease. */
|
||||
/* This protects any outer object from being prematurely */
|
||||
/* released by an inner object that may have to be created */
|
||||
/* in order to supply the requested interface. */
|
||||
pObj->NonDelegatingAddRef();
|
||||
hr = pObj->NonDelegatingQueryInterface(riid, pv);
|
||||
pObj->NonDelegatingRelease();
|
||||
|
||||
/* Note that if NonDelegatingQueryInterface fails, it will */
|
||||
/* not increment the ref count, so the NonDelegatingRelease */
|
||||
/* will drop the ref back to zero and the object will "self-*/
|
||||
/* destruct". Hence we don't need additional tidy-up code */
|
||||
/* to cope with NonDelegatingQueryInterface failing. */
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
ASSERT(*pv);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::LockServer(BOOL fLock) {
|
||||
if(fLock) {
|
||||
m_cLocked++;
|
||||
}
|
||||
else {
|
||||
m_cLocked--;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// --- COM entrypoints -----------------------------------------
|
||||
|
||||
//called by COM to get the class factory object for a given class
|
||||
STDAPI
|
||||
DllGetClassObject(
|
||||
REFCLSID rClsID,
|
||||
REFIID riid,
|
||||
void **pv) {
|
||||
if(!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
// traverse the array of templates looking for one with this
|
||||
// class id
|
||||
for(int i = 0; i < g_cTemplates; i++) {
|
||||
const CFactoryTemplate * pT = &g_Templates[i];
|
||||
if(pT->IsClassID(rClsID)) {
|
||||
|
||||
// found a template - make a class factory based on this
|
||||
// template
|
||||
|
||||
*pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
|
||||
if(*pv == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
((LPUNKNOWN)*pv)->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
//
|
||||
// Call any initialization routines
|
||||
//
|
||||
void
|
||||
DllInitClasses(BOOL bLoading) {
|
||||
int i;
|
||||
|
||||
// traverse the array of templates calling the init routine
|
||||
// if they have one
|
||||
for(i = 0; i < g_cTemplates; i++) {
|
||||
const CFactoryTemplate * pT = &g_Templates[i];
|
||||
if(pT->m_lpfnInit != NULL) {
|
||||
(*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// called by COM to determine if this dll can be unloaded
|
||||
// return ok unless there are outstanding objects or a lock requested
|
||||
// by IClassFactory::LockServer
|
||||
//
|
||||
// CClassFactory has a static function that can tell us about the locks,
|
||||
// and CCOMObject has a static function that can tell us about the active
|
||||
// object count
|
||||
STDAPI
|
||||
DllCanUnloadNow() {
|
||||
DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"),
|
||||
CClassFactory::IsLocked(),
|
||||
CBaseObject::ObjectsActive()));
|
||||
|
||||
if(CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) {
|
||||
return S_FALSE;
|
||||
}
|
||||
else {
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- standard WIN32 entrypoints --------------------------------------
|
||||
|
||||
|
||||
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
|
||||
|
||||
BOOL WINAPI
|
||||
DllEntryPoint(HINSTANCE hInstance, ULONG ulReason, LPVOID pv) {
|
||||
#ifdef DEBUG
|
||||
extern bool g_fDbgInDllEntryPoint;
|
||||
g_fDbgInDllEntryPoint = true;
|
||||
#endif
|
||||
|
||||
switch(ulReason) {
|
||||
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
#ifdef DEBUG
|
||||
DbgInitialise(hInstance);
|
||||
#endif
|
||||
|
||||
{
|
||||
// The platform identifier is used to work out whether
|
||||
// full unicode support is available or not. Hence the
|
||||
// default will be the lowest common denominator - i.e. N/A
|
||||
g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails
|
||||
|
||||
g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);
|
||||
if(GetVersionEx(&g_osInfo)) {
|
||||
g_amPlatform = g_osInfo.dwPlatformId;
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95")));
|
||||
}
|
||||
}
|
||||
|
||||
g_hInst = hInstance;
|
||||
DllInitClasses(TRUE);
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
DllInitClasses(FALSE);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(CBaseObject::ObjectsActive()) {
|
||||
DbgSetModuleLevel(LOG_MEMORY, 2);
|
||||
TCHAR szInfo[512];
|
||||
extern TCHAR m_ModuleName[]; // Cut down module name
|
||||
|
||||
TCHAR FullName[_MAX_PATH]; // Load the full path and module name
|
||||
TCHAR *pName; // Searches from the end for a backslash
|
||||
|
||||
GetModuleFileName(NULL,FullName,_MAX_PATH);
|
||||
pName = _tcsrchr(FullName,'\\');
|
||||
if(pName == NULL) {
|
||||
pName = FullName;
|
||||
}
|
||||
else {
|
||||
pName++;
|
||||
}
|
||||
|
||||
DWORD cch = wsprintf(szInfo, TEXT("Executable: %s Pid %x Tid %x. "),
|
||||
pName, GetCurrentProcessId(), GetCurrentThreadId());
|
||||
|
||||
wsprintf(szInfo+cch, TEXT("Module %s, %d objects left active!"),
|
||||
m_ModuleName, CBaseObject::ObjectsActive());
|
||||
DbgAssert(szInfo, TEXT(__FILE__),__LINE__);
|
||||
|
||||
// If running remotely wait for the Assert to be acknowledged
|
||||
// before dumping out the object register
|
||||
DbgDumpObjectRegister();
|
||||
}
|
||||
|
||||
DbgTerminate();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
g_fDbgInDllEntryPoint = false;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DllEntry.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements classes used to support dll
|
||||
// entry points for COM objects.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <initguid.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef UNICODE
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif // _UNICODE
|
||||
#endif // UNICODE
|
||||
|
||||
#include <tchar.h>
|
||||
#endif // DEBUG
|
||||
|
||||
extern CFactoryTemplate g_Templates[];
|
||||
extern int g_cTemplates;
|
||||
|
||||
HINSTANCE g_hInst;
|
||||
DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)
|
||||
OSVERSIONINFO g_osInfo;
|
||||
|
||||
//
|
||||
// an instance of this is created by the DLLGetClassObject entrypoint
|
||||
// it uses the CFactoryTemplate object it is given to support the
|
||||
// IClassFactory interface
|
||||
|
||||
class CClassFactory : public IClassFactory, public CBaseObject {
|
||||
|
||||
private:
|
||||
const CFactoryTemplate *const m_pTemplate;
|
||||
|
||||
ULONG m_cRef;
|
||||
|
||||
static int m_cLocked;
|
||||
public:
|
||||
CClassFactory(const CFactoryTemplate *);
|
||||
|
||||
// IUnknown
|
||||
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
|
||||
STDMETHODIMP_(ULONG)AddRef();
|
||||
STDMETHODIMP_(ULONG)Release();
|
||||
|
||||
// IClassFactory
|
||||
STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv);
|
||||
STDMETHODIMP LockServer(BOOL fLock);
|
||||
|
||||
// allow DLLGetClassObject to know about global server lock status
|
||||
static BOOL IsLocked() {
|
||||
return (m_cLocked > 0);
|
||||
};
|
||||
};
|
||||
|
||||
// process-wide dll locked state
|
||||
int CClassFactory::m_cLocked = 0;
|
||||
|
||||
CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate)
|
||||
: CBaseObject(NAME("Class Factory"))
|
||||
, m_cRef(0)
|
||||
, m_pTemplate(pTemplate) {
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::QueryInterface(REFIID riid,void **ppv) {
|
||||
CheckPointer(ppv,E_POINTER)
|
||||
ValidateReadWritePtr(ppv,sizeof(PVOID));
|
||||
*ppv = NULL;
|
||||
|
||||
// any interface on this object is the object pointer.
|
||||
if((riid == IID_IUnknown) || (riid == IID_IClassFactory)) {
|
||||
*ppv = (LPVOID) this;
|
||||
// AddRef returned interface pointer
|
||||
((LPUNKNOWN) *ppv)->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
return ResultFromScode(E_NOINTERFACE);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CClassFactory::AddRef() {
|
||||
return ++m_cRef;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG)
|
||||
CClassFactory::Release() {
|
||||
if(--m_cRef == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return m_cRef;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::CreateInstance(
|
||||
LPUNKNOWN pUnkOuter,
|
||||
REFIID riid,
|
||||
void **pv) {
|
||||
CheckPointer(pv,E_POINTER)
|
||||
ValidateReadWritePtr(pv,sizeof(void *));
|
||||
|
||||
/* Enforce the normal OLE rules regarding interfaces and delegation */
|
||||
|
||||
if(pUnkOuter != NULL) {
|
||||
if(IsEqualIID(riid,IID_IUnknown) == FALSE) {
|
||||
return ResultFromScode(E_NOINTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the new object through the derived class's create function */
|
||||
|
||||
HRESULT hr = NOERROR;
|
||||
CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);
|
||||
|
||||
if(pObj == NULL) {
|
||||
if(SUCCEEDED(hr)) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Delete the object if we got a construction error */
|
||||
|
||||
if(FAILED(hr)) {
|
||||
delete pObj;
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Get a reference counted interface on the object */
|
||||
|
||||
/* We wrap the non-delegating QI with NDAddRef & NDRelease. */
|
||||
/* This protects any outer object from being prematurely */
|
||||
/* released by an inner object that may have to be created */
|
||||
/* in order to supply the requested interface. */
|
||||
pObj->NonDelegatingAddRef();
|
||||
hr = pObj->NonDelegatingQueryInterface(riid, pv);
|
||||
pObj->NonDelegatingRelease();
|
||||
|
||||
/* Note that if NonDelegatingQueryInterface fails, it will */
|
||||
/* not increment the ref count, so the NonDelegatingRelease */
|
||||
/* will drop the ref back to zero and the object will "self-*/
|
||||
/* destruct". Hence we don't need additional tidy-up code */
|
||||
/* to cope with NonDelegatingQueryInterface failing. */
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
ASSERT(*pv);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
CClassFactory::LockServer(BOOL fLock) {
|
||||
if(fLock) {
|
||||
m_cLocked++;
|
||||
}
|
||||
else {
|
||||
m_cLocked--;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// --- COM entrypoints -----------------------------------------
|
||||
|
||||
//called by COM to get the class factory object for a given class
|
||||
STDAPI
|
||||
DllGetClassObject(
|
||||
REFCLSID rClsID,
|
||||
REFIID riid,
|
||||
void **pv) {
|
||||
if(!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
// traverse the array of templates looking for one with this
|
||||
// class id
|
||||
for(int i = 0; i < g_cTemplates; i++) {
|
||||
const CFactoryTemplate * pT = &g_Templates[i];
|
||||
if(pT->IsClassID(rClsID)) {
|
||||
|
||||
// found a template - make a class factory based on this
|
||||
// template
|
||||
|
||||
*pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);
|
||||
if(*pv == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
((LPUNKNOWN)*pv)->AddRef();
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
//
|
||||
// Call any initialization routines
|
||||
//
|
||||
void
|
||||
DllInitClasses(BOOL bLoading) {
|
||||
int i;
|
||||
|
||||
// traverse the array of templates calling the init routine
|
||||
// if they have one
|
||||
for(i = 0; i < g_cTemplates; i++) {
|
||||
const CFactoryTemplate * pT = &g_Templates[i];
|
||||
if(pT->m_lpfnInit != NULL) {
|
||||
(*pT->m_lpfnInit)(bLoading, pT->m_ClsID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// called by COM to determine if this dll can be unloaded
|
||||
// return ok unless there are outstanding objects or a lock requested
|
||||
// by IClassFactory::LockServer
|
||||
//
|
||||
// CClassFactory has a static function that can tell us about the locks,
|
||||
// and CCOMObject has a static function that can tell us about the active
|
||||
// object count
|
||||
STDAPI
|
||||
DllCanUnloadNow() {
|
||||
DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"),
|
||||
CClassFactory::IsLocked(),
|
||||
CBaseObject::ObjectsActive()));
|
||||
|
||||
if(CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) {
|
||||
return S_FALSE;
|
||||
}
|
||||
else {
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- standard WIN32 entrypoints --------------------------------------
|
||||
|
||||
|
||||
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
|
||||
|
||||
BOOL WINAPI
|
||||
DllEntryPoint(HINSTANCE hInstance, ULONG ulReason, LPVOID pv) {
|
||||
#ifdef DEBUG
|
||||
extern bool g_fDbgInDllEntryPoint;
|
||||
g_fDbgInDllEntryPoint = true;
|
||||
#endif
|
||||
|
||||
switch(ulReason) {
|
||||
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hInstance);
|
||||
#ifdef DEBUG
|
||||
DbgInitialise(hInstance);
|
||||
#endif
|
||||
|
||||
{
|
||||
// The platform identifier is used to work out whether
|
||||
// full unicode support is available or not. Hence the
|
||||
// default will be the lowest common denominator - i.e. N/A
|
||||
g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails
|
||||
|
||||
g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);
|
||||
if(GetVersionEx(&g_osInfo)) {
|
||||
g_amPlatform = g_osInfo.dwPlatformId;
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95")));
|
||||
}
|
||||
}
|
||||
|
||||
g_hInst = hInstance;
|
||||
DllInitClasses(TRUE);
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
DllInitClasses(FALSE);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(CBaseObject::ObjectsActive()) {
|
||||
DbgSetModuleLevel(LOG_MEMORY, 2);
|
||||
TCHAR szInfo[512];
|
||||
extern TCHAR m_ModuleName[]; // Cut down module name
|
||||
|
||||
TCHAR FullName[_MAX_PATH]; // Load the full path and module name
|
||||
TCHAR *pName; // Searches from the end for a backslash
|
||||
|
||||
GetModuleFileName(NULL,FullName,_MAX_PATH);
|
||||
pName = _tcsrchr(FullName,'\\');
|
||||
if(pName == NULL) {
|
||||
pName = FullName;
|
||||
}
|
||||
else {
|
||||
pName++;
|
||||
}
|
||||
|
||||
DWORD cch = wsprintf(szInfo, TEXT("Executable: %s Pid %x Tid %x. "),
|
||||
pName, GetCurrentProcessId(), GetCurrentThreadId());
|
||||
|
||||
wsprintf(szInfo+cch, TEXT("Module %s, %d objects left active!"),
|
||||
m_ModuleName, CBaseObject::ObjectsActive());
|
||||
DbgAssert(szInfo, TEXT(__FILE__),__LINE__);
|
||||
|
||||
// If running remotely wait for the Assert to be acknowledged
|
||||
// before dumping out the object register
|
||||
DbgDumpObjectRegister();
|
||||
}
|
||||
|
||||
DbgTerminate();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
g_fDbgInDllEntryPoint = false;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+651
-651
File diff suppressed because it is too large
Load Diff
+46
-46
@@ -1,46 +1,46 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DllSetup.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// To be self registering, OLE servers must
|
||||
// export functions named DllRegisterServer
|
||||
// and DllUnregisterServer. To allow use of
|
||||
// custom and default implementations the
|
||||
// defaults are named AMovieDllRegisterServer
|
||||
// and AMovieDllUnregisterServer.
|
||||
//
|
||||
// To the use the default implementation you
|
||||
// must provide stub functions.
|
||||
//
|
||||
// i.e. STDAPI DllRegisterServer()
|
||||
// {
|
||||
// return AMovieDllRegisterServer();
|
||||
// }
|
||||
//
|
||||
// STDAPI DllUnregisterServer()
|
||||
// {
|
||||
// return AMovieDllUnregisterServer();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// AMovieDllRegisterServer calls IAMovieSetup.Register(), and
|
||||
// AMovieDllUnregisterServer calls IAMovieSetup.Unregister().
|
||||
|
||||
STDAPI AMovieDllRegisterServer2( BOOL );
|
||||
STDAPI AMovieDllRegisterServer();
|
||||
STDAPI AMovieDllUnregisterServer();
|
||||
|
||||
// helper functions
|
||||
STDAPI EliminateSubKey( HKEY, LPTSTR );
|
||||
|
||||
|
||||
STDAPI
|
||||
AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata
|
||||
, IFilterMapper2 * pIFM2
|
||||
, BOOL bRegister );
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DllSetup.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// To be self registering, OLE servers must
|
||||
// export functions named DllRegisterServer
|
||||
// and DllUnregisterServer. To allow use of
|
||||
// custom and default implementations the
|
||||
// defaults are named AMovieDllRegisterServer
|
||||
// and AMovieDllUnregisterServer.
|
||||
//
|
||||
// To the use the default implementation you
|
||||
// must provide stub functions.
|
||||
//
|
||||
// i.e. STDAPI DllRegisterServer()
|
||||
// {
|
||||
// return AMovieDllRegisterServer();
|
||||
// }
|
||||
//
|
||||
// STDAPI DllUnregisterServer()
|
||||
// {
|
||||
// return AMovieDllUnregisterServer();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// AMovieDllRegisterServer calls IAMovieSetup.Register(), and
|
||||
// AMovieDllUnregisterServer calls IAMovieSetup.Unregister().
|
||||
|
||||
STDAPI AMovieDllRegisterServer2( BOOL );
|
||||
STDAPI AMovieDllRegisterServer();
|
||||
STDAPI AMovieDllUnregisterServer();
|
||||
|
||||
// helper functions
|
||||
STDAPI EliminateSubKey( HKEY, LPTSTR );
|
||||
|
||||
|
||||
STDAPI
|
||||
AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata
|
||||
, IFilterMapper2 * pIFM2
|
||||
, BOOL bRegister );
|
||||
|
||||
|
||||
+132
-132
@@ -1,132 +1,132 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DSSchedule.h (replaces DX8's schedule.h)
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __CAMSchedule__
|
||||
#define __CAMSchedule__
|
||||
|
||||
class CAMSchedule : private CBaseObject
|
||||
{
|
||||
public:
|
||||
virtual ~CAMSchedule();
|
||||
// ev is the event we should fire if the advise time needs re-evaluating
|
||||
CAMSchedule( HANDLE ev );
|
||||
|
||||
DWORD GetAdviseCount();
|
||||
REFERENCE_TIME GetNextAdviseTime();
|
||||
|
||||
// We need a method for derived classes to add advise packets, we return the cookie
|
||||
DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic );
|
||||
// And a way to cancel
|
||||
HRESULT Unadvise(DWORD_PTR dwAdviseCookie);
|
||||
|
||||
// Tell us the time please, and we'll dispatch the expired events. We return the time of the next event.
|
||||
// NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of
|
||||
// whoever is using this helper class (typically a clock).
|
||||
REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime );
|
||||
|
||||
// Get the event handle which will be set if advise time requires re-evaluation.
|
||||
HANDLE GetEvent() const { return m_ev; }
|
||||
|
||||
private:
|
||||
// We define the nodes that will be used in our singly linked list
|
||||
// of advise packets. The list is ordered by time, with the
|
||||
// elements that will expire first at the front.
|
||||
class CAdvisePacket
|
||||
{
|
||||
public:
|
||||
CAdvisePacket()
|
||||
{}
|
||||
|
||||
CAdvisePacket * m_next;
|
||||
DWORD_PTR m_dwAdviseCookie;
|
||||
REFERENCE_TIME m_rtEventTime; // Time at which event should be set
|
||||
REFERENCE_TIME m_rtPeriod; // Periodic time
|
||||
HANDLE m_hNotify; // Handle to event or semephore
|
||||
BOOL m_bPeriodic; // TRUE => Periodic event
|
||||
|
||||
CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time)
|
||||
{}
|
||||
|
||||
void InsertAfter( CAdvisePacket * p )
|
||||
{
|
||||
p->m_next = m_next;
|
||||
m_next = p;
|
||||
}
|
||||
|
||||
int IsZ() const // That is, is it the node that represents the end of the list
|
||||
{
|
||||
return m_next == 0;
|
||||
}
|
||||
|
||||
CAdvisePacket * RemoveNext()
|
||||
{
|
||||
CAdvisePacket *const next = m_next;
|
||||
CAdvisePacket *const new_next = next->m_next;
|
||||
m_next = new_next;
|
||||
return next;
|
||||
}
|
||||
|
||||
void DeleteNext()
|
||||
{
|
||||
delete RemoveNext();
|
||||
}
|
||||
|
||||
CAdvisePacket * Next() const
|
||||
{
|
||||
CAdvisePacket * result = m_next;
|
||||
if (result->IsZ()) result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD_PTR Cookie() const
|
||||
{
|
||||
return m_dwAdviseCookie;
|
||||
}
|
||||
};
|
||||
|
||||
// Structure is:
|
||||
// head -> elmt1 -> elmt2 -> z -> null
|
||||
// So an empty list is: head -> z -> null
|
||||
// Having head & z as links makes insertaion,
|
||||
// deletion and shunting much easier.
|
||||
CAdvisePacket head, z; // z is both a tail and a sentry
|
||||
|
||||
volatile DWORD_PTR m_dwNextCookie; // Strictly increasing
|
||||
volatile DWORD m_dwAdviseCount; // Number of elements on list
|
||||
|
||||
CCritSec m_Serialize;
|
||||
|
||||
// AddAdvisePacket: adds the packet, returns the cookie (0 if failed)
|
||||
DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket );
|
||||
// Event that we should set if the packed added above will be the next to fire.
|
||||
const HANDLE m_ev;
|
||||
|
||||
// A Shunt is where we have changed the first element in the
|
||||
// list and want it re-evaluating (i.e. repositioned) in
|
||||
// the list.
|
||||
void ShuntHead();
|
||||
|
||||
// Rather than delete advise packets, we cache them for future use
|
||||
CAdvisePacket * m_pAdviseCache;
|
||||
DWORD m_dwCacheCount;
|
||||
enum { dwCacheMax = 5 }; // Don't bother caching more than five
|
||||
|
||||
void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link
|
||||
|
||||
// Attributes and methods for debugging
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
void DumpLinkedList();
|
||||
#else
|
||||
void DumpLinkedList() {}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // __CAMSchedule__
|
||||
//------------------------------------------------------------------------------
|
||||
// File: DSSchedule.h (replaces DX8's schedule.h)
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __CAMSchedule__
|
||||
#define __CAMSchedule__
|
||||
|
||||
class CAMSchedule : private CBaseObject
|
||||
{
|
||||
public:
|
||||
virtual ~CAMSchedule();
|
||||
// ev is the event we should fire if the advise time needs re-evaluating
|
||||
CAMSchedule( HANDLE ev );
|
||||
|
||||
DWORD GetAdviseCount();
|
||||
REFERENCE_TIME GetNextAdviseTime();
|
||||
|
||||
// We need a method for derived classes to add advise packets, we return the cookie
|
||||
DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic );
|
||||
// And a way to cancel
|
||||
HRESULT Unadvise(DWORD_PTR dwAdviseCookie);
|
||||
|
||||
// Tell us the time please, and we'll dispatch the expired events. We return the time of the next event.
|
||||
// NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of
|
||||
// whoever is using this helper class (typically a clock).
|
||||
REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime );
|
||||
|
||||
// Get the event handle which will be set if advise time requires re-evaluation.
|
||||
HANDLE GetEvent() const { return m_ev; }
|
||||
|
||||
private:
|
||||
// We define the nodes that will be used in our singly linked list
|
||||
// of advise packets. The list is ordered by time, with the
|
||||
// elements that will expire first at the front.
|
||||
class CAdvisePacket
|
||||
{
|
||||
public:
|
||||
CAdvisePacket()
|
||||
{}
|
||||
|
||||
CAdvisePacket * m_next;
|
||||
DWORD_PTR m_dwAdviseCookie;
|
||||
REFERENCE_TIME m_rtEventTime; // Time at which event should be set
|
||||
REFERENCE_TIME m_rtPeriod; // Periodic time
|
||||
HANDLE m_hNotify; // Handle to event or semephore
|
||||
BOOL m_bPeriodic; // TRUE => Periodic event
|
||||
|
||||
CAdvisePacket( CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time)
|
||||
{}
|
||||
|
||||
void InsertAfter( CAdvisePacket * p )
|
||||
{
|
||||
p->m_next = m_next;
|
||||
m_next = p;
|
||||
}
|
||||
|
||||
int IsZ() const // That is, is it the node that represents the end of the list
|
||||
{
|
||||
return m_next == 0;
|
||||
}
|
||||
|
||||
CAdvisePacket * RemoveNext()
|
||||
{
|
||||
CAdvisePacket *const next = m_next;
|
||||
CAdvisePacket *const new_next = next->m_next;
|
||||
m_next = new_next;
|
||||
return next;
|
||||
}
|
||||
|
||||
void DeleteNext()
|
||||
{
|
||||
delete RemoveNext();
|
||||
}
|
||||
|
||||
CAdvisePacket * Next() const
|
||||
{
|
||||
CAdvisePacket * result = m_next;
|
||||
if (result->IsZ()) result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD_PTR Cookie() const
|
||||
{
|
||||
return m_dwAdviseCookie;
|
||||
}
|
||||
};
|
||||
|
||||
// Structure is:
|
||||
// head -> elmt1 -> elmt2 -> z -> null
|
||||
// So an empty list is: head -> z -> null
|
||||
// Having head & z as links makes insertaion,
|
||||
// deletion and shunting much easier.
|
||||
CAdvisePacket head, z; // z is both a tail and a sentry
|
||||
|
||||
volatile DWORD_PTR m_dwNextCookie; // Strictly increasing
|
||||
volatile DWORD m_dwAdviseCount; // Number of elements on list
|
||||
|
||||
CCritSec m_Serialize;
|
||||
|
||||
// AddAdvisePacket: adds the packet, returns the cookie (0 if failed)
|
||||
DWORD_PTR AddAdvisePacket( CAdvisePacket * pPacket );
|
||||
// Event that we should set if the packed added above will be the next to fire.
|
||||
const HANDLE m_ev;
|
||||
|
||||
// A Shunt is where we have changed the first element in the
|
||||
// list and want it re-evaluating (i.e. repositioned) in
|
||||
// the list.
|
||||
void ShuntHead();
|
||||
|
||||
// Rather than delete advise packets, we cache them for future use
|
||||
CAdvisePacket * m_pAdviseCache;
|
||||
DWORD m_dwCacheCount;
|
||||
enum { dwCacheMax = 5 }; // Don't bother caching more than five
|
||||
|
||||
void Delete( CAdvisePacket * pLink );// This "Delete" will cache the Link
|
||||
|
||||
// Attributes and methods for debugging
|
||||
public:
|
||||
#ifdef DEBUG
|
||||
void DumpLinkedList();
|
||||
#else
|
||||
void DumpLinkedList() {}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // __CAMSchedule__
|
||||
|
||||
+100
-100
@@ -1,100 +1,100 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: FourCC.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// FOURCCMap
|
||||
//
|
||||
// provides a mapping between old-style multimedia format DWORDs
|
||||
// and new-style GUIDs.
|
||||
//
|
||||
// A range of 4 billion GUIDs has been allocated to ensure that this
|
||||
// mapping can be done straightforwardly one-to-one in both directions.
|
||||
//
|
||||
// January 95
|
||||
|
||||
|
||||
#ifndef __FOURCC__
|
||||
#define __FOURCC__
|
||||
|
||||
|
||||
// Multimedia format types are marked with DWORDs built from four 8-bit
|
||||
// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include
|
||||
// a subtype GUID. In order to simplify the mapping, GUIDs in the range:
|
||||
// XXXXXXXX-0000-0010-8000-00AA00389B71
|
||||
// are reserved for FOURCCs.
|
||||
|
||||
class FOURCCMap : public GUID
|
||||
{
|
||||
|
||||
public:
|
||||
FOURCCMap();
|
||||
FOURCCMap(DWORD Fourcc);
|
||||
FOURCCMap(const GUID *);
|
||||
|
||||
DWORD GetFOURCC(void);
|
||||
void SetFOURCC(DWORD fourcc);
|
||||
void SetFOURCC(const GUID *);
|
||||
|
||||
private:
|
||||
void InitGUID();
|
||||
};
|
||||
|
||||
#define GUID_Data2 0
|
||||
#define GUID_Data3 0x10
|
||||
#define GUID_Data4_1 0xaa000080
|
||||
#define GUID_Data4_2 0x719b3800
|
||||
|
||||
inline void
|
||||
FOURCCMap::InitGUID() {
|
||||
Data2 = GUID_Data2;
|
||||
Data3 = GUID_Data3;
|
||||
((DWORD *)Data4)[0] = GUID_Data4_1;
|
||||
((DWORD *)Data4)[1] = GUID_Data4_2;
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap() {
|
||||
InitGUID();
|
||||
SetFOURCC( DWORD(0));
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap(DWORD fourcc)
|
||||
{
|
||||
InitGUID();
|
||||
SetFOURCC(fourcc);
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap(const GUID * pGuid)
|
||||
{
|
||||
InitGUID();
|
||||
SetFOURCC(pGuid);
|
||||
}
|
||||
|
||||
inline void
|
||||
FOURCCMap::SetFOURCC(const GUID * pGuid)
|
||||
{
|
||||
FOURCCMap * p = (FOURCCMap*) pGuid;
|
||||
SetFOURCC(p->GetFOURCC());
|
||||
}
|
||||
|
||||
inline void
|
||||
FOURCCMap::SetFOURCC(DWORD fourcc)
|
||||
{
|
||||
Data1 = fourcc;
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
FOURCCMap::GetFOURCC(void)
|
||||
{
|
||||
return Data1;
|
||||
}
|
||||
|
||||
#endif /* __FOURCC__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: FourCC.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// FOURCCMap
|
||||
//
|
||||
// provides a mapping between old-style multimedia format DWORDs
|
||||
// and new-style GUIDs.
|
||||
//
|
||||
// A range of 4 billion GUIDs has been allocated to ensure that this
|
||||
// mapping can be done straightforwardly one-to-one in both directions.
|
||||
//
|
||||
// January 95
|
||||
|
||||
|
||||
#ifndef __FOURCC__
|
||||
#define __FOURCC__
|
||||
|
||||
|
||||
// Multimedia format types are marked with DWORDs built from four 8-bit
|
||||
// chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include
|
||||
// a subtype GUID. In order to simplify the mapping, GUIDs in the range:
|
||||
// XXXXXXXX-0000-0010-8000-00AA00389B71
|
||||
// are reserved for FOURCCs.
|
||||
|
||||
class FOURCCMap : public GUID
|
||||
{
|
||||
|
||||
public:
|
||||
FOURCCMap();
|
||||
FOURCCMap(DWORD Fourcc);
|
||||
FOURCCMap(const GUID *);
|
||||
|
||||
DWORD GetFOURCC(void);
|
||||
void SetFOURCC(DWORD fourcc);
|
||||
void SetFOURCC(const GUID *);
|
||||
|
||||
private:
|
||||
void InitGUID();
|
||||
};
|
||||
|
||||
#define GUID_Data2 0
|
||||
#define GUID_Data3 0x10
|
||||
#define GUID_Data4_1 0xaa000080
|
||||
#define GUID_Data4_2 0x719b3800
|
||||
|
||||
inline void
|
||||
FOURCCMap::InitGUID() {
|
||||
Data2 = GUID_Data2;
|
||||
Data3 = GUID_Data3;
|
||||
((DWORD *)Data4)[0] = GUID_Data4_1;
|
||||
((DWORD *)Data4)[1] = GUID_Data4_2;
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap() {
|
||||
InitGUID();
|
||||
SetFOURCC( DWORD(0));
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap(DWORD fourcc)
|
||||
{
|
||||
InitGUID();
|
||||
SetFOURCC(fourcc);
|
||||
}
|
||||
|
||||
inline
|
||||
FOURCCMap::FOURCCMap(const GUID * pGuid)
|
||||
{
|
||||
InitGUID();
|
||||
SetFOURCC(pGuid);
|
||||
}
|
||||
|
||||
inline void
|
||||
FOURCCMap::SetFOURCC(const GUID * pGuid)
|
||||
{
|
||||
FOURCCMap * p = (FOURCCMap*) pGuid;
|
||||
SetFOURCC(p->GetFOURCC());
|
||||
}
|
||||
|
||||
inline void
|
||||
FOURCCMap::SetFOURCC(DWORD fourcc)
|
||||
{
|
||||
Data1 = fourcc;
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
FOURCCMap::GetFOURCC(void)
|
||||
{
|
||||
return Data1;
|
||||
}
|
||||
|
||||
#endif /* __FOURCC__ */
|
||||
|
||||
|
||||
+222
-222
@@ -1,222 +1,222 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Measure.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
The idea is to pepper the source code with interesting measurements and
|
||||
have the last few thousand of these recorded in a circular buffer that
|
||||
can be post-processed to give interesting numbers.
|
||||
|
||||
WHAT THE LOG LOOKS LIKE:
|
||||
|
||||
Time (sec) Type Delta Incident_Name
|
||||
0.055,41 NOTE -. Incident Nine - Another note
|
||||
0.055,42 NOTE 0.000,01 Incident Nine - Another note
|
||||
0.055,44 NOTE 0.000,02 Incident Nine - Another note
|
||||
0.055,45 STOP -. Incident Eight - Also random
|
||||
0.055,47 START -. Incident Seven - Random
|
||||
0.055,49 NOTE 0.000,05 Incident Nine - Another note
|
||||
------- <etc. there is a lot of this> ----------------
|
||||
0.125,60 STOP 0.000,03 Msr_Stop
|
||||
0.125,62 START -. Msr_Start
|
||||
0.125,63 START -. Incident Two - Start/Stop
|
||||
0.125,65 STOP 0.000,03 Msr_Start
|
||||
0.125,66 START -. Msr_Stop
|
||||
0.125,68 STOP 0.000,05 Incident Two - Start/Stop
|
||||
0.125,70 STOP 0.000,04 Msr_Stop
|
||||
0.125,72 START -. Msr_Start
|
||||
0.125,73 START -. Incident Two - Start/Stop
|
||||
0.125,75 STOP 0.000,03 Msr_Start
|
||||
0.125,77 START -. Msr_Stop
|
||||
0.125,78 STOP 0.000,05 Incident Two - Start/Stop
|
||||
0.125,80 STOP 0.000,03 Msr_Stop
|
||||
0.125,81 NOTE -. Incident Three - single Note
|
||||
0.125,83 START -. Incident Four - Start, no stop
|
||||
0.125,85 START -. Incident Five - Single Start/Stop
|
||||
0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop
|
||||
|
||||
Number Average StdDev Smallest Largest Incident_Name
|
||||
10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note
|
||||
50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop
|
||||
1 -. -. -. -. Incident Three - single Note
|
||||
0 -. -. -. -. Incident Four - Start, no stop
|
||||
1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop
|
||||
0 -. -. -. -. Incident Six - zero occurrences
|
||||
100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random
|
||||
100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random
|
||||
5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note
|
||||
10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note
|
||||
50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start
|
||||
50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop
|
||||
|
||||
WHAT IT MEANS:
|
||||
The log shows what happened and when. Each line shows the time at which
|
||||
something happened (see WHAT YOU CODE below) what it was that happened
|
||||
and (if approporate) the time since the corresponding previous event
|
||||
(that's the delta column).
|
||||
|
||||
The statistics show how many times each event occurred, what the average
|
||||
delta time was, also the standard deviation, largest and smalles delta.
|
||||
|
||||
WHAT YOU CODE:
|
||||
|
||||
Before anything else executes: - register your ids
|
||||
|
||||
int id1 = Msr_Register("Incident One - Note");
|
||||
int id2 = Msr_Register("Incident Two - Start/Stop");
|
||||
int id3 = Msr_Register("Incident Three - single Note");
|
||||
etc.
|
||||
|
||||
At interesting moments:
|
||||
|
||||
// To measure a repetitive event - e.g. end of bitblt to screen
|
||||
Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!"
|
||||
|
||||
or
|
||||
|
||||
// To measure an elapsed time e.g. time taken to decode an MPEG B-frame
|
||||
Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame"
|
||||
. . .
|
||||
MsrStop(Id2); // "Finished MPEG decode"
|
||||
|
||||
At the end:
|
||||
|
||||
HANDLE hFile;
|
||||
hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
Msr_Dump(hFile); // This writes the log out to the file
|
||||
CloseHandle(hFile);
|
||||
|
||||
or
|
||||
|
||||
Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... ));
|
||||
// but if you are writing it out to the debugger
|
||||
// then the times are probably all garbage because
|
||||
// the debugger can make things run awfully slow.
|
||||
|
||||
A given id should be used either for start / stop or Note calls. If Notes
|
||||
are mixed in with Starts and Stops their statistics will be gibberish.
|
||||
|
||||
If you code the calls in upper case i.e. MSR_START(idMunge); then you get
|
||||
macros which will turn into nothing unless PERF is defined.
|
||||
|
||||
You can reset the statistical counts for a given id by calling Reset(Id).
|
||||
They are reset by default at the start.
|
||||
It logs Reset as a special incident, so you can see it in the log.
|
||||
|
||||
The log is a circular buffer in storage (to try to minimise disk I/O).
|
||||
It overwrites the oldest entries once full. The statistics include ALL
|
||||
incidents since the last Reset, whether still visible in the log or not.
|
||||
*/
|
||||
|
||||
#ifndef __MEASURE__
|
||||
#define __MEASURE__
|
||||
|
||||
#ifdef PERF
|
||||
#define MSR_INIT() Msr_Init()
|
||||
#define MSR_TERMINATE() Msr_Terminate()
|
||||
#define MSR_REGISTER(a) Msr_Register(a)
|
||||
#define MSR_RESET(a) Msr_Reset(a)
|
||||
#define MSR_CONTROL(a) Msr_Control(a)
|
||||
#define MSR_START(a) Msr_Start(a)
|
||||
#define MSR_STOP(a) Msr_Stop(a)
|
||||
#define MSR_NOTE(a) Msr_Note(a)
|
||||
#define MSR_INTEGER(a,b) Msr_Integer(a,b)
|
||||
#define MSR_DUMP(a) Msr_Dump(a)
|
||||
#define MSR_DUMPSTATS(a) Msr_DumpStats(a)
|
||||
#else
|
||||
#define MSR_INIT() ((void)0)
|
||||
#define MSR_TERMINATE() ((void)0)
|
||||
#define MSR_REGISTER(a) 0
|
||||
#define MSR_RESET(a) ((void)0)
|
||||
#define MSR_CONTROL(a) ((void)0)
|
||||
#define MSR_START(a) ((void)0)
|
||||
#define MSR_STOP(a) ((void)0)
|
||||
#define MSR_NOTE(a) ((void)0)
|
||||
#define MSR_INTEGER(a,b) ((void)0)
|
||||
#define MSR_DUMP(a) ((void)0)
|
||||
#define MSR_DUMPSTATS(a) ((void)0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This must be called first - (called by the DllEntry)
|
||||
|
||||
void WINAPI Msr_Init(void);
|
||||
|
||||
|
||||
// Call this last to clean up (or just let it fall off the end - who cares?)
|
||||
|
||||
void WINAPI Msr_Terminate(void);
|
||||
|
||||
|
||||
// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note
|
||||
// everything that's logged is called an "incident".
|
||||
|
||||
int WINAPI Msr_Register(LPTSTR Incident);
|
||||
|
||||
|
||||
// Reset the statistical counts for an incident
|
||||
|
||||
void WINAPI Msr_Reset(int Id);
|
||||
|
||||
|
||||
// Reset all the counts for all incidents
|
||||
#define MSR_RESET_ALL 0
|
||||
#define MSR_PAUSE 1
|
||||
#define MSR_RUN 2
|
||||
|
||||
void WINAPI Msr_Control(int iAction);
|
||||
|
||||
|
||||
// log the start of an operation
|
||||
|
||||
void WINAPI Msr_Start(int Id);
|
||||
|
||||
|
||||
// log the end of an operation
|
||||
|
||||
void WINAPI Msr_Stop(int Id);
|
||||
|
||||
|
||||
// log a one-off or repetitive operation
|
||||
|
||||
void WINAPI Msr_Note(int Id);
|
||||
|
||||
|
||||
// log an integer (on which we can see statistics later)
|
||||
void WINAPI Msr_Integer(int Id, int n);
|
||||
|
||||
|
||||
// print out all the vaialable log (it may have wrapped) and then the statistics.
|
||||
// When the log wraps you lose log but the statistics are still complete.
|
||||
// hFIle==NULL => use DbgLog
|
||||
// otherwise hFile must have come from CreateFile or OpenFile.
|
||||
|
||||
void WINAPI Msr_Dump(HANDLE hFile);
|
||||
|
||||
|
||||
// just dump the statistics - never mind the log
|
||||
|
||||
void WINAPI Msr_DumpStats(HANDLE hFile);
|
||||
|
||||
// Type definitions in case you want to declare a pointer to the dump functions
|
||||
// (makes it a trifle easier to do dynamic linking
|
||||
// i.e. LoadModule, GetProcAddress and call that)
|
||||
|
||||
// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever
|
||||
typedef void WINAPI MSR_DUMPPROC(HANDLE hFile);
|
||||
typedef void WINAPI MSR_CONTROLPROC(int iAction);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __MEASURE__
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Measure.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/*
|
||||
The idea is to pepper the source code with interesting measurements and
|
||||
have the last few thousand of these recorded in a circular buffer that
|
||||
can be post-processed to give interesting numbers.
|
||||
|
||||
WHAT THE LOG LOOKS LIKE:
|
||||
|
||||
Time (sec) Type Delta Incident_Name
|
||||
0.055,41 NOTE -. Incident Nine - Another note
|
||||
0.055,42 NOTE 0.000,01 Incident Nine - Another note
|
||||
0.055,44 NOTE 0.000,02 Incident Nine - Another note
|
||||
0.055,45 STOP -. Incident Eight - Also random
|
||||
0.055,47 START -. Incident Seven - Random
|
||||
0.055,49 NOTE 0.000,05 Incident Nine - Another note
|
||||
------- <etc. there is a lot of this> ----------------
|
||||
0.125,60 STOP 0.000,03 Msr_Stop
|
||||
0.125,62 START -. Msr_Start
|
||||
0.125,63 START -. Incident Two - Start/Stop
|
||||
0.125,65 STOP 0.000,03 Msr_Start
|
||||
0.125,66 START -. Msr_Stop
|
||||
0.125,68 STOP 0.000,05 Incident Two - Start/Stop
|
||||
0.125,70 STOP 0.000,04 Msr_Stop
|
||||
0.125,72 START -. Msr_Start
|
||||
0.125,73 START -. Incident Two - Start/Stop
|
||||
0.125,75 STOP 0.000,03 Msr_Start
|
||||
0.125,77 START -. Msr_Stop
|
||||
0.125,78 STOP 0.000,05 Incident Two - Start/Stop
|
||||
0.125,80 STOP 0.000,03 Msr_Stop
|
||||
0.125,81 NOTE -. Incident Three - single Note
|
||||
0.125,83 START -. Incident Four - Start, no stop
|
||||
0.125,85 START -. Incident Five - Single Start/Stop
|
||||
0.125,87 STOP 0.000,02 Incident Five - Single Start/Stop
|
||||
|
||||
Number Average StdDev Smallest Largest Incident_Name
|
||||
10 0.000,58 0.000,10 0.000,55 0.000,85 Incident One - Note
|
||||
50 0.000,05 0.000,00 0.000,05 0.000,05 Incident Two - Start/Stop
|
||||
1 -. -. -. -. Incident Three - single Note
|
||||
0 -. -. -. -. Incident Four - Start, no stop
|
||||
1 0.000,02 -. 0.000,02 0.000,02 Incident Five - Single Start/Stop
|
||||
0 -. -. -. -. Incident Six - zero occurrences
|
||||
100 0.000,25 0.000,12 0.000,02 0.000,62 Incident Seven - Random
|
||||
100 0.000,79 0.000,48 0.000,02 0.001,92 Incident Eight - Also random
|
||||
5895 0.000,01 0.000,01 0.000,01 0.000,56 Incident Nine - Another note
|
||||
10 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Note
|
||||
50 0.000,03 0.000,00 0.000,03 0.000,04 Msr_Start
|
||||
50 0.000,04 0.000,03 0.000,03 0.000,31 Msr_Stop
|
||||
|
||||
WHAT IT MEANS:
|
||||
The log shows what happened and when. Each line shows the time at which
|
||||
something happened (see WHAT YOU CODE below) what it was that happened
|
||||
and (if approporate) the time since the corresponding previous event
|
||||
(that's the delta column).
|
||||
|
||||
The statistics show how many times each event occurred, what the average
|
||||
delta time was, also the standard deviation, largest and smalles delta.
|
||||
|
||||
WHAT YOU CODE:
|
||||
|
||||
Before anything else executes: - register your ids
|
||||
|
||||
int id1 = Msr_Register("Incident One - Note");
|
||||
int id2 = Msr_Register("Incident Two - Start/Stop");
|
||||
int id3 = Msr_Register("Incident Three - single Note");
|
||||
etc.
|
||||
|
||||
At interesting moments:
|
||||
|
||||
// To measure a repetitive event - e.g. end of bitblt to screen
|
||||
Msr_Note(Id9); // e.g. "video frame hiting the screen NOW!"
|
||||
|
||||
or
|
||||
|
||||
// To measure an elapsed time e.g. time taken to decode an MPEG B-frame
|
||||
Msr_Start(Id2); // e.g. "Starting to decode MPEG B-frame"
|
||||
. . .
|
||||
MsrStop(Id2); // "Finished MPEG decode"
|
||||
|
||||
At the end:
|
||||
|
||||
HANDLE hFile;
|
||||
hFile = CreateFile("Perf.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
Msr_Dump(hFile); // This writes the log out to the file
|
||||
CloseHandle(hFile);
|
||||
|
||||
or
|
||||
|
||||
Msr_Dump(NULL); // This writes it to DbgLog((LOG_TRACE,0, ... ));
|
||||
// but if you are writing it out to the debugger
|
||||
// then the times are probably all garbage because
|
||||
// the debugger can make things run awfully slow.
|
||||
|
||||
A given id should be used either for start / stop or Note calls. If Notes
|
||||
are mixed in with Starts and Stops their statistics will be gibberish.
|
||||
|
||||
If you code the calls in upper case i.e. MSR_START(idMunge); then you get
|
||||
macros which will turn into nothing unless PERF is defined.
|
||||
|
||||
You can reset the statistical counts for a given id by calling Reset(Id).
|
||||
They are reset by default at the start.
|
||||
It logs Reset as a special incident, so you can see it in the log.
|
||||
|
||||
The log is a circular buffer in storage (to try to minimise disk I/O).
|
||||
It overwrites the oldest entries once full. The statistics include ALL
|
||||
incidents since the last Reset, whether still visible in the log or not.
|
||||
*/
|
||||
|
||||
#ifndef __MEASURE__
|
||||
#define __MEASURE__
|
||||
|
||||
#ifdef PERF
|
||||
#define MSR_INIT() Msr_Init()
|
||||
#define MSR_TERMINATE() Msr_Terminate()
|
||||
#define MSR_REGISTER(a) Msr_Register(a)
|
||||
#define MSR_RESET(a) Msr_Reset(a)
|
||||
#define MSR_CONTROL(a) Msr_Control(a)
|
||||
#define MSR_START(a) Msr_Start(a)
|
||||
#define MSR_STOP(a) Msr_Stop(a)
|
||||
#define MSR_NOTE(a) Msr_Note(a)
|
||||
#define MSR_INTEGER(a,b) Msr_Integer(a,b)
|
||||
#define MSR_DUMP(a) Msr_Dump(a)
|
||||
#define MSR_DUMPSTATS(a) Msr_DumpStats(a)
|
||||
#else
|
||||
#define MSR_INIT() ((void)0)
|
||||
#define MSR_TERMINATE() ((void)0)
|
||||
#define MSR_REGISTER(a) 0
|
||||
#define MSR_RESET(a) ((void)0)
|
||||
#define MSR_CONTROL(a) ((void)0)
|
||||
#define MSR_START(a) ((void)0)
|
||||
#define MSR_STOP(a) ((void)0)
|
||||
#define MSR_NOTE(a) ((void)0)
|
||||
#define MSR_INTEGER(a,b) ((void)0)
|
||||
#define MSR_DUMP(a) ((void)0)
|
||||
#define MSR_DUMPSTATS(a) ((void)0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This must be called first - (called by the DllEntry)
|
||||
|
||||
void WINAPI Msr_Init(void);
|
||||
|
||||
|
||||
// Call this last to clean up (or just let it fall off the end - who cares?)
|
||||
|
||||
void WINAPI Msr_Terminate(void);
|
||||
|
||||
|
||||
// Call this to get an Id for an "incident" that you can pass to Start, Stop or Note
|
||||
// everything that's logged is called an "incident".
|
||||
|
||||
int WINAPI Msr_Register(LPTSTR Incident);
|
||||
|
||||
|
||||
// Reset the statistical counts for an incident
|
||||
|
||||
void WINAPI Msr_Reset(int Id);
|
||||
|
||||
|
||||
// Reset all the counts for all incidents
|
||||
#define MSR_RESET_ALL 0
|
||||
#define MSR_PAUSE 1
|
||||
#define MSR_RUN 2
|
||||
|
||||
void WINAPI Msr_Control(int iAction);
|
||||
|
||||
|
||||
// log the start of an operation
|
||||
|
||||
void WINAPI Msr_Start(int Id);
|
||||
|
||||
|
||||
// log the end of an operation
|
||||
|
||||
void WINAPI Msr_Stop(int Id);
|
||||
|
||||
|
||||
// log a one-off or repetitive operation
|
||||
|
||||
void WINAPI Msr_Note(int Id);
|
||||
|
||||
|
||||
// log an integer (on which we can see statistics later)
|
||||
void WINAPI Msr_Integer(int Id, int n);
|
||||
|
||||
|
||||
// print out all the vaialable log (it may have wrapped) and then the statistics.
|
||||
// When the log wraps you lose log but the statistics are still complete.
|
||||
// hFIle==NULL => use DbgLog
|
||||
// otherwise hFile must have come from CreateFile or OpenFile.
|
||||
|
||||
void WINAPI Msr_Dump(HANDLE hFile);
|
||||
|
||||
|
||||
// just dump the statistics - never mind the log
|
||||
|
||||
void WINAPI Msr_DumpStats(HANDLE hFile);
|
||||
|
||||
// Type definitions in case you want to declare a pointer to the dump functions
|
||||
// (makes it a trifle easier to do dynamic linking
|
||||
// i.e. LoadModule, GetProcAddress and call that)
|
||||
|
||||
// Typedefs so can declare MSR_DUMPPROC *MsrDumpStats; or whatever
|
||||
typedef void WINAPI MSR_DUMPPROC(HANDLE hFile);
|
||||
typedef void WINAPI MSR_CONTROLPROC(int iAction);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __MEASURE__
|
||||
|
||||
+120
-120
@@ -1,120 +1,120 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MsgThrd.h
|
||||
//
|
||||
// Desc: DirectShow base classes - provides support for a worker thread
|
||||
// class to which one can asynchronously post messages.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Message class - really just a structure.
|
||||
//
|
||||
class CMsg {
|
||||
public:
|
||||
UINT uMsg;
|
||||
DWORD dwFlags;
|
||||
LPVOID lpParam;
|
||||
CAMEvent *pEvent;
|
||||
|
||||
CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt)
|
||||
: uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {}
|
||||
|
||||
CMsg()
|
||||
: uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {}
|
||||
};
|
||||
|
||||
// This is the actual thread class. It exports all the usual thread control
|
||||
// functions. The created thread is different from a normal WIN32 thread in
|
||||
// that it is prompted to perform particaular tasks by responding to messages
|
||||
// posted to its message queue.
|
||||
//
|
||||
class AM_NOVTABLE CMsgThread {
|
||||
private:
|
||||
static DWORD WINAPI DefaultThreadProc(LPVOID lpParam);
|
||||
DWORD m_ThreadId;
|
||||
HANDLE m_hThread;
|
||||
|
||||
protected:
|
||||
|
||||
// if you want to override GetThreadMsg to block on other things
|
||||
// as well as this queue, you need access to this
|
||||
CGenericList<CMsg> m_ThreadQueue;
|
||||
CCritSec m_Lock;
|
||||
HANDLE m_hSem;
|
||||
LONG m_lWaiting;
|
||||
|
||||
public:
|
||||
CMsgThread()
|
||||
: m_ThreadId(0),
|
||||
m_hThread(NULL),
|
||||
m_lWaiting(0),
|
||||
m_hSem(NULL),
|
||||
// make a list with a cache of 5 items
|
||||
m_ThreadQueue(NAME("MsgThread list"), 5)
|
||||
{
|
||||
}
|
||||
|
||||
~CMsgThread();
|
||||
// override this if you want to block on other things as well
|
||||
// as the message loop
|
||||
void virtual GetThreadMsg(CMsg *msg);
|
||||
|
||||
// override this if you want to do something on thread startup
|
||||
virtual void OnThreadInit() { };
|
||||
|
||||
BOOL CreateThread();
|
||||
|
||||
BOOL WaitForThreadExit(LPDWORD lpdwExitCode) {
|
||||
if (m_hThread != NULL) {
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
return GetExitCodeThread(m_hThread, lpdwExitCode);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD ResumeThread() {
|
||||
return ::ResumeThread(m_hThread);
|
||||
}
|
||||
|
||||
DWORD SuspendThread() {
|
||||
return ::SuspendThread(m_hThread);
|
||||
}
|
||||
|
||||
int GetThreadPriority() {
|
||||
return ::GetThreadPriority(m_hThread);
|
||||
}
|
||||
|
||||
BOOL SetThreadPriority(int nPriority) {
|
||||
return ::SetThreadPriority(m_hThread, nPriority);
|
||||
}
|
||||
|
||||
HANDLE GetThreadHandle() {
|
||||
return m_hThread;
|
||||
}
|
||||
|
||||
DWORD GetThreadId() {
|
||||
return m_ThreadId;
|
||||
}
|
||||
|
||||
|
||||
void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags,
|
||||
LPVOID lpMsgParam, CAMEvent *pEvent = NULL) {
|
||||
CAutoLock lck(&m_Lock);
|
||||
CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent);
|
||||
m_ThreadQueue.AddTail(pMsg);
|
||||
|
||||
if (m_lWaiting != 0) {
|
||||
ReleaseSemaphore(m_hSem, m_lWaiting, 0);
|
||||
m_lWaiting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This is the function prototype of the function that the client
|
||||
// supplies. It is always called on the created thread, never on
|
||||
// the creator thread.
|
||||
//
|
||||
virtual LRESULT ThreadMessageProc(
|
||||
UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MsgThrd.h
|
||||
//
|
||||
// Desc: DirectShow base classes - provides support for a worker thread
|
||||
// class to which one can asynchronously post messages.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Message class - really just a structure.
|
||||
//
|
||||
class CMsg {
|
||||
public:
|
||||
UINT uMsg;
|
||||
DWORD dwFlags;
|
||||
LPVOID lpParam;
|
||||
CAMEvent *pEvent;
|
||||
|
||||
CMsg(UINT u, DWORD dw, LPVOID lp, CAMEvent *pEvnt)
|
||||
: uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {}
|
||||
|
||||
CMsg()
|
||||
: uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {}
|
||||
};
|
||||
|
||||
// This is the actual thread class. It exports all the usual thread control
|
||||
// functions. The created thread is different from a normal WIN32 thread in
|
||||
// that it is prompted to perform particaular tasks by responding to messages
|
||||
// posted to its message queue.
|
||||
//
|
||||
class AM_NOVTABLE CMsgThread {
|
||||
private:
|
||||
static DWORD WINAPI DefaultThreadProc(LPVOID lpParam);
|
||||
DWORD m_ThreadId;
|
||||
HANDLE m_hThread;
|
||||
|
||||
protected:
|
||||
|
||||
// if you want to override GetThreadMsg to block on other things
|
||||
// as well as this queue, you need access to this
|
||||
CGenericList<CMsg> m_ThreadQueue;
|
||||
CCritSec m_Lock;
|
||||
HANDLE m_hSem;
|
||||
LONG m_lWaiting;
|
||||
|
||||
public:
|
||||
CMsgThread()
|
||||
: m_ThreadId(0),
|
||||
m_hThread(NULL),
|
||||
m_lWaiting(0),
|
||||
m_hSem(NULL),
|
||||
// make a list with a cache of 5 items
|
||||
m_ThreadQueue(NAME("MsgThread list"), 5)
|
||||
{
|
||||
}
|
||||
|
||||
~CMsgThread();
|
||||
// override this if you want to block on other things as well
|
||||
// as the message loop
|
||||
void virtual GetThreadMsg(CMsg *msg);
|
||||
|
||||
// override this if you want to do something on thread startup
|
||||
virtual void OnThreadInit() { };
|
||||
|
||||
BOOL CreateThread();
|
||||
|
||||
BOOL WaitForThreadExit(LPDWORD lpdwExitCode) {
|
||||
if (m_hThread != NULL) {
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
return GetExitCodeThread(m_hThread, lpdwExitCode);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD ResumeThread() {
|
||||
return ::ResumeThread(m_hThread);
|
||||
}
|
||||
|
||||
DWORD SuspendThread() {
|
||||
return ::SuspendThread(m_hThread);
|
||||
}
|
||||
|
||||
int GetThreadPriority() {
|
||||
return ::GetThreadPriority(m_hThread);
|
||||
}
|
||||
|
||||
BOOL SetThreadPriority(int nPriority) {
|
||||
return ::SetThreadPriority(m_hThread, nPriority);
|
||||
}
|
||||
|
||||
HANDLE GetThreadHandle() {
|
||||
return m_hThread;
|
||||
}
|
||||
|
||||
DWORD GetThreadId() {
|
||||
return m_ThreadId;
|
||||
}
|
||||
|
||||
|
||||
void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags,
|
||||
LPVOID lpMsgParam, CAMEvent *pEvent = NULL) {
|
||||
CAutoLock lck(&m_Lock);
|
||||
CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent);
|
||||
m_ThreadQueue.AddTail(pMsg);
|
||||
|
||||
if (m_lWaiting != 0) {
|
||||
ReleaseSemaphore(m_hSem, m_lWaiting, 0);
|
||||
m_lWaiting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This is the function prototype of the function that the client
|
||||
// supplies. It is always called on the created thread, never on
|
||||
// the creator thread.
|
||||
//
|
||||
virtual LRESULT ThreadMessageProc(
|
||||
UINT uMsg, DWORD dwFlags, LPVOID lpParam, CAMEvent *pEvent) = 0;
|
||||
};
|
||||
|
||||
|
||||
+478
-478
@@ -1,478 +1,478 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MType.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements a class that holds and
|
||||
// manages media type information.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// helper class that derived pin objects can use to compare media
|
||||
// types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
||||
// in the streams IDL file, but also has (non-virtual) functions
|
||||
|
||||
#include <streams.h>
|
||||
#include <mmreg.h>
|
||||
|
||||
CMediaType::~CMediaType(){
|
||||
FreeMediaType(*this);
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType()
|
||||
{
|
||||
InitMediaType();
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType(const GUID * type)
|
||||
{
|
||||
InitMediaType();
|
||||
majortype = *type;
|
||||
}
|
||||
|
||||
|
||||
// copy constructor does a deep copy of the format block
|
||||
|
||||
CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, HRESULT* phr)
|
||||
{
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr) && (NULL != phr)) {
|
||||
*phr = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType(const CMediaType& rt, HRESULT* phr)
|
||||
{
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr) && (NULL != phr)) {
|
||||
*phr = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate
|
||||
// the following assignment operator itself, however it could introduce some
|
||||
// memory conflicts and leaks in the process because the structure contains
|
||||
// a dynamically allocated block (pbFormat) which it will not copy correctly
|
||||
|
||||
CMediaType&
|
||||
CMediaType::operator=(const AM_MEDIA_TYPE& rt)
|
||||
{
|
||||
Set(rt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CMediaType&
|
||||
CMediaType::operator=(const CMediaType& rt)
|
||||
{
|
||||
*this = (AM_MEDIA_TYPE &) rt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::operator == (const CMediaType& rt) const
|
||||
{
|
||||
// I don't believe we need to check sample size or
|
||||
// temporal compression flags, since I think these must
|
||||
// be represented in the type, subtype and format somehow. They
|
||||
// are pulled out as separate flags so that people who don't understand
|
||||
// the particular format representation can still see them, but
|
||||
// they should duplicate information in the format block.
|
||||
|
||||
return ((IsEqualGUID(majortype,rt.majortype) == TRUE) &&
|
||||
(IsEqualGUID(subtype,rt.subtype) == TRUE) &&
|
||||
(IsEqualGUID(formattype,rt.formattype) == TRUE) &&
|
||||
(cbFormat == rt.cbFormat) &&
|
||||
( (cbFormat == 0) ||
|
||||
(memcmp(pbFormat, rt.pbFormat, cbFormat) == 0)));
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMediaType::operator != (const CMediaType& rt) const
|
||||
{
|
||||
/* Check to see if they are equal */
|
||||
|
||||
if (*this == rt) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CMediaType::Set(const CMediaType& rt)
|
||||
{
|
||||
return Set((AM_MEDIA_TYPE &) rt);
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CMediaType::Set(const AM_MEDIA_TYPE& rt)
|
||||
{
|
||||
if (&rt != this) {
|
||||
FreeMediaType(*this);
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr)) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMediaType::IsValid() const
|
||||
{
|
||||
return (!IsEqualGUID(majortype,GUID_NULL));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetType(const GUID* ptype)
|
||||
{
|
||||
majortype = *ptype;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetSubtype(const GUID* ptype)
|
||||
{
|
||||
subtype = *ptype;
|
||||
}
|
||||
|
||||
|
||||
ULONG
|
||||
CMediaType::GetSampleSize() const {
|
||||
if (IsFixedSize()) {
|
||||
return lSampleSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetSampleSize(ULONG sz) {
|
||||
if (sz == 0) {
|
||||
SetVariableSize();
|
||||
} else {
|
||||
bFixedSizeSamples = TRUE;
|
||||
lSampleSize = sz;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetVariableSize() {
|
||||
bFixedSizeSamples = FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetTemporalCompression(BOOL bCompressed) {
|
||||
bTemporalCompression = bCompressed;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::SetFormat(BYTE * pformat, ULONG cb)
|
||||
{
|
||||
if (NULL == AllocFormatBuffer(cb))
|
||||
return(FALSE);
|
||||
|
||||
ASSERT(pbFormat);
|
||||
memcpy(pbFormat, pformat, cb);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// set the type of the media type format block, this type defines what you
|
||||
// will actually find in the format pointer. For example FORMAT_VideoInfo or
|
||||
// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a
|
||||
// property set. Before sending out media types this should be filled in.
|
||||
|
||||
void
|
||||
CMediaType::SetFormatType(const GUID *pformattype)
|
||||
{
|
||||
formattype = *pformattype;
|
||||
}
|
||||
|
||||
|
||||
// reset the format buffer
|
||||
|
||||
void CMediaType::ResetFormatBuffer()
|
||||
{
|
||||
if (cbFormat) {
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
cbFormat = 0;
|
||||
pbFormat = NULL;
|
||||
}
|
||||
|
||||
|
||||
// allocate length bytes for the format and return a read/write pointer
|
||||
// If we cannot allocate the new block of memory we return NULL leaving
|
||||
// the original block of memory untouched (as does ReallocFormatBuffer)
|
||||
|
||||
BYTE*
|
||||
CMediaType::AllocFormatBuffer(ULONG length)
|
||||
{
|
||||
ASSERT(length);
|
||||
|
||||
// do the types have the same buffer size
|
||||
|
||||
if (cbFormat == length) {
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
// allocate the new format buffer
|
||||
|
||||
BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
||||
if (pNewFormat == NULL) {
|
||||
if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// delete the old format
|
||||
|
||||
if (cbFormat != 0) {
|
||||
ASSERT(pbFormat);
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
|
||||
cbFormat = length;
|
||||
pbFormat = pNewFormat;
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
|
||||
// reallocate length bytes for the format and return a read/write pointer
|
||||
// to it. We keep as much information as we can given the new buffer size
|
||||
// if this fails the original format buffer is left untouched. The caller
|
||||
// is responsible for ensuring the size of memory required is non zero
|
||||
|
||||
BYTE*
|
||||
CMediaType::ReallocFormatBuffer(ULONG length)
|
||||
{
|
||||
ASSERT(length);
|
||||
|
||||
// do the types have the same buffer size
|
||||
|
||||
if (cbFormat == length) {
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
// allocate the new format buffer
|
||||
|
||||
BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
||||
if (pNewFormat == NULL) {
|
||||
if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// copy any previous format (or part of if new is smaller)
|
||||
// delete the old format and replace with the new one
|
||||
|
||||
if (cbFormat != 0) {
|
||||
ASSERT(pbFormat);
|
||||
memcpy(pNewFormat,pbFormat,min(length,cbFormat));
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
|
||||
cbFormat = length;
|
||||
pbFormat = pNewFormat;
|
||||
return pNewFormat;
|
||||
}
|
||||
|
||||
// initialise a media type structure
|
||||
|
||||
void CMediaType::InitMediaType()
|
||||
{
|
||||
ZeroMemory((PVOID)this, sizeof(*this));
|
||||
lSampleSize = 1;
|
||||
bFixedSizeSamples = TRUE;
|
||||
}
|
||||
|
||||
|
||||
// a partially specified media type can be passed to IPin::Connect
|
||||
// as a constraint on the media type used in the connection.
|
||||
// the type, subtype or format type can be null.
|
||||
BOOL
|
||||
CMediaType::IsPartiallySpecified(void) const
|
||||
{
|
||||
if ((majortype == GUID_NULL) ||
|
||||
(formattype == GUID_NULL)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::MatchesPartial(const CMediaType* ppartial) const
|
||||
{
|
||||
if ((ppartial->majortype != GUID_NULL) &&
|
||||
(majortype != ppartial->majortype)) {
|
||||
return FALSE;
|
||||
}
|
||||
if ((ppartial->subtype != GUID_NULL) &&
|
||||
(subtype != ppartial->subtype)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ppartial->formattype != GUID_NULL) {
|
||||
// if the format block is specified then it must match exactly
|
||||
if (formattype != ppartial->formattype) {
|
||||
return FALSE;
|
||||
}
|
||||
if (cbFormat != ppartial->cbFormat) {
|
||||
return FALSE;
|
||||
}
|
||||
if ((cbFormat != 0) &&
|
||||
(memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure
|
||||
// which is useful when calling IEnumMediaTypes::Next as the interface
|
||||
// implementation allocates the structures which you must later delete
|
||||
// the format block may also be a pointer to an interface to release
|
||||
|
||||
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt)
|
||||
{
|
||||
// allow NULL pointers for coding simplicity
|
||||
|
||||
if (pmt == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreeMediaType(*pmt);
|
||||
CoTaskMemFree((PVOID)pmt);
|
||||
}
|
||||
|
||||
|
||||
// this also comes in useful when using the IEnumMediaTypes interface so
|
||||
// that you can copy a media type, you can do nearly the same by creating
|
||||
// a CMediaType object but as soon as it goes out of scope the destructor
|
||||
// will delete the memory it allocated (this takes a copy of the memory)
|
||||
|
||||
AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc)
|
||||
{
|
||||
ASSERT(pSrc);
|
||||
|
||||
// Allocate a block of memory for the media type
|
||||
|
||||
AM_MEDIA_TYPE *pMediaType =
|
||||
(AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
|
||||
|
||||
if (pMediaType == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Copy the variable length format block
|
||||
|
||||
HRESULT hr = CopyMediaType(pMediaType,pSrc);
|
||||
if (FAILED(hr)) {
|
||||
CoTaskMemFree((PVOID)pMediaType);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pMediaType;
|
||||
}
|
||||
|
||||
|
||||
// Copy 1 media type to another
|
||||
|
||||
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource)
|
||||
{
|
||||
// We'll leak if we copy onto one that already exists - there's one
|
||||
// case we can check like that - copying to itself.
|
||||
ASSERT(pmtSource != pmtTarget);
|
||||
*pmtTarget = *pmtSource;
|
||||
if (pmtSource->cbFormat != 0) {
|
||||
ASSERT(pmtSource->pbFormat != NULL);
|
||||
pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat);
|
||||
if (pmtTarget->pbFormat == NULL) {
|
||||
pmtTarget->cbFormat = 0;
|
||||
return E_OUTOFMEMORY;
|
||||
} else {
|
||||
CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
|
||||
pmtTarget->cbFormat);
|
||||
}
|
||||
}
|
||||
if (pmtTarget->pUnk != NULL) {
|
||||
pmtTarget->pUnk->AddRef();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Free an existing media type (ie free resources it holds)
|
||||
|
||||
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt)
|
||||
{
|
||||
if (mt.cbFormat != 0) {
|
||||
CoTaskMemFree((PVOID)mt.pbFormat);
|
||||
|
||||
// Strictly unnecessary but tidier
|
||||
mt.cbFormat = 0;
|
||||
mt.pbFormat = NULL;
|
||||
}
|
||||
if (mt.pUnk != NULL) {
|
||||
mt.pUnk->Release();
|
||||
mt.pUnk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a media type from a WAVEFORMATEX
|
||||
|
||||
STDAPI CreateAudioMediaType(
|
||||
const WAVEFORMATEX *pwfx,
|
||||
AM_MEDIA_TYPE *pmt,
|
||||
BOOL bSetFormat
|
||||
)
|
||||
{
|
||||
pmt->majortype = MEDIATYPE_Audio;
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat;
|
||||
} else {
|
||||
pmt->subtype = FOURCCMap(pwfx->wFormatTag);
|
||||
}
|
||||
|
||||
pmt->formattype = FORMAT_WaveFormatEx;
|
||||
pmt->bFixedSizeSamples = TRUE;
|
||||
pmt->bTemporalCompression = FALSE;
|
||||
pmt->lSampleSize = pwfx->nBlockAlign;
|
||||
pmt->pUnk = NULL;
|
||||
if (bSetFormat) {
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
pmt->cbFormat = sizeof(WAVEFORMATEX);
|
||||
} else {
|
||||
pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize;
|
||||
}
|
||||
pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat);
|
||||
if (pmt->pbFormat == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT));
|
||||
((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0;
|
||||
} else {
|
||||
CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat);
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// eliminate very many spurious warnings from MS compiler
|
||||
#pragma warning(disable:4514)
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MType.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements a class that holds and
|
||||
// manages media type information.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// helper class that derived pin objects can use to compare media
|
||||
// types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
||||
// in the streams IDL file, but also has (non-virtual) functions
|
||||
|
||||
#include <streams.h>
|
||||
#include <mmreg.h>
|
||||
|
||||
CMediaType::~CMediaType(){
|
||||
FreeMediaType(*this);
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType()
|
||||
{
|
||||
InitMediaType();
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType(const GUID * type)
|
||||
{
|
||||
InitMediaType();
|
||||
majortype = *type;
|
||||
}
|
||||
|
||||
|
||||
// copy constructor does a deep copy of the format block
|
||||
|
||||
CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, HRESULT* phr)
|
||||
{
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr) && (NULL != phr)) {
|
||||
*phr = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CMediaType::CMediaType(const CMediaType& rt, HRESULT* phr)
|
||||
{
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr) && (NULL != phr)) {
|
||||
*phr = hr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate
|
||||
// the following assignment operator itself, however it could introduce some
|
||||
// memory conflicts and leaks in the process because the structure contains
|
||||
// a dynamically allocated block (pbFormat) which it will not copy correctly
|
||||
|
||||
CMediaType&
|
||||
CMediaType::operator=(const AM_MEDIA_TYPE& rt)
|
||||
{
|
||||
Set(rt);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CMediaType&
|
||||
CMediaType::operator=(const CMediaType& rt)
|
||||
{
|
||||
*this = (AM_MEDIA_TYPE &) rt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::operator == (const CMediaType& rt) const
|
||||
{
|
||||
// I don't believe we need to check sample size or
|
||||
// temporal compression flags, since I think these must
|
||||
// be represented in the type, subtype and format somehow. They
|
||||
// are pulled out as separate flags so that people who don't understand
|
||||
// the particular format representation can still see them, but
|
||||
// they should duplicate information in the format block.
|
||||
|
||||
return ((IsEqualGUID(majortype,rt.majortype) == TRUE) &&
|
||||
(IsEqualGUID(subtype,rt.subtype) == TRUE) &&
|
||||
(IsEqualGUID(formattype,rt.formattype) == TRUE) &&
|
||||
(cbFormat == rt.cbFormat) &&
|
||||
( (cbFormat == 0) ||
|
||||
(memcmp(pbFormat, rt.pbFormat, cbFormat) == 0)));
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMediaType::operator != (const CMediaType& rt) const
|
||||
{
|
||||
/* Check to see if they are equal */
|
||||
|
||||
if (*this == rt) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CMediaType::Set(const CMediaType& rt)
|
||||
{
|
||||
return Set((AM_MEDIA_TYPE &) rt);
|
||||
}
|
||||
|
||||
|
||||
HRESULT
|
||||
CMediaType::Set(const AM_MEDIA_TYPE& rt)
|
||||
{
|
||||
if (&rt != this) {
|
||||
FreeMediaType(*this);
|
||||
HRESULT hr = CopyMediaType(this, &rt);
|
||||
if (FAILED(hr)) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMediaType::IsValid() const
|
||||
{
|
||||
return (!IsEqualGUID(majortype,GUID_NULL));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetType(const GUID* ptype)
|
||||
{
|
||||
majortype = *ptype;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetSubtype(const GUID* ptype)
|
||||
{
|
||||
subtype = *ptype;
|
||||
}
|
||||
|
||||
|
||||
ULONG
|
||||
CMediaType::GetSampleSize() const {
|
||||
if (IsFixedSize()) {
|
||||
return lSampleSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetSampleSize(ULONG sz) {
|
||||
if (sz == 0) {
|
||||
SetVariableSize();
|
||||
} else {
|
||||
bFixedSizeSamples = TRUE;
|
||||
lSampleSize = sz;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetVariableSize() {
|
||||
bFixedSizeSamples = FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CMediaType::SetTemporalCompression(BOOL bCompressed) {
|
||||
bTemporalCompression = bCompressed;
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::SetFormat(BYTE * pformat, ULONG cb)
|
||||
{
|
||||
if (NULL == AllocFormatBuffer(cb))
|
||||
return(FALSE);
|
||||
|
||||
ASSERT(pbFormat);
|
||||
memcpy(pbFormat, pformat, cb);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
|
||||
// set the type of the media type format block, this type defines what you
|
||||
// will actually find in the format pointer. For example FORMAT_VideoInfo or
|
||||
// FORMAT_WaveFormatEx. In the future this may be an interface pointer to a
|
||||
// property set. Before sending out media types this should be filled in.
|
||||
|
||||
void
|
||||
CMediaType::SetFormatType(const GUID *pformattype)
|
||||
{
|
||||
formattype = *pformattype;
|
||||
}
|
||||
|
||||
|
||||
// reset the format buffer
|
||||
|
||||
void CMediaType::ResetFormatBuffer()
|
||||
{
|
||||
if (cbFormat) {
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
cbFormat = 0;
|
||||
pbFormat = NULL;
|
||||
}
|
||||
|
||||
|
||||
// allocate length bytes for the format and return a read/write pointer
|
||||
// If we cannot allocate the new block of memory we return NULL leaving
|
||||
// the original block of memory untouched (as does ReallocFormatBuffer)
|
||||
|
||||
BYTE*
|
||||
CMediaType::AllocFormatBuffer(ULONG length)
|
||||
{
|
||||
ASSERT(length);
|
||||
|
||||
// do the types have the same buffer size
|
||||
|
||||
if (cbFormat == length) {
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
// allocate the new format buffer
|
||||
|
||||
BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
||||
if (pNewFormat == NULL) {
|
||||
if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// delete the old format
|
||||
|
||||
if (cbFormat != 0) {
|
||||
ASSERT(pbFormat);
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
|
||||
cbFormat = length;
|
||||
pbFormat = pNewFormat;
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
|
||||
// reallocate length bytes for the format and return a read/write pointer
|
||||
// to it. We keep as much information as we can given the new buffer size
|
||||
// if this fails the original format buffer is left untouched. The caller
|
||||
// is responsible for ensuring the size of memory required is non zero
|
||||
|
||||
BYTE*
|
||||
CMediaType::ReallocFormatBuffer(ULONG length)
|
||||
{
|
||||
ASSERT(length);
|
||||
|
||||
// do the types have the same buffer size
|
||||
|
||||
if (cbFormat == length) {
|
||||
return pbFormat;
|
||||
}
|
||||
|
||||
// allocate the new format buffer
|
||||
|
||||
BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
||||
if (pNewFormat == NULL) {
|
||||
if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// copy any previous format (or part of if new is smaller)
|
||||
// delete the old format and replace with the new one
|
||||
|
||||
if (cbFormat != 0) {
|
||||
ASSERT(pbFormat);
|
||||
memcpy(pNewFormat,pbFormat,min(length,cbFormat));
|
||||
CoTaskMemFree((PVOID)pbFormat);
|
||||
}
|
||||
|
||||
cbFormat = length;
|
||||
pbFormat = pNewFormat;
|
||||
return pNewFormat;
|
||||
}
|
||||
|
||||
// initialise a media type structure
|
||||
|
||||
void CMediaType::InitMediaType()
|
||||
{
|
||||
ZeroMemory((PVOID)this, sizeof(*this));
|
||||
lSampleSize = 1;
|
||||
bFixedSizeSamples = TRUE;
|
||||
}
|
||||
|
||||
|
||||
// a partially specified media type can be passed to IPin::Connect
|
||||
// as a constraint on the media type used in the connection.
|
||||
// the type, subtype or format type can be null.
|
||||
BOOL
|
||||
CMediaType::IsPartiallySpecified(void) const
|
||||
{
|
||||
if ((majortype == GUID_NULL) ||
|
||||
(formattype == GUID_NULL)) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMediaType::MatchesPartial(const CMediaType* ppartial) const
|
||||
{
|
||||
if ((ppartial->majortype != GUID_NULL) &&
|
||||
(majortype != ppartial->majortype)) {
|
||||
return FALSE;
|
||||
}
|
||||
if ((ppartial->subtype != GUID_NULL) &&
|
||||
(subtype != ppartial->subtype)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ppartial->formattype != GUID_NULL) {
|
||||
// if the format block is specified then it must match exactly
|
||||
if (formattype != ppartial->formattype) {
|
||||
return FALSE;
|
||||
}
|
||||
if (cbFormat != ppartial->cbFormat) {
|
||||
return FALSE;
|
||||
}
|
||||
if ((cbFormat != 0) &&
|
||||
(memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// general purpose function to delete a heap allocated AM_MEDIA_TYPE structure
|
||||
// which is useful when calling IEnumMediaTypes::Next as the interface
|
||||
// implementation allocates the structures which you must later delete
|
||||
// the format block may also be a pointer to an interface to release
|
||||
|
||||
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt)
|
||||
{
|
||||
// allow NULL pointers for coding simplicity
|
||||
|
||||
if (pmt == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreeMediaType(*pmt);
|
||||
CoTaskMemFree((PVOID)pmt);
|
||||
}
|
||||
|
||||
|
||||
// this also comes in useful when using the IEnumMediaTypes interface so
|
||||
// that you can copy a media type, you can do nearly the same by creating
|
||||
// a CMediaType object but as soon as it goes out of scope the destructor
|
||||
// will delete the memory it allocated (this takes a copy of the memory)
|
||||
|
||||
AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc)
|
||||
{
|
||||
ASSERT(pSrc);
|
||||
|
||||
// Allocate a block of memory for the media type
|
||||
|
||||
AM_MEDIA_TYPE *pMediaType =
|
||||
(AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
|
||||
|
||||
if (pMediaType == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// Copy the variable length format block
|
||||
|
||||
HRESULT hr = CopyMediaType(pMediaType,pSrc);
|
||||
if (FAILED(hr)) {
|
||||
CoTaskMemFree((PVOID)pMediaType);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pMediaType;
|
||||
}
|
||||
|
||||
|
||||
// Copy 1 media type to another
|
||||
|
||||
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource)
|
||||
{
|
||||
// We'll leak if we copy onto one that already exists - there's one
|
||||
// case we can check like that - copying to itself.
|
||||
ASSERT(pmtSource != pmtTarget);
|
||||
*pmtTarget = *pmtSource;
|
||||
if (pmtSource->cbFormat != 0) {
|
||||
ASSERT(pmtSource->pbFormat != NULL);
|
||||
pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat);
|
||||
if (pmtTarget->pbFormat == NULL) {
|
||||
pmtTarget->cbFormat = 0;
|
||||
return E_OUTOFMEMORY;
|
||||
} else {
|
||||
CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
|
||||
pmtTarget->cbFormat);
|
||||
}
|
||||
}
|
||||
if (pmtTarget->pUnk != NULL) {
|
||||
pmtTarget->pUnk->AddRef();
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Free an existing media type (ie free resources it holds)
|
||||
|
||||
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt)
|
||||
{
|
||||
if (mt.cbFormat != 0) {
|
||||
CoTaskMemFree((PVOID)mt.pbFormat);
|
||||
|
||||
// Strictly unnecessary but tidier
|
||||
mt.cbFormat = 0;
|
||||
mt.pbFormat = NULL;
|
||||
}
|
||||
if (mt.pUnk != NULL) {
|
||||
mt.pUnk->Release();
|
||||
mt.pUnk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a media type from a WAVEFORMATEX
|
||||
|
||||
STDAPI CreateAudioMediaType(
|
||||
const WAVEFORMATEX *pwfx,
|
||||
AM_MEDIA_TYPE *pmt,
|
||||
BOOL bSetFormat
|
||||
)
|
||||
{
|
||||
pmt->majortype = MEDIATYPE_Audio;
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat;
|
||||
} else {
|
||||
pmt->subtype = FOURCCMap(pwfx->wFormatTag);
|
||||
}
|
||||
|
||||
pmt->formattype = FORMAT_WaveFormatEx;
|
||||
pmt->bFixedSizeSamples = TRUE;
|
||||
pmt->bTemporalCompression = FALSE;
|
||||
pmt->lSampleSize = pwfx->nBlockAlign;
|
||||
pmt->pUnk = NULL;
|
||||
if (bSetFormat) {
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
pmt->cbFormat = sizeof(WAVEFORMATEX);
|
||||
} else {
|
||||
pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize;
|
||||
}
|
||||
pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat);
|
||||
if (pmt->pbFormat == NULL) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
||||
CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT));
|
||||
((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0;
|
||||
} else {
|
||||
CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat);
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// eliminate very many spurious warnings from MS compiler
|
||||
#pragma warning(disable:4514)
|
||||
|
||||
+89
-89
@@ -1,89 +1,89 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MtType.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class that holds and manages
|
||||
// media type information.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __MTYPE__
|
||||
#define __MTYPE__
|
||||
|
||||
/* Helper class that derived pin objects can use to compare media
|
||||
types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
||||
in the streams IDL file, but also has (non-virtual) functions */
|
||||
|
||||
class CMediaType : public _AMMediaType {
|
||||
|
||||
public:
|
||||
|
||||
~CMediaType();
|
||||
CMediaType();
|
||||
CMediaType(const GUID * majortype);
|
||||
CMediaType(const AM_MEDIA_TYPE&, HRESULT* phr = NULL);
|
||||
CMediaType(const CMediaType&, HRESULT* phr = NULL);
|
||||
|
||||
CMediaType& operator=(const CMediaType&);
|
||||
CMediaType& operator=(const AM_MEDIA_TYPE&);
|
||||
|
||||
BOOL operator == (const CMediaType&) const;
|
||||
BOOL operator != (const CMediaType&) const;
|
||||
|
||||
HRESULT Set(const CMediaType& rt);
|
||||
HRESULT Set(const AM_MEDIA_TYPE& rt);
|
||||
|
||||
BOOL IsValid() const;
|
||||
|
||||
const GUID *Type() const { return &majortype;} ;
|
||||
void SetType(const GUID *);
|
||||
const GUID *Subtype() const { return &subtype;} ;
|
||||
void SetSubtype(const GUID *);
|
||||
|
||||
BOOL IsFixedSize() const {return bFixedSizeSamples; };
|
||||
BOOL IsTemporalCompressed() const {return bTemporalCompression; };
|
||||
ULONG GetSampleSize() const;
|
||||
|
||||
void SetSampleSize(ULONG sz);
|
||||
void SetVariableSize();
|
||||
void SetTemporalCompression(BOOL bCompressed);
|
||||
|
||||
// read/write pointer to format - can't change length without
|
||||
// calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer
|
||||
|
||||
BYTE* Format() const {return pbFormat; };
|
||||
ULONG FormatLength() const { return cbFormat; };
|
||||
|
||||
void SetFormatType(const GUID *);
|
||||
const GUID *FormatType() const {return &formattype; };
|
||||
BOOL SetFormat(BYTE *pFormat, ULONG length);
|
||||
void ResetFormatBuffer();
|
||||
BYTE* AllocFormatBuffer(ULONG length);
|
||||
BYTE* ReallocFormatBuffer(ULONG length);
|
||||
|
||||
void InitMediaType();
|
||||
|
||||
BOOL MatchesPartial(const CMediaType* ppartial) const;
|
||||
BOOL IsPartiallySpecified(void) const;
|
||||
};
|
||||
|
||||
|
||||
/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE
|
||||
structure which is useful when using the IEnumMediaFormats interface as
|
||||
the implementation allocates the structures which you must later delete */
|
||||
|
||||
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt);
|
||||
AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc);
|
||||
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource);
|
||||
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt);
|
||||
|
||||
// Initialize a media type from a WAVEFORMATEX
|
||||
|
||||
STDAPI CreateAudioMediaType(
|
||||
const WAVEFORMATEX *pwfx,
|
||||
AM_MEDIA_TYPE *pmt,
|
||||
BOOL bSetFormat);
|
||||
|
||||
#endif /* __MTYPE__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: MtType.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class that holds and manages
|
||||
// media type information.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __MTYPE__
|
||||
#define __MTYPE__
|
||||
|
||||
/* Helper class that derived pin objects can use to compare media
|
||||
types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
||||
in the streams IDL file, but also has (non-virtual) functions */
|
||||
|
||||
class CMediaType : public _AMMediaType {
|
||||
|
||||
public:
|
||||
|
||||
~CMediaType();
|
||||
CMediaType();
|
||||
CMediaType(const GUID * majortype);
|
||||
CMediaType(const AM_MEDIA_TYPE&, HRESULT* phr = NULL);
|
||||
CMediaType(const CMediaType&, HRESULT* phr = NULL);
|
||||
|
||||
CMediaType& operator=(const CMediaType&);
|
||||
CMediaType& operator=(const AM_MEDIA_TYPE&);
|
||||
|
||||
BOOL operator == (const CMediaType&) const;
|
||||
BOOL operator != (const CMediaType&) const;
|
||||
|
||||
HRESULT Set(const CMediaType& rt);
|
||||
HRESULT Set(const AM_MEDIA_TYPE& rt);
|
||||
|
||||
BOOL IsValid() const;
|
||||
|
||||
const GUID *Type() const { return &majortype;} ;
|
||||
void SetType(const GUID *);
|
||||
const GUID *Subtype() const { return &subtype;} ;
|
||||
void SetSubtype(const GUID *);
|
||||
|
||||
BOOL IsFixedSize() const {return bFixedSizeSamples; };
|
||||
BOOL IsTemporalCompressed() const {return bTemporalCompression; };
|
||||
ULONG GetSampleSize() const;
|
||||
|
||||
void SetSampleSize(ULONG sz);
|
||||
void SetVariableSize();
|
||||
void SetTemporalCompression(BOOL bCompressed);
|
||||
|
||||
// read/write pointer to format - can't change length without
|
||||
// calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer
|
||||
|
||||
BYTE* Format() const {return pbFormat; };
|
||||
ULONG FormatLength() const { return cbFormat; };
|
||||
|
||||
void SetFormatType(const GUID *);
|
||||
const GUID *FormatType() const {return &formattype; };
|
||||
BOOL SetFormat(BYTE *pFormat, ULONG length);
|
||||
void ResetFormatBuffer();
|
||||
BYTE* AllocFormatBuffer(ULONG length);
|
||||
BYTE* ReallocFormatBuffer(ULONG length);
|
||||
|
||||
void InitMediaType();
|
||||
|
||||
BOOL MatchesPartial(const CMediaType* ppartial) const;
|
||||
BOOL IsPartiallySpecified(void) const;
|
||||
};
|
||||
|
||||
|
||||
/* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE
|
||||
structure which is useful when using the IEnumMediaFormats interface as
|
||||
the implementation allocates the structures which you must later delete */
|
||||
|
||||
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt);
|
||||
AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc);
|
||||
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource);
|
||||
void WINAPI FreeMediaType(AM_MEDIA_TYPE& mt);
|
||||
|
||||
// Initialize a media type from a WAVEFORMATEX
|
||||
|
||||
STDAPI CreateAudioMediaType(
|
||||
const WAVEFORMATEX *pwfx,
|
||||
AM_MEDIA_TYPE *pmt,
|
||||
BOOL bSetFormat);
|
||||
|
||||
#endif /* __MTYPE__ */
|
||||
|
||||
|
||||
+790
-790
File diff suppressed because it is too large
Load Diff
+137
-137
@@ -1,137 +1,137 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: OutputQ.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines the COutputQueue class, which
|
||||
// makes a queue of samples and sends them to an output pin. The
|
||||
// class will optionally send the samples to the pin directly.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef CGenericList<IMediaSample> CSampleList;
|
||||
|
||||
class COutputQueue : public CCritSec
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
COutputQueue(IPin *pInputPin, // Pin to send stuff to
|
||||
HRESULT *phr, // 'Return code'
|
||||
BOOL bAuto = TRUE, // Ask pin if blocks
|
||||
BOOL bQueue = TRUE, // Send through queue (ignored if
|
||||
// bAuto set)
|
||||
LONG lBatchSize = 1, // Batch
|
||||
BOOL bBatchExact = FALSE,// Batch exactly to BatchSize
|
||||
LONG lListSize = // Likely number in the list
|
||||
DEFAULTCACHE,
|
||||
DWORD dwPriority = // Priority of thread to create
|
||||
THREAD_PRIORITY_NORMAL,
|
||||
bool bFlushingOpt = false // flushing optimization
|
||||
);
|
||||
~COutputQueue();
|
||||
|
||||
// enter flush state - discard all data
|
||||
void BeginFlush(); // Begin flushing samples
|
||||
|
||||
// re-enable receives (pass this downstream)
|
||||
void EndFlush(); // Complete flush of samples - downstream
|
||||
// pin guaranteed not to block at this stage
|
||||
|
||||
void EOS(); // Call this on End of stream
|
||||
|
||||
void SendAnyway(); // Send batched samples anyway (if bBatchExact set)
|
||||
|
||||
void NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// do something with these media samples
|
||||
HRESULT ReceiveMultiple (
|
||||
IMediaSample **pSamples,
|
||||
long nSamples,
|
||||
long *nSamplesProcessed);
|
||||
|
||||
void Reset(); // Reset m_hr ready for more data
|
||||
|
||||
// See if its idle or not
|
||||
BOOL IsIdle();
|
||||
|
||||
// give the class an event to fire after everything removed from the queue
|
||||
void SetPopEvent(HANDLE hEvent);
|
||||
|
||||
protected:
|
||||
static DWORD WINAPI InitialThreadProc(LPVOID pv);
|
||||
DWORD ThreadProc();
|
||||
BOOL IsQueued()
|
||||
{
|
||||
return m_List != NULL;
|
||||
}
|
||||
|
||||
// The critical section MUST be held when this is called
|
||||
void QueueSample(IMediaSample *pSample);
|
||||
|
||||
BOOL IsSpecialSample(IMediaSample *pSample)
|
||||
{
|
||||
return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16);
|
||||
}
|
||||
|
||||
// Remove and Release() batched and queued samples
|
||||
void FreeSamples();
|
||||
|
||||
// Notify the thread there is something to do
|
||||
void NotifyThread();
|
||||
|
||||
|
||||
protected:
|
||||
// Queue 'messages'
|
||||
#define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch
|
||||
#define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream
|
||||
#define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr
|
||||
#define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment
|
||||
|
||||
// new segment packet is always followed by one of these
|
||||
struct NewSegmentPacket {
|
||||
REFERENCE_TIME tStart;
|
||||
REFERENCE_TIME tStop;
|
||||
double dRate;
|
||||
};
|
||||
|
||||
// Remember input stuff
|
||||
IPin * const m_pPin;
|
||||
IMemInputPin * m_pInputPin;
|
||||
BOOL const m_bBatchExact;
|
||||
LONG const m_lBatchSize;
|
||||
|
||||
CSampleList * m_List;
|
||||
HANDLE m_hSem;
|
||||
CAMEvent m_evFlushComplete;
|
||||
HANDLE m_hThread;
|
||||
IMediaSample ** m_ppSamples;
|
||||
LONG m_nBatched;
|
||||
|
||||
// Wait optimization
|
||||
LONG m_lWaiting;
|
||||
// Flush synchronization
|
||||
BOOL m_bFlushing;
|
||||
|
||||
// flushing optimization. some downstream filters have trouble
|
||||
// with the queue's flushing optimization. other rely on it
|
||||
BOOL m_bFlushed;
|
||||
bool m_bFlushingOpt;
|
||||
|
||||
// Terminate now
|
||||
BOOL m_bTerminate;
|
||||
|
||||
// Send anyway flag for batching
|
||||
BOOL m_bSendAnyway;
|
||||
|
||||
// Deferred 'return code'
|
||||
BOOL volatile m_hr;
|
||||
|
||||
// an event that can be fired after every deliver
|
||||
HANDLE m_hEventPop;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: OutputQ.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines the COutputQueue class, which
|
||||
// makes a queue of samples and sends them to an output pin. The
|
||||
// class will optionally send the samples to the pin directly.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef CGenericList<IMediaSample> CSampleList;
|
||||
|
||||
class COutputQueue : public CCritSec
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
COutputQueue(IPin *pInputPin, // Pin to send stuff to
|
||||
HRESULT *phr, // 'Return code'
|
||||
BOOL bAuto = TRUE, // Ask pin if blocks
|
||||
BOOL bQueue = TRUE, // Send through queue (ignored if
|
||||
// bAuto set)
|
||||
LONG lBatchSize = 1, // Batch
|
||||
BOOL bBatchExact = FALSE,// Batch exactly to BatchSize
|
||||
LONG lListSize = // Likely number in the list
|
||||
DEFAULTCACHE,
|
||||
DWORD dwPriority = // Priority of thread to create
|
||||
THREAD_PRIORITY_NORMAL,
|
||||
bool bFlushingOpt = false // flushing optimization
|
||||
);
|
||||
~COutputQueue();
|
||||
|
||||
// enter flush state - discard all data
|
||||
void BeginFlush(); // Begin flushing samples
|
||||
|
||||
// re-enable receives (pass this downstream)
|
||||
void EndFlush(); // Complete flush of samples - downstream
|
||||
// pin guaranteed not to block at this stage
|
||||
|
||||
void EOS(); // Call this on End of stream
|
||||
|
||||
void SendAnyway(); // Send batched samples anyway (if bBatchExact set)
|
||||
|
||||
void NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// do something with these media samples
|
||||
HRESULT ReceiveMultiple (
|
||||
IMediaSample **pSamples,
|
||||
long nSamples,
|
||||
long *nSamplesProcessed);
|
||||
|
||||
void Reset(); // Reset m_hr ready for more data
|
||||
|
||||
// See if its idle or not
|
||||
BOOL IsIdle();
|
||||
|
||||
// give the class an event to fire after everything removed from the queue
|
||||
void SetPopEvent(HANDLE hEvent);
|
||||
|
||||
protected:
|
||||
static DWORD WINAPI InitialThreadProc(LPVOID pv);
|
||||
DWORD ThreadProc();
|
||||
BOOL IsQueued()
|
||||
{
|
||||
return m_List != NULL;
|
||||
}
|
||||
|
||||
// The critical section MUST be held when this is called
|
||||
void QueueSample(IMediaSample *pSample);
|
||||
|
||||
BOOL IsSpecialSample(IMediaSample *pSample)
|
||||
{
|
||||
return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16);
|
||||
}
|
||||
|
||||
// Remove and Release() batched and queued samples
|
||||
void FreeSamples();
|
||||
|
||||
// Notify the thread there is something to do
|
||||
void NotifyThread();
|
||||
|
||||
|
||||
protected:
|
||||
// Queue 'messages'
|
||||
#define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch
|
||||
#define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream
|
||||
#define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr
|
||||
#define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment
|
||||
|
||||
// new segment packet is always followed by one of these
|
||||
struct NewSegmentPacket {
|
||||
REFERENCE_TIME tStart;
|
||||
REFERENCE_TIME tStop;
|
||||
double dRate;
|
||||
};
|
||||
|
||||
// Remember input stuff
|
||||
IPin * const m_pPin;
|
||||
IMemInputPin * m_pInputPin;
|
||||
BOOL const m_bBatchExact;
|
||||
LONG const m_lBatchSize;
|
||||
|
||||
CSampleList * m_List;
|
||||
HANDLE m_hSem;
|
||||
CAMEvent m_evFlushComplete;
|
||||
HANDLE m_hThread;
|
||||
IMediaSample ** m_ppSamples;
|
||||
LONG m_nBatched;
|
||||
|
||||
// Wait optimization
|
||||
LONG m_lWaiting;
|
||||
// Flush synchronization
|
||||
BOOL m_bFlushing;
|
||||
|
||||
// flushing optimization. some downstream filters have trouble
|
||||
// with the queue's flushing optimization. other rely on it
|
||||
BOOL m_bFlushed;
|
||||
bool m_bFlushingOpt;
|
||||
|
||||
// Terminate now
|
||||
BOOL m_bTerminate;
|
||||
|
||||
// Send anyway flag for batching
|
||||
BOOL m_bSendAnyway;
|
||||
|
||||
// Deferred 'return code'
|
||||
BOOL volatile m_hr;
|
||||
|
||||
// an event that can be fired after every deliver
|
||||
HANDLE m_hEventPop;
|
||||
};
|
||||
|
||||
|
||||
+196
-196
@@ -1,196 +1,196 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PStream.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#ifdef PERF
|
||||
#include <measure.h>
|
||||
#endif
|
||||
// #include "pstream.h" in streams.h
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
CPersistStream::CPersistStream(IUnknown *punk, HRESULT *phr)
|
||||
: mPS_fDirty(FALSE)
|
||||
{
|
||||
mPS_dwFileVersion = GetSoftwareVersion();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Destructor
|
||||
//
|
||||
CPersistStream::~CPersistStream() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
#if 0
|
||||
SAMPLE CODE TO COPY - not active at the moment
|
||||
|
||||
//
|
||||
// NonDelegatingQueryInterface
|
||||
//
|
||||
// This object supports IPersist & IPersistStream
|
||||
STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
if (riid == IID_IPersist) {
|
||||
return GetInterface((IPersist *) this, ppv); // ???
|
||||
}
|
||||
else if (riid == IID_IPersistStream) {
|
||||
return GetInterface((IPersistStream *) this, ppv);
|
||||
}
|
||||
else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// WriteToStream
|
||||
//
|
||||
// Writes to the stream (default action is to write nothing)
|
||||
HRESULT CPersistStream::WriteToStream(IStream *pStream)
|
||||
{
|
||||
// You can override this to do things like
|
||||
// hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL);
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CPersistStream::ReadFromStream(IStream * pStream)
|
||||
{
|
||||
// You can override this to do things like
|
||||
// hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL);
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Load
|
||||
//
|
||||
// Load all the data from the given stream
|
||||
STDMETHODIMP CPersistStream::Load(LPSTREAM pStm)
|
||||
{
|
||||
HRESULT hr;
|
||||
// Load the version number then the data
|
||||
mPS_dwFileVersion = ReadInt(pStm, hr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ReadFromStream(pStm);
|
||||
} // Load
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Save
|
||||
//
|
||||
// Save the contents of this Stream.
|
||||
STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty)
|
||||
{
|
||||
|
||||
HRESULT hr = WriteInt(pStm, GetSoftwareVersion());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = WriteToStream(pStm);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
mPS_fDirty = !fClearDirty;
|
||||
|
||||
return hr;
|
||||
} // Save
|
||||
|
||||
|
||||
// WriteInt
|
||||
//
|
||||
// Writes an integer to an IStream as 11 UNICODE characters followed by one space.
|
||||
// You could use this for shorts or unsigneds or anything (up to 32 bits)
|
||||
// where the value isn't actually truncated by squeezing it into 32 bits.
|
||||
// Values such as (unsigned) 0x80000000 would come out as -2147483648
|
||||
// but would then load as 0x80000000 through ReadInt. Cast as you please.
|
||||
|
||||
STDAPI WriteInt(IStream *pIStream, int n)
|
||||
{
|
||||
WCHAR Buff[13]; // Allows for trailing null that we don't write
|
||||
wsprintfW(Buff, L"%011d ",n);
|
||||
return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL);
|
||||
} // WriteInt
|
||||
|
||||
|
||||
// ReadInt
|
||||
//
|
||||
// Reads an integer from an IStream.
|
||||
// Read as 4 bytes. You could use this for shorts or unsigneds or anything
|
||||
// where the value isn't actually truncated by squeezing it into 32 bits
|
||||
// Striped down subset of what sscanf can do (without dragging in the C runtime)
|
||||
|
||||
STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr)
|
||||
{
|
||||
|
||||
int Sign = 1;
|
||||
unsigned int n = 0; // result wil be n*Sign
|
||||
WCHAR wch;
|
||||
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wch==L'-'){
|
||||
Sign = -1;
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for( ; ; ) {
|
||||
if (wch>=L'0' && wch<=L'9') {
|
||||
n = 10*n+(int)(wch-L'0');
|
||||
} else if ( wch == L' '
|
||||
|| wch == L'\t'
|
||||
|| wch == L'\r'
|
||||
|| wch == L'\n'
|
||||
|| wch == L'\0'
|
||||
) {
|
||||
break;
|
||||
} else {
|
||||
hr = VFW_E_INVALID_FILE_FORMAT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n==0x80000000 && Sign==-1) {
|
||||
// This is the negative number that has no positive version!
|
||||
return (int)n;
|
||||
}
|
||||
else return (int)n * Sign;
|
||||
} // ReadInt
|
||||
|
||||
|
||||
// The microsoft C/C++ compile generates level 4 warnings to the effect that
|
||||
// a particular inline function (from some base class) was not needed.
|
||||
// This line gets rid of hundreds of such unwanted messages and makes
|
||||
// -W4 compilation feasible:
|
||||
#pragma warning(disable: 4514)
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PStream.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#ifdef PERF
|
||||
#include <measure.h>
|
||||
#endif
|
||||
// #include "pstream.h" in streams.h
|
||||
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
CPersistStream::CPersistStream(IUnknown *punk, HRESULT *phr)
|
||||
: mPS_fDirty(FALSE)
|
||||
{
|
||||
mPS_dwFileVersion = GetSoftwareVersion();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Destructor
|
||||
//
|
||||
CPersistStream::~CPersistStream() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
#if 0
|
||||
SAMPLE CODE TO COPY - not active at the moment
|
||||
|
||||
//
|
||||
// NonDelegatingQueryInterface
|
||||
//
|
||||
// This object supports IPersist & IPersistStream
|
||||
STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, void **ppv)
|
||||
{
|
||||
if (riid == IID_IPersist) {
|
||||
return GetInterface((IPersist *) this, ppv); // ???
|
||||
}
|
||||
else if (riid == IID_IPersistStream) {
|
||||
return GetInterface((IPersistStream *) this, ppv);
|
||||
}
|
||||
else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// WriteToStream
|
||||
//
|
||||
// Writes to the stream (default action is to write nothing)
|
||||
HRESULT CPersistStream::WriteToStream(IStream *pStream)
|
||||
{
|
||||
// You can override this to do things like
|
||||
// hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL);
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CPersistStream::ReadFromStream(IStream * pStream)
|
||||
{
|
||||
// You can override this to do things like
|
||||
// hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL);
|
||||
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Load
|
||||
//
|
||||
// Load all the data from the given stream
|
||||
STDMETHODIMP CPersistStream::Load(LPSTREAM pStm)
|
||||
{
|
||||
HRESULT hr;
|
||||
// Load the version number then the data
|
||||
mPS_dwFileVersion = ReadInt(pStm, hr);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ReadFromStream(pStm);
|
||||
} // Load
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Save
|
||||
//
|
||||
// Save the contents of this Stream.
|
||||
STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty)
|
||||
{
|
||||
|
||||
HRESULT hr = WriteInt(pStm, GetSoftwareVersion());
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = WriteToStream(pStm);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
mPS_fDirty = !fClearDirty;
|
||||
|
||||
return hr;
|
||||
} // Save
|
||||
|
||||
|
||||
// WriteInt
|
||||
//
|
||||
// Writes an integer to an IStream as 11 UNICODE characters followed by one space.
|
||||
// You could use this for shorts or unsigneds or anything (up to 32 bits)
|
||||
// where the value isn't actually truncated by squeezing it into 32 bits.
|
||||
// Values such as (unsigned) 0x80000000 would come out as -2147483648
|
||||
// but would then load as 0x80000000 through ReadInt. Cast as you please.
|
||||
|
||||
STDAPI WriteInt(IStream *pIStream, int n)
|
||||
{
|
||||
WCHAR Buff[13]; // Allows for trailing null that we don't write
|
||||
wsprintfW(Buff, L"%011d ",n);
|
||||
return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL);
|
||||
} // WriteInt
|
||||
|
||||
|
||||
// ReadInt
|
||||
//
|
||||
// Reads an integer from an IStream.
|
||||
// Read as 4 bytes. You could use this for shorts or unsigneds or anything
|
||||
// where the value isn't actually truncated by squeezing it into 32 bits
|
||||
// Striped down subset of what sscanf can do (without dragging in the C runtime)
|
||||
|
||||
STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr)
|
||||
{
|
||||
|
||||
int Sign = 1;
|
||||
unsigned int n = 0; // result wil be n*Sign
|
||||
WCHAR wch;
|
||||
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wch==L'-'){
|
||||
Sign = -1;
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for( ; ; ) {
|
||||
if (wch>=L'0' && wch<=L'9') {
|
||||
n = 10*n+(int)(wch-L'0');
|
||||
} else if ( wch == L' '
|
||||
|| wch == L'\t'
|
||||
|| wch == L'\r'
|
||||
|| wch == L'\n'
|
||||
|| wch == L'\0'
|
||||
) {
|
||||
break;
|
||||
} else {
|
||||
hr = VFW_E_INVALID_FILE_FORMAT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hr = pIStream->Read( &wch, sizeof(wch), NULL);
|
||||
if (FAILED(hr)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n==0x80000000 && Sign==-1) {
|
||||
// This is the negative number that has no positive version!
|
||||
return (int)n;
|
||||
}
|
||||
else return (int)n * Sign;
|
||||
} // ReadInt
|
||||
|
||||
|
||||
// The microsoft C/C++ compile generates level 4 warnings to the effect that
|
||||
// a particular inline function (from some base class) was not needed.
|
||||
// This line gets rid of hundreds of such unwanted messages and makes
|
||||
// -W4 compilation feasible:
|
||||
#pragma warning(disable: 4514)
|
||||
|
||||
+114
-114
@@ -1,114 +1,114 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PStream.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class for persistent properties
|
||||
// of filters.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __PSTREAM__
|
||||
#define __PSTREAM__
|
||||
|
||||
// Base class for persistent properties of filters
|
||||
// (i.e. filter properties in saved graphs)
|
||||
|
||||
// The simplest way to use this is:
|
||||
// 1. Arrange for your filter to inherit this class
|
||||
// 2. Implement in your class WriteToStream and ReadFromStream
|
||||
// These will override the "do nothing" functions here.
|
||||
// 3. Change your NonDelegatingQueryInterface to handle IPersistStream
|
||||
// 4. Implement SizeMax to return the number of bytes of data you save.
|
||||
// If you save UNICODE data, don't forget a char is 2 bytes.
|
||||
// 5. Whenever your data changes, call SetDirty()
|
||||
//
|
||||
// At some point you may decide to alter, or extend the format of your data.
|
||||
// At that point you will wish that you had a version number in all the old
|
||||
// saved graphs, so that you can tell, when you read them, whether they
|
||||
// represent the old or new form. To assist you in this, this class
|
||||
// writes and reads a version number.
|
||||
// When it writes, it calls GetSoftwareVersion() to enquire what version
|
||||
// of the software we have at the moment. (In effect this is a version number
|
||||
// of the data layout in the file). It writes this as the first thing in the data.
|
||||
// If you want to change the version, implement (override) GetSoftwareVersion().
|
||||
// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream,
|
||||
// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading
|
||||
// an old version file.
|
||||
// Normally you should accept files whose version is no newer than the software
|
||||
// version that's reading them.
|
||||
|
||||
|
||||
// CPersistStream
|
||||
//
|
||||
// Implements IPersistStream.
|
||||
// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for
|
||||
// more implementation information.
|
||||
class CPersistStream : public IPersistStream {
|
||||
private:
|
||||
|
||||
// Internal state:
|
||||
|
||||
protected:
|
||||
DWORD mPS_dwFileVersion; // version number of file (being read)
|
||||
BOOL mPS_fDirty;
|
||||
|
||||
public:
|
||||
|
||||
// IPersistStream methods
|
||||
|
||||
STDMETHODIMP IsDirty()
|
||||
{return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean
|
||||
STDMETHODIMP Load(LPSTREAM pStm);
|
||||
STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty);
|
||||
STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize)
|
||||
// Allow 24 bytes for version.
|
||||
{ pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; }
|
||||
|
||||
// implementation
|
||||
|
||||
CPersistStream(IUnknown *punk, HRESULT *phr);
|
||||
~CPersistStream();
|
||||
|
||||
HRESULT SetDirty(BOOL fDirty)
|
||||
{ mPS_fDirty = fDirty; return NOERROR;}
|
||||
|
||||
|
||||
// override to reveal IPersist & IPersistStream
|
||||
// STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
|
||||
|
||||
// --- IPersist ---
|
||||
|
||||
// You must override this to provide your own class id
|
||||
STDMETHODIMP GetClassID(CLSID *pClsid) PURE;
|
||||
|
||||
// overrideable if you want
|
||||
// file version number. Override it if you ever change format
|
||||
virtual DWORD GetSoftwareVersion(void) { return 0; }
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// OVERRIDE THESE to read and write your data
|
||||
// OVERRIDE THESE to read and write your data
|
||||
// OVERRIDE THESE to read and write your data
|
||||
|
||||
virtual int SizeMax() {return 0;}
|
||||
virtual HRESULT WriteToStream(IStream *pStream);
|
||||
virtual HRESULT ReadFromStream(IStream *pStream);
|
||||
//=========================================================================
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
// --- Useful helpers ---
|
||||
|
||||
|
||||
// Writes an int to an IStream as UNICODE.
|
||||
STDAPI WriteInt(IStream *pIStream, int n);
|
||||
|
||||
// inverse of WriteInt
|
||||
STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr);
|
||||
|
||||
#endif // __PSTREAM__
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PStream.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a class for persistent properties
|
||||
// of filters.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __PSTREAM__
|
||||
#define __PSTREAM__
|
||||
|
||||
// Base class for persistent properties of filters
|
||||
// (i.e. filter properties in saved graphs)
|
||||
|
||||
// The simplest way to use this is:
|
||||
// 1. Arrange for your filter to inherit this class
|
||||
// 2. Implement in your class WriteToStream and ReadFromStream
|
||||
// These will override the "do nothing" functions here.
|
||||
// 3. Change your NonDelegatingQueryInterface to handle IPersistStream
|
||||
// 4. Implement SizeMax to return the number of bytes of data you save.
|
||||
// If you save UNICODE data, don't forget a char is 2 bytes.
|
||||
// 5. Whenever your data changes, call SetDirty()
|
||||
//
|
||||
// At some point you may decide to alter, or extend the format of your data.
|
||||
// At that point you will wish that you had a version number in all the old
|
||||
// saved graphs, so that you can tell, when you read them, whether they
|
||||
// represent the old or new form. To assist you in this, this class
|
||||
// writes and reads a version number.
|
||||
// When it writes, it calls GetSoftwareVersion() to enquire what version
|
||||
// of the software we have at the moment. (In effect this is a version number
|
||||
// of the data layout in the file). It writes this as the first thing in the data.
|
||||
// If you want to change the version, implement (override) GetSoftwareVersion().
|
||||
// It reads this from the file into mPS_dwFileVersion before calling ReadFromStream,
|
||||
// so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading
|
||||
// an old version file.
|
||||
// Normally you should accept files whose version is no newer than the software
|
||||
// version that's reading them.
|
||||
|
||||
|
||||
// CPersistStream
|
||||
//
|
||||
// Implements IPersistStream.
|
||||
// See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for
|
||||
// more implementation information.
|
||||
class CPersistStream : public IPersistStream {
|
||||
private:
|
||||
|
||||
// Internal state:
|
||||
|
||||
protected:
|
||||
DWORD mPS_dwFileVersion; // version number of file (being read)
|
||||
BOOL mPS_fDirty;
|
||||
|
||||
public:
|
||||
|
||||
// IPersistStream methods
|
||||
|
||||
STDMETHODIMP IsDirty()
|
||||
{return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean
|
||||
STDMETHODIMP Load(LPSTREAM pStm);
|
||||
STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty);
|
||||
STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize)
|
||||
// Allow 24 bytes for version.
|
||||
{ pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; }
|
||||
|
||||
// implementation
|
||||
|
||||
CPersistStream(IUnknown *punk, HRESULT *phr);
|
||||
~CPersistStream();
|
||||
|
||||
HRESULT SetDirty(BOOL fDirty)
|
||||
{ mPS_fDirty = fDirty; return NOERROR;}
|
||||
|
||||
|
||||
// override to reveal IPersist & IPersistStream
|
||||
// STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
|
||||
|
||||
// --- IPersist ---
|
||||
|
||||
// You must override this to provide your own class id
|
||||
STDMETHODIMP GetClassID(CLSID *pClsid) PURE;
|
||||
|
||||
// overrideable if you want
|
||||
// file version number. Override it if you ever change format
|
||||
virtual DWORD GetSoftwareVersion(void) { return 0; }
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// OVERRIDE THESE to read and write your data
|
||||
// OVERRIDE THESE to read and write your data
|
||||
// OVERRIDE THESE to read and write your data
|
||||
|
||||
virtual int SizeMax() {return 0;}
|
||||
virtual HRESULT WriteToStream(IStream *pStream);
|
||||
virtual HRESULT ReadFromStream(IStream *pStream);
|
||||
//=========================================================================
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
// --- Useful helpers ---
|
||||
|
||||
|
||||
// Writes an int to an IStream as UNICODE.
|
||||
STDAPI WriteInt(IStream *pIStream, int n);
|
||||
|
||||
// inverse of WriteInt
|
||||
STDAPI_(int) ReadInt(IStream *pIStream, HRESULT &hr);
|
||||
|
||||
#endif // __PSTREAM__
|
||||
|
||||
+510
-510
File diff suppressed because it is too large
Load Diff
+152
-152
@@ -1,152 +1,152 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PullPin.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines CPullPin class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __PULLPIN_H__
|
||||
#define __PULLPIN_H__
|
||||
|
||||
//
|
||||
// CPullPin
|
||||
//
|
||||
// object supporting pulling data from an IAsyncReader interface.
|
||||
// Given a start/stop position, calls a pure Receive method with each
|
||||
// IMediaSample received.
|
||||
//
|
||||
// This is essentially for use in a MemInputPin when it finds itself
|
||||
// connected to an IAsyncReader pin instead of a pushing pin.
|
||||
//
|
||||
|
||||
class CPullPin : public CAMThread
|
||||
{
|
||||
IAsyncReader* m_pReader;
|
||||
REFERENCE_TIME m_tStart;
|
||||
REFERENCE_TIME m_tStop;
|
||||
REFERENCE_TIME m_tDuration;
|
||||
BOOL m_bSync;
|
||||
|
||||
enum ThreadMsg {
|
||||
TM_Pause, // stop pulling and wait for next message
|
||||
TM_Start, // start pulling
|
||||
TM_Exit, // stop and exit
|
||||
};
|
||||
|
||||
ThreadMsg m_State;
|
||||
|
||||
// override pure thread proc from CAMThread
|
||||
DWORD ThreadProc(void);
|
||||
|
||||
// running pull method (check m_bSync)
|
||||
void Process(void);
|
||||
|
||||
// clean up any cancelled i/o after a flush
|
||||
void CleanupCancelled(void);
|
||||
|
||||
// suspend thread from pulling, eg during seek
|
||||
HRESULT PauseThread();
|
||||
|
||||
// start thread pulling - create thread if necy
|
||||
HRESULT StartThread();
|
||||
|
||||
// stop and close thread
|
||||
HRESULT StopThread();
|
||||
|
||||
// called from ProcessAsync to queue and collect requests
|
||||
HRESULT QueueSample(
|
||||
REFERENCE_TIME& tCurrent,
|
||||
REFERENCE_TIME tAlignStop,
|
||||
BOOL bDiscontinuity);
|
||||
|
||||
HRESULT CollectAndDeliver(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop);
|
||||
|
||||
HRESULT DeliverSample(
|
||||
IMediaSample* pSample,
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop);
|
||||
|
||||
protected:
|
||||
IMemAllocator * m_pAlloc;
|
||||
|
||||
public:
|
||||
CPullPin();
|
||||
virtual ~CPullPin();
|
||||
|
||||
// returns S_OK if successfully connected to an IAsyncReader interface
|
||||
// from this object
|
||||
// Optional allocator should be proposed as a preferred allocator if
|
||||
// necessary
|
||||
// bSync is TRUE if we are to use sync reads instead of the
|
||||
// async methods.
|
||||
HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync);
|
||||
|
||||
// disconnect any connection made in Connect
|
||||
HRESULT Disconnect();
|
||||
|
||||
// agree an allocator using RequestAllocator - optional
|
||||
// props param specifies your requirements (non-zero fields).
|
||||
// returns an error code if fail to match requirements.
|
||||
// optional IMemAllocator interface is offered as a preferred allocator
|
||||
// but no error occurs if it can't be met.
|
||||
virtual HRESULT DecideAllocator(
|
||||
IMemAllocator* pAlloc,
|
||||
ALLOCATOR_PROPERTIES * pProps);
|
||||
|
||||
// set start and stop position. if active, will start immediately at
|
||||
// the new position. Default is 0 to duration
|
||||
HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop);
|
||||
|
||||
// return the total duration
|
||||
HRESULT Duration(REFERENCE_TIME* ptDuration);
|
||||
|
||||
// start pulling data
|
||||
HRESULT Active(void);
|
||||
|
||||
// stop pulling data
|
||||
HRESULT Inactive(void);
|
||||
|
||||
// helper functions
|
||||
LONGLONG AlignDown(LONGLONG ll, LONG lAlign) {
|
||||
// aligning downwards is just truncation
|
||||
return ll & ~(lAlign-1);
|
||||
};
|
||||
|
||||
LONGLONG AlignUp(LONGLONG ll, LONG lAlign) {
|
||||
// align up: round up to next boundary
|
||||
return (ll + (lAlign -1)) & ~(lAlign -1);
|
||||
};
|
||||
|
||||
// GetReader returns the (addrefed) IAsyncReader interface
|
||||
// for SyncRead etc
|
||||
IAsyncReader* GetReader() {
|
||||
m_pReader->AddRef();
|
||||
return m_pReader;
|
||||
};
|
||||
|
||||
// -- pure --
|
||||
|
||||
// override this to handle data arrival
|
||||
// return value other than S_OK will stop data
|
||||
virtual HRESULT Receive(IMediaSample*) PURE;
|
||||
|
||||
// override this to handle end-of-stream
|
||||
virtual HRESULT EndOfStream(void) PURE;
|
||||
|
||||
// called on runtime errors that will have caused pulling
|
||||
// to stop
|
||||
// these errors are all returned from the upstream filter, who
|
||||
// will have already reported any errors to the filtergraph.
|
||||
virtual void OnError(HRESULT hr) PURE;
|
||||
|
||||
// flush this pin and all downstream
|
||||
virtual HRESULT BeginFlush() PURE;
|
||||
virtual HRESULT EndFlush() PURE;
|
||||
|
||||
};
|
||||
|
||||
#endif //__PULLPIN_H__
|
||||
//------------------------------------------------------------------------------
|
||||
// File: PullPin.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines CPullPin class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __PULLPIN_H__
|
||||
#define __PULLPIN_H__
|
||||
|
||||
//
|
||||
// CPullPin
|
||||
//
|
||||
// object supporting pulling data from an IAsyncReader interface.
|
||||
// Given a start/stop position, calls a pure Receive method with each
|
||||
// IMediaSample received.
|
||||
//
|
||||
// This is essentially for use in a MemInputPin when it finds itself
|
||||
// connected to an IAsyncReader pin instead of a pushing pin.
|
||||
//
|
||||
|
||||
class CPullPin : public CAMThread
|
||||
{
|
||||
IAsyncReader* m_pReader;
|
||||
REFERENCE_TIME m_tStart;
|
||||
REFERENCE_TIME m_tStop;
|
||||
REFERENCE_TIME m_tDuration;
|
||||
BOOL m_bSync;
|
||||
|
||||
enum ThreadMsg {
|
||||
TM_Pause, // stop pulling and wait for next message
|
||||
TM_Start, // start pulling
|
||||
TM_Exit, // stop and exit
|
||||
};
|
||||
|
||||
ThreadMsg m_State;
|
||||
|
||||
// override pure thread proc from CAMThread
|
||||
DWORD ThreadProc(void);
|
||||
|
||||
// running pull method (check m_bSync)
|
||||
void Process(void);
|
||||
|
||||
// clean up any cancelled i/o after a flush
|
||||
void CleanupCancelled(void);
|
||||
|
||||
// suspend thread from pulling, eg during seek
|
||||
HRESULT PauseThread();
|
||||
|
||||
// start thread pulling - create thread if necy
|
||||
HRESULT StartThread();
|
||||
|
||||
// stop and close thread
|
||||
HRESULT StopThread();
|
||||
|
||||
// called from ProcessAsync to queue and collect requests
|
||||
HRESULT QueueSample(
|
||||
REFERENCE_TIME& tCurrent,
|
||||
REFERENCE_TIME tAlignStop,
|
||||
BOOL bDiscontinuity);
|
||||
|
||||
HRESULT CollectAndDeliver(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop);
|
||||
|
||||
HRESULT DeliverSample(
|
||||
IMediaSample* pSample,
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop);
|
||||
|
||||
protected:
|
||||
IMemAllocator * m_pAlloc;
|
||||
|
||||
public:
|
||||
CPullPin();
|
||||
virtual ~CPullPin();
|
||||
|
||||
// returns S_OK if successfully connected to an IAsyncReader interface
|
||||
// from this object
|
||||
// Optional allocator should be proposed as a preferred allocator if
|
||||
// necessary
|
||||
// bSync is TRUE if we are to use sync reads instead of the
|
||||
// async methods.
|
||||
HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync);
|
||||
|
||||
// disconnect any connection made in Connect
|
||||
HRESULT Disconnect();
|
||||
|
||||
// agree an allocator using RequestAllocator - optional
|
||||
// props param specifies your requirements (non-zero fields).
|
||||
// returns an error code if fail to match requirements.
|
||||
// optional IMemAllocator interface is offered as a preferred allocator
|
||||
// but no error occurs if it can't be met.
|
||||
virtual HRESULT DecideAllocator(
|
||||
IMemAllocator* pAlloc,
|
||||
ALLOCATOR_PROPERTIES * pProps);
|
||||
|
||||
// set start and stop position. if active, will start immediately at
|
||||
// the new position. Default is 0 to duration
|
||||
HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop);
|
||||
|
||||
// return the total duration
|
||||
HRESULT Duration(REFERENCE_TIME* ptDuration);
|
||||
|
||||
// start pulling data
|
||||
HRESULT Active(void);
|
||||
|
||||
// stop pulling data
|
||||
HRESULT Inactive(void);
|
||||
|
||||
// helper functions
|
||||
LONGLONG AlignDown(LONGLONG ll, LONG lAlign) {
|
||||
// aligning downwards is just truncation
|
||||
return ll & ~(lAlign-1);
|
||||
};
|
||||
|
||||
LONGLONG AlignUp(LONGLONG ll, LONG lAlign) {
|
||||
// align up: round up to next boundary
|
||||
return (ll + (lAlign -1)) & ~(lAlign -1);
|
||||
};
|
||||
|
||||
// GetReader returns the (addrefed) IAsyncReader interface
|
||||
// for SyncRead etc
|
||||
IAsyncReader* GetReader() {
|
||||
m_pReader->AddRef();
|
||||
return m_pReader;
|
||||
};
|
||||
|
||||
// -- pure --
|
||||
|
||||
// override this to handle data arrival
|
||||
// return value other than S_OK will stop data
|
||||
virtual HRESULT Receive(IMediaSample*) PURE;
|
||||
|
||||
// override this to handle end-of-stream
|
||||
virtual HRESULT EndOfStream(void) PURE;
|
||||
|
||||
// called on runtime errors that will have caused pulling
|
||||
// to stop
|
||||
// these errors are all returned from the upstream filter, who
|
||||
// will have already reported any errors to the filtergraph.
|
||||
virtual void OnError(HRESULT hr) PURE;
|
||||
|
||||
// flush this pin and all downstream
|
||||
virtual HRESULT BeginFlush() PURE;
|
||||
virtual HRESULT EndFlush() PURE;
|
||||
|
||||
};
|
||||
|
||||
#endif //__PULLPIN_H__
|
||||
|
||||
+25
-25
@@ -1,25 +1,25 @@
|
||||
DirectShow Sample -- Base Classes
|
||||
---------------------------------
|
||||
|
||||
The Microsoft DirectShow base classes are a set of C++ classes
|
||||
and utility functions that you can use to implement DirectShow filters.
|
||||
For complete documentation of the base classes, see "DirectShow Base Classes"
|
||||
in the DirectShow Reference section of the DirectX SDK documentation.
|
||||
|
||||
NOTE: The BaseClasses header file schedule.h has been renamed to dsschedule.h
|
||||
to prevent conflicts with the Platform SDK <schedule.h>. Only the refclock.h
|
||||
header in the BaseClasses directory uses this header, so the impact should
|
||||
be minimal.
|
||||
|
||||
Building for Windows XP
|
||||
-----------------------
|
||||
If you want to target Windows XP specifically to use its new features,
|
||||
you must set WINVER=0x501 in the BaseClasses project file. You must also
|
||||
install the Windows XP Platform SDK, however, to ensure that you have the
|
||||
latest header files. For example, wxutil.cpp uses the new TIME_KILL_SYNCHRONOUS flag
|
||||
only if (WINVER >= 0x501). This flag is conditionally defined in the Windows XP
|
||||
Platform SDK in mmsystem.h, but only if WINVER is also set to 0x501 when compiling.
|
||||
|
||||
#if (WINVER >= 0x501)
|
||||
#define TIME_KILL_SYNCHRONOUS 0x0100
|
||||
#endif
|
||||
DirectShow Sample -- Base Classes
|
||||
---------------------------------
|
||||
|
||||
The Microsoft DirectShow base classes are a set of C++ classes
|
||||
and utility functions that you can use to implement DirectShow filters.
|
||||
For complete documentation of the base classes, see "DirectShow Base Classes"
|
||||
in the DirectShow Reference section of the DirectX SDK documentation.
|
||||
|
||||
NOTE: The BaseClasses header file schedule.h has been renamed to dsschedule.h
|
||||
to prevent conflicts with the Platform SDK <schedule.h>. Only the refclock.h
|
||||
header in the BaseClasses directory uses this header, so the impact should
|
||||
be minimal.
|
||||
|
||||
Building for Windows XP
|
||||
-----------------------
|
||||
If you want to target Windows XP specifically to use its new features,
|
||||
you must set WINVER=0x501 in the BaseClasses project file. You must also
|
||||
install the Windows XP Platform SDK, however, to ensure that you have the
|
||||
latest header files. For example, wxutil.cpp uses the new TIME_KILL_SYNCHRONOUS flag
|
||||
only if (WINVER >= 0x501). This flag is conditionally defined in the Windows XP
|
||||
Platform SDK in mmsystem.h, but only if WINVER is also set to 0x501 when compiling.
|
||||
|
||||
#if (WINVER >= 0x501)
|
||||
#define TIME_KILL_SYNCHRONOUS 0x0100
|
||||
#endif
|
||||
|
||||
+308
-308
@@ -1,308 +1,308 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefClock.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements the IReferenceClock interface.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
|
||||
// 'this' used in constructor list
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface(
|
||||
REFIID riid,
|
||||
void ** ppv) {
|
||||
HRESULT hr;
|
||||
|
||||
if(riid == IID_IReferenceClock) {
|
||||
hr = GetInterface((IReferenceClock *) this, ppv);
|
||||
}
|
||||
else {
|
||||
hr = CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
CBaseReferenceClock::~CBaseReferenceClock() {
|
||||
|
||||
if(m_TimerResolution) timeEndPeriod(m_TimerResolution);
|
||||
|
||||
m_pSchedule->DumpLinkedList();
|
||||
|
||||
if(m_hThread) {
|
||||
m_bAbort = TRUE;
|
||||
TriggerThread();
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
EXECUTE_ASSERT(CloseHandle(m_hThread));
|
||||
m_hThread = 0;
|
||||
EXECUTE_ASSERT(CloseHandle(m_pSchedule->GetEvent()));
|
||||
delete m_pSchedule;
|
||||
}
|
||||
}
|
||||
|
||||
// A derived class may supply a hThreadEvent if it has its own thread that will take care
|
||||
// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread()
|
||||
// to see what such a thread has to do.)
|
||||
CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed )
|
||||
: CUnknown( pName, pUnk )
|
||||
, m_rtLastGotTime(0)
|
||||
, m_TimerResolution(0)
|
||||
, m_bAbort( FALSE )
|
||||
, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) )
|
||||
, m_hThread(0) {
|
||||
|
||||
|
||||
ASSERT(m_pSchedule);
|
||||
if(!m_pSchedule) {
|
||||
*phr = E_OUTOFMEMORY;
|
||||
}
|
||||
else {
|
||||
// Set up the highest resolution timer we can manage
|
||||
TIMECAPS tc;
|
||||
m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc)))
|
||||
? tc.wPeriodMin : 1;
|
||||
|
||||
timeBeginPeriod(m_TimerResolution);
|
||||
|
||||
/* Initialise our system times - the derived clock should set the right values */
|
||||
m_dwPrevSystemTime = timeGetTime();
|
||||
m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime;
|
||||
|
||||
#ifdef PERF
|
||||
m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime"));
|
||||
#endif
|
||||
|
||||
if(!pShed) {
|
||||
DWORD ThreadID;
|
||||
m_hThread = ::CreateThread(NULL, // Security attributes
|
||||
(DWORD) 0, // Initial stack size
|
||||
AdviseThreadFunction, // Thread start address
|
||||
(LPVOID) this, // Thread parameter
|
||||
(DWORD) 0, // Creation flags
|
||||
&ThreadID); // Thread identifier
|
||||
|
||||
if(m_hThread) {
|
||||
SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
else {
|
||||
*phr = E_FAIL;
|
||||
EXECUTE_ASSERT(CloseHandle(m_pSchedule->GetEvent()));
|
||||
delete m_pSchedule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::GetTime(REFERENCE_TIME *pTime) {
|
||||
HRESULT hr;
|
||||
if(pTime) {
|
||||
REFERENCE_TIME rtNow;
|
||||
Lock();
|
||||
rtNow = GetPrivateTime();
|
||||
if(rtNow > m_rtLastGotTime) {
|
||||
m_rtLastGotTime = rtNow;
|
||||
hr = S_OK;
|
||||
}
|
||||
else {
|
||||
hr = S_FALSE;
|
||||
}
|
||||
|
||||
*pTime = m_rtLastGotTime;
|
||||
Unlock();
|
||||
MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)));
|
||||
}
|
||||
else hr = E_POINTER;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Ask for an async notification that a time has elapsed */
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::AdviseTime(
|
||||
REFERENCE_TIME baseTime, // base reference time
|
||||
REFERENCE_TIME streamTime, // stream offset time
|
||||
HEVENT hEvent, // advise via this event
|
||||
DWORD_PTR *pdwAdviseCookie) // where your cookie goes
|
||||
{
|
||||
CheckPointer(pdwAdviseCookie, E_POINTER);
|
||||
*pdwAdviseCookie = 0;
|
||||
|
||||
// Check that the event is not already set
|
||||
ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0));
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
const REFERENCE_TIME lRefTime = baseTime + streamTime;
|
||||
if(lRefTime <= 0 || lRefTime == MAX_TIME) {
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else {
|
||||
*pdwAdviseCookie = m_pSchedule->AddAdvisePacket(lRefTime, 0, HANDLE(hEvent), FALSE);
|
||||
hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
/* Ask for an asynchronous periodic notification that a time has elapsed */
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::AdvisePeriodic(
|
||||
REFERENCE_TIME StartTime, // starting at this time
|
||||
REFERENCE_TIME PeriodTime, // time between notifications
|
||||
HSEMAPHORE hSemaphore, // advise via a semaphore
|
||||
DWORD_PTR *pdwAdviseCookie) // where your cookie goes
|
||||
{
|
||||
CheckPointer(pdwAdviseCookie, E_POINTER);
|
||||
*pdwAdviseCookie = 0;
|
||||
|
||||
HRESULT hr;
|
||||
if(StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME) {
|
||||
*pdwAdviseCookie = m_pSchedule->AddAdvisePacket(StartTime, PeriodTime, HANDLE(hSemaphore), TRUE);
|
||||
hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
|
||||
}
|
||||
else hr = E_INVALIDARG;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) {
|
||||
return m_pSchedule->Unadvise(dwAdviseCookie);
|
||||
}
|
||||
|
||||
|
||||
REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() {
|
||||
CAutoLock cObjectLock(this);
|
||||
|
||||
|
||||
/* If the clock has wrapped then the current time will be less than
|
||||
* the last time we were notified so add on the extra milliseconds
|
||||
*
|
||||
* The time period is long enough so that the likelihood of
|
||||
* successive calls spanning the clock cycle is not considered.
|
||||
*/
|
||||
|
||||
DWORD dwTime = timeGetTime(); {
|
||||
m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime));
|
||||
m_dwPrevSystemTime = dwTime;
|
||||
}
|
||||
|
||||
return m_rtPrivateTime;
|
||||
}
|
||||
|
||||
|
||||
/* Adjust the current time by the input value. This allows an
|
||||
external time source to work out some of the latency of the clock
|
||||
system and adjust the "current" time accordingly. The intent is
|
||||
that the time returned to the user is synchronised to a clock
|
||||
source and allows drift to be catered for.
|
||||
|
||||
For example: if the clock source detects a drift it can pass a delta
|
||||
to the current time rather than having to set an explicit time.
|
||||
*/
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) {
|
||||
#ifdef DEBUG
|
||||
|
||||
// Just break if passed an improper time delta value
|
||||
LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta;
|
||||
if(llDelta > UNITS * 1000) {
|
||||
DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta")));
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
// We're going to calculate a "severity" for the time change. Max -1
|
||||
// min 8. We'll then use this as the debug logging level for a
|
||||
// debug log message.
|
||||
const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs
|
||||
|
||||
DWORD delta = abs(usDelta); // varying delta
|
||||
// Severity == 8 - ceil(log<base 8>(abs( micro-secs delta)))
|
||||
int Severity = 8;
|
||||
while(delta > 0) {
|
||||
delta >>= 3; // div 8
|
||||
Severity--;
|
||||
}
|
||||
|
||||
// Sev == 0 => > 2 second delta!
|
||||
DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity,
|
||||
TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."),
|
||||
Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)),
|
||||
DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) ));
|
||||
|
||||
// Don't want the DbgBreak to fire when running stress on debug-builds.
|
||||
#ifdef BREAK_ON_SEVERE_TIME_DELTA
|
||||
if(Severity < 0)
|
||||
DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"),
|
||||
TEXT(__FILE__),__LINE__);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
CAutoLock cObjectLock(this);
|
||||
m_rtPrivateTime += TimeDelta;
|
||||
// If time goes forwards, and we have advises, then we need to
|
||||
// trigger the thread so that it can re-evaluate its wait time.
|
||||
// Since we don't want the cost of the thread switches if the change
|
||||
// is really small, only do it if clock goes forward by more than
|
||||
// 0.5 millisecond. If the time goes backwards, the thread will
|
||||
// wake up "early" (relativly speaking) and will re-evaluate at
|
||||
// that time.
|
||||
if(TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0) TriggerThread();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Thread stuff
|
||||
|
||||
DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(LPVOID p) {
|
||||
return DWORD(reinterpret_cast<CBaseReferenceClock*>(p)->AdviseThread());
|
||||
}
|
||||
|
||||
HRESULT CBaseReferenceClock::AdviseThread() {
|
||||
DWORD dwWait = INFINITE;
|
||||
|
||||
// The first thing we do is wait until something interesting happens
|
||||
// (meaning a first advise or shutdown). This prevents us calling
|
||||
// GetPrivateTime immediately which is goodness as that is a virtual
|
||||
// routine and the derived class may not yet be constructed. (This
|
||||
// thread is created in the base class constructor.)
|
||||
|
||||
while(!m_bAbort) {
|
||||
// Wait for an interesting event to happen
|
||||
DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait ));
|
||||
WaitForSingleObject(m_pSchedule->GetEvent(), dwWait);
|
||||
if(m_bAbort) break;
|
||||
|
||||
// There are several reasons why we need to work from the internal
|
||||
// time, mainly to do with what happens when time goes backwards.
|
||||
// Mainly, it stop us looping madly if an event is just about to
|
||||
// expire when the clock goes backward (i.e. GetTime stop for a
|
||||
// while).
|
||||
const REFERENCE_TIME rtNow = GetPrivateTime();
|
||||
|
||||
DbgLog((LOG_TIMING, 3,
|
||||
TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"),
|
||||
ConvertToMilliseconds(rtNow) ));
|
||||
|
||||
// We must add in a millisecond, since this is the resolution of our
|
||||
// WaitForSingleObject timer. Failure to do so will cause us to loop
|
||||
// franticly for (approx) 1 a millisecond.
|
||||
m_rtNextAdvise = m_pSchedule->Advise(10000 + rtNow);
|
||||
LONGLONG llWait = m_rtNextAdvise - rtNow;
|
||||
|
||||
ASSERT(llWait > 0);
|
||||
|
||||
llWait = ConvertToMilliseconds(llWait);
|
||||
// DON'T replace this with a max!! (The type's of these things is VERY important)
|
||||
dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait);
|
||||
};
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefClock.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements the IReferenceClock interface.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
|
||||
// 'this' used in constructor list
|
||||
#pragma warning(disable:4355)
|
||||
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::NonDelegatingQueryInterface(
|
||||
REFIID riid,
|
||||
void ** ppv) {
|
||||
HRESULT hr;
|
||||
|
||||
if(riid == IID_IReferenceClock) {
|
||||
hr = GetInterface((IReferenceClock *) this, ppv);
|
||||
}
|
||||
else {
|
||||
hr = CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
CBaseReferenceClock::~CBaseReferenceClock() {
|
||||
|
||||
if(m_TimerResolution) timeEndPeriod(m_TimerResolution);
|
||||
|
||||
m_pSchedule->DumpLinkedList();
|
||||
|
||||
if(m_hThread) {
|
||||
m_bAbort = TRUE;
|
||||
TriggerThread();
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
EXECUTE_ASSERT(CloseHandle(m_hThread));
|
||||
m_hThread = 0;
|
||||
EXECUTE_ASSERT(CloseHandle(m_pSchedule->GetEvent()));
|
||||
delete m_pSchedule;
|
||||
}
|
||||
}
|
||||
|
||||
// A derived class may supply a hThreadEvent if it has its own thread that will take care
|
||||
// of calling the schedulers Advise method. (Refere to CBaseReferenceClock::AdviseThread()
|
||||
// to see what such a thread has to do.)
|
||||
CBaseReferenceClock::CBaseReferenceClock( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pShed )
|
||||
: CUnknown( pName, pUnk )
|
||||
, m_rtLastGotTime(0)
|
||||
, m_TimerResolution(0)
|
||||
, m_bAbort( FALSE )
|
||||
, m_pSchedule( pShed ? pShed : new CAMSchedule(CreateEvent(NULL, FALSE, FALSE, NULL)) )
|
||||
, m_hThread(0) {
|
||||
|
||||
|
||||
ASSERT(m_pSchedule);
|
||||
if(!m_pSchedule) {
|
||||
*phr = E_OUTOFMEMORY;
|
||||
}
|
||||
else {
|
||||
// Set up the highest resolution timer we can manage
|
||||
TIMECAPS tc;
|
||||
m_TimerResolution = (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof(tc)))
|
||||
? tc.wPeriodMin : 1;
|
||||
|
||||
timeBeginPeriod(m_TimerResolution);
|
||||
|
||||
/* Initialise our system times - the derived clock should set the right values */
|
||||
m_dwPrevSystemTime = timeGetTime();
|
||||
m_rtPrivateTime = (UNITS / MILLISECONDS) * m_dwPrevSystemTime;
|
||||
|
||||
#ifdef PERF
|
||||
m_idGetSystemTime = MSR_REGISTER(TEXT("CBaseReferenceClock::GetTime"));
|
||||
#endif
|
||||
|
||||
if(!pShed) {
|
||||
DWORD ThreadID;
|
||||
m_hThread = ::CreateThread(NULL, // Security attributes
|
||||
(DWORD) 0, // Initial stack size
|
||||
AdviseThreadFunction, // Thread start address
|
||||
(LPVOID) this, // Thread parameter
|
||||
(DWORD) 0, // Creation flags
|
||||
&ThreadID); // Thread identifier
|
||||
|
||||
if(m_hThread) {
|
||||
SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
}
|
||||
else {
|
||||
*phr = E_FAIL;
|
||||
EXECUTE_ASSERT(CloseHandle(m_pSchedule->GetEvent()));
|
||||
delete m_pSchedule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::GetTime(REFERENCE_TIME *pTime) {
|
||||
HRESULT hr;
|
||||
if(pTime) {
|
||||
REFERENCE_TIME rtNow;
|
||||
Lock();
|
||||
rtNow = GetPrivateTime();
|
||||
if(rtNow > m_rtLastGotTime) {
|
||||
m_rtLastGotTime = rtNow;
|
||||
hr = S_OK;
|
||||
}
|
||||
else {
|
||||
hr = S_FALSE;
|
||||
}
|
||||
|
||||
*pTime = m_rtLastGotTime;
|
||||
Unlock();
|
||||
MSR_INTEGER(m_idGetSystemTime, LONG((*pTime) / (UNITS/MILLISECONDS)));
|
||||
}
|
||||
else hr = E_POINTER;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Ask for an async notification that a time has elapsed */
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::AdviseTime(
|
||||
REFERENCE_TIME baseTime, // base reference time
|
||||
REFERENCE_TIME streamTime, // stream offset time
|
||||
HEVENT hEvent, // advise via this event
|
||||
DWORD_PTR *pdwAdviseCookie) // where your cookie goes
|
||||
{
|
||||
CheckPointer(pdwAdviseCookie, E_POINTER);
|
||||
*pdwAdviseCookie = 0;
|
||||
|
||||
// Check that the event is not already set
|
||||
ASSERT(WAIT_TIMEOUT == WaitForSingleObject(HANDLE(hEvent),0));
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
const REFERENCE_TIME lRefTime = baseTime + streamTime;
|
||||
if(lRefTime <= 0 || lRefTime == MAX_TIME) {
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else {
|
||||
*pdwAdviseCookie = m_pSchedule->AddAdvisePacket(lRefTime, 0, HANDLE(hEvent), FALSE);
|
||||
hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
/* Ask for an asynchronous periodic notification that a time has elapsed */
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::AdvisePeriodic(
|
||||
REFERENCE_TIME StartTime, // starting at this time
|
||||
REFERENCE_TIME PeriodTime, // time between notifications
|
||||
HSEMAPHORE hSemaphore, // advise via a semaphore
|
||||
DWORD_PTR *pdwAdviseCookie) // where your cookie goes
|
||||
{
|
||||
CheckPointer(pdwAdviseCookie, E_POINTER);
|
||||
*pdwAdviseCookie = 0;
|
||||
|
||||
HRESULT hr;
|
||||
if(StartTime > 0 && PeriodTime > 0 && StartTime != MAX_TIME) {
|
||||
*pdwAdviseCookie = m_pSchedule->AddAdvisePacket(StartTime, PeriodTime, HANDLE(hSemaphore), TRUE);
|
||||
hr = *pdwAdviseCookie ? NOERROR : E_OUTOFMEMORY;
|
||||
}
|
||||
else hr = E_INVALIDARG;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::Unadvise(DWORD_PTR dwAdviseCookie) {
|
||||
return m_pSchedule->Unadvise(dwAdviseCookie);
|
||||
}
|
||||
|
||||
|
||||
REFERENCE_TIME CBaseReferenceClock::GetPrivateTime() {
|
||||
CAutoLock cObjectLock(this);
|
||||
|
||||
|
||||
/* If the clock has wrapped then the current time will be less than
|
||||
* the last time we were notified so add on the extra milliseconds
|
||||
*
|
||||
* The time period is long enough so that the likelihood of
|
||||
* successive calls spanning the clock cycle is not considered.
|
||||
*/
|
||||
|
||||
DWORD dwTime = timeGetTime(); {
|
||||
m_rtPrivateTime += Int32x32To64(UNITS / MILLISECONDS, (DWORD)(dwTime - m_dwPrevSystemTime));
|
||||
m_dwPrevSystemTime = dwTime;
|
||||
}
|
||||
|
||||
return m_rtPrivateTime;
|
||||
}
|
||||
|
||||
|
||||
/* Adjust the current time by the input value. This allows an
|
||||
external time source to work out some of the latency of the clock
|
||||
system and adjust the "current" time accordingly. The intent is
|
||||
that the time returned to the user is synchronised to a clock
|
||||
source and allows drift to be catered for.
|
||||
|
||||
For example: if the clock source detects a drift it can pass a delta
|
||||
to the current time rather than having to set an explicit time.
|
||||
*/
|
||||
|
||||
STDMETHODIMP CBaseReferenceClock::SetTimeDelta(const REFERENCE_TIME & TimeDelta) {
|
||||
#ifdef DEBUG
|
||||
|
||||
// Just break if passed an improper time delta value
|
||||
LONGLONG llDelta = TimeDelta > 0 ? TimeDelta : -TimeDelta;
|
||||
if(llDelta > UNITS * 1000) {
|
||||
DbgLog((LOG_TRACE, 0, TEXT("Bad Time Delta")));
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
// We're going to calculate a "severity" for the time change. Max -1
|
||||
// min 8. We'll then use this as the debug logging level for a
|
||||
// debug log message.
|
||||
const LONG usDelta = LONG(TimeDelta/10); // Delta in micro-secs
|
||||
|
||||
DWORD delta = abs(usDelta); // varying delta
|
||||
// Severity == 8 - ceil(log<base 8>(abs( micro-secs delta)))
|
||||
int Severity = 8;
|
||||
while(delta > 0) {
|
||||
delta >>= 3; // div 8
|
||||
Severity--;
|
||||
}
|
||||
|
||||
// Sev == 0 => > 2 second delta!
|
||||
DbgLog((LOG_TIMING, Severity < 0 ? 0 : Severity,
|
||||
TEXT("Sev %2i: CSystemClock::SetTimeDelta(%8ld us) %lu -> %lu ms."),
|
||||
Severity, usDelta, DWORD(ConvertToMilliseconds(m_rtPrivateTime)),
|
||||
DWORD(ConvertToMilliseconds(TimeDelta+m_rtPrivateTime)) ));
|
||||
|
||||
// Don't want the DbgBreak to fire when running stress on debug-builds.
|
||||
#ifdef BREAK_ON_SEVERE_TIME_DELTA
|
||||
if(Severity < 0)
|
||||
DbgBreakPoint(TEXT("SetTimeDelta > 16 seconds!"),
|
||||
TEXT(__FILE__),__LINE__);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
CAutoLock cObjectLock(this);
|
||||
m_rtPrivateTime += TimeDelta;
|
||||
// If time goes forwards, and we have advises, then we need to
|
||||
// trigger the thread so that it can re-evaluate its wait time.
|
||||
// Since we don't want the cost of the thread switches if the change
|
||||
// is really small, only do it if clock goes forward by more than
|
||||
// 0.5 millisecond. If the time goes backwards, the thread will
|
||||
// wake up "early" (relativly speaking) and will re-evaluate at
|
||||
// that time.
|
||||
if(TimeDelta > 5000 && m_pSchedule->GetAdviseCount() > 0) TriggerThread();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Thread stuff
|
||||
|
||||
DWORD __stdcall CBaseReferenceClock::AdviseThreadFunction(LPVOID p) {
|
||||
return DWORD(reinterpret_cast<CBaseReferenceClock*>(p)->AdviseThread());
|
||||
}
|
||||
|
||||
HRESULT CBaseReferenceClock::AdviseThread() {
|
||||
DWORD dwWait = INFINITE;
|
||||
|
||||
// The first thing we do is wait until something interesting happens
|
||||
// (meaning a first advise or shutdown). This prevents us calling
|
||||
// GetPrivateTime immediately which is goodness as that is a virtual
|
||||
// routine and the derived class may not yet be constructed. (This
|
||||
// thread is created in the base class constructor.)
|
||||
|
||||
while(!m_bAbort) {
|
||||
// Wait for an interesting event to happen
|
||||
DbgLog((LOG_TIMING, 3, TEXT("CBaseRefClock::AdviseThread() Delay: %lu ms"), dwWait ));
|
||||
WaitForSingleObject(m_pSchedule->GetEvent(), dwWait);
|
||||
if(m_bAbort) break;
|
||||
|
||||
// There are several reasons why we need to work from the internal
|
||||
// time, mainly to do with what happens when time goes backwards.
|
||||
// Mainly, it stop us looping madly if an event is just about to
|
||||
// expire when the clock goes backward (i.e. GetTime stop for a
|
||||
// while).
|
||||
const REFERENCE_TIME rtNow = GetPrivateTime();
|
||||
|
||||
DbgLog((LOG_TIMING, 3,
|
||||
TEXT("CBaseRefClock::AdviseThread() Woke at = %lu ms"),
|
||||
ConvertToMilliseconds(rtNow) ));
|
||||
|
||||
// We must add in a millisecond, since this is the resolution of our
|
||||
// WaitForSingleObject timer. Failure to do so will cause us to loop
|
||||
// franticly for (approx) 1 a millisecond.
|
||||
m_rtNextAdvise = m_pSchedule->Advise(10000 + rtNow);
|
||||
LONGLONG llWait = m_rtNextAdvise - rtNow;
|
||||
|
||||
ASSERT(llWait > 0);
|
||||
|
||||
llWait = ConvertToMilliseconds(llWait);
|
||||
// DON'T replace this with a max!! (The type's of these things is VERY important)
|
||||
dwWait = (llWait > REFERENCE_TIME(UINT_MAX)) ? UINT_MAX : DWORD(llWait);
|
||||
};
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
+169
-169
@@ -1,169 +1,169 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefClock.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines the IReferenceClock interface.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __BASEREFCLOCK__
|
||||
#define __BASEREFCLOCK__
|
||||
|
||||
#include "dsschedule.h"
|
||||
|
||||
const UINT RESOLUTION = 1; /* High resolution timer */
|
||||
const INT ADVISE_CACHE = 4; /* Default cache size */
|
||||
const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */
|
||||
|
||||
inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT)
|
||||
{
|
||||
/* This converts an arbitrary value representing a reference time
|
||||
into a MILLISECONDS value for use in subsequent system calls */
|
||||
|
||||
return (RT / (UNITS / MILLISECONDS));
|
||||
}
|
||||
|
||||
/* This class hierarchy will support an IReferenceClock interface so
|
||||
that an audio card (or other externally driven clock) can update the
|
||||
system wide clock that everyone uses.
|
||||
|
||||
The interface will be pretty thin with probably just one update method
|
||||
This interface has not yet been defined.
|
||||
*/
|
||||
|
||||
/* This abstract base class implements the IReferenceClock
|
||||
* interface. Classes that actually provide clock signals (from
|
||||
* whatever source) have to be derived from this class.
|
||||
*
|
||||
* The abstract class provides implementations for:
|
||||
* CUnknown support
|
||||
* locking support (CCritSec)
|
||||
* client advise code (creates a thread)
|
||||
*
|
||||
* Question: what can we do about quality? Change the timer
|
||||
* resolution to lower the system load? Up the priority of the
|
||||
* timer thread to force more responsive signals?
|
||||
*
|
||||
* During class construction we create a worker thread that is destroyed during
|
||||
* destuction. This thread executes a series of WaitForSingleObject calls,
|
||||
* waking up when a command is given to the thread or the next wake up point
|
||||
* is reached. The wakeup points are determined by clients making Advise
|
||||
* calls.
|
||||
*
|
||||
* Each advise call defines a point in time when they wish to be notified. A
|
||||
* periodic advise is a series of these such events. We maintain a list of
|
||||
* advise links and calculate when the nearest event notification is due for.
|
||||
* We then call WaitForSingleObject with a timeout equal to this time. The
|
||||
* handle we wait on is used by the class to signal that something has changed
|
||||
* and that we must reschedule the next event. This typically happens when
|
||||
* someone comes in and asks for an advise link while we are waiting for an
|
||||
* event to timeout.
|
||||
*
|
||||
* While we are modifying the list of advise requests we
|
||||
* are protected from interference through a critical section. Clients are NOT
|
||||
* advised through callbacks. One shot clients have an event set, while
|
||||
* periodic clients have a semaphore released for each event notification. A
|
||||
* semaphore allows a client to be kept up to date with the number of events
|
||||
* actually triggered and be assured that they can't miss multiple events being
|
||||
* set.
|
||||
*
|
||||
* Keeping track of advises is taken care of by the CAMSchedule class.
|
||||
*/
|
||||
|
||||
class CBaseReferenceClock
|
||||
: public CUnknown, public IReferenceClock, public CCritSec
|
||||
{
|
||||
protected:
|
||||
virtual ~CBaseReferenceClock(); // Don't let me be created on the stack!
|
||||
public:
|
||||
CBaseReferenceClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pSched = 0 );
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
/* IReferenceClock methods */
|
||||
// Derived classes must implement GetPrivateTime(). All our GetTime
|
||||
// does is call GetPrivateTime and then check so that time does not
|
||||
// go backwards. A return code of S_FALSE implies that the internal
|
||||
// clock has gone backwards and GetTime time has halted until internal
|
||||
// time has caught up. (Don't know if this will be much use to folk,
|
||||
// but it seems odd not to use the return code for something useful.)
|
||||
STDMETHODIMP GetTime(REFERENCE_TIME *pTime);
|
||||
// When this is called, it sets m_rtLastGotTime to the time it returns.
|
||||
|
||||
/* Provide standard mechanisms for scheduling events */
|
||||
|
||||
/* Ask for an async notification that a time has elapsed */
|
||||
STDMETHODIMP AdviseTime(
|
||||
REFERENCE_TIME baseTime, // base reference time
|
||||
REFERENCE_TIME streamTime, // stream offset time
|
||||
HEVENT hEvent, // advise via this event
|
||||
DWORD_PTR *pdwAdviseCookie // where your cookie goes
|
||||
);
|
||||
|
||||
/* Ask for an asynchronous periodic notification that a time has elapsed */
|
||||
STDMETHODIMP AdvisePeriodic(
|
||||
REFERENCE_TIME StartTime, // starting at this time
|
||||
REFERENCE_TIME PeriodTime, // time between notifications
|
||||
HSEMAPHORE hSemaphore, // advise via a semaphore
|
||||
DWORD_PTR *pdwAdviseCookie // where your cookie goes
|
||||
);
|
||||
|
||||
/* Cancel a request for notification(s) - if the notification was
|
||||
* a one shot timer then this function doesn't need to be called
|
||||
* as the advise is automatically cancelled, however it does no
|
||||
* harm to explicitly cancel a one-shot advise. It is REQUIRED that
|
||||
* clients call Unadvise to clear a Periodic advise setting.
|
||||
*/
|
||||
|
||||
STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie);
|
||||
|
||||
/* Methods for the benefit of derived classes or outer objects */
|
||||
|
||||
// GetPrivateTime() is the REAL clock. GetTime is just a cover for
|
||||
// it. Derived classes will probably override this method but not
|
||||
// GetTime() itself.
|
||||
// The important point about GetPrivateTime() is it's allowed to go
|
||||
// backwards. Our GetTime() will keep returning the LastGotTime
|
||||
// until GetPrivateTime() catches up.
|
||||
virtual REFERENCE_TIME GetPrivateTime();
|
||||
|
||||
/* Provide a method for correcting drift */
|
||||
STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta );
|
||||
|
||||
CAMSchedule * GetSchedule() const { return m_pSchedule; }
|
||||
|
||||
private:
|
||||
REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time
|
||||
DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime
|
||||
REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime
|
||||
REFERENCE_TIME m_rtNextAdvise; // Time of next advise
|
||||
UINT m_TimerResolution;
|
||||
|
||||
#ifdef PERF
|
||||
int m_idGetSystemTime;
|
||||
#endif
|
||||
|
||||
// Thread stuff
|
||||
public:
|
||||
void TriggerThread() // Wakes thread up. Need to do this if
|
||||
{ // time to next advise needs reevaluating.
|
||||
EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent()));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
BOOL m_bAbort; // Flag used for thread shutdown
|
||||
HANDLE m_hThread; // Thread handle
|
||||
|
||||
HRESULT AdviseThread(); // Method in which the advise thread runs
|
||||
static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there
|
||||
|
||||
protected:
|
||||
CAMSchedule * const m_pSchedule;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefClock.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines the IReferenceClock interface.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __BASEREFCLOCK__
|
||||
#define __BASEREFCLOCK__
|
||||
|
||||
#include "dsschedule.h"
|
||||
|
||||
const UINT RESOLUTION = 1; /* High resolution timer */
|
||||
const INT ADVISE_CACHE = 4; /* Default cache size */
|
||||
const LONGLONG MAX_TIME = 0x7FFFFFFFFFFFFFFF; /* Maximum LONGLONG value */
|
||||
|
||||
inline LONGLONG WINAPI ConvertToMilliseconds(const REFERENCE_TIME& RT)
|
||||
{
|
||||
/* This converts an arbitrary value representing a reference time
|
||||
into a MILLISECONDS value for use in subsequent system calls */
|
||||
|
||||
return (RT / (UNITS / MILLISECONDS));
|
||||
}
|
||||
|
||||
/* This class hierarchy will support an IReferenceClock interface so
|
||||
that an audio card (or other externally driven clock) can update the
|
||||
system wide clock that everyone uses.
|
||||
|
||||
The interface will be pretty thin with probably just one update method
|
||||
This interface has not yet been defined.
|
||||
*/
|
||||
|
||||
/* This abstract base class implements the IReferenceClock
|
||||
* interface. Classes that actually provide clock signals (from
|
||||
* whatever source) have to be derived from this class.
|
||||
*
|
||||
* The abstract class provides implementations for:
|
||||
* CUnknown support
|
||||
* locking support (CCritSec)
|
||||
* client advise code (creates a thread)
|
||||
*
|
||||
* Question: what can we do about quality? Change the timer
|
||||
* resolution to lower the system load? Up the priority of the
|
||||
* timer thread to force more responsive signals?
|
||||
*
|
||||
* During class construction we create a worker thread that is destroyed during
|
||||
* destuction. This thread executes a series of WaitForSingleObject calls,
|
||||
* waking up when a command is given to the thread or the next wake up point
|
||||
* is reached. The wakeup points are determined by clients making Advise
|
||||
* calls.
|
||||
*
|
||||
* Each advise call defines a point in time when they wish to be notified. A
|
||||
* periodic advise is a series of these such events. We maintain a list of
|
||||
* advise links and calculate when the nearest event notification is due for.
|
||||
* We then call WaitForSingleObject with a timeout equal to this time. The
|
||||
* handle we wait on is used by the class to signal that something has changed
|
||||
* and that we must reschedule the next event. This typically happens when
|
||||
* someone comes in and asks for an advise link while we are waiting for an
|
||||
* event to timeout.
|
||||
*
|
||||
* While we are modifying the list of advise requests we
|
||||
* are protected from interference through a critical section. Clients are NOT
|
||||
* advised through callbacks. One shot clients have an event set, while
|
||||
* periodic clients have a semaphore released for each event notification. A
|
||||
* semaphore allows a client to be kept up to date with the number of events
|
||||
* actually triggered and be assured that they can't miss multiple events being
|
||||
* set.
|
||||
*
|
||||
* Keeping track of advises is taken care of by the CAMSchedule class.
|
||||
*/
|
||||
|
||||
class CBaseReferenceClock
|
||||
: public CUnknown, public IReferenceClock, public CCritSec
|
||||
{
|
||||
protected:
|
||||
virtual ~CBaseReferenceClock(); // Don't let me be created on the stack!
|
||||
public:
|
||||
CBaseReferenceClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr, CAMSchedule * pSched = 0 );
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
/* IReferenceClock methods */
|
||||
// Derived classes must implement GetPrivateTime(). All our GetTime
|
||||
// does is call GetPrivateTime and then check so that time does not
|
||||
// go backwards. A return code of S_FALSE implies that the internal
|
||||
// clock has gone backwards and GetTime time has halted until internal
|
||||
// time has caught up. (Don't know if this will be much use to folk,
|
||||
// but it seems odd not to use the return code for something useful.)
|
||||
STDMETHODIMP GetTime(REFERENCE_TIME *pTime);
|
||||
// When this is called, it sets m_rtLastGotTime to the time it returns.
|
||||
|
||||
/* Provide standard mechanisms for scheduling events */
|
||||
|
||||
/* Ask for an async notification that a time has elapsed */
|
||||
STDMETHODIMP AdviseTime(
|
||||
REFERENCE_TIME baseTime, // base reference time
|
||||
REFERENCE_TIME streamTime, // stream offset time
|
||||
HEVENT hEvent, // advise via this event
|
||||
DWORD_PTR *pdwAdviseCookie // where your cookie goes
|
||||
);
|
||||
|
||||
/* Ask for an asynchronous periodic notification that a time has elapsed */
|
||||
STDMETHODIMP AdvisePeriodic(
|
||||
REFERENCE_TIME StartTime, // starting at this time
|
||||
REFERENCE_TIME PeriodTime, // time between notifications
|
||||
HSEMAPHORE hSemaphore, // advise via a semaphore
|
||||
DWORD_PTR *pdwAdviseCookie // where your cookie goes
|
||||
);
|
||||
|
||||
/* Cancel a request for notification(s) - if the notification was
|
||||
* a one shot timer then this function doesn't need to be called
|
||||
* as the advise is automatically cancelled, however it does no
|
||||
* harm to explicitly cancel a one-shot advise. It is REQUIRED that
|
||||
* clients call Unadvise to clear a Periodic advise setting.
|
||||
*/
|
||||
|
||||
STDMETHODIMP Unadvise(DWORD_PTR dwAdviseCookie);
|
||||
|
||||
/* Methods for the benefit of derived classes or outer objects */
|
||||
|
||||
// GetPrivateTime() is the REAL clock. GetTime is just a cover for
|
||||
// it. Derived classes will probably override this method but not
|
||||
// GetTime() itself.
|
||||
// The important point about GetPrivateTime() is it's allowed to go
|
||||
// backwards. Our GetTime() will keep returning the LastGotTime
|
||||
// until GetPrivateTime() catches up.
|
||||
virtual REFERENCE_TIME GetPrivateTime();
|
||||
|
||||
/* Provide a method for correcting drift */
|
||||
STDMETHODIMP SetTimeDelta( const REFERENCE_TIME& TimeDelta );
|
||||
|
||||
CAMSchedule * GetSchedule() const { return m_pSchedule; }
|
||||
|
||||
private:
|
||||
REFERENCE_TIME m_rtPrivateTime; // Current best estimate of time
|
||||
DWORD m_dwPrevSystemTime; // Last vaule we got from timeGetTime
|
||||
REFERENCE_TIME m_rtLastGotTime; // Last time returned by GetTime
|
||||
REFERENCE_TIME m_rtNextAdvise; // Time of next advise
|
||||
UINT m_TimerResolution;
|
||||
|
||||
#ifdef PERF
|
||||
int m_idGetSystemTime;
|
||||
#endif
|
||||
|
||||
// Thread stuff
|
||||
public:
|
||||
void TriggerThread() // Wakes thread up. Need to do this if
|
||||
{ // time to next advise needs reevaluating.
|
||||
EXECUTE_ASSERT(SetEvent(m_pSchedule->GetEvent()));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
BOOL m_bAbort; // Flag used for thread shutdown
|
||||
HANDLE m_hThread; // Thread handle
|
||||
|
||||
HRESULT AdviseThread(); // Method in which the advise thread runs
|
||||
static DWORD __stdcall AdviseThreadFunction(LPVOID); // Function used to get there
|
||||
|
||||
protected:
|
||||
CAMSchedule * const m_pSchedule;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+116
-116
@@ -1,116 +1,116 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefTime.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines CRefTime, a class that manages
|
||||
// reference times.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// CRefTime
|
||||
//
|
||||
// Manage reference times.
|
||||
// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual)
|
||||
// functions providing simple comparison, conversion and arithmetic.
|
||||
//
|
||||
// A reference time (at the moment) is a unit of seconds represented in
|
||||
// 100ns units as is used in the Win32 FILETIME structure. BUT the time
|
||||
// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it
|
||||
// will either be stream time or reference time depending upon context
|
||||
//
|
||||
// This class provides simple arithmetic operations on reference times
|
||||
//
|
||||
// keep non-virtual otherwise the data layout will not be the same as
|
||||
// REFERENCE_TIME
|
||||
|
||||
|
||||
// -----
|
||||
// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but
|
||||
// you will need to do so explicitly
|
||||
// -----
|
||||
|
||||
|
||||
#ifndef __REFTIME__
|
||||
#define __REFTIME__
|
||||
|
||||
|
||||
const LONGLONG MILLISECONDS = (1000); // 10 ^ 3
|
||||
const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9
|
||||
const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7
|
||||
|
||||
/* Unfortunately an inline function here generates a call to __allmul
|
||||
- even for constants!
|
||||
*/
|
||||
#define MILLISECONDS_TO_100NS_UNITS(lMs) \
|
||||
Int32x32To64((lMs), (UNITS / MILLISECONDS))
|
||||
|
||||
class CRefTime
|
||||
{
|
||||
public:
|
||||
|
||||
// *MUST* be the only data member so that this class is exactly
|
||||
// equivalent to a REFERENCE_TIME.
|
||||
// Also, must be *no virtual functions*
|
||||
|
||||
REFERENCE_TIME m_time;
|
||||
|
||||
inline CRefTime()
|
||||
{
|
||||
// default to 0 time
|
||||
m_time = 0;
|
||||
};
|
||||
|
||||
inline CRefTime(LONG msecs)
|
||||
{
|
||||
m_time = MILLISECONDS_TO_100NS_UNITS(msecs);
|
||||
};
|
||||
|
||||
inline CRefTime(REFERENCE_TIME rt)
|
||||
{
|
||||
m_time = rt;
|
||||
};
|
||||
|
||||
inline operator REFERENCE_TIME() const
|
||||
{
|
||||
return m_time;
|
||||
};
|
||||
|
||||
inline CRefTime& operator=(const CRefTime& rt)
|
||||
{
|
||||
m_time = rt.m_time;
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline CRefTime& operator=(const LONGLONG ll)
|
||||
{
|
||||
m_time = ll;
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline CRefTime& operator+=(const CRefTime& rt)
|
||||
{
|
||||
return (*this = *this + rt);
|
||||
};
|
||||
|
||||
inline CRefTime& operator-=(const CRefTime& rt)
|
||||
{
|
||||
return (*this = *this - rt);
|
||||
};
|
||||
|
||||
inline LONG Millisecs(void)
|
||||
{
|
||||
return (LONG)(m_time / (UNITS / MILLISECONDS));
|
||||
};
|
||||
|
||||
inline LONGLONG GetUnits(void)
|
||||
{
|
||||
return m_time;
|
||||
};
|
||||
};
|
||||
|
||||
const LONGLONG TimeZero = 0;
|
||||
|
||||
#endif /* __REFTIME__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RefTime.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines CRefTime, a class that manages
|
||||
// reference times.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// CRefTime
|
||||
//
|
||||
// Manage reference times.
|
||||
// Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual)
|
||||
// functions providing simple comparison, conversion and arithmetic.
|
||||
//
|
||||
// A reference time (at the moment) is a unit of seconds represented in
|
||||
// 100ns units as is used in the Win32 FILETIME structure. BUT the time
|
||||
// a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it
|
||||
// will either be stream time or reference time depending upon context
|
||||
//
|
||||
// This class provides simple arithmetic operations on reference times
|
||||
//
|
||||
// keep non-virtual otherwise the data layout will not be the same as
|
||||
// REFERENCE_TIME
|
||||
|
||||
|
||||
// -----
|
||||
// note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but
|
||||
// you will need to do so explicitly
|
||||
// -----
|
||||
|
||||
|
||||
#ifndef __REFTIME__
|
||||
#define __REFTIME__
|
||||
|
||||
|
||||
const LONGLONG MILLISECONDS = (1000); // 10 ^ 3
|
||||
const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9
|
||||
const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7
|
||||
|
||||
/* Unfortunately an inline function here generates a call to __allmul
|
||||
- even for constants!
|
||||
*/
|
||||
#define MILLISECONDS_TO_100NS_UNITS(lMs) \
|
||||
Int32x32To64((lMs), (UNITS / MILLISECONDS))
|
||||
|
||||
class CRefTime
|
||||
{
|
||||
public:
|
||||
|
||||
// *MUST* be the only data member so that this class is exactly
|
||||
// equivalent to a REFERENCE_TIME.
|
||||
// Also, must be *no virtual functions*
|
||||
|
||||
REFERENCE_TIME m_time;
|
||||
|
||||
inline CRefTime()
|
||||
{
|
||||
// default to 0 time
|
||||
m_time = 0;
|
||||
};
|
||||
|
||||
inline CRefTime(LONG msecs)
|
||||
{
|
||||
m_time = MILLISECONDS_TO_100NS_UNITS(msecs);
|
||||
};
|
||||
|
||||
inline CRefTime(REFERENCE_TIME rt)
|
||||
{
|
||||
m_time = rt;
|
||||
};
|
||||
|
||||
inline operator REFERENCE_TIME() const
|
||||
{
|
||||
return m_time;
|
||||
};
|
||||
|
||||
inline CRefTime& operator=(const CRefTime& rt)
|
||||
{
|
||||
m_time = rt.m_time;
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline CRefTime& operator=(const LONGLONG ll)
|
||||
{
|
||||
m_time = ll;
|
||||
return *this;
|
||||
};
|
||||
|
||||
inline CRefTime& operator+=(const CRefTime& rt)
|
||||
{
|
||||
return (*this = *this + rt);
|
||||
};
|
||||
|
||||
inline CRefTime& operator-=(const CRefTime& rt)
|
||||
{
|
||||
return (*this = *this - rt);
|
||||
};
|
||||
|
||||
inline LONG Millisecs(void)
|
||||
{
|
||||
return (LONG)(m_time / (UNITS / MILLISECONDS));
|
||||
};
|
||||
|
||||
inline LONGLONG GetUnits(void)
|
||||
{
|
||||
return m_time;
|
||||
};
|
||||
};
|
||||
|
||||
const LONGLONG TimeZero = 0;
|
||||
|
||||
#endif /* __REFTIME__ */
|
||||
|
||||
|
||||
+2833
-2833
File diff suppressed because it is too large
Load Diff
+479
-479
@@ -1,479 +1,479 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RenBase.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a generic ActiveX base renderer
|
||||
// class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __RENBASE__
|
||||
#define __RENBASE__
|
||||
|
||||
// Forward class declarations
|
||||
|
||||
class CBaseRenderer;
|
||||
class CBaseVideoRenderer;
|
||||
class CRendererInputPin;
|
||||
|
||||
// This is our input pin class that channels calls to the renderer
|
||||
|
||||
class CRendererInputPin : public CBaseInputPin
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseRenderer *m_pRenderer;
|
||||
|
||||
public:
|
||||
|
||||
CRendererInputPin(CBaseRenderer *pRenderer,
|
||||
HRESULT *phr,
|
||||
LPCWSTR Name);
|
||||
|
||||
// Overriden from the base pin classes
|
||||
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
HRESULT SetMediaType(const CMediaType *pmt);
|
||||
HRESULT CheckMediaType(const CMediaType *pmt);
|
||||
HRESULT Active();
|
||||
HRESULT Inactive();
|
||||
|
||||
// Add rendering behaviour to interface functions
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR *Id);
|
||||
STDMETHODIMP EndOfStream();
|
||||
STDMETHODIMP BeginFlush();
|
||||
STDMETHODIMP EndFlush();
|
||||
STDMETHODIMP Receive(IMediaSample *pMediaSample);
|
||||
|
||||
// Helper
|
||||
IMemAllocator inline *Allocator() const
|
||||
{
|
||||
return m_pAllocator;
|
||||
}
|
||||
};
|
||||
|
||||
// Main renderer class that handles synchronisation and state changes
|
||||
|
||||
class CBaseRenderer : public CBaseFilter
|
||||
{
|
||||
protected:
|
||||
|
||||
friend class CRendererInputPin;
|
||||
|
||||
friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier
|
||||
UINT uMsg, // Not currently used
|
||||
DWORD_PTR dwUser, // User information
|
||||
DWORD_PTR dw1, // Windows reserved
|
||||
DWORD_PTR dw2); // Is also reserved
|
||||
|
||||
CRendererPosPassThru *m_pPosition; // Media seeking pass by object
|
||||
CAMEvent m_RenderEvent; // Used to signal timer events
|
||||
CAMEvent m_ThreadSignal; // Signalled to release worker thread
|
||||
CAMEvent m_evComplete; // Signalled when state complete
|
||||
BOOL m_bAbort; // Stop us from rendering more data
|
||||
BOOL m_bStreaming; // Are we currently streaming
|
||||
DWORD_PTR m_dwAdvise; // Timer advise cookie
|
||||
IMediaSample *m_pMediaSample; // Current image media sample
|
||||
BOOL m_bEOS; // Any more samples in the stream
|
||||
BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE
|
||||
CRendererInputPin *m_pInputPin; // Our renderer input pin object
|
||||
CCritSec m_InterfaceLock; // Critical section for interfaces
|
||||
CCritSec m_RendererLock; // Controls access to internals
|
||||
IQualityControl * m_pQSink; // QualityControl sink
|
||||
BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT
|
||||
|
||||
// Avoid some deadlocks by tracking filter during stop
|
||||
volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive
|
||||
// And actually processing the sample
|
||||
REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE
|
||||
UINT m_EndOfStreamTimer; // Used to signal end of stream
|
||||
CCritSec m_ObjectCreationLock; // This lock protects the creation and
|
||||
// of m_pPosition and m_pInputPin. It
|
||||
// ensures that two threads cannot create
|
||||
// either object simultaneously.
|
||||
|
||||
public:
|
||||
|
||||
CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer
|
||||
TCHAR *pName, // Debug ONLY description
|
||||
LPUNKNOWN pUnk, // Aggregated owner object
|
||||
HRESULT *phr); // General OLE return code
|
||||
|
||||
~CBaseRenderer();
|
||||
|
||||
// Overriden to say what interfaces we support and where
|
||||
|
||||
virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv);
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
|
||||
|
||||
virtual HRESULT SourceThreadCanWait(BOOL bCanWait);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug only dump of the renderer state
|
||||
void DisplayRendererState();
|
||||
#endif
|
||||
virtual HRESULT WaitForRenderTime();
|
||||
virtual HRESULT CompleteStateChange(FILTER_STATE OldState);
|
||||
|
||||
// Return internal information about this filter
|
||||
|
||||
BOOL IsEndOfStream() { return m_bEOS; };
|
||||
BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; };
|
||||
BOOL IsStreaming() { return m_bStreaming; };
|
||||
void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; };
|
||||
virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { };
|
||||
CAMEvent *GetRenderEvent() { return &m_RenderEvent; };
|
||||
|
||||
// Permit access to the transition state
|
||||
|
||||
void Ready() { m_evComplete.Set(); };
|
||||
void NotReady() { m_evComplete.Reset(); };
|
||||
BOOL CheckReady() { return m_evComplete.Check(); };
|
||||
|
||||
virtual int GetPinCount();
|
||||
virtual CBasePin *GetPin(int n);
|
||||
FILTER_STATE GetRealState();
|
||||
void SendRepaint();
|
||||
void SendNotifyWindow(IPin *pPin,HWND hwnd);
|
||||
BOOL OnDisplayChange();
|
||||
void SetRepaintStatus(BOOL bRepaint);
|
||||
|
||||
// Override the filter and pin interface functions
|
||||
|
||||
STDMETHODIMP Stop();
|
||||
STDMETHODIMP Pause();
|
||||
STDMETHODIMP Run(REFERENCE_TIME StartTime);
|
||||
STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State);
|
||||
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
|
||||
|
||||
// These are available for a quality management implementation
|
||||
|
||||
virtual void OnRenderStart(IMediaSample *pMediaSample);
|
||||
virtual void OnRenderEnd(IMediaSample *pMediaSample);
|
||||
virtual HRESULT OnStartStreaming() { return NOERROR; };
|
||||
virtual HRESULT OnStopStreaming() { return NOERROR; };
|
||||
virtual void OnWaitStart() { };
|
||||
virtual void OnWaitEnd() { };
|
||||
virtual void PrepareRender() { };
|
||||
|
||||
#ifdef PERF
|
||||
REFERENCE_TIME m_trRenderStart; // Just before we started drawing
|
||||
// Set in OnRenderStart, Used in OnRenderEnd
|
||||
int m_idBaseStamp; // MSR_id for frame time stamp
|
||||
int m_idBaseRenderTime; // MSR_id for true wait time
|
||||
int m_idBaseAccuracy; // MSR_id for time frame is late (int)
|
||||
#endif
|
||||
|
||||
// Quality management implementation for scheduling rendering
|
||||
|
||||
virtual BOOL ScheduleSample(IMediaSample *pMediaSample);
|
||||
virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *pStartTime,
|
||||
REFERENCE_TIME *pEndTime);
|
||||
|
||||
virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *ptrStart,
|
||||
REFERENCE_TIME *ptrEnd);
|
||||
|
||||
// Lots of end of stream complexities
|
||||
|
||||
void TimerCallback();
|
||||
void ResetEndOfStreamTimer();
|
||||
HRESULT NotifyEndOfStream();
|
||||
virtual HRESULT SendEndOfStream();
|
||||
virtual HRESULT ResetEndOfStream();
|
||||
virtual HRESULT EndOfStream();
|
||||
|
||||
// Rendering is based around the clock
|
||||
|
||||
void SignalTimerFired();
|
||||
virtual HRESULT CancelNotification();
|
||||
virtual HRESULT ClearPendingSample();
|
||||
|
||||
// Called when the filter changes state
|
||||
|
||||
virtual HRESULT Active();
|
||||
virtual HRESULT Inactive();
|
||||
virtual HRESULT StartStreaming();
|
||||
virtual HRESULT StopStreaming();
|
||||
virtual HRESULT BeginFlush();
|
||||
virtual HRESULT EndFlush();
|
||||
|
||||
// Deal with connections and type changes
|
||||
|
||||
virtual HRESULT BreakConnect();
|
||||
virtual HRESULT SetMediaType(const CMediaType *pmt);
|
||||
virtual HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// These look after the handling of data samples
|
||||
|
||||
virtual HRESULT PrepareReceive(IMediaSample *pMediaSample);
|
||||
virtual HRESULT Receive(IMediaSample *pMediaSample);
|
||||
virtual BOOL HaveCurrentSample();
|
||||
virtual IMediaSample *GetCurrentSample();
|
||||
virtual HRESULT Render(IMediaSample *pMediaSample);
|
||||
|
||||
// Derived classes MUST override these
|
||||
virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE;
|
||||
virtual HRESULT CheckMediaType(const CMediaType *) PURE;
|
||||
|
||||
// Helper
|
||||
void WaitForReceiveToComplete();
|
||||
};
|
||||
|
||||
|
||||
// CBaseVideoRenderer is a renderer class (see its ancestor class) and
|
||||
// it handles scheduling of media samples so that they are drawn at the
|
||||
// correct time by the reference clock. It implements a degradation
|
||||
// strategy. Possible degradation modes are:
|
||||
// Drop frames here (only useful if the drawing takes significant time)
|
||||
// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip.
|
||||
// Signal supplier to change the frame rate - i.e. ongoing skipping.
|
||||
// Or any combination of the above.
|
||||
// In order to determine what's useful to try we need to know what's going
|
||||
// on. This is done by timing various operations (including the supplier).
|
||||
// This timing is done by using timeGetTime as it is accurate enough and
|
||||
// usually cheaper than calling the reference clock. It also tells the
|
||||
// truth if there is an audio break and the reference clock stops.
|
||||
// We provide a number of public entry points (named OnXxxStart, OnXxxEnd)
|
||||
// which the rest of the renderer calls at significant moments. These do
|
||||
// the timing.
|
||||
|
||||
// the number of frames that the sliding averages are averaged over.
|
||||
// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
|
||||
#define AVGPERIOD 4
|
||||
#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
|
||||
// Spot the bug in this macro - I can't. but it doesn't work!
|
||||
|
||||
class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class
|
||||
public IQualProp, // Property page guff
|
||||
public IQualityControl // Allow throttling
|
||||
{
|
||||
protected:
|
||||
|
||||
// Hungarian:
|
||||
// tFoo is the time Foo in mSec (beware m_tStart from filter.h)
|
||||
// trBar is the time Bar by the reference clock
|
||||
|
||||
//******************************************************************
|
||||
// State variables to control synchronisation
|
||||
//******************************************************************
|
||||
|
||||
// Control of sending Quality messages. We need to know whether
|
||||
// we are in trouble (e.g. frames being dropped) and where the time
|
||||
// is being spent.
|
||||
|
||||
// When we drop a frame we play the next one early.
|
||||
// The frame after that is likely to wait before drawing and counting this
|
||||
// wait as spare time is unfair, so we count it as a zero wait.
|
||||
// We therefore need to know whether we are playing frames early or not.
|
||||
|
||||
int m_nNormal; // The number of consecutive frames
|
||||
// drawn at their normal time (not early)
|
||||
// -1 means we just dropped a frame.
|
||||
|
||||
#ifdef PERF
|
||||
BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm
|
||||
// not keen on people using it!)
|
||||
#endif
|
||||
|
||||
BOOL m_bSupplierHandlingQuality;// The response to Quality messages says
|
||||
// our supplier is handling things.
|
||||
// We will allow things to go extra late
|
||||
// before dropping frames. We will play
|
||||
// very early after he has dropped one.
|
||||
|
||||
// Control of scheduling, frame dropping etc.
|
||||
// We need to know where the time is being spent so as to tell whether
|
||||
// we should be taking action here, signalling supplier or what.
|
||||
// The variables are initialised to a mode of NOT dropping frames.
|
||||
// They will tell the truth after a few frames.
|
||||
// We typically record a start time for an event, later we get the time
|
||||
// again and subtract to get the elapsed time, and we average this over
|
||||
// a few frames. The average is used to tell what mode we are in.
|
||||
|
||||
// Although these are reference times (64 bit) they are all DIFFERENCES
|
||||
// between times which are small. An int will go up to 214 secs before
|
||||
// overflow. Avoiding 64 bit multiplications and divisions seems
|
||||
// worth while.
|
||||
|
||||
|
||||
|
||||
// Audio-video throttling. If the user has turned up audio quality
|
||||
// very high (in principle it could be any other stream, not just audio)
|
||||
// then we can receive cries for help via the graph manager. In this case
|
||||
// we put in a wait for some time after rendering each frame.
|
||||
int m_trThrottle;
|
||||
|
||||
// The time taken to render (i.e. BitBlt) frames controls which component
|
||||
// needs to degrade. If the blt is expensive, the renderer degrades.
|
||||
// If the blt is cheap it's done anyway and the supplier degrades.
|
||||
int m_trRenderAvg; // Time frames are taking to blt
|
||||
int m_trRenderLast; // Time for last frame blt
|
||||
int m_tRenderStart; // Just before we started drawing (mSec)
|
||||
// derived from timeGetTime.
|
||||
|
||||
// When frames are dropped we will play the next frame as early as we can.
|
||||
// If it was a false alarm and the machine is fast we slide gently back to
|
||||
// normal timing. To do this, we record the offset showing just how early
|
||||
// we really are. This will normally be negative meaning early or zero.
|
||||
int m_trEarliness;
|
||||
|
||||
// Target provides slow long-term feedback to try to reduce the
|
||||
// average sync offset to zero. Whenever a frame is actually rendered
|
||||
// early we add a msec or two, whenever late we take off a few.
|
||||
// We add or take off 1/32 of the error time.
|
||||
// Eventually we should be hovering around zero. For a really bad case
|
||||
// where we were (say) 300mSec off, it might take 100 odd frames to
|
||||
// settle down. The rate of change of this is intended to be slower
|
||||
// than any other mechanism in Quartz, thereby avoiding hunting.
|
||||
int m_trTarget;
|
||||
|
||||
// The proportion of time spent waiting for the right moment to blt
|
||||
// controls whether we bother to drop a frame or whether we reckon that
|
||||
// we're doing well enough that we can stand a one-frame glitch.
|
||||
int m_trWaitAvg; // Average of last few wait times
|
||||
// (actually we just average how early
|
||||
// we were). Negative here means LATE.
|
||||
|
||||
// The average inter-frame time.
|
||||
// This is used to calculate the proportion of the time used by the
|
||||
// three operations (supplying us, waiting, rendering)
|
||||
int m_trFrameAvg; // Average inter-frame time
|
||||
int m_trDuration; // duration of last frame.
|
||||
|
||||
#ifdef PERF
|
||||
// Performance logging identifiers
|
||||
int m_idTimeStamp; // MSR_id for frame time stamp
|
||||
int m_idEarliness; // MSR_id for earliness fudge
|
||||
int m_idTarget; // MSR_id for Target fudge
|
||||
int m_idWaitReal; // MSR_id for true wait time
|
||||
int m_idWait; // MSR_id for wait time recorded
|
||||
int m_idFrameAccuracy; // MSR_id for time frame is late (int)
|
||||
int m_idRenderAvg; // MSR_id for Render time recorded (int)
|
||||
int m_idSchLateTime; // MSR_id for lateness at scheduler
|
||||
int m_idQualityRate; // MSR_id for Quality rate requested
|
||||
int m_idQualityTime; // MSR_id for Quality time requested
|
||||
int m_idDecision; // MSR_id for decision code
|
||||
int m_idDuration; // MSR_id for duration of a frame
|
||||
int m_idThrottle; // MSR_id for audio-video throttling
|
||||
//int m_idDebug; // MSR_id for trace style debugging
|
||||
//int m_idSendQuality; // MSR_id for timing the notifications per se
|
||||
#endif // PERF
|
||||
REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame
|
||||
// with no earliness fudges etc.
|
||||
#ifdef PERF
|
||||
REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered
|
||||
|
||||
// debug...
|
||||
int m_idFrameAvg;
|
||||
int m_idWaitAvg;
|
||||
#endif
|
||||
|
||||
// PROPERTY PAGE
|
||||
// This has edit fields that show the user what's happening
|
||||
// These member variables hold these counts.
|
||||
|
||||
int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER
|
||||
int m_cFramesDrawn; // Frames since streaming started seen BY THE
|
||||
// RENDERER (some may be dropped upstream)
|
||||
|
||||
// Next two support average sync offset and standard deviation of sync offset.
|
||||
LONGLONG m_iTotAcc; // Sum of accuracies in mSec
|
||||
LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec)
|
||||
|
||||
// Next two allow jitter calculation. Jitter is std deviation of frame time.
|
||||
REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times)
|
||||
LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec)
|
||||
LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec
|
||||
|
||||
// To get performance statistics on frame rate, jitter etc, we need
|
||||
// to record the lateness and inter-frame time. What we actually need are the
|
||||
// data above (sum, sum of squares and number of entries for each) but the data
|
||||
// is generated just ahead of time and only later do we discover whether the
|
||||
// frame was actually drawn or not. So we have to hang on to the data
|
||||
int m_trLate; // hold onto frame lateness
|
||||
int m_trFrame; // hold onto inter-frame time
|
||||
|
||||
int m_tStreamingStart; // if streaming then time streaming started
|
||||
// else time of last streaming session
|
||||
// used for property page statistics
|
||||
#ifdef PERF
|
||||
LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
||||
CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer
|
||||
TCHAR *pName, // Debug ONLY description
|
||||
LPUNKNOWN pUnk, // Aggregated owner object
|
||||
HRESULT *phr); // General OLE return code
|
||||
|
||||
~CBaseVideoRenderer();
|
||||
|
||||
// IQualityControl methods - Notify allows audio-video throttling
|
||||
|
||||
STDMETHODIMP SetSink( IQualityControl * piqc);
|
||||
STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q);
|
||||
|
||||
// These provide a full video quality management implementation
|
||||
|
||||
void OnRenderStart(IMediaSample *pMediaSample);
|
||||
void OnRenderEnd(IMediaSample *pMediaSample);
|
||||
void OnWaitStart();
|
||||
void OnWaitEnd();
|
||||
HRESULT OnStartStreaming();
|
||||
HRESULT OnStopStreaming();
|
||||
void ThrottleWait();
|
||||
|
||||
// Handle the statistics gathering for our quality management
|
||||
|
||||
void PreparePerformanceData(int trLate, int trFrame);
|
||||
virtual void RecordFrameLateness(int trLate, int trFrame);
|
||||
virtual void OnDirectRender(IMediaSample *pMediaSample);
|
||||
virtual HRESULT ResetStreamingTimes();
|
||||
BOOL ScheduleSample(IMediaSample *pMediaSample);
|
||||
HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *ptrStart,
|
||||
REFERENCE_TIME *ptrEnd);
|
||||
|
||||
virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream);
|
||||
STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName);
|
||||
|
||||
//
|
||||
// Do estimates for standard deviations for per-frame
|
||||
// statistics
|
||||
//
|
||||
// *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
|
||||
// (m_cFramesDrawn - 2)
|
||||
// or 0 if m_cFramesDrawn <= 3
|
||||
//
|
||||
HRESULT GetStdDev(
|
||||
int nSamples,
|
||||
int *piResult,
|
||||
LONGLONG llSumSq,
|
||||
LONGLONG iTot
|
||||
);
|
||||
public:
|
||||
|
||||
// IQualProp property page support
|
||||
|
||||
STDMETHODIMP get_FramesDroppedInRenderer(int *cFramesDropped);
|
||||
STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn);
|
||||
STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate);
|
||||
STDMETHODIMP get_Jitter(int *piJitter);
|
||||
STDMETHODIMP get_AvgSyncOffset(int *piAvg);
|
||||
STDMETHODIMP get_DevSyncOffset(int *piDev);
|
||||
|
||||
// Implement an IUnknown interface and expose IQualProp
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,VOID **ppv);
|
||||
};
|
||||
|
||||
#endif // __RENBASE__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: RenBase.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a generic ActiveX base renderer
|
||||
// class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __RENBASE__
|
||||
#define __RENBASE__
|
||||
|
||||
// Forward class declarations
|
||||
|
||||
class CBaseRenderer;
|
||||
class CBaseVideoRenderer;
|
||||
class CRendererInputPin;
|
||||
|
||||
// This is our input pin class that channels calls to the renderer
|
||||
|
||||
class CRendererInputPin : public CBaseInputPin
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseRenderer *m_pRenderer;
|
||||
|
||||
public:
|
||||
|
||||
CRendererInputPin(CBaseRenderer *pRenderer,
|
||||
HRESULT *phr,
|
||||
LPCWSTR Name);
|
||||
|
||||
// Overriden from the base pin classes
|
||||
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
HRESULT SetMediaType(const CMediaType *pmt);
|
||||
HRESULT CheckMediaType(const CMediaType *pmt);
|
||||
HRESULT Active();
|
||||
HRESULT Inactive();
|
||||
|
||||
// Add rendering behaviour to interface functions
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR *Id);
|
||||
STDMETHODIMP EndOfStream();
|
||||
STDMETHODIMP BeginFlush();
|
||||
STDMETHODIMP EndFlush();
|
||||
STDMETHODIMP Receive(IMediaSample *pMediaSample);
|
||||
|
||||
// Helper
|
||||
IMemAllocator inline *Allocator() const
|
||||
{
|
||||
return m_pAllocator;
|
||||
}
|
||||
};
|
||||
|
||||
// Main renderer class that handles synchronisation and state changes
|
||||
|
||||
class CBaseRenderer : public CBaseFilter
|
||||
{
|
||||
protected:
|
||||
|
||||
friend class CRendererInputPin;
|
||||
|
||||
friend void CALLBACK EndOfStreamTimer(UINT uID, // Timer identifier
|
||||
UINT uMsg, // Not currently used
|
||||
DWORD_PTR dwUser, // User information
|
||||
DWORD_PTR dw1, // Windows reserved
|
||||
DWORD_PTR dw2); // Is also reserved
|
||||
|
||||
CRendererPosPassThru *m_pPosition; // Media seeking pass by object
|
||||
CAMEvent m_RenderEvent; // Used to signal timer events
|
||||
CAMEvent m_ThreadSignal; // Signalled to release worker thread
|
||||
CAMEvent m_evComplete; // Signalled when state complete
|
||||
BOOL m_bAbort; // Stop us from rendering more data
|
||||
BOOL m_bStreaming; // Are we currently streaming
|
||||
DWORD_PTR m_dwAdvise; // Timer advise cookie
|
||||
IMediaSample *m_pMediaSample; // Current image media sample
|
||||
BOOL m_bEOS; // Any more samples in the stream
|
||||
BOOL m_bEOSDelivered; // Have we delivered an EC_COMPLETE
|
||||
CRendererInputPin *m_pInputPin; // Our renderer input pin object
|
||||
CCritSec m_InterfaceLock; // Critical section for interfaces
|
||||
CCritSec m_RendererLock; // Controls access to internals
|
||||
IQualityControl * m_pQSink; // QualityControl sink
|
||||
BOOL m_bRepaintStatus; // Can we signal an EC_REPAINT
|
||||
|
||||
// Avoid some deadlocks by tracking filter during stop
|
||||
volatile BOOL m_bInReceive; // Inside Receive between PrepareReceive
|
||||
// And actually processing the sample
|
||||
REFERENCE_TIME m_SignalTime; // Time when we signal EC_COMPLETE
|
||||
UINT m_EndOfStreamTimer; // Used to signal end of stream
|
||||
CCritSec m_ObjectCreationLock; // This lock protects the creation and
|
||||
// of m_pPosition and m_pInputPin. It
|
||||
// ensures that two threads cannot create
|
||||
// either object simultaneously.
|
||||
|
||||
public:
|
||||
|
||||
CBaseRenderer(REFCLSID RenderClass, // CLSID for this renderer
|
||||
TCHAR *pName, // Debug ONLY description
|
||||
LPUNKNOWN pUnk, // Aggregated owner object
|
||||
HRESULT *phr); // General OLE return code
|
||||
|
||||
~CBaseRenderer();
|
||||
|
||||
// Overriden to say what interfaces we support and where
|
||||
|
||||
virtual HRESULT GetMediaPositionInterface(REFIID riid,void **ppv);
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **);
|
||||
|
||||
virtual HRESULT SourceThreadCanWait(BOOL bCanWait);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug only dump of the renderer state
|
||||
void DisplayRendererState();
|
||||
#endif
|
||||
virtual HRESULT WaitForRenderTime();
|
||||
virtual HRESULT CompleteStateChange(FILTER_STATE OldState);
|
||||
|
||||
// Return internal information about this filter
|
||||
|
||||
BOOL IsEndOfStream() { return m_bEOS; };
|
||||
BOOL IsEndOfStreamDelivered() { return m_bEOSDelivered; };
|
||||
BOOL IsStreaming() { return m_bStreaming; };
|
||||
void SetAbortSignal(BOOL bAbort) { m_bAbort = bAbort; };
|
||||
virtual void OnReceiveFirstSample(IMediaSample *pMediaSample) { };
|
||||
CAMEvent *GetRenderEvent() { return &m_RenderEvent; };
|
||||
|
||||
// Permit access to the transition state
|
||||
|
||||
void Ready() { m_evComplete.Set(); };
|
||||
void NotReady() { m_evComplete.Reset(); };
|
||||
BOOL CheckReady() { return m_evComplete.Check(); };
|
||||
|
||||
virtual int GetPinCount();
|
||||
virtual CBasePin *GetPin(int n);
|
||||
FILTER_STATE GetRealState();
|
||||
void SendRepaint();
|
||||
void SendNotifyWindow(IPin *pPin,HWND hwnd);
|
||||
BOOL OnDisplayChange();
|
||||
void SetRepaintStatus(BOOL bRepaint);
|
||||
|
||||
// Override the filter and pin interface functions
|
||||
|
||||
STDMETHODIMP Stop();
|
||||
STDMETHODIMP Pause();
|
||||
STDMETHODIMP Run(REFERENCE_TIME StartTime);
|
||||
STDMETHODIMP GetState(DWORD dwMSecs,FILTER_STATE *State);
|
||||
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
|
||||
|
||||
// These are available for a quality management implementation
|
||||
|
||||
virtual void OnRenderStart(IMediaSample *pMediaSample);
|
||||
virtual void OnRenderEnd(IMediaSample *pMediaSample);
|
||||
virtual HRESULT OnStartStreaming() { return NOERROR; };
|
||||
virtual HRESULT OnStopStreaming() { return NOERROR; };
|
||||
virtual void OnWaitStart() { };
|
||||
virtual void OnWaitEnd() { };
|
||||
virtual void PrepareRender() { };
|
||||
|
||||
#ifdef PERF
|
||||
REFERENCE_TIME m_trRenderStart; // Just before we started drawing
|
||||
// Set in OnRenderStart, Used in OnRenderEnd
|
||||
int m_idBaseStamp; // MSR_id for frame time stamp
|
||||
int m_idBaseRenderTime; // MSR_id for true wait time
|
||||
int m_idBaseAccuracy; // MSR_id for time frame is late (int)
|
||||
#endif
|
||||
|
||||
// Quality management implementation for scheduling rendering
|
||||
|
||||
virtual BOOL ScheduleSample(IMediaSample *pMediaSample);
|
||||
virtual HRESULT GetSampleTimes(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *pStartTime,
|
||||
REFERENCE_TIME *pEndTime);
|
||||
|
||||
virtual HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *ptrStart,
|
||||
REFERENCE_TIME *ptrEnd);
|
||||
|
||||
// Lots of end of stream complexities
|
||||
|
||||
void TimerCallback();
|
||||
void ResetEndOfStreamTimer();
|
||||
HRESULT NotifyEndOfStream();
|
||||
virtual HRESULT SendEndOfStream();
|
||||
virtual HRESULT ResetEndOfStream();
|
||||
virtual HRESULT EndOfStream();
|
||||
|
||||
// Rendering is based around the clock
|
||||
|
||||
void SignalTimerFired();
|
||||
virtual HRESULT CancelNotification();
|
||||
virtual HRESULT ClearPendingSample();
|
||||
|
||||
// Called when the filter changes state
|
||||
|
||||
virtual HRESULT Active();
|
||||
virtual HRESULT Inactive();
|
||||
virtual HRESULT StartStreaming();
|
||||
virtual HRESULT StopStreaming();
|
||||
virtual HRESULT BeginFlush();
|
||||
virtual HRESULT EndFlush();
|
||||
|
||||
// Deal with connections and type changes
|
||||
|
||||
virtual HRESULT BreakConnect();
|
||||
virtual HRESULT SetMediaType(const CMediaType *pmt);
|
||||
virtual HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// These look after the handling of data samples
|
||||
|
||||
virtual HRESULT PrepareReceive(IMediaSample *pMediaSample);
|
||||
virtual HRESULT Receive(IMediaSample *pMediaSample);
|
||||
virtual BOOL HaveCurrentSample();
|
||||
virtual IMediaSample *GetCurrentSample();
|
||||
virtual HRESULT Render(IMediaSample *pMediaSample);
|
||||
|
||||
// Derived classes MUST override these
|
||||
virtual HRESULT DoRenderSample(IMediaSample *pMediaSample) PURE;
|
||||
virtual HRESULT CheckMediaType(const CMediaType *) PURE;
|
||||
|
||||
// Helper
|
||||
void WaitForReceiveToComplete();
|
||||
};
|
||||
|
||||
|
||||
// CBaseVideoRenderer is a renderer class (see its ancestor class) and
|
||||
// it handles scheduling of media samples so that they are drawn at the
|
||||
// correct time by the reference clock. It implements a degradation
|
||||
// strategy. Possible degradation modes are:
|
||||
// Drop frames here (only useful if the drawing takes significant time)
|
||||
// Signal supplier (upstream) to drop some frame(s) - i.e. one-off skip.
|
||||
// Signal supplier to change the frame rate - i.e. ongoing skipping.
|
||||
// Or any combination of the above.
|
||||
// In order to determine what's useful to try we need to know what's going
|
||||
// on. This is done by timing various operations (including the supplier).
|
||||
// This timing is done by using timeGetTime as it is accurate enough and
|
||||
// usually cheaper than calling the reference clock. It also tells the
|
||||
// truth if there is an audio break and the reference clock stops.
|
||||
// We provide a number of public entry points (named OnXxxStart, OnXxxEnd)
|
||||
// which the rest of the renderer calls at significant moments. These do
|
||||
// the timing.
|
||||
|
||||
// the number of frames that the sliding averages are averaged over.
|
||||
// the rule is (1024*NewObservation + (AVGPERIOD-1) * PreviousAverage)/AVGPERIOD
|
||||
#define AVGPERIOD 4
|
||||
#define DO_MOVING_AVG(avg,obs) (avg = (1024*obs + (AVGPERIOD-1)*avg)/AVGPERIOD)
|
||||
// Spot the bug in this macro - I can't. but it doesn't work!
|
||||
|
||||
class CBaseVideoRenderer : public CBaseRenderer, // Base renderer class
|
||||
public IQualProp, // Property page guff
|
||||
public IQualityControl // Allow throttling
|
||||
{
|
||||
protected:
|
||||
|
||||
// Hungarian:
|
||||
// tFoo is the time Foo in mSec (beware m_tStart from filter.h)
|
||||
// trBar is the time Bar by the reference clock
|
||||
|
||||
//******************************************************************
|
||||
// State variables to control synchronisation
|
||||
//******************************************************************
|
||||
|
||||
// Control of sending Quality messages. We need to know whether
|
||||
// we are in trouble (e.g. frames being dropped) and where the time
|
||||
// is being spent.
|
||||
|
||||
// When we drop a frame we play the next one early.
|
||||
// The frame after that is likely to wait before drawing and counting this
|
||||
// wait as spare time is unfair, so we count it as a zero wait.
|
||||
// We therefore need to know whether we are playing frames early or not.
|
||||
|
||||
int m_nNormal; // The number of consecutive frames
|
||||
// drawn at their normal time (not early)
|
||||
// -1 means we just dropped a frame.
|
||||
|
||||
#ifdef PERF
|
||||
BOOL m_bDrawLateFrames; // Don't drop any frames (debug and I'm
|
||||
// not keen on people using it!)
|
||||
#endif
|
||||
|
||||
BOOL m_bSupplierHandlingQuality;// The response to Quality messages says
|
||||
// our supplier is handling things.
|
||||
// We will allow things to go extra late
|
||||
// before dropping frames. We will play
|
||||
// very early after he has dropped one.
|
||||
|
||||
// Control of scheduling, frame dropping etc.
|
||||
// We need to know where the time is being spent so as to tell whether
|
||||
// we should be taking action here, signalling supplier or what.
|
||||
// The variables are initialised to a mode of NOT dropping frames.
|
||||
// They will tell the truth after a few frames.
|
||||
// We typically record a start time for an event, later we get the time
|
||||
// again and subtract to get the elapsed time, and we average this over
|
||||
// a few frames. The average is used to tell what mode we are in.
|
||||
|
||||
// Although these are reference times (64 bit) they are all DIFFERENCES
|
||||
// between times which are small. An int will go up to 214 secs before
|
||||
// overflow. Avoiding 64 bit multiplications and divisions seems
|
||||
// worth while.
|
||||
|
||||
|
||||
|
||||
// Audio-video throttling. If the user has turned up audio quality
|
||||
// very high (in principle it could be any other stream, not just audio)
|
||||
// then we can receive cries for help via the graph manager. In this case
|
||||
// we put in a wait for some time after rendering each frame.
|
||||
int m_trThrottle;
|
||||
|
||||
// The time taken to render (i.e. BitBlt) frames controls which component
|
||||
// needs to degrade. If the blt is expensive, the renderer degrades.
|
||||
// If the blt is cheap it's done anyway and the supplier degrades.
|
||||
int m_trRenderAvg; // Time frames are taking to blt
|
||||
int m_trRenderLast; // Time for last frame blt
|
||||
int m_tRenderStart; // Just before we started drawing (mSec)
|
||||
// derived from timeGetTime.
|
||||
|
||||
// When frames are dropped we will play the next frame as early as we can.
|
||||
// If it was a false alarm and the machine is fast we slide gently back to
|
||||
// normal timing. To do this, we record the offset showing just how early
|
||||
// we really are. This will normally be negative meaning early or zero.
|
||||
int m_trEarliness;
|
||||
|
||||
// Target provides slow long-term feedback to try to reduce the
|
||||
// average sync offset to zero. Whenever a frame is actually rendered
|
||||
// early we add a msec or two, whenever late we take off a few.
|
||||
// We add or take off 1/32 of the error time.
|
||||
// Eventually we should be hovering around zero. For a really bad case
|
||||
// where we were (say) 300mSec off, it might take 100 odd frames to
|
||||
// settle down. The rate of change of this is intended to be slower
|
||||
// than any other mechanism in Quartz, thereby avoiding hunting.
|
||||
int m_trTarget;
|
||||
|
||||
// The proportion of time spent waiting for the right moment to blt
|
||||
// controls whether we bother to drop a frame or whether we reckon that
|
||||
// we're doing well enough that we can stand a one-frame glitch.
|
||||
int m_trWaitAvg; // Average of last few wait times
|
||||
// (actually we just average how early
|
||||
// we were). Negative here means LATE.
|
||||
|
||||
// The average inter-frame time.
|
||||
// This is used to calculate the proportion of the time used by the
|
||||
// three operations (supplying us, waiting, rendering)
|
||||
int m_trFrameAvg; // Average inter-frame time
|
||||
int m_trDuration; // duration of last frame.
|
||||
|
||||
#ifdef PERF
|
||||
// Performance logging identifiers
|
||||
int m_idTimeStamp; // MSR_id for frame time stamp
|
||||
int m_idEarliness; // MSR_id for earliness fudge
|
||||
int m_idTarget; // MSR_id for Target fudge
|
||||
int m_idWaitReal; // MSR_id for true wait time
|
||||
int m_idWait; // MSR_id for wait time recorded
|
||||
int m_idFrameAccuracy; // MSR_id for time frame is late (int)
|
||||
int m_idRenderAvg; // MSR_id for Render time recorded (int)
|
||||
int m_idSchLateTime; // MSR_id for lateness at scheduler
|
||||
int m_idQualityRate; // MSR_id for Quality rate requested
|
||||
int m_idQualityTime; // MSR_id for Quality time requested
|
||||
int m_idDecision; // MSR_id for decision code
|
||||
int m_idDuration; // MSR_id for duration of a frame
|
||||
int m_idThrottle; // MSR_id for audio-video throttling
|
||||
//int m_idDebug; // MSR_id for trace style debugging
|
||||
//int m_idSendQuality; // MSR_id for timing the notifications per se
|
||||
#endif // PERF
|
||||
REFERENCE_TIME m_trRememberStampForPerf; // original time stamp of frame
|
||||
// with no earliness fudges etc.
|
||||
#ifdef PERF
|
||||
REFERENCE_TIME m_trRememberFrameForPerf; // time when previous frame rendered
|
||||
|
||||
// debug...
|
||||
int m_idFrameAvg;
|
||||
int m_idWaitAvg;
|
||||
#endif
|
||||
|
||||
// PROPERTY PAGE
|
||||
// This has edit fields that show the user what's happening
|
||||
// These member variables hold these counts.
|
||||
|
||||
int m_cFramesDropped; // cumulative frames dropped IN THE RENDERER
|
||||
int m_cFramesDrawn; // Frames since streaming started seen BY THE
|
||||
// RENDERER (some may be dropped upstream)
|
||||
|
||||
// Next two support average sync offset and standard deviation of sync offset.
|
||||
LONGLONG m_iTotAcc; // Sum of accuracies in mSec
|
||||
LONGLONG m_iSumSqAcc; // Sum of squares of (accuracies in mSec)
|
||||
|
||||
// Next two allow jitter calculation. Jitter is std deviation of frame time.
|
||||
REFERENCE_TIME m_trLastDraw; // Time of prev frame (for inter-frame times)
|
||||
LONGLONG m_iSumSqFrameTime; // Sum of squares of (inter-frame time in mSec)
|
||||
LONGLONG m_iSumFrameTime; // Sum of inter-frame times in mSec
|
||||
|
||||
// To get performance statistics on frame rate, jitter etc, we need
|
||||
// to record the lateness and inter-frame time. What we actually need are the
|
||||
// data above (sum, sum of squares and number of entries for each) but the data
|
||||
// is generated just ahead of time and only later do we discover whether the
|
||||
// frame was actually drawn or not. So we have to hang on to the data
|
||||
int m_trLate; // hold onto frame lateness
|
||||
int m_trFrame; // hold onto inter-frame time
|
||||
|
||||
int m_tStreamingStart; // if streaming then time streaming started
|
||||
// else time of last streaming session
|
||||
// used for property page statistics
|
||||
#ifdef PERF
|
||||
LONGLONG m_llTimeOffset; // timeGetTime()*10000+m_llTimeOffset==ref time
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
||||
CBaseVideoRenderer(REFCLSID RenderClass, // CLSID for this renderer
|
||||
TCHAR *pName, // Debug ONLY description
|
||||
LPUNKNOWN pUnk, // Aggregated owner object
|
||||
HRESULT *phr); // General OLE return code
|
||||
|
||||
~CBaseVideoRenderer();
|
||||
|
||||
// IQualityControl methods - Notify allows audio-video throttling
|
||||
|
||||
STDMETHODIMP SetSink( IQualityControl * piqc);
|
||||
STDMETHODIMP Notify( IBaseFilter * pSelf, Quality q);
|
||||
|
||||
// These provide a full video quality management implementation
|
||||
|
||||
void OnRenderStart(IMediaSample *pMediaSample);
|
||||
void OnRenderEnd(IMediaSample *pMediaSample);
|
||||
void OnWaitStart();
|
||||
void OnWaitEnd();
|
||||
HRESULT OnStartStreaming();
|
||||
HRESULT OnStopStreaming();
|
||||
void ThrottleWait();
|
||||
|
||||
// Handle the statistics gathering for our quality management
|
||||
|
||||
void PreparePerformanceData(int trLate, int trFrame);
|
||||
virtual void RecordFrameLateness(int trLate, int trFrame);
|
||||
virtual void OnDirectRender(IMediaSample *pMediaSample);
|
||||
virtual HRESULT ResetStreamingTimes();
|
||||
BOOL ScheduleSample(IMediaSample *pMediaSample);
|
||||
HRESULT ShouldDrawSampleNow(IMediaSample *pMediaSample,
|
||||
REFERENCE_TIME *ptrStart,
|
||||
REFERENCE_TIME *ptrEnd);
|
||||
|
||||
virtual HRESULT SendQuality(REFERENCE_TIME trLate, REFERENCE_TIME trRealStream);
|
||||
STDMETHODIMP JoinFilterGraph(IFilterGraph * pGraph, LPCWSTR pName);
|
||||
|
||||
//
|
||||
// Do estimates for standard deviations for per-frame
|
||||
// statistics
|
||||
//
|
||||
// *piResult = (llSumSq - iTot * iTot / m_cFramesDrawn - 1) /
|
||||
// (m_cFramesDrawn - 2)
|
||||
// or 0 if m_cFramesDrawn <= 3
|
||||
//
|
||||
HRESULT GetStdDev(
|
||||
int nSamples,
|
||||
int *piResult,
|
||||
LONGLONG llSumSq,
|
||||
LONGLONG iTot
|
||||
);
|
||||
public:
|
||||
|
||||
// IQualProp property page support
|
||||
|
||||
STDMETHODIMP get_FramesDroppedInRenderer(int *cFramesDropped);
|
||||
STDMETHODIMP get_FramesDrawn(int *pcFramesDrawn);
|
||||
STDMETHODIMP get_AvgFrameRate(int *piAvgFrameRate);
|
||||
STDMETHODIMP get_Jitter(int *piJitter);
|
||||
STDMETHODIMP get_AvgSyncOffset(int *piAvg);
|
||||
STDMETHODIMP get_DevSyncOffset(int *piDev);
|
||||
|
||||
// Implement an IUnknown interface and expose IQualProp
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,VOID **ppv);
|
||||
};
|
||||
|
||||
#endif // __RENBASE__
|
||||
|
||||
|
||||
+265
-265
@@ -1,265 +1,265 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Schedule.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#pragma warning(disable:4706) // C4706: assignment within conditional expression
|
||||
|
||||
// DbgLog values (all on LOG_TIMING):
|
||||
//
|
||||
// 2 for schedulting, firing and shunting of events
|
||||
// 3 for wait delays and wake-up times of event thread
|
||||
// 4 for details of whats on the list when the thread awakes
|
||||
|
||||
/* Construct & destructors */
|
||||
|
||||
CAMSchedule::CAMSchedule( HANDLE ev )
|
||||
: CBaseObject(TEXT("CAMSchedule"))
|
||||
, head(&z, 0), z(0, MAX_TIME)
|
||||
, m_dwNextCookie(0), m_dwAdviseCount(0)
|
||||
, m_pAdviseCache(0), m_dwCacheCount(0)
|
||||
, m_ev( ev ) {
|
||||
head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
|
||||
}
|
||||
|
||||
CAMSchedule::~CAMSchedule() {
|
||||
m_Serialize.Lock();
|
||||
|
||||
// Delete cache
|
||||
CAdvisePacket * p = m_pAdviseCache;
|
||||
while(p) {
|
||||
CAdvisePacket *const p_next = p->m_next;
|
||||
delete p;
|
||||
p = p_next;
|
||||
}
|
||||
|
||||
ASSERT(m_dwAdviseCount == 0);
|
||||
// Better to be safe than sorry
|
||||
if(m_dwAdviseCount > 0) {
|
||||
DumpLinkedList();
|
||||
while(!head.m_next->IsZ()) {
|
||||
head.DeleteNext();
|
||||
--m_dwAdviseCount;
|
||||
}
|
||||
}
|
||||
|
||||
// If, in the debug version, we assert twice, it means, not only
|
||||
// did we have left over advises, but we have also let m_dwAdviseCount
|
||||
// get out of sync. with the number of advises actually on the list.
|
||||
ASSERT(m_dwAdviseCount == 0);
|
||||
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
|
||||
/* Public methods */
|
||||
|
||||
DWORD CAMSchedule::GetAdviseCount() {
|
||||
// No need to lock, m_dwAdviseCount is 32bits & declared volatile
|
||||
return m_dwAdviseCount;
|
||||
}
|
||||
|
||||
REFERENCE_TIME CAMSchedule::GetNextAdviseTime() {
|
||||
CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing
|
||||
return head.m_next->m_rtEventTime;
|
||||
}
|
||||
|
||||
DWORD_PTR CAMSchedule::AddAdvisePacket
|
||||
( const REFERENCE_TIME & time1
|
||||
, const REFERENCE_TIME & time2
|
||||
, HANDLE h, BOOL periodic
|
||||
) {
|
||||
// Since we use MAX_TIME as a sentry, we can't afford to
|
||||
// schedule a notification at MAX_TIME
|
||||
ASSERT(time1 < MAX_TIME);
|
||||
DWORD_PTR Result;
|
||||
CAdvisePacket * p;
|
||||
|
||||
m_Serialize.Lock();
|
||||
|
||||
if(m_pAdviseCache) {
|
||||
p = m_pAdviseCache;
|
||||
m_pAdviseCache = p->m_next;
|
||||
--m_dwCacheCount;
|
||||
}
|
||||
else {
|
||||
p = new CAdvisePacket();
|
||||
}
|
||||
if(p) {
|
||||
p->m_rtEventTime = time1; p->m_rtPeriod = time2;
|
||||
p->m_hNotify = h; p->m_bPeriodic = periodic;
|
||||
Result = AddAdvisePacket(p);
|
||||
}
|
||||
else Result = 0;
|
||||
|
||||
m_Serialize.Unlock();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) {
|
||||
HRESULT hr = S_FALSE;
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
m_Serialize.Lock();
|
||||
while(p_n = p_prev->Next()) // The Next() method returns NULL when it hits z
|
||||
{
|
||||
if(p_n->m_dwAdviseCookie == dwAdviseCookie) {
|
||||
Delete(p_prev->RemoveNext());
|
||||
--m_dwAdviseCount;
|
||||
hr = S_OK;
|
||||
// Having found one cookie that matches, there should be no more
|
||||
#ifdef DEBUG
|
||||
while(p_n = p_prev->Next()) {
|
||||
ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
|
||||
p_prev = p_n;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
p_prev = p_n;
|
||||
};
|
||||
m_Serialize.Unlock();
|
||||
return hr;
|
||||
}
|
||||
|
||||
REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) {
|
||||
REFERENCE_TIME rtNextTime;
|
||||
CAdvisePacket * pAdvise;
|
||||
|
||||
DbgLog((LOG_TIMING, 2,
|
||||
TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
|
||||
|
||||
CAutoLock lck(&m_Serialize);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList();
|
||||
#endif
|
||||
|
||||
// Note - DON'T cache the difference, it might overflow
|
||||
while(rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
|
||||
!pAdvise->IsZ()) {
|
||||
ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!!
|
||||
|
||||
ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
|
||||
|
||||
if(pAdvise->m_bPeriodic == TRUE) {
|
||||
ReleaseSemaphore(pAdvise->m_hNotify,1,NULL);
|
||||
pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
|
||||
ShuntHead();
|
||||
}
|
||||
else {
|
||||
ASSERT(pAdvise->m_bPeriodic == FALSE);
|
||||
EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
|
||||
--m_dwAdviseCount;
|
||||
Delete(head.RemoveNext());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DbgLog((LOG_TIMING, 3,
|
||||
TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."),
|
||||
DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie ));
|
||||
|
||||
return rtNextTime;
|
||||
}
|
||||
|
||||
/* Private methods */
|
||||
|
||||
DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket ) {
|
||||
ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
|
||||
ASSERT(CritCheckIn(&m_Serialize));
|
||||
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
|
||||
const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie;
|
||||
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
||||
for(;;p_prev = p_n)
|
||||
{
|
||||
p_n = p_prev->m_next;
|
||||
if(p_n->m_rtEventTime >= pPacket->m_rtEventTime)
|
||||
break;
|
||||
}
|
||||
p_prev->InsertAfter( pPacket );
|
||||
++m_dwAdviseCount;
|
||||
|
||||
DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"),
|
||||
pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
||||
|
||||
// If packet added at the head, then clock needs to re-evaluate wait time.
|
||||
if(p_prev == &head) SetEvent(m_ev);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void CAMSchedule::Delete( CAdvisePacket * pPacket ) {
|
||||
if(m_dwCacheCount >= dwCacheMax) delete pPacket;
|
||||
else {
|
||||
m_Serialize.Lock();
|
||||
pPacket->m_next = m_pAdviseCache;
|
||||
m_pAdviseCache = pPacket;
|
||||
++m_dwCacheCount;
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Takes the head of the list & repositions it
|
||||
void CAMSchedule::ShuntHead() {
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
|
||||
m_Serialize.Lock();
|
||||
CAdvisePacket *const pPacket = head.m_next;
|
||||
|
||||
// This will catch both an empty list,
|
||||
// and if somehow a MAX_TIME time gets into the list
|
||||
// (which would also break this method).
|
||||
ASSERT(pPacket->m_rtEventTime < MAX_TIME);
|
||||
|
||||
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
||||
for(;;p_prev = p_n)
|
||||
{
|
||||
p_n = p_prev->m_next;
|
||||
if(p_n->m_rtEventTime > pPacket->m_rtEventTime)
|
||||
break;
|
||||
}
|
||||
|
||||
// If p_prev == pPacket then we're already in the right place
|
||||
if(p_prev != pPacket)
|
||||
{
|
||||
head.m_next = pPacket->m_next;
|
||||
(p_prev->m_next = pPacket)->m_next = p_n;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"),
|
||||
pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
||||
#endif
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void CAMSchedule::DumpLinkedList() {
|
||||
m_Serialize.Lock();
|
||||
int i=0;
|
||||
DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this));
|
||||
for(CAdvisePacket * p = &head
|
||||
; p
|
||||
; p = p->m_next , i++) {
|
||||
DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
|
||||
i,
|
||||
p->m_dwAdviseCookie,
|
||||
p->m_rtEventTime / (UNITS / MILLISECONDS)
|
||||
));
|
||||
}
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Schedule.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
|
||||
#pragma warning(disable:4706) // C4706: assignment within conditional expression
|
||||
|
||||
// DbgLog values (all on LOG_TIMING):
|
||||
//
|
||||
// 2 for schedulting, firing and shunting of events
|
||||
// 3 for wait delays and wake-up times of event thread
|
||||
// 4 for details of whats on the list when the thread awakes
|
||||
|
||||
/* Construct & destructors */
|
||||
|
||||
CAMSchedule::CAMSchedule( HANDLE ev )
|
||||
: CBaseObject(TEXT("CAMSchedule"))
|
||||
, head(&z, 0), z(0, MAX_TIME)
|
||||
, m_dwNextCookie(0), m_dwAdviseCount(0)
|
||||
, m_pAdviseCache(0), m_dwCacheCount(0)
|
||||
, m_ev( ev ) {
|
||||
head.m_dwAdviseCookie = z.m_dwAdviseCookie = 0;
|
||||
}
|
||||
|
||||
CAMSchedule::~CAMSchedule() {
|
||||
m_Serialize.Lock();
|
||||
|
||||
// Delete cache
|
||||
CAdvisePacket * p = m_pAdviseCache;
|
||||
while(p) {
|
||||
CAdvisePacket *const p_next = p->m_next;
|
||||
delete p;
|
||||
p = p_next;
|
||||
}
|
||||
|
||||
ASSERT(m_dwAdviseCount == 0);
|
||||
// Better to be safe than sorry
|
||||
if(m_dwAdviseCount > 0) {
|
||||
DumpLinkedList();
|
||||
while(!head.m_next->IsZ()) {
|
||||
head.DeleteNext();
|
||||
--m_dwAdviseCount;
|
||||
}
|
||||
}
|
||||
|
||||
// If, in the debug version, we assert twice, it means, not only
|
||||
// did we have left over advises, but we have also let m_dwAdviseCount
|
||||
// get out of sync. with the number of advises actually on the list.
|
||||
ASSERT(m_dwAdviseCount == 0);
|
||||
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
|
||||
/* Public methods */
|
||||
|
||||
DWORD CAMSchedule::GetAdviseCount() {
|
||||
// No need to lock, m_dwAdviseCount is 32bits & declared volatile
|
||||
return m_dwAdviseCount;
|
||||
}
|
||||
|
||||
REFERENCE_TIME CAMSchedule::GetNextAdviseTime() {
|
||||
CAutoLock lck(&m_Serialize); // Need to stop the linked list from changing
|
||||
return head.m_next->m_rtEventTime;
|
||||
}
|
||||
|
||||
DWORD_PTR CAMSchedule::AddAdvisePacket
|
||||
( const REFERENCE_TIME & time1
|
||||
, const REFERENCE_TIME & time2
|
||||
, HANDLE h, BOOL periodic
|
||||
) {
|
||||
// Since we use MAX_TIME as a sentry, we can't afford to
|
||||
// schedule a notification at MAX_TIME
|
||||
ASSERT(time1 < MAX_TIME);
|
||||
DWORD_PTR Result;
|
||||
CAdvisePacket * p;
|
||||
|
||||
m_Serialize.Lock();
|
||||
|
||||
if(m_pAdviseCache) {
|
||||
p = m_pAdviseCache;
|
||||
m_pAdviseCache = p->m_next;
|
||||
--m_dwCacheCount;
|
||||
}
|
||||
else {
|
||||
p = new CAdvisePacket();
|
||||
}
|
||||
if(p) {
|
||||
p->m_rtEventTime = time1; p->m_rtPeriod = time2;
|
||||
p->m_hNotify = h; p->m_bPeriodic = periodic;
|
||||
Result = AddAdvisePacket(p);
|
||||
}
|
||||
else Result = 0;
|
||||
|
||||
m_Serialize.Unlock();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
HRESULT CAMSchedule::Unadvise(DWORD_PTR dwAdviseCookie) {
|
||||
HRESULT hr = S_FALSE;
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
m_Serialize.Lock();
|
||||
while(p_n = p_prev->Next()) // The Next() method returns NULL when it hits z
|
||||
{
|
||||
if(p_n->m_dwAdviseCookie == dwAdviseCookie) {
|
||||
Delete(p_prev->RemoveNext());
|
||||
--m_dwAdviseCount;
|
||||
hr = S_OK;
|
||||
// Having found one cookie that matches, there should be no more
|
||||
#ifdef DEBUG
|
||||
while(p_n = p_prev->Next()) {
|
||||
ASSERT(p_n->m_dwAdviseCookie != dwAdviseCookie);
|
||||
p_prev = p_n;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
p_prev = p_n;
|
||||
};
|
||||
m_Serialize.Unlock();
|
||||
return hr;
|
||||
}
|
||||
|
||||
REFERENCE_TIME CAMSchedule::Advise( const REFERENCE_TIME & rtTime ) {
|
||||
REFERENCE_TIME rtNextTime;
|
||||
CAdvisePacket * pAdvise;
|
||||
|
||||
DbgLog((LOG_TIMING, 2,
|
||||
TEXT("CAMSchedule::Advise( %lu ms )"), ULONG(rtTime / (UNITS / MILLISECONDS))));
|
||||
|
||||
CAutoLock lck(&m_Serialize);
|
||||
|
||||
#ifdef DEBUG
|
||||
if(DbgCheckModuleLevel(LOG_TIMING, 4)) DumpLinkedList();
|
||||
#endif
|
||||
|
||||
// Note - DON'T cache the difference, it might overflow
|
||||
while(rtTime >= (rtNextTime = (pAdvise=head.m_next)->m_rtEventTime) &&
|
||||
!pAdvise->IsZ()) {
|
||||
ASSERT(pAdvise->m_dwAdviseCookie); // If this is zero, its the head or the tail!!
|
||||
|
||||
ASSERT(pAdvise->m_hNotify != INVALID_HANDLE_VALUE);
|
||||
|
||||
if(pAdvise->m_bPeriodic == TRUE) {
|
||||
ReleaseSemaphore(pAdvise->m_hNotify,1,NULL);
|
||||
pAdvise->m_rtEventTime += pAdvise->m_rtPeriod;
|
||||
ShuntHead();
|
||||
}
|
||||
else {
|
||||
ASSERT(pAdvise->m_bPeriodic == FALSE);
|
||||
EXECUTE_ASSERT(SetEvent(pAdvise->m_hNotify));
|
||||
--m_dwAdviseCount;
|
||||
Delete(head.RemoveNext());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DbgLog((LOG_TIMING, 3,
|
||||
TEXT("CAMSchedule::Advise() Next time stamp: %lu ms, for advise %lu."),
|
||||
DWORD(rtNextTime / (UNITS / MILLISECONDS)), pAdvise->m_dwAdviseCookie ));
|
||||
|
||||
return rtNextTime;
|
||||
}
|
||||
|
||||
/* Private methods */
|
||||
|
||||
DWORD_PTR CAMSchedule::AddAdvisePacket( CAdvisePacket * pPacket ) {
|
||||
ASSERT(pPacket->m_rtEventTime >= 0 && pPacket->m_rtEventTime < MAX_TIME);
|
||||
ASSERT(CritCheckIn(&m_Serialize));
|
||||
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
|
||||
const DWORD_PTR Result = pPacket->m_dwAdviseCookie = ++m_dwNextCookie;
|
||||
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
||||
for(;;p_prev = p_n)
|
||||
{
|
||||
p_n = p_prev->m_next;
|
||||
if(p_n->m_rtEventTime >= pPacket->m_rtEventTime)
|
||||
break;
|
||||
}
|
||||
p_prev->InsertAfter( pPacket );
|
||||
++m_dwAdviseCount;
|
||||
|
||||
DbgLog((LOG_TIMING, 2, TEXT("Added advise %lu, for thread 0x%02X, scheduled at %lu"),
|
||||
pPacket->m_dwAdviseCookie, GetCurrentThreadId(), (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
||||
|
||||
// If packet added at the head, then clock needs to re-evaluate wait time.
|
||||
if(p_prev == &head) SetEvent(m_ev);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void CAMSchedule::Delete( CAdvisePacket * pPacket ) {
|
||||
if(m_dwCacheCount >= dwCacheMax) delete pPacket;
|
||||
else {
|
||||
m_Serialize.Lock();
|
||||
pPacket->m_next = m_pAdviseCache;
|
||||
m_pAdviseCache = pPacket;
|
||||
++m_dwCacheCount;
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Takes the head of the list & repositions it
|
||||
void CAMSchedule::ShuntHead() {
|
||||
CAdvisePacket * p_prev = &head;
|
||||
CAdvisePacket * p_n;
|
||||
|
||||
m_Serialize.Lock();
|
||||
CAdvisePacket *const pPacket = head.m_next;
|
||||
|
||||
// This will catch both an empty list,
|
||||
// and if somehow a MAX_TIME time gets into the list
|
||||
// (which would also break this method).
|
||||
ASSERT(pPacket->m_rtEventTime < MAX_TIME);
|
||||
|
||||
// This relies on the fact that z is a sentry with a maximal m_rtEventTime
|
||||
for(;;p_prev = p_n)
|
||||
{
|
||||
p_n = p_prev->m_next;
|
||||
if(p_n->m_rtEventTime > pPacket->m_rtEventTime)
|
||||
break;
|
||||
}
|
||||
|
||||
// If p_prev == pPacket then we're already in the right place
|
||||
if(p_prev != pPacket)
|
||||
{
|
||||
head.m_next = pPacket->m_next;
|
||||
(p_prev->m_next = pPacket)->m_next = p_n;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
DbgLog((LOG_TIMING, 2, TEXT("Periodic advise %lu, shunted to %lu"),
|
||||
pPacket->m_dwAdviseCookie, (pPacket->m_rtEventTime / (UNITS / MILLISECONDS)) ));
|
||||
#endif
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void CAMSchedule::DumpLinkedList() {
|
||||
m_Serialize.Lock();
|
||||
int i=0;
|
||||
DbgLog((LOG_TIMING, 1, TEXT("CAMSchedule::DumpLinkedList() this = 0x%p"), this));
|
||||
for(CAdvisePacket * p = &head
|
||||
; p
|
||||
; p = p->m_next , i++) {
|
||||
DbgLog((LOG_TIMING, 1, TEXT("Advise List # %lu, Cookie %d, RefTime %lu"),
|
||||
i,
|
||||
p->m_dwAdviseCookie,
|
||||
p->m_rtEventTime / (UNITS / MILLISECONDS)
|
||||
));
|
||||
}
|
||||
m_Serialize.Unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+83
-83
@@ -1,83 +1,83 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SeekPT.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include "seekpt.h"
|
||||
|
||||
//==================================================================
|
||||
// CreateInstance
|
||||
// This goes in the factory template table to create new instances
|
||||
// If there is already a mapper instance - return that, else make one
|
||||
// and save it in a static variable so that forever after we can return that.
|
||||
//==================================================================
|
||||
|
||||
CUnknown * CSeekingPassThru::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
|
||||
{
|
||||
return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
if (riid == IID_ISeekingPassThru) {
|
||||
return GetInterface((ISeekingPassThru *) this, ppv);
|
||||
} else {
|
||||
if (m_pPosPassThru &&
|
||||
(riid == IID_IMediaSeeking ||
|
||||
riid == IID_IMediaPosition)) {
|
||||
return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr )
|
||||
: CUnknown(pName, pUnk, phr),
|
||||
m_pPosPassThru(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CSeekingPassThru::~CSeekingPassThru()
|
||||
{
|
||||
delete m_pPosPassThru;
|
||||
}
|
||||
|
||||
STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin)
|
||||
{
|
||||
HRESULT hr = NOERROR;
|
||||
if (m_pPosPassThru) {
|
||||
hr = E_FAIL;
|
||||
} else {
|
||||
m_pPosPassThru =
|
||||
bRendererSeeking ?
|
||||
new CRendererPosPassThru(
|
||||
NAME("Render Seeking COM object"),
|
||||
(IUnknown *)this,
|
||||
&hr,
|
||||
pPin) :
|
||||
new CPosPassThru(
|
||||
NAME("Render Seeking COM object"),
|
||||
(IUnknown *)this,
|
||||
&hr,
|
||||
pPin);
|
||||
if (!m_pPosPassThru) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
} else {
|
||||
if (FAILED(hr)) {
|
||||
delete m_pPosPassThru;
|
||||
m_pPosPassThru = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SeekPT.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include "seekpt.h"
|
||||
|
||||
//==================================================================
|
||||
// CreateInstance
|
||||
// This goes in the factory template table to create new instances
|
||||
// If there is already a mapper instance - return that, else make one
|
||||
// and save it in a static variable so that forever after we can return that.
|
||||
//==================================================================
|
||||
|
||||
CUnknown * CSeekingPassThru::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
|
||||
{
|
||||
return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
|
||||
{
|
||||
if (riid == IID_ISeekingPassThru) {
|
||||
return GetInterface((ISeekingPassThru *) this, ppv);
|
||||
} else {
|
||||
if (m_pPosPassThru &&
|
||||
(riid == IID_IMediaSeeking ||
|
||||
riid == IID_IMediaPosition)) {
|
||||
return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv);
|
||||
} else {
|
||||
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CSeekingPassThru::CSeekingPassThru( TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr )
|
||||
: CUnknown(pName, pUnk, phr),
|
||||
m_pPosPassThru(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CSeekingPassThru::~CSeekingPassThru()
|
||||
{
|
||||
delete m_pPosPassThru;
|
||||
}
|
||||
|
||||
STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin)
|
||||
{
|
||||
HRESULT hr = NOERROR;
|
||||
if (m_pPosPassThru) {
|
||||
hr = E_FAIL;
|
||||
} else {
|
||||
m_pPosPassThru =
|
||||
bRendererSeeking ?
|
||||
new CRendererPosPassThru(
|
||||
NAME("Render Seeking COM object"),
|
||||
(IUnknown *)this,
|
||||
&hr,
|
||||
pPin) :
|
||||
new CPosPassThru(
|
||||
NAME("Render Seeking COM object"),
|
||||
(IUnknown *)this,
|
||||
&hr,
|
||||
pPin);
|
||||
if (!m_pPosPassThru) {
|
||||
hr = E_OUTOFMEMORY;
|
||||
} else {
|
||||
if (FAILED(hr)) {
|
||||
delete m_pPosPassThru;
|
||||
m_pPosPassThru = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
+30
-30
@@ -1,30 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SeekPT.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __seekpt_h__
|
||||
#define __seekpt_h__
|
||||
|
||||
|
||||
class CSeekingPassThru : public ISeekingPassThru, public CUnknown
|
||||
{
|
||||
public:
|
||||
static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
|
||||
~CSeekingPassThru();
|
||||
|
||||
DECLARE_IUNKNOWN;
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
|
||||
|
||||
STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin);
|
||||
|
||||
private:
|
||||
CPosPassThru *m_pPosPassThru;
|
||||
};
|
||||
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SeekPT.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __seekpt_h__
|
||||
#define __seekpt_h__
|
||||
|
||||
|
||||
class CSeekingPassThru : public ISeekingPassThru, public CUnknown
|
||||
{
|
||||
public:
|
||||
static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
CSeekingPassThru(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
|
||||
~CSeekingPassThru();
|
||||
|
||||
DECLARE_IUNKNOWN;
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
|
||||
|
||||
STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin);
|
||||
|
||||
private:
|
||||
CPosPassThru *m_pPosPassThru;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+519
-519
File diff suppressed because it is too large
Load Diff
+172
-172
@@ -1,172 +1,172 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Source.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes to simplify creation of
|
||||
// ActiveX source filters that support continuous generation of data.
|
||||
// No support is provided for IMediaControl or IMediaPosition.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// Derive your source filter from CSource.
|
||||
// During construction either:
|
||||
// Create some CSourceStream objects to manage your pins
|
||||
// Provide the user with a means of doing so eg, an IPersistFile interface.
|
||||
//
|
||||
// CSource provides:
|
||||
// IBaseFilter interface management
|
||||
// IMediaFilter interface management, via CBaseFilter
|
||||
// Pin counting for CBaseFilter
|
||||
//
|
||||
// Derive a class from CSourceStream to manage your output pin types
|
||||
// Implement GetMediaType/1 to return the type you support. If you support multiple
|
||||
// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount.
|
||||
// Implement Fillbuffer() to put data into one buffer.
|
||||
//
|
||||
// CSourceStream provides:
|
||||
// IPin management via CBaseOutputPin
|
||||
// Worker thread management
|
||||
|
||||
#ifndef __CSOURCE__
|
||||
#define __CSOURCE__
|
||||
|
||||
class CSourceStream; // The class that will handle each pin
|
||||
|
||||
|
||||
//
|
||||
// CSource
|
||||
//
|
||||
// Override construction to provide a means of creating
|
||||
// CSourceStream derived objects - ie a way of creating pins.
|
||||
class CSource : public CBaseFilter {
|
||||
public:
|
||||
|
||||
CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
|
||||
CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
|
||||
#ifdef UNICODE
|
||||
CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
|
||||
CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
|
||||
#endif
|
||||
~CSource();
|
||||
|
||||
int GetPinCount(void);
|
||||
CBasePin *GetPin(int n);
|
||||
|
||||
// -- Utilities --
|
||||
|
||||
CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section
|
||||
|
||||
HRESULT AddPin(CSourceStream *);
|
||||
HRESULT RemovePin(CSourceStream *);
|
||||
|
||||
STDMETHODIMP FindPin(
|
||||
LPCWSTR Id,
|
||||
IPin ** ppPin
|
||||
);
|
||||
|
||||
int FindPinNumber(IPin *iPin);
|
||||
|
||||
protected:
|
||||
|
||||
int m_iPins; // The number of pins on this filter. Updated by CSourceStream
|
||||
// constructors & destructors.
|
||||
CSourceStream **m_paStreams; // the pins on this filter.
|
||||
|
||||
CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CSourceStream
|
||||
//
|
||||
// Use this class to manage a stream of data that comes from a
|
||||
// pin.
|
||||
// Uses a worker thread to put data on the pin.
|
||||
class CSourceStream : public CAMThread, public CBaseOutputPin {
|
||||
public:
|
||||
|
||||
CSourceStream(TCHAR *pObjectName,
|
||||
HRESULT *phr,
|
||||
CSource *pms,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CSourceStream(CHAR *pObjectName,
|
||||
HRESULT *phr,
|
||||
CSource *pms,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too.
|
||||
|
||||
protected:
|
||||
|
||||
CSource *m_pFilter; // The parent of this stream
|
||||
|
||||
// *
|
||||
// * Data Source
|
||||
// *
|
||||
// * The following three functions: FillBuffer, OnThreadCreate/Destroy, are
|
||||
// * called from within the ThreadProc. They are used in the creation of
|
||||
// * the media samples this pin will provide
|
||||
// *
|
||||
|
||||
// Override this to provide the worker thread a means
|
||||
// of processing a buffer
|
||||
virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE;
|
||||
|
||||
// Called as the thread is created/destroyed - use to perform
|
||||
// jobs such as start/stop streaming mode
|
||||
// If OnThreadCreate returns an error the thread will exit.
|
||||
virtual HRESULT OnThreadCreate(void) {return NOERROR;};
|
||||
virtual HRESULT OnThreadDestroy(void) {return NOERROR;};
|
||||
virtual HRESULT OnThreadStartPlay(void) {return NOERROR;};
|
||||
|
||||
// *
|
||||
// * Worker Thread
|
||||
// *
|
||||
|
||||
HRESULT Active(void); // Starts up the worker thread
|
||||
HRESULT Inactive(void); // Exits the worker thread.
|
||||
|
||||
public:
|
||||
// thread commands
|
||||
enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT};
|
||||
HRESULT Init(void) { return CallWorker(CMD_INIT); }
|
||||
HRESULT Exit(void) { return CallWorker(CMD_EXIT); }
|
||||
HRESULT Run(void) { return CallWorker(CMD_RUN); }
|
||||
HRESULT Pause(void) { return CallWorker(CMD_PAUSE); }
|
||||
HRESULT Stop(void) { return CallWorker(CMD_STOP); }
|
||||
|
||||
protected:
|
||||
Command GetRequest(void) { return (Command) CAMThread::GetRequest(); }
|
||||
BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); }
|
||||
|
||||
// override these if you want to add thread commands
|
||||
virtual DWORD ThreadProc(void); // the thread function
|
||||
|
||||
virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running
|
||||
|
||||
|
||||
// *
|
||||
// * AM_MEDIA_TYPE support
|
||||
// *
|
||||
|
||||
// If you support more than one media type then override these 2 functions
|
||||
virtual HRESULT CheckMediaType(const CMediaType *pMediaType);
|
||||
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); // List pos. 0-n
|
||||
|
||||
// If you support only one type then override this fn.
|
||||
// This will only be called by the default implementations
|
||||
// of CheckMediaType and GetMediaType(int, CMediaType*)
|
||||
// You must override this fn. or the above 2!
|
||||
virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;}
|
||||
|
||||
STDMETHODIMP QueryId(
|
||||
LPWSTR * Id
|
||||
);
|
||||
};
|
||||
|
||||
#endif // __CSOURCE__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Source.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes to simplify creation of
|
||||
// ActiveX source filters that support continuous generation of data.
|
||||
// No support is provided for IMediaControl or IMediaPosition.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// Derive your source filter from CSource.
|
||||
// During construction either:
|
||||
// Create some CSourceStream objects to manage your pins
|
||||
// Provide the user with a means of doing so eg, an IPersistFile interface.
|
||||
//
|
||||
// CSource provides:
|
||||
// IBaseFilter interface management
|
||||
// IMediaFilter interface management, via CBaseFilter
|
||||
// Pin counting for CBaseFilter
|
||||
//
|
||||
// Derive a class from CSourceStream to manage your output pin types
|
||||
// Implement GetMediaType/1 to return the type you support. If you support multiple
|
||||
// types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount.
|
||||
// Implement Fillbuffer() to put data into one buffer.
|
||||
//
|
||||
// CSourceStream provides:
|
||||
// IPin management via CBaseOutputPin
|
||||
// Worker thread management
|
||||
|
||||
#ifndef __CSOURCE__
|
||||
#define __CSOURCE__
|
||||
|
||||
class CSourceStream; // The class that will handle each pin
|
||||
|
||||
|
||||
//
|
||||
// CSource
|
||||
//
|
||||
// Override construction to provide a means of creating
|
||||
// CSourceStream derived objects - ie a way of creating pins.
|
||||
class CSource : public CBaseFilter {
|
||||
public:
|
||||
|
||||
CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
|
||||
CSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
|
||||
#ifdef UNICODE
|
||||
CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
|
||||
CSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid);
|
||||
#endif
|
||||
~CSource();
|
||||
|
||||
int GetPinCount(void);
|
||||
CBasePin *GetPin(int n);
|
||||
|
||||
// -- Utilities --
|
||||
|
||||
CCritSec* pStateLock(void) { return &m_cStateLock; } // provide our critical section
|
||||
|
||||
HRESULT AddPin(CSourceStream *);
|
||||
HRESULT RemovePin(CSourceStream *);
|
||||
|
||||
STDMETHODIMP FindPin(
|
||||
LPCWSTR Id,
|
||||
IPin ** ppPin
|
||||
);
|
||||
|
||||
int FindPinNumber(IPin *iPin);
|
||||
|
||||
protected:
|
||||
|
||||
int m_iPins; // The number of pins on this filter. Updated by CSourceStream
|
||||
// constructors & destructors.
|
||||
CSourceStream **m_paStreams; // the pins on this filter.
|
||||
|
||||
CCritSec m_cStateLock; // Lock this to serialize function accesses to the filter state
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// CSourceStream
|
||||
//
|
||||
// Use this class to manage a stream of data that comes from a
|
||||
// pin.
|
||||
// Uses a worker thread to put data on the pin.
|
||||
class CSourceStream : public CAMThread, public CBaseOutputPin {
|
||||
public:
|
||||
|
||||
CSourceStream(TCHAR *pObjectName,
|
||||
HRESULT *phr,
|
||||
CSource *pms,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CSourceStream(CHAR *pObjectName,
|
||||
HRESULT *phr,
|
||||
CSource *pms,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
virtual ~CSourceStream(void); // virtual destructor ensures derived class destructors are called too.
|
||||
|
||||
protected:
|
||||
|
||||
CSource *m_pFilter; // The parent of this stream
|
||||
|
||||
// *
|
||||
// * Data Source
|
||||
// *
|
||||
// * The following three functions: FillBuffer, OnThreadCreate/Destroy, are
|
||||
// * called from within the ThreadProc. They are used in the creation of
|
||||
// * the media samples this pin will provide
|
||||
// *
|
||||
|
||||
// Override this to provide the worker thread a means
|
||||
// of processing a buffer
|
||||
virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE;
|
||||
|
||||
// Called as the thread is created/destroyed - use to perform
|
||||
// jobs such as start/stop streaming mode
|
||||
// If OnThreadCreate returns an error the thread will exit.
|
||||
virtual HRESULT OnThreadCreate(void) {return NOERROR;};
|
||||
virtual HRESULT OnThreadDestroy(void) {return NOERROR;};
|
||||
virtual HRESULT OnThreadStartPlay(void) {return NOERROR;};
|
||||
|
||||
// *
|
||||
// * Worker Thread
|
||||
// *
|
||||
|
||||
HRESULT Active(void); // Starts up the worker thread
|
||||
HRESULT Inactive(void); // Exits the worker thread.
|
||||
|
||||
public:
|
||||
// thread commands
|
||||
enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT};
|
||||
HRESULT Init(void) { return CallWorker(CMD_INIT); }
|
||||
HRESULT Exit(void) { return CallWorker(CMD_EXIT); }
|
||||
HRESULT Run(void) { return CallWorker(CMD_RUN); }
|
||||
HRESULT Pause(void) { return CallWorker(CMD_PAUSE); }
|
||||
HRESULT Stop(void) { return CallWorker(CMD_STOP); }
|
||||
|
||||
protected:
|
||||
Command GetRequest(void) { return (Command) CAMThread::GetRequest(); }
|
||||
BOOL CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); }
|
||||
|
||||
// override these if you want to add thread commands
|
||||
virtual DWORD ThreadProc(void); // the thread function
|
||||
|
||||
virtual HRESULT DoBufferProcessingLoop(void); // the loop executed whilst running
|
||||
|
||||
|
||||
// *
|
||||
// * AM_MEDIA_TYPE support
|
||||
// *
|
||||
|
||||
// If you support more than one media type then override these 2 functions
|
||||
virtual HRESULT CheckMediaType(const CMediaType *pMediaType);
|
||||
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); // List pos. 0-n
|
||||
|
||||
// If you support only one type then override this fn.
|
||||
// This will only be called by the default implementations
|
||||
// of CheckMediaType and GetMediaType(int, CMediaType*)
|
||||
// You must override this fn. or the above 2!
|
||||
virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;}
|
||||
|
||||
STDMETHODIMP QueryId(
|
||||
LPWSTR * Id
|
||||
);
|
||||
};
|
||||
|
||||
#endif // __CSOURCE__
|
||||
|
||||
|
||||
+172
-172
@@ -1,172 +1,172 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Streams.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines overall streams architecture.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __STREAMS__
|
||||
#define __STREAMS__
|
||||
|
||||
// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable
|
||||
#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter
|
||||
#pragma warning(disable:4127) // warning C4127: conditional expression is constant
|
||||
#pragma warning(disable:4189) // warning C4189: local variable is initialized but not referenced
|
||||
#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
|
||||
#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated
|
||||
#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated
|
||||
#pragma warning(disable:4514) // warning C4514: unreferenced inline function has been removed
|
||||
#pragma warning(disable:4710) // warning C4710: 'function' not inlined
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER>=1100
|
||||
#define AM_NOVTABLE __declspec(novtable)
|
||||
#else
|
||||
#define AM_NOVTABLE
|
||||
#endif
|
||||
#endif // MSC_VER
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <olectl.h>
|
||||
#include <ddraw.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#ifndef NUMELMS
|
||||
#define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The following definitions come from the Platform SDK and are required if
|
||||
// the applicaiton is being compiled with the headers from Visual C++ 6.0.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#ifndef InterlockedExchangePointer
|
||||
#define InterlockedExchangePointer(Target, Value) \
|
||||
(PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
|
||||
#endif
|
||||
|
||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||
#define _WAVEFORMATEXTENSIBLE_
|
||||
typedef struct {
|
||||
WAVEFORMATEX Format;
|
||||
union {
|
||||
WORD wValidBitsPerSample; /* bits of precision */
|
||||
WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
|
||||
WORD wReserved; /* If neither applies, set to zero. */
|
||||
} Samples;
|
||||
DWORD dwChannelMask; /* which channels are */
|
||||
/* present in stream */
|
||||
GUID SubFormat;
|
||||
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
|
||||
#endif // !_WAVEFORMATEXTENSIBLE_
|
||||
|
||||
#if !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
|
||||
#endif // !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
|
||||
#ifndef GetWindowLongPtr
|
||||
#define GetWindowLongPtrA GetWindowLongA
|
||||
#define GetWindowLongPtrW GetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define GetWindowLongPtr GetWindowLongPtrW
|
||||
#else
|
||||
#define GetWindowLongPtr GetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
#endif // !GetWindowLongPtr
|
||||
|
||||
#ifndef SetWindowLongPtr
|
||||
#define SetWindowLongPtrA SetWindowLongA
|
||||
#define SetWindowLongPtrW SetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define SetWindowLongPtr SetWindowLongPtrW
|
||||
#else
|
||||
#define SetWindowLongPtr SetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
#endif // !SetWindowLongPtr
|
||||
|
||||
#ifndef GWLP_WNDPROC
|
||||
#define GWLP_WNDPROC (-4)
|
||||
#endif
|
||||
#ifndef GWLP_HINSTANCE
|
||||
#define GWLP_HINSTANCE (-6)
|
||||
#endif
|
||||
#ifndef GWLP_HWNDPARENT
|
||||
#define GWLP_HWNDPARENT (-8)
|
||||
#endif
|
||||
#ifndef GWLP_USERDATA
|
||||
#define GWLP_USERDATA (-21)
|
||||
#endif
|
||||
#ifndef GWLP_ID
|
||||
#define GWLP_ID (-12)
|
||||
#endif
|
||||
#ifndef DWLP_MSGRESULT
|
||||
#define DWLP_MSGRESULT 0
|
||||
#endif
|
||||
#ifndef DWLP_DLGPROC
|
||||
#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT)
|
||||
#endif
|
||||
#ifndef DWLP_USER
|
||||
#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC)
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// End Platform SDK definitions
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
|
||||
#include <strmif.h> // Generated IDL header file for streams interfaces
|
||||
|
||||
//
|
||||
// Modified by Chris to look in local baseclasses directory instead of include path
|
||||
//
|
||||
#include "baseclasses/reftime.h" // Helper class for REFERENCE_TIME management
|
||||
#include "baseclasses/wxdebug.h" // Debug support for logging and ASSERTs
|
||||
#include "baseclasses/amvideo.h" // ActiveMovie video interfaces and definitions
|
||||
|
||||
//include amaudio.h explicitly if you need it. it requires the DX SDK.
|
||||
//#include <amaudio.h> // ActiveMovie audio interfaces and definitions
|
||||
|
||||
#include "baseclasses/wxutil.h" // General helper classes for threads etc
|
||||
#include "baseclasses/combase.h" // Base COM classes to support IUnknown
|
||||
#include "baseclasses/dllsetup.h" // Filter registration support functions
|
||||
#include "baseclasses/measure.h" // Performance measurement
|
||||
#include <comlite.h> // Light weight com function prototypes
|
||||
|
||||
#include "baseclasses/cache.h" // Simple cache container class
|
||||
#include "baseclasses/wxlist.h" // Non MFC generic list class
|
||||
#include "baseclasses/msgthrd.h" // CMsgThread
|
||||
#include "baseclasses/mtype.h" // Helper class for managing media types
|
||||
#include "baseclasses/fourcc.h" // conversions between FOURCCs and GUIDs
|
||||
#include <control.h> // generated from control.odl
|
||||
#include "baseclasses/ctlutil.h" // control interface utility classes
|
||||
#include <evcode.h> // event code definitions
|
||||
#include "baseclasses/amfilter.h" // Main streams architecture class hierachy
|
||||
#include "baseclasses/transfrm.h" // Generic transform filter
|
||||
#include "baseclasses/transip.h" // Generic transform-in-place filter
|
||||
#include <uuids.h> // declaration of type GUIDs and well-known clsids
|
||||
#include "baseclasses/source.h" // Generic source filter
|
||||
#include "baseclasses/outputq.h" // Output pin queueing
|
||||
#include <errors.h> // HRESULT status and error definitions
|
||||
#include "baseclasses/renbase.h" // Base class for writing ActiveX renderers
|
||||
#include "baseclasses/winutil.h" // Helps with filters that manage windows
|
||||
#include "baseclasses/winctrl.h" // Implements the IVideoWindow interface
|
||||
#include "baseclasses/videoctl.h" // Specifically video related classes
|
||||
#include "baseclasses/refclock.h" // Base clock class
|
||||
#include "baseclasses/sysclock.h" // System clock
|
||||
#include "baseclasses/pstream.h" // IPersistStream helper class
|
||||
#include "baseclasses/vtrans.h" // Video Transform Filter base class
|
||||
#include "baseclasses/amextra.h"
|
||||
#include "baseclasses/cprop.h" // Base property page class
|
||||
#include "baseclasses/strmctl.h" // IAMStreamControl support
|
||||
#include <edevdefs.h> // External device control interface defines
|
||||
#include <audevcod.h> // audio filter device error event codes
|
||||
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
#pragma message("STREAMS.H included TWICE")
|
||||
#endif
|
||||
#endif // __STREAMS__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Streams.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines overall streams architecture.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __STREAMS__
|
||||
#define __STREAMS__
|
||||
|
||||
// disable some level-4 warnings, use #pragma warning(enable:###) to re-enable
|
||||
#pragma warning(disable:4100) // warning C4100: unreferenced formal parameter
|
||||
#pragma warning(disable:4127) // warning C4127: conditional expression is constant
|
||||
#pragma warning(disable:4189) // warning C4189: local variable is initialized but not referenced
|
||||
#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
|
||||
#pragma warning(disable:4511) // warning C4511: copy constructor could not be generated
|
||||
#pragma warning(disable:4512) // warning C4512: assignment operator could not be generated
|
||||
#pragma warning(disable:4514) // warning C4514: unreferenced inline function has been removed
|
||||
#pragma warning(disable:4710) // warning C4710: 'function' not inlined
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER>=1100
|
||||
#define AM_NOVTABLE __declspec(novtable)
|
||||
#else
|
||||
#define AM_NOVTABLE
|
||||
#endif
|
||||
#endif // MSC_VER
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <olectl.h>
|
||||
#include <ddraw.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#ifndef NUMELMS
|
||||
#define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// The following definitions come from the Platform SDK and are required if
|
||||
// the applicaiton is being compiled with the headers from Visual C++ 6.0.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
#ifndef InterlockedExchangePointer
|
||||
#define InterlockedExchangePointer(Target, Value) \
|
||||
(PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
|
||||
#endif
|
||||
|
||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||
#define _WAVEFORMATEXTENSIBLE_
|
||||
typedef struct {
|
||||
WAVEFORMATEX Format;
|
||||
union {
|
||||
WORD wValidBitsPerSample; /* bits of precision */
|
||||
WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
|
||||
WORD wReserved; /* If neither applies, set to zero. */
|
||||
} Samples;
|
||||
DWORD dwChannelMask; /* which channels are */
|
||||
/* present in stream */
|
||||
GUID SubFormat;
|
||||
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
|
||||
#endif // !_WAVEFORMATEXTENSIBLE_
|
||||
|
||||
#if !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
|
||||
#endif // !defined(WAVE_FORMAT_EXTENSIBLE)
|
||||
|
||||
#ifndef GetWindowLongPtr
|
||||
#define GetWindowLongPtrA GetWindowLongA
|
||||
#define GetWindowLongPtrW GetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define GetWindowLongPtr GetWindowLongPtrW
|
||||
#else
|
||||
#define GetWindowLongPtr GetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
#endif // !GetWindowLongPtr
|
||||
|
||||
#ifndef SetWindowLongPtr
|
||||
#define SetWindowLongPtrA SetWindowLongA
|
||||
#define SetWindowLongPtrW SetWindowLongW
|
||||
#ifdef UNICODE
|
||||
#define SetWindowLongPtr SetWindowLongPtrW
|
||||
#else
|
||||
#define SetWindowLongPtr SetWindowLongPtrA
|
||||
#endif // !UNICODE
|
||||
#endif // !SetWindowLongPtr
|
||||
|
||||
#ifndef GWLP_WNDPROC
|
||||
#define GWLP_WNDPROC (-4)
|
||||
#endif
|
||||
#ifndef GWLP_HINSTANCE
|
||||
#define GWLP_HINSTANCE (-6)
|
||||
#endif
|
||||
#ifndef GWLP_HWNDPARENT
|
||||
#define GWLP_HWNDPARENT (-8)
|
||||
#endif
|
||||
#ifndef GWLP_USERDATA
|
||||
#define GWLP_USERDATA (-21)
|
||||
#endif
|
||||
#ifndef GWLP_ID
|
||||
#define GWLP_ID (-12)
|
||||
#endif
|
||||
#ifndef DWLP_MSGRESULT
|
||||
#define DWLP_MSGRESULT 0
|
||||
#endif
|
||||
#ifndef DWLP_DLGPROC
|
||||
#define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT)
|
||||
#endif
|
||||
#ifndef DWLP_USER
|
||||
#define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC)
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// End Platform SDK definitions
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
|
||||
#include <strmif.h> // Generated IDL header file for streams interfaces
|
||||
|
||||
//
|
||||
// Modified by Chris to look in local baseclasses directory instead of include path
|
||||
//
|
||||
#include "baseclasses/reftime.h" // Helper class for REFERENCE_TIME management
|
||||
#include "baseclasses/wxdebug.h" // Debug support for logging and ASSERTs
|
||||
#include "baseclasses/amvideo.h" // ActiveMovie video interfaces and definitions
|
||||
|
||||
//include amaudio.h explicitly if you need it. it requires the DX SDK.
|
||||
//#include <amaudio.h> // ActiveMovie audio interfaces and definitions
|
||||
|
||||
#include "baseclasses/wxutil.h" // General helper classes for threads etc
|
||||
#include "baseclasses/combase.h" // Base COM classes to support IUnknown
|
||||
#include "baseclasses/dllsetup.h" // Filter registration support functions
|
||||
#include "baseclasses/measure.h" // Performance measurement
|
||||
#include <comlite.h> // Light weight com function prototypes
|
||||
|
||||
#include "baseclasses/cache.h" // Simple cache container class
|
||||
#include "baseclasses/wxlist.h" // Non MFC generic list class
|
||||
#include "baseclasses/msgthrd.h" // CMsgThread
|
||||
#include "baseclasses/mtype.h" // Helper class for managing media types
|
||||
#include "baseclasses/fourcc.h" // conversions between FOURCCs and GUIDs
|
||||
#include <control.h> // generated from control.odl
|
||||
#include "baseclasses/ctlutil.h" // control interface utility classes
|
||||
#include <evcode.h> // event code definitions
|
||||
#include "baseclasses/amfilter.h" // Main streams architecture class hierachy
|
||||
#include "baseclasses/transfrm.h" // Generic transform filter
|
||||
#include "baseclasses/transip.h" // Generic transform-in-place filter
|
||||
#include <uuids.h> // declaration of type GUIDs and well-known clsids
|
||||
#include "baseclasses/source.h" // Generic source filter
|
||||
#include "baseclasses/outputq.h" // Output pin queueing
|
||||
#include <errors.h> // HRESULT status and error definitions
|
||||
#include "baseclasses/renbase.h" // Base class for writing ActiveX renderers
|
||||
#include "baseclasses/winutil.h" // Helps with filters that manage windows
|
||||
#include "baseclasses/winctrl.h" // Implements the IVideoWindow interface
|
||||
#include "baseclasses/videoctl.h" // Specifically video related classes
|
||||
#include "baseclasses/refclock.h" // Base clock class
|
||||
#include "baseclasses/sysclock.h" // System clock
|
||||
#include "baseclasses/pstream.h" // IPersistStream helper class
|
||||
#include "baseclasses/vtrans.h" // Video Transform Filter base class
|
||||
#include "baseclasses/amextra.h"
|
||||
#include "baseclasses/cprop.h" // Base property page class
|
||||
#include "baseclasses/strmctl.h" // IAMStreamControl support
|
||||
#include <edevdefs.h> // External device control interface defines
|
||||
#include <audevcod.h> // audio filter device error event codes
|
||||
|
||||
#else
|
||||
#ifdef DEBUG
|
||||
#pragma message("STREAMS.H included TWICE")
|
||||
#endif
|
||||
#endif // __STREAMS__
|
||||
|
||||
|
||||
+386
-386
@@ -1,386 +1,386 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: StrmCtl.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <strmctl.h>
|
||||
|
||||
CBaseStreamControl::CBaseStreamControl()
|
||||
: m_StreamState(STREAM_FLOWING)
|
||||
, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop
|
||||
, m_tStartTime(MAX_TIME)
|
||||
, m_tStopTime(MAX_TIME)
|
||||
, m_dwStartCookie(0)
|
||||
, m_dwStopCookie(0)
|
||||
, m_pRefClock(NULL)
|
||||
, m_FilterState(State_Stopped)
|
||||
, m_bIsFlushing(FALSE)
|
||||
, m_bStopSendExtra(FALSE) {
|
||||
}
|
||||
|
||||
CBaseStreamControl::~CBaseStreamControl() {
|
||||
// Make sure we release the clock.
|
||||
SetSyncSource(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
m_bStopSendExtra = FALSE; // reset
|
||||
m_bStopExtraSent = FALSE;
|
||||
if(ptStop) {
|
||||
if(*ptStop == MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop")));
|
||||
CancelStop();
|
||||
// If there's now a command to start in the future, we assume
|
||||
// they want to be stopped when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) {
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"),
|
||||
(int)(*ptStop/10000), bSendExtra));
|
||||
// if the first command is to stop in the future, then we assume they
|
||||
// want to be started when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStartTime > *ptStop) {
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
|
||||
}
|
||||
m_bStopSendExtra = bSendExtra;
|
||||
m_tStopTime = *ptStop;
|
||||
m_dwStopCookie = dwCookie;
|
||||
m_StreamStateOnStop = STREAM_DISCARDING;
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: now")));
|
||||
// sending an extra frame when told to stop now would mess people up
|
||||
m_bStopSendExtra = FALSE;
|
||||
m_tStopTime = MAX_TIME;
|
||||
m_dwStopCookie = 0;
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
m_StreamStateOnStop = STREAM_FLOWING; // no pending stop
|
||||
}
|
||||
// we might change our mind what to do with a sample we're blocking
|
||||
m_StreamEvent.Set();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseStreamControl::StartAt
|
||||
( const REFERENCE_TIME *ptStart, DWORD dwCookie ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
if(ptStart) {
|
||||
if(*ptStart == MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start")));
|
||||
CancelStart();
|
||||
// If there's now a command to stop in the future, we assume
|
||||
// they want to be started when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000)));
|
||||
// if the first command is to start in the future, then we assume they
|
||||
// want to be stopped when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStopTime >= *ptStart) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
}
|
||||
m_tStartTime = *ptStart;
|
||||
m_dwStartCookie = dwCookie;
|
||||
// if (m_tStopTime == m_tStartTime) CancelStop();
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: now")));
|
||||
m_tStartTime = MAX_TIME;
|
||||
m_dwStartCookie = 0;
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
}
|
||||
// we might change our mind what to do with a sample we're blocking
|
||||
m_StreamEvent.Set();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Retrieve information about current settings
|
||||
STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo) {
|
||||
if(pInfo == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
pInfo->tStart = m_tStartTime;
|
||||
pInfo->tStop = m_tStopTime;
|
||||
pInfo->dwStartCookie = m_dwStartCookie;
|
||||
pInfo->dwStopCookie = m_dwStopCookie;
|
||||
pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0;
|
||||
pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED;
|
||||
pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED;
|
||||
switch(m_StreamState) {
|
||||
default:
|
||||
DbgBreak("Invalid stream state");
|
||||
case STREAM_FLOWING:
|
||||
break;
|
||||
case STREAM_DISCARDING:
|
||||
pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING;
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::ExecuteStop() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_StreamState = m_StreamStateOnStop;
|
||||
if(m_dwStopCookie && m_pSink) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"),
|
||||
m_dwStopCookie));
|
||||
m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie);
|
||||
}
|
||||
CancelStop(); // This will do the tidy up
|
||||
}
|
||||
|
||||
void CBaseStreamControl::ExecuteStart() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
if(m_dwStartCookie) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"),
|
||||
m_dwStartCookie));
|
||||
m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie);
|
||||
}
|
||||
CancelStart(); // This will do the tidy up
|
||||
}
|
||||
|
||||
void CBaseStreamControl::CancelStop() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_tStopTime = MAX_TIME;
|
||||
m_dwStopCookie = 0;
|
||||
m_StreamStateOnStop = STREAM_FLOWING;
|
||||
}
|
||||
|
||||
void CBaseStreamControl::CancelStart() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_tStartTime = MAX_TIME;
|
||||
m_dwStartCookie = 0;
|
||||
}
|
||||
|
||||
|
||||
// This guy will return one of the three StreamControlState's. Here's what the caller
|
||||
// should do for each one:
|
||||
//
|
||||
// STREAM_FLOWING: Proceed as usual (render or pass the sample on)
|
||||
// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long
|
||||
// for the event handle (GetStreamEventHandle()). If the
|
||||
// wait expires, throw the sample away. If the event
|
||||
// fires, call me back, I've changed my mind.
|
||||
// I use pSampleStart (not Stop) so that live sources don't
|
||||
// block for the duration of their samples, since the clock
|
||||
// will always read approximately pSampleStart when called
|
||||
|
||||
|
||||
// All through this code, you'll notice the following rules:
|
||||
// - When start and stop time are the same, it's as if start was first
|
||||
// - An event is considered inside the sample when it's >= sample start time
|
||||
// but < sample stop time
|
||||
// - if any part of the sample is supposed to be sent, we'll send the whole
|
||||
// thing since we don't break it into smaller pieces
|
||||
// - If we skip over a start or stop without doing it, we still signal the event
|
||||
// and reset ourselves in case somebody's waiting for the event, and to make
|
||||
// sure we notice that the event is past and should be forgotten
|
||||
// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample):
|
||||
//
|
||||
// 1. xo<--> start then stop
|
||||
// 2. ox<--> stop then start
|
||||
// 3. x<o-> start
|
||||
// 4. o<x-> stop then start
|
||||
// 5. x<-->o start
|
||||
// 6. o<-->x stop
|
||||
// 7. <x->o start
|
||||
// 8. <o->x no change
|
||||
// 9. <xo> start
|
||||
// 10. <ox> stop then start
|
||||
// 11. <-->xo no change
|
||||
// 12. <-->ox no change
|
||||
// 13. x<--> start
|
||||
// 14. <x-> start
|
||||
// 15. <-->x no change
|
||||
// 16. o<--> stop
|
||||
// 17. <o-> no change
|
||||
// 18. <-->o no change
|
||||
// 19. <--> no change
|
||||
|
||||
|
||||
enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes
|
||||
( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
|
||||
ASSERT(!m_bIsFlushing);
|
||||
ASSERT(pSampleStart && pSampleStop);
|
||||
|
||||
// Don't ask how I came up with the code below to handle all 19 cases...
|
||||
if(m_tStopTime >= *pSampleStart) {
|
||||
if(m_tStartTime >= *pSampleStop)
|
||||
return m_StreamState; // cases 8 11 12 15 17 18 19
|
||||
|
||||
if(m_tStopTime < m_tStartTime)
|
||||
ExecuteStop(); // case 10
|
||||
|
||||
ExecuteStart(); // cases 3 5 7 9 13 14
|
||||
return m_StreamState;
|
||||
}
|
||||
|
||||
if(m_tStartTime >= *pSampleStop) {
|
||||
ExecuteStop(); // cases 6 16
|
||||
return m_StreamState;
|
||||
}
|
||||
|
||||
if(m_tStartTime <= m_tStopTime) {
|
||||
ExecuteStart();
|
||||
ExecuteStop();
|
||||
}
|
||||
else {
|
||||
ExecuteStop();
|
||||
ExecuteStart();
|
||||
}
|
||||
|
||||
return m_StreamState; // case 1, 2, or 4
|
||||
}
|
||||
|
||||
|
||||
enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) {
|
||||
|
||||
REFERENCE_TIME rtBufferStart, rtBufferStop;
|
||||
const BOOL bNoBufferTimes =
|
||||
pSample == NULL ||
|
||||
FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop));
|
||||
|
||||
StreamControlState state;
|
||||
LONG lWait;
|
||||
|
||||
do {
|
||||
// something has to break out of the blocking
|
||||
if(m_bIsFlushing || m_FilterState == State_Stopped)
|
||||
return STREAM_DISCARDING;
|
||||
|
||||
if(bNoBufferTimes) {
|
||||
// Can't do anything until we get a time stamp
|
||||
state = m_StreamState;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
state = CheckSampleTimes(&rtBufferStart, &rtBufferStop);
|
||||
if(state == STREAM_FLOWING)
|
||||
break;
|
||||
|
||||
// we aren't supposed to send this, but we've been
|
||||
// told to send one more than we were supposed to
|
||||
// (and the stop isn't still pending and we're streaming)
|
||||
if(m_bStopSendExtra && !m_bStopExtraSent &&
|
||||
m_tStopTime == MAX_TIME &&
|
||||
m_FilterState != State_Stopped) {
|
||||
m_bStopExtraSent = TRUE;
|
||||
DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"),
|
||||
m_dwStopCookie));
|
||||
state = STREAM_FLOWING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We're in discarding mode
|
||||
|
||||
// If we've no clock, discard as fast as we can
|
||||
if(!m_pRefClock) {
|
||||
break;
|
||||
|
||||
// If we're paused, we can't discard in a timely manner because
|
||||
// there's no such thing as stream times. We must block until
|
||||
// we run or stop, or we'll end up throwing the whole stream away
|
||||
// as quickly as possible
|
||||
}
|
||||
else if(m_FilterState == State_Paused) {
|
||||
lWait = INFINITE;
|
||||
|
||||
}
|
||||
else {
|
||||
// wait until it's time for the sample until we say "discard"
|
||||
// ("discard in a timely fashion")
|
||||
REFERENCE_TIME rtNow;
|
||||
EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow)));
|
||||
rtNow -= m_tRunStart; // Into relative ref-time
|
||||
lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms
|
||||
if(lWait < 10) break; // Not worth waiting - discard early
|
||||
}
|
||||
|
||||
} while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
|
||||
// or we will get confused
|
||||
if(m_FilterState == new_state)
|
||||
return;
|
||||
|
||||
switch(new_state) {
|
||||
case State_Stopped:
|
||||
|
||||
DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED")));
|
||||
|
||||
// execute any pending starts and stops in the right order,
|
||||
// to make sure all notifications get sent, and we end up
|
||||
// in the right state to begin next time (??? why not?)
|
||||
|
||||
if(m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) {
|
||||
ExecuteStart();
|
||||
}
|
||||
else if(m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) {
|
||||
ExecuteStop();
|
||||
}
|
||||
else if(m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) {
|
||||
if(m_tStartTime <= m_tStopTime) {
|
||||
ExecuteStart();
|
||||
ExecuteStop();
|
||||
}
|
||||
else {
|
||||
ExecuteStop();
|
||||
ExecuteStart();
|
||||
}
|
||||
}
|
||||
// always start off flowing when the graph starts streaming
|
||||
// unless told otherwise
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
m_FilterState = new_state;
|
||||
break;
|
||||
|
||||
case State_Running:
|
||||
|
||||
DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING")));
|
||||
|
||||
m_tRunStart = tStart;
|
||||
// fall-through
|
||||
|
||||
default: // case State_Paused:
|
||||
m_FilterState = new_state;
|
||||
}
|
||||
// unblock!
|
||||
m_StreamEvent.Set();
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::Flushing(BOOL bInProgress) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
m_bIsFlushing = bInProgress;
|
||||
m_StreamEvent.Set();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: StrmCtl.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <strmctl.h>
|
||||
|
||||
CBaseStreamControl::CBaseStreamControl()
|
||||
: m_StreamState(STREAM_FLOWING)
|
||||
, m_StreamStateOnStop(STREAM_FLOWING) // means no pending stop
|
||||
, m_tStartTime(MAX_TIME)
|
||||
, m_tStopTime(MAX_TIME)
|
||||
, m_dwStartCookie(0)
|
||||
, m_dwStopCookie(0)
|
||||
, m_pRefClock(NULL)
|
||||
, m_FilterState(State_Stopped)
|
||||
, m_bIsFlushing(FALSE)
|
||||
, m_bStopSendExtra(FALSE) {
|
||||
}
|
||||
|
||||
CBaseStreamControl::~CBaseStreamControl() {
|
||||
// Make sure we release the clock.
|
||||
SetSyncSource(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseStreamControl::StopAt(const REFERENCE_TIME * ptStop, BOOL bSendExtra, DWORD dwCookie) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
m_bStopSendExtra = FALSE; // reset
|
||||
m_bStopExtraSent = FALSE;
|
||||
if(ptStop) {
|
||||
if(*ptStop == MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: Cancel stop")));
|
||||
CancelStop();
|
||||
// If there's now a command to start in the future, we assume
|
||||
// they want to be stopped when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStartTime < MAX_TIME) {
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: %dms extra=%d"),
|
||||
(int)(*ptStop/10000), bSendExtra));
|
||||
// if the first command is to stop in the future, then we assume they
|
||||
// want to be started when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStartTime > *ptStop) {
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
|
||||
}
|
||||
m_bStopSendExtra = bSendExtra;
|
||||
m_tStopTime = *ptStop;
|
||||
m_dwStopCookie = dwCookie;
|
||||
m_StreamStateOnStop = STREAM_DISCARDING;
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StopAt: now")));
|
||||
// sending an extra frame when told to stop now would mess people up
|
||||
m_bStopSendExtra = FALSE;
|
||||
m_tStopTime = MAX_TIME;
|
||||
m_dwStopCookie = 0;
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
m_StreamStateOnStop = STREAM_FLOWING; // no pending stop
|
||||
}
|
||||
// we might change our mind what to do with a sample we're blocking
|
||||
m_StreamEvent.Set();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CBaseStreamControl::StartAt
|
||||
( const REFERENCE_TIME *ptStart, DWORD dwCookie ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
if(ptStart) {
|
||||
if(*ptStart == MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: Cancel start")));
|
||||
CancelStart();
|
||||
// If there's now a command to stop in the future, we assume
|
||||
// they want to be started when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStopTime < MAX_TIME) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by FLOWING")));
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: %dms"), (int)(*ptStart/10000)));
|
||||
// if the first command is to start in the future, then we assume they
|
||||
// want to be stopped when the graph is first run
|
||||
if(m_FilterState == State_Stopped && m_tStopTime >= *ptStart) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("graph will begin by DISCARDING")));
|
||||
m_StreamState = STREAM_DISCARDING;
|
||||
}
|
||||
m_tStartTime = *ptStart;
|
||||
m_dwStartCookie = dwCookie;
|
||||
// if (m_tStopTime == m_tStartTime) CancelStop();
|
||||
}
|
||||
else {
|
||||
DbgLog((LOG_TRACE,2,TEXT("StartAt: now")));
|
||||
m_tStartTime = MAX_TIME;
|
||||
m_dwStartCookie = 0;
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
}
|
||||
// we might change our mind what to do with a sample we're blocking
|
||||
m_StreamEvent.Set();
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Retrieve information about current settings
|
||||
STDMETHODIMP CBaseStreamControl::GetInfo(AM_STREAM_INFO *pInfo) {
|
||||
if(pInfo == NULL)
|
||||
return E_POINTER;
|
||||
|
||||
pInfo->tStart = m_tStartTime;
|
||||
pInfo->tStop = m_tStopTime;
|
||||
pInfo->dwStartCookie = m_dwStartCookie;
|
||||
pInfo->dwStopCookie = m_dwStopCookie;
|
||||
pInfo->dwFlags = m_bStopSendExtra ? AM_STREAM_INFO_STOP_SEND_EXTRA : 0;
|
||||
pInfo->dwFlags |= m_tStartTime == MAX_TIME ? 0 : AM_STREAM_INFO_START_DEFINED;
|
||||
pInfo->dwFlags |= m_tStopTime == MAX_TIME ? 0 : AM_STREAM_INFO_STOP_DEFINED;
|
||||
switch(m_StreamState) {
|
||||
default:
|
||||
DbgBreak("Invalid stream state");
|
||||
case STREAM_FLOWING:
|
||||
break;
|
||||
case STREAM_DISCARDING:
|
||||
pInfo->dwFlags |= AM_STREAM_INFO_DISCARDING;
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::ExecuteStop() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_StreamState = m_StreamStateOnStop;
|
||||
if(m_dwStopCookie && m_pSink) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STOPPED (%d)"),
|
||||
m_dwStopCookie));
|
||||
m_pSink->Notify(EC_STREAM_CONTROL_STOPPED, (LONG_PTR)this, m_dwStopCookie);
|
||||
}
|
||||
CancelStop(); // This will do the tidy up
|
||||
}
|
||||
|
||||
void CBaseStreamControl::ExecuteStart() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
if(m_dwStartCookie) {
|
||||
DbgLog((LOG_TRACE,2,TEXT("*sending EC_STREAM_CONTROL_STARTED (%d)"),
|
||||
m_dwStartCookie));
|
||||
m_pSink->Notify(EC_STREAM_CONTROL_STARTED, (LONG_PTR)this, m_dwStartCookie);
|
||||
}
|
||||
CancelStart(); // This will do the tidy up
|
||||
}
|
||||
|
||||
void CBaseStreamControl::CancelStop() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_tStopTime = MAX_TIME;
|
||||
m_dwStopCookie = 0;
|
||||
m_StreamStateOnStop = STREAM_FLOWING;
|
||||
}
|
||||
|
||||
void CBaseStreamControl::CancelStart() {
|
||||
ASSERT(CritCheckIn(&m_CritSec));
|
||||
m_tStartTime = MAX_TIME;
|
||||
m_dwStartCookie = 0;
|
||||
}
|
||||
|
||||
|
||||
// This guy will return one of the three StreamControlState's. Here's what the caller
|
||||
// should do for each one:
|
||||
//
|
||||
// STREAM_FLOWING: Proceed as usual (render or pass the sample on)
|
||||
// STREAM_DISCARDING: Calculate the time 'til *pSampleStart and wait that long
|
||||
// for the event handle (GetStreamEventHandle()). If the
|
||||
// wait expires, throw the sample away. If the event
|
||||
// fires, call me back, I've changed my mind.
|
||||
// I use pSampleStart (not Stop) so that live sources don't
|
||||
// block for the duration of their samples, since the clock
|
||||
// will always read approximately pSampleStart when called
|
||||
|
||||
|
||||
// All through this code, you'll notice the following rules:
|
||||
// - When start and stop time are the same, it's as if start was first
|
||||
// - An event is considered inside the sample when it's >= sample start time
|
||||
// but < sample stop time
|
||||
// - if any part of the sample is supposed to be sent, we'll send the whole
|
||||
// thing since we don't break it into smaller pieces
|
||||
// - If we skip over a start or stop without doing it, we still signal the event
|
||||
// and reset ourselves in case somebody's waiting for the event, and to make
|
||||
// sure we notice that the event is past and should be forgotten
|
||||
// Here are the 19 cases that have to be handled (x=start o=stop <-->=sample):
|
||||
//
|
||||
// 1. xo<--> start then stop
|
||||
// 2. ox<--> stop then start
|
||||
// 3. x<o-> start
|
||||
// 4. o<x-> stop then start
|
||||
// 5. x<-->o start
|
||||
// 6. o<-->x stop
|
||||
// 7. <x->o start
|
||||
// 8. <o->x no change
|
||||
// 9. <xo> start
|
||||
// 10. <ox> stop then start
|
||||
// 11. <-->xo no change
|
||||
// 12. <-->ox no change
|
||||
// 13. x<--> start
|
||||
// 14. <x-> start
|
||||
// 15. <-->x no change
|
||||
// 16. o<--> stop
|
||||
// 17. <o-> no change
|
||||
// 18. <-->o no change
|
||||
// 19. <--> no change
|
||||
|
||||
|
||||
enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckSampleTimes
|
||||
( const REFERENCE_TIME * pSampleStart, const REFERENCE_TIME * pSampleStop ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
|
||||
ASSERT(!m_bIsFlushing);
|
||||
ASSERT(pSampleStart && pSampleStop);
|
||||
|
||||
// Don't ask how I came up with the code below to handle all 19 cases...
|
||||
if(m_tStopTime >= *pSampleStart) {
|
||||
if(m_tStartTime >= *pSampleStop)
|
||||
return m_StreamState; // cases 8 11 12 15 17 18 19
|
||||
|
||||
if(m_tStopTime < m_tStartTime)
|
||||
ExecuteStop(); // case 10
|
||||
|
||||
ExecuteStart(); // cases 3 5 7 9 13 14
|
||||
return m_StreamState;
|
||||
}
|
||||
|
||||
if(m_tStartTime >= *pSampleStop) {
|
||||
ExecuteStop(); // cases 6 16
|
||||
return m_StreamState;
|
||||
}
|
||||
|
||||
if(m_tStartTime <= m_tStopTime) {
|
||||
ExecuteStart();
|
||||
ExecuteStop();
|
||||
}
|
||||
else {
|
||||
ExecuteStop();
|
||||
ExecuteStart();
|
||||
}
|
||||
|
||||
return m_StreamState; // case 1, 2, or 4
|
||||
}
|
||||
|
||||
|
||||
enum CBaseStreamControl::StreamControlState CBaseStreamControl::CheckStreamState( IMediaSample * pSample ) {
|
||||
|
||||
REFERENCE_TIME rtBufferStart, rtBufferStop;
|
||||
const BOOL bNoBufferTimes =
|
||||
pSample == NULL ||
|
||||
FAILED(pSample->GetTime(&rtBufferStart, &rtBufferStop));
|
||||
|
||||
StreamControlState state;
|
||||
LONG lWait;
|
||||
|
||||
do {
|
||||
// something has to break out of the blocking
|
||||
if(m_bIsFlushing || m_FilterState == State_Stopped)
|
||||
return STREAM_DISCARDING;
|
||||
|
||||
if(bNoBufferTimes) {
|
||||
// Can't do anything until we get a time stamp
|
||||
state = m_StreamState;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
state = CheckSampleTimes(&rtBufferStart, &rtBufferStop);
|
||||
if(state == STREAM_FLOWING)
|
||||
break;
|
||||
|
||||
// we aren't supposed to send this, but we've been
|
||||
// told to send one more than we were supposed to
|
||||
// (and the stop isn't still pending and we're streaming)
|
||||
if(m_bStopSendExtra && !m_bStopExtraSent &&
|
||||
m_tStopTime == MAX_TIME &&
|
||||
m_FilterState != State_Stopped) {
|
||||
m_bStopExtraSent = TRUE;
|
||||
DbgLog((LOG_TRACE,2,TEXT("%d sending an EXTRA frame"),
|
||||
m_dwStopCookie));
|
||||
state = STREAM_FLOWING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We're in discarding mode
|
||||
|
||||
// If we've no clock, discard as fast as we can
|
||||
if(!m_pRefClock) {
|
||||
break;
|
||||
|
||||
// If we're paused, we can't discard in a timely manner because
|
||||
// there's no such thing as stream times. We must block until
|
||||
// we run or stop, or we'll end up throwing the whole stream away
|
||||
// as quickly as possible
|
||||
}
|
||||
else if(m_FilterState == State_Paused) {
|
||||
lWait = INFINITE;
|
||||
|
||||
}
|
||||
else {
|
||||
// wait until it's time for the sample until we say "discard"
|
||||
// ("discard in a timely fashion")
|
||||
REFERENCE_TIME rtNow;
|
||||
EXECUTE_ASSERT(SUCCEEDED(m_pRefClock->GetTime(&rtNow)));
|
||||
rtNow -= m_tRunStart; // Into relative ref-time
|
||||
lWait = LONG((rtBufferStart - rtNow)/10000); // 100ns -> ms
|
||||
if(lWait < 10) break; // Not worth waiting - discard early
|
||||
}
|
||||
|
||||
} while(WaitForSingleObject(GetStreamEventHandle(), lWait) != WAIT_TIMEOUT);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart ) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
|
||||
// or we will get confused
|
||||
if(m_FilterState == new_state)
|
||||
return;
|
||||
|
||||
switch(new_state) {
|
||||
case State_Stopped:
|
||||
|
||||
DbgLog((LOG_TRACE,2,TEXT("Filter is STOPPED")));
|
||||
|
||||
// execute any pending starts and stops in the right order,
|
||||
// to make sure all notifications get sent, and we end up
|
||||
// in the right state to begin next time (??? why not?)
|
||||
|
||||
if(m_tStartTime != MAX_TIME && m_tStopTime == MAX_TIME) {
|
||||
ExecuteStart();
|
||||
}
|
||||
else if(m_tStopTime != MAX_TIME && m_tStartTime == MAX_TIME) {
|
||||
ExecuteStop();
|
||||
}
|
||||
else if(m_tStopTime != MAX_TIME && m_tStartTime != MAX_TIME) {
|
||||
if(m_tStartTime <= m_tStopTime) {
|
||||
ExecuteStart();
|
||||
ExecuteStop();
|
||||
}
|
||||
else {
|
||||
ExecuteStop();
|
||||
ExecuteStart();
|
||||
}
|
||||
}
|
||||
// always start off flowing when the graph starts streaming
|
||||
// unless told otherwise
|
||||
m_StreamState = STREAM_FLOWING;
|
||||
m_FilterState = new_state;
|
||||
break;
|
||||
|
||||
case State_Running:
|
||||
|
||||
DbgLog((LOG_TRACE,2,TEXT("Filter is RUNNING")));
|
||||
|
||||
m_tRunStart = tStart;
|
||||
// fall-through
|
||||
|
||||
default: // case State_Paused:
|
||||
m_FilterState = new_state;
|
||||
}
|
||||
// unblock!
|
||||
m_StreamEvent.Set();
|
||||
}
|
||||
|
||||
|
||||
void CBaseStreamControl::Flushing(BOOL bInProgress) {
|
||||
CAutoLock lck(&m_CritSec);
|
||||
m_bIsFlushing = bInProgress;
|
||||
m_StreamEvent.Set();
|
||||
}
|
||||
|
||||
|
||||
+158
-158
@@ -1,158 +1,158 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: StrmCtl.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __strmctl_h__
|
||||
#define __strmctl_h__
|
||||
|
||||
class CBaseStreamControl : public IAMStreamControl
|
||||
{
|
||||
public:
|
||||
// Used by the implementation
|
||||
enum StreamControlState
|
||||
{ STREAM_FLOWING = 0x1000,
|
||||
STREAM_DISCARDING
|
||||
};
|
||||
|
||||
private:
|
||||
enum StreamControlState m_StreamState; // Current stream state
|
||||
enum StreamControlState m_StreamStateOnStop; // State after next stop
|
||||
// (i.e.Blocking or Discarding)
|
||||
|
||||
REFERENCE_TIME m_tStartTime; // MAX_TIME implies none
|
||||
REFERENCE_TIME m_tStopTime; // MAX_TIME implies none
|
||||
DWORD m_dwStartCookie; // Cookie for notification to app
|
||||
DWORD m_dwStopCookie; // Cookie for notification to app
|
||||
volatile BOOL m_bIsFlushing; // No optimization pls!
|
||||
volatile BOOL m_bStopSendExtra; // bSendExtra was set
|
||||
volatile BOOL m_bStopExtraSent; // the extra one was sent
|
||||
|
||||
CCritSec m_CritSec; // CritSec to guard above attributes
|
||||
|
||||
// Event to fire when we can come
|
||||
// out of blocking, or to come out of waiting
|
||||
// to discard if we change our minds.
|
||||
//
|
||||
CAMEvent m_StreamEvent;
|
||||
|
||||
// All of these methods execute immediately. Helpers for others.
|
||||
//
|
||||
void ExecuteStop();
|
||||
void ExecuteStart();
|
||||
void CancelStop();
|
||||
void CancelStart();
|
||||
|
||||
// Some things we need to be told by our owning filter
|
||||
// Your pin must also expose IAMStreamControl when QI'd for it!
|
||||
//
|
||||
IReferenceClock * m_pRefClock; // Need it to set advises
|
||||
// Filter must tell us via
|
||||
// SetSyncSource
|
||||
IMediaEventSink * m_pSink; // Event sink
|
||||
// Filter must tell us after it
|
||||
// creates it in JoinFilterGraph()
|
||||
FILTER_STATE m_FilterState; // Just need it!
|
||||
// Filter must tell us via
|
||||
// NotifyFilterState
|
||||
REFERENCE_TIME m_tRunStart; // Per the Run call to the filter
|
||||
|
||||
// This guy will return one of the three StreamControlState's. Here's what
|
||||
// the caller should do for each one:
|
||||
//
|
||||
// STREAM_FLOWING: Proceed as usual (render or pass the sample on)
|
||||
// STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait
|
||||
// that long for the event handle
|
||||
// (GetStreamEventHandle()). If the wait
|
||||
// expires, throw the sample away. If the event
|
||||
// fires, call me back - I've changed my mind.
|
||||
//
|
||||
enum StreamControlState CheckSampleTimes( const REFERENCE_TIME * pSampleStart,
|
||||
const REFERENCE_TIME * pSampleStop );
|
||||
|
||||
public:
|
||||
// You don't have to tell us much when we're created, but there are other
|
||||
// obligations that must be met. See SetSyncSource & NotifyFilterState
|
||||
// below.
|
||||
//
|
||||
CBaseStreamControl();
|
||||
~CBaseStreamControl();
|
||||
|
||||
// If you want this class to work properly, there are thing you need to
|
||||
// (keep) telling it. Filters with pins that use this class
|
||||
// should ensure that they pass through to this method any calls they
|
||||
// receive on their SetSyncSource.
|
||||
|
||||
// We need a clock to see what time it is. This is for the
|
||||
// "discard in a timely fashion" logic. If we discard everything as
|
||||
// quick as possible, a whole 60 minute file could get discarded in the
|
||||
// first 10 seconds, and if somebody wants to turn streaming on at 30
|
||||
// minutes into the file, and they make the call more than a few seconds
|
||||
// after the graph is run, it may be too late!
|
||||
// So we hold every sample until it's time has gone, then we discard it.
|
||||
// The filter should call this when it gets a SetSyncSource
|
||||
//
|
||||
void SetSyncSource( IReferenceClock * pRefClock )
|
||||
{
|
||||
CAutoLock lck(&m_CritSec);
|
||||
if (m_pRefClock) m_pRefClock->Release();
|
||||
m_pRefClock = pRefClock;
|
||||
if (m_pRefClock)
|
||||
m_pRefClock->AddRef();
|
||||
}
|
||||
|
||||
// Set event sink for notifications
|
||||
// The filter should call this in its JoinFilterGraph after it creates the
|
||||
// IMediaEventSink
|
||||
//
|
||||
void SetFilterGraph( IMediaEventSink *pSink ) {
|
||||
m_pSink = pSink;
|
||||
}
|
||||
|
||||
// Since we schedule in stream time, we need the tStart and must track the
|
||||
// state of our owning filter.
|
||||
// The app should call this ever state change
|
||||
//
|
||||
void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 );
|
||||
|
||||
// Filter should call Flushing(TRUE) in BeginFlush,
|
||||
// and Flushing(FALSE) in EndFlush.
|
||||
//
|
||||
void Flushing( BOOL bInProgress );
|
||||
|
||||
|
||||
// The two main methods of IAMStreamControl
|
||||
|
||||
// Class adds default values suitable for immediate
|
||||
// muting and unmuting of the stream.
|
||||
|
||||
STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL,
|
||||
BOOL bSendExtra = FALSE,
|
||||
DWORD dwCookie = 0 );
|
||||
STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL,
|
||||
DWORD dwCookie = 0 );
|
||||
STDMETHODIMP GetInfo( AM_STREAM_INFO *pInfo);
|
||||
|
||||
// Helper function for pin's receive method. Call this with
|
||||
// the sample and we'll tell you what to do with it. We'll do a
|
||||
// WaitForSingleObject within this call if one is required. This is
|
||||
// a "What should I do with this sample?" kind of call. We'll tell the
|
||||
// caller to either flow it or discard it.
|
||||
// If pSample is NULL we evaluate based on the current state
|
||||
// settings
|
||||
enum StreamControlState CheckStreamState( IMediaSample * pSample );
|
||||
|
||||
private:
|
||||
// These don't require locking, but we are relying on the fact that
|
||||
// m_StreamState can be retrieved with integrity, and is a snap shot that
|
||||
// may have just been, or may be just about to be, changed.
|
||||
HANDLE GetStreamEventHandle() const { return m_StreamEvent; }
|
||||
enum StreamControlState GetStreamState() const { return m_StreamState; }
|
||||
BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; }
|
||||
};
|
||||
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
// File: StrmCtl.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __strmctl_h__
|
||||
#define __strmctl_h__
|
||||
|
||||
class CBaseStreamControl : public IAMStreamControl
|
||||
{
|
||||
public:
|
||||
// Used by the implementation
|
||||
enum StreamControlState
|
||||
{ STREAM_FLOWING = 0x1000,
|
||||
STREAM_DISCARDING
|
||||
};
|
||||
|
||||
private:
|
||||
enum StreamControlState m_StreamState; // Current stream state
|
||||
enum StreamControlState m_StreamStateOnStop; // State after next stop
|
||||
// (i.e.Blocking or Discarding)
|
||||
|
||||
REFERENCE_TIME m_tStartTime; // MAX_TIME implies none
|
||||
REFERENCE_TIME m_tStopTime; // MAX_TIME implies none
|
||||
DWORD m_dwStartCookie; // Cookie for notification to app
|
||||
DWORD m_dwStopCookie; // Cookie for notification to app
|
||||
volatile BOOL m_bIsFlushing; // No optimization pls!
|
||||
volatile BOOL m_bStopSendExtra; // bSendExtra was set
|
||||
volatile BOOL m_bStopExtraSent; // the extra one was sent
|
||||
|
||||
CCritSec m_CritSec; // CritSec to guard above attributes
|
||||
|
||||
// Event to fire when we can come
|
||||
// out of blocking, or to come out of waiting
|
||||
// to discard if we change our minds.
|
||||
//
|
||||
CAMEvent m_StreamEvent;
|
||||
|
||||
// All of these methods execute immediately. Helpers for others.
|
||||
//
|
||||
void ExecuteStop();
|
||||
void ExecuteStart();
|
||||
void CancelStop();
|
||||
void CancelStart();
|
||||
|
||||
// Some things we need to be told by our owning filter
|
||||
// Your pin must also expose IAMStreamControl when QI'd for it!
|
||||
//
|
||||
IReferenceClock * m_pRefClock; // Need it to set advises
|
||||
// Filter must tell us via
|
||||
// SetSyncSource
|
||||
IMediaEventSink * m_pSink; // Event sink
|
||||
// Filter must tell us after it
|
||||
// creates it in JoinFilterGraph()
|
||||
FILTER_STATE m_FilterState; // Just need it!
|
||||
// Filter must tell us via
|
||||
// NotifyFilterState
|
||||
REFERENCE_TIME m_tRunStart; // Per the Run call to the filter
|
||||
|
||||
// This guy will return one of the three StreamControlState's. Here's what
|
||||
// the caller should do for each one:
|
||||
//
|
||||
// STREAM_FLOWING: Proceed as usual (render or pass the sample on)
|
||||
// STREAM_DISCARDING: Calculate the time 'til *pSampleStop and wait
|
||||
// that long for the event handle
|
||||
// (GetStreamEventHandle()). If the wait
|
||||
// expires, throw the sample away. If the event
|
||||
// fires, call me back - I've changed my mind.
|
||||
//
|
||||
enum StreamControlState CheckSampleTimes( const REFERENCE_TIME * pSampleStart,
|
||||
const REFERENCE_TIME * pSampleStop );
|
||||
|
||||
public:
|
||||
// You don't have to tell us much when we're created, but there are other
|
||||
// obligations that must be met. See SetSyncSource & NotifyFilterState
|
||||
// below.
|
||||
//
|
||||
CBaseStreamControl();
|
||||
~CBaseStreamControl();
|
||||
|
||||
// If you want this class to work properly, there are thing you need to
|
||||
// (keep) telling it. Filters with pins that use this class
|
||||
// should ensure that they pass through to this method any calls they
|
||||
// receive on their SetSyncSource.
|
||||
|
||||
// We need a clock to see what time it is. This is for the
|
||||
// "discard in a timely fashion" logic. If we discard everything as
|
||||
// quick as possible, a whole 60 minute file could get discarded in the
|
||||
// first 10 seconds, and if somebody wants to turn streaming on at 30
|
||||
// minutes into the file, and they make the call more than a few seconds
|
||||
// after the graph is run, it may be too late!
|
||||
// So we hold every sample until it's time has gone, then we discard it.
|
||||
// The filter should call this when it gets a SetSyncSource
|
||||
//
|
||||
void SetSyncSource( IReferenceClock * pRefClock )
|
||||
{
|
||||
CAutoLock lck(&m_CritSec);
|
||||
if (m_pRefClock) m_pRefClock->Release();
|
||||
m_pRefClock = pRefClock;
|
||||
if (m_pRefClock)
|
||||
m_pRefClock->AddRef();
|
||||
}
|
||||
|
||||
// Set event sink for notifications
|
||||
// The filter should call this in its JoinFilterGraph after it creates the
|
||||
// IMediaEventSink
|
||||
//
|
||||
void SetFilterGraph( IMediaEventSink *pSink ) {
|
||||
m_pSink = pSink;
|
||||
}
|
||||
|
||||
// Since we schedule in stream time, we need the tStart and must track the
|
||||
// state of our owning filter.
|
||||
// The app should call this ever state change
|
||||
//
|
||||
void NotifyFilterState( FILTER_STATE new_state, REFERENCE_TIME tStart = 0 );
|
||||
|
||||
// Filter should call Flushing(TRUE) in BeginFlush,
|
||||
// and Flushing(FALSE) in EndFlush.
|
||||
//
|
||||
void Flushing( BOOL bInProgress );
|
||||
|
||||
|
||||
// The two main methods of IAMStreamControl
|
||||
|
||||
// Class adds default values suitable for immediate
|
||||
// muting and unmuting of the stream.
|
||||
|
||||
STDMETHODIMP StopAt( const REFERENCE_TIME * ptStop = NULL,
|
||||
BOOL bSendExtra = FALSE,
|
||||
DWORD dwCookie = 0 );
|
||||
STDMETHODIMP StartAt( const REFERENCE_TIME * ptStart = NULL,
|
||||
DWORD dwCookie = 0 );
|
||||
STDMETHODIMP GetInfo( AM_STREAM_INFO *pInfo);
|
||||
|
||||
// Helper function for pin's receive method. Call this with
|
||||
// the sample and we'll tell you what to do with it. We'll do a
|
||||
// WaitForSingleObject within this call if one is required. This is
|
||||
// a "What should I do with this sample?" kind of call. We'll tell the
|
||||
// caller to either flow it or discard it.
|
||||
// If pSample is NULL we evaluate based on the current state
|
||||
// settings
|
||||
enum StreamControlState CheckStreamState( IMediaSample * pSample );
|
||||
|
||||
private:
|
||||
// These don't require locking, but we are relying on the fact that
|
||||
// m_StreamState can be retrieved with integrity, and is a snap shot that
|
||||
// may have just been, or may be just about to be, changed.
|
||||
HANDLE GetStreamEventHandle() const { return m_StreamEvent; }
|
||||
enum StreamControlState GetStreamState() const { return m_StreamState; }
|
||||
BOOL IsStreaming() const { return m_StreamState == STREAM_FLOWING; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,75 +1,75 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SysClock.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements a system clock based on
|
||||
// IReferenceClock.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
/*NABIL: I changed this*/
|
||||
//#ifdef FILTER_DLL
|
||||
|
||||
/* List of class IDs and creator functions for the class factory. This
|
||||
provides the link between the OLE entry point in the DLL and an object
|
||||
being created. The class factory will call the static CreateInstance
|
||||
function when it is asked to create a CLSID_SystemClock object */
|
||||
|
||||
/*NABIL: This was screwed up....(It didn't have the "blah")*/
|
||||
CFactoryTemplate g_Templates[1] = {
|
||||
{ (const WCHAR *) "blah", &CLSID_SystemClock, CSystemClock::CreateInstance }
|
||||
};
|
||||
|
||||
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
|
||||
//#endif
|
||||
|
||||
/* This goes in the factory template table to create new instances */
|
||||
CUnknown * WINAPI CSystemClock::CreateInstance(LPUNKNOWN pUnk,HRESULT *phr)
|
||||
{
|
||||
return new CSystemClock(NAME("System reference clock"),pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
CSystemClock::CSystemClock(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseReferenceClock(pName, pUnk, phr)
|
||||
{
|
||||
}
|
||||
|
||||
STDMETHODIMP CSystemClock::NonDelegatingQueryInterface(
|
||||
REFIID riid,
|
||||
void ** ppv)
|
||||
{
|
||||
if (riid == IID_IPersist)
|
||||
{
|
||||
return GetInterface(static_cast<IPersist *>(this), ppv);
|
||||
}
|
||||
else if (riid == IID_IAMClockAdjust)
|
||||
{
|
||||
return GetInterface(static_cast<IAMClockAdjust *>(this), ppv);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the clock's clsid */
|
||||
STDMETHODIMP
|
||||
CSystemClock::GetClassID(CLSID *pClsID)
|
||||
{
|
||||
CheckPointer(pClsID,E_POINTER);
|
||||
ValidateReadWritePtr(pClsID,sizeof(CLSID));
|
||||
*pClsID = CLSID_SystemClock;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta)
|
||||
{
|
||||
return SetTimeDelta(rtDelta);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SysClock.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes - implements a system clock based on
|
||||
// IReferenceClock.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <limits.h>
|
||||
|
||||
/*NABIL: I changed this*/
|
||||
//#ifdef FILTER_DLL
|
||||
|
||||
/* List of class IDs and creator functions for the class factory. This
|
||||
provides the link between the OLE entry point in the DLL and an object
|
||||
being created. The class factory will call the static CreateInstance
|
||||
function when it is asked to create a CLSID_SystemClock object */
|
||||
|
||||
/*NABIL: This was screwed up....(It didn't have the "blah")*/
|
||||
CFactoryTemplate g_Templates[1] = {
|
||||
{ (const WCHAR *) "blah", &CLSID_SystemClock, CSystemClock::CreateInstance }
|
||||
};
|
||||
|
||||
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
|
||||
//#endif
|
||||
|
||||
/* This goes in the factory template table to create new instances */
|
||||
CUnknown * WINAPI CSystemClock::CreateInstance(LPUNKNOWN pUnk,HRESULT *phr)
|
||||
{
|
||||
return new CSystemClock(NAME("System reference clock"),pUnk, phr);
|
||||
}
|
||||
|
||||
|
||||
CSystemClock::CSystemClock(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *phr) :
|
||||
CBaseReferenceClock(pName, pUnk, phr)
|
||||
{
|
||||
}
|
||||
|
||||
STDMETHODIMP CSystemClock::NonDelegatingQueryInterface(
|
||||
REFIID riid,
|
||||
void ** ppv)
|
||||
{
|
||||
if (riid == IID_IPersist)
|
||||
{
|
||||
return GetInterface(static_cast<IPersist *>(this), ppv);
|
||||
}
|
||||
else if (riid == IID_IAMClockAdjust)
|
||||
{
|
||||
return GetInterface(static_cast<IAMClockAdjust *>(this), ppv);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the clock's clsid */
|
||||
STDMETHODIMP
|
||||
CSystemClock::GetClassID(CLSID *pClsID)
|
||||
{
|
||||
CheckPointer(pClsID,E_POINTER);
|
||||
ValidateReadWritePtr(pClsID,sizeof(CLSID));
|
||||
*pClsID = CLSID_SystemClock;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP
|
||||
CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta)
|
||||
{
|
||||
return SetTimeDelta(rtDelta);
|
||||
}
|
||||
|
||||
+39
-39
@@ -1,39 +1,39 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SysClock.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a system clock implementation of
|
||||
// IReferenceClock.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __SYSTEMCLOCK__
|
||||
#define __SYSTEMCLOCK__
|
||||
|
||||
//
|
||||
// Base clock. Uses timeGetTime ONLY
|
||||
// Uses most of the code in the base reference clock.
|
||||
// Provides GetTime
|
||||
//
|
||||
|
||||
class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist
|
||||
{
|
||||
public:
|
||||
// We must be able to create an instance of ourselves
|
||||
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
CSystemClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv);
|
||||
|
||||
// Yield up our class id so that we can be persisted
|
||||
// Implement required Ipersist method
|
||||
STDMETHODIMP GetClassID(CLSID *pClsID);
|
||||
|
||||
// IAMClockAdjust methods
|
||||
STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta);
|
||||
}; //CSystemClock
|
||||
|
||||
#endif /* __SYSTEMCLOCK__ */
|
||||
//------------------------------------------------------------------------------
|
||||
// File: SysClock.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a system clock implementation of
|
||||
// IReferenceClock.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __SYSTEMCLOCK__
|
||||
#define __SYSTEMCLOCK__
|
||||
|
||||
//
|
||||
// Base clock. Uses timeGetTime ONLY
|
||||
// Uses most of the code in the base reference clock.
|
||||
// Provides GetTime
|
||||
//
|
||||
|
||||
class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist
|
||||
{
|
||||
public:
|
||||
// We must be able to create an instance of ourselves
|
||||
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
|
||||
CSystemClock(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr);
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void ** ppv);
|
||||
|
||||
// Yield up our class id so that we can be persisted
|
||||
// Implement required Ipersist method
|
||||
STDMETHODIMP GetClassID(CLSID *pClsID);
|
||||
|
||||
// IAMClockAdjust methods
|
||||
STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta);
|
||||
}; //CSystemClock
|
||||
|
||||
#endif /* __SYSTEMCLOCK__ */
|
||||
|
||||
+974
-974
File diff suppressed because it is too large
Load Diff
+304
-304
@@ -1,304 +1,304 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Transfrm.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes from which simple
|
||||
// transform codecs may be derived.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// It assumes the codec has one input and one output stream, and has no
|
||||
// interest in memory management, interface negotiation or anything else.
|
||||
//
|
||||
// derive your class from this, and supply Transform and the media type/format
|
||||
// negotiation functions. Implement that class, compile and link and
|
||||
// you're done.
|
||||
|
||||
|
||||
#ifndef __TRANSFRM__
|
||||
#define __TRANSFRM__
|
||||
|
||||
// ======================================================================
|
||||
// This is the com object that represents a simple transform filter. It
|
||||
// supports IBaseFilter, IMediaFilter and two pins through nested interfaces
|
||||
// ======================================================================
|
||||
|
||||
class CTransformFilter;
|
||||
|
||||
// ==================================================
|
||||
// Implements the input pin
|
||||
// ==================================================
|
||||
|
||||
class CTransformInputPin : public CBaseInputPin
|
||||
{
|
||||
friend class CTransformFilter;
|
||||
|
||||
protected:
|
||||
CTransformFilter *m_pTransformFilter;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CTransformInputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CTransformInputPin(
|
||||
char *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR * Id)
|
||||
{
|
||||
return AMGetWideString(L"In", Id);
|
||||
}
|
||||
|
||||
// Grab and release extra interfaces if required
|
||||
|
||||
HRESULT CheckConnect(IPin *pPin);
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// check that we can support this output type
|
||||
HRESULT CheckMediaType(const CMediaType* mtIn);
|
||||
|
||||
// set the connection media type
|
||||
HRESULT SetMediaType(const CMediaType* mt);
|
||||
|
||||
// --- IMemInputPin -----
|
||||
|
||||
// here's the next block of data from the stream.
|
||||
// AddRef it yourself if you need to hold it beyond the end
|
||||
// of this call.
|
||||
STDMETHODIMP Receive(IMediaSample * pSample);
|
||||
|
||||
// provide EndOfStream that passes straight downstream
|
||||
// (there is no queued data)
|
||||
STDMETHODIMP EndOfStream(void);
|
||||
|
||||
// passes it to CTransformFilter::BeginFlush
|
||||
STDMETHODIMP BeginFlush(void);
|
||||
|
||||
// passes it to CTransformFilter::EndFlush
|
||||
STDMETHODIMP EndFlush(void);
|
||||
|
||||
STDMETHODIMP NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
// Check if it's OK to process samples
|
||||
virtual HRESULT CheckStreaming();
|
||||
|
||||
// Media type
|
||||
public:
|
||||
CMediaType& CurrentMediaType() { return m_mt; };
|
||||
|
||||
};
|
||||
|
||||
// ==================================================
|
||||
// Implements the output pin
|
||||
// ==================================================
|
||||
|
||||
class CTransformOutputPin : public CBaseOutputPin
|
||||
{
|
||||
friend class CTransformFilter;
|
||||
|
||||
protected:
|
||||
CTransformFilter *m_pTransformFilter;
|
||||
|
||||
public:
|
||||
|
||||
// implement IMediaPosition by passing upstream
|
||||
IUnknown * m_pPosition;
|
||||
|
||||
CTransformOutputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CTransformOutputPin(
|
||||
CHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
~CTransformOutputPin();
|
||||
|
||||
// override to expose IMediaPosition
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
|
||||
|
||||
// --- CBaseOutputPin ------------
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR * Id)
|
||||
{
|
||||
return AMGetWideString(L"Out", Id);
|
||||
}
|
||||
|
||||
// Grab and release extra interfaces if required
|
||||
|
||||
HRESULT CheckConnect(IPin *pPin);
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// check that we can support this output type
|
||||
HRESULT CheckMediaType(const CMediaType* mtOut);
|
||||
|
||||
// set the connection media type
|
||||
HRESULT SetMediaType(const CMediaType *pmt);
|
||||
|
||||
// called from CBaseOutputPin during connection to ask for
|
||||
// the count and size of buffers we need.
|
||||
HRESULT DecideBufferSize(
|
||||
IMemAllocator * pAlloc,
|
||||
ALLOCATOR_PROPERTIES *pProp);
|
||||
|
||||
// returns the preferred formats for a pin
|
||||
HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);
|
||||
|
||||
// inherited from IQualityControl via CBasePin
|
||||
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
|
||||
|
||||
// Media type
|
||||
public:
|
||||
CMediaType& CurrentMediaType() { return m_mt; };
|
||||
};
|
||||
|
||||
|
||||
class AM_NOVTABLE CTransformFilter : public CBaseFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// map getpin/getpincount for base enum of pins to owner
|
||||
// override this to return more specialised pin objects
|
||||
|
||||
virtual int GetPinCount();
|
||||
virtual CBasePin * GetPin(int n);
|
||||
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
|
||||
|
||||
// override state changes to allow derived transform filter
|
||||
// to control streaming start/stop
|
||||
STDMETHODIMP Stop();
|
||||
STDMETHODIMP Pause();
|
||||
|
||||
public:
|
||||
|
||||
CTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
#ifdef UNICODE
|
||||
CTransformFilter(CHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
#endif
|
||||
~CTransformFilter();
|
||||
|
||||
// =================================================================
|
||||
// ----- override these bits ---------------------------------------
|
||||
// =================================================================
|
||||
|
||||
// These must be supplied in a derived class
|
||||
|
||||
virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
|
||||
|
||||
// check if you can support mtIn
|
||||
virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
|
||||
|
||||
// check if you can support the transform from this input to this output
|
||||
virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE;
|
||||
|
||||
// this goes in the factory template table to create new instances
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
// call the SetProperties function with appropriate arguments
|
||||
virtual HRESULT DecideBufferSize(
|
||||
IMemAllocator * pAllocator,
|
||||
ALLOCATOR_PROPERTIES *pprop) PURE;
|
||||
|
||||
// override to suggest OUTPUT pin media types
|
||||
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
|
||||
|
||||
|
||||
|
||||
// =================================================================
|
||||
// ----- Optional Override Methods -----------------------
|
||||
// =================================================================
|
||||
|
||||
// you can also override these if you want to know about streaming
|
||||
virtual HRESULT StartStreaming();
|
||||
virtual HRESULT StopStreaming();
|
||||
|
||||
// override if you can do anything constructive with quality notifications
|
||||
virtual HRESULT AlterQuality(Quality q);
|
||||
|
||||
// override this to know when the media type is actually set
|
||||
virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
|
||||
|
||||
// chance to grab extra interfaces on connection
|
||||
virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
|
||||
virtual HRESULT BreakConnect(PIN_DIRECTION dir);
|
||||
virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
|
||||
|
||||
// chance to customize the transform process
|
||||
virtual HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// Standard setup for output sample
|
||||
HRESULT InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample);
|
||||
|
||||
// if you override Receive, you may need to override these three too
|
||||
virtual HRESULT EndOfStream(void);
|
||||
virtual HRESULT BeginFlush(void);
|
||||
virtual HRESULT EndFlush(void);
|
||||
virtual HRESULT NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
#ifdef PERF
|
||||
// Override to register performance measurement with a less generic string
|
||||
// You should do this to avoid confusion with other filters
|
||||
virtual void RegisterPerfId()
|
||||
{m_idTransform = MSR_REGISTER(TEXT("Transform"));}
|
||||
#endif // PERF
|
||||
|
||||
|
||||
// implementation details
|
||||
|
||||
protected:
|
||||
|
||||
#ifdef PERF
|
||||
int m_idTransform; // performance measuring id
|
||||
#endif
|
||||
BOOL m_bEOSDelivered; // have we sent EndOfStream
|
||||
BOOL m_bSampleSkipped; // Did we just skip a frame
|
||||
BOOL m_bQualityChanged; // Have we degraded?
|
||||
|
||||
// critical section protecting filter state.
|
||||
|
||||
CCritSec m_csFilter;
|
||||
|
||||
// critical section stopping state changes (ie Stop) while we're
|
||||
// processing a sample.
|
||||
//
|
||||
// This critical section is held when processing
|
||||
// events that occur on the receive thread - Receive() and EndOfStream().
|
||||
//
|
||||
// If you want to hold both m_csReceive and m_csFilter then grab
|
||||
// m_csFilter FIRST - like CTransformFilter::Stop() does.
|
||||
|
||||
CCritSec m_csReceive;
|
||||
|
||||
// these hold our input and output pins
|
||||
|
||||
friend class CTransformInputPin;
|
||||
friend class CTransformOutputPin;
|
||||
CTransformInputPin *m_pInput;
|
||||
CTransformOutputPin *m_pOutput;
|
||||
};
|
||||
|
||||
#endif /* __TRANSFRM__ */
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Transfrm.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes from which simple
|
||||
// transform codecs may be derived.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// It assumes the codec has one input and one output stream, and has no
|
||||
// interest in memory management, interface negotiation or anything else.
|
||||
//
|
||||
// derive your class from this, and supply Transform and the media type/format
|
||||
// negotiation functions. Implement that class, compile and link and
|
||||
// you're done.
|
||||
|
||||
|
||||
#ifndef __TRANSFRM__
|
||||
#define __TRANSFRM__
|
||||
|
||||
// ======================================================================
|
||||
// This is the com object that represents a simple transform filter. It
|
||||
// supports IBaseFilter, IMediaFilter and two pins through nested interfaces
|
||||
// ======================================================================
|
||||
|
||||
class CTransformFilter;
|
||||
|
||||
// ==================================================
|
||||
// Implements the input pin
|
||||
// ==================================================
|
||||
|
||||
class CTransformInputPin : public CBaseInputPin
|
||||
{
|
||||
friend class CTransformFilter;
|
||||
|
||||
protected:
|
||||
CTransformFilter *m_pTransformFilter;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CTransformInputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CTransformInputPin(
|
||||
char *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR * Id)
|
||||
{
|
||||
return AMGetWideString(L"In", Id);
|
||||
}
|
||||
|
||||
// Grab and release extra interfaces if required
|
||||
|
||||
HRESULT CheckConnect(IPin *pPin);
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// check that we can support this output type
|
||||
HRESULT CheckMediaType(const CMediaType* mtIn);
|
||||
|
||||
// set the connection media type
|
||||
HRESULT SetMediaType(const CMediaType* mt);
|
||||
|
||||
// --- IMemInputPin -----
|
||||
|
||||
// here's the next block of data from the stream.
|
||||
// AddRef it yourself if you need to hold it beyond the end
|
||||
// of this call.
|
||||
STDMETHODIMP Receive(IMediaSample * pSample);
|
||||
|
||||
// provide EndOfStream that passes straight downstream
|
||||
// (there is no queued data)
|
||||
STDMETHODIMP EndOfStream(void);
|
||||
|
||||
// passes it to CTransformFilter::BeginFlush
|
||||
STDMETHODIMP BeginFlush(void);
|
||||
|
||||
// passes it to CTransformFilter::EndFlush
|
||||
STDMETHODIMP EndFlush(void);
|
||||
|
||||
STDMETHODIMP NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
// Check if it's OK to process samples
|
||||
virtual HRESULT CheckStreaming();
|
||||
|
||||
// Media type
|
||||
public:
|
||||
CMediaType& CurrentMediaType() { return m_mt; };
|
||||
|
||||
};
|
||||
|
||||
// ==================================================
|
||||
// Implements the output pin
|
||||
// ==================================================
|
||||
|
||||
class CTransformOutputPin : public CBaseOutputPin
|
||||
{
|
||||
friend class CTransformFilter;
|
||||
|
||||
protected:
|
||||
CTransformFilter *m_pTransformFilter;
|
||||
|
||||
public:
|
||||
|
||||
// implement IMediaPosition by passing upstream
|
||||
IUnknown * m_pPosition;
|
||||
|
||||
CTransformOutputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#ifdef UNICODE
|
||||
CTransformOutputPin(
|
||||
CHAR *pObjectName,
|
||||
CTransformFilter *pTransformFilter,
|
||||
HRESULT * phr,
|
||||
LPCWSTR pName);
|
||||
#endif
|
||||
~CTransformOutputPin();
|
||||
|
||||
// override to expose IMediaPosition
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
|
||||
|
||||
// --- CBaseOutputPin ------------
|
||||
|
||||
STDMETHODIMP QueryId(LPWSTR * Id)
|
||||
{
|
||||
return AMGetWideString(L"Out", Id);
|
||||
}
|
||||
|
||||
// Grab and release extra interfaces if required
|
||||
|
||||
HRESULT CheckConnect(IPin *pPin);
|
||||
HRESULT BreakConnect();
|
||||
HRESULT CompleteConnect(IPin *pReceivePin);
|
||||
|
||||
// check that we can support this output type
|
||||
HRESULT CheckMediaType(const CMediaType* mtOut);
|
||||
|
||||
// set the connection media type
|
||||
HRESULT SetMediaType(const CMediaType *pmt);
|
||||
|
||||
// called from CBaseOutputPin during connection to ask for
|
||||
// the count and size of buffers we need.
|
||||
HRESULT DecideBufferSize(
|
||||
IMemAllocator * pAlloc,
|
||||
ALLOCATOR_PROPERTIES *pProp);
|
||||
|
||||
// returns the preferred formats for a pin
|
||||
HRESULT GetMediaType(int iPosition,CMediaType *pMediaType);
|
||||
|
||||
// inherited from IQualityControl via CBasePin
|
||||
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
|
||||
|
||||
// Media type
|
||||
public:
|
||||
CMediaType& CurrentMediaType() { return m_mt; };
|
||||
};
|
||||
|
||||
|
||||
class AM_NOVTABLE CTransformFilter : public CBaseFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// map getpin/getpincount for base enum of pins to owner
|
||||
// override this to return more specialised pin objects
|
||||
|
||||
virtual int GetPinCount();
|
||||
virtual CBasePin * GetPin(int n);
|
||||
STDMETHODIMP FindPin(LPCWSTR Id, IPin **ppPin);
|
||||
|
||||
// override state changes to allow derived transform filter
|
||||
// to control streaming start/stop
|
||||
STDMETHODIMP Stop();
|
||||
STDMETHODIMP Pause();
|
||||
|
||||
public:
|
||||
|
||||
CTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
#ifdef UNICODE
|
||||
CTransformFilter(CHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
#endif
|
||||
~CTransformFilter();
|
||||
|
||||
// =================================================================
|
||||
// ----- override these bits ---------------------------------------
|
||||
// =================================================================
|
||||
|
||||
// These must be supplied in a derived class
|
||||
|
||||
virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
|
||||
|
||||
// check if you can support mtIn
|
||||
virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
|
||||
|
||||
// check if you can support the transform from this input to this output
|
||||
virtual HRESULT CheckTransform(const CMediaType* mtIn, const CMediaType* mtOut) PURE;
|
||||
|
||||
// this goes in the factory template table to create new instances
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
// call the SetProperties function with appropriate arguments
|
||||
virtual HRESULT DecideBufferSize(
|
||||
IMemAllocator * pAllocator,
|
||||
ALLOCATOR_PROPERTIES *pprop) PURE;
|
||||
|
||||
// override to suggest OUTPUT pin media types
|
||||
virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
|
||||
|
||||
|
||||
|
||||
// =================================================================
|
||||
// ----- Optional Override Methods -----------------------
|
||||
// =================================================================
|
||||
|
||||
// you can also override these if you want to know about streaming
|
||||
virtual HRESULT StartStreaming();
|
||||
virtual HRESULT StopStreaming();
|
||||
|
||||
// override if you can do anything constructive with quality notifications
|
||||
virtual HRESULT AlterQuality(Quality q);
|
||||
|
||||
// override this to know when the media type is actually set
|
||||
virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
|
||||
|
||||
// chance to grab extra interfaces on connection
|
||||
virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
|
||||
virtual HRESULT BreakConnect(PIN_DIRECTION dir);
|
||||
virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
|
||||
|
||||
// chance to customize the transform process
|
||||
virtual HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// Standard setup for output sample
|
||||
HRESULT InitializeOutputSample(IMediaSample *pSample, IMediaSample **ppOutSample);
|
||||
|
||||
// if you override Receive, you may need to override these three too
|
||||
virtual HRESULT EndOfStream(void);
|
||||
virtual HRESULT BeginFlush(void);
|
||||
virtual HRESULT EndFlush(void);
|
||||
virtual HRESULT NewSegment(
|
||||
REFERENCE_TIME tStart,
|
||||
REFERENCE_TIME tStop,
|
||||
double dRate);
|
||||
|
||||
#ifdef PERF
|
||||
// Override to register performance measurement with a less generic string
|
||||
// You should do this to avoid confusion with other filters
|
||||
virtual void RegisterPerfId()
|
||||
{m_idTransform = MSR_REGISTER(TEXT("Transform"));}
|
||||
#endif // PERF
|
||||
|
||||
|
||||
// implementation details
|
||||
|
||||
protected:
|
||||
|
||||
#ifdef PERF
|
||||
int m_idTransform; // performance measuring id
|
||||
#endif
|
||||
BOOL m_bEOSDelivered; // have we sent EndOfStream
|
||||
BOOL m_bSampleSkipped; // Did we just skip a frame
|
||||
BOOL m_bQualityChanged; // Have we degraded?
|
||||
|
||||
// critical section protecting filter state.
|
||||
|
||||
CCritSec m_csFilter;
|
||||
|
||||
// critical section stopping state changes (ie Stop) while we're
|
||||
// processing a sample.
|
||||
//
|
||||
// This critical section is held when processing
|
||||
// events that occur on the receive thread - Receive() and EndOfStream().
|
||||
//
|
||||
// If you want to hold both m_csReceive and m_csFilter then grab
|
||||
// m_csFilter FIRST - like CTransformFilter::Stop() does.
|
||||
|
||||
CCritSec m_csReceive;
|
||||
|
||||
// these hold our input and output pins
|
||||
|
||||
friend class CTransformInputPin;
|
||||
friend class CTransformOutputPin;
|
||||
CTransformInputPin *m_pInput;
|
||||
CTransformOutputPin *m_pOutput;
|
||||
};
|
||||
|
||||
#endif /* __TRANSFRM__ */
|
||||
|
||||
|
||||
|
||||
+922
-922
File diff suppressed because it is too large
Load Diff
+246
-246
@@ -1,246 +1,246 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: TransIP.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes from which simple
|
||||
// Transform-In-Place filters may be derived.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// The difference between this and Transfrm.h is that Transfrm copies the data.
|
||||
//
|
||||
// It assumes the filter has one input and one output stream, and has no
|
||||
// interest in memory management, interface negotiation or anything else.
|
||||
//
|
||||
// Derive your class from this, and supply Transform and the media type/format
|
||||
// negotiation functions. Implement that class, compile and link and
|
||||
// you're done.
|
||||
|
||||
|
||||
#ifndef __TRANSIP__
|
||||
#define __TRANSIP__
|
||||
|
||||
// ======================================================================
|
||||
// This is the com object that represents a simple transform filter. It
|
||||
// supports IBaseFilter, IMediaFilter and two pins through nested interfaces
|
||||
// ======================================================================
|
||||
|
||||
class CTransInPlaceFilter;
|
||||
|
||||
// Several of the pin functions call filter functions to do the work,
|
||||
// so you can often use the pin classes unaltered, just overriding the
|
||||
// functions in CTransInPlaceFilter. If that's not enough and you want
|
||||
// to derive your own pin class, override GetPin in the filter to supply
|
||||
// your own pin classes to the filter.
|
||||
|
||||
// ==================================================
|
||||
// Implements the input pin
|
||||
// ==================================================
|
||||
|
||||
class CTransInPlaceInputPin : public CTransformInputPin
|
||||
{
|
||||
|
||||
protected:
|
||||
CTransInPlaceFilter * const m_pTIPFilter; // our filter
|
||||
BOOL m_bReadOnly; // incoming stream is read only
|
||||
|
||||
public:
|
||||
|
||||
CTransInPlaceInputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransInPlaceFilter *pFilter,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
|
||||
// --- IMemInputPin -----
|
||||
|
||||
// Provide an enumerator for media types by getting one from downstream
|
||||
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
|
||||
|
||||
// Say whether media type is acceptable.
|
||||
HRESULT CheckMediaType(const CMediaType* pmt);
|
||||
|
||||
// Return our upstream allocator
|
||||
STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator);
|
||||
|
||||
// get told which allocator the upstream output pin is actually
|
||||
// going to use.
|
||||
STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator,
|
||||
BOOL bReadOnly);
|
||||
|
||||
// Allow the filter to see what allocator we have
|
||||
// N.B. This does NOT AddRef
|
||||
IMemAllocator * PeekAllocator() const
|
||||
{ return m_pAllocator; }
|
||||
|
||||
// Pass this on downstream if it ever gets called.
|
||||
STDMETHODIMP
|
||||
CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps);
|
||||
|
||||
inline const BOOL ReadOnly() { return m_bReadOnly ; }
|
||||
|
||||
}; // CTransInPlaceInputPin
|
||||
|
||||
// ==================================================
|
||||
// Implements the output pin
|
||||
// ==================================================
|
||||
|
||||
class CTransInPlaceOutputPin : public CTransformOutputPin
|
||||
{
|
||||
|
||||
protected:
|
||||
// m_pFilter points to our CBaseFilter
|
||||
CTransInPlaceFilter * const m_pTIPFilter;
|
||||
|
||||
public:
|
||||
|
||||
CTransInPlaceOutputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransInPlaceFilter *pFilter,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
|
||||
|
||||
// --- CBaseOutputPin ------------
|
||||
|
||||
// negotiate the allocator and its buffer size/count
|
||||
// Insists on using our own allocator. (Actually the one upstream of us).
|
||||
// We don't override this - instead we just agree the default
|
||||
// then let the upstream filter decide for itself on reconnect
|
||||
// virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
|
||||
|
||||
// Provide a media type enumerator. Get it from upstream.
|
||||
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
|
||||
|
||||
// Say whether media type is acceptable.
|
||||
HRESULT CheckMediaType(const CMediaType* pmt);
|
||||
|
||||
// This just saves the allocator being used on the output pin
|
||||
// Also called by input pin's GetAllocator()
|
||||
void SetAllocator(IMemAllocator * pAllocator);
|
||||
|
||||
IMemInputPin * ConnectedIMemInputPin()
|
||||
{ return m_pInputPin; }
|
||||
|
||||
// Allow the filter to see what allocator we have
|
||||
// N.B. This does NOT AddRef
|
||||
IMemAllocator * PeekAllocator() const
|
||||
{ return m_pAllocator; }
|
||||
}; // CTransInPlaceOutputPin
|
||||
|
||||
|
||||
class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// map getpin/getpincount for base enum of pins to owner
|
||||
// override this to return more specialised pin objects
|
||||
|
||||
virtual CBasePin *GetPin(int n);
|
||||
|
||||
public:
|
||||
|
||||
// Set bModifiesData == false if your derived filter does
|
||||
// not modify the data samples (for instance it's just copying
|
||||
// them somewhere else or looking at the timestamps).
|
||||
|
||||
CTransInPlaceFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *,
|
||||
bool bModifiesData = true);
|
||||
#ifdef UNICODE
|
||||
CTransInPlaceFilter(CHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *,
|
||||
bool bModifiesData = true);
|
||||
#endif
|
||||
// The following are defined to avoid undefined pure virtuals.
|
||||
// Even if they are never called, they will give linkage warnings/errors
|
||||
|
||||
// We override EnumMediaTypes to bypass the transform class enumerator
|
||||
// which would otherwise call this.
|
||||
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType)
|
||||
{ DbgBreak("CTransInPlaceFilter::GetMediaType should never be called");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// This is called when we actually have to provide out own allocator.
|
||||
HRESULT DecideBufferSize(IMemAllocator*, ALLOCATOR_PROPERTIES *);
|
||||
|
||||
// The functions which call this in CTransform are overridden in this
|
||||
// class to call CheckInputType with the assumption that the type
|
||||
// does not change. In Debug builds some calls will be made and
|
||||
// we just ensure that they do not assert.
|
||||
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
|
||||
{
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
|
||||
// =================================================================
|
||||
// ----- You may want to override this -----------------------------
|
||||
// =================================================================
|
||||
|
||||
HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin);
|
||||
|
||||
// chance to customize the transform process
|
||||
virtual HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// =================================================================
|
||||
// ----- You MUST override these -----------------------------------
|
||||
// =================================================================
|
||||
|
||||
virtual HRESULT Transform(IMediaSample *pSample) PURE;
|
||||
|
||||
// this goes in the factory template table to create new instances
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
|
||||
#ifdef PERF
|
||||
// Override to register performance measurement with a less generic string
|
||||
// You should do this to avoid confusion with other filters
|
||||
virtual void RegisterPerfId()
|
||||
{m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));}
|
||||
#endif // PERF
|
||||
|
||||
|
||||
// implementation details
|
||||
|
||||
protected:
|
||||
|
||||
IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource);
|
||||
|
||||
#ifdef PERF
|
||||
int m_idTransInPlace; // performance measuring id
|
||||
#endif // PERF
|
||||
bool m_bModifiesData; // Does this filter change the data?
|
||||
|
||||
// these hold our input and output pins
|
||||
|
||||
friend class CTransInPlaceInputPin;
|
||||
friend class CTransInPlaceOutputPin;
|
||||
|
||||
CTransInPlaceInputPin *InputPin() const
|
||||
{
|
||||
return (CTransInPlaceInputPin *)m_pInput;
|
||||
};
|
||||
CTransInPlaceOutputPin *OutputPin() const
|
||||
{
|
||||
return (CTransInPlaceOutputPin *)m_pOutput;
|
||||
};
|
||||
|
||||
// Helper to see if the input and output types match
|
||||
BOOL TypesMatch()
|
||||
{
|
||||
return InputPin()->CurrentMediaType() ==
|
||||
OutputPin()->CurrentMediaType();
|
||||
}
|
||||
|
||||
// Are the input and output allocators different?
|
||||
BOOL UsingDifferentAllocators() const
|
||||
{
|
||||
return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator();
|
||||
}
|
||||
}; // CTransInPlaceFilter
|
||||
|
||||
#endif /* __TRANSIP__ */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: TransIP.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes from which simple
|
||||
// Transform-In-Place filters may be derived.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//
|
||||
// The difference between this and Transfrm.h is that Transfrm copies the data.
|
||||
//
|
||||
// It assumes the filter has one input and one output stream, and has no
|
||||
// interest in memory management, interface negotiation or anything else.
|
||||
//
|
||||
// Derive your class from this, and supply Transform and the media type/format
|
||||
// negotiation functions. Implement that class, compile and link and
|
||||
// you're done.
|
||||
|
||||
|
||||
#ifndef __TRANSIP__
|
||||
#define __TRANSIP__
|
||||
|
||||
// ======================================================================
|
||||
// This is the com object that represents a simple transform filter. It
|
||||
// supports IBaseFilter, IMediaFilter and two pins through nested interfaces
|
||||
// ======================================================================
|
||||
|
||||
class CTransInPlaceFilter;
|
||||
|
||||
// Several of the pin functions call filter functions to do the work,
|
||||
// so you can often use the pin classes unaltered, just overriding the
|
||||
// functions in CTransInPlaceFilter. If that's not enough and you want
|
||||
// to derive your own pin class, override GetPin in the filter to supply
|
||||
// your own pin classes to the filter.
|
||||
|
||||
// ==================================================
|
||||
// Implements the input pin
|
||||
// ==================================================
|
||||
|
||||
class CTransInPlaceInputPin : public CTransformInputPin
|
||||
{
|
||||
|
||||
protected:
|
||||
CTransInPlaceFilter * const m_pTIPFilter; // our filter
|
||||
BOOL m_bReadOnly; // incoming stream is read only
|
||||
|
||||
public:
|
||||
|
||||
CTransInPlaceInputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransInPlaceFilter *pFilter,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
|
||||
// --- IMemInputPin -----
|
||||
|
||||
// Provide an enumerator for media types by getting one from downstream
|
||||
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
|
||||
|
||||
// Say whether media type is acceptable.
|
||||
HRESULT CheckMediaType(const CMediaType* pmt);
|
||||
|
||||
// Return our upstream allocator
|
||||
STDMETHODIMP GetAllocator(IMemAllocator ** ppAllocator);
|
||||
|
||||
// get told which allocator the upstream output pin is actually
|
||||
// going to use.
|
||||
STDMETHODIMP NotifyAllocator(IMemAllocator * pAllocator,
|
||||
BOOL bReadOnly);
|
||||
|
||||
// Allow the filter to see what allocator we have
|
||||
// N.B. This does NOT AddRef
|
||||
IMemAllocator * PeekAllocator() const
|
||||
{ return m_pAllocator; }
|
||||
|
||||
// Pass this on downstream if it ever gets called.
|
||||
STDMETHODIMP
|
||||
CTransInPlaceInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps);
|
||||
|
||||
inline const BOOL ReadOnly() { return m_bReadOnly ; }
|
||||
|
||||
}; // CTransInPlaceInputPin
|
||||
|
||||
// ==================================================
|
||||
// Implements the output pin
|
||||
// ==================================================
|
||||
|
||||
class CTransInPlaceOutputPin : public CTransformOutputPin
|
||||
{
|
||||
|
||||
protected:
|
||||
// m_pFilter points to our CBaseFilter
|
||||
CTransInPlaceFilter * const m_pTIPFilter;
|
||||
|
||||
public:
|
||||
|
||||
CTransInPlaceOutputPin(
|
||||
TCHAR *pObjectName,
|
||||
CTransInPlaceFilter *pFilter,
|
||||
HRESULT *phr,
|
||||
LPCWSTR pName);
|
||||
|
||||
|
||||
// --- CBaseOutputPin ------------
|
||||
|
||||
// negotiate the allocator and its buffer size/count
|
||||
// Insists on using our own allocator. (Actually the one upstream of us).
|
||||
// We don't override this - instead we just agree the default
|
||||
// then let the upstream filter decide for itself on reconnect
|
||||
// virtual HRESULT DecideAllocator(IMemInputPin * pPin, IMemAllocator ** pAlloc);
|
||||
|
||||
// Provide a media type enumerator. Get it from upstream.
|
||||
STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
|
||||
|
||||
// Say whether media type is acceptable.
|
||||
HRESULT CheckMediaType(const CMediaType* pmt);
|
||||
|
||||
// This just saves the allocator being used on the output pin
|
||||
// Also called by input pin's GetAllocator()
|
||||
void SetAllocator(IMemAllocator * pAllocator);
|
||||
|
||||
IMemInputPin * ConnectedIMemInputPin()
|
||||
{ return m_pInputPin; }
|
||||
|
||||
// Allow the filter to see what allocator we have
|
||||
// N.B. This does NOT AddRef
|
||||
IMemAllocator * PeekAllocator() const
|
||||
{ return m_pAllocator; }
|
||||
}; // CTransInPlaceOutputPin
|
||||
|
||||
|
||||
class AM_NOVTABLE CTransInPlaceFilter : public CTransformFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// map getpin/getpincount for base enum of pins to owner
|
||||
// override this to return more specialised pin objects
|
||||
|
||||
virtual CBasePin *GetPin(int n);
|
||||
|
||||
public:
|
||||
|
||||
// Set bModifiesData == false if your derived filter does
|
||||
// not modify the data samples (for instance it's just copying
|
||||
// them somewhere else or looking at the timestamps).
|
||||
|
||||
CTransInPlaceFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *,
|
||||
bool bModifiesData = true);
|
||||
#ifdef UNICODE
|
||||
CTransInPlaceFilter(CHAR *, LPUNKNOWN, REFCLSID clsid, HRESULT *,
|
||||
bool bModifiesData = true);
|
||||
#endif
|
||||
// The following are defined to avoid undefined pure virtuals.
|
||||
// Even if they are never called, they will give linkage warnings/errors
|
||||
|
||||
// We override EnumMediaTypes to bypass the transform class enumerator
|
||||
// which would otherwise call this.
|
||||
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType)
|
||||
{ DbgBreak("CTransInPlaceFilter::GetMediaType should never be called");
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
// This is called when we actually have to provide out own allocator.
|
||||
HRESULT DecideBufferSize(IMemAllocator*, ALLOCATOR_PROPERTIES *);
|
||||
|
||||
// The functions which call this in CTransform are overridden in this
|
||||
// class to call CheckInputType with the assumption that the type
|
||||
// does not change. In Debug builds some calls will be made and
|
||||
// we just ensure that they do not assert.
|
||||
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)
|
||||
{
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
|
||||
// =================================================================
|
||||
// ----- You may want to override this -----------------------------
|
||||
// =================================================================
|
||||
|
||||
HRESULT CompleteConnect(PIN_DIRECTION dir,IPin *pReceivePin);
|
||||
|
||||
// chance to customize the transform process
|
||||
virtual HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
// =================================================================
|
||||
// ----- You MUST override these -----------------------------------
|
||||
// =================================================================
|
||||
|
||||
virtual HRESULT Transform(IMediaSample *pSample) PURE;
|
||||
|
||||
// this goes in the factory template table to create new instances
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
|
||||
|
||||
#ifdef PERF
|
||||
// Override to register performance measurement with a less generic string
|
||||
// You should do this to avoid confusion with other filters
|
||||
virtual void RegisterPerfId()
|
||||
{m_idTransInPlace = MSR_REGISTER(TEXT("TransInPlace"));}
|
||||
#endif // PERF
|
||||
|
||||
|
||||
// implementation details
|
||||
|
||||
protected:
|
||||
|
||||
IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource);
|
||||
|
||||
#ifdef PERF
|
||||
int m_idTransInPlace; // performance measuring id
|
||||
#endif // PERF
|
||||
bool m_bModifiesData; // Does this filter change the data?
|
||||
|
||||
// these hold our input and output pins
|
||||
|
||||
friend class CTransInPlaceInputPin;
|
||||
friend class CTransInPlaceOutputPin;
|
||||
|
||||
CTransInPlaceInputPin *InputPin() const
|
||||
{
|
||||
return (CTransInPlaceInputPin *)m_pInput;
|
||||
};
|
||||
CTransInPlaceOutputPin *OutputPin() const
|
||||
{
|
||||
return (CTransInPlaceOutputPin *)m_pOutput;
|
||||
};
|
||||
|
||||
// Helper to see if the input and output types match
|
||||
BOOL TypesMatch()
|
||||
{
|
||||
return InputPin()->CurrentMediaType() ==
|
||||
OutputPin()->CurrentMediaType();
|
||||
}
|
||||
|
||||
// Are the input and output allocators different?
|
||||
BOOL UsingDifferentAllocators() const
|
||||
{
|
||||
return InputPin()->PeekAllocator() != OutputPin()->PeekAllocator();
|
||||
}
|
||||
}; // CTransInPlaceFilter
|
||||
|
||||
#endif /* __TRANSIP__ */
|
||||
|
||||
|
||||
+653
-653
File diff suppressed because it is too large
Load Diff
+178
-178
@@ -1,178 +1,178 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: VideoCtl.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __VIDEOCTL__
|
||||
#define __VIDEOCTL__
|
||||
|
||||
// These help with property page implementations. The first can be used to
|
||||
// load any string from a resource file. The buffer to load into is passed
|
||||
// as an input parameter. The same buffer is the return value if the string
|
||||
// was found otherwise it returns TEXT(""). The GetDialogSize is passed the
|
||||
// resource ID of a dialog box and returns the size of it in screen pixels
|
||||
|
||||
#define STR_MAX_LENGTH 256
|
||||
TCHAR * WINAPI StringFromResource(TCHAR *pBuffer, int iResourceID);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define WideStringFromResource StringFromResource
|
||||
char* WINAPI StringFromResource(char*pBuffer, int iResourceID);
|
||||
#else
|
||||
WCHAR * WINAPI WideStringFromResource(WCHAR *pBuffer, int iResourceID);
|
||||
#endif
|
||||
|
||||
|
||||
BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier
|
||||
DLGPROC pDlgProc, // Pointer to dialog procedure
|
||||
LPARAM lParam, // Any user data wanted in pDlgProc
|
||||
SIZE *pResult); // Returns the size of dialog box
|
||||
|
||||
// Class that aggregates an IDirectDraw interface
|
||||
|
||||
class CAggDirectDraw : public IDirectDraw, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPDIRECTDRAW m_pDirectDraw;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CAggDirectDraw(TCHAR *pName,LPUNKNOWN pUnk) :
|
||||
CUnknown(pName,pUnk),
|
||||
m_pDirectDraw(NULL) { };
|
||||
|
||||
virtual CAggDirectDraw::~CAggDirectDraw() { };
|
||||
|
||||
// Set the object we should be aggregating
|
||||
void SetDirectDraw(LPDIRECTDRAW pDirectDraw) {
|
||||
m_pDirectDraw = pDirectDraw;
|
||||
}
|
||||
|
||||
// IDirectDraw methods
|
||||
|
||||
STDMETHODIMP Compact();
|
||||
STDMETHODIMP CreateClipper(DWORD dwFlags,LPDIRECTDRAWCLIPPER *lplpDDClipper,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP CreatePalette(DWORD dwFlags,LPPALETTEENTRY lpColorTable,LPDIRECTDRAWPALETTE *lplpDDPalette,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc,LPDIRECTDRAWSURFACE *lplpDDSurface,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP DuplicateSurface(LPDIRECTDRAWSURFACE lpDDSurface,LPDIRECTDRAWSURFACE *lplpDupDDSurface);
|
||||
STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,LPDDSURFACEDESC lplpDDSurfaceDescList,LPVOID lpContext,LPDDENUMMODESCALLBACK lpEnumCallback);
|
||||
STDMETHODIMP EnumSurfaces(DWORD dwFlags,LPDDSURFACEDESC lpDDSD,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumCallback);
|
||||
STDMETHODIMP FlipToGDISurface();
|
||||
STDMETHODIMP GetCaps(LPDDCAPS lpDDDriverCaps,LPDDCAPS lpDDHELCaps);
|
||||
STDMETHODIMP GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP GetFourCCCodes(LPDWORD lpNumCodes,LPDWORD lpCodes);
|
||||
STDMETHODIMP GetGDISurface(LPDIRECTDRAWSURFACE *lplpGDIDDSurface);
|
||||
STDMETHODIMP GetMonitorFrequency(LPDWORD lpdwFrequency);
|
||||
STDMETHODIMP GetScanLine(LPDWORD lpdwScanLine);
|
||||
STDMETHODIMP GetVerticalBlankStatus(LPBOOL lpblsInVB);
|
||||
STDMETHODIMP Initialize(GUID *lpGUID);
|
||||
STDMETHODIMP RestoreDisplayMode();
|
||||
STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags);
|
||||
STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp);
|
||||
STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent);
|
||||
};
|
||||
|
||||
|
||||
// Class that aggregates an IDirectDrawSurface interface
|
||||
|
||||
class CAggDrawSurface : public IDirectDrawSurface, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPDIRECTDRAWSURFACE m_pDirectDrawSurface;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CAggDrawSurface(TCHAR *pName,LPUNKNOWN pUnk) :
|
||||
CUnknown(pName,pUnk),
|
||||
m_pDirectDrawSurface(NULL) { };
|
||||
|
||||
virtual ~CAggDrawSurface() { };
|
||||
|
||||
// Set the object we should be aggregating
|
||||
void SetDirectDrawSurface(LPDIRECTDRAWSURFACE pDirectDrawSurface) {
|
||||
m_pDirectDrawSurface = pDirectDrawSurface;
|
||||
}
|
||||
|
||||
// IDirectDrawSurface methods
|
||||
|
||||
STDMETHODIMP AddAttachedSurface(LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
|
||||
STDMETHODIMP AddOverlayDirtyRect(LPRECT lpRect);
|
||||
STDMETHODIMP Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx);
|
||||
STDMETHODIMP BltBatch(LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags);
|
||||
STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwTrans);
|
||||
STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
|
||||
STDMETHODIMP EnumAttachedSurfaces(LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback);
|
||||
STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpfnCallback);
|
||||
STDMETHODIMP Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags);
|
||||
STDMETHODIMP GetAttachedSurface(LPDDSCAPS lpDDSCaps,LPDIRECTDRAWSURFACE *lplpDDAttachedSurface);
|
||||
STDMETHODIMP GetBltStatus(DWORD dwFlags);
|
||||
STDMETHODIMP GetCaps(LPDDSCAPS lpDDSCaps);
|
||||
STDMETHODIMP GetClipper(LPDIRECTDRAWCLIPPER *lplpDDClipper);
|
||||
STDMETHODIMP GetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey);
|
||||
STDMETHODIMP GetDC(HDC *lphDC);
|
||||
STDMETHODIMP GetFlipStatus(DWORD dwFlags);
|
||||
STDMETHODIMP GetOverlayPosition(LPLONG lpdwX,LPLONG lpdwY);
|
||||
STDMETHODIMP GetPalette(LPDIRECTDRAWPALETTE *lplpDDPalette);
|
||||
STDMETHODIMP GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat);
|
||||
STDMETHODIMP GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP Initialize(LPDIRECTDRAW lpDD,LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP IsLost();
|
||||
STDMETHODIMP Lock(LPRECT lpDestRect,LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent);
|
||||
STDMETHODIMP ReleaseDC(HDC hDC);
|
||||
STDMETHODIMP Restore();
|
||||
STDMETHODIMP SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);
|
||||
STDMETHODIMP SetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey);
|
||||
STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY);
|
||||
STDMETHODIMP SetPalette(LPDIRECTDRAWPALETTE lpDDPalette);
|
||||
STDMETHODIMP Unlock(LPVOID lpSurfaceData);
|
||||
STDMETHODIMP UpdateOverlay(LPRECT lpSrcRect,LPDIRECTDRAWSURFACE lpDDDestSurface,LPRECT lpDestRect,DWORD dwFlags,LPDDOVERLAYFX lpDDOverlayFX);
|
||||
STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags);
|
||||
STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSReference);
|
||||
};
|
||||
|
||||
|
||||
// DirectShow must work on multiple platforms. In particular, it also runs on
|
||||
// Windows NT 3.51 which does not have DirectDraw capabilities. The filters
|
||||
// cannot therefore link statically to the DirectDraw library. To make their
|
||||
// lives that little bit easier we provide this class that manages loading
|
||||
// and unloading the library and creating the initial IDirectDraw interface
|
||||
|
||||
typedef DWORD (WINAPI *PGETFILEVERSIONINFOSIZE)(LPTSTR,LPDWORD);
|
||||
typedef BOOL (WINAPI *PGETFILEVERSIONINFO)(LPTSTR,DWORD,DWORD,LPVOID);
|
||||
typedef BOOL (WINAPI *PVERQUERYVALUE)(LPVOID,LPTSTR,LPVOID,PUINT);
|
||||
|
||||
class CLoadDirectDraw
|
||||
{
|
||||
LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance
|
||||
HINSTANCE m_hDirectDraw; // Handle to the loaded library
|
||||
|
||||
public:
|
||||
|
||||
CLoadDirectDraw();
|
||||
~CLoadDirectDraw();
|
||||
|
||||
HRESULT LoadDirectDraw(LPSTR szDevice);
|
||||
void ReleaseDirectDraw();
|
||||
HRESULT IsDirectDrawLoaded();
|
||||
LPDIRECTDRAW GetDirectDraw();
|
||||
BOOL IsDirectDrawVersion1();
|
||||
};
|
||||
|
||||
#endif // __VIDEOCTL__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: VideoCtl.h
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __VIDEOCTL__
|
||||
#define __VIDEOCTL__
|
||||
|
||||
// These help with property page implementations. The first can be used to
|
||||
// load any string from a resource file. The buffer to load into is passed
|
||||
// as an input parameter. The same buffer is the return value if the string
|
||||
// was found otherwise it returns TEXT(""). The GetDialogSize is passed the
|
||||
// resource ID of a dialog box and returns the size of it in screen pixels
|
||||
|
||||
#define STR_MAX_LENGTH 256
|
||||
TCHAR * WINAPI StringFromResource(TCHAR *pBuffer, int iResourceID);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define WideStringFromResource StringFromResource
|
||||
char* WINAPI StringFromResource(char*pBuffer, int iResourceID);
|
||||
#else
|
||||
WCHAR * WINAPI WideStringFromResource(WCHAR *pBuffer, int iResourceID);
|
||||
#endif
|
||||
|
||||
|
||||
BOOL WINAPI GetDialogSize(int iResourceID, // Dialog box resource identifier
|
||||
DLGPROC pDlgProc, // Pointer to dialog procedure
|
||||
LPARAM lParam, // Any user data wanted in pDlgProc
|
||||
SIZE *pResult); // Returns the size of dialog box
|
||||
|
||||
// Class that aggregates an IDirectDraw interface
|
||||
|
||||
class CAggDirectDraw : public IDirectDraw, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPDIRECTDRAW m_pDirectDraw;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CAggDirectDraw(TCHAR *pName,LPUNKNOWN pUnk) :
|
||||
CUnknown(pName,pUnk),
|
||||
m_pDirectDraw(NULL) { };
|
||||
|
||||
virtual CAggDirectDraw::~CAggDirectDraw() { };
|
||||
|
||||
// Set the object we should be aggregating
|
||||
void SetDirectDraw(LPDIRECTDRAW pDirectDraw) {
|
||||
m_pDirectDraw = pDirectDraw;
|
||||
}
|
||||
|
||||
// IDirectDraw methods
|
||||
|
||||
STDMETHODIMP Compact();
|
||||
STDMETHODIMP CreateClipper(DWORD dwFlags,LPDIRECTDRAWCLIPPER *lplpDDClipper,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP CreatePalette(DWORD dwFlags,LPPALETTEENTRY lpColorTable,LPDIRECTDRAWPALETTE *lplpDDPalette,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc,LPDIRECTDRAWSURFACE *lplpDDSurface,IUnknown *pUnkOuter);
|
||||
STDMETHODIMP DuplicateSurface(LPDIRECTDRAWSURFACE lpDDSurface,LPDIRECTDRAWSURFACE *lplpDupDDSurface);
|
||||
STDMETHODIMP EnumDisplayModes(DWORD dwSurfaceDescCount,LPDDSURFACEDESC lplpDDSurfaceDescList,LPVOID lpContext,LPDDENUMMODESCALLBACK lpEnumCallback);
|
||||
STDMETHODIMP EnumSurfaces(DWORD dwFlags,LPDDSURFACEDESC lpDDSD,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumCallback);
|
||||
STDMETHODIMP FlipToGDISurface();
|
||||
STDMETHODIMP GetCaps(LPDDCAPS lpDDDriverCaps,LPDDCAPS lpDDHELCaps);
|
||||
STDMETHODIMP GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP GetFourCCCodes(LPDWORD lpNumCodes,LPDWORD lpCodes);
|
||||
STDMETHODIMP GetGDISurface(LPDIRECTDRAWSURFACE *lplpGDIDDSurface);
|
||||
STDMETHODIMP GetMonitorFrequency(LPDWORD lpdwFrequency);
|
||||
STDMETHODIMP GetScanLine(LPDWORD lpdwScanLine);
|
||||
STDMETHODIMP GetVerticalBlankStatus(LPBOOL lpblsInVB);
|
||||
STDMETHODIMP Initialize(GUID *lpGUID);
|
||||
STDMETHODIMP RestoreDisplayMode();
|
||||
STDMETHODIMP SetCooperativeLevel(HWND hWnd,DWORD dwFlags);
|
||||
STDMETHODIMP SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBpp);
|
||||
STDMETHODIMP WaitForVerticalBlank(DWORD dwFlags,HANDLE hEvent);
|
||||
};
|
||||
|
||||
|
||||
// Class that aggregates an IDirectDrawSurface interface
|
||||
|
||||
class CAggDrawSurface : public IDirectDrawSurface, public CUnknown
|
||||
{
|
||||
protected:
|
||||
|
||||
LPDIRECTDRAWSURFACE m_pDirectDrawSurface;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_IUNKNOWN
|
||||
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CAggDrawSurface(TCHAR *pName,LPUNKNOWN pUnk) :
|
||||
CUnknown(pName,pUnk),
|
||||
m_pDirectDrawSurface(NULL) { };
|
||||
|
||||
virtual ~CAggDrawSurface() { };
|
||||
|
||||
// Set the object we should be aggregating
|
||||
void SetDirectDrawSurface(LPDIRECTDRAWSURFACE pDirectDrawSurface) {
|
||||
m_pDirectDrawSurface = pDirectDrawSurface;
|
||||
}
|
||||
|
||||
// IDirectDrawSurface methods
|
||||
|
||||
STDMETHODIMP AddAttachedSurface(LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
|
||||
STDMETHODIMP AddOverlayDirtyRect(LPRECT lpRect);
|
||||
STDMETHODIMP Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx);
|
||||
STDMETHODIMP BltBatch(LPDDBLTBATCH lpDDBltBatch,DWORD dwCount,DWORD dwFlags);
|
||||
STDMETHODIMP BltFast(DWORD dwX,DWORD dwY,LPDIRECTDRAWSURFACE lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwTrans);
|
||||
STDMETHODIMP DeleteAttachedSurface(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSAttachedSurface);
|
||||
STDMETHODIMP EnumAttachedSurfaces(LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback);
|
||||
STDMETHODIMP EnumOverlayZOrders(DWORD dwFlags,LPVOID lpContext,LPDDENUMSURFACESCALLBACK lpfnCallback);
|
||||
STDMETHODIMP Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride,DWORD dwFlags);
|
||||
STDMETHODIMP GetAttachedSurface(LPDDSCAPS lpDDSCaps,LPDIRECTDRAWSURFACE *lplpDDAttachedSurface);
|
||||
STDMETHODIMP GetBltStatus(DWORD dwFlags);
|
||||
STDMETHODIMP GetCaps(LPDDSCAPS lpDDSCaps);
|
||||
STDMETHODIMP GetClipper(LPDIRECTDRAWCLIPPER *lplpDDClipper);
|
||||
STDMETHODIMP GetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey);
|
||||
STDMETHODIMP GetDC(HDC *lphDC);
|
||||
STDMETHODIMP GetFlipStatus(DWORD dwFlags);
|
||||
STDMETHODIMP GetOverlayPosition(LPLONG lpdwX,LPLONG lpdwY);
|
||||
STDMETHODIMP GetPalette(LPDIRECTDRAWPALETTE *lplpDDPalette);
|
||||
STDMETHODIMP GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat);
|
||||
STDMETHODIMP GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP Initialize(LPDIRECTDRAW lpDD,LPDDSURFACEDESC lpDDSurfaceDesc);
|
||||
STDMETHODIMP IsLost();
|
||||
STDMETHODIMP Lock(LPRECT lpDestRect,LPDDSURFACEDESC lpDDSurfaceDesc,DWORD dwFlags,HANDLE hEvent);
|
||||
STDMETHODIMP ReleaseDC(HDC hDC);
|
||||
STDMETHODIMP Restore();
|
||||
STDMETHODIMP SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);
|
||||
STDMETHODIMP SetColorKey(DWORD dwFlags,LPDDCOLORKEY lpDDColorKey);
|
||||
STDMETHODIMP SetOverlayPosition(LONG dwX,LONG dwY);
|
||||
STDMETHODIMP SetPalette(LPDIRECTDRAWPALETTE lpDDPalette);
|
||||
STDMETHODIMP Unlock(LPVOID lpSurfaceData);
|
||||
STDMETHODIMP UpdateOverlay(LPRECT lpSrcRect,LPDIRECTDRAWSURFACE lpDDDestSurface,LPRECT lpDestRect,DWORD dwFlags,LPDDOVERLAYFX lpDDOverlayFX);
|
||||
STDMETHODIMP UpdateOverlayDisplay(DWORD dwFlags);
|
||||
STDMETHODIMP UpdateOverlayZOrder(DWORD dwFlags,LPDIRECTDRAWSURFACE lpDDSReference);
|
||||
};
|
||||
|
||||
|
||||
// DirectShow must work on multiple platforms. In particular, it also runs on
|
||||
// Windows NT 3.51 which does not have DirectDraw capabilities. The filters
|
||||
// cannot therefore link statically to the DirectDraw library. To make their
|
||||
// lives that little bit easier we provide this class that manages loading
|
||||
// and unloading the library and creating the initial IDirectDraw interface
|
||||
|
||||
typedef DWORD (WINAPI *PGETFILEVERSIONINFOSIZE)(LPTSTR,LPDWORD);
|
||||
typedef BOOL (WINAPI *PGETFILEVERSIONINFO)(LPTSTR,DWORD,DWORD,LPVOID);
|
||||
typedef BOOL (WINAPI *PVERQUERYVALUE)(LPVOID,LPTSTR,LPVOID,PUINT);
|
||||
|
||||
class CLoadDirectDraw
|
||||
{
|
||||
LPDIRECTDRAW m_pDirectDraw; // The DirectDraw driver instance
|
||||
HINSTANCE m_hDirectDraw; // Handle to the loaded library
|
||||
|
||||
public:
|
||||
|
||||
CLoadDirectDraw();
|
||||
~CLoadDirectDraw();
|
||||
|
||||
HRESULT LoadDirectDraw(LPSTR szDevice);
|
||||
void ReleaseDirectDraw();
|
||||
HRESULT IsDirectDrawLoaded();
|
||||
LPDIRECTDRAW GetDirectDraw();
|
||||
BOOL IsDirectDrawVersion1();
|
||||
};
|
||||
|
||||
#endif // __VIDEOCTL__
|
||||
|
||||
|
||||
+468
-468
@@ -1,468 +1,468 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Vtrans.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <measure.h>
|
||||
// #include <vtransfr.h> // now in precomp file streams.h
|
||||
|
||||
CVideoTransformFilter::CVideoTransformFilter
|
||||
( TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid)
|
||||
: CTransformFilter(pName, pUnk, clsid)
|
||||
, m_itrLate(0)
|
||||
, m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames
|
||||
, m_nFramesSinceKeyFrame(0)
|
||||
, m_bSkipping(FALSE)
|
||||
, m_tDecodeStart(0)
|
||||
, m_itrAvgDecode(300000) // 30mSec - probably allows skipping
|
||||
, m_bQualityChanged(FALSE) {
|
||||
#ifdef PERF
|
||||
RegisterPerfId();
|
||||
#endif // PERF
|
||||
}
|
||||
|
||||
|
||||
CVideoTransformFilter::~CVideoTransformFilter() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
// Reset our quality management state
|
||||
|
||||
HRESULT CVideoTransformFilter::StartStreaming() {
|
||||
m_itrLate = 0;
|
||||
m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames
|
||||
m_nFramesSinceKeyFrame = 0;
|
||||
m_bSkipping = FALSE;
|
||||
m_tDecodeStart = 0;
|
||||
m_itrAvgDecode = 300000; // 30mSec - probably allows skipping
|
||||
m_bQualityChanged = FALSE;
|
||||
m_bSampleSkipped = FALSE;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Overriden to reset quality management information
|
||||
|
||||
HRESULT CVideoTransformFilter::EndFlush() { {
|
||||
// Synchronize
|
||||
CAutoLock lck(&m_csReceive);
|
||||
|
||||
// Reset our stats
|
||||
//
|
||||
// Note - we don't want to call derived classes here,
|
||||
// we only want to reset our internal variables and this
|
||||
// is a convenient way to do it
|
||||
CVideoTransformFilter::StartStreaming();
|
||||
}
|
||||
return CTransformFilter::EndFlush();
|
||||
}
|
||||
|
||||
|
||||
HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) {
|
||||
NotifyEvent(EC_ERRORABORT, hr, 0);
|
||||
m_pOutput->DeliverEndOfStream();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Receive()
|
||||
//
|
||||
// Accept a sample from upstream, decide whether to process it
|
||||
// or drop it. If we process it then get a buffer from the
|
||||
// allocator of the downstream connection, transform it into the
|
||||
// new buffer and deliver it to the downstream filter.
|
||||
// If we decide not to process it then we do not get a buffer.
|
||||
|
||||
// Remember that although this code will notice format changes coming into
|
||||
// the input pin, it will NOT change its output format if that results
|
||||
// in the filter needing to make a corresponding output format change. Your
|
||||
// derived filter will have to take care of that. (eg. a palette change if
|
||||
// the input and output is an 8 bit format). If the input sample is discarded
|
||||
// and nothing is sent out for this Receive, please remember to put the format
|
||||
// change on the first output sample that you actually do send.
|
||||
// If your filter will produce the same output type even when the input type
|
||||
// changes, then this base class code will do everything you need.
|
||||
|
||||
HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) {
|
||||
// If the next filter downstream is the video renderer, then it may
|
||||
// be able to operate in DirectDraw mode which saves copying the data
|
||||
// and gives higher performance. In that case the buffer which we
|
||||
// get from GetDeliveryBuffer will be a DirectDraw buffer, and
|
||||
// drawing into this buffer draws directly onto the display surface.
|
||||
// This means that any waiting for the correct time to draw occurs
|
||||
// during GetDeliveryBuffer, and that once the buffer is given to us
|
||||
// the video renderer will count it in its statistics as a frame drawn.
|
||||
// This means that any decision to drop the frame must be taken before
|
||||
// calling GetDeliveryBuffer.
|
||||
|
||||
ASSERT(CritCheckIn(&m_csReceive));
|
||||
AM_MEDIA_TYPE *pmtOut, *pmt;
|
||||
#ifdef DEBUG
|
||||
FOURCCMap fccOut;
|
||||
#endif
|
||||
HRESULT hr;
|
||||
ASSERT(pSample);
|
||||
IMediaSample * pOutSample;
|
||||
|
||||
// If no output pin to deliver to then no point sending us data
|
||||
ASSERT(m_pOutput != NULL) ;
|
||||
|
||||
// The source filter may dynamically ask us to start transforming from a
|
||||
// different media type than the one we're using now. If we don't, we'll
|
||||
// draw garbage. (typically, this is a palette change in the movie,
|
||||
// but could be something more sinister like the compression type changing,
|
||||
// or even the video size changing)
|
||||
|
||||
#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource
|
||||
#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget
|
||||
|
||||
pSample->GetMediaType(&pmt);
|
||||
if(pmt != NULL && pmt->pbFormat != NULL) {
|
||||
|
||||
// spew some debug output
|
||||
ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL));
|
||||
#ifdef DEBUG
|
||||
fccOut.SetFOURCC(&pmt->subtype);
|
||||
LONG lCompression = HEADER(pmt->pbFormat)->biCompression;
|
||||
LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount;
|
||||
LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8;
|
||||
lStride = (lStride + 3) & ~3;
|
||||
DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to")));
|
||||
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
|
||||
fccOut.GetFOURCC(), lCompression, lBitCount));
|
||||
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
|
||||
HEADER(pmt->pbFormat)->biHeight,
|
||||
rcT1.left, rcT1.top, rcT1.right, rcT1.bottom));
|
||||
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
|
||||
rcS1.left, rcS1.top, rcS1.right, rcS1.bottom,
|
||||
lStride));
|
||||
#endif
|
||||
|
||||
// now switch to using the new format. I am assuming that the
|
||||
// derived filter will do the right thing when its media type is
|
||||
// switched and streaming is restarted.
|
||||
|
||||
StopStreaming();
|
||||
m_pInput->CurrentMediaType() = *pmt;
|
||||
DeleteMediaType(pmt);
|
||||
// if this fails, playback will stop, so signal an error
|
||||
hr = StartStreaming();
|
||||
if(FAILED(hr)) {
|
||||
return AbortPlayback(hr);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have noticed any format changes on the input sample, it's
|
||||
// OK to discard it.
|
||||
|
||||
if(ShouldSkipFrame(pSample)) {
|
||||
MSR_NOTE(m_idSkip);
|
||||
m_bSampleSkipped = TRUE;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Set up the output sample
|
||||
hr = InitializeOutputSample(pSample, &pOutSample);
|
||||
|
||||
if(FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_bSampleSkipped = FALSE;
|
||||
|
||||
// The renderer may ask us to on-the-fly to start transforming to a
|
||||
// different format. If we don't obey it, we'll draw garbage
|
||||
|
||||
#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource
|
||||
#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget
|
||||
|
||||
pOutSample->GetMediaType(&pmtOut);
|
||||
if(pmtOut != NULL && pmtOut->pbFormat != NULL) {
|
||||
|
||||
// spew some debug output
|
||||
ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL));
|
||||
#ifdef DEBUG
|
||||
fccOut.SetFOURCC(&pmtOut->subtype);
|
||||
LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression;
|
||||
LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount;
|
||||
LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8;
|
||||
lStride = (lStride + 3) & ~3;
|
||||
DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to")));
|
||||
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
|
||||
fccOut.GetFOURCC(), lCompression, lBitCount));
|
||||
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
|
||||
HEADER(pmtOut->pbFormat)->biHeight,
|
||||
rcT.left, rcT.top, rcT.right, rcT.bottom));
|
||||
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
|
||||
rcS.left, rcS.top, rcS.right, rcS.bottom,
|
||||
lStride));
|
||||
#endif
|
||||
|
||||
// now switch to using the new format. I am assuming that the
|
||||
// derived filter will do the right thing when its media type is
|
||||
// switched and streaming is restarted.
|
||||
|
||||
StopStreaming();
|
||||
m_pOutput->CurrentMediaType() = *pmtOut;
|
||||
DeleteMediaType(pmtOut);
|
||||
hr = StartStreaming();
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
// a new format, means a new empty buffer, so wait for a keyframe
|
||||
// before passing anything on to the renderer.
|
||||
// !!! a keyframe may never come, so give up after 30 frames
|
||||
DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe")));
|
||||
m_nWaitForKey = 30;
|
||||
|
||||
// if this fails, playback will stop, so signal an error
|
||||
}
|
||||
else {
|
||||
|
||||
// Must release the sample before calling AbortPlayback
|
||||
// because we might be holding the win16 lock or
|
||||
// ddraw lock
|
||||
pOutSample->Release();
|
||||
AbortPlayback(hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
// After a discontinuity, we need to wait for the next key frame
|
||||
if(pSample->IsDiscontinuity() == S_OK) {
|
||||
DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe")));
|
||||
m_nWaitForKey = 30;
|
||||
}
|
||||
|
||||
// Start timing the transform (and log it if PERF is defined)
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
m_tDecodeStart = timeGetTime();
|
||||
MSR_START(m_idTransform);
|
||||
|
||||
// have the derived class transform the data
|
||||
hr = Transform(pSample, pOutSample);
|
||||
|
||||
// Stop the clock (and log it if PERF is defined)
|
||||
MSR_STOP(m_idTransform);
|
||||
m_tDecodeStart = timeGetTime()-m_tDecodeStart;
|
||||
m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16);
|
||||
|
||||
// Maybe we're waiting for a keyframe still?
|
||||
if(m_nWaitForKey)
|
||||
m_nWaitForKey--;
|
||||
if(m_nWaitForKey && pSample->IsSyncPoint() == S_OK)
|
||||
m_nWaitForKey = FALSE;
|
||||
|
||||
// if so, then we don't want to pass this on to the renderer
|
||||
if(m_nWaitForKey && hr == NOERROR) {
|
||||
DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe")));
|
||||
hr = S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(FAILED(hr)) {
|
||||
DbgLog((LOG_TRACE,1,TEXT("Error from video transform")));
|
||||
}
|
||||
else {
|
||||
// the Transform() function can return S_FALSE to indicate that the
|
||||
// sample should not be delivered; we only deliver the sample if it's
|
||||
// really S_OK (same as NOERROR, of course.)
|
||||
// Try not to return S_FALSE to a direct draw buffer (it's wasteful)
|
||||
// Try to take the decision earlier - before you get it.
|
||||
|
||||
if(hr == NOERROR) {
|
||||
hr = m_pOutput->Deliver(pOutSample);
|
||||
}
|
||||
else {
|
||||
// S_FALSE returned from Transform is a PRIVATE agreement
|
||||
// We should return NOERROR from Receive() in this case because returning S_FALSE
|
||||
// from Receive() means that this is the end of the stream and no more data should
|
||||
// be sent.
|
||||
if(S_FALSE == hr) {
|
||||
|
||||
// We must Release() the sample before doing anything
|
||||
// like calling the filter graph because having the
|
||||
// sample means we may have the DirectDraw lock
|
||||
// (== win16 lock on some versions)
|
||||
pOutSample->Release();
|
||||
m_bSampleSkipped = TRUE;
|
||||
if(!m_bQualityChanged) {
|
||||
m_bQualityChanged = TRUE;
|
||||
NotifyEvent(EC_QUALITY_CHANGE,0,0);
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release the output buffer. If the connected pin still needs it,
|
||||
// it will have addrefed it itself.
|
||||
pOutSample->Release();
|
||||
ASSERT(CritCheckIn(&m_csReceive));
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) {
|
||||
REFERENCE_TIME trStart, trStopAt;
|
||||
HRESULT hr = pIn->GetTime(&trStart, &trStopAt);
|
||||
|
||||
// Don't skip frames with no timestamps
|
||||
if(hr != S_OK)
|
||||
return FALSE;
|
||||
|
||||
int itrFrame = (int)(trStopAt - trStart); // frame duration
|
||||
|
||||
if(S_OK==pIn->IsSyncPoint()) {
|
||||
MSR_INTEGER(m_idFrameType, 1);
|
||||
if(m_nKeyFramePeriod < m_nFramesSinceKeyFrame) {
|
||||
// record the max
|
||||
m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
|
||||
}
|
||||
m_nFramesSinceKeyFrame = 0;
|
||||
m_bSkipping = FALSE;
|
||||
}
|
||||
else {
|
||||
MSR_INTEGER(m_idFrameType, 2);
|
||||
if(m_nFramesSinceKeyFrame>m_nKeyFramePeriod
|
||||
&& m_nKeyFramePeriod>0) {
|
||||
// We haven't seen the key frame yet, but we were clearly being
|
||||
// overoptimistic about how frequent they are.
|
||||
m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Whatever we might otherwise decide,
|
||||
// if we are taking only a small fraction of the required frame time to decode
|
||||
// then any quality problems are actually coming from somewhere else.
|
||||
// Could be a net problem at the source for instance. In this case there's
|
||||
// no point in us skipping frames here.
|
||||
if(m_itrAvgDecode*4>itrFrame) {
|
||||
|
||||
// Don't skip unless we are at least a whole frame late.
|
||||
// (We would skip B frames if more than 1/2 frame late, but they're safe).
|
||||
if(m_itrLate > itrFrame) {
|
||||
|
||||
// Don't skip unless the anticipated key frame would be no more than
|
||||
// 1 frame early. If the renderer has not been waiting (we *guess*
|
||||
// it hasn't because we're late) then it will allow frames to be
|
||||
// played early by up to a frame.
|
||||
|
||||
// Let T = Stream time from now to anticipated next key frame
|
||||
// = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame)
|
||||
// So we skip if T - Late < one frame i.e.
|
||||
// (duration) * (freq - FramesSince) - Late < duration
|
||||
// or (duration) * (freq - FramesSince - 1) < Late
|
||||
|
||||
// We don't dare skip until we have seen some key frames and have
|
||||
// some idea how often they occur and they are reasonably frequent.
|
||||
if(m_nKeyFramePeriod>0) {
|
||||
// It would be crazy - but we could have a stream with key frames
|
||||
// a very long way apart - and if they are further than about
|
||||
// 3.5 minutes apart then we could get arithmetic overflow in
|
||||
// reference time units. Therefore we switch to mSec at this point
|
||||
int it = (itrFrame/10000)
|
||||
* (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1);
|
||||
MSR_INTEGER(m_idTimeTillKey, it);
|
||||
|
||||
// For debug - might want to see the details - dump them as scratch pad
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
MSR_INTEGER(0, m_nFramesSinceKeyFrame);
|
||||
MSR_INTEGER(0, m_nKeyFramePeriod);
|
||||
#endif
|
||||
if(m_itrLate/10000 > it) {
|
||||
m_bSkipping = TRUE;
|
||||
// Now we are committed. Once we start skipping, we
|
||||
// cannot stop until we hit a key frame.
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777770); // not near enough to next key
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777771); // Next key not predictable
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777772); // Less than one frame late
|
||||
MSR_INTEGER(0, m_itrLate);
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping
|
||||
MSR_INTEGER(0, m_itrAvgDecode);
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
++m_nFramesSinceKeyFrame;
|
||||
|
||||
if(m_bSkipping) {
|
||||
// We will count down the lateness as we skip each frame.
|
||||
// We re-assess each frame. The key frame might not arrive when expected.
|
||||
// We reset m_itrLate if we get a new Quality message, but actually that's
|
||||
// not likely because we're not sending frames on to the Renderer. In
|
||||
// fact if we DID get another one it would mean that there's a long
|
||||
// pipe between us and the renderer and we might need an altogether
|
||||
// better strategy to avoid hunting!
|
||||
m_itrLate = m_itrLate - itrFrame;
|
||||
}
|
||||
|
||||
MSR_INTEGER(m_idLate, (int)m_itrLate/10000); // Note how late we think we are
|
||||
if(m_bSkipping) {
|
||||
if(!m_bQualityChanged) {
|
||||
m_bQualityChanged = TRUE;
|
||||
NotifyEvent(EC_QUALITY_CHANGE,0,0);
|
||||
}
|
||||
}
|
||||
return m_bSkipping;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CVideoTransformFilter::AlterQuality(Quality q) {
|
||||
// to reduce the amount of 64 bit arithmetic, m_itrLate is an int.
|
||||
// +, -, >, == etc are not too bad, but * and / are painful.
|
||||
if(m_itrLate>300000000) {
|
||||
// Avoid overflow and silliness - more than 30 secs late is already silly
|
||||
m_itrLate = 300000000;
|
||||
}
|
||||
else {
|
||||
m_itrLate = (int)q.Late;
|
||||
}
|
||||
// We ignore the other fields
|
||||
|
||||
// We're actually not very good at handling this. In non-direct draw mode
|
||||
// most of the time can be spent in the renderer which can skip any frame.
|
||||
// In that case we'd rather the renderer handled things.
|
||||
// Nevertheless we will keep an eye on it and if we really start getting
|
||||
// a very long way behind then we will actually skip - but we'll still tell
|
||||
// the renderer (or whoever is downstream) that they should handle quality.
|
||||
|
||||
return E_FAIL; // Tell the renderer to do his thing.
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4
|
||||
#pragma warning(disable:4514)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: Vtrans.cpp
|
||||
//
|
||||
// Desc: DirectShow base classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <streams.h>
|
||||
#include <measure.h>
|
||||
// #include <vtransfr.h> // now in precomp file streams.h
|
||||
|
||||
CVideoTransformFilter::CVideoTransformFilter
|
||||
( TCHAR *pName, LPUNKNOWN pUnk, REFCLSID clsid)
|
||||
: CTransformFilter(pName, pUnk, clsid)
|
||||
, m_itrLate(0)
|
||||
, m_nKeyFramePeriod(0) // No QM until we see at least 2 key frames
|
||||
, m_nFramesSinceKeyFrame(0)
|
||||
, m_bSkipping(FALSE)
|
||||
, m_tDecodeStart(0)
|
||||
, m_itrAvgDecode(300000) // 30mSec - probably allows skipping
|
||||
, m_bQualityChanged(FALSE) {
|
||||
#ifdef PERF
|
||||
RegisterPerfId();
|
||||
#endif // PERF
|
||||
}
|
||||
|
||||
|
||||
CVideoTransformFilter::~CVideoTransformFilter() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
// Reset our quality management state
|
||||
|
||||
HRESULT CVideoTransformFilter::StartStreaming() {
|
||||
m_itrLate = 0;
|
||||
m_nKeyFramePeriod = 0; // No QM until we see at least 2 key frames
|
||||
m_nFramesSinceKeyFrame = 0;
|
||||
m_bSkipping = FALSE;
|
||||
m_tDecodeStart = 0;
|
||||
m_itrAvgDecode = 300000; // 30mSec - probably allows skipping
|
||||
m_bQualityChanged = FALSE;
|
||||
m_bSampleSkipped = FALSE;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
|
||||
// Overriden to reset quality management information
|
||||
|
||||
HRESULT CVideoTransformFilter::EndFlush() { {
|
||||
// Synchronize
|
||||
CAutoLock lck(&m_csReceive);
|
||||
|
||||
// Reset our stats
|
||||
//
|
||||
// Note - we don't want to call derived classes here,
|
||||
// we only want to reset our internal variables and this
|
||||
// is a convenient way to do it
|
||||
CVideoTransformFilter::StartStreaming();
|
||||
}
|
||||
return CTransformFilter::EndFlush();
|
||||
}
|
||||
|
||||
|
||||
HRESULT CVideoTransformFilter::AbortPlayback(HRESULT hr) {
|
||||
NotifyEvent(EC_ERRORABORT, hr, 0);
|
||||
m_pOutput->DeliverEndOfStream();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
// Receive()
|
||||
//
|
||||
// Accept a sample from upstream, decide whether to process it
|
||||
// or drop it. If we process it then get a buffer from the
|
||||
// allocator of the downstream connection, transform it into the
|
||||
// new buffer and deliver it to the downstream filter.
|
||||
// If we decide not to process it then we do not get a buffer.
|
||||
|
||||
// Remember that although this code will notice format changes coming into
|
||||
// the input pin, it will NOT change its output format if that results
|
||||
// in the filter needing to make a corresponding output format change. Your
|
||||
// derived filter will have to take care of that. (eg. a palette change if
|
||||
// the input and output is an 8 bit format). If the input sample is discarded
|
||||
// and nothing is sent out for this Receive, please remember to put the format
|
||||
// change on the first output sample that you actually do send.
|
||||
// If your filter will produce the same output type even when the input type
|
||||
// changes, then this base class code will do everything you need.
|
||||
|
||||
HRESULT CVideoTransformFilter::Receive(IMediaSample *pSample) {
|
||||
// If the next filter downstream is the video renderer, then it may
|
||||
// be able to operate in DirectDraw mode which saves copying the data
|
||||
// and gives higher performance. In that case the buffer which we
|
||||
// get from GetDeliveryBuffer will be a DirectDraw buffer, and
|
||||
// drawing into this buffer draws directly onto the display surface.
|
||||
// This means that any waiting for the correct time to draw occurs
|
||||
// during GetDeliveryBuffer, and that once the buffer is given to us
|
||||
// the video renderer will count it in its statistics as a frame drawn.
|
||||
// This means that any decision to drop the frame must be taken before
|
||||
// calling GetDeliveryBuffer.
|
||||
|
||||
ASSERT(CritCheckIn(&m_csReceive));
|
||||
AM_MEDIA_TYPE *pmtOut, *pmt;
|
||||
#ifdef DEBUG
|
||||
FOURCCMap fccOut;
|
||||
#endif
|
||||
HRESULT hr;
|
||||
ASSERT(pSample);
|
||||
IMediaSample * pOutSample;
|
||||
|
||||
// If no output pin to deliver to then no point sending us data
|
||||
ASSERT(m_pOutput != NULL) ;
|
||||
|
||||
// The source filter may dynamically ask us to start transforming from a
|
||||
// different media type than the one we're using now. If we don't, we'll
|
||||
// draw garbage. (typically, this is a palette change in the movie,
|
||||
// but could be something more sinister like the compression type changing,
|
||||
// or even the video size changing)
|
||||
|
||||
#define rcS1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcSource
|
||||
#define rcT1 ((VIDEOINFOHEADER *)(pmt->pbFormat))->rcTarget
|
||||
|
||||
pSample->GetMediaType(&pmt);
|
||||
if(pmt != NULL && pmt->pbFormat != NULL) {
|
||||
|
||||
// spew some debug output
|
||||
ASSERT(!IsEqualGUID(pmt->majortype, GUID_NULL));
|
||||
#ifdef DEBUG
|
||||
fccOut.SetFOURCC(&pmt->subtype);
|
||||
LONG lCompression = HEADER(pmt->pbFormat)->biCompression;
|
||||
LONG lBitCount = HEADER(pmt->pbFormat)->biBitCount;
|
||||
LONG lStride = (HEADER(pmt->pbFormat)->biWidth * lBitCount + 7) / 8;
|
||||
lStride = (lStride + 3) & ~3;
|
||||
DbgLog((LOG_TRACE,3,TEXT("*Changing input type on the fly to")));
|
||||
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
|
||||
fccOut.GetFOURCC(), lCompression, lBitCount));
|
||||
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
|
||||
HEADER(pmt->pbFormat)->biHeight,
|
||||
rcT1.left, rcT1.top, rcT1.right, rcT1.bottom));
|
||||
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
|
||||
rcS1.left, rcS1.top, rcS1.right, rcS1.bottom,
|
||||
lStride));
|
||||
#endif
|
||||
|
||||
// now switch to using the new format. I am assuming that the
|
||||
// derived filter will do the right thing when its media type is
|
||||
// switched and streaming is restarted.
|
||||
|
||||
StopStreaming();
|
||||
m_pInput->CurrentMediaType() = *pmt;
|
||||
DeleteMediaType(pmt);
|
||||
// if this fails, playback will stop, so signal an error
|
||||
hr = StartStreaming();
|
||||
if(FAILED(hr)) {
|
||||
return AbortPlayback(hr);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have noticed any format changes on the input sample, it's
|
||||
// OK to discard it.
|
||||
|
||||
if(ShouldSkipFrame(pSample)) {
|
||||
MSR_NOTE(m_idSkip);
|
||||
m_bSampleSkipped = TRUE;
|
||||
return NOERROR;
|
||||
}
|
||||
|
||||
// Set up the output sample
|
||||
hr = InitializeOutputSample(pSample, &pOutSample);
|
||||
|
||||
if(FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
m_bSampleSkipped = FALSE;
|
||||
|
||||
// The renderer may ask us to on-the-fly to start transforming to a
|
||||
// different format. If we don't obey it, we'll draw garbage
|
||||
|
||||
#define rcS ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcSource
|
||||
#define rcT ((VIDEOINFOHEADER *)(pmtOut->pbFormat))->rcTarget
|
||||
|
||||
pOutSample->GetMediaType(&pmtOut);
|
||||
if(pmtOut != NULL && pmtOut->pbFormat != NULL) {
|
||||
|
||||
// spew some debug output
|
||||
ASSERT(!IsEqualGUID(pmtOut->majortype, GUID_NULL));
|
||||
#ifdef DEBUG
|
||||
fccOut.SetFOURCC(&pmtOut->subtype);
|
||||
LONG lCompression = HEADER(pmtOut->pbFormat)->biCompression;
|
||||
LONG lBitCount = HEADER(pmtOut->pbFormat)->biBitCount;
|
||||
LONG lStride = (HEADER(pmtOut->pbFormat)->biWidth * lBitCount + 7) / 8;
|
||||
lStride = (lStride + 3) & ~3;
|
||||
DbgLog((LOG_TRACE,3,TEXT("*Changing output type on the fly to")));
|
||||
DbgLog((LOG_TRACE,3,TEXT("FourCC: %lx Compression: %lx BitCount: %ld"),
|
||||
fccOut.GetFOURCC(), lCompression, lBitCount));
|
||||
DbgLog((LOG_TRACE,3,TEXT("biHeight: %ld rcDst: (%ld, %ld, %ld, %ld)"),
|
||||
HEADER(pmtOut->pbFormat)->biHeight,
|
||||
rcT.left, rcT.top, rcT.right, rcT.bottom));
|
||||
DbgLog((LOG_TRACE,3,TEXT("rcSrc: (%ld, %ld, %ld, %ld) Stride: %ld"),
|
||||
rcS.left, rcS.top, rcS.right, rcS.bottom,
|
||||
lStride));
|
||||
#endif
|
||||
|
||||
// now switch to using the new format. I am assuming that the
|
||||
// derived filter will do the right thing when its media type is
|
||||
// switched and streaming is restarted.
|
||||
|
||||
StopStreaming();
|
||||
m_pOutput->CurrentMediaType() = *pmtOut;
|
||||
DeleteMediaType(pmtOut);
|
||||
hr = StartStreaming();
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
// a new format, means a new empty buffer, so wait for a keyframe
|
||||
// before passing anything on to the renderer.
|
||||
// !!! a keyframe may never come, so give up after 30 frames
|
||||
DbgLog((LOG_TRACE,3,TEXT("Output format change means we must wait for a keyframe")));
|
||||
m_nWaitForKey = 30;
|
||||
|
||||
// if this fails, playback will stop, so signal an error
|
||||
}
|
||||
else {
|
||||
|
||||
// Must release the sample before calling AbortPlayback
|
||||
// because we might be holding the win16 lock or
|
||||
// ddraw lock
|
||||
pOutSample->Release();
|
||||
AbortPlayback(hr);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
// After a discontinuity, we need to wait for the next key frame
|
||||
if(pSample->IsDiscontinuity() == S_OK) {
|
||||
DbgLog((LOG_TRACE,3,TEXT("Non-key discontinuity - wait for keyframe")));
|
||||
m_nWaitForKey = 30;
|
||||
}
|
||||
|
||||
// Start timing the transform (and log it if PERF is defined)
|
||||
|
||||
if(SUCCEEDED(hr)) {
|
||||
m_tDecodeStart = timeGetTime();
|
||||
MSR_START(m_idTransform);
|
||||
|
||||
// have the derived class transform the data
|
||||
hr = Transform(pSample, pOutSample);
|
||||
|
||||
// Stop the clock (and log it if PERF is defined)
|
||||
MSR_STOP(m_idTransform);
|
||||
m_tDecodeStart = timeGetTime()-m_tDecodeStart;
|
||||
m_itrAvgDecode = m_tDecodeStart*(10000/16) + 15*(m_itrAvgDecode/16);
|
||||
|
||||
// Maybe we're waiting for a keyframe still?
|
||||
if(m_nWaitForKey)
|
||||
m_nWaitForKey--;
|
||||
if(m_nWaitForKey && pSample->IsSyncPoint() == S_OK)
|
||||
m_nWaitForKey = FALSE;
|
||||
|
||||
// if so, then we don't want to pass this on to the renderer
|
||||
if(m_nWaitForKey && hr == NOERROR) {
|
||||
DbgLog((LOG_TRACE,3,TEXT("still waiting for a keyframe")));
|
||||
hr = S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if(FAILED(hr)) {
|
||||
DbgLog((LOG_TRACE,1,TEXT("Error from video transform")));
|
||||
}
|
||||
else {
|
||||
// the Transform() function can return S_FALSE to indicate that the
|
||||
// sample should not be delivered; we only deliver the sample if it's
|
||||
// really S_OK (same as NOERROR, of course.)
|
||||
// Try not to return S_FALSE to a direct draw buffer (it's wasteful)
|
||||
// Try to take the decision earlier - before you get it.
|
||||
|
||||
if(hr == NOERROR) {
|
||||
hr = m_pOutput->Deliver(pOutSample);
|
||||
}
|
||||
else {
|
||||
// S_FALSE returned from Transform is a PRIVATE agreement
|
||||
// We should return NOERROR from Receive() in this case because returning S_FALSE
|
||||
// from Receive() means that this is the end of the stream and no more data should
|
||||
// be sent.
|
||||
if(S_FALSE == hr) {
|
||||
|
||||
// We must Release() the sample before doing anything
|
||||
// like calling the filter graph because having the
|
||||
// sample means we may have the DirectDraw lock
|
||||
// (== win16 lock on some versions)
|
||||
pOutSample->Release();
|
||||
m_bSampleSkipped = TRUE;
|
||||
if(!m_bQualityChanged) {
|
||||
m_bQualityChanged = TRUE;
|
||||
NotifyEvent(EC_QUALITY_CHANGE,0,0);
|
||||
}
|
||||
return NOERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// release the output buffer. If the connected pin still needs it,
|
||||
// it will have addrefed it itself.
|
||||
pOutSample->Release();
|
||||
ASSERT(CritCheckIn(&m_csReceive));
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOL CVideoTransformFilter::ShouldSkipFrame( IMediaSample * pIn) {
|
||||
REFERENCE_TIME trStart, trStopAt;
|
||||
HRESULT hr = pIn->GetTime(&trStart, &trStopAt);
|
||||
|
||||
// Don't skip frames with no timestamps
|
||||
if(hr != S_OK)
|
||||
return FALSE;
|
||||
|
||||
int itrFrame = (int)(trStopAt - trStart); // frame duration
|
||||
|
||||
if(S_OK==pIn->IsSyncPoint()) {
|
||||
MSR_INTEGER(m_idFrameType, 1);
|
||||
if(m_nKeyFramePeriod < m_nFramesSinceKeyFrame) {
|
||||
// record the max
|
||||
m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
|
||||
}
|
||||
m_nFramesSinceKeyFrame = 0;
|
||||
m_bSkipping = FALSE;
|
||||
}
|
||||
else {
|
||||
MSR_INTEGER(m_idFrameType, 2);
|
||||
if(m_nFramesSinceKeyFrame>m_nKeyFramePeriod
|
||||
&& m_nKeyFramePeriod>0) {
|
||||
// We haven't seen the key frame yet, but we were clearly being
|
||||
// overoptimistic about how frequent they are.
|
||||
m_nKeyFramePeriod = m_nFramesSinceKeyFrame;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Whatever we might otherwise decide,
|
||||
// if we are taking only a small fraction of the required frame time to decode
|
||||
// then any quality problems are actually coming from somewhere else.
|
||||
// Could be a net problem at the source for instance. In this case there's
|
||||
// no point in us skipping frames here.
|
||||
if(m_itrAvgDecode*4>itrFrame) {
|
||||
|
||||
// Don't skip unless we are at least a whole frame late.
|
||||
// (We would skip B frames if more than 1/2 frame late, but they're safe).
|
||||
if(m_itrLate > itrFrame) {
|
||||
|
||||
// Don't skip unless the anticipated key frame would be no more than
|
||||
// 1 frame early. If the renderer has not been waiting (we *guess*
|
||||
// it hasn't because we're late) then it will allow frames to be
|
||||
// played early by up to a frame.
|
||||
|
||||
// Let T = Stream time from now to anticipated next key frame
|
||||
// = (frame duration) * (KeyFramePeriod - FramesSinceKeyFrame)
|
||||
// So we skip if T - Late < one frame i.e.
|
||||
// (duration) * (freq - FramesSince) - Late < duration
|
||||
// or (duration) * (freq - FramesSince - 1) < Late
|
||||
|
||||
// We don't dare skip until we have seen some key frames and have
|
||||
// some idea how often they occur and they are reasonably frequent.
|
||||
if(m_nKeyFramePeriod>0) {
|
||||
// It would be crazy - but we could have a stream with key frames
|
||||
// a very long way apart - and if they are further than about
|
||||
// 3.5 minutes apart then we could get arithmetic overflow in
|
||||
// reference time units. Therefore we switch to mSec at this point
|
||||
int it = (itrFrame/10000)
|
||||
* (m_nKeyFramePeriod-m_nFramesSinceKeyFrame - 1);
|
||||
MSR_INTEGER(m_idTimeTillKey, it);
|
||||
|
||||
// For debug - might want to see the details - dump them as scratch pad
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
MSR_INTEGER(0, m_nFramesSinceKeyFrame);
|
||||
MSR_INTEGER(0, m_nKeyFramePeriod);
|
||||
#endif
|
||||
if(m_itrLate/10000 > it) {
|
||||
m_bSkipping = TRUE;
|
||||
// Now we are committed. Once we start skipping, we
|
||||
// cannot stop until we hit a key frame.
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777770); // not near enough to next key
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777771); // Next key not predictable
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777772); // Less than one frame late
|
||||
MSR_INTEGER(0, m_itrLate);
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef VTRANSPERF
|
||||
MSR_INTEGER(0, 777773); // Decode time short - not not worth skipping
|
||||
MSR_INTEGER(0, m_itrAvgDecode);
|
||||
MSR_INTEGER(0, itrFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
++m_nFramesSinceKeyFrame;
|
||||
|
||||
if(m_bSkipping) {
|
||||
// We will count down the lateness as we skip each frame.
|
||||
// We re-assess each frame. The key frame might not arrive when expected.
|
||||
// We reset m_itrLate if we get a new Quality message, but actually that's
|
||||
// not likely because we're not sending frames on to the Renderer. In
|
||||
// fact if we DID get another one it would mean that there's a long
|
||||
// pipe between us and the renderer and we might need an altogether
|
||||
// better strategy to avoid hunting!
|
||||
m_itrLate = m_itrLate - itrFrame;
|
||||
}
|
||||
|
||||
MSR_INTEGER(m_idLate, (int)m_itrLate/10000); // Note how late we think we are
|
||||
if(m_bSkipping) {
|
||||
if(!m_bQualityChanged) {
|
||||
m_bQualityChanged = TRUE;
|
||||
NotifyEvent(EC_QUALITY_CHANGE,0,0);
|
||||
}
|
||||
}
|
||||
return m_bSkipping;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CVideoTransformFilter::AlterQuality(Quality q) {
|
||||
// to reduce the amount of 64 bit arithmetic, m_itrLate is an int.
|
||||
// +, -, >, == etc are not too bad, but * and / are painful.
|
||||
if(m_itrLate>300000000) {
|
||||
// Avoid overflow and silliness - more than 30 secs late is already silly
|
||||
m_itrLate = 300000000;
|
||||
}
|
||||
else {
|
||||
m_itrLate = (int)q.Late;
|
||||
}
|
||||
// We ignore the other fields
|
||||
|
||||
// We're actually not very good at handling this. In non-direct draw mode
|
||||
// most of the time can be spent in the renderer which can skip any frame.
|
||||
// In that case we'd rather the renderer handled things.
|
||||
// Nevertheless we will keep an eye on it and if we really start getting
|
||||
// a very long way behind then we will actually skip - but we'll still tell
|
||||
// the renderer (or whoever is downstream) that they should handle quality.
|
||||
|
||||
return E_FAIL; // Tell the renderer to do his thing.
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This will avoid several hundred useless warnings if compiled -W4 by MS VC++ v4
|
||||
#pragma warning(disable:4514)
|
||||
|
||||
|
||||
|
||||
+143
-143
@@ -1,143 +1,143 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: VTrans.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a video transform class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// This class is derived from CTransformFilter, but is specialised to handle
|
||||
// the requirements of video quality control by frame dropping.
|
||||
// This is a non-in-place transform, (i.e. it copies the data) such as a decoder.
|
||||
|
||||
class CVideoTransformFilter : public CTransformFilter
|
||||
{
|
||||
public:
|
||||
|
||||
CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
~CVideoTransformFilter();
|
||||
HRESULT EndFlush();
|
||||
|
||||
// =================================================================
|
||||
// ----- override these bits ---------------------------------------
|
||||
// =================================================================
|
||||
// The following methods are in CTransformFilter which is inherited.
|
||||
// They are mentioned here for completeness
|
||||
//
|
||||
// These MUST be supplied in a derived class
|
||||
//
|
||||
// NOTE:
|
||||
// virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
|
||||
// virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
|
||||
// virtual HRESULT CheckTransform
|
||||
// (const CMediaType* mtIn, const CMediaType* mtOut) PURE;
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
// virtual HRESULT DecideBufferSize
|
||||
// (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE;
|
||||
// virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
|
||||
//
|
||||
// These MAY also be overridden
|
||||
//
|
||||
// virtual HRESULT StopStreaming();
|
||||
// virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
|
||||
// virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
|
||||
// virtual HRESULT BreakConnect(PIN_DIRECTION dir);
|
||||
// virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
|
||||
// virtual HRESULT EndOfStream(void);
|
||||
// virtual HRESULT BeginFlush(void);
|
||||
// virtual HRESULT EndFlush(void);
|
||||
// virtual HRESULT NewSegment
|
||||
// (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate);
|
||||
#ifdef PERF
|
||||
|
||||
// If you override this - ensure that you register all these ids
|
||||
// as well as any of your own,
|
||||
virtual void RegisterPerfId() {
|
||||
m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame"));
|
||||
m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type"));
|
||||
m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness"));
|
||||
m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key"));
|
||||
CTransformFilter::RegisterPerfId();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
// =========== QUALITY MANAGEMENT IMPLEMENTATION ========================
|
||||
// Frames are assumed to come in three types:
|
||||
// Type 1: an AVI key frame or an MPEG I frame.
|
||||
// This frame can be decoded with no history.
|
||||
// Dropping this frame means that no further frame can be decoded
|
||||
// until the next type 1 frame.
|
||||
// Type 1 frames are sync points.
|
||||
// Type 2: an AVI non-key frame or an MPEG P frame.
|
||||
// This frame cannot be decoded unless the previous type 1 frame was
|
||||
// decoded and all type 2 frames since have been decoded.
|
||||
// Dropping this frame means that no further frame can be decoded
|
||||
// until the next type 1 frame.
|
||||
// Type 3: An MPEG B frame.
|
||||
// This frame cannot be decoded unless the previous type 1 or 2 frame
|
||||
// has been decoded AND the subsequent type 1 or 2 frame has also
|
||||
// been decoded. (This requires decoding the frames out of sequence).
|
||||
// Dropping this frame affects no other frames. This implementation
|
||||
// does not allow for these. All non-sync-point frames are treated
|
||||
// as being type 2.
|
||||
//
|
||||
// The spacing of frames of type 1 in a file is not guaranteed. There MUST
|
||||
// be a type 1 frame at (well, near) the start of the file in order to start
|
||||
// decoding at all. After that there could be one every half second or so,
|
||||
// there could be one at the start of each scene (aka "cut", "shot") or
|
||||
// there could be no more at all.
|
||||
// If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED
|
||||
// without losing all the rest of the movie. There is no way to tell whether
|
||||
// this is the case, so we find that we are in the gambling business.
|
||||
// To try to improve the odds, we record the greatest interval between type 1s
|
||||
// that we have seen and we bet on things being no worse than this in the
|
||||
// future.
|
||||
|
||||
// You can tell if it's a type 1 frame by calling IsSyncPoint().
|
||||
// there is no architected way to test for a type 3, so you should override
|
||||
// the quality management here if you have B-frames.
|
||||
|
||||
int m_nKeyFramePeriod; // the largest observed interval between type 1 frames
|
||||
// 1 means every frame is type 1, 2 means every other.
|
||||
|
||||
int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1.
|
||||
// becomes the new m_nKeyFramePeriod if greater.
|
||||
|
||||
BOOL m_bSkipping; // we are skipping to the next type 1 frame
|
||||
|
||||
#ifdef PERF
|
||||
int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key"
|
||||
int m_idSkip; // MSR id skipping
|
||||
int m_idLate; // MSR id lateness
|
||||
int m_idTimeTillKey; // MSR id for guessed time till next key frame.
|
||||
#endif
|
||||
|
||||
virtual HRESULT StartStreaming();
|
||||
|
||||
HRESULT AbortPlayback(HRESULT hr); // if something bad happens
|
||||
|
||||
HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
HRESULT AlterQuality(Quality q);
|
||||
|
||||
BOOL ShouldSkipFrame(IMediaSample * pIn);
|
||||
|
||||
int m_itrLate; // lateness from last Quality message
|
||||
// (this overflows at 214 secs late).
|
||||
int m_tDecodeStart; // timeGetTime when decode started.
|
||||
int m_itrAvgDecode; // Average decode time in reference units.
|
||||
|
||||
BOOL m_bNoSkip; // debug - no skipping.
|
||||
|
||||
// We send an EC_QUALITY_CHANGE notification to the app if we have to degrade.
|
||||
// We send one when we start degrading, not one for every frame, this means
|
||||
// we track whether we've sent one yet.
|
||||
BOOL m_bQualityChanged;
|
||||
|
||||
// When non-zero, don't pass anything to renderer until next keyframe
|
||||
// If there are few keys, give up and eventually draw something
|
||||
int m_nWaitForKey;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// File: VTrans.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines a video transform class.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// This class is derived from CTransformFilter, but is specialised to handle
|
||||
// the requirements of video quality control by frame dropping.
|
||||
// This is a non-in-place transform, (i.e. it copies the data) such as a decoder.
|
||||
|
||||
class CVideoTransformFilter : public CTransformFilter
|
||||
{
|
||||
public:
|
||||
|
||||
CVideoTransformFilter(TCHAR *, LPUNKNOWN, REFCLSID clsid);
|
||||
~CVideoTransformFilter();
|
||||
HRESULT EndFlush();
|
||||
|
||||
// =================================================================
|
||||
// ----- override these bits ---------------------------------------
|
||||
// =================================================================
|
||||
// The following methods are in CTransformFilter which is inherited.
|
||||
// They are mentioned here for completeness
|
||||
//
|
||||
// These MUST be supplied in a derived class
|
||||
//
|
||||
// NOTE:
|
||||
// virtual HRESULT Transform(IMediaSample * pIn, IMediaSample *pOut);
|
||||
// virtual HRESULT CheckInputType(const CMediaType* mtIn) PURE;
|
||||
// virtual HRESULT CheckTransform
|
||||
// (const CMediaType* mtIn, const CMediaType* mtOut) PURE;
|
||||
// static CCOMObject * CreateInstance(LPUNKNOWN, HRESULT *);
|
||||
// virtual HRESULT DecideBufferSize
|
||||
// (IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop) PURE;
|
||||
// virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType) PURE;
|
||||
//
|
||||
// These MAY also be overridden
|
||||
//
|
||||
// virtual HRESULT StopStreaming();
|
||||
// virtual HRESULT SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt);
|
||||
// virtual HRESULT CheckConnect(PIN_DIRECTION dir,IPin *pPin);
|
||||
// virtual HRESULT BreakConnect(PIN_DIRECTION dir);
|
||||
// virtual HRESULT CompleteConnect(PIN_DIRECTION direction,IPin *pReceivePin);
|
||||
// virtual HRESULT EndOfStream(void);
|
||||
// virtual HRESULT BeginFlush(void);
|
||||
// virtual HRESULT EndFlush(void);
|
||||
// virtual HRESULT NewSegment
|
||||
// (REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate);
|
||||
#ifdef PERF
|
||||
|
||||
// If you override this - ensure that you register all these ids
|
||||
// as well as any of your own,
|
||||
virtual void RegisterPerfId() {
|
||||
m_idSkip = MSR_REGISTER(TEXT("Video Transform Skip frame"));
|
||||
m_idFrameType = MSR_REGISTER(TEXT("Video transform frame type"));
|
||||
m_idLate = MSR_REGISTER(TEXT("Video Transform Lateness"));
|
||||
m_idTimeTillKey = MSR_REGISTER(TEXT("Video Transform Estd. time to next key"));
|
||||
CTransformFilter::RegisterPerfId();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
// =========== QUALITY MANAGEMENT IMPLEMENTATION ========================
|
||||
// Frames are assumed to come in three types:
|
||||
// Type 1: an AVI key frame or an MPEG I frame.
|
||||
// This frame can be decoded with no history.
|
||||
// Dropping this frame means that no further frame can be decoded
|
||||
// until the next type 1 frame.
|
||||
// Type 1 frames are sync points.
|
||||
// Type 2: an AVI non-key frame or an MPEG P frame.
|
||||
// This frame cannot be decoded unless the previous type 1 frame was
|
||||
// decoded and all type 2 frames since have been decoded.
|
||||
// Dropping this frame means that no further frame can be decoded
|
||||
// until the next type 1 frame.
|
||||
// Type 3: An MPEG B frame.
|
||||
// This frame cannot be decoded unless the previous type 1 or 2 frame
|
||||
// has been decoded AND the subsequent type 1 or 2 frame has also
|
||||
// been decoded. (This requires decoding the frames out of sequence).
|
||||
// Dropping this frame affects no other frames. This implementation
|
||||
// does not allow for these. All non-sync-point frames are treated
|
||||
// as being type 2.
|
||||
//
|
||||
// The spacing of frames of type 1 in a file is not guaranteed. There MUST
|
||||
// be a type 1 frame at (well, near) the start of the file in order to start
|
||||
// decoding at all. After that there could be one every half second or so,
|
||||
// there could be one at the start of each scene (aka "cut", "shot") or
|
||||
// there could be no more at all.
|
||||
// If there is only a single type 1 frame then NO FRAMES CAN BE DROPPED
|
||||
// without losing all the rest of the movie. There is no way to tell whether
|
||||
// this is the case, so we find that we are in the gambling business.
|
||||
// To try to improve the odds, we record the greatest interval between type 1s
|
||||
// that we have seen and we bet on things being no worse than this in the
|
||||
// future.
|
||||
|
||||
// You can tell if it's a type 1 frame by calling IsSyncPoint().
|
||||
// there is no architected way to test for a type 3, so you should override
|
||||
// the quality management here if you have B-frames.
|
||||
|
||||
int m_nKeyFramePeriod; // the largest observed interval between type 1 frames
|
||||
// 1 means every frame is type 1, 2 means every other.
|
||||
|
||||
int m_nFramesSinceKeyFrame; // Used to count frames since the last type 1.
|
||||
// becomes the new m_nKeyFramePeriod if greater.
|
||||
|
||||
BOOL m_bSkipping; // we are skipping to the next type 1 frame
|
||||
|
||||
#ifdef PERF
|
||||
int m_idFrameType; // MSR id Frame type. 1=Key, 2="non-key"
|
||||
int m_idSkip; // MSR id skipping
|
||||
int m_idLate; // MSR id lateness
|
||||
int m_idTimeTillKey; // MSR id for guessed time till next key frame.
|
||||
#endif
|
||||
|
||||
virtual HRESULT StartStreaming();
|
||||
|
||||
HRESULT AbortPlayback(HRESULT hr); // if something bad happens
|
||||
|
||||
HRESULT Receive(IMediaSample *pSample);
|
||||
|
||||
HRESULT AlterQuality(Quality q);
|
||||
|
||||
BOOL ShouldSkipFrame(IMediaSample * pIn);
|
||||
|
||||
int m_itrLate; // lateness from last Quality message
|
||||
// (this overflows at 214 secs late).
|
||||
int m_tDecodeStart; // timeGetTime when decode started.
|
||||
int m_itrAvgDecode; // Average decode time in reference units.
|
||||
|
||||
BOOL m_bNoSkip; // debug - no skipping.
|
||||
|
||||
// We send an EC_QUALITY_CHANGE notification to the app if we have to degrade.
|
||||
// We send one when we start degrading, not one for every frame, this means
|
||||
// we track whether we've sent one yet.
|
||||
BOOL m_bQualityChanged;
|
||||
|
||||
// When non-zero, don't pass anything to renderer until next keyframe
|
||||
// If there are few keys, give up and eventually draw something
|
||||
int m_nWaitForKey;
|
||||
};
|
||||
|
||||
+1977
-1977
File diff suppressed because it is too large
Load Diff
+224
-224
@@ -1,224 +1,224 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: WinCtrl.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes for video control
|
||||
// interfaces.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __WINCTRL__
|
||||
#define __WINCTRL__
|
||||
|
||||
#define ABSOL(x) (x < 0 ? -x : x)
|
||||
#define NEGAT(x) (x > 0 ? -x : x)
|
||||
|
||||
// Helper
|
||||
BOOL WINAPI PossiblyEatMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
class CBaseControlWindow : public CBaseVideoWindow, public CBaseWindow
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseFilter *m_pFilter; // Pointer to owning media filter
|
||||
CBasePin *m_pPin; // Controls media types for connection
|
||||
CCritSec *m_pInterfaceLock; // Externally defined critical section
|
||||
COLORREF m_BorderColour; // Current window border colour
|
||||
BOOL m_bAutoShow; // What happens when the state changes
|
||||
HWND m_hwndOwner; // Owner window that we optionally have
|
||||
HWND m_hwndDrain; // HWND to post any messages received
|
||||
BOOL m_bCursorHidden; // Should we hide the window cursor
|
||||
|
||||
public:
|
||||
|
||||
// Internal methods for other objects to get information out
|
||||
|
||||
HRESULT DoSetWindowStyle(long Style,long WindowLong);
|
||||
HRESULT DoGetWindowStyle(long *pStyle,long WindowLong);
|
||||
BOOL IsAutoShowEnabled() { return m_bAutoShow; };
|
||||
COLORREF GetBorderColour() { return m_BorderColour; };
|
||||
HWND GetOwnerWindow() { return m_hwndOwner; };
|
||||
BOOL IsCursorHidden() { return m_bCursorHidden; };
|
||||
|
||||
inline BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return ::PossiblyEatMessage(m_hwndDrain, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
// Derived classes must call this to set the pin the filter is using
|
||||
// We don't have the pin passed in to the constructor (as we do with
|
||||
// the CBaseFilter object) because filters typically create the
|
||||
// pins dynamically when requested in CBaseFilter::GetPin. This can
|
||||
// not be called from our constructor because is is a virtual method
|
||||
|
||||
void SetControlWindowPin(CBasePin *pPin) {
|
||||
m_pPin = pPin;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
CBaseControlWindow(CBaseFilter *pFilter, // Owning media filter
|
||||
CCritSec *pInterfaceLock, // Locking object
|
||||
TCHAR *pName, // Object description
|
||||
LPUNKNOWN pUnk, // Normal COM ownership
|
||||
HRESULT *phr); // OLE return code
|
||||
|
||||
// These are the properties we support
|
||||
|
||||
STDMETHODIMP put_Caption(BSTR strCaption);
|
||||
STDMETHODIMP get_Caption(BSTR *pstrCaption);
|
||||
STDMETHODIMP put_AutoShow(long AutoShow);
|
||||
STDMETHODIMP get_AutoShow(long *AutoShow);
|
||||
STDMETHODIMP put_WindowStyle(long WindowStyle);
|
||||
STDMETHODIMP get_WindowStyle(long *pWindowStyle);
|
||||
STDMETHODIMP put_WindowStyleEx(long WindowStyleEx);
|
||||
STDMETHODIMP get_WindowStyleEx(long *pWindowStyleEx);
|
||||
STDMETHODIMP put_WindowState(long WindowState);
|
||||
STDMETHODIMP get_WindowState(long *pWindowState);
|
||||
STDMETHODIMP put_BackgroundPalette(long BackgroundPalette);
|
||||
STDMETHODIMP get_BackgroundPalette(long *pBackgroundPalette);
|
||||
STDMETHODIMP put_Visible(long Visible);
|
||||
STDMETHODIMP get_Visible(long *pVisible);
|
||||
STDMETHODIMP put_Left(long Left);
|
||||
STDMETHODIMP get_Left(long *pLeft);
|
||||
STDMETHODIMP put_Width(long Width);
|
||||
STDMETHODIMP get_Width(long *pWidth);
|
||||
STDMETHODIMP put_Top(long Top);
|
||||
STDMETHODIMP get_Top(long *pTop);
|
||||
STDMETHODIMP put_Height(long Height);
|
||||
STDMETHODIMP get_Height(long *pHeight);
|
||||
STDMETHODIMP put_Owner(OAHWND Owner);
|
||||
STDMETHODIMP get_Owner(OAHWND *Owner);
|
||||
STDMETHODIMP put_MessageDrain(OAHWND Drain);
|
||||
STDMETHODIMP get_MessageDrain(OAHWND *Drain);
|
||||
STDMETHODIMP get_BorderColor(long *Color);
|
||||
STDMETHODIMP put_BorderColor(long Color);
|
||||
STDMETHODIMP get_FullScreenMode(long *FullScreenMode);
|
||||
STDMETHODIMP put_FullScreenMode(long FullScreenMode);
|
||||
|
||||
// And these are the methods
|
||||
|
||||
STDMETHODIMP SetWindowForeground(long Focus);
|
||||
STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd,long uMsg,LONG_PTR wParam,LONG_PTR lParam);
|
||||
STDMETHODIMP GetMinIdealImageSize(long *pWidth,long *pHeight);
|
||||
STDMETHODIMP GetMaxIdealImageSize(long *pWidth,long *pHeight);
|
||||
STDMETHODIMP SetWindowPosition(long Left,long Top,long Width,long Height);
|
||||
STDMETHODIMP GetWindowPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight);
|
||||
STDMETHODIMP GetRestorePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight);
|
||||
STDMETHODIMP HideCursor(long HideCursor);
|
||||
STDMETHODIMP IsCursorHidden(long *CursorHidden);
|
||||
};
|
||||
|
||||
// This class implements the IBasicVideo interface
|
||||
|
||||
class CBaseControlVideo : public CBaseBasicVideo
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseFilter *m_pFilter; // Pointer to owning media filter
|
||||
CBasePin *m_pPin; // Controls media types for connection
|
||||
CCritSec *m_pInterfaceLock; // Externally defined critical section
|
||||
|
||||
public:
|
||||
|
||||
// Derived classes must provide these for the implementation
|
||||
|
||||
virtual HRESULT IsDefaultTargetRect() PURE;
|
||||
virtual HRESULT SetDefaultTargetRect() PURE;
|
||||
virtual HRESULT SetTargetRect(RECT *pTargetRect) PURE;
|
||||
virtual HRESULT GetTargetRect(RECT *pTargetRect) PURE;
|
||||
virtual HRESULT IsDefaultSourceRect() PURE;
|
||||
virtual HRESULT SetDefaultSourceRect() PURE;
|
||||
virtual HRESULT SetSourceRect(RECT *pSourceRect) PURE;
|
||||
virtual HRESULT GetSourceRect(RECT *pSourceRect) PURE;
|
||||
virtual HRESULT GetStaticImage(long *pBufferSize,long *pDIBImage) PURE;
|
||||
|
||||
// Derived classes must override this to return a VIDEOINFO representing
|
||||
// the video format. We cannot call IPin ConnectionMediaType to get this
|
||||
// format because various filters dynamically change the type when using
|
||||
// DirectDraw such that the format shows the position of the logical
|
||||
// bitmap in a frame buffer surface, so the size might be returned as
|
||||
// 1024x768 pixels instead of 320x240 which is the real video dimensions
|
||||
|
||||
virtual VIDEOINFOHEADER *GetVideoFormat() PURE;
|
||||
|
||||
// Helper functions for creating memory renderings of a DIB image
|
||||
|
||||
HRESULT GetImageSize(VIDEOINFOHEADER *pVideoInfo,
|
||||
LONG *pBufferSize,
|
||||
RECT *pSourceRect);
|
||||
|
||||
HRESULT CopyImage(IMediaSample *pMediaSample,
|
||||
VIDEOINFOHEADER *pVideoInfo,
|
||||
LONG *pBufferSize,
|
||||
BYTE *pVideoImage,
|
||||
RECT *pSourceRect);
|
||||
|
||||
// Override this if you want notifying when the rectangles change
|
||||
virtual HRESULT OnUpdateRectangles() { return NOERROR; };
|
||||
virtual HRESULT OnVideoSizeChange();
|
||||
|
||||
// Derived classes must call this to set the pin the filter is using
|
||||
// We don't have the pin passed in to the constructor (as we do with
|
||||
// the CBaseFilter object) because filters typically create the
|
||||
// pins dynamically when requested in CBaseFilter::GetPin. This can
|
||||
// not be called from our constructor because is is a virtual method
|
||||
|
||||
void SetControlVideoPin(CBasePin *pPin) {
|
||||
m_pPin = pPin;
|
||||
}
|
||||
|
||||
// Helper methods for checking rectangles
|
||||
virtual HRESULT CheckSourceRect(RECT *pSourceRect);
|
||||
virtual HRESULT CheckTargetRect(RECT *pTargetRect);
|
||||
|
||||
public:
|
||||
|
||||
CBaseControlVideo(CBaseFilter *pFilter, // Owning media filter
|
||||
CCritSec *pInterfaceLock, // Serialise interface
|
||||
TCHAR *pName, // Object description
|
||||
LPUNKNOWN pUnk, // Normal COM ownership
|
||||
HRESULT *phr); // OLE return code
|
||||
|
||||
// These are the properties we support
|
||||
|
||||
STDMETHODIMP get_AvgTimePerFrame(REFTIME *pAvgTimePerFrame);
|
||||
STDMETHODIMP get_BitRate(long *pBitRate);
|
||||
STDMETHODIMP get_BitErrorRate(long *pBitErrorRate);
|
||||
STDMETHODIMP get_VideoWidth(long *pVideoWidth);
|
||||
STDMETHODIMP get_VideoHeight(long *pVideoHeight);
|
||||
STDMETHODIMP put_SourceLeft(long SourceLeft);
|
||||
STDMETHODIMP get_SourceLeft(long *pSourceLeft);
|
||||
STDMETHODIMP put_SourceWidth(long SourceWidth);
|
||||
STDMETHODIMP get_SourceWidth(long *pSourceWidth);
|
||||
STDMETHODIMP put_SourceTop(long SourceTop);
|
||||
STDMETHODIMP get_SourceTop(long *pSourceTop);
|
||||
STDMETHODIMP put_SourceHeight(long SourceHeight);
|
||||
STDMETHODIMP get_SourceHeight(long *pSourceHeight);
|
||||
STDMETHODIMP put_DestinationLeft(long DestinationLeft);
|
||||
STDMETHODIMP get_DestinationLeft(long *pDestinationLeft);
|
||||
STDMETHODIMP put_DestinationWidth(long DestinationWidth);
|
||||
STDMETHODIMP get_DestinationWidth(long *pDestinationWidth);
|
||||
STDMETHODIMP put_DestinationTop(long DestinationTop);
|
||||
STDMETHODIMP get_DestinationTop(long *pDestinationTop);
|
||||
STDMETHODIMP put_DestinationHeight(long DestinationHeight);
|
||||
STDMETHODIMP get_DestinationHeight(long *pDestinationHeight);
|
||||
|
||||
// And these are the methods
|
||||
|
||||
STDMETHODIMP GetVideoSize(long *pWidth,long *pHeight);
|
||||
STDMETHODIMP SetSourcePosition(long Left,long Top,long Width,long Height);
|
||||
STDMETHODIMP GetSourcePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight);
|
||||
STDMETHODIMP GetVideoPaletteEntries(long StartIndex,long Entries,long *pRetrieved,long *pPalette);
|
||||
STDMETHODIMP SetDefaultSourcePosition();
|
||||
STDMETHODIMP IsUsingDefaultSource();
|
||||
STDMETHODIMP SetDestinationPosition(long Left,long Top,long Width,long Height);
|
||||
STDMETHODIMP GetDestinationPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight);
|
||||
STDMETHODIMP SetDefaultDestinationPosition();
|
||||
STDMETHODIMP IsUsingDefaultDestination();
|
||||
STDMETHODIMP GetCurrentImage(long *pBufferSize,long *pVideoImage);
|
||||
};
|
||||
|
||||
#endif // __WINCTRL__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: WinCtrl.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines classes for video control
|
||||
// interfaces.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __WINCTRL__
|
||||
#define __WINCTRL__
|
||||
|
||||
#define ABSOL(x) (x < 0 ? -x : x)
|
||||
#define NEGAT(x) (x > 0 ? -x : x)
|
||||
|
||||
// Helper
|
||||
BOOL WINAPI PossiblyEatMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
class CBaseControlWindow : public CBaseVideoWindow, public CBaseWindow
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseFilter *m_pFilter; // Pointer to owning media filter
|
||||
CBasePin *m_pPin; // Controls media types for connection
|
||||
CCritSec *m_pInterfaceLock; // Externally defined critical section
|
||||
COLORREF m_BorderColour; // Current window border colour
|
||||
BOOL m_bAutoShow; // What happens when the state changes
|
||||
HWND m_hwndOwner; // Owner window that we optionally have
|
||||
HWND m_hwndDrain; // HWND to post any messages received
|
||||
BOOL m_bCursorHidden; // Should we hide the window cursor
|
||||
|
||||
public:
|
||||
|
||||
// Internal methods for other objects to get information out
|
||||
|
||||
HRESULT DoSetWindowStyle(long Style,long WindowLong);
|
||||
HRESULT DoGetWindowStyle(long *pStyle,long WindowLong);
|
||||
BOOL IsAutoShowEnabled() { return m_bAutoShow; };
|
||||
COLORREF GetBorderColour() { return m_BorderColour; };
|
||||
HWND GetOwnerWindow() { return m_hwndOwner; };
|
||||
BOOL IsCursorHidden() { return m_bCursorHidden; };
|
||||
|
||||
inline BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return ::PossiblyEatMessage(m_hwndDrain, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
// Derived classes must call this to set the pin the filter is using
|
||||
// We don't have the pin passed in to the constructor (as we do with
|
||||
// the CBaseFilter object) because filters typically create the
|
||||
// pins dynamically when requested in CBaseFilter::GetPin. This can
|
||||
// not be called from our constructor because is is a virtual method
|
||||
|
||||
void SetControlWindowPin(CBasePin *pPin) {
|
||||
m_pPin = pPin;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
CBaseControlWindow(CBaseFilter *pFilter, // Owning media filter
|
||||
CCritSec *pInterfaceLock, // Locking object
|
||||
TCHAR *pName, // Object description
|
||||
LPUNKNOWN pUnk, // Normal COM ownership
|
||||
HRESULT *phr); // OLE return code
|
||||
|
||||
// These are the properties we support
|
||||
|
||||
STDMETHODIMP put_Caption(BSTR strCaption);
|
||||
STDMETHODIMP get_Caption(BSTR *pstrCaption);
|
||||
STDMETHODIMP put_AutoShow(long AutoShow);
|
||||
STDMETHODIMP get_AutoShow(long *AutoShow);
|
||||
STDMETHODIMP put_WindowStyle(long WindowStyle);
|
||||
STDMETHODIMP get_WindowStyle(long *pWindowStyle);
|
||||
STDMETHODIMP put_WindowStyleEx(long WindowStyleEx);
|
||||
STDMETHODIMP get_WindowStyleEx(long *pWindowStyleEx);
|
||||
STDMETHODIMP put_WindowState(long WindowState);
|
||||
STDMETHODIMP get_WindowState(long *pWindowState);
|
||||
STDMETHODIMP put_BackgroundPalette(long BackgroundPalette);
|
||||
STDMETHODIMP get_BackgroundPalette(long *pBackgroundPalette);
|
||||
STDMETHODIMP put_Visible(long Visible);
|
||||
STDMETHODIMP get_Visible(long *pVisible);
|
||||
STDMETHODIMP put_Left(long Left);
|
||||
STDMETHODIMP get_Left(long *pLeft);
|
||||
STDMETHODIMP put_Width(long Width);
|
||||
STDMETHODIMP get_Width(long *pWidth);
|
||||
STDMETHODIMP put_Top(long Top);
|
||||
STDMETHODIMP get_Top(long *pTop);
|
||||
STDMETHODIMP put_Height(long Height);
|
||||
STDMETHODIMP get_Height(long *pHeight);
|
||||
STDMETHODIMP put_Owner(OAHWND Owner);
|
||||
STDMETHODIMP get_Owner(OAHWND *Owner);
|
||||
STDMETHODIMP put_MessageDrain(OAHWND Drain);
|
||||
STDMETHODIMP get_MessageDrain(OAHWND *Drain);
|
||||
STDMETHODIMP get_BorderColor(long *Color);
|
||||
STDMETHODIMP put_BorderColor(long Color);
|
||||
STDMETHODIMP get_FullScreenMode(long *FullScreenMode);
|
||||
STDMETHODIMP put_FullScreenMode(long FullScreenMode);
|
||||
|
||||
// And these are the methods
|
||||
|
||||
STDMETHODIMP SetWindowForeground(long Focus);
|
||||
STDMETHODIMP NotifyOwnerMessage(OAHWND hwnd,long uMsg,LONG_PTR wParam,LONG_PTR lParam);
|
||||
STDMETHODIMP GetMinIdealImageSize(long *pWidth,long *pHeight);
|
||||
STDMETHODIMP GetMaxIdealImageSize(long *pWidth,long *pHeight);
|
||||
STDMETHODIMP SetWindowPosition(long Left,long Top,long Width,long Height);
|
||||
STDMETHODIMP GetWindowPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight);
|
||||
STDMETHODIMP GetRestorePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight);
|
||||
STDMETHODIMP HideCursor(long HideCursor);
|
||||
STDMETHODIMP IsCursorHidden(long *CursorHidden);
|
||||
};
|
||||
|
||||
// This class implements the IBasicVideo interface
|
||||
|
||||
class CBaseControlVideo : public CBaseBasicVideo
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseFilter *m_pFilter; // Pointer to owning media filter
|
||||
CBasePin *m_pPin; // Controls media types for connection
|
||||
CCritSec *m_pInterfaceLock; // Externally defined critical section
|
||||
|
||||
public:
|
||||
|
||||
// Derived classes must provide these for the implementation
|
||||
|
||||
virtual HRESULT IsDefaultTargetRect() PURE;
|
||||
virtual HRESULT SetDefaultTargetRect() PURE;
|
||||
virtual HRESULT SetTargetRect(RECT *pTargetRect) PURE;
|
||||
virtual HRESULT GetTargetRect(RECT *pTargetRect) PURE;
|
||||
virtual HRESULT IsDefaultSourceRect() PURE;
|
||||
virtual HRESULT SetDefaultSourceRect() PURE;
|
||||
virtual HRESULT SetSourceRect(RECT *pSourceRect) PURE;
|
||||
virtual HRESULT GetSourceRect(RECT *pSourceRect) PURE;
|
||||
virtual HRESULT GetStaticImage(long *pBufferSize,long *pDIBImage) PURE;
|
||||
|
||||
// Derived classes must override this to return a VIDEOINFO representing
|
||||
// the video format. We cannot call IPin ConnectionMediaType to get this
|
||||
// format because various filters dynamically change the type when using
|
||||
// DirectDraw such that the format shows the position of the logical
|
||||
// bitmap in a frame buffer surface, so the size might be returned as
|
||||
// 1024x768 pixels instead of 320x240 which is the real video dimensions
|
||||
|
||||
virtual VIDEOINFOHEADER *GetVideoFormat() PURE;
|
||||
|
||||
// Helper functions for creating memory renderings of a DIB image
|
||||
|
||||
HRESULT GetImageSize(VIDEOINFOHEADER *pVideoInfo,
|
||||
LONG *pBufferSize,
|
||||
RECT *pSourceRect);
|
||||
|
||||
HRESULT CopyImage(IMediaSample *pMediaSample,
|
||||
VIDEOINFOHEADER *pVideoInfo,
|
||||
LONG *pBufferSize,
|
||||
BYTE *pVideoImage,
|
||||
RECT *pSourceRect);
|
||||
|
||||
// Override this if you want notifying when the rectangles change
|
||||
virtual HRESULT OnUpdateRectangles() { return NOERROR; };
|
||||
virtual HRESULT OnVideoSizeChange();
|
||||
|
||||
// Derived classes must call this to set the pin the filter is using
|
||||
// We don't have the pin passed in to the constructor (as we do with
|
||||
// the CBaseFilter object) because filters typically create the
|
||||
// pins dynamically when requested in CBaseFilter::GetPin. This can
|
||||
// not be called from our constructor because is is a virtual method
|
||||
|
||||
void SetControlVideoPin(CBasePin *pPin) {
|
||||
m_pPin = pPin;
|
||||
}
|
||||
|
||||
// Helper methods for checking rectangles
|
||||
virtual HRESULT CheckSourceRect(RECT *pSourceRect);
|
||||
virtual HRESULT CheckTargetRect(RECT *pTargetRect);
|
||||
|
||||
public:
|
||||
|
||||
CBaseControlVideo(CBaseFilter *pFilter, // Owning media filter
|
||||
CCritSec *pInterfaceLock, // Serialise interface
|
||||
TCHAR *pName, // Object description
|
||||
LPUNKNOWN pUnk, // Normal COM ownership
|
||||
HRESULT *phr); // OLE return code
|
||||
|
||||
// These are the properties we support
|
||||
|
||||
STDMETHODIMP get_AvgTimePerFrame(REFTIME *pAvgTimePerFrame);
|
||||
STDMETHODIMP get_BitRate(long *pBitRate);
|
||||
STDMETHODIMP get_BitErrorRate(long *pBitErrorRate);
|
||||
STDMETHODIMP get_VideoWidth(long *pVideoWidth);
|
||||
STDMETHODIMP get_VideoHeight(long *pVideoHeight);
|
||||
STDMETHODIMP put_SourceLeft(long SourceLeft);
|
||||
STDMETHODIMP get_SourceLeft(long *pSourceLeft);
|
||||
STDMETHODIMP put_SourceWidth(long SourceWidth);
|
||||
STDMETHODIMP get_SourceWidth(long *pSourceWidth);
|
||||
STDMETHODIMP put_SourceTop(long SourceTop);
|
||||
STDMETHODIMP get_SourceTop(long *pSourceTop);
|
||||
STDMETHODIMP put_SourceHeight(long SourceHeight);
|
||||
STDMETHODIMP get_SourceHeight(long *pSourceHeight);
|
||||
STDMETHODIMP put_DestinationLeft(long DestinationLeft);
|
||||
STDMETHODIMP get_DestinationLeft(long *pDestinationLeft);
|
||||
STDMETHODIMP put_DestinationWidth(long DestinationWidth);
|
||||
STDMETHODIMP get_DestinationWidth(long *pDestinationWidth);
|
||||
STDMETHODIMP put_DestinationTop(long DestinationTop);
|
||||
STDMETHODIMP get_DestinationTop(long *pDestinationTop);
|
||||
STDMETHODIMP put_DestinationHeight(long DestinationHeight);
|
||||
STDMETHODIMP get_DestinationHeight(long *pDestinationHeight);
|
||||
|
||||
// And these are the methods
|
||||
|
||||
STDMETHODIMP GetVideoSize(long *pWidth,long *pHeight);
|
||||
STDMETHODIMP SetSourcePosition(long Left,long Top,long Width,long Height);
|
||||
STDMETHODIMP GetSourcePosition(long *pLeft,long *pTop,long *pWidth,long *pHeight);
|
||||
STDMETHODIMP GetVideoPaletteEntries(long StartIndex,long Entries,long *pRetrieved,long *pPalette);
|
||||
STDMETHODIMP SetDefaultSourcePosition();
|
||||
STDMETHODIMP IsUsingDefaultSource();
|
||||
STDMETHODIMP SetDestinationPosition(long Left,long Top,long Width,long Height);
|
||||
STDMETHODIMP GetDestinationPosition(long *pLeft,long *pTop,long *pWidth,long *pHeight);
|
||||
STDMETHODIMP SetDefaultDestinationPosition();
|
||||
STDMETHODIMP IsUsingDefaultDestination();
|
||||
STDMETHODIMP GetCurrentImage(long *pBufferSize,long *pVideoImage);
|
||||
};
|
||||
|
||||
#endif // __WINCTRL__
|
||||
|
||||
|
||||
+2696
-2696
File diff suppressed because it is too large
Load Diff
+414
-414
@@ -1,414 +1,414 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: WinUtil.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines generic handler classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Make sure that you call PrepareWindow to initialise the window after
|
||||
// the object has been constructed. It is a separate method so that
|
||||
// derived classes can override useful methods like MessageLoop. Also
|
||||
// any derived class must call DoneWithWindow in its destructor. If it
|
||||
// doesn't a message may be retrieved and call a derived class member
|
||||
// function while a thread is executing the base class destructor code
|
||||
|
||||
#ifndef __WINUTIL__
|
||||
#define __WINUTIL__
|
||||
|
||||
const int DEFWIDTH = 320; // Initial window width
|
||||
const int DEFHEIGHT = 240; // Initial window height
|
||||
const int CAPTION = 256; // Maximum length of caption
|
||||
const int TIMELENGTH = 50; // Maximum length of times
|
||||
const int PROFILESTR = 128; // Normal profile string
|
||||
const WORD PALVERSION = 0x300; // GDI palette version
|
||||
const LONG PALETTE_VERSION = (LONG) 1; // Initial palette version
|
||||
const COLORREF VIDEO_COLOUR = 0; // Defaults to black background
|
||||
const HANDLE hMEMORY = (HANDLE) (-1); // Says to open as memory file
|
||||
|
||||
#define WIDTH(x) ((*(x)).right - (*(x)).left)
|
||||
#define HEIGHT(x) ((*(x)).bottom - (*(x)).top)
|
||||
#define SHOWSTAGE TEXT("WM_SHOWSTAGE")
|
||||
#define SHOWSTAGETOP TEXT("WM_SHOWSTAGETOP")
|
||||
#define REALIZEPALETTE TEXT("WM_REALIZEPALETTE")
|
||||
|
||||
class AM_NOVTABLE CBaseWindow
|
||||
{
|
||||
protected:
|
||||
|
||||
HINSTANCE m_hInstance; // Global module instance handle
|
||||
HWND m_hwnd; // Handle for our window
|
||||
HDC m_hdc; // Device context for the window
|
||||
LONG m_Width; // Client window width
|
||||
LONG m_Height; // Client window height
|
||||
BOOL m_bActivated; // Has the window been activated
|
||||
LPTSTR m_pClassName; // Static string holding class name
|
||||
DWORD m_ClassStyles; // Passed in to our constructor
|
||||
DWORD m_WindowStyles; // Likewise the initial window styles
|
||||
DWORD m_WindowStylesEx; // And the extended window styles
|
||||
UINT m_ShowStageMessage; // Have the window shown with focus
|
||||
UINT m_ShowStageTop; // Makes the window WS_EX_TOPMOST
|
||||
UINT m_RealizePalette; // Makes us realize our new palette
|
||||
HDC m_MemoryDC; // Used for fast BitBlt operations
|
||||
HPALETTE m_hPalette; // Handle to any palette we may have
|
||||
BYTE m_bNoRealize; // Don't realize palette now
|
||||
BYTE m_bBackground; // Should we realise in background
|
||||
BYTE m_bRealizing; // already realizing the palette
|
||||
CCritSec m_WindowLock; // Serialise window object access
|
||||
BOOL m_bDoGetDC; // Should this window get a DC
|
||||
bool m_bDoPostToDestroy; // Use PostMessage to destroy
|
||||
CCritSec m_PaletteLock; // This lock protects m_hPalette.
|
||||
// It should be held anytime the
|
||||
// program use the value of m_hPalette.
|
||||
|
||||
// Maps windows message procedure into C++ methods
|
||||
friend LRESULT CALLBACK WndProc(HWND hwnd, // Window handle
|
||||
UINT uMsg, // Message ID
|
||||
WPARAM wParam, // First parameter
|
||||
LPARAM lParam); // Other parameter
|
||||
|
||||
virtual LRESULT OnPaletteChange(HWND hwnd, UINT Message);
|
||||
|
||||
public:
|
||||
|
||||
CBaseWindow(BOOL bDoGetDC = TRUE, bool bPostToDestroy = false);
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual ~CBaseWindow();
|
||||
#endif
|
||||
|
||||
virtual HRESULT DoneWithWindow();
|
||||
virtual HRESULT PrepareWindow();
|
||||
virtual HRESULT InactivateWindow();
|
||||
virtual HRESULT ActivateWindow();
|
||||
virtual BOOL OnSize(LONG Width, LONG Height);
|
||||
virtual BOOL OnClose();
|
||||
virtual RECT GetDefaultRect();
|
||||
virtual HRESULT UninitialiseWindow();
|
||||
virtual HRESULT InitialiseWindow(HWND hwnd);
|
||||
|
||||
HRESULT CompleteConnect();
|
||||
HRESULT DoCreateWindow();
|
||||
|
||||
HRESULT PerformanceAlignWindow();
|
||||
HRESULT DoShowWindow(LONG ShowCmd);
|
||||
void PaintWindow(BOOL bErase);
|
||||
void DoSetWindowForeground(BOOL bFocus);
|
||||
virtual HRESULT SetPalette(HPALETTE hPalette);
|
||||
|
||||
void SetRealize(BOOL bRealize)
|
||||
{
|
||||
m_bNoRealize = !bRealize;
|
||||
}
|
||||
|
||||
// Jump over to the window thread to set the current palette
|
||||
HRESULT SetPalette();
|
||||
void UnsetPalette(void);
|
||||
virtual HRESULT DoRealisePalette(BOOL bForceBackground = FALSE);
|
||||
|
||||
void LockPaletteLock();
|
||||
void UnlockPaletteLock();
|
||||
|
||||
virtual BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{ return FALSE; };
|
||||
|
||||
// Access our window information
|
||||
|
||||
bool WindowExists();
|
||||
LONG GetWindowWidth();
|
||||
LONG GetWindowHeight();
|
||||
HWND GetWindowHWND();
|
||||
HDC GetMemoryHDC();
|
||||
HDC GetWindowHDC();
|
||||
|
||||
#ifdef DEBUG
|
||||
HPALETTE GetPalette();
|
||||
#endif // DEBUG
|
||||
|
||||
// This is the window procedure the derived object should override
|
||||
|
||||
virtual LRESULT OnReceiveMessage(HWND hwnd, // Window handle
|
||||
UINT uMsg, // Message ID
|
||||
WPARAM wParam, // First parameter
|
||||
LPARAM lParam); // Other parameter
|
||||
|
||||
// Must be overriden to return class and window styles
|
||||
|
||||
virtual LPTSTR GetClassWindowStyles(
|
||||
DWORD *pClassStyles, // Class styles
|
||||
DWORD *pWindowStyles, // Window styles
|
||||
DWORD *pWindowStylesEx) PURE; // Extended styles
|
||||
};
|
||||
|
||||
|
||||
// This helper class is entirely subservient to the owning CBaseWindow object
|
||||
// All this object does is to split out the actual drawing operation from the
|
||||
// main object (because it was becoming too large). We have a number of entry
|
||||
// points to set things like the draw device contexts, to implement the actual
|
||||
// drawing and to set the destination rectangle in the client window. We have
|
||||
// no critical section locking in this class because we are used exclusively
|
||||
// by the owning window object which looks after serialising calls into us
|
||||
|
||||
// If you want to use this class make sure you call NotifyAllocator once the
|
||||
// allocate has been agreed, also call NotifyMediaType with a pointer to a
|
||||
// NON stack based CMediaType once that has been set (we keep a pointer to
|
||||
// the original rather than taking a copy). When the palette changes call
|
||||
// IncrementPaletteVersion (easiest thing to do is to also call this method
|
||||
// in the SetMediaType method most filters implement). Finally before you
|
||||
// start rendering anything call SetDrawContext so that we can get the HDCs
|
||||
// for drawing from the CBaseWindow object we are given during construction
|
||||
|
||||
class CDrawImage
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseWindow *m_pBaseWindow; // Owning video window object
|
||||
CRefTime m_StartSample; // Start time for the current sample
|
||||
CRefTime m_EndSample; // And likewise it's end sample time
|
||||
HDC m_hdc; // Main window device context
|
||||
HDC m_MemoryDC; // Offscreen draw device context
|
||||
RECT m_TargetRect; // Target destination rectangle
|
||||
RECT m_SourceRect; // Source image rectangle
|
||||
BOOL m_bStretch; // Do we have to stretch the images
|
||||
BOOL m_bUsingImageAllocator; // Are the samples shared DIBSECTIONs
|
||||
CMediaType *m_pMediaType; // Pointer to the current format
|
||||
int m_perfidRenderTime; // Time taken to render an image
|
||||
LONG m_PaletteVersion; // Current palette version cookie
|
||||
|
||||
// Draw the video images in the window
|
||||
|
||||
void SlowRender(IMediaSample *pMediaSample);
|
||||
void FastRender(IMediaSample *pMediaSample);
|
||||
void DisplaySampleTimes(IMediaSample *pSample);
|
||||
void UpdateColourTable(HDC hdc,BITMAPINFOHEADER *pbmi);
|
||||
void SetStretchMode();
|
||||
|
||||
public:
|
||||
|
||||
// Used to control the image drawing
|
||||
|
||||
CDrawImage(CBaseWindow *pBaseWindow);
|
||||
BOOL DrawImage(IMediaSample *pMediaSample);
|
||||
BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample,
|
||||
LPRECT lprcSrc, LPRECT lprcDst);
|
||||
void SetDrawContext();
|
||||
void SetTargetRect(RECT *pTargetRect);
|
||||
void SetSourceRect(RECT *pSourceRect);
|
||||
void GetTargetRect(RECT *pTargetRect);
|
||||
void GetSourceRect(RECT *pSourceRect);
|
||||
virtual RECT ScaleSourceRect(const RECT *pSource);
|
||||
|
||||
// Handle updating palettes as they change
|
||||
|
||||
LONG GetPaletteVersion();
|
||||
void ResetPaletteVersion();
|
||||
void IncrementPaletteVersion();
|
||||
|
||||
// Tell us media types and allocator assignments
|
||||
|
||||
void NotifyAllocator(BOOL bUsingImageAllocator);
|
||||
void NotifyMediaType(CMediaType *pMediaType);
|
||||
BOOL UsingImageAllocator();
|
||||
|
||||
// Called when we are about to draw an image
|
||||
|
||||
void NotifyStartDraw() {
|
||||
MSR_START(m_perfidRenderTime);
|
||||
};
|
||||
|
||||
// Called when we complete an image rendering
|
||||
|
||||
void NotifyEndDraw() {
|
||||
MSR_STOP(m_perfidRenderTime);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// This is the structure used to keep information about each GDI DIB. All the
|
||||
// samples we create from our allocator will have a DIBSECTION allocated to
|
||||
// them. When we receive the sample we know we can BitBlt straight to an HDC
|
||||
|
||||
typedef struct tagDIBDATA {
|
||||
|
||||
LONG PaletteVersion; // Current palette version in use
|
||||
DIBSECTION DibSection; // Details of DIB section allocated
|
||||
HBITMAP hBitmap; // Handle to bitmap for drawing
|
||||
HANDLE hMapping; // Handle to shared memory block
|
||||
BYTE *pBase; // Pointer to base memory address
|
||||
|
||||
} DIBDATA;
|
||||
|
||||
|
||||
// This class inherits from CMediaSample and uses all of it's methods but it
|
||||
// overrides the constructor to initialise itself with the DIBDATA structure
|
||||
// When we come to render an IMediaSample we will know if we are using our own
|
||||
// allocator, and if we are, we can cast the IMediaSample to a pointer to one
|
||||
// of these are retrieve the DIB section information and hence the HBITMAP
|
||||
|
||||
class CImageSample : public CMediaSample
|
||||
{
|
||||
protected:
|
||||
|
||||
DIBDATA m_DibData; // Information about the DIBSECTION
|
||||
BOOL m_bInit; // Is the DIB information setup
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
|
||||
CImageSample(CBaseAllocator *pAllocator,
|
||||
TCHAR *pName,
|
||||
HRESULT *phr,
|
||||
LPBYTE pBuffer,
|
||||
LONG length);
|
||||
|
||||
// Maintain the DIB/DirectDraw state
|
||||
|
||||
void SetDIBData(DIBDATA *pDibData);
|
||||
DIBDATA *GetDIBData();
|
||||
};
|
||||
|
||||
|
||||
// This is an allocator based on the abstract CBaseAllocator base class that
|
||||
// allocates sample buffers in shared memory. The number and size of these
|
||||
// are determined when the output pin calls Prepare on us. The shared memory
|
||||
// blocks are used in subsequent calls to GDI CreateDIBSection, once that
|
||||
// has been done the output pin can fill the buffers with data which will
|
||||
// then be handed to GDI through BitBlt calls and thereby remove one copy
|
||||
|
||||
class CImageAllocator : public CBaseAllocator
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseFilter *m_pFilter; // Delegate reference counts to
|
||||
CMediaType *m_pMediaType; // Pointer to the current format
|
||||
|
||||
// Used to create and delete samples
|
||||
|
||||
HRESULT Alloc();
|
||||
void Free();
|
||||
|
||||
// Manage the shared DIBSECTION and DCI/DirectDraw buffers
|
||||
|
||||
HRESULT CreateDIB(LONG InSize,DIBDATA &DibData);
|
||||
STDMETHODIMP CheckSizes(ALLOCATOR_PROPERTIES *pRequest);
|
||||
virtual CImageSample *CreateImageSample(LPBYTE pData,LONG Length);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CImageAllocator(CBaseFilter *pFilter,TCHAR *pName,HRESULT *phr);
|
||||
#ifdef DEBUG
|
||||
~CImageAllocator();
|
||||
#endif
|
||||
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
void NotifyMediaType(CMediaType *pMediaType);
|
||||
|
||||
// Agree the number of buffers to be used and their size
|
||||
|
||||
STDMETHODIMP SetProperties(
|
||||
ALLOCATOR_PROPERTIES *pRequest,
|
||||
ALLOCATOR_PROPERTIES *pActual);
|
||||
};
|
||||
|
||||
|
||||
// This class is a fairly specialised helper class for image renderers that
|
||||
// have to create and manage palettes. The CBaseWindow class looks after
|
||||
// realising palettes once they have been installed. This class can be used
|
||||
// to create the palette handles from a media format (which must contain a
|
||||
// VIDEOINFO structure in the format block). We try to make the palette an
|
||||
// identity palette to maximise performance and also only change palettes
|
||||
// if actually required to (we compare palette colours before updating).
|
||||
// All the methods are virtual so that they can be overriden if so required
|
||||
|
||||
class CImagePalette
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseWindow *m_pBaseWindow; // Window to realise palette in
|
||||
CBaseFilter *m_pFilter; // Media filter to send events
|
||||
CDrawImage *m_pDrawImage; // Object who will be drawing
|
||||
HPALETTE m_hPalette; // The palette handle we own
|
||||
|
||||
public:
|
||||
|
||||
CImagePalette(CBaseFilter *pBaseFilter,
|
||||
CBaseWindow *pBaseWindow,
|
||||
CDrawImage *pDrawImage);
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual ~CImagePalette();
|
||||
#endif
|
||||
|
||||
static HPALETTE MakePalette(const VIDEOINFOHEADER *pVideoInfo, LPSTR szDevice);
|
||||
HRESULT RemovePalette();
|
||||
static HRESULT MakeIdentityPalette(PALETTEENTRY *pEntry,INT iColours, LPSTR szDevice);
|
||||
HRESULT CopyPalette(const CMediaType *pSrc,CMediaType *pDest);
|
||||
BOOL ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,const VIDEOINFOHEADER *pOldInfo);
|
||||
HRESULT PreparePalette(const CMediaType *pmtNew,const CMediaType *pmtOld,LPSTR szDevice);
|
||||
|
||||
BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, LPRECT lprcSrc, LPRECT lprcDst)
|
||||
{
|
||||
return m_pDrawImage->DrawVideoImageHere(hdc, pMediaSample, lprcSrc,lprcDst);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Another helper class really for video based renderers. Most such renderers
|
||||
// need to know what the display format is to some degree or another. This
|
||||
// class initialises itself with the display format. The format can be asked
|
||||
// for through GetDisplayFormat and various other accessor functions. If a
|
||||
// filter detects a display format change (perhaps it gets a WM_DEVMODECHANGE
|
||||
// message then it can call RefreshDisplayType to reset that format). Also
|
||||
// many video renderers will want to check formats as they are proposed by
|
||||
// source filters. This class provides methods to check formats and only
|
||||
// accept those video formats that can be efficiently drawn using GDI calls
|
||||
|
||||
class CImageDisplay : public CCritSec
|
||||
{
|
||||
protected:
|
||||
|
||||
// This holds the display format; biSize should not be too big, so we can
|
||||
// safely use the VIDEOINFO structure
|
||||
VIDEOINFO m_Display;
|
||||
|
||||
static DWORD CountSetBits(const DWORD Field);
|
||||
static DWORD CountPrefixBits(const DWORD Field);
|
||||
static BOOL CheckBitFields(const VIDEOINFO *pInput);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CImageDisplay();
|
||||
|
||||
// Used to manage BITMAPINFOHEADERs and the display format
|
||||
|
||||
const VIDEOINFO *GetDisplayFormat();
|
||||
HRESULT RefreshDisplayType(LPSTR szDeviceName);
|
||||
static BOOL CheckHeaderValidity(const VIDEOINFO *pInput);
|
||||
static BOOL CheckPaletteHeader(const VIDEOINFO *pInput);
|
||||
BOOL IsPalettised();
|
||||
WORD GetDisplayDepth();
|
||||
|
||||
// Provide simple video format type checking
|
||||
|
||||
HRESULT CheckMediaType(const CMediaType *pmtIn);
|
||||
HRESULT CheckVideoType(const VIDEOINFO *pInput);
|
||||
HRESULT UpdateFormat(VIDEOINFO *pVideoInfo);
|
||||
const DWORD *GetBitMasks(const VIDEOINFO *pVideoInfo);
|
||||
|
||||
BOOL GetColourMask(DWORD *pMaskRed,
|
||||
DWORD *pMaskGreen,
|
||||
DWORD *pMaskBlue);
|
||||
};
|
||||
|
||||
// Convert a FORMAT_VideoInfo to FORMAT_VideoInfo2
|
||||
STDAPI ConvertVideoInfoToVideoInfo2(AM_MEDIA_TYPE *pmt);
|
||||
|
||||
#endif // __WINUTIL__
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: WinUtil.h
|
||||
//
|
||||
// Desc: DirectShow base classes - defines generic handler classes.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Make sure that you call PrepareWindow to initialise the window after
|
||||
// the object has been constructed. It is a separate method so that
|
||||
// derived classes can override useful methods like MessageLoop. Also
|
||||
// any derived class must call DoneWithWindow in its destructor. If it
|
||||
// doesn't a message may be retrieved and call a derived class member
|
||||
// function while a thread is executing the base class destructor code
|
||||
|
||||
#ifndef __WINUTIL__
|
||||
#define __WINUTIL__
|
||||
|
||||
const int DEFWIDTH = 320; // Initial window width
|
||||
const int DEFHEIGHT = 240; // Initial window height
|
||||
const int CAPTION = 256; // Maximum length of caption
|
||||
const int TIMELENGTH = 50; // Maximum length of times
|
||||
const int PROFILESTR = 128; // Normal profile string
|
||||
const WORD PALVERSION = 0x300; // GDI palette version
|
||||
const LONG PALETTE_VERSION = (LONG) 1; // Initial palette version
|
||||
const COLORREF VIDEO_COLOUR = 0; // Defaults to black background
|
||||
const HANDLE hMEMORY = (HANDLE) (-1); // Says to open as memory file
|
||||
|
||||
#define WIDTH(x) ((*(x)).right - (*(x)).left)
|
||||
#define HEIGHT(x) ((*(x)).bottom - (*(x)).top)
|
||||
#define SHOWSTAGE TEXT("WM_SHOWSTAGE")
|
||||
#define SHOWSTAGETOP TEXT("WM_SHOWSTAGETOP")
|
||||
#define REALIZEPALETTE TEXT("WM_REALIZEPALETTE")
|
||||
|
||||
class AM_NOVTABLE CBaseWindow
|
||||
{
|
||||
protected:
|
||||
|
||||
HINSTANCE m_hInstance; // Global module instance handle
|
||||
HWND m_hwnd; // Handle for our window
|
||||
HDC m_hdc; // Device context for the window
|
||||
LONG m_Width; // Client window width
|
||||
LONG m_Height; // Client window height
|
||||
BOOL m_bActivated; // Has the window been activated
|
||||
LPTSTR m_pClassName; // Static string holding class name
|
||||
DWORD m_ClassStyles; // Passed in to our constructor
|
||||
DWORD m_WindowStyles; // Likewise the initial window styles
|
||||
DWORD m_WindowStylesEx; // And the extended window styles
|
||||
UINT m_ShowStageMessage; // Have the window shown with focus
|
||||
UINT m_ShowStageTop; // Makes the window WS_EX_TOPMOST
|
||||
UINT m_RealizePalette; // Makes us realize our new palette
|
||||
HDC m_MemoryDC; // Used for fast BitBlt operations
|
||||
HPALETTE m_hPalette; // Handle to any palette we may have
|
||||
BYTE m_bNoRealize; // Don't realize palette now
|
||||
BYTE m_bBackground; // Should we realise in background
|
||||
BYTE m_bRealizing; // already realizing the palette
|
||||
CCritSec m_WindowLock; // Serialise window object access
|
||||
BOOL m_bDoGetDC; // Should this window get a DC
|
||||
bool m_bDoPostToDestroy; // Use PostMessage to destroy
|
||||
CCritSec m_PaletteLock; // This lock protects m_hPalette.
|
||||
// It should be held anytime the
|
||||
// program use the value of m_hPalette.
|
||||
|
||||
// Maps windows message procedure into C++ methods
|
||||
friend LRESULT CALLBACK WndProc(HWND hwnd, // Window handle
|
||||
UINT uMsg, // Message ID
|
||||
WPARAM wParam, // First parameter
|
||||
LPARAM lParam); // Other parameter
|
||||
|
||||
virtual LRESULT OnPaletteChange(HWND hwnd, UINT Message);
|
||||
|
||||
public:
|
||||
|
||||
CBaseWindow(BOOL bDoGetDC = TRUE, bool bPostToDestroy = false);
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual ~CBaseWindow();
|
||||
#endif
|
||||
|
||||
virtual HRESULT DoneWithWindow();
|
||||
virtual HRESULT PrepareWindow();
|
||||
virtual HRESULT InactivateWindow();
|
||||
virtual HRESULT ActivateWindow();
|
||||
virtual BOOL OnSize(LONG Width, LONG Height);
|
||||
virtual BOOL OnClose();
|
||||
virtual RECT GetDefaultRect();
|
||||
virtual HRESULT UninitialiseWindow();
|
||||
virtual HRESULT InitialiseWindow(HWND hwnd);
|
||||
|
||||
HRESULT CompleteConnect();
|
||||
HRESULT DoCreateWindow();
|
||||
|
||||
HRESULT PerformanceAlignWindow();
|
||||
HRESULT DoShowWindow(LONG ShowCmd);
|
||||
void PaintWindow(BOOL bErase);
|
||||
void DoSetWindowForeground(BOOL bFocus);
|
||||
virtual HRESULT SetPalette(HPALETTE hPalette);
|
||||
|
||||
void SetRealize(BOOL bRealize)
|
||||
{
|
||||
m_bNoRealize = !bRealize;
|
||||
}
|
||||
|
||||
// Jump over to the window thread to set the current palette
|
||||
HRESULT SetPalette();
|
||||
void UnsetPalette(void);
|
||||
virtual HRESULT DoRealisePalette(BOOL bForceBackground = FALSE);
|
||||
|
||||
void LockPaletteLock();
|
||||
void UnlockPaletteLock();
|
||||
|
||||
virtual BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{ return FALSE; };
|
||||
|
||||
// Access our window information
|
||||
|
||||
bool WindowExists();
|
||||
LONG GetWindowWidth();
|
||||
LONG GetWindowHeight();
|
||||
HWND GetWindowHWND();
|
||||
HDC GetMemoryHDC();
|
||||
HDC GetWindowHDC();
|
||||
|
||||
#ifdef DEBUG
|
||||
HPALETTE GetPalette();
|
||||
#endif // DEBUG
|
||||
|
||||
// This is the window procedure the derived object should override
|
||||
|
||||
virtual LRESULT OnReceiveMessage(HWND hwnd, // Window handle
|
||||
UINT uMsg, // Message ID
|
||||
WPARAM wParam, // First parameter
|
||||
LPARAM lParam); // Other parameter
|
||||
|
||||
// Must be overriden to return class and window styles
|
||||
|
||||
virtual LPTSTR GetClassWindowStyles(
|
||||
DWORD *pClassStyles, // Class styles
|
||||
DWORD *pWindowStyles, // Window styles
|
||||
DWORD *pWindowStylesEx) PURE; // Extended styles
|
||||
};
|
||||
|
||||
|
||||
// This helper class is entirely subservient to the owning CBaseWindow object
|
||||
// All this object does is to split out the actual drawing operation from the
|
||||
// main object (because it was becoming too large). We have a number of entry
|
||||
// points to set things like the draw device contexts, to implement the actual
|
||||
// drawing and to set the destination rectangle in the client window. We have
|
||||
// no critical section locking in this class because we are used exclusively
|
||||
// by the owning window object which looks after serialising calls into us
|
||||
|
||||
// If you want to use this class make sure you call NotifyAllocator once the
|
||||
// allocate has been agreed, also call NotifyMediaType with a pointer to a
|
||||
// NON stack based CMediaType once that has been set (we keep a pointer to
|
||||
// the original rather than taking a copy). When the palette changes call
|
||||
// IncrementPaletteVersion (easiest thing to do is to also call this method
|
||||
// in the SetMediaType method most filters implement). Finally before you
|
||||
// start rendering anything call SetDrawContext so that we can get the HDCs
|
||||
// for drawing from the CBaseWindow object we are given during construction
|
||||
|
||||
class CDrawImage
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseWindow *m_pBaseWindow; // Owning video window object
|
||||
CRefTime m_StartSample; // Start time for the current sample
|
||||
CRefTime m_EndSample; // And likewise it's end sample time
|
||||
HDC m_hdc; // Main window device context
|
||||
HDC m_MemoryDC; // Offscreen draw device context
|
||||
RECT m_TargetRect; // Target destination rectangle
|
||||
RECT m_SourceRect; // Source image rectangle
|
||||
BOOL m_bStretch; // Do we have to stretch the images
|
||||
BOOL m_bUsingImageAllocator; // Are the samples shared DIBSECTIONs
|
||||
CMediaType *m_pMediaType; // Pointer to the current format
|
||||
int m_perfidRenderTime; // Time taken to render an image
|
||||
LONG m_PaletteVersion; // Current palette version cookie
|
||||
|
||||
// Draw the video images in the window
|
||||
|
||||
void SlowRender(IMediaSample *pMediaSample);
|
||||
void FastRender(IMediaSample *pMediaSample);
|
||||
void DisplaySampleTimes(IMediaSample *pSample);
|
||||
void UpdateColourTable(HDC hdc,BITMAPINFOHEADER *pbmi);
|
||||
void SetStretchMode();
|
||||
|
||||
public:
|
||||
|
||||
// Used to control the image drawing
|
||||
|
||||
CDrawImage(CBaseWindow *pBaseWindow);
|
||||
BOOL DrawImage(IMediaSample *pMediaSample);
|
||||
BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample,
|
||||
LPRECT lprcSrc, LPRECT lprcDst);
|
||||
void SetDrawContext();
|
||||
void SetTargetRect(RECT *pTargetRect);
|
||||
void SetSourceRect(RECT *pSourceRect);
|
||||
void GetTargetRect(RECT *pTargetRect);
|
||||
void GetSourceRect(RECT *pSourceRect);
|
||||
virtual RECT ScaleSourceRect(const RECT *pSource);
|
||||
|
||||
// Handle updating palettes as they change
|
||||
|
||||
LONG GetPaletteVersion();
|
||||
void ResetPaletteVersion();
|
||||
void IncrementPaletteVersion();
|
||||
|
||||
// Tell us media types and allocator assignments
|
||||
|
||||
void NotifyAllocator(BOOL bUsingImageAllocator);
|
||||
void NotifyMediaType(CMediaType *pMediaType);
|
||||
BOOL UsingImageAllocator();
|
||||
|
||||
// Called when we are about to draw an image
|
||||
|
||||
void NotifyStartDraw() {
|
||||
MSR_START(m_perfidRenderTime);
|
||||
};
|
||||
|
||||
// Called when we complete an image rendering
|
||||
|
||||
void NotifyEndDraw() {
|
||||
MSR_STOP(m_perfidRenderTime);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// This is the structure used to keep information about each GDI DIB. All the
|
||||
// samples we create from our allocator will have a DIBSECTION allocated to
|
||||
// them. When we receive the sample we know we can BitBlt straight to an HDC
|
||||
|
||||
typedef struct tagDIBDATA {
|
||||
|
||||
LONG PaletteVersion; // Current palette version in use
|
||||
DIBSECTION DibSection; // Details of DIB section allocated
|
||||
HBITMAP hBitmap; // Handle to bitmap for drawing
|
||||
HANDLE hMapping; // Handle to shared memory block
|
||||
BYTE *pBase; // Pointer to base memory address
|
||||
|
||||
} DIBDATA;
|
||||
|
||||
|
||||
// This class inherits from CMediaSample and uses all of it's methods but it
|
||||
// overrides the constructor to initialise itself with the DIBDATA structure
|
||||
// When we come to render an IMediaSample we will know if we are using our own
|
||||
// allocator, and if we are, we can cast the IMediaSample to a pointer to one
|
||||
// of these are retrieve the DIB section information and hence the HBITMAP
|
||||
|
||||
class CImageSample : public CMediaSample
|
||||
{
|
||||
protected:
|
||||
|
||||
DIBDATA m_DibData; // Information about the DIBSECTION
|
||||
BOOL m_bInit; // Is the DIB information setup
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
|
||||
CImageSample(CBaseAllocator *pAllocator,
|
||||
TCHAR *pName,
|
||||
HRESULT *phr,
|
||||
LPBYTE pBuffer,
|
||||
LONG length);
|
||||
|
||||
// Maintain the DIB/DirectDraw state
|
||||
|
||||
void SetDIBData(DIBDATA *pDibData);
|
||||
DIBDATA *GetDIBData();
|
||||
};
|
||||
|
||||
|
||||
// This is an allocator based on the abstract CBaseAllocator base class that
|
||||
// allocates sample buffers in shared memory. The number and size of these
|
||||
// are determined when the output pin calls Prepare on us. The shared memory
|
||||
// blocks are used in subsequent calls to GDI CreateDIBSection, once that
|
||||
// has been done the output pin can fill the buffers with data which will
|
||||
// then be handed to GDI through BitBlt calls and thereby remove one copy
|
||||
|
||||
class CImageAllocator : public CBaseAllocator
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseFilter *m_pFilter; // Delegate reference counts to
|
||||
CMediaType *m_pMediaType; // Pointer to the current format
|
||||
|
||||
// Used to create and delete samples
|
||||
|
||||
HRESULT Alloc();
|
||||
void Free();
|
||||
|
||||
// Manage the shared DIBSECTION and DCI/DirectDraw buffers
|
||||
|
||||
HRESULT CreateDIB(LONG InSize,DIBDATA &DibData);
|
||||
STDMETHODIMP CheckSizes(ALLOCATOR_PROPERTIES *pRequest);
|
||||
virtual CImageSample *CreateImageSample(LPBYTE pData,LONG Length);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CImageAllocator(CBaseFilter *pFilter,TCHAR *pName,HRESULT *phr);
|
||||
#ifdef DEBUG
|
||||
~CImageAllocator();
|
||||
#endif
|
||||
|
||||
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
|
||||
STDMETHODIMP_(ULONG) NonDelegatingRelease();
|
||||
void NotifyMediaType(CMediaType *pMediaType);
|
||||
|
||||
// Agree the number of buffers to be used and their size
|
||||
|
||||
STDMETHODIMP SetProperties(
|
||||
ALLOCATOR_PROPERTIES *pRequest,
|
||||
ALLOCATOR_PROPERTIES *pActual);
|
||||
};
|
||||
|
||||
|
||||
// This class is a fairly specialised helper class for image renderers that
|
||||
// have to create and manage palettes. The CBaseWindow class looks after
|
||||
// realising palettes once they have been installed. This class can be used
|
||||
// to create the palette handles from a media format (which must contain a
|
||||
// VIDEOINFO structure in the format block). We try to make the palette an
|
||||
// identity palette to maximise performance and also only change palettes
|
||||
// if actually required to (we compare palette colours before updating).
|
||||
// All the methods are virtual so that they can be overriden if so required
|
||||
|
||||
class CImagePalette
|
||||
{
|
||||
protected:
|
||||
|
||||
CBaseWindow *m_pBaseWindow; // Window to realise palette in
|
||||
CBaseFilter *m_pFilter; // Media filter to send events
|
||||
CDrawImage *m_pDrawImage; // Object who will be drawing
|
||||
HPALETTE m_hPalette; // The palette handle we own
|
||||
|
||||
public:
|
||||
|
||||
CImagePalette(CBaseFilter *pBaseFilter,
|
||||
CBaseWindow *pBaseWindow,
|
||||
CDrawImage *pDrawImage);
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual ~CImagePalette();
|
||||
#endif
|
||||
|
||||
static HPALETTE MakePalette(const VIDEOINFOHEADER *pVideoInfo, LPSTR szDevice);
|
||||
HRESULT RemovePalette();
|
||||
static HRESULT MakeIdentityPalette(PALETTEENTRY *pEntry,INT iColours, LPSTR szDevice);
|
||||
HRESULT CopyPalette(const CMediaType *pSrc,CMediaType *pDest);
|
||||
BOOL ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,const VIDEOINFOHEADER *pOldInfo);
|
||||
HRESULT PreparePalette(const CMediaType *pmtNew,const CMediaType *pmtOld,LPSTR szDevice);
|
||||
|
||||
BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, LPRECT lprcSrc, LPRECT lprcDst)
|
||||
{
|
||||
return m_pDrawImage->DrawVideoImageHere(hdc, pMediaSample, lprcSrc,lprcDst);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Another helper class really for video based renderers. Most such renderers
|
||||
// need to know what the display format is to some degree or another. This
|
||||
// class initialises itself with the display format. The format can be asked
|
||||
// for through GetDisplayFormat and various other accessor functions. If a
|
||||
// filter detects a display format change (perhaps it gets a WM_DEVMODECHANGE
|
||||
// message then it can call RefreshDisplayType to reset that format). Also
|
||||
// many video renderers will want to check formats as they are proposed by
|
||||
// source filters. This class provides methods to check formats and only
|
||||
// accept those video formats that can be efficiently drawn using GDI calls
|
||||
|
||||
class CImageDisplay : public CCritSec
|
||||
{
|
||||
protected:
|
||||
|
||||
// This holds the display format; biSize should not be too big, so we can
|
||||
// safely use the VIDEOINFO structure
|
||||
VIDEOINFO m_Display;
|
||||
|
||||
static DWORD CountSetBits(const DWORD Field);
|
||||
static DWORD CountPrefixBits(const DWORD Field);
|
||||
static BOOL CheckBitFields(const VIDEOINFO *pInput);
|
||||
|
||||
public:
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
CImageDisplay();
|
||||
|
||||
// Used to manage BITMAPINFOHEADERs and the display format
|
||||
|
||||
const VIDEOINFO *GetDisplayFormat();
|
||||
HRESULT RefreshDisplayType(LPSTR szDeviceName);
|
||||
static BOOL CheckHeaderValidity(const VIDEOINFO *pInput);
|
||||
static BOOL CheckPaletteHeader(const VIDEOINFO *pInput);
|
||||
BOOL IsPalettised();
|
||||
WORD GetDisplayDepth();
|
||||
|
||||
// Provide simple video format type checking
|
||||
|
||||
HRESULT CheckMediaType(const CMediaType *pmtIn);
|
||||
HRESULT CheckVideoType(const VIDEOINFO *pInput);
|
||||
HRESULT UpdateFormat(VIDEOINFO *pVideoInfo);
|
||||
const DWORD *GetBitMasks(const VIDEOINFO *pVideoInfo);
|
||||
|
||||
BOOL GetColourMask(DWORD *pMaskRed,
|
||||
DWORD *pMaskGreen,
|
||||
DWORD *pMaskBlue);
|
||||
};
|
||||
|
||||
// Convert a FORMAT_VideoInfo to FORMAT_VideoInfo2
|
||||
STDAPI ConvertVideoInfoToVideoInfo2(AM_MEDIA_TYPE *pmt);
|
||||
|
||||
#endif // __WINUTIL__
|
||||
|
||||
|
||||
+1311
-1311
File diff suppressed because it is too large
Load Diff
+379
-379
@@ -1,379 +1,379 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// File: WXDebug.h
|
||||
//
|
||||
// Desc: DirectShow base classes - provides debugging facilities.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __WXDEBUG__
|
||||
#define __WXDEBUG__
|
||||
|
||||
// This library provides fairly straight forward debugging functionality, this
|
||||
// is split into two main sections. The first is assertion handling, there are
|
||||
// three types of assertions provided here. The most commonly used one is the
|
||||
// ASSERT(condition) macro which will pop up a message box including the file
|
||||
// and line number if the condition evaluates to FALSE. Then there is the
|
||||
// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will
|
||||
// still be executed in NON debug builds. The final type of assertion is the
|
||||
// KASSERT macro which is more suitable for pure (perhaps kernel) filters as
|
||||
// the condition is printed onto the debugger rather than in a message box.
|
||||
//
|
||||
// The other part of the debug module facilties is general purpose logging.
|
||||
// This is accessed by calling DbgLog(). The function takes a type and level
|
||||
// field which define the type of informational string you are presenting and
|
||||
// it's relative importance. The type field can be a combination (one or more)
|
||||
// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level
|
||||
// is a DWORD value where zero defines highest important. Use of zero as the
|
||||
// debug logging level is to be encouraged ONLY for major errors or events as
|
||||
// they will ALWAYS be displayed on the debugger. Other debug output has it's
|
||||
// level matched against the current debug output level stored in the registry
|
||||
// for this module and if less than the current setting it will be displayed.
|
||||
//
|
||||
// Each module or executable has it's own debug output level for each of the
|
||||
// five types. These are read in when the DbgInitialise function is called
|
||||
// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL
|
||||
// is loaded, executables must call it explicitely with the module instance
|
||||
// handle given to them through the WINMAIN entry point. An executable must
|
||||
// also call DbgTerminate when they have finished to clean up the resources
|
||||
// the debug library uses, once again this is done automatically for DLLs
|
||||
|
||||
// These are the five different categories of logging information
|
||||
|
||||
enum { LOG_TIMING = 0x01, // Timing and performance measurements
|
||||
LOG_TRACE = 0x02, // General step point call tracing
|
||||
LOG_MEMORY = 0x04, // Memory and object allocation/destruction
|
||||
LOG_LOCKING = 0x08, // Locking/unlocking of critical sections
|
||||
LOG_ERROR = 0x10, // Debug error notification
|
||||
LOG_CUSTOM1 = 0x20,
|
||||
LOG_CUSTOM2 = 0x40,
|
||||
LOG_CUSTOM3 = 0x80,
|
||||
LOG_CUSTOM4 = 0x100,
|
||||
LOG_CUSTOM5 = 0x200,
|
||||
};
|
||||
|
||||
#define LOG_FORCIBLY_SET 0x80000000
|
||||
|
||||
enum { CDISP_HEX = 0x01,
|
||||
CDISP_DEC = 0x02};
|
||||
|
||||
// For each object created derived from CBaseObject (in debug builds) we
|
||||
// create a descriptor that holds it's name (statically allocated memory)
|
||||
// and a cookie we assign it. We keep a list of all the active objects
|
||||
// we have registered so that we can dump a list of remaining objects
|
||||
|
||||
typedef struct tag_ObjectDesc {
|
||||
const CHAR *m_szName;
|
||||
const WCHAR *m_wszName;
|
||||
DWORD m_dwCookie;
|
||||
tag_ObjectDesc *m_pNext;
|
||||
} ObjectDesc;
|
||||
|
||||
#define DLLIMPORT __declspec(dllimport)
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define NAME(x) TEXT(x)
|
||||
|
||||
// These are used internally by the debug library (PRIVATE)
|
||||
|
||||
void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax);
|
||||
void WINAPI DbgInitGlobalSettings(bool fTakeMax);
|
||||
void WINAPI DbgInitModuleSettings(bool fTakeMax);
|
||||
void WINAPI DbgInitModuleName();
|
||||
DWORD WINAPI DbgRegisterObjectCreation(
|
||||
const CHAR *szObjectName, const WCHAR *wszObjectName);
|
||||
|
||||
BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie);
|
||||
|
||||
// These are the PUBLIC entry points
|
||||
|
||||
BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level);
|
||||
void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level);
|
||||
void WINAPI DbgSetAutoRefreshLevels(bool fAuto);
|
||||
|
||||
// Initialise the library with the module handle
|
||||
|
||||
void WINAPI DbgInitialise(HINSTANCE hInst);
|
||||
void WINAPI DbgTerminate();
|
||||
|
||||
void WINAPI DbgDumpObjectRegister();
|
||||
|
||||
// Display error and logging to the user
|
||||
|
||||
void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...);
|
||||
|
||||
void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...);
|
||||
#ifdef UNICODE
|
||||
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const CHAR *pFormat,...);
|
||||
void WINAPI DbgAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgBreakPoint(const CHAR *pCondition,const CHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgKernelAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine);
|
||||
#endif
|
||||
void WINAPI DbgOutString(LPCTSTR psz);
|
||||
|
||||
// Debug infinite wait stuff
|
||||
DWORD WINAPI DbgWaitForSingleObject(HANDLE h);
|
||||
DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount,
|
||||
CONST HANDLE *lpHandles,
|
||||
BOOL bWaitAll);
|
||||
void WINAPI DbgSetWaitTimeout(DWORD dwTimeout);
|
||||
|
||||
#ifdef __strmif_h__
|
||||
// Display a media type: Terse at level 2, verbose at level 5
|
||||
void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn);
|
||||
|
||||
// Dump lots of information about a filter graph
|
||||
void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel);
|
||||
#endif
|
||||
|
||||
#define KASSERT(_x_) if (!(_x_)) \
|
||||
DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
|
||||
|
||||
// Break on the debugger without putting up a message box
|
||||
// message goes to debugger instead
|
||||
|
||||
#define KDbgBreak(_x_) \
|
||||
DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
|
||||
|
||||
// We chose a common name for our ASSERT macro, MFC also uses this name
|
||||
// So long as the implementation evaluates the condition and handles it
|
||||
// then we will be ok. Rather than override the behaviour expected we
|
||||
// will leave whatever first defines ASSERT as the handler (i.e. MFC)
|
||||
#ifndef ASSERT
|
||||
#define ASSERT(_x_) if (!(_x_)) \
|
||||
DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
|
||||
#endif
|
||||
|
||||
#define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0)
|
||||
|
||||
// Put up a message box informing the user of a halt
|
||||
// condition in the program
|
||||
|
||||
#define DbgBreak(_x_) \
|
||||
DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__)
|
||||
|
||||
#define EXECUTE_ASSERT(_x_) ASSERT(_x_)
|
||||
#define DbgLog(_x_) DbgLogInfo _x_
|
||||
// MFC style trace macros
|
||||
|
||||
#define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_)))
|
||||
#define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a))
|
||||
#define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b))
|
||||
#define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c))
|
||||
#define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d))
|
||||
#define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e))
|
||||
|
||||
#else
|
||||
|
||||
// Retail builds make public debug functions inert - WARNING the source
|
||||
// files do not define or build any of the entry points in debug builds
|
||||
// (public entry points compile to nothing) so if you go trying to call
|
||||
// any of the private entry points in your source they won't compile
|
||||
|
||||
#define NAME(_x_) ((TCHAR *) NULL)
|
||||
|
||||
#define DbgInitialise(hInst)
|
||||
#define DbgTerminate()
|
||||
#define DbgLog(_x_) 0
|
||||
#define DbgOutString(psz)
|
||||
#define DbgAssertAligned( _ptr_, _alignment_ ) 0
|
||||
|
||||
#define DbgRegisterObjectCreation(pObjectName)
|
||||
#define DbgRegisterObjectDestruction(dwCookie)
|
||||
#define DbgDumpObjectRegister()
|
||||
|
||||
#define DbgCheckModuleLevel(Type,Level)
|
||||
#define DbgSetModuleLevel(Type,Level)
|
||||
#define DbgSetAutoRefreshLevels(fAuto)
|
||||
|
||||
#define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE)
|
||||
#define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \
|
||||
WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE)
|
||||
#define DbgSetWaitTimeout(dwTimeout)
|
||||
|
||||
#define KDbgBreak(_x_)
|
||||
#define DbgBreak(_x_)
|
||||
|
||||
#define KASSERT(_x_) ((void)0)
|
||||
#ifndef ASSERT
|
||||
#define ASSERT(_x_) ((void)0)
|
||||
#endif
|
||||
#define EXECUTE_ASSERT(_x_) ((void)(_x_))
|
||||
|
||||
// MFC style trace macros
|
||||
|
||||
#define NOTE(_x_) ((void)0)
|
||||
#define NOTE1(_x_,a) ((void)0)
|
||||
#define NOTE2(_x_,a,b) ((void)0)
|
||||
#define NOTE3(_x_,a,b,c) ((void)0)
|
||||
#define NOTE4(_x_,a,b,c,d) ((void)0)
|
||||
#define NOTE5(_x_,a,b,c,d,e) ((void)0)
|
||||
|
||||
#define DisplayType(label, pmtIn) ((void)0)
|
||||
#define DumpGraph(pGraph, label) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
// Checks a pointer which should be non NULL - can be used as follows.
|
||||
|
||||
#define CheckPointer(p,ret) {if((p)==NULL) return (ret);}
|
||||
|
||||
// HRESULT Foo(VOID *pBar)
|
||||
// {
|
||||
// CheckPointer(pBar,E_INVALIDARG)
|
||||
// }
|
||||
//
|
||||
// Or if the function returns a boolean
|
||||
//
|
||||
// BOOL Foo(VOID *pBar)
|
||||
// {
|
||||
// CheckPointer(pBar,FALSE)
|
||||
// }
|
||||
|
||||
// These validate pointers when symbol VFWROBUST is defined
|
||||
// This will normally be defined in debug not retail builds
|
||||
|
||||
#ifdef DEBUG
|
||||
#define VFWROBUST
|
||||
#endif
|
||||
|
||||
#ifdef VFWROBUST
|
||||
|
||||
#define ValidateReadPtr(p,cb) \
|
||||
{if(IsBadReadPtr((PVOID)p,cb) == TRUE) \
|
||||
DbgBreak("Invalid read pointer");}
|
||||
|
||||
#define ValidateWritePtr(p,cb) \
|
||||
{if(IsBadWritePtr((PVOID)p,cb) == TRUE) \
|
||||
DbgBreak("Invalid write pointer");}
|
||||
|
||||
#define ValidateReadWritePtr(p,cb) \
|
||||
{ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)}
|
||||
|
||||
#define ValidateStringPtr(p) \
|
||||
{if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \
|
||||
DbgBreak("Invalid string pointer");}
|
||||
|
||||
#define ValidateStringPtrA(p) \
|
||||
{if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \
|
||||
DbgBreak("Invalid ANSI string pointer");}
|
||||
|
||||
#define ValidateStringPtrW(p) \
|
||||
{if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \
|
||||
DbgBreak("Invalid UNICODE string pointer");}
|
||||
|
||||
#else
|
||||
#define ValidateReadPtr(p,cb) 0
|
||||
#define ValidateWritePtr(p,cb) 0
|
||||
#define ValidateReadWritePtr(p,cb) 0
|
||||
#define ValidateStringPtr(p) 0
|
||||
#define ValidateStringPtrA(p) 0
|
||||
#define ValidateStringPtrW(p) 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _OBJBASE_H_
|
||||
|
||||
// Outputting GUID names. If you want to include the name
|
||||
// associated with a GUID (eg CLSID_...) then
|
||||
//
|
||||
// GuidNames[yourGUID]
|
||||
//
|
||||
// Returns the name defined in uuids.h as a string
|
||||
|
||||
typedef struct {
|
||||
CHAR *szName;
|
||||
GUID guid;
|
||||
} GUID_STRING_ENTRY;
|
||||
|
||||
class CGuidNameList {
|
||||
public:
|
||||
CHAR *operator [] (const GUID& guid);
|
||||
};
|
||||
|
||||
extern CGuidNameList GuidNames;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef REMIND
|
||||
// REMIND macro - generates warning as reminder to complete coding
|
||||
// (eg) usage:
|
||||
//
|
||||
// #pragma message (REMIND("Add automation support"))
|
||||
|
||||
|
||||
#define QUOTE(x) #x
|
||||
#define QQUOTE(y) QUOTE(y)
|
||||
#define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str
|
||||
#endif
|
||||
|
||||
// Method to display objects in a useful format
|
||||
//
|
||||
// eg If you want to display a LONGLONG ll in a debug string do (eg)
|
||||
//
|
||||
// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX)));
|
||||
|
||||
|
||||
class CDispBasic
|
||||
{
|
||||
public:
|
||||
CDispBasic() { m_pString = m_String; };
|
||||
~CDispBasic();
|
||||
protected:
|
||||
PTCHAR m_pString; // normally points to m_String... unless too much data
|
||||
TCHAR m_String[50];
|
||||
};
|
||||
class CDisp : public CDispBasic
|
||||
{
|
||||
public:
|
||||
CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form
|
||||
CDisp(REFCLSID clsid); // Display a GUID
|
||||
CDisp(double d); // Display a floating point number
|
||||
#ifdef __strmif_h__
|
||||
#ifdef __STREAMS__
|
||||
CDisp(CRefTime t); // Display a Reference Time
|
||||
#endif
|
||||
CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name)
|
||||
CDisp(IUnknown *pUnk); // Display a filter or pin
|
||||
#endif // __strmif_h__
|
||||
~CDisp();
|
||||
|
||||
// Implement cast to (LPCTSTR) as parameter to logger
|
||||
operator LPCTSTR()
|
||||
{
|
||||
return (LPCTSTR)m_pString;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
class CAutoTrace
|
||||
{
|
||||
private:
|
||||
const TCHAR* _szBlkName;
|
||||
const int _level;
|
||||
static const TCHAR _szEntering[];
|
||||
static const TCHAR _szLeaving[];
|
||||
public:
|
||||
CAutoTrace(const TCHAR* szBlkName, const int level = 15)
|
||||
: _szBlkName(szBlkName), _level(level)
|
||||
{DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));}
|
||||
|
||||
~CAutoTrace()
|
||||
{DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));}
|
||||
};
|
||||
|
||||
#define AMTRACE(_x_) CAutoTrace __trace _x_
|
||||
#else
|
||||
#define AMTRACE(_x_)
|
||||
#endif
|
||||
|
||||
#endif // __WXDEBUG__
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// File: WXDebug.h
|
||||
//
|
||||
// Desc: DirectShow base classes - provides debugging facilities.
|
||||
//
|
||||
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef __WXDEBUG__
|
||||
#define __WXDEBUG__
|
||||
|
||||
// This library provides fairly straight forward debugging functionality, this
|
||||
// is split into two main sections. The first is assertion handling, there are
|
||||
// three types of assertions provided here. The most commonly used one is the
|
||||
// ASSERT(condition) macro which will pop up a message box including the file
|
||||
// and line number if the condition evaluates to FALSE. Then there is the
|
||||
// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will
|
||||
// still be executed in NON debug builds. The final type of assertion is the
|
||||
// KASSERT macro which is more suitable for pure (perhaps kernel) filters as
|
||||
// the condition is printed onto the debugger rather than in a message box.
|
||||
//
|
||||
// The other part of the debug module facilties is general purpose logging.
|
||||
// This is accessed by calling DbgLog(). The function takes a type and level
|
||||
// field which define the type of informational string you are presenting and
|
||||
// it's relative importance. The type field can be a combination (one or more)
|
||||
// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level
|
||||
// is a DWORD value where zero defines highest important. Use of zero as the
|
||||
// debug logging level is to be encouraged ONLY for major errors or events as
|
||||
// they will ALWAYS be displayed on the debugger. Other debug output has it's
|
||||
// level matched against the current debug output level stored in the registry
|
||||
// for this module and if less than the current setting it will be displayed.
|
||||
//
|
||||
// Each module or executable has it's own debug output level for each of the
|
||||
// five types. These are read in when the DbgInitialise function is called
|
||||
// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL
|
||||
// is loaded, executables must call it explicitely with the module instance
|
||||
// handle given to them through the WINMAIN entry point. An executable must
|
||||
// also call DbgTerminate when they have finished to clean up the resources
|
||||
// the debug library uses, once again this is done automatically for DLLs
|
||||
|
||||
// These are the five different categories of logging information
|
||||
|
||||
enum { LOG_TIMING = 0x01, // Timing and performance measurements
|
||||
LOG_TRACE = 0x02, // General step point call tracing
|
||||
LOG_MEMORY = 0x04, // Memory and object allocation/destruction
|
||||
LOG_LOCKING = 0x08, // Locking/unlocking of critical sections
|
||||
LOG_ERROR = 0x10, // Debug error notification
|
||||
LOG_CUSTOM1 = 0x20,
|
||||
LOG_CUSTOM2 = 0x40,
|
||||
LOG_CUSTOM3 = 0x80,
|
||||
LOG_CUSTOM4 = 0x100,
|
||||
LOG_CUSTOM5 = 0x200,
|
||||
};
|
||||
|
||||
#define LOG_FORCIBLY_SET 0x80000000
|
||||
|
||||
enum { CDISP_HEX = 0x01,
|
||||
CDISP_DEC = 0x02};
|
||||
|
||||
// For each object created derived from CBaseObject (in debug builds) we
|
||||
// create a descriptor that holds it's name (statically allocated memory)
|
||||
// and a cookie we assign it. We keep a list of all the active objects
|
||||
// we have registered so that we can dump a list of remaining objects
|
||||
|
||||
typedef struct tag_ObjectDesc {
|
||||
const CHAR *m_szName;
|
||||
const WCHAR *m_wszName;
|
||||
DWORD m_dwCookie;
|
||||
tag_ObjectDesc *m_pNext;
|
||||
} ObjectDesc;
|
||||
|
||||
#define DLLIMPORT __declspec(dllimport)
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define NAME(x) TEXT(x)
|
||||
|
||||
// These are used internally by the debug library (PRIVATE)
|
||||
|
||||
void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax);
|
||||
void WINAPI DbgInitGlobalSettings(bool fTakeMax);
|
||||
void WINAPI DbgInitModuleSettings(bool fTakeMax);
|
||||
void WINAPI DbgInitModuleName();
|
||||
DWORD WINAPI DbgRegisterObjectCreation(
|
||||
const CHAR *szObjectName, const WCHAR *wszObjectName);
|
||||
|
||||
BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie);
|
||||
|
||||
// These are the PUBLIC entry points
|
||||
|
||||
BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level);
|
||||
void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level);
|
||||
void WINAPI DbgSetAutoRefreshLevels(bool fAuto);
|
||||
|
||||
// Initialise the library with the module handle
|
||||
|
||||
void WINAPI DbgInitialise(HINSTANCE hInst);
|
||||
void WINAPI DbgTerminate();
|
||||
|
||||
void WINAPI DbgDumpObjectRegister();
|
||||
|
||||
// Display error and logging to the user
|
||||
|
||||
void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...);
|
||||
|
||||
void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...);
|
||||
#ifdef UNICODE
|
||||
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const CHAR *pFormat,...);
|
||||
void WINAPI DbgAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgBreakPoint(const CHAR *pCondition,const CHAR *pFileName,INT iLine);
|
||||
void WINAPI DbgKernelAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine);
|
||||
#endif
|
||||
void WINAPI DbgOutString(LPCTSTR psz);
|
||||
|
||||
// Debug infinite wait stuff
|
||||
DWORD WINAPI DbgWaitForSingleObject(HANDLE h);
|
||||
DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount,
|
||||
CONST HANDLE *lpHandles,
|
||||
BOOL bWaitAll);
|
||||
void WINAPI DbgSetWaitTimeout(DWORD dwTimeout);
|
||||
|
||||
#ifdef __strmif_h__
|
||||
// Display a media type: Terse at level 2, verbose at level 5
|
||||
void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn);
|
||||
|
||||
// Dump lots of information about a filter graph
|
||||
void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel);
|
||||
#endif
|
||||
|
||||
#define KASSERT(_x_) if (!(_x_)) \
|
||||
DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
|
||||
|
||||
// Break on the debugger without putting up a message box
|
||||
// message goes to debugger instead
|
||||
|
||||
#define KDbgBreak(_x_) \
|
||||
DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
|
||||
|
||||
// We chose a common name for our ASSERT macro, MFC also uses this name
|
||||
// So long as the implementation evaluates the condition and handles it
|
||||
// then we will be ok. Rather than override the behaviour expected we
|
||||
// will leave whatever first defines ASSERT as the handler (i.e. MFC)
|
||||
#ifndef ASSERT
|
||||
#define ASSERT(_x_) if (!(_x_)) \
|
||||
DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__)
|
||||
#endif
|
||||
|
||||
#define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0)
|
||||
|
||||
// Put up a message box informing the user of a halt
|
||||
// condition in the program
|
||||
|
||||
#define DbgBreak(_x_) \
|
||||
DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__)
|
||||
|
||||
#define EXECUTE_ASSERT(_x_) ASSERT(_x_)
|
||||
#define DbgLog(_x_) DbgLogInfo _x_
|
||||
// MFC style trace macros
|
||||
|
||||
#define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_)))
|
||||
#define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a))
|
||||
#define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b))
|
||||
#define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c))
|
||||
#define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d))
|
||||
#define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e))
|
||||
|
||||
#else
|
||||
|
||||
// Retail builds make public debug functions inert - WARNING the source
|
||||
// files do not define or build any of the entry points in debug builds
|
||||
// (public entry points compile to nothing) so if you go trying to call
|
||||
// any of the private entry points in your source they won't compile
|
||||
|
||||
#define NAME(_x_) ((TCHAR *) NULL)
|
||||
|
||||
#define DbgInitialise(hInst)
|
||||
#define DbgTerminate()
|
||||
#define DbgLog(_x_) 0
|
||||
#define DbgOutString(psz)
|
||||
#define DbgAssertAligned( _ptr_, _alignment_ ) 0
|
||||
|
||||
#define DbgRegisterObjectCreation(pObjectName)
|
||||
#define DbgRegisterObjectDestruction(dwCookie)
|
||||
#define DbgDumpObjectRegister()
|
||||
|
||||
#define DbgCheckModuleLevel(Type,Level)
|
||||
#define DbgSetModuleLevel(Type,Level)
|
||||
#define DbgSetAutoRefreshLevels(fAuto)
|
||||
|
||||
#define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE)
|
||||
#define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \
|
||||
WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE)
|
||||
#define DbgSetWaitTimeout(dwTimeout)
|
||||
|
||||
#define KDbgBreak(_x_)
|
||||
#define DbgBreak(_x_)
|
||||
|
||||
#define KASSERT(_x_) ((void)0)
|
||||
#ifndef ASSERT
|
||||
#define ASSERT(_x_) ((void)0)
|
||||
#endif
|
||||
#define EXECUTE_ASSERT(_x_) ((void)(_x_))
|
||||
|
||||
// MFC style trace macros
|
||||
|
||||
#define NOTE(_x_) ((void)0)
|
||||
#define NOTE1(_x_,a) ((void)0)
|
||||
#define NOTE2(_x_,a,b) ((void)0)
|
||||
#define NOTE3(_x_,a,b,c) ((void)0)
|
||||
#define NOTE4(_x_,a,b,c,d) ((void)0)
|
||||
#define NOTE5(_x_,a,b,c,d,e) ((void)0)
|
||||
|
||||
#define DisplayType(label, pmtIn) ((void)0)
|
||||
#define DumpGraph(pGraph, label) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
// Checks a pointer which should be non NULL - can be used as follows.
|
||||
|
||||
#define CheckPointer(p,ret) {if((p)==NULL) return (ret);}
|
||||
|
||||
// HRESULT Foo(VOID *pBar)
|
||||
// {
|
||||
// CheckPointer(pBar,E_INVALIDARG)
|
||||
// }
|
||||
//
|
||||
// Or if the function returns a boolean
|
||||
//
|
||||
// BOOL Foo(VOID *pBar)
|
||||
// {
|
||||
// CheckPointer(pBar,FALSE)
|
||||
// }
|
||||
|
||||
// These validate pointers when symbol VFWROBUST is defined
|
||||
// This will normally be defined in debug not retail builds
|
||||
|
||||
#ifdef DEBUG
|
||||
#define VFWROBUST
|
||||
#endif
|
||||
|
||||
#ifdef VFWROBUST
|
||||
|
||||
#define ValidateReadPtr(p,cb) \
|
||||
{if(IsBadReadPtr((PVOID)p,cb) == TRUE) \
|
||||
DbgBreak("Invalid read pointer");}
|
||||
|
||||
#define ValidateWritePtr(p,cb) \
|
||||
{if(IsBadWritePtr((PVOID)p,cb) == TRUE) \
|
||||
DbgBreak("Invalid write pointer");}
|
||||
|
||||
#define ValidateReadWritePtr(p,cb) \
|
||||
{ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)}
|
||||
|
||||
#define ValidateStringPtr(p) \
|
||||
{if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \
|
||||
DbgBreak("Invalid string pointer");}
|
||||
|
||||
#define ValidateStringPtrA(p) \
|
||||
{if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \
|
||||
DbgBreak("Invalid ANSI string pointer");}
|
||||
|
||||
#define ValidateStringPtrW(p) \
|
||||
{if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \
|
||||
DbgBreak("Invalid UNICODE string pointer");}
|
||||
|
||||
#else
|
||||
#define ValidateReadPtr(p,cb) 0
|
||||
#define ValidateWritePtr(p,cb) 0
|
||||
#define ValidateReadWritePtr(p,cb) 0
|
||||
#define ValidateStringPtr(p) 0
|
||||
#define ValidateStringPtrA(p) 0
|
||||
#define ValidateStringPtrW(p) 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _OBJBASE_H_
|
||||
|
||||
// Outputting GUID names. If you want to include the name
|
||||
// associated with a GUID (eg CLSID_...) then
|
||||
//
|
||||
// GuidNames[yourGUID]
|
||||
//
|
||||
// Returns the name defined in uuids.h as a string
|
||||
|
||||
typedef struct {
|
||||
CHAR *szName;
|
||||
GUID guid;
|
||||
} GUID_STRING_ENTRY;
|
||||
|
||||
class CGuidNameList {
|
||||
public:
|
||||
CHAR *operator [] (const GUID& guid);
|
||||
};
|
||||
|
||||
extern CGuidNameList GuidNames;
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef REMIND
|
||||
// REMIND macro - generates warning as reminder to complete coding
|
||||
// (eg) usage:
|
||||
//
|
||||
// #pragma message (REMIND("Add automation support"))
|
||||
|
||||
|
||||
#define QUOTE(x) #x
|
||||
#define QQUOTE(y) QUOTE(y)
|
||||
#define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str
|
||||
#endif
|
||||
|
||||
// Method to display objects in a useful format
|
||||
//
|
||||
// eg If you want to display a LONGLONG ll in a debug string do (eg)
|
||||
//
|
||||
// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX)));
|
||||
|
||||
|
||||
class CDispBasic
|
||||
{
|
||||
public:
|
||||
CDispBasic() { m_pString = m_String; };
|
||||
~CDispBasic();
|
||||
protected:
|
||||
PTCHAR m_pString; // normally points to m_String... unless too much data
|
||||
TCHAR m_String[50];
|
||||
};
|
||||
class CDisp : public CDispBasic
|
||||
{
|
||||
public:
|
||||
CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form
|
||||
CDisp(REFCLSID clsid); // Display a GUID
|
||||
CDisp(double d); // Display a floating point number
|
||||
#ifdef __strmif_h__
|
||||
#ifdef __STREAMS__
|
||||
CDisp(CRefTime t); // Display a Reference Time
|
||||
#endif
|
||||
CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name)
|
||||
CDisp(IUnknown *pUnk); // Display a filter or pin
|
||||
#endif // __strmif_h__
|
||||
~CDisp();
|
||||
|
||||
// Implement cast to (LPCTSTR) as parameter to logger
|
||||
operator LPCTSTR()
|
||||
{
|
||||
return (LPCTSTR)m_pString;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
class CAutoTrace
|
||||
{
|
||||
private:
|
||||
const TCHAR* _szBlkName;
|
||||
const int _level;
|
||||
static const TCHAR _szEntering[];
|
||||
static const TCHAR _szLeaving[];
|
||||
public:
|
||||
CAutoTrace(const TCHAR* szBlkName, const int level = 15)
|
||||
: _szBlkName(szBlkName), _level(level)
|
||||
{DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));}
|
||||
|
||||
~CAutoTrace()
|
||||
{DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));}
|
||||
};
|
||||
|
||||
#define AMTRACE(_x_) CAutoTrace __trace _x_
|
||||
#else
|
||||
#define AMTRACE(_x_)
|
||||
#endif
|
||||
|
||||
#endif // __WXDEBUG__
|
||||
|
||||
|
||||
|
||||
+885
-885
File diff suppressed because it is too large
Load Diff
+551
-551
File diff suppressed because it is too large
Load Diff
+1210
-1210
File diff suppressed because it is too large
Load Diff
+533
-533
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user