[XviD-devel] FrameAnalyzer help (was: codec performance)

H. K. Rosbach xvid-devel@xvid.org
Mon, 16 Dec 2002 23:37:23 +0100


> > > I found nothing corresponding to what I wanted.
> > okay, it was called FrameAnalyser.
> http://www.xvid.org/modules.php?op=modload&name=phpBB2&file=viewtopic&t=145

Hmm..  Talking about my tool behind my back, eh?  =)

Nice to see somebody are still interested..

I have been developing on it quite a lot this year, but I have stumbled into some problems
a few months ago that totally block me from continuting the development. No, they are not
personal problems for once..

I'm using DirectShow to decode the videos, and for some reason the code no longer works
like it should at all. It compiles.. most of the time, but it generates strange errors.
Probably filers that cannot connect to eachother. The problem is, I do not know where the
fault lies, and it seems that I have only made it worse since I found it.

Thus my development code does not work, and no real work on the code can be done. Now, my
real problem is that I have very little experience with DirectShow, and thus do not really
know where to start to actually debug it.

So, now I have no other choice than to ask you kind souls for assistance. I included the
code that makes problems below. If/when this problem is solved, I hope to once again
develop FrameAnalyzer actively to further increase it's useability.

I hope to see some suggestions as to what might be wrong, and/or other improvements I can
make. Remember that I do not really understand this code myself, just briefly.. So any hel
is good help. Oh, and remember that I'm developing this utility for you, the xvid community.

-=Dead2=-

Btw, I use the Intel compiler.. Not sure the code compiles on plain MSVC++


 --- Source code in question included from here on ---

HRESULT DoExtractFrame(char *pFilePath, BITMAP_CLASS *Bitmap, long long FrameNum){
	//Declare commonly used things
	HRESULT			hr;		//Error Result Code
	AM_MEDIA_TYPE	mt;		//Media type

	WCHAR wFile[MAX_PATH];
    MultiByteToWideChar( CP_ACP, 0, pFilePath, -1, wFile, MAX_PATH );

	// Create the graph builder
	CComPtr<IGraphBuilder> pGraphBuilder;		
	CoInitialize(NULL);
	hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void
**)&pGraphBuilder);
	if (FAILED(hr))return hr;

	// Create the "Grabber filter"
	CComPtr<IBaseFilter>    pGrabberBaseFilter;
	CComPtr<ISampleGrabber> pSampleGrabber;
	
	hr =
