Witam ponownie.
Napisałem malutką aplikację do konwersji "kosmicznych" formatów audio (np .mpc) do mp3. Winamp nie potrafi tego odegrać więc musiałem coś z tym zrobić.
MediaPlayer (a nawet PlayWnd sample) to odgrywało więc zainteresowałem się dshow.
I tu powstały dwa problemy:

  1. Graph builder tylko w trybie playback zwraca poprawne duration. W trybie z grabberem połączonym do NullRenderer'a zwraca duration 0.
  2. Nie czyści po sobie - nie zamyka uchwytu do renderowanego pliku i nie ubija swoich threadów, co łatwo sprawdzić dowolnym handle-viewerem (np. ProcessExplorer)

oto kod który pobiera duration, czyści po sobie i wyświetla wynik.
Podczas gdy wynik jest widoczny trzeba zerknąć na uchwyty aplikacji gdzie widać jakieś 5 aktywnych threadów i uchwyt do renderowanego pliku.

Czy czegoś tu brakuje? Próbowałem nawet po kolei odłączać wszystkie filtry od grafu i po tym release'ować, ale to wcale nie pomogło, plik wejściowy nadal był otwarty.

#include <dshow.h>
#include <Qedit.h>
#include <stdio.h>
#pragma comment(lib, "strmiids.lib")

#define FILE_TO_RENDER L"M:\\apfelringe.mp3" // zmień to sobie

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
    double duration = 0.0;

    CoInitialize(0);

    IGraphBuilder  *pGraph;
    IMediaSeeking  *pSeeker;
    IMediaControl  *pControl;
    if (!CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph))
    {
        if (!pGraph->QueryInterface(IID_IMediaSeeking, (void**)&pSeeker))
        {
            if (!pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl))
            {
                if (!pGraph->RenderFile(FILE_TO_RENDER, NULL))
                {
                    LONGLONG duration64;
                    pSeeker->GetDuration(&duration64);
                    duration = (double)(duration64 / 10000000.0);
                    pControl->Stop();
                }
                else
                {
                    MessageBox(0, "nie znaleziono filtra dla tego typu pliku", "", 0);
                }
                pControl->Release();
            }
            pSeeker->Release();
        }
        pGraph->Release();
    }
    CoUninitialize();

    // teraz podgl?daj?c uchwyty procesu w ProcessExplorer
    // wida? ?e uchwyt do pliku nadal jest aktywny
    // pomijaj?c ilo?? threadów i innych uchwytów...
    char sz[256];
    sprintf(sz,"wskazane multimedia ma %.2f sekund\n", (float)duration);
    MessageBox(0, sz, "", 0);
    return 0;
}

ps. do dekompresji potrzebuję duration aby wizualizować postęp, a sam plik otwieram ciut inaczej:

pGraph->AddSourceFilter(m_OpenPath, L"Input File", &pFileFilter);

i łączę ten filtr do grabbera z callbackiem, a grabbera do NullRender'era, jak bozia przykazała.
W callbacku CSampleGrabberCB ostatnią dawkę PCM wykrywam albo nagłym spadkiem ilości danych, albo porównując (ilość odebranych bajtów * samplerate) z duration w sekundach.

IMediaEventEx wysyła tylko dwa eventy zaraz po uruchomieniu grafu, więc wywaliłem to z programu bo okazało się zbyteczne. Podobnie IMediaSeeking i IMediaPosition - zwraca zero dla position i duration.