Take the 2-minute tour ×

Basiclly, I want to capture audio/video. Run it through a mp4 muxer and save it to a file on disk. Before I used ICaptureGraphBuilder2, but it seems unusuable when saving to custom formats.

My code so far,

I enumerate video/audio devices. In this sample I only try to capture audio. I get the correct device and use GetPin to enumerate the filters pins to get its output pin.

hr = pMoniker2->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc2);
hr = pGraph->AddFilter(pSrc2, L"AudioCap");

hr = GetPin(pSrc2, PINDIR_OUTPUT, &outPin);

This is the custom filter, a MP4 muxer. It properly loads and I can get the input pin and connect it with my output pin. So far so good.

HRESULT hr = CreateObjectFromPath(TEXT("c:\\filters\\mp4mux.dll"), clsid, &pUnk);
if (SUCCEEDED(hr))
    IBaseFilterPtr pFilter = pUnk;
    HRESULT hr = pGraph->AddFilter(pFilter, L"Private Filter");
    hr = GetPin(pFilter, PINDIR_INPUT, &inPin);

hr = pGraph->Connect(outPin, inPin);

This is where I get lost, I can't find out how to take the next steps to Render and save the output to a file on disk. So any help with the next steps would be greatfully appreciated, thanks in advance!

EDIT: Filesink code


mType.majortype = MEDIATYPE_Video;
mType.subtype = MEDIASUBTYPE_H264;
mType.bFixedSizeSamples = FALSE;
mType.bTemporalCompression = TRUE;
mType.lSampleSize = 0;
mType.formattype = FORMAT_None;
mType.pUnk = NULL;
mType.cbFormat = 0;
mType.pbFormat = NULL;
//Not 100% sure about the setup of the media format.

IBaseFilter * iFiltera = NULL; 
IFileSinkFilter* iFilter = NULL; 
IGraphBuilder *pGraph;

hr = pMoniker2->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc2); //audio capture
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,  IID_IGraphBuilder, (void**)&pGraph);
hr = CoCreateInstance(CLSID_FileWriter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&iFiltera);

hr = pBuild->SetFiltergraph(pGraph);

hr = GetPin(pSrc2, PINDIR_OUTPUT, &outPin); //ADDED

hr = pGraph->AddFilter(iFiltera, L"FileWriter");
hr = iFiltera->QueryInterface(IID_IFileSinkFilter, (void**)&iFilter);

iFilter->SetFileName((LPCOLESTR)"c:\\wav\\tester.mp4", NULL); //UPDATED mType set to NULL


IBaseFilterPtr pFilter = pUnk;
if (SUCCEEDED(hr))

    hr = GetPin(pFilter, PINDIR_INPUT, &inPin); //mux in

    hr = GetPin(pFilter, PINDIR_OUTPUT, &mOutPin); //mux out
    hr = GetPin(iFiltera, PINDIR_INPUT, &filePin); // filewriter in

hr = pGraph->Connect(outPin, inPin); //connect audio out and mux in
hr = pGraph->Connect(mOutPin, filePin); //connect mux out and file in; Error 0x80040217(VFW_E_CANNOT_CONNECT?) //works now

//ADDED code
IMediaControl *pMC = NULL;
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pMC);

hr = pMC->Run();
hr = pMC->Stop();  
share|improve this question

1 Answer 1

up vote 0 down vote accepted

You need to have an idea what filter graph topology you need for specific task. You are doing capture, here - fine. So you have audio capture filter you provided code snippet for. Then you either compress audio (where your preferred choice should be AAC AKA MPEG-4 Part 3, provided that you are to produce MP4 file), or keep audio uncompressed PCM. Then you connect MPEG-4 multiplexer as you do. The multiplexer produces output stream and you are expected to complete the pipeline with File Writer Filter.

You can manually build the chain in GraphEdit SDK application (or there are alternate richer tools). Your filter graph looks like this:

Filter Graph

Note that you can expose filter graph in your application, and connect to it remotely and inspect the topology. This makes debugging much easier. Starting/stopping the filter graph (IMediaControl::Run, ::Stop from code) creates you the file.

My understanding is that you get lost immediately after adding multiplexer. Now you need to find its output pin, add File Writer, query its IFileSinkFilter, set the destination file name using it, find its input pin, connect the two unconnected pins (mux output, writer input). Your pipeline is ready to run.

share|improve this answer
If im understanding this right. Connect microphone outpin to MP4 multiplexer inpin. If thats right then im on the right way. Then im stuck. So I'm supposed to create a filesink, find the input pin and connect it to the MP4 multiplexer output? Then everything is set and I just use mediacontrols on my filtergraph as before with start stop? If I'm right and if you dont mind me asking, do you have a suggestion for finding pins of a IFileSinkFilter? Also thanks a lot for that picture, it made everything a lot clearer i believe :) –  Erik Swansson Jun 26 '12 at 17:56
Temp.mp4 on my screenshot is File Writer which has both IBaseFilter and IFileSinkFilter. That is you add it connect its pin to the input, set file name and you are good to go. –  Roman R. Jun 26 '12 at 18:44
Please forgive my inexperience with COM and Directshow. I'm not 100% sure about how to implement a Filewriter with both filters. I added some code to my post that does what I think you meant, however it fails at connecting the filewriter input with the mpeg4mux output. If you can take a look at it whenever you have time and point out what I'm doing wrong id be very thankful. –  Erik Swansson Jun 27 '12 at 7:35
Your code is about right. There is no need for media type in SetFileName call, and after all you provide video media type there while your question is about recording audio. Is there any hr error on the way? Consider using smart pointers CComPtr for better reference management and readability of code. –  Roman R. Jun 27 '12 at 21:38
Ok, good and bad news. It seems you were right about the media type, if I set it to NULL everything seems to run fine even if i change capture source to video. But in both cases even though there are no errors there is no output file created. I put if(FAILED(hr)){printf("error");} after every call but no errors pops. Could it be the media type? Any ideas? I also updated the changes and added the last part of my code with the media control in case i messed that up somehow. Again, thanks for your persistance and patience. –  Erik Swansson Jun 28 '12 at 10:12

Your Answer


