Published by alax on 24 Aug 2008

How To: Save image to BMP file from IBasicVideo or VMR windowless interface

A simple question being asked all over again. Given IBasicVideo, IBasicVideo2, IVMRWindowlessControl or IVMRWindowlessControl9, how to save image to file? It is easy. It is a bit easier with IBasicVideo because it is possible to query this interface directly from graph’s interface, such asĀ  IGraphBuilder, and the call will be forwarded to video renderer. This code assumes internal bitmap format is non-paletted, which I believe is always the case.

LONG nBufferSize = 0;
ATLENSURE_SUCCEEDED(pBasicVideo->GetCurrentImage(&nBufferSize, NULL));
CHeapPtr<BITMAPINFO> pBitmapInfo;
ATLENSURE_THROW(pBitmapInfo.AllocateBytes(nBufferSize), E_OUTOFMEMORY);
ATLENSURE_SUCCEEDED(pBasicVideo->GetCurrentImage(&nBufferSize, (LONG*) (BITMAPINFO*) pBitmapInfo));
const BYTE* pnData = (const BYTE*) (&pBitmapInfo->bmiHeader + 1);
// NOTE: You might wish to handle <=8 bpp bitmaps here
ATLASSERT(pBitmapInfo->bmiHeader.biBitCount > 8);
ATLASSERT(pBitmapInfo->bmiHeader.biCompression == BI_RGB);
ATLASSERT(pBitmapInfo->bmiHeader.biSizeImage);
BITMAPFILEHEADER BitmapFileHeader;
ZeroMemory(&BitmapFileHeader, sizeof BitmapFileHeader);
BitmapFileHeader.bfType = 'MB';
BitmapFileHeader.bfSize = (DWORD) (sizeof (BITMAPFILEHEADER) + pBitmapInfo->bmiHeader.biSize + pBitmapInfo->bmiHeader.biSizeImage);
BitmapFileHeader.bfOffBits = (DWORD) (sizeof (BITMAPFILEHEADER) + pBitmapInfo->bmiHeader.biSize);
ATLENSURE_SUCCEEDED(File.Write(&BitmapFileHeader, sizeof BitmapFileHeader));
ATLENSURE_SUCCEEDED(File.Write(&pBitmapInfo->bmiHeader, pBitmapInfo->bmiHeader.biSize));
ATLENSURE_SUCCEEDED(File.Write(pnData, (DWORD) pBitmapInfo->bmiHeader.biSizeImage));

Published by alax on 23 Aug 2008

How To: Dump CAtlRegExp regular expression variable on parse error

ATL regular expression code adds dump/debug capabilities with ATL_REGEXP_DUMP preprocessor definition defined (undocumented). Dump output is directed to stdout, so if the application is not console, it has to be redirected in advance, e.g. into a $(BinaryPath)$(BinaryName)-atlrx.h file.

	CAtlRegExp<> Expression; LPCTSTR pszPattern; BOOL bCaseSensitive;
#if defined(ATL_REGEXP_DUMP)
	REParseError Error = Expression.Parse(pszPattern, bCaseSensitive);
	if(Error != REPARSE_ERROR_OK)
	{
		FILE* pStream = NULL;
		if(!GetStdHandle(STD_OUTPUT_HANDLE))
		{
			TCHAR pszPath[MAX_PATH] = { 0 };
			ATLVERIFY(GetModuleFileName(_AtlBaseModule.GetModuleInstance(), pszPath, _countof(pszPath)));
			RemoveExtension(pszPath); // ATLPath::
			_tcscat_s(pszPath, _countof(pszPath), _T("-atlrx.txt"));
			ATLVERIFY(freopen_s(&pStream, CStringA(pszPath), "w", stdout) == 0);
		}
		_tprintf(_T("Error %d\n"), Error);
		Expression.Dump();
		if(pStream)
			ATLVERIFY(fclose(pStream) == 0);
		ATLASSERT(FALSE); // Break into debugger
	}
#else
	ATLVERIFY(Expression.Parse(pszPattern, bCaseSensitive) == REPARSE_ERROR_OK);
#endif // defined(ATL_REGEXP_DUMP)

There is also ATLRX_DEBUG definition, which enables other debug capabilities. CAtlRegExp object is given a virtual function OnDebugEvent through which it prints comments on CAtlRegExp::Match process, which can be also redirected to file similar way.

Published by alax on 22 Aug 2008

How To: Dump DirectShow media samples

Given a DirectShow filter graph, what media samples are being sent through particular graph point? DumpMediaSamples utility gives a fast answer to this question. It prints out connection media type details (with details of VIDEOINFOHEADER, VIDEOINFOHEADER2 and WAVEFORMATEX structures corresponding to FORMAT_VideoInfo, FORMAT_VideoInfo2 and FORMAT_WaveFormatEx format types) and IMediaSample details obtained through AM_SAMPLE2_PROPERTIES structure.

First of all, it is necessary to create a graph of interest using GraphEdit utility. At the point of interest it is necessary to insert [an uninitialized] Sample Grabber Filter with the filter name “SampleGrabber” (this is the default name but if you add second filter which will be given a different name and remove first filter then, the utility would fail).

The graph may look like this:

Continue Reading »

Published by alax on 26 Jul 2008

How To: Implement DirectShow Filter using DirectX Media Object DMO (Part 5: In-Place Processing)

Previously on the topic:

Due to the nature of the brightness and constract correction processing, it would make sense to combine and simplify processing to apply correction “in-place”, that is without copying data from input to output buffer, but instead processing the same buffer before it is passed further downstream.

DMO API offers additional optional IMediaObjectInPlace interface to be implemented on the DMO which the hosting object might prefer to regular IMediaObject.

The interface itself is simple with basically the only Process method to actually handle the processing:

// IMediaObjectInPlace
	STDMETHOD(Process)(ULONG nSize, BYTE* pnData, REFERENCE_TIME nStartTime, DWORD nFlags)
	STDMETHOD(Clone)(IMediaObjectInPlace** ppMediaObject)
	STDMETHOD(GetLatency)(REFERENCE_TIME* pnLatencyTime)

Continue Reading »

Published by alax on 26 Jul 2008

How To: Implement DirectShow Filter using DirectX Media Object DMO (Part 4: Merit)

Previously on the topic:

The implemented so far filter/DMO shown a problem related to its unexpectedly high “importance” in the system with the symptom of “auto-insertion” the filter when it is not necessary. For example, let us render an AVI file through Infinite Tee Pin Filter:

The problem is that DirectShow auto-inserts our Brightness/Contrast filter into the graph while it is obviously not expected, wanted or necessary:

The problem is high filter/DMO merit value and a popular YUY2 video format the filter is advertised to accept on input during DMO registration.

Continue Reading »

Published by alax on 18 Jul 2008

How To: Implement DirectShow Filter using DirectX Media Object DMO (Part 3: Persistence, Automation and Property Pages)

Previously on the topic:

The principal task of video processing is done but there are still things mandatory for the filter to be usable. First of all, a custom interface is required to be able to control the filter from higher level application and to adjust brightness and constract correction values on the run time. Additionally, persistence would not hurt at all to be able to store correction settings along with other graph settings in GraphEdit graph file or anywhere else. Additionally, it would also be convenient to have a property page for the filter to be able to adjust the correction settings through GUI, both on graph composition and while the graph is running.

All the mentioned tasks are interconnected and ATL has an answer in implementation of:

Continue Reading »

Published by alax on 12 Jul 2008

How To: Implement DirectShow Filter using DirectX Media Object DMO (Part 2: Video Processing)

Previously on the topic:

We have the DMO filter project compilable and registered with the system and it is right time to start putting code in that allows connecting the filter to other DirectShow filters, such as video capture or video file source on the input and video renderer on the output.

IMediaObject implementation includes the following groups of functions:

  • object capabilities:
    STDMETHOD(GetStreamCount)(DWORD* pnInputStreamCount, DWORD* pnOutputStreamCount)
    STDMETHOD(GetInputStreamInfo)(DWORD nInputStreamIndex, DWORD* pnFlags)
    STDMETHOD(GetOutputStreamInfo)(DWORD nOutputStreamIndex, DWORD* pnFlags)
    STDMETHOD(GetInputType)(DWORD nInputStreamIndex, DWORD nTypeIndex, DMO_MEDIA_TYPE* pMediaType)
    STDMETHOD(GetOutputType)(DWORD nOutputStreamIndex, DWORD nTypeIndex, DMO_MEDIA_TYPE* pMediaType)
  • current media types:
    STDMETHOD(SetInputType)(DWORD nInputStreamIndex, const DMO_MEDIA_TYPE* pMediaType, DWORD nFlags)
    STDMETHOD(SetOutputType)(DWORD nOutputStreamIndex, const DMO_MEDIA_TYPE* pMediaType, DWORD nFlags)
    STDMETHOD(GetInputCurrentType)(DWORD nInputStreamIndex, DMO_MEDIA_TYPE* pMediaType)
    STDMETHOD(GetOutputCurrentType)(DWORD nOutputStreamIndex, DMO_MEDIA_TYPE* pMediaType)
    STDMETHOD(GetInputSizeInfo)(DWORD nInputStreamIndex, DWORD* pnBufferSize, DWORD* pnMaximalLookAheadBufferSize, DWORD* pnAlignment)
    STDMETHOD(GetOutputSizeInfo)(DWORD nOutputStreamIndex, DWORD* pnBufferSize, DWORD* pnAlignment)
  • streaming:
    STDMETHOD(GetInputMaxLatency)(DWORD nInputStreamIndex, REFERENCE_TIME* pnMaximalLatency)
    STDMETHOD(SetInputMaxLatency)(DWORD nInputStreamIndex, REFERENCE_TIME nMaximalLatency)
    STDMETHOD(Flush)()
    STDMETHOD(Discontinuity)(DWORD nInputStreamIndex)
    STDMETHOD(AllocateStreamingResources)()
  • data processing:
    STDMETHOD(GetInputStatus)(DWORD nInputStreamIndex, DWORD* pnFlags)
    STDMETHOD(Lock)(LONG bLock)
    STDMETHOD(ProcessInput)(DWORD nInputStreamIndex, IMediaBuffer* pMediaBuffer, DWORD nFlags, REFERENCE_TIME nTime, REFERENCE_TIME nLength)
    STDMETHOD(ProcessOutput)(DWORD nFlags, DWORD nOutputBufferCount, DMO_OUTPUT_DATA_BUFFER* pOutputBuffers, DWORD* pnStatus)

Continue Reading »

Next »