Infognition forum
February 05, 2012, 08:43:03 AM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
News: Last GraphEditPlus version: 1.4.0   Last Video Enhancer version: 1.9.7
 
   Home   Help Search Login Register  
Pages: [1]
  Print  
Author Topic: How to build generated code  (Read 1456 times)
Dee Mon
Administrator
Hero Member
*****

Karma: +8/-0
Posts: 511



View Profile WWW
« on: May 26, 2010, 02:25:16 PM »

A couple of short tutorials on how to build generated C++ code in Visual Studio:
http://www.infognition.com/blog/2010/directshow_in_vs2005.html
http://www.infognition.com/blog/2010/directshow_in_vs6.html

For VS2008 and 2010 I guess it's the same as for VS2005.
Logged
MicoMaco
Newbie
*

Karma: +1/-0
Posts: 15


View Profile
« Reply #1 on: October 03, 2010, 03:08:18 PM »

I managed to create a working console app like in tutorial for vs6 (needed 2 days to get it done with VS2010, gui not the same Sad ), but this works only for the one file, the file that is specified in the code. How do we create a win32 console app that uses any file we want for input and outputs the result? For example the way eac3to works: eac3to.exe input.wav output.mp3.

Regards, MicoMaco
Logged
Dee Mon
Administrator
Hero Member
*****

Karma: +8/-0
Posts: 511



View Profile WWW
« Reply #2 on: October 03, 2010, 06:04:01 PM »

The main() function has argc and argv arguments - number of command line parameters and their contents. Use them instead of string constants when specifying filenames. If you build a non-unicode app you'll need to convert them from ANSI to Unicode. See MultiByteToWideChar in MSDN.
Logged
MicoMaco
Newbie
*

Karma: +1/-0
Posts: 15


View Profile
« Reply #3 on: October 03, 2010, 06:24:03 PM »

I created this short video tutorial for VS2010 based on your's for VS2006 (http://www.youtube.com/watch?v=qmx-abUEbAk). I'll try to "decode" what you meant later Wink .

Thx for the advice tho!
Logged
MicoMaco
Newbie
*

Karma: +1/-0
Posts: 15


View Profile
« Reply #4 on: October 10, 2010, 09:20:04 PM »

Unfortunately I was unable to quickly (few days) learn specifying filenames with argc, argv arguments in c++. There are no straightforward and easy enough tutorials for the case I was previously mentioning. I guess I should be learning the whole c++ code but I don't have time for that. I'll stick with string constants and changing names each time I'd execute the compiled code.
Logged
MicoMaco
Newbie
*

Karma: +1/-0
Posts: 15


View Profile
« Reply #5 on: October 11, 2010, 07:30:17 PM »

I just tried this "change name of file" method and I was very surprised that it doesn't work. When I run the compiled program which should play the song it plays back the same song no matter what I do with the original file (rename it, delete it completely, use same name for a different audio). Maybe I should start learning c++ Sad. If it's not a big problem for you, would you be so kind to make a template code which will take arguments from console in this order: graph.exe input output (graph.exe being the compiled code, input being the full name of the input file, output being the full name of the output file).  I'd just need that part when you put argc and argv arguments inside the code to specify argv[1] as input and argv[2] as output.
Logged
Dee Mon
Administrator
Hero Member
*****

Karma: +8/-0
Posts: 511



View Profile WWW
« Reply #6 on: October 12, 2010, 06:39:05 AM »

