views:

387

answers:

3

I know there is a question similar to mine: http://stackoverflow.com/questions/1010937/extract-wav-file-from-video-file

I am new to C++ and understand about COM library + directX is needed for video and audio. I been looking for tutorial and samples code but little success.

My question is how do I code the application to take video file (any type) and saved the extracted audio as .wav in my application rather than using other applications such as graphedit or virtualdub?

+4  A: 

Can't you use something like ffmpeg, or one of the libraries it uses? Or maybe mencoder, which can do the same. Both of them have a command line interface as far as I know, and they might have some API as well...

Ruben
A: 

You can use Directshow filters to construct a graph that will save the audio as .wav.

The interfaces that you need to use are: (Note: This solution will extract audio from avi files)

IGraphBuilder: This will be used to build graph.

IBaseFilter: This will be the filters that you initialize to make part of the graph

To initialize graph you do:

IGraphBuilder *pGraph = NULL;
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph)

CLSID_FilterGraph is defined in uuids.h which is part of PaltformSDK.

Once the graph is initialized, you will need to initialize 3 filters that will be added in the graph.

  1. AVI Multiplexer: CLSID_AviDest
  2. File Writer: CLSID_FileWriter.
  3. Null renderer: CLSID_NullRenderer

You can initialize filters by:

IBaseFilter *pF = NULL;
CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER,  IID_IBaseFilter, (void**)&pF);
clsid = clsid of the filter

And add the filter in graph using:

pGraph->AddFilter(pF, name)
name = name of the filter. Can be 'AVI Mux' etc

Once you initialize 'File writer' filter you will need to set the path where you wish to write the file. You can do that:

IFileSinkFilter* pFileSink=NULL;
 fileWriterFilter->QueryInterface(IID_IFileSinkFilter, (void**)&pFileSink);
pFileSink->SetFileName(filepath, NULL);


Here: fileWriter = file writer filter instance.

Make sure that the extension of file name is .wav

Once you added the filters in graph, you will need to render the video file like:

pGraph->RenderFile(sourcePath, NULL);

Once rendered, you will now need to Run this graph. You can do this by querying couple of interfaces from the graph:

IMediaControl Used to run the filter

and IMediaEvent Used to get events from graph.

Query the interface:

pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
and pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

Run the graph:

pControl->Run();

And wait for the rendering for completion:

pEvent->WaitForCompletion(INFINITE, &evCode);

Once done, you will find a file having audio in .wav format.

I have tested this through graphedit and it works. I hope this will help.

cornerback84
A: 

I'll second the motion to just use a build of ffmpeg to perform the audio extraction. It can be done in one easy command as opposed to most likely hundreds of lines of code (If your going to check for all of the possible problems that could happen when dealing with different video formats and codecs).

ffmpeg -i video.avi -vn soundfile.wav

You could use libavformat and libavformat(libraries behind ffmpeg) to do the same thing, but unless you need to do some processing on the raw audio before outputting to wav, there would be nothing to gain except for knowledge.

ffmpeg is nice because the executable contains all of the audio and video decoders you'll probably ever need so the solution is highly portable. You don't have it install codecs or anything. The input video file can be in any format or codec that ffmpeg supports and you don't have to bother with treating them differently in your code.

From C++ you can call ffmpeg by building the command line string in your code and kicking off the process from your code (being new the C++, you'll probably need to research how to do this, but it's pretty easy).

Jason
Thank you for the answer and clear explanation. I downloaded ffmpeg but found the wiki on the site for building ffmpeg is confusing and not updated. Not sure which type of library to build as (static or dll) but I assume it will be static if I am going to include the library in my application to be release to other people?
John Meyers
You can get win32 binaries for ffmpeg here: http://ffmpeg.arrozcru.org/builds/ so you don't have to build it yourself. Just download the latest win32 binary package (ffmpeg-r16537-gpl-static-win32.tar.bz2) and it will contain "ffmpeg.exe" in the bin directory. Since it is a static build, all you need is the exe file. Building ffmpeg on a li/unix system is a piece of cake, but on Windows it is more difficult because you can't build it with Visual Studio's compiler so you have to use mingw. I would just go with the pre-built binary.
Jason