Files
Client/Library/dxx8/samples/Multimedia/DirectShow/Common/dshowutil.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

619 lines
15 KiB
C++

//------------------------------------------------------------------------------
// File: DShowUtil.cpp
//
// Desc: DirectShow sample code - utility functions.
//
// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include "stdafx.h"
#include <atlbase.h>
#include <dshow.h>
#include <mtype.h>
#include <wxdebug.h>
#include <reftime.h>
#include "dshowutil.h"
HRESULT FindRenderer(IGraphBuilder *pGB, const GUID *mediatype, IBaseFilter **ppFilter)
{
HRESULT hr;
IEnumFilters *pEnum = NULL;
IBaseFilter *pFilter = NULL;
IPin *pPin;
ULONG ulFetched, ulInPins, ulOutPins;
BOOL bFound=FALSE;
// Verify graph builder interface
if (!pGB)
return E_NOINTERFACE;
// Verify that a media type was passed
if (!mediatype)
return E_POINTER;
// Clear the filter pointer in case there is no match
if (ppFilter)
*ppFilter = NULL;
// Get filter enumerator
hr = pGB->EnumFilters(&pEnum);
if (FAILED(hr))
return hr;
pEnum->Reset();
// Enumerate all filters in the graph
while(!bFound && (pEnum->Next(1, &pFilter, &ulFetched) == S_OK))
{
#ifdef DEBUG
// Read filter name for debugging purposes
FILTER_INFO FilterInfo;
TCHAR szName[256];
hr = pFilter->QueryFilterInfo(&FilterInfo);
if (SUCCEEDED(hr))
{
// Show filter name in debugger
#ifdef UNICODE
lstrcpy(szName, FilterInfo.achName);
#else
WideCharToMultiByte(CP_ACP, 0, FilterInfo.achName, -1, szName, 256, 0, 0);
#endif
FilterInfo.pGraph->Release();
}
#endif
// Find a filter with one input and no output pins
hr = CountFilterPins(pFilter, &ulInPins, &ulOutPins);
if (FAILED(hr))
break;
if ((ulInPins == 1) && (ulOutPins == 0))
{
// Get the first pin on the filter
pPin=0;
pPin = GetInPin(pFilter, 0);
// Read this pin's major media type
AM_MEDIA_TYPE type={0};
hr = pPin->ConnectionMediaType(&type);
if (FAILED(hr))
break;
// Is this pin's media type the requested type?
// If so, then this is the renderer for which we are searching.
// Copy the interface pointer and return.
if (type.majortype == *mediatype)
{
// Found our filter
*ppFilter = pFilter;
bFound = TRUE;;
}
// This is not the renderer, so release the interface.
else
pFilter->Release();
// Delete memory allocated by ConnectionMediaType()
FreeMediaType(type);
}
else
{
// No match, so release the interface
pFilter->Release();
}
}
pEnum->Release();
return hr;
}
HRESULT FindAudioRenderer(IGraphBuilder *pGB, IBaseFilter **ppFilter)
{
return FindRenderer(pGB, &MEDIATYPE_Audio, ppFilter);
}
HRESULT FindVideoRenderer(IGraphBuilder *pGB, IBaseFilter **ppFilter)
{
return FindRenderer(pGB, &MEDIATYPE_Video, ppFilter);
}
HRESULT CountFilterPins(IBaseFilter *pFilter, ULONG *pulInPins, ULONG *pulOutPins)
{
HRESULT hr=S_OK;
IEnumPins *pEnum=0;
ULONG ulFound;
IPin *pPin;
// Verify input
if (!pFilter || !pulInPins || !pulOutPins)
return E_POINTER;
// Clear number of pins found
*pulInPins = 0;
*pulOutPins = 0;
// Get pin enumerator
hr = pFilter->EnumPins(&pEnum);
if(FAILED(hr))
return hr;
pEnum->Reset();
// Count every pin on the filter
while(S_OK == pEnum->Next(1, &pPin, &ulFound))
{
PIN_DIRECTION pindir = (PIN_DIRECTION)3;
hr = pPin->QueryDirection(&pindir);
if(pindir == PINDIR_INPUT)
(*pulInPins)++;
else
(*pulOutPins)++;
pPin->Release();
}
pEnum->Release();
return hr;
}
HRESULT CountTotalFilterPins(IBaseFilter *pFilter, ULONG *pulPins)
{
HRESULT hr;
IEnumPins *pEnum=0;
ULONG ulFound;
IPin *pPin;
// Verify input
if (!pFilter || !pulPins)
return E_POINTER;
// Clear number of pins found
*pulPins = 0;
// Get pin enumerator
hr = pFilter->EnumPins(&pEnum);
if(FAILED(hr))
return hr;
// Count every pin on the filter, ignoring direction
while(S_OK == pEnum->Next(1, &pPin, &ulFound))
{
(*pulPins)++;
pPin->Release();
}
pEnum->Release();
return hr;
}
HRESULT GetPin( IBaseFilter * pFilter, PIN_DIRECTION dirrequired, int iNum, IPin **ppPin)
{
CComPtr< IEnumPins > pEnum;
*ppPin = NULL;
HRESULT hr = pFilter->EnumPins(&pEnum);
if(FAILED(hr))
return hr;
ULONG ulFound;
IPin *pPin;
hr = E_FAIL;
while(S_OK == pEnum->Next(1, &pPin, &ulFound))
{
PIN_DIRECTION pindir = (PIN_DIRECTION)3;
pPin->QueryDirection(&pindir);
if(pindir == dirrequired)
{
if(iNum == 0)
{
*ppPin = pPin;
// Found requested pin, so clear error
hr = S_OK;
break;
}
iNum--;
}
pPin->Release();
}
return hr;
}
IPin * GetInPin( IBaseFilter * pFilter, int Num )
{
CComPtr< IPin > pComPin;
GetPin(pFilter, PINDIR_INPUT, Num, &pComPin);
return pComPin;
}
IPin * GetOutPin( IBaseFilter * pFilter, int Num )
{
CComPtr< IPin > pComPin;
GetPin(pFilter, PINDIR_OUTPUT, Num, &pComPin);
return pComPin;
}
HRESULT FindOtherSplitterPin(IPin *pPinIn, GUID guid, int nStream, IPin **ppSplitPin)
{
if (!ppSplitPin)
return E_POINTER;
CComPtr< IPin > pPinOut;
pPinOut = pPinIn;
while(pPinOut)
{
PIN_INFO ThisPinInfo;
pPinOut->QueryPinInfo(&ThisPinInfo);
if(ThisPinInfo.pFilter) ThisPinInfo.pFilter->Release();
pPinOut = NULL;
CComPtr< IEnumPins > pEnumPins;
ThisPinInfo.pFilter->EnumPins(&pEnumPins);
if(!pEnumPins)
{
return NULL;
}
// look at every pin on the current filter...
//
ULONG Fetched = 0;
while(1)
{
CComPtr< IPin > pPin;
Fetched = 0;
ASSERT(!pPin); // is it out of scope?
pEnumPins->Next(1, &pPin, &Fetched);
if(!Fetched)
{
break;
}
PIN_INFO pi;
pPin->QueryPinInfo(&pi);
if(pi.pFilter) pi.pFilter->Release();
// if it's an input pin...
//
if(pi.dir == PINDIR_INPUT)
{
// continue searching upstream from this pin
//
pPin->ConnectedTo(&pPinOut);
// a pin that supports the required media type is the
// splitter pin we are looking for! We are done
//
}
else
{
CComPtr< IEnumMediaTypes > pMediaEnum;
pPin->EnumMediaTypes(&pMediaEnum);
if(pMediaEnum)
{
Fetched = 0;
AM_MEDIA_TYPE *pMediaType;
pMediaEnum->Next(1, &pMediaType, &Fetched);
if(Fetched)
{
if(pMediaType->majortype == guid)
{
if(nStream-- == 0)
{
DeleteMediaType(pMediaType);
*ppSplitPin = pPin;
(*ppSplitPin)->AddRef();
return S_OK;
}
}
DeleteMediaType(pMediaType);
}
}
}
// go try the next pin
} // while
}
ASSERT(FALSE);
return E_FAIL;
}
HRESULT SeekNextFrame( IMediaSeeking * pSeeking, double FPS, long Frame )
{
// try seeking by frames first
//
HRESULT hr = pSeeking->SetTimeFormat(&TIME_FORMAT_FRAME);
REFERENCE_TIME Pos = 0;
if(!FAILED(hr))
{
pSeeking->GetCurrentPosition(&Pos);
Pos++;
}
else
{
// couldn't seek by frames, use Frame and FPS to calculate time
//
Pos = REFERENCE_TIME(double( Frame * UNITS ) / FPS);
// add a half-frame to seek to middle of the frame
//
Pos += REFERENCE_TIME(double( UNITS ) * 0.5 / FPS);
}
hr = pSeeking->SetPositions(&Pos, AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning);
return hr;
}
#ifdef DEBUG
// for debugging purposes
const INT iMAXLEVELS = 5; // Maximum debug categories
extern DWORD m_Levels[iMAXLEVELS]; // Debug level per category
#endif
void TurnOnDebugDllDebugging( )
{
#ifdef DEBUG
for(int i = 0 ; i < iMAXLEVELS ; i++)
{
m_Levels[i] = 1;
}
#endif
}
void DbgPrint( char * pText )
{
DbgLog(( LOG_TRACE, 1, "%s", pText ));
}
void ErrPrint( char * pText )
{
printf(pText);
return;
}
// Adds a DirectShow filter graph to the Running Object Table,
// allowing GraphEdit to "spy" on a remote filter graph.
HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
{
IMoniker * pMoniker;
IRunningObjectTable *pROT;
WCHAR wsz[128];
HRESULT hr;
if (FAILED(GetRunningObjectTable(0, &pROT)))
return E_FAIL;
wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph,
GetCurrentProcessId());
hr = CreateItemMoniker(L"!", wsz, &pMoniker);
if (SUCCEEDED(hr))
{
hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);
pMoniker->Release();
}
pROT->Release();
return hr;
}
// Removes a filter graph from the Running Object Table
void RemoveGraphFromRot(DWORD pdwRegister)
{
IRunningObjectTable *pROT;
if (SUCCEEDED(GetRunningObjectTable(0, &pROT)))
{
pROT->Revoke(pdwRegister);
pROT->Release();
}
}
void ShowFilenameByCLSID(REFCLSID clsid, TCHAR *szFilename)
{
HRESULT hr;
LPOLESTR strCLSID;
// Convert binary CLSID to a readable version
hr = StringFromCLSID(clsid, &strCLSID);
if(SUCCEEDED(hr))
{
TCHAR szKey[512];
CString strQuery(strCLSID);
// Create key name for reading filename registry
wsprintf(szKey, TEXT("Software\\Classes\\CLSID\\%s\\InprocServer32\0"),
strQuery);
// Free memory associated with strCLSID (allocated in StringFromCLSID)
CoTaskMemFree(strCLSID);
HKEY hkeyFilter=0;
DWORD dwSize=MAX_PATH;
BYTE szFile[MAX_PATH];
int rc=0;
// Open the CLSID key that contains information about the filter
rc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &hkeyFilter);
if (rc == ERROR_SUCCESS)
{
rc = RegQueryValueEx(hkeyFilter, NULL, // Read (Default) value
NULL, NULL, szFile, &dwSize);
if (rc == ERROR_SUCCESS)
wsprintf(szFilename, TEXT("%s"), szFile);
else
wsprintf(szFilename, TEXT("<Unknown>\0"));
rc = RegCloseKey(hkeyFilter);
}
}
}
HRESULT GetFileDurationString(IMediaSeeking *pMS, TCHAR *szDuration)
{
HRESULT hr;
if (!pMS)
return E_NOINTERFACE;
if (!szDuration)
return E_POINTER;
// Initialize the display in case we can't read the duration
wsprintf(szDuration, TEXT("<00:00.000>"));
// Is media time supported for this file?
if (S_OK != pMS->IsFormatSupported(&TIME_FORMAT_MEDIA_TIME))
return E_NOINTERFACE;
// Read the time format to restore later
GUID guidOriginalFormat;
hr = pMS->GetTimeFormat(&guidOriginalFormat);
if (FAILED(hr))
return hr;
// Ensure media time format for easy display
hr = pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
if (FAILED(hr))
return hr;
// Read the file's duration
LONGLONG llDuration;
hr = pMS->GetDuration(&llDuration);
if (FAILED(hr))
return hr;
// Return to the original format
if (guidOriginalFormat != TIME_FORMAT_MEDIA_TIME)
{
hr = pMS->SetTimeFormat(&guidOriginalFormat);
if (FAILED(hr))
return hr;
}
// Convert the LONGLONG duration into human-readable format
unsigned long nTotalMS = (unsigned long) llDuration / 10000; // 100ns -> ms
int nMS = nTotalMS % 1000;
int nSeconds = nTotalMS / 1000;
int nMinutes = nSeconds / 60;
nSeconds %= 60;
// Update the string
wsprintf(szDuration, _T("%02dm:%02d.%03ds\0"), nMinutes, nSeconds, nMS);
return hr;
}
BOOL SupportsPropertyPage(IBaseFilter *pFilter)
{
HRESULT hr;
ISpecifyPropertyPages *pSpecify;
// Discover if this filter contains a property page
hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
if (SUCCEEDED(hr))
{
pSpecify->Release();
return TRUE;
}
else
return FALSE;
}
HRESULT ShowFilterPropertyPage(IBaseFilter *pFilter, HWND hwndParent)
{
HRESULT hr;
ISpecifyPropertyPages *pSpecify=0;
if (!pFilter)
return E_NOINTERFACE;
// Discover if this filter contains a property page
hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
if (SUCCEEDED(hr))
{
do
{
FILTER_INFO FilterInfo;
hr = pFilter->QueryFilterInfo(&FilterInfo);
if (FAILED(hr))
break;
CAUUID caGUID;
hr = pSpecify->GetPages(&caGUID);
if (FAILED(hr))
break;
pSpecify->Release();
// Display the filter's property page
OleCreatePropertyFrame(
hwndParent, // Parent window
0, // x (Reserved)
0, // y (Reserved)
FilterInfo.achName, // Caption for the dialog box
1, // Number of filters
(IUnknown **)&pFilter, // Pointer to the filter
caGUID.cElems, // Number of property pages
caGUID.pElems, // Pointer to property page CLSIDs
0, // Locale identifier
0, // Reserved
NULL // Reserved
);
CoTaskMemFree(caGUID.pElems);
FilterInfo.pGraph->Release();
} while(0);
}
pFilter->Release();
return hr;
}
//
// Some hardware decoders and video renderers support stepping media
// frame by frame with the IVideoFrameStep interface. See the interface
// documentation for more details on frame stepping.
//
BOOL CanFrameStep(IGraphBuilder *pGB)
{
HRESULT hr;
IVideoFrameStep* pFS;
hr = pGB->QueryInterface(__uuidof(IVideoFrameStep), (PVOID *)&pFS);
if (FAILED(hr))
return FALSE;
// Check if this decoder can step
hr = pFS->CanStep(0L, NULL);
pFS->Release();
if (hr == S_OK)
return TRUE;
else
return FALSE;
}