Как да напиша avi файл с DirectShow

Опитвам се да напиша avi видео файл въз основа на стрийминг на моята Decklink SDI карта, след като потърсих в интернет и тук написах този код, тъй като проблемът ми е, че програмата не записва файла, ето кодът:

#include <Windows.h>
#include <DShow.h>
#include <iostream>


 int main(void)
{
IGraphBuilder* pGraph = NULL;
ICaptureGraphBuilder2* pBuild = NULL;
IMediaControl* pControl = NULL;

ICreateDevEnum* pDevEnum = NULL;
IEnumMoniker* pEnum = NULL;
IMoniker *pMoniker = NULL;
IMoniker* goodMoniker = NULL;
IBaseFilter* pCap;
HRESULT hr;

//Initialize pGraph
hr = CoInitialize(NULL);
   hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **) &pGraph);
if(FAILED(hr))
{
    printf("ERROR - Could not initialize COM library");
    return 1;
}

//Initialize pBuild


 hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**) &pBuild);
if(FAILED(hr))
{
    printf("ERROR - Could not create the Filter Graph Manager.");
    return 2;
}
pBuild->SetFiltergraph(pGraph);



hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pDevEnum));
if(SUCCEEDED(hr))
{
    hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
}


HWND hList;

while(pEnum->Next(1, &pMoniker, NULL) == S_OK)
{
    IPropertyBag* pPropBag;
    hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
    if(FAILED(hr))
    {
        pMoniker->Release();
        continue;
    }

    VARIANT varName;
    VariantInit(&varName);
    hr = pPropBag->Read(L"Description", &varName, 0);
    if(FAILED(hr))
    {
        hr = pPropBag->Read(L"FriendlyName", &varName, 0);
    }
    if(SUCCEEDED(hr))
    {
        for(int i=0;i<20;i++)
        {
           std::cout<<(char)*(varName.bstrVal + i);
        }

        char yn;
        std::cin>>yn;

        if(yn=='Y')
        {
            std::cout<<"SUCCESSFUL"<<std::endl;
            goodMoniker = pMoniker;
            VariantClear(&varName);
        }
    }
    pPropBag->Release();
    if(pMoniker != goodMoniker)
    {
        pMoniker->Release();
    }
}


hr = goodMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)(&pCap));

if(SUCCEEDED(hr))
{
    hr = pGraph->AddFilter(pCap, L"Capture Filter");

}

IBaseFilter *pMux = NULL;

//  hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL);

hr = pBuild->SetOutputFileName(
&MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.
L"C:\\stuff.avi", // File name.
&pCap,              // Receives a pointer to the mux.
NULL);              // (Optional) Receives a pointer to the file sink.

hr =pBuild->RenderStream(
&PIN_CATEGORY_CAPTURE, // Pin category.
&MEDIATYPE_Video,      // Media type.
pCap,                  // Capture filter.
NULL,                  // Intermediate filter (optional).
pMux);                 // Mux or file sink filter.  


hr = pCap->QueryInterface(IID_IMediaControl,(void**) pControl);

printf("START ");
hr = pControl->Run();

Sleep(100000);
hr = pControl->Stop();
CoUninitialize();


pGraph->Release();
pBuild->Release();
pCap->Release();

}

ето съобщението за грешка, което получавам, когато се опитвам да го отстраня:

  Unhandled exception at 0x776015de in STREAMMMMM.exe: 0xC0000005: Access violation reading location 0x00000000.

програмата се срива в този ред:

 r = pCap->QueryInterface(IID_IMediaControl,(void**) pControl);

person Engine    schedule 24.01.2013    source източник
comment
Не пишете файлове в главната директория c:\, UAC забранява достъпа за запис. Използвайте примера на AmCap за вдъхновение. msdn.microsoft.com/en-us/ библиотека/dd373424%28v=VS.85%29.aspx   -  person Hans Passant    schedule 24.01.2013


Отговори (1)


Има десетки, ако не и стотици, примери как да пишете в AVI с DirectShow в Интернет.

Този конкретен кодов фрагмент дори не започва да пише. Той само подготвя тръбопровода, а вие дори не правите IMediaControl::Run, това, което трябва да правите. По-нататък трябва да изчакате, докато напишете достатъчно, след което да спрете записа и едва тогава да освободите указателите на интерфейса.

Разгледайте този въпрос: Използване на DirectShow филтрирайте, без да го регистрирате, чрез частен CoCreateInstance върху това, което ви липсва, за да започнете действително заснемане и писане (IMediaControl::Run и Sleep по-специално).

person Roman R.    schedule 24.01.2013
comment
Просто искам да запиша 10 s от моето устройство - person Engine; 24.01.2013
comment
Добавих връзка към друг въпрос, който да разгледате. - person Roman R.; 24.01.2013
comment
@ Роман, благодаря за помощта, редактирах кода въз основа на другия въпрос, но все още не работи (моля, вижте моя редактиран въпрос - person Engine; 25.01.2013
comment
Трябва да направите малко отстраняване на грешки и да получите каквито и да било кодове за грешки. Нещо, което може също да искате да разгледате, е SDK от Blackmagic. Това е публично изтегляне и има примерен код за проекти на DirectShow, вижте \Blackmagic DeckLink SDK 9.5\Win\Samples там. Има и предварително изградени изпълними файлове. Освен вече споменатите, може да има и други причини да не записвате видео, като например задаване на неправилен формат на заснемане на платката на Decklink. - person Roman R.; 25.01.2013
comment
Моят код не работи както за уеб камера, така и за Decklink SDI карта. - person Engine; 25.01.2013
comment
и примерът на Blackmagic е твърде сложен за разбиране (по-малко за мен) и те използват кодеците и всичко, което искам, е да направя видеото и да го напиша. благодаря отново за помощта - person Engine; 25.01.2013
comment
Не мисля, че сте предоставили правилния ред за грешка, но този ред определено има проблем. Трябваше да бъде така: pGraph->QueryInterface(..., IID_IMediaControl, тоест pGraph, а не pCap. - person Roman R.; 25.01.2013
comment
Направих го, но промених кода си. Просто не разбирам защо е толкова сложно да се вземе видеоклип с помощта на Direchtshow. Направих го с opencv и беше добре, качеството е мой проблем - person Engine; 25.01.2013