How to control IP Video Source JPEG video filter from C# programmatically

User’s question about Alax.Info IP Video Source DirectShow filter for JPEG/M-JPEG video:

As it stands now, in order to configure the video capture source filter, I have to instantiate it […], set the properties (camera URL, and video dimensions), then save the filter state to a data array which is then compiled into the application. That doesn’t provide a feasible system for user configuration at run time: Telling our customers we need to have the IP address(es) of their camera(s) so we can build a custom version of our software for them isn’t going to be very marketable.

[…]

I looked on the Alax.Info Web site, and didn’t see anything that looks like an API for configuration. I also didn’t see anything inside […] that looks like configuration parameters. I find it hard to believe this isn’t a common requirement, so I suspect I’m overlooking something.

Is there an “easy” way to configure the parameters of the Alax.info video capture filter at run time? Where is it documented?

Is there a structure that describes the state info that is captured [into raw configuration data array]?

Are there any other considerations I’ve overlooked?

C++ and C# sample code (Trac, SVN) appears to be not easy no discover. The code snippets include PlayJpegLocation (C++) and PlayJpegLocationSharp (C#) projects/snippets demonstrating import of IP Video Source COM interfaces via COM and use them from code.

IP Video Source comes with a COM type library which is well suited for import by development environments, specifically by Visual Studio as a reference for .NET projects. To avoid bitness issues, it is recommended to have both 32 and 64 bit versions of IP Video Source installed.

C# integration is straightforward:

First, one needs to add a reference to AlaxInfoIpVideoSource type library, the same way DirectShow.NET is added to the project. The type library is imported and is available via .NET COM Interop at this point (specifically, visible in Object Browser). In code, the definitions are in AlaxInfoIpVideoSource namespace, JpegVideoSourceFilter represents a filter class, with IJpegVideoSourceFilter interface offering filter configuration.

The filter is also compatible with generic COM persistence: it implements standard IPersistStream, IPersistStreamInit, IPersistPropertyBag and other interfaces, its state can be saved to stream or property bad and loaded back.

Using IP Video Source programmatically as a standalone DirectShow Video Source Filter for JPEG and M-JPEG IP Cameras

Recent IP Video Source class/module is not limited to use via registration as a video input/capture/source device. The filter is also registered as a regular filter and can be used programmatically in a regular way: CoCreateInstance, AddFilter etc.

A C++ code snippet below shows how to import interface definition, create an instance of the filter, set it up and start video from a camera:

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

#import "libid:BDCE8B49-8895-4605-8278-E9A1FBC889AC" no_namespace raw_interfaces_only raw_dispinterfaces named_guids // IpVideoSource

// [...]

inline VOID ATLENSURE_INLINE_SUCCEEDED(HRESULT nResult)
{
    ATLENSURE_SUCCEEDED(nResult);
}

// [...]

CComPtr<IBaseFilter> pBaseFilter;
ATLENSURE_INLINE_SUCCEEDED(pBaseFilter.CoCreateInstance(CLSID_JpegVideoSourceFilter));
CComQIPtr<IJpegVideoSourceFilter> pJpegVideoSourceFilter = pBaseFilter;
ATLENSURE_THROW(pJpegVideoSourceFilter, E_NOINTERFACE);
ATLENSURE_INLINE_SUCCEEDED(pFilterGraph->AddFilter(pBaseFilter, L"Source"));

ATLENSURE_INLINE_SUCCEEDED(pJpegVideoSourceFilter->put_Location(CComBSTR(_T("http://p.viewnetcam.com:60001/nphMotionJpeg?Resolution=640x480&Quality=Standard"))));
ATLENSURE_INLINE_SUCCEEDED(pJpegVideoSourceFilter->put_Width(640));
ATLENSURE_INLINE_SUCCEEDED(pJpegVideoSourceFilter->put_Height(480));

#pragma region Render Output Pin
CComPtr<IEnumPins> pEnumPins;
ATLENSURE_INLINE_SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins));
CComPtr<IPin> pPin;
ATLENSURE_THROW(pEnumPins->Next(1, &pPin, NULL) == S_OK, E_FAIL);
ATLASSERT(pPin);
ATLENSURE_INLINE_SUCCEEDED(pFilterGraph->Render(pPin));
#pragma endregion

This starts M-JPEG video from Panasonic BB-HCM381A camera available to public online at http://p.viewnetcam.com:60001/nphMotionJpeg?Resolution=640×480&Quality=Standard

UPDATE: ATLENSURE_SUCCEEDED macro in the snippet replaced with ATLENSURE_INLINE_SUCCEEDED – see additional post on this.

C#.NET code snippet will look like this (using DirectShowLib):

using DirectShowLib;
using AlaxInfoIpVideoSource;

// [...]

FilterGraph filterGraph = new FilterGraph();
IJpegVideoSourceFilter sourceFilter = Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("{A8DA2ECB-DEF6-414D-8CE2-E651640DBA4F}"))) as IJpegVideoSourceFilter;
IBaseFilter sourceBaseFilter = sourceFilter as IBaseFilter;
(filterGraph as IFilterGraph2).AddFilter(sourceBaseFilter, "Source");
sourceFilter.Location = @"http://p.viewnetcam.com:60001/nphMotionJpeg?Resolution=640x480&Quality=Standard";
sourceFilter.Width = 640;
sourceFilter.Height = 480;
IPin pin = DsFindPin.ByDirection(sourceBaseFilter, PinDirection.Output, 0);
(filterGraph as IFilterGraph2).Render(pin);
(filterGraph as IMediaControl).Run();
EventCode eventCode;
(filterGraph as IMediaEvent).WaitForCompletion(-1, out eventCode);

MediaTools: Two samples to capture M-JPEG video into JPEG files and to play JPEG files back

I added two new simple samples for the MediaTools DirectShow filters to demonstrate how to capture M-JPEG video feed, esp. from an IP camera, and write the video frames into sequence of JPEG files. The other sample takes a directory on the input and plays the images back as video. If you are working on certain transformation filter, it is an easy way to make a reference feed and use it for debugging purposes.

The filters behind that empower the sample are described in another post.

RenderHttpMjpegVideoIntoFiles01 sample takes an URL on the input to generate image/jpeg JPEG or multipart/x-mixed-replace M-JPEG stream. For example, it might be http://demo1.stardotcams.com/nph-mjpeg.cgi feed from a demo StarDot Technologies IP camera.

The application will create a new directory to write files into, and will save each new video frame received into new JPEG file.

Z:\MediaTools\Samples\RenderHttpMjpegVideoIntoFiles01\Release>RenderHttpMjpegVideoIntoFiles01.exe http://demo1.stardotcams.com/nph-mjpeg.cgi
URL: http://demo1.stardotcams.com/nph-mjpeg.cgi
Writing to directory: Z:\MediaTools\Samples\RenderHttpMjpegVideoIntoFiles01\Release\2010-05-12 22-07-37
Event: nCode EC_CLOCK_CHANGED 0xD, nParameter1 0x00000000, nParameter2 0x00000000
Event: nCode EC_PAUSED 0xE, nResult 0x00000000, nParameter2 0x00000000
[...]
^C

The application will generate the files and convert media sample time stamps into file time.

RenderHttpMjpegVideoIntoFiles01 Sample Output

The DirectShow graph that implements the operation is the following:

RenderHttpMjpegVideoIntoFiles01 Filter Graph

The other sample RenderJpegFiles01 takes a directory path to look for JPEG files, e.g. generated by previous sample, and pushes them into DirectShow graph as a video feed. File times will be converted [back] to media sample times.

Continue reading →

How to use windowless Video Mixing Renderer Filter to show video fullscreen

The question is being asked from time to time. Everyone knows what is full screen video. Video renderers implement full screen capability since long ago through their IVideoWindow::put_FullScreenMode property, and even Filter Graph Manager exposes its own IVideoWindow interface to forward calls to filter’s implementation of IVideoWindow interface.

However, for Video Mixing Renderers, version 7 and 9, the preferred and recommended mode is windowless, where no IVideoWindow interface is available.

Note The IVMRWindowlessControl or IVMRWindowlessControl9 interface is now preferred over IVideoWindow. For more information, see Using Windowless Mode.

So in order to implement full screen mode it takes the application to attach Video Mixing Renderer filter to a private frameless window, to its entire client area and expand the window to entire monitor area.

The sample project FullScreenWindowlessVmrSample01 is illustrating this technique.

FullScreenWindowlessVmrSample01 Main Dialog

Continue reading →

How to overlay a bitmap on top of video with Video Mixing Renderer (VMR-9)

A 100-lines code snippet which illustrates how a bitmap is overlaid over displayed video with Video Mixing Renderer 9 Filter using IVMRMixerBitmap9 interface. A video clip is played (default is Windows clock.avi, but you can replace it with your longer one to see overlay is really in a loop).

http://code.assembla.com/…/VmrMixerBitmapSample01/…

VMR9AlphaBitmap AlphaBitmap;
ZeroMemory(&AlphaBitmap, sizeof AlphaBitmap);
AlphaBitmap.dwFlags = VMR9AlphaBitmap_hDC;
AlphaBitmap.hdc = Dc;
AlphaBitmap.rSrc = CRect(0, 0, 32, 32);
AlphaBitmap.rDest.left = (FLOAT) 0.75;
AlphaBitmap.rDest.top = (FLOAT) 0.75;
AlphaBitmap.rDest.right = (FLOAT) 0.95;
AlphaBitmap.rDest.bottom = (FLOAT) 0.95;
AlphaBitmap.fAlpha = 0.75;
const HRESULT nSetAlphaBitmapResult = pVmrMixerBitmap->SetAlphaBitmap(&AlphaBitmap);
ATLENSURE_SUCCEEDED(nSetAlphaBitmapResult);

With a low FPS clip like clock.avi it is clear that the overlaid image is only updated with the next “main” video frame.

IVMRMixerBitmap9 Usage Sample

Visual C++ .NET 2008 source code is available from SVN, release binary included.

MediaTools: How to manually configure filters to render M-JPEG video stream from an IP camera

Media Tools DirectShow Filters can be used to acquire, parse and decoder M-JPEG encoded video stream from an IP camera or a video server, however for a quick start it is necessary to properly register filters on system and create a DirectShow graph.

To register the filters, it is necessary to download DLLs from repository. While Acquisition.dll does not require special prerequisites installed, CodingI.dll is using Intel Integrated Performance Primitives (IPP) version 6.0.0 internally and requires its [at least] redistributables installed before DLLs are being registered using regsvr32.

Intel went further with new releases of IPP, which are incompatible with the version used to build CodingI.dll, so it is version 6.0.0 (in downloads on Intel website: version 6.0 build 0) has to be installed. Note that Intel DLLs from C:\Program Files\Intel\IPP\6.0.0.044\ia32\bin (version 6.0.0.062 is known to be also compatible) need to be on system search path, or copied to C:\Windows\system32 directory.

Once Intel IPP is prepared, it is required to register CodingI.dll using regsvr32. This registers filters and they are available in GraphEdit and for applications. It is important that on the way of constructing graph which renders video using standard video renderers it is required to specify correct resolution for video, or otherwise graph might fail to start with a message “The graph could not change state”, caused by video renderer failure to dynamically change to different (effective) resolution.

To create rendering graph, add Alax.Info HTTP Stream Source Filter from the filter list and provide camera URL in properties, e.g. http://cam15001.miemasu.net/nphMotionJPEG?Kind=1

Adding Alax.Info HTTP Stream Source Filter

Continue reading →

Private DMO

Started as Is it possible to use local component in DLL? on microsoft.public.vc.atl newsgroup. The question is to embed a custom DirectX Media Object (DMO) into executable so that it is only available to proprietary application and not to entire system and could be reused in other applications. If in particular this DMO should be available to intelligent connect, e.g. used by embedded Windows Media Player control, the solution requires that private DMO appears fully registered as full featured regular DMO.

A while ago I proposed a solution on getting COM Class/DMO embedded into executable and temporarily exposed as availble without registry registration through CoRegisterClassObject/RegisterClassObject, however in addition to COM class registration, a DMO needs to also be specifically listed as a DMO, through DMORegister API.

In order to expose private DMO to DirectShow subsystem the following steps has to be performed:

  • register COM class object as a COM class (CoRegisterClassObject) to enable its instantiation by its CLSID
  • use DMORegister API to list DMO in global list (warning, seems to be requiring write permission on HKEY_CLASSES_ROOT key)
  • have the filter graph of interest created
  • use DMOUnregister API as early as possible to unlist private DMO from global list
ATLENSURE_SUCCEEDED(__objMap_CPrivateMediaObject.RegisterClassObject(CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE));
DMO_PARTIAL_MEDIATYPE pInputMediaTypes[] = { { MEDIATYPE_Video, CPrivateMediaObject::GetXxxxSubtype() } };
ATLENSURE_SUCCEEDED(DMORegister(L"Private DMO", CLSID_PrivateMediaObject, DMOCATEGORY_VIDEO_DECODER, 0, _countof(pInputMediaTypes), pInputMediaTypes, 0, NULL));
...
ATLVERIFY(SUCCEEDED(DMOUnregister(CLSID_PrivateMediaObject, DMOCATEGORY_VIDEO_DECODER)));

The sample code/project takes an .AVI file which is a XVID video file with a FOURCC compression code changed from XVID to XXXX. The file is unplayable but there is a private DMO which accepts XXXX video and copies data as is into XVID format on its output.

A Visual C++ .NET 2008 source code is available from SVN.