Created
May 26, 2021 08:56
-
-
Save LinArcX/b43ce8b1905b165de2314e6f9b202c8c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <DShow.h> | |
#include <qedit.h> | |
#include <stdio.h> | |
#include <wmcodecdsp.h> | |
#include "Module_i.h" | |
HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) | |
{ | |
const WCHAR wszStreamName[] = L"ActiveMovieGraph"; | |
HRESULT hr; | |
IStorage *pStorage = NULL; | |
// First, create a document file which will hold the GRF file | |
hr = StgCreateDocfile( | |
wszPath, | |
STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, | |
0, &pStorage); | |
if(FAILED(hr)) | |
{ | |
return hr; | |
} | |
// Next, create a stream to store. | |
IStream *pStream; | |
hr = pStorage->CreateStream( | |
wszStreamName, | |
STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, | |
0, 0, &pStream); | |
if (FAILED(hr)) | |
{ | |
pStorage->Release(); | |
return hr; | |
} | |
// The IPersistStream converts a stream into a persistent object. | |
IPersistStream *pPersist = NULL; | |
pGraph->QueryInterface(IID_IPersistStream, reinterpret_cast<void**>(&pPersist)); | |
hr = pPersist->Save(pStream, TRUE); | |
pStream->Release(); | |
pPersist->Release(); | |
if (SUCCEEDED(hr)) | |
{ | |
hr = pStorage->Commit(STGC_DEFAULT); | |
} | |
pStorage->Release(); | |
return hr; | |
} | |
HRESULT GetUnconnectedPin( | |
IBaseFilter *pFilter, // Pointer to the filter. | |
PIN_DIRECTION PinDir, // Direction of the pin to find. | |
IPin **ppPin) // Receives a pointer to the pin. | |
{ | |
*ppPin = 0; | |
IEnumPins *pEnum = 0; | |
IPin *pPin = 0; | |
HRESULT hr = pFilter->EnumPins(&pEnum); | |
if (FAILED(hr)) | |
{ | |
return hr; | |
} | |
while (pEnum->Next(1, &pPin, NULL) == S_OK) | |
{ | |
PIN_DIRECTION ThisPinDir; | |
pPin->QueryDirection(&ThisPinDir); | |
if (ThisPinDir == PinDir) | |
{ | |
IPin *pTmp = 0; | |
hr = pPin->ConnectedTo(&pTmp); | |
if (SUCCEEDED(hr)) // Already connected, not the pin we want. | |
{ | |
pTmp->Release(); | |
} | |
else // Unconnected, this is the pin we want. | |
{ | |
pEnum->Release(); | |
*ppPin = pPin; | |
return S_OK; | |
} | |
} | |
pPin->Release(); | |
} | |
pEnum->Release(); | |
// Did not find a matching pin. | |
return E_FAIL; | |
} | |
HRESULT ConnectFilters( | |
IGraphBuilder *pGraph, // Filter Graph Manager. | |
IPin *pOut, // Output pin on the upstream filter. | |
IBaseFilter *pDest) // Downstream filter. | |
{ | |
if ((pGraph == NULL) || (pOut == NULL) || (pDest == NULL)) | |
{ | |
return E_POINTER; | |
} | |
#ifdef debug | |
PIN_DIRECTION PinDir; | |
pOut->QueryDirection(&PinDir); | |
_ASSERTE(PinDir == PINDIR_OUTPUT); | |
#endif | |
// Find an input pin on the downstream filter. | |
IPin *pIn = 0; | |
HRESULT hr = GetUnconnectedPin(pDest, PINDIR_INPUT, &pIn); | |
if (FAILED(hr)) | |
{ | |
return hr; | |
} | |
// Try to connect them. | |
hr = pGraph->Connect(pOut, pIn); | |
pIn->Release(); | |
return hr; | |
} | |
HRESULT ConnectFilters(IGraphBuilder *pGraph, IBaseFilter *pSrc, IBaseFilter *pDest) | |
{ | |
if ((pGraph == NULL) || (pSrc == NULL) || (pDest == NULL)) | |
{ | |
return E_POINTER; | |
} | |
// Find an output pin on the first filter. | |
IPin *pOut = 0; | |
HRESULT hr = GetUnconnectedPin(pSrc, PINDIR_OUTPUT, &pOut); | |
if (FAILED(hr)) | |
{ | |
return hr; | |
} | |
hr = ConnectFilters(pGraph, pOut, pDest); | |
pOut->Release(); | |
return hr; | |
} | |
HRESULT GetVideoInputFilter(IBaseFilter** gottaFilter, int cam_id) | |
{ | |
// Create the System Device Enumerator. | |
HRESULT hr; | |
ICreateDevEnum *pSysDevEnum = NULL; | |
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, | |
IID_ICreateDevEnum, (void **)&pSysDevEnum); | |
if (FAILED(hr)) | |
{ | |
return hr; | |
} | |
// Obtain a class enumerator for the video compressor category. | |
IEnumMoniker *pEnumCat = NULL; | |
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); | |
int counter = 0; | |
if (hr == S_OK) | |
{ | |
// Enumerate the monikers. | |
IMoniker *pMoniker = NULL; | |
ULONG cFetched; | |
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) | |
{ | |
IPropertyBag *pPropBag; | |
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, | |
(void **)&pPropBag); | |
if (SUCCEEDED(hr)) | |
{ | |
// To retrieve the filter's friendly name, do the following: | |
VARIANT varName; | |
VariantInit(&varName); | |
hr = pPropBag->Read(L"FriendlyName", &varName, 0); | |
if (SUCCEEDED(hr)) | |
{ | |
// Display the name in your UI somehow. | |
} | |
VariantClear(&varName); | |
if(counter == cam_id){ | |
// To create an instance of the filter, do the following: | |
//IBaseFilter *pFilter; | |
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, | |
(void**) gottaFilter); | |
} | |
// Now add the filter to the graph. | |
//Remember to release pFilter later. | |
pPropBag->Release(); | |
counter++; | |
} | |
pMoniker->Release(); | |
} | |
pEnumCat->Release(); | |
} | |
pSysDevEnum->Release(); | |
} | |
HRESULT GetAudioInputFilter(IBaseFilter** gottaFilter, int mic_id) | |
{ | |
// Create the System Device Enumerator. | |
HRESULT hr; | |
ICreateDevEnum *pSysDevEnum = NULL; | |
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, | |
IID_ICreateDevEnum, (void **)&pSysDevEnum); | |
if (FAILED(hr)) | |
{ | |
return hr; | |
} | |
// Obtain a class enumerator for the audio input category. | |
IEnumMoniker *pEnumCat = NULL; | |
hr = pSysDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEnumCat, 0); | |
int counter = 0; | |
if (hr == S_OK) | |
{ | |
// Enumerate the monikers. | |
IMoniker *pMoniker = NULL; | |
ULONG cFetched; | |
while ((pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)) | |
{ | |
// Bind the first moniker to an object | |
IPropertyBag *pPropBag; | |
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, | |
(void **)&pPropBag); | |
if (SUCCEEDED(hr)) | |
{ | |
// To retrieve the filter's friendly name, do the following: | |
VARIANT varName; | |
VariantInit(&varName); | |
hr = pPropBag->Read(L"FriendlyName", &varName, 0); | |
VariantClear(&varName); | |
if(counter == mic_id){ | |
// To create an instance of the filter, do the following: | |
//IBaseFilter *pFilter; | |
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, | |
(void**) gottaFilter); | |
} | |
pPropBag->Release(); | |
counter++; | |
} | |
pMoniker->Release(); | |
} | |
pEnumCat->Release(); | |
} | |
pSysDevEnum->Release(); | |
} | |
int main(int argc, char** argv) | |
{ | |
// 0. Initialize | |
// 1. Create AudioCaptureFilter | |
// 2. Create VideoCaptureFilter | |
// 3. Create AudioSampleGrabber | |
// 4. Create VideoSampleGrabber | |
// 5. Create MPEG-2 Encoder | |
// 6. Create FileWriter | |
// 0 Initialize | |
HRESULT hr = 0; | |
IGraphBuilder *pGraph = NULL; | |
IMediaControl *pMediaControl = NULL; | |
IMediaEventEx *pMediaEvent = NULL; | |
// | |
IBaseFilter *pMyAudioCaptureFilter = NULL; | |
IBaseFilter *pAudioGrabber = NULL; | |
ISampleGrabber *pAudioSampleGrabber = NULL; | |
IBaseFilter *pMyVideoCaptureFilter = NULL; | |
IBaseFilter *pVideoGrabber = NULL; | |
ISampleGrabber *pVideoSampleGrabber = NULL; | |
// | |
IBaseFilter *pMpeg2Encoder = NULL; | |
IBaseFilter *pMpeg4Encoder = NULL; | |
IBaseFilter *pBaseWriter = NULL; | |
IFileSinkFilter *pFileSinkWriter = NULL; | |
hr = CoInitialize(NULL); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to initialize COM! hr=0x%x\n", hr); | |
return hr; | |
} | |
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&pGraph)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to create FilterGraph! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pMediaControl)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to find pMediaControl! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pMediaEvent)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to find pMediaEvent! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
// 1. Create VideoCaptureFilter | |
hr = GetAudioInputFilter(&pMyAudioCaptureFilter, 0); | |
if (SUCCEEDED(hr)) { | |
hr = pGraph->AddFilter(pMyAudioCaptureFilter, L"Microphone"); | |
} | |
// 2. Create VideoCaptureFilter | |
hr = GetVideoInputFilter(&pMyVideoCaptureFilter, 0); | |
if (SUCCEEDED(hr)) { | |
hr = pGraph->AddFilter(pMyVideoCaptureFilter, L"Webcam"); | |
} | |
// 3. Create AudioSampleGrabber | |
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pAudioGrabber)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to create pAudioGrabber! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = pAudioGrabber->QueryInterface(IID_PPV_ARGS(&pAudioSampleGrabber)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to find pAudioSampleGrabber! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
// 4. Create VideoSampleGrabber | |
hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pVideoGrabber)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to create pVideoGrabber! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = pVideoGrabber->QueryInterface(IID_PPV_ARGS(&pVideoSampleGrabber)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to find pVideoSampleGrabber! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
// Set the Video Type | |
AM_MEDIA_TYPE audio_media_type; | |
ZeroMemory(&audio_media_type, sizeof(audio_media_type)); | |
audio_media_type.majortype = MEDIATYPE_Audio; | |
//audio_media_type.subtype = MEDIASUBTYPE_RGB24; | |
hr = pAudioSampleGrabber->SetMediaType(&audio_media_type); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to SetMediaType for pAudioSampleGrabber! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = pGraph->AddFilter(pAudioGrabber, L"Audio Grabber"); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to add pAudioSampleGrabber to GraphBuilder! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
// Set the Video Type | |
AM_MEDIA_TYPE mt; | |
ZeroMemory(&mt, sizeof(mt)); | |
mt.majortype = MEDIATYPE_Video; | |
mt.subtype = MEDIASUBTYPE_RGB24; | |
hr = pVideoSampleGrabber->SetMediaType(&mt); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to SetMediaType for SampleGrabber! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = pGraph->AddFilter(pVideoGrabber, L"Video Grabber"); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to add pVideoGrabber to GraphBuilder! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
// 5. Create MPEG-2 Encoder | |
hr = CoCreateInstance(CLSID_CMPEG2EncoderDS, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pMpeg2Encoder)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to create pMpeg2Encoder! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = pGraph->AddFilter(pMpeg2Encoder, L"MPEG-2 Encoder"); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to add pMpeg2Encoder to GraphBuilder! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
// 5. Create MPEG-4 Encoder | |
hr = CoCreateInstance(CLSID_MuxFilter, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pMpeg4Encoder)); | |
// 6. Create FileWriter | |
//hr = AddFilterByCLSID(pGraph, CLSID_FileWriter, L"File Writer", &pWriter); | |
hr = CoCreateInstance(CLSID_FileWriter, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pBaseWriter)); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to create pFileWriter! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
// Set the file name. | |
hr = pBaseWriter->QueryInterface(IID_IFileSinkFilter, (void**)&pFileSinkWriter); | |
hr = pFileSinkWriter->SetFileName(L"C:\\test.mpeg2", NULL); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to SetFileName! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = pGraph->AddFilter(pBaseWriter, L"File Writer"); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to add pFileWriter to GraphBuilder! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
//*** Connect Filters ***// | |
hr = ConnectFilters(pGraph, pMyAudioCaptureFilter, pAudioGrabber); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to Connect pMyAudioCaptureFilter with pAudioGrabber! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = ConnectFilters(pGraph, pMyVideoCaptureFilter, pVideoGrabber); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to Connect pMyVideoCaptureFilter with pVideoGrabber! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = ConnectFilters(pGraph, pAudioGrabber, pMpeg2Encoder); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to Connect pAudioGrabberF with pMpeg2Encoder! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = ConnectFilters(pGraph, pVideoGrabber, pMpeg2Encoder); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to Connect pGrabberF with pMpeg2Encoder! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
hr = ConnectFilters(pGraph, pMpeg2Encoder, pBaseWriter); | |
if (FAILED(hr)) | |
{ | |
printf("Failed to Connect pMpeg2Encoder with pBaseWriter! hr=0x%x\n", hr); | |
goto EXIT; | |
} | |
pMediaControl->Run(); | |
Sleep(5000); | |
pMediaControl->Stop(); | |
SaveGraphFile(pGraph, L"C:\\MyGraph.GRF"); | |
EXIT: | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment