Link to home
Start Free TrialLog in
Avatar of CongUan
CongUan

asked on

Record avi with sound

Hi Experts,
I have record a video file(avi) and audio file(wav) as separate files, now I want to combine these into a avi file that can play with video and audio.

Please help me with this.

Thank in advance!
Avatar of Dariusz Dziara
Dariusz Dziara
Flag of Poland image

You can use graph editor from DirectX SDK and mount DirectShow graph with two input streams - video & audio using AVI Mux filter.
Or you could build own, more sophisticated application based od DirectShow.
Or maybe locate some shareware in Internet.
Avatar of CongUan
CongUan

ASKER

I had not used DirectShow, Please help me for some link or example code about this.

Thanks agian!
Here sample how to join AVI with WAVE (add strmiids.lib to link list):

You can also start Graph Editor & connect to created graph:
File->Connect to Remote Graph...

// TEST_EE_AVIwSound.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <dshow.h>
#include <comdef.h>
#include <initguid.h>

_COM_SMARTPTR_TYPEDEF(IGraphBuilder, IID_IGraphBuilder);
_COM_SMARTPTR_TYPEDEF(ICaptureGraphBuilder2, IID_ICaptureGraphBuilder2);
_COM_SMARTPTR_TYPEDEF(IMediaControl, IID_IMediaControl);
_COM_SMARTPTR_TYPEDEF(IMediaEvent, IID_IMediaEvent);
_COM_SMARTPTR_TYPEDEF(IBaseFilter, IID_IBaseFilter);
_COM_SMARTPTR_TYPEDEF(IFileSinkFilter2, IID_IFileSinkFilter2);

DEFINE_GUID(CLSID_WAVEParser,
0xD51BD5A1, 0x7548, 0x11CF, 0xA5, 0x20, 0x00, 0x80, 0xC7, 0x7E, 0xF5, 0x8A);


HRESULT AddToRot(IUnknownPtr pUnkGraph, DWORD *pdwRegister)
{
    IMonikerPtr pMoniker;
    IRunningObjectTablePtr pROT;

    if(FAILED(GetRunningObjectTable(0, &pROT))) return E_FAIL;

    WCHAR wsz[256];
    wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
    HRESULT hRes = CreateItemMoniker(L"!", wsz, &pMoniker);

    if(SUCCEEDED(hRes)) {
        hRes = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph, pMoniker, pdwRegister);
    }

    return hRes;
}

void RemoveFromRot(DWORD pdwRegister)
{
    IRunningObjectTablePtr pROT;

    if(SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
        pROT->Revoke(pdwRegister);
    };
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
      HRESULT hRes;

       hRes = CoInitialize(NULL);

      if(SUCCEEDED(hRes)) {
            IGraphBuilderPtr pGraph;

            hRes = pGraph.CreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);

            if(SUCCEEDED(hRes)) {
                  DWORD dwRegister;
                  ICaptureGraphBuilder2Ptr pICaptureGraphBuilder2;

                  hRes = AddToRot(pGraph, &dwRegister);

                  hRes = pICaptureGraphBuilder2.CreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER);

                  if(SUCCEEDED(hRes)) {
                        IMediaControlPtr pControl;
                        IMediaEventPtr pEvent;
                        IBaseFilterPtr pAVISource, pWAVESource, pAVISplitter, pWAVEParser, pAVIMux, pFileWriter;
                        IFileSinkFilter2Ptr pIFileSinkFilter2;

                        pICaptureGraphBuilder2->SetFiltergraph(pGraph);
                        hRes = pGraph.QueryInterface(IID_IMediaControl, &pControl);
                        hRes = pGraph.QueryInterface(IID_IMediaEvent, &pEvent);

                        hRes = pGraph->AddSourceFilter(L"C:\\DXSDK9\\Samples\\Media\\highway.avi", L"AVI File", &pAVISource);
                        hRes = pGraph->AddSourceFilter(L"C:\\DXSDK9\\Samples\\Media\\audiopath3.wav", L"WAVE File", &pWAVESource);

                        hRes = pAVISplitter.CreateInstance(CLSID_AviSplitter, NULL, CLSCTX_INPROC_SERVER);
                        hRes = pGraph->AddFilter(pAVISplitter, L"AVI Splitter");

                        hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pAVISource, NULL, pAVISplitter);

                        hRes = pWAVEParser.CreateInstance(CLSID_WAVEParser, NULL, CLSCTX_INPROC_SERVER);
                        hRes = pGraph->AddFilter(pWAVEParser, L"WAVE Parser");

                        hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pWAVESource, NULL, pWAVEParser);

                        hRes = pAVIMux.CreateInstance(CLSID_AviDest, NULL, CLSCTX_INPROC_SERVER);
                        hRes = pGraph->AddFilter(pAVIMux, L"AVI Mux");

                        hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pAVISplitter, NULL, pAVIMux);
                        hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pWAVEParser, NULL, pAVIMux);

                        hRes = pFileWriter.CreateInstance(CLSID_FileWriter, NULL, CLSCTX_INPROC_SERVER);
                        hRes = pGraph->AddFilter(pFileWriter, L"File Writer");

                        hRes = pFileWriter.QueryInterface(IID_IFileSinkFilter2, &pIFileSinkFilter2);
                        hRes = pIFileSinkFilter2->SetFileName(L"c:\\result.avi", NULL);

                        hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pAVIMux, NULL, pFileWriter);

                        hRes = MessageBox(NULL, TEXT("Test"), TEXT("Check #1"), MB_OK);

                        hRes = pControl->Run();

                        long evCode = 0;
                        pEvent->WaitForCompletion(INFINITE, &evCode);
                  };


                  RemoveFromRot(dwRegister);
            };

            CoUninitialize();
      };

      return 0;
}





Avatar of CongUan

ASKER

I tested this, it work but the sound some time interrupted (not the same original sound)
Do you have any suggestion for this?

For more question, if the lenght of wav file is not the same the length of AVIs file (for example: wav: 24s AVis: 25s)then what happent with final avi file?

Many thank again!
Avatar of CongUan

ASKER

Hi mrblue,
How can I set the param with my source file with the follow comment

Instead of harding-code as L"C:\\DXSDK9\\Samples\\Media\\highway.avi" I want to send my param source file to this,
so, How can I do this, I used WCHAR* but it is not work.

I want to write a function as AddWavToAVI(const WCHAR* wavFile, const WCHAR* aviFile, const WCHAR* rsAVIFile)
But when I used
hRes = pGraph->AddSourceFilter(aviFile, L"AVI File", &pAVISource);
hRes = pGraph->AddSourceFilter(wavFile, L"WAVE File", &pWAVESource);
and
hRes = pIFileSinkFilter2->SetFileName(rsAVIFile, NULL);

I don't see any result for this, it seem to can not write.

Please give me more suggestion

Tx,
"I tested this, it work but the sound some time interrupted (not the same original sound)
Do you have any suggestion for this?"

Try this (add pointed code):

_COM_SMARTPTR_TYPEDEF(IFileSinkFilter2, IID_IFileSinkFilter2);
_COM_SMARTPTR_TYPEDEF(IConfigAviMux, IID_IConfigAviMux);    // <---

IFileSinkFilter2Ptr pIFileSinkFilter2;
IConfigAviMuxPtr pIConfigAviMux;        // <---

hRes = pAVIMux.CreateInstance(CLSID_AviDest, NULL, CLSCTX_INPROC_SERVER);
hRes = pGraph->AddFilter(pAVIMux, L"AVI Mux");

"For more question, if the lenght of wav file is not the same the length of AVIs file (for example: wav: 24s AVis: 25s)then what happent with final avi file?"

If I remember well:
1.If video is longer the rest of movie will be without sound
2.If sound is longer the last frame will be "repeated" (actually shown longer)


hRes = pAVIMux.QueryInterface(IID_IConfigAviMux, &pIConfigAviMux); // <---
hRes = pIConfigAviMux->SetMasterStream(1);  // <---

It simply selects master (more important) stream for synchronization.

In your case it should be:
-1 - none is master
0 - video
1 - sound

From Doc:
"It is recomended to use the audio stream as the master stream, because minor adjustment to the video playback rate are less noticable than changes to the audio playback rate"


I have used literally the following code and it works:

============
#include "stdafx.h"
#include <dshow.h>
#include <comdef.h>
#include <initguid.h>

_COM_SMARTPTR_TYPEDEF(IGraphBuilder, IID_IGraphBuilder);
_COM_SMARTPTR_TYPEDEF(ICaptureGraphBuilder2, IID_ICaptureGraphBuilder2);
_COM_SMARTPTR_TYPEDEF(IMediaControl, IID_IMediaControl);
_COM_SMARTPTR_TYPEDEF(IMediaEvent, IID_IMediaEvent);
_COM_SMARTPTR_TYPEDEF(IBaseFilter, IID_IBaseFilter);
_COM_SMARTPTR_TYPEDEF(IFileSinkFilter2, IID_IFileSinkFilter2);
_COM_SMARTPTR_TYPEDEF(IConfigAviMux, IID_IConfigAviMux);

DEFINE_GUID(CLSID_WAVEParser,
0xD51BD5A1, 0x7548, 0x11CF, 0xA5, 0x20, 0x00, 0x80, 0xC7, 0x7E, 0xF5, 0x8A);


HRESULT AddToRot(IUnknownPtr pUnkGraph, DWORD *pdwRegister)
{
    IMonikerPtr pMoniker;
    IRunningObjectTablePtr pROT;

    if(FAILED(GetRunningObjectTable(0, &pROT))) return E_FAIL;

    WCHAR wsz[256];
    wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
    HRESULT hRes = CreateItemMoniker(L"!", wsz, &pMoniker);

    if(SUCCEEDED(hRes)) {
        hRes = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph, pMoniker, pdwRegister);
    }

    return hRes;
}

void RemoveFromRot(DWORD pdwRegister)
{
    IRunningObjectTablePtr pROT;

    if(SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
        pROT->Revoke(pdwRegister);
    };
}

VOID AddWavToAVI(const WCHAR *wavFile, const WCHAR *aviFile, const WCHAR *rsAVIFile)
{
      HRESULT hRes;
      IGraphBuilderPtr pGraph;

      hRes = pGraph.CreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);

      if(SUCCEEDED(hRes)) {
            DWORD dwRegister;
            ICaptureGraphBuilder2Ptr pICaptureGraphBuilder2;

            hRes = AddToRot(pGraph, &dwRegister);

            hRes = pICaptureGraphBuilder2.CreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER);

            if(SUCCEEDED(hRes)) {
                  IMediaControlPtr pControl;
                  IMediaEventPtr pEvent;
                  IBaseFilterPtr pAVISource, pWAVESource, pAVISplitter, pWAVEParser, pAVIMux, pFileWriter;
                  IFileSinkFilter2Ptr pIFileSinkFilter2;
                  IConfigAviMuxPtr pIConfigAviMux;

                  pICaptureGraphBuilder2->SetFiltergraph(pGraph);
                  hRes = pGraph.QueryInterface(IID_IMediaControl, &pControl);
                  hRes = pGraph.QueryInterface(IID_IMediaEvent, &pEvent);

                  hRes = pGraph->AddSourceFilter(aviFile, L"AVI File", &pAVISource);
                  hRes = pGraph->AddSourceFilter(wavFile, L"WAVE File", &pWAVESource);

                  hRes = pAVISplitter.CreateInstance(CLSID_AviSplitter, NULL, CLSCTX_INPROC_SERVER);
                  hRes = pGraph->AddFilter(pAVISplitter, L"AVI Splitter");

                  hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pAVISource, NULL, pAVISplitter);

                  hRes = pWAVEParser.CreateInstance(CLSID_WAVEParser, NULL, CLSCTX_INPROC_SERVER);
                  hRes = pGraph->AddFilter(pWAVEParser, L"WAVE Parser");

                  hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pWAVESource, NULL, pWAVEParser);

                  hRes = pAVIMux.CreateInstance(CLSID_AviDest, NULL, CLSCTX_INPROC_SERVER);
                  hRes = pGraph->AddFilter(pAVIMux, L"AVI Mux");


                  hRes = pAVIMux.QueryInterface(IID_IConfigAviMux, &pIConfigAviMux);
                  hRes = pIConfigAviMux->SetMasterStream(1);


                  hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pAVISplitter, NULL, pAVIMux);
                  hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pWAVEParser, NULL, pAVIMux);

                  hRes = pFileWriter.CreateInstance(CLSID_FileWriter, NULL, CLSCTX_INPROC_SERVER);
                  hRes = pGraph->AddFilter(pFileWriter, L"File Writer");

                  hRes = pFileWriter.QueryInterface(IID_IFileSinkFilter2, &pIFileSinkFilter2);
                  hRes = pIFileSinkFilter2->SetFileName(rsAVIFile, NULL);

                  hRes = pICaptureGraphBuilder2->RenderStream(NULL, NULL, pAVIMux, NULL, pFileWriter);

                  hRes = MessageBox(NULL, TEXT("Test"), TEXT("Check #1"), MB_OK);

                  hRes = pControl->Run();

                  long evCode = 0;
                  pEvent->WaitForCompletion(INFINITE, &evCode);
            };

            RemoveFromRot(dwRegister);
      };
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
      HRESULT hRes;

       hRes = CoInitialize(NULL);

      if(SUCCEEDED(hRes)) {
            AddWavToAVI(L"C:\\DXSDK9\\Samples\\Media\\audiopath3.wav", L"C:\\DXSDK9\\Samples\\Media\\highway.avi", L"c:\\result.avi");
            CoUninitialize();
      };

      return 0;
}
Avatar of CongUan

ASKER

Thank you very much for your help.
I resolved my problem.
AddWavToAVI(L"C:\\DXSDK9\\Samples\\Media\\audiopath3.wav", L"C:\\DXSDK9\\Samples\\Media\\highway.avi", L"c:\\result.avi");
This is still a hard-code, I try to write a function to convert a char* to WCHAR*
It work now.

Thank you again.

ASKER CERTIFIED SOLUTION
Avatar of Dariusz Dziara
Dariusz Dziara
Flag of Poland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of CongUan

ASKER

Yah, Many thank again, I used this with im my code before!