::CoCreateInstance(CLSID_SampleGrabber,NULL,CLSCTX_INPROC_SERVER,IID_IBaseFilter,(LPVOID
*)&pGrabberBaseFilter);
	if (FAILED(hr))return hr;

	pGrabberBaseFilter->QueryInterface(IID_ISampleGrabber, (void**)&pSampleGrabber);
	if (pSampleGrabber == NULL) return E_NOINTERFACE;
	
	hr = pGraphBuilder->AddFilter(pGrabberBaseFilter,L"Grabber");
	if (FAILED(hr))return hr;
	
	//Set media type
	memset(&mt, 0, sizeof(AM_MEDIA_TYPE));
	mt.majortype = MEDIATYPE_Video;
	mt.formattype = FORMAT_VideoInfo; 
	mt.subtype = MEDIASUBTYPE_RGB32;
	
	hr = pGraphBuilder->RenderFile(wFile,NULL);
	if (FAILED(hr)){ //Try RGB32 instead of ARGB32 just in case
		mt.subtype = MEDIASUBTYPE_RGB32;
		hr = pSampleGrabber->SetMediaType(&mt);
		if (FAILED(hr)) return hr;
		hr = pGraphBuilder->RenderFile(wFile,NULL);
		if (FAILED(hr)) return hr;
	}

	CComPtr<IMediaControl> pMediaControl;
	CComPtr<IMediaEvent> pMediaEventEx;
	// QueryInterface for some basic interfaces
    pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
    pGraphBuilder->QueryInterface(IID_IMediaEvent, (void **)&pMediaEventEx);
	
	if (pMediaControl == NULL || pMediaEventEx == NULL) return E_NOINTERFACE;
	
	// Set up one-shot mode.
	hr = pSampleGrabber->SetBufferSamples(TRUE);
	if (FAILED(hr))	return hr;
	
	hr = pSampleGrabber->SetOneShot(TRUE);
	if (FAILED(hr))	return hr;
	
	CComQIPtr<IMediaSeeking> pSeek = pMediaControl;
	if (pSeek == NULL) return E_NOINTERFACE;
	
	LONGLONG Duration = 0;
	hr = pSeek->SetTimeFormat(&TIME_FORMAT_FRAME);
	if (FAILED(hr)){
		//This might work if its an .OGM file..
		hr = pSeek->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
		if (FAILED(hr)){
			return hr;
		}else{
			hr = pSeek->GetDuration(&Duration);
			if (!FAILED(hr)){
				if (Duration < FrameNum)  {FrameNum = Duration;}
			}
		}
	}else{
		hr = pSeek->GetDuration(&Duration);
		if (!FAILED(hr)){
			if (Duration < FrameNum)  {FrameNum = Duration;}
		}
	}	
	
	hr = pSeek->SetPositions(&FrameNum, AM_SEEKING_AbsolutePositioning, &FrameNum,
AM_SEEKING_AbsolutePositioning);
	if (FAILED(hr))	return hr;
	
	long long trash = 0;
	pSeek->GetPositions(&Bitmap->ActualFramePos, &trash);
	
	CComQIPtr<IVideoWindow> pVideoWindow = pGraphBuilder;
	hr = pVideoWindow->put_AutoShow(OAFALSE);
	if (FAILED(hr))	return hr;
	
	// Run the graph and wait for completion.
	hr = pMediaControl->Run();
	if (FAILED(hr))	return hr;
	long evCode;
	hr = pMediaEventEx->WaitForCompletion(INFINITE, &evCode);
	if (FAILED(hr))	return hr;

	// Get a pointer to the video header.
	memset(&mt, 0, sizeof(mt));
	hr = pSampleGrabber->GetConnectedMediaType(&mt); 
	if (FAILED(hr))	return hr;
	VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)mt.pbFormat;
	if (pVideoHeader == NULL) return E_FAIL;
	
	Bitmap->newbitmap(pVideoHeader->bmiHeader.biWidth, pVideoHeader->bmiHeader.biHeight);
	
	long size = 0;
	size = ((pVideoHeader->bmiHeader.biWidth * pVideoHeader->bmiHeader.biHeight) * 4);
	//hr = pSampleGrabber->GetCurrentBuffer(&size, NULL);
	hr = pSampleGrabber->GetCurrentBuffer(&size, (long *)(Bitmap->Buffer));
	if (FAILED(hr))	return hr;

	//Do some cleanups just in case..
	FreeMediaType(mt);
	SAFE_RELEASE(pGrabberBaseFilter);
	//pGrabberBaseFilter.Release();
	pSampleGrabber.Release();
	pGraphBuilder.Release();
	pMediaControl.Release();
	pMediaEventEx.Release();
	pVideoWindow.Release();
	pSeek.Release();

	return hr;
}


 --- Additional code you might need ---

class BITMAP_CLASS{ // This is the Structure that contains the results
public:
	BITMAPINFOHEADER InfoHeader;
	BITMAPINFO Info;
	HBITMAP	Bitmap;
	BYTE* Buffer;
	long Width;
	long Height;
	long long ActualFramePos;

	void initialize();
	void unload();
	void newbitmap(int inWidth, int inHeight);
	void resize();
};

extern BITMAP_CLASS* Bitmap;

void BITMAP_CLASS::newbitmap(int inWidth, int inHeight){
	unload();

	Width = inWidth;
	Height = inHeight;

	InfoHeader.biSize = sizeof(BITMAPINFOHEADER);
	InfoHeader.biWidth = Width;
	InfoHeader.biHeight = Height;
	InfoHeader.biPlanes = 1;
	InfoHeader.biBitCount = 32;
	InfoHeader.biCompression = BI_RGB;
	InfoHeader.biSizeImage = 0;
	InfoHeader.biXPelsPerMeter = 0;
	InfoHeader.biYPelsPerMeter = 0;
	InfoHeader.biClrUsed = 0;
	InfoHeader.biClrImportant = 0;
	
	Info.bmiHeader = InfoHeader;
	
	Bitmap = CreateDIBSection(0, (BITMAPINFO *)&InfoHeader, DIB_RGB_COLORS,
(void**)&(Buffer), NULL, 0);
}