Skip to content

Instantly share code, notes, and snippets.

@LinArcX
Created May 26, 2021 08:56
Show Gist options
  • Save LinArcX/b43ce8b1905b165de2314e6f9b202c8c to your computer and use it in GitHub Desktop.
Save LinArcX/b43ce8b1905b165de2314e6f9b202c8c to your computer and use it in GitHub Desktop.
#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