Here's a sample, a program I made recently to grab pictures from video:
http://stuff.thedeemon.com/grab.cpp
It takes filenames as well as frame number and coordinates from command line arguments.
The interesting part for you is this:
Code:
int main(int argc, char* argv[])
{
    if (argc<6) { //check number of arguments, print message if there are not enough
        printf("usage: grab video.avi video.bmp frame_number X Y\n");
        return 0;
    }
    unsigned short fname[1024]={0}; //buffer for Unicode string with filename
    MultiByteToWideChar(CP_ACP, 0, argv[1], strlen(argv[1]), fname, 1020); //convert ANSI to Unicode

    CoInitialize(NULL);
    CComPtr<IGraphBuilder> graph;
    graph.CoCreateInstance(CLSID_FilterGraph);

    printf("Building graph...\n");
    HRESULT hr = BuildGraph(graph, fname, argv[2], atoi(argv[3]), atoi(argv[4]), atoi(argv[5]));
    ...

where BuildGraph has following type:
Code:
HRESULT BuildGraph(IGraphBuilder *pGraph, LPCOLESTR srcFile1, const char *outfile, int fn, int sx, int sy)

Quote
Maybe I should start learning c++
That's definitely the case. Or you can start with C#, it's much simpler and more convenient to develop with (IDE support is better).
Logged
MicoMaco
Newbie
*

Karma: +1/-0
Posts: 15


View Profile
« Reply #7 on: October 13, 2010, 12:23:06 PM »

At first I was extremely happy when saw your suggested code; thought of it that this is a done deal for me. However being a newbie in any coding, in this case c++, I just can't get this code going. I'm working with VS2010 which helps a lot with intuitive suggestions and extensive error and warning messages but it seems that's not enough. I will have to go deeper and try harder with c++. Thx a lot anyway!!! I'm guessing that certain parameters in this "int main" part must also be defined and somehow introduced before it.
Logged
MicoMaco
Newbie
*

Karma: +1/-0
Posts: 15


View Profile
« Reply #8 on: October 15, 2010, 11:47:20 PM »

OK, this is the C++ code I believe when compiled should play back an mp3 file (since it's not working the most probable reason for that might be that I made a cardinal mistake):
Code:
//Don't forget to change project settings:
//1. C++: add include path to DirectShow include folder (such as c:\dxsdk\include)
//2. Link: add link path to DirectShow lib folder (such as c:\dxsdk\lib).
//3. Link: add strmiids.lib and quartz.lib

#include "stdafx.h"
#include <DShow.h>
#include <atlbase.h>
#include <initguid.h>
#include <dvdmedia.h>

BOOL hrcheck(HRESULT hr, char* errtext)
{
    if (hr >= S_OK)
        return FALSE;
    TCHAR szErr[MAX_ERROR_TEXT_LEN];
    DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
    if (res)
        printf("Error %x: %s\n%s\n",hr, errtext,szErr);
    else
        printf("Error %x: %s\n", hr, errtext);
    return TRUE;
}

//change this macro to fit your style of error handling
#define CHECK_HR(hr, msg) if (hrcheck(hr, msg)) return hr;

CComPtr<IPin> GetPin(IBaseFilter *pFilter, LPCOLESTR pinname)
{
    CComPtr<IEnumPins>  pEnum;
    CComPtr<IPin>       pPin;

    HRESULT hr = pFilter->EnumPins(&pEnum);
    if (hrcheck(hr, "Can't enumerate pins."))
        return NULL;

    while(pEnum->Next(1, &pPin, 0) == S_OK)
    {
        PIN_INFO pinfo;
        pPin->QueryPinInfo(&pinfo);
        BOOL found = !wcsicmp(pinname, pinfo.achName);
        if (pinfo.pFilter) pinfo.pFilter->Release();
        if (found)
            return pPin;
        pPin.Release();
    }
    printf("Pin not found!\n");
    return NULL; 
}

// {0F40E1E5-4F79-4988-B1A9-CC98794E6B55}
DEFINE_GUID(CLSID_ffdshowAudioDecoder,
0x0F40E1E5, 0x4F79, 0x4988, 0xB1, 0xA9, 0xCC, 0x98, 0x79, 0x4E, 0x6B, 0x55); //ffdshow.ax




HRESULT BuildGraph(IGraphBuilder *pGraph, LPCOLESTR srcFile1)
{
    HRESULT hr = S_OK;

    //graph builder
    CComPtr<ICaptureGraphBuilder2> pBuilder;
    hr = pBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder2);
    CHECK_HR(hr, "Can't create Capture Graph Builder");
    hr = pBuilder->SetFiltergraph(pGraph);
    CHECK_HR(hr, "Can't SetFiltergraph");

    //add File Source (Async.)
    CComPtr<IBaseFilter> pFileSourceAsync;
    hr = pFileSourceAsync.CoCreateInstance(CLSID_AsyncReader);
    CHECK_HR(hr, "Can't create File Source (Async.)");
    hr = pGraph->AddFilter(pFileSourceAsync, L"File Source (Async.)");
    CHECK_HR(hr, "Can't add File Source (Async.) to graph");
    //set source filename
    CComQIPtr<IFileSourceFilter, &IID_IFileSourceFilter> pFileSourceAsync_src(pFileSourceAsync);
    if (!pFileSourceAsync_src)
        CHECK_HR(E_NOINTERFACE, "Can't get IFileSourceFilter");
    hr = pFileSourceAsync_src->Load(srcFile1, NULL);
    CHECK_HR(hr, "Can't load file");


    //add MPEG-I Stream Splitter
    CComPtr<IBaseFilter> pMPEGIStreamSplitter;
    hr = pMPEGIStreamSplitter.CoCreateInstance(CLSID_MPEG1Splitter);
    CHECK_HR(hr, "Can't create MPEG-I Stream Splitter");
    hr = pGraph->AddFilter(pMPEGIStreamSplitter, L"MPEG-I Stream Splitter");
    CHECK_HR(hr, "Can't add MPEG-I Stream Splitter to graph");


    //connect File Source (Async.) and MPEG-I Stream Splitter
    hr = pGraph->ConnectDirect(GetPin(pFileSourceAsync, L"Output"), GetPin(pMPEGIStreamSplitter, L"Input"), NULL);
    CHECK_HR(hr, "Can't connect File Source (Async.) and MPEG-I Stream Splitter");


    //add ffdshow Audio Decoder
    CComPtr<IBaseFilter> pffdshowAudioDecoder;
    hr = pffdshowAudioDecoder.CoCreateInstance(CLSID_ffdshowAudioDecoder);
    CHECK_HR(hr, "Can't create ffdshow Audio Decoder");
    hr = pGraph->AddFilter(pffdshowAudioDecoder, L"ffdshow Audio Decoder");
    CHECK_HR(hr, "Can't add ffdshow Audio Decoder to graph");


    //connect MPEG-I Stream Splitter and ffdshow Audio Decoder
    hr = pGraph->ConnectDirect(GetPin(pMPEGIStreamSplitter, L"Audio"), GetPin(pffdshowAudioDecoder, L"In"), NULL);
    CHECK_HR(hr, "Can't connect MPEG-I Stream Splitter and ffdshow Audio Decoder");


    //add Default DirectSound Device
    CComPtr<IBaseFilter> pDefaultDirectSoundDevice;
    hr = pDefaultDirectSoundDevice.CoCreateInstance(CLSID_DSoundRender);
    CHECK_HR(hr, "Can't create Default DirectSound Device");
    hr = pGraph->AddFilter(pDefaultDirectSoundDevice, L"Default DirectSound Device");
    CHECK_HR(hr, "Can't add Default DirectSound Device to graph");


    //connect ffdshow Audio Decoder and Default DirectSound Device
    hr = pGraph->ConnectDirect(GetPin(pffdshowAudioDecoder, L"Out"), GetPin(pDefaultDirectSoundDevice, L"Audio Input pin (rendered)"), NULL);
    CHECK_HR(hr, "Can't connect ffdshow Audio Decoder and Default DirectSound Device");


    return S_OK;
}

//int _tmain(int argc, _TCHAR* argv[]) //use this line in VS2008
int main(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
    CComPtr<IGraphBuilder> graph;
    graph.CoCreateInstance(CLSID_FilterGraph);

    printf("Building graph...\n");
    HRESULT hr = BuildGraph(graph, argv[1]);
    if (hr==S_OK) {
        printf("Running");
        CComQIPtr<IMediaControl, &IID_IMediaControl> mediaControl(graph);
        hr = mediaControl->Run();
        CHECK_HR(hr, "Can't run the graph");
        CComQIPtr<IMediaEvent, &IID_IMediaEvent> mediaEvent(graph);
        BOOL stop = FALSE;
        MSG msg;
        while(!stop)
        {
            long ev=0, p1=0, p2=0;
            Sleep(500);
            printf(".");
            while(PeekMessage(&msg, NULL, 0,0, PM_REMOVE))
                DispatchMessage(&msg);
            while (mediaEvent->GetEvent(&ev, &p1, &p2, 0)==S_OK)
            {
                if (ev == EC_COMPLETE || ev == EC_USERABORT)
                {
                    printf("Done!\n");
                    stop = TRUE;
                }
                else
                if (ev == EC_ERRORABORT)
                {
                    printf("An error occured: HRESULT=%x\n", p1);
                    mediaControl->Stop();
                    stop = TRUE;
                }
                mediaEvent->FreeEventParams(ev, p1, p2);
            }
        }
    }
    CoUninitialize();
    return 0;
}


The code was built with Microsoft VS2010 and this is the log report from the build:

1>------ Rebuild All started: Project: nov poskus, Configuration: Debug Win32 ------
1>  stdafx.cpp
1>  nov poskus.cpp
1>c:\program files (x86)\microsoft visual studio 10.0\vc\atlmfc\include\atlconv.h(757): warning C4995: 'wcscpy': name was marked as #pragma deprecated
1>c:\program files (x86)\microsoft visual studio 10.0\vc\atlmfc\include\atlconv.h(768): warning C4995: 'wcscat': name was marked as #pragma deprecated
1>c:\vc\nov poskus\nov poskus\nov poskus.cpp(41): warning C4996: 'wcsicmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _wcsicmp. See online help for details.
1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\wchar.h(1095) : see declaration of 'wcsicmp'
1>  nov poskus.vcxproj -> C:\vc\nov poskus\Debug\nov poskus.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

I'm not sure about these warnings, I googled them a bit and I assume they are not important for the proper functioning of the application.

I also debugged the app and this is the log:

'nov poskus.exe': Loaded 'C:\vc\nov poskus\Debug\nov poskus.exe', Symbols loaded.
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\ntdll.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\kernel32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\KernelBase.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\user32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\gdi32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\lpk.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\usp10.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\msvcrt.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\advapi32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\sechost.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\rpcrt4.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\sspicli.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\cryptbase.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\ole32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\quartz.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\oleaut32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\winmm.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\shell32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\shlwapi.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\msvcr100d.dll', Symbols loaded.
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\imm32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\msctf.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\uxtheme.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\clbcatq.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\dwmapi.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\qcap.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\msvfw32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\winsxs\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.7600.16661_none_ebfb56996c72aefc\comctl32.dll', Symbols loaded (source information stripped).
'nov poskus.exe': Loaded 'C:\Windows\SysWOW64\version.dll', Symbols loaded (source information stripped).
The thread 'Win32 Thread' (0x1114) has exited with code 0 (0x0).
The program '[816] nov poskus.exe: Native' has exited with code 0 (0x0).

When I try to run the application (open console, drag'n drop the app in there, space, drag'n drop some mp3 file) this is the error message I get:


C:\Users\MicoMaco>"C:\vc\nov poskus\Debug\nov poskus.exe" "C:\Users\MicoMaco\Music\AC DC\Back In Black\AC DC_BACK IN BLACK_Hells Bells.mp3"
Building graph...
Error 80070002: Can't load file
N

Can you please tell me what's wrong with the code? I'd be very grateful.

Regards, MicoMaco
Logged
Dee Mon
Administrator
Hero Member
*****

Karma: +8/-0
Posts: 511



View Profile WWW
« Reply #9 on: October 16, 2010, 08:45:25 AM »

Error 80070002 means "File not found", the file reader can't find your mp3 file.
The problem is that you get filename in argv[1] in ANSI encoding where each character is represented by one byte but here:
pFileSourceAsync_src->Load(srcFile1, NULL);
the Load method must receive the filename in Unicode, where each character is 2 bytes.
That's why in the sample I provided there is ANSI to Unicode conversion using MultiByteToWideChar.
You won't get this problem in C# because there all strings are in Unicode. But in C++ you have a choice: build a Unicode or ANSI app. ANSI is default but if you select build target Release_Unicode or Debug_Unicode then TCHAR will be 2 bytes long, your argv parameters will be in Unicode, so no conversion will be required but some other parts of the code will need some changes.
Logged
MicoMaco
Newbie
*

Karma: +1/-0
Posts: 15


View Profile
« Reply #10 on: October 16, 2010, 01:18:53 PM »

Thank you very much for this insight. I'll try to correct the code.
Logged
MicoMaco
Newbie
*

Karma: +1/-0
Posts: 15


View Profile
« Reply #11 on: October 16, 2010, 03:24:54 PM »

I just found out an easy and elegant solution. A part of the default generated code by GE+ for my graph looks like this:

Code:
int main(int argc, char* argv[])
{
    CoInitialize(NULL);
    CComPtr<IGraphBuilder> graph;
    graph.CoCreateInstance(CLSID_FilterGraph);

    printf("Building graph...\n");
    HRESULT hr = BuildGraph(graph, L"C:\\Users\\MicoMaco\\Desktop\\test.avi", L"C:\\Users\\MicoMaco\\Desktop\\karkoli.avi");

VS2010 builds a working console application if I make these changes:

Code:
int wmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
    CComPtr<IGraphBuilder> graph;
    graph.CoCreateInstance(CLSID_FilterGraph);

    printf("Building graph...\n");
    HRESULT hr = BuildGraph(graph, argv[1], argv[2]);

Of course the later code works for any input (argv[1]) and output (argv[2]) file which meets the filters requirements. And that was my main goal.

I thank you a lot Dee Mon, without you this would be almost impossible for me!  Smiley

Kind regards, MicoMaco
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.13 | SMF © 2006-2011, Simple Machines LLC Valid XHTML 1.0! Valid CSS!