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.