Files
Client/Library/dxx8/samples/Multimedia/DirectShow/Misc/ASFCopy/asfcopy.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

739 lines
18 KiB
C++

//------------------------------------------------------------------------------
// File: ASFCopy.cpp
//
// Desc: DirectShow sample code - ASF copy.
//
// Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include <streams.h>
// Disable warning C4268, which is generated within <wmsdk.h>
#pragma warning(disable:4268)
#include <wmsdk.h>
#pragma warning(default:4268)
#include <atlbase.h>
#include <atlimpl.cpp>
#include <stdio.h>
#include <dshowasf.h>
//
// Build warning to remind developers of the dependency on the
// Windows Media Format SDK libraries, which do not ship with
// the DirectX SDK.
//
#pragma message("NOTE: To link and run this sample, you must install the Windows Media Format SDK.")
#pragma message("After signing a license agreement with Microsoft, you will receive a")
#pragma message("unique version of WMStub.LIB, which should be added to this VC++ project.")
#pragma message("Without this library, you will receive linker errors for the following:")
#pragma message(" WMCreateCertificate")
#pragma message("You must also add WMVCore.LIB to the linker settings to resolve the following:")
#pragma message(" WMCreateProfileManager")
// Global data
BOOL fVerbose = FALSE;
// Function prototypes
HRESULT MapProfileIdToProfile(int iProfile, IWMProfile **ppProfile);
class CKeyProvider : public IServiceProvider
{
public:
//
// IUnknown interface
//
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
CKeyProvider();
// IServiceProvider
STDMETHODIMP QueryService(REFIID siid, REFIID riid, void **ppv);
private:
ULONG m_cRef;
};
CKeyProvider::CKeyProvider() : m_cRef(0)
{
}
//////////////////////////////////////////////////////////////////////////
//
// IUnknown methods
//
//////////////////////////////////////////////////////////////////////////
ULONG CKeyProvider::AddRef()
{
return ++m_cRef;
}
ULONG CKeyProvider::Release()
{
ASSERT(m_cRef > 0);
m_cRef--;
if(m_cRef == 0)
{
delete this;
// don't return m_cRef, because the object doesn't exist anymore
return((ULONG) 0);
}
return(m_cRef);
}
//
// QueryInterface
//
// We only support IUnknown and IServiceProvider
//
HRESULT CKeyProvider::QueryInterface(REFIID riid, void ** ppv)
{
if(riid == IID_IServiceProvider || riid == IID_IUnknown)
{
*ppv = (void *) static_cast<IServiceProvider *>(this);
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP CKeyProvider::QueryService(REFIID siid, REFIID riid, void **ppv)
{
if(siid == __uuidof(IWMReader) && riid == IID_IUnknown)
{
IUnknown *punkCert;
HRESULT hr = WMCreateCertificate(&punkCert);
if(SUCCEEDED(hr))
*ppv = (void *) punkCert;
else
printf("CKeyProvider::QueryService failed to create certificate! hr=0x%x\n", hr);
return hr;
}
return E_NOINTERFACE;
}
HRESULT FindPinOnFilter( IBaseFilter * pFilter, PIN_DIRECTION PinDir,
DWORD dwPin, BOOL fConnected, IPin ** ppPin )
{
HRESULT hr = S_OK;
IEnumPins * pEnumPin = NULL;
IPin * pConnectedPin = NULL;
PIN_DIRECTION PinDirection;
ULONG ulFetched;
DWORD nFound = 0;
ASSERT( pFilter != NULL );
*ppPin = NULL;
hr = pFilter->EnumPins( &pEnumPin );
if(SUCCEEDED(hr))
{
while ( S_OK == ( hr = pEnumPin->Next( 1L, ppPin, &ulFetched ) ) )
{
hr = (*ppPin)->ConnectedTo( &pConnectedPin );
if (pConnectedPin)
{
pConnectedPin->Release();
pConnectedPin = NULL;
}
if ( ( ( VFW_E_NOT_CONNECTED == hr ) && !fConnected ) ||
( ( S_OK == hr ) && fConnected ) )
{
hr = (*ppPin)->QueryDirection( &PinDirection );
if ( ( S_OK == hr ) && ( PinDirection == PinDir ) )
{
if ( nFound == dwPin ) break;
nFound++;
}
}
(*ppPin)->Release();
}
}
pEnumPin->Release();
return hr;
} // FindPinOnFilter
HRESULT GetPin(IBaseFilter *pFilter, DWORD dwPin, IPin **ppPin)
{
IEnumPins *pins;
*ppPin = NULL;
HRESULT hr = pFilter->EnumPins(&pins);
if(FAILED(hr))
{
DbgLog((LOG_ERROR,1,TEXT("EnumPins failed! (%x)\n"), hr));
return hr;
}
if(dwPin > 0)
{
hr = pins->Skip(dwPin);
if(FAILED(hr))
{
DbgLog((LOG_ERROR,1,TEXT("Skip(%d) failed! (%x)\n"), dwPin, hr));
pins->Release();
return hr;
}
if(hr == S_FALSE)
{
DbgLog((LOG_ERROR,1,TEXT("Skip(%d) ran out of pins!\n"), dwPin));
pins->Release();
return hr;
}
}
DWORD n;
hr = pins->Next(1, ppPin, &n);
if(FAILED(hr))
{
DbgLog((LOG_ERROR,1,TEXT("Next() failed! (%x)\n"), hr));
}
if(hr == S_FALSE)
{
DbgLog((LOG_ERROR,1,TEXT("Next() ran out of pins! \n")));
pins->Release();
return hr;
}
pins->Release();
return hr;
}
void ListProfiles()
{
USES_CONVERSION;
int wextent = 0, Loop = 0;
DWORD cProfiles = 0;
DWORD cchName, cchDescription;
CComPtr <IWMProfileManager> pIWMProfileManager;
printf("Standard system profiles:\n");
HRESULT hr = WMCreateProfileManager(&pIWMProfileManager);
if(FAILED(hr))
{
printf("ListProfiles: Failed to create profile manager! hr=0x%x\n", hr);
return; // error
}
CComQIPtr<IWMProfileManager2, &IID_IWMProfileManager2> pIPM2(pIWMProfileManager);
if(!pIPM2)
{
printf("ListProfiles: Failed to QI IWMProfileManager2! hr=0x%x\n", hr);
return;
}
// we only use 7_0 profiles
hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );
if(FAILED(hr))
{
printf("ListProfiles: Failed to set system profile version! hr=0x%x\n", hr);
return;
}
hr = pIWMProfileManager->GetSystemProfileCount(&cProfiles);
if(FAILED(hr))
{
printf("ListProfiles: Failed to get system profile count! hr=0x%x\n", hr);
return;
}
// Load the profile strings
for(int i = 0; i < (int)cProfiles; ++i)
{
CComPtr <IWMProfile> pIWMProfile;
hr = pIWMProfileManager->LoadSystemProfile(i, &pIWMProfile);
if(FAILED(hr))
{
printf("ListProfiles: Failed to load system profile! hr=0x%x\n", hr);
return;
}
// How large is the profile name?
hr = pIWMProfile->GetName(NULL, &cchName);
if(FAILED(hr))
{
printf("ListProfiles: Failed to read profile name size! hr=0x%x\n", hr);
return;
}
WCHAR *wszProfile = new WCHAR[ cchName + 1 ];
if(NULL == wszProfile)
return;
hr = pIWMProfile->GetName(wszProfile, &cchName);
if(FAILED(hr))
{
printf("ListProfiles: Failed to read profile name! hr=0x%x\n", hr);
return;
}
// How large is the description?
hr = pIWMProfile->GetDescription(NULL, &cchDescription);
if(FAILED(hr))
{
printf("ListProfiles: Failed to read profile description size! hr=0x%x\n", hr);
return;
}
WCHAR *wszDescription = new WCHAR[ cchDescription + 1 ];
if(NULL == wszDescription)
return;
hr = pIWMProfile->GetDescription(wszDescription, &cchDescription);
if(FAILED(hr))
{
printf("ListProfiles: Failed to read profile description! hr=0x%x\n", hr);
return;
}
// Display the profile name and description
if (fVerbose)
printf(" %3d: %ls \n[%ls]\n\n", i, wszProfile, wszDescription);
else
printf(" %3d: %ls\n", i, wszProfile);
delete[] wszProfile;
delete[] wszDescription;
}
}
//=======================
// CreateFilterGraph
//=======================
HRESULT CreateFilterGraph(IGraphBuilder **pGraph)
{
HRESULT hr;
hr = CoCreateInstance(CLSID_FilterGraph, // get the graph object
NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void **) pGraph);
if(FAILED(hr))
{
printf("CreateFilterGraph: Failed to create graph! hr=0x%x\n", hr);
*pGraph = NULL;
return hr;
}
return S_OK;
}
HRESULT CreateFilter(REFCLSID clsid, IBaseFilter **ppFilter)
{
HRESULT hr;
hr = CoCreateInstance(clsid,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void **) ppFilter);
if(FAILED(hr))
{
printf("CreateFilter: Failed to create filter! hr=0x%x\n", hr);
*ppFilter = NULL;
return hr;
}
return S_OK;
}
HRESULT SetNoClock(IFilterGraph *graph)
{
// Keep a useless clock from being instantiated....
IMediaFilter *graphF;
HRESULT hr = graph->QueryInterface(IID_IMediaFilter, (void **) &graphF);
if(SUCCEEDED(hr))
{
hr = graphF->SetSyncSource(NULL);
if (FAILED(hr))
printf("SetNoClock: Failed to set sync source! hr=0x%x\n", hr);
graphF->Release();
}
else
{
printf("SetNoClock: Failed to QI for media filter! hr=0x%x\n", hr);
}
return hr;
}
HRESULT MapProfileIdToProfile(int iProfile, IWMProfile **ppProfile)
{
DWORD cProfiles;
*ppProfile = 0;
CComPtr <IWMProfileManager> pIWMProfileManager;
HRESULT hr = WMCreateProfileManager( &pIWMProfileManager );
if(FAILED(hr))
{
printf("MapProfile: Failed to create profile manager! hr=0x%x\n", hr);
return hr;
}
// We only use 7_0 profiles
CComQIPtr<IWMProfileManager2, &IID_IWMProfileManager2> pIPM2(pIWMProfileManager);
if(!pIPM2)
{
printf("MapProfile: Failed to QI IWMProfileManager2!\n");
return E_UNEXPECTED;
}
hr = pIPM2->SetSystemProfileVersion( WMT_VER_7_0 );
if(FAILED(hr))
{
printf("MapProfile: Failed to set system profile version! hr=0x%x\n", hr);
return hr;
}
hr = pIWMProfileManager->GetSystemProfileCount( &cProfiles );
if(FAILED(hr))
{
printf("MapProfile: Failed to get system profile count! hr=0x%x\n", hr);
return hr;
}
// Invalid profile requested?
if( (DWORD)iProfile >= cProfiles )
{
printf("Invalid profile: %d\n", iProfile);
return E_INVALIDARG;
}
return (pIWMProfileManager->LoadSystemProfile( iProfile, ppProfile ));
}
void WaitForCompletion( IGraphBuilder *pGraph )
{
HRESULT hr;
LONG lEvCode = 0;
IMediaEvent *pEvent;
pGraph->QueryInterface(IID_IMediaEvent, (void **) &pEvent);
printf("Waiting for completion...\n This could take several minutes, "
"depending on file size and selected profile.\n");
do
{
MSG Message;
while(PeekMessage(&Message, NULL, 0, 0, TRUE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
hr = pEvent->WaitForCompletion(10, &lEvCode);
} while(lEvCode == 0);
pEvent->Release();
}
HRESULT CopyASF(int argc, char *argv[])
{
HRESULT hr;
WCHAR SourceFile[256], TargetFile[256];
BOOL fListProfiles = TRUE;
DWORD dwProfile=0;
int i = 1;
// Parse command line options
while(i < argc && (argv[i][0] == '-' || argv[i][0] == '/'))
{
// options
if(lstrcmpiA(argv[i] + 1, "v") == 0)
{
fVerbose = TRUE;
printf("Verbose mode enabled.\n");
}
else if((i+1 < argc) && lstrcmpiA(argv[i] + 1, "p") == 0)
{
fListProfiles = FALSE;
dwProfile = atoiA(argv[i+1]);
i++; // skip two args here
}
i++;
}
// List profiles only?
if(fListProfiles)
{
printf("Usage: asfcopy [/v] /p profnum file1 [ file2 ...] target\n\n");
HRESULT hr = CoInitialize(NULL);
ListProfiles();
CoUninitialize();
return -1;
}
// Fail with usage information if improper number of arguments
if(argc < i+2)
{
printf("Usage: asfcopy [/v] /p profnum file1 [ file2 ...] target\n");
return -1;
}
CComPtr <IGraphBuilder> pGraph;
CComPtr <IObjectWithSite> pObjectWithSite;
CComPtr <IBaseFilter> pMux;
CComPtr <IBaseFilter> pWriter;
CComPtr <IFileSinkFilter> pFS;
CComPtr <IConfigInterleaving> pConfigInterleaving;
CComPtr <IConfigAsfWriter> pConfigAsfWriter;
CComPtr <IMediaControl> pGraphC;
// Convert target filename
MultiByteToWideChar(CP_ACP, 0, argv[argc - 1], -1, TargetFile, 256);
hr = CreateFilterGraph(&pGraph);
if(FAILED(hr))
{
printf("Couldn't create filter graph! hr=0x%x", hr);
return hr;
}
CKeyProvider prov;
prov.AddRef(); // Don't let COM try to free our static object
// Give the graph a pointer to us for callbacks & QueryService
hr = pGraph->QueryInterface(IID_IObjectWithSite, (void**)&pObjectWithSite);
if(SUCCEEDED(hr))
{
hr = pObjectWithSite->SetSite((IUnknown *) (IServiceProvider *) &prov);
if(FAILED(hr))
{
printf("Failed to set service provider! hr=0x%x\n", hr);
return hr;
}
}
hr = CreateFilter(CLSID_WMAsfWriter, &pMux);
if(FAILED(hr))
{
printf("Failed to create WMAsfWriter filter! hr=0x%x\n", hr);
return hr;
}
hr = pMux->QueryInterface(IID_IFileSinkFilter, (void **) &pFS);
if(FAILED(hr))
{
// We need a writer also
hr = CreateFilter(CLSID_FileWriter, &pWriter);
if(FAILED(hr))
{
printf("Failed to create FileWriter filter! hr=0x%x\n", hr);
return hr;
}
else
{
hr = pWriter->QueryInterface(IID_IFileSinkFilter, (void **) &pFS);
if(FAILED(hr))
{
printf("Failed to create QI IFileSinkFilter! hr=0x%x\n", hr);
return hr;
}
}
}
hr = pFS->SetFileName(TargetFile, NULL);
if(FAILED(hr))
{
printf("Failed to set target filename! hr=0x%x\n", hr);
return hr;
}
hr = pGraph->AddFilter(pMux, L"Mux");
if(FAILED(hr))
{
printf("Failed to add Mux filter to graph! hr=0x%x\n", hr);
return hr;
}
// Set interleaving mode to FULL
// !!! ASF won't support this, but that's okay
hr = pMux->QueryInterface(IID_IConfigInterleaving, (void **) &pConfigInterleaving);
if(SUCCEEDED(hr))
{
printf("Setting interleaving mode to INTERLEAVE_FULL\r\n");
hr = pConfigInterleaving->put_Mode(INTERLEAVE_FULL);
}
// !!! We should only require a profile if we're using a filter which needs it
hr = pMux->QueryInterface(IID_IConfigAsfWriter, (void **) &pConfigAsfWriter);
if(SUCCEEDED(hr))
{
if (fVerbose)
printf("Setting profile to %d\r\n", dwProfile);
CComPtr<IWMProfile> pProfile;
hr = MapProfileIdToProfile(dwProfile, &pProfile);
if(FAILED(hr)) {
printf("Failed to map profile ID! hr=0x%x\n", hr);
return hr;
}
// Note that the ASF writer will not run if the number of streams
// does not match the profile.
hr = pConfigAsfWriter->ConfigureFilterUsingProfile(pProfile);
if(FAILED(hr)) {
printf("Failed to configure filter to use profile! hr=0x%x\n", hr);
return hr;
}
}
else
{
printf("Failed to QI for IConfigAsfWriter! hr=0x%x\n", hr);
return hr;
}
// Connect writer filter if needed
if(pWriter)
{
IPin *pMuxOut, *pWriterIn;
hr = pGraph->AddFilter(pWriter, L"Writer");
if(FAILED(hr))
{
printf("Failed to add FileWriter filter to graph! hr=0x%x\n", hr);
return hr;
}
// Look for the first unconnected output pin
hr = FindPinOnFilter(pMux, PINDIR_OUTPUT, 0, FALSE, &pMuxOut);
if(FAILED(hr))
{
printf("Failed to find output pin on Mux! hr=0x%x\n", hr);
return hr;
}
// Find the first connected pin
hr = FindPinOnFilter(pWriter, PINDIR_INPUT, 0, FALSE, &pWriterIn);
if(FAILED(hr))
{
printf("Failed to find input pin on FileWriter! hr=0x%x\n", hr);
pMuxOut->Release();
return hr;
}
hr = pGraph->ConnectDirect(pMuxOut, pWriterIn, NULL);
pMuxOut->Release();
pWriterIn->Release();
if(FAILED(hr))
{
printf("Failed to connect Mux to FileWriter! hr=0x%x\n", hr);
return hr;
}
if(fVerbose)
printf("Connected Mux and writer, hr = 0x%x\n", hr);
}
// Set sync source to NULL to speed processing
SetNoClock(pGraph);
// Render all source files listed on the command line
while(i < argc - 1)
{
MultiByteToWideChar(CP_ACP, 0, argv[i], -1,
SourceFile, 256);
printf("Copying %ls to %ls\n", SourceFile, TargetFile);
hr = pGraph->RenderFile(SourceFile, NULL);
if(FAILED(hr))
printf("Failed to render source file %s! hr=0x%x\n", argv[i], hr);
else if (fVerbose)
printf("RenderFile('%ls') returned hr=0x%x\n", SourceFile, hr);
++i;
}
// Run the graph
hr = pGraph->QueryInterface(IID_IMediaControl, (void **) &pGraphC);
if(FAILED(hr))
{
printf("Failed to QI for IMediaControl! hr=0x%x\n", hr);
return hr;
}
hr = pGraphC->Run();
if(FAILED(hr))
{
printf("Failed to run the graph! hr=0x%x\nCopy aborted.\n\n", hr);
printf("Please check that you have selected the correct profile for copying.\n"
"Note that if your source ASF file is audio-only, then selecting a\n"
"video profile will cause a failure when running the graph.\n\n");
ListProfiles();
}
else
{
WaitForCompletion(pGraph);
printf("Copy complete.\n");
// Stop the graph
hr = pGraphC->Stop();
}
return hr;
}
int __cdecl
main(
int argc,
char *argv[]
)
{
// Initialize COM
HRESULT hr = CoInitialize(NULL);
// Since COM smart pointers are used, the main functionality is wrapped
// in CopyASF(). When the function returns, the smart pointers will clean
// up properly, and then we'll uninitialize COM.
hr = CopyASF(argc, argv);
CoUninitialize();
return hr;
}