Multiple Windowless Video Mixing Renderers (VMR9) Sample

This is a begged MFC code for multiple windowless video renderers. MFC project, two independent video renderers hosted by the same parent window (actually through owned controls but this makes no major difference), VMR9 in windowless mode.

Image001

(this expects C:\Windows\clock.avi file to be available which is no longer the case after Windows XP – simply copy any AVI there as a replacement)

There are no WM_PAINT/WM_ERASEBKGND handlers, IVMRWindowlessControl9::RepaintVideo calls and other basically required code, instead a minimalistic snippet to make video rendered the requested way.

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

Performance

> How do you test performance?

I don’t. I just believe in it.

This is actually what we have here but still we have managed to deliver software that gives more frames per second than rivals. Why? We hopefully knew what we did in first place. According to one of our partner hardware vendors, there are only two software packages which could render multiple megapixel video feeds at the rates cameras can provide, the ours one and another one with the track leading to sources in Eastern Europe…

Disappointment with Magellan MapSend Lite

I was recently at an autosport event under the aegis of FIA, where I leased my Magellan eXplorist 600 Europe unit to be used in the off-road race/baja (or “rally raid”) as a helper navigation device (the primary navigation for pilots is their roadmap in a hard paper version). Immediately before the rally the organizer was loading the track into pilot’s GPS and for the Magellan GPS owner it has always been an additional headache. First of all, most GPS units are Windows Mobile based or Garmins. Magellan is a rare bird and it was not the first time when they were just unable to load a track into it. I don’t even mention USB cable, which is buggy enough that only the device owner (who is also an advanced PC user) can make it work from time to time. Loading to SD card is also a problem.

However it would be the only problem if Magellan would provide satisfactory software. I used to make a few tools myself for frequent tasks and track log conversion is among them. But I am also using MapSend Lite to visualise tracklogs on map, correct, modify tracks etc. Earlier and this time again I had a problem loading a track into MapSend Lite for ridiculous reason. Once loaded most of the track points disappear.

Disappointment was the feeling to say the least. I am making software myself: codecs, performance, sophisticated format conversions, bugfixes and workarounds, maintaning version compatibility, third party components and stuff – all this myself. And from this point of view I don’t see any rocket science in getting damn track log loaded into map management software. Still the reality is that track log points disappear just because… they have the same timestamp. I had to manually add .01 to each timestamp in text editor to make the track log file valid for Magellan software! Maybe it is not quite correct that points don’t have valid time, I can understand this, but still this is the track and longitude and lattitude differ from point to point so why the hell software from leading vendor would drop points that have duplicate time – I could not accept any justification for this. With a $600 worth GPS device I would expect this be handled more adequately in software.

I would also wish eXplorist could follow track while recording a new one but frankly after disappearing points thing I can see that it is too much to ask from Magellan, basically it is the impossible. I am afraid there is no way I am going to have another piece of hardware from Magellan ever soon.

A bright and diverse world of HDD failures

Yesterday there was a support request on another weird problem which was eventually forwarded to me for investigation. The symptom was “application configured as Windows service does not start and shows “Starting” in services console all the time”. The case did not look difficult as the symptom clearly indicates a freeze or deadlock inside service, but the task is anyway to find the reason and make it fast.

The symptom was exactly the same if software was started as a regular application. Luckily I already have the tool available, ProcessSnapshot, to troubleshoot things easily. The call stack indicated that software froze inside CreateFile function and further investigation revealed that it was a particular drive which was causing the problem. This was a digital video recording server with several HDDs attached building up a total video archive capacity of over 7 terabytes.

So basically the job was done but what was particularly interesting: the drive was still accessible from Windows Vista shell explorer, however there was a noticable delay opening a subdirectory. I was trying to find an evidence of HDD failure in system event logs but there were none. The drive did looks healthy in system information and logs, shown unreasonable delay but still was openable when browsing directory, and was completely freezing an application which attempted to write to this drive. And as it is natural in case of such symptoms, the first suspect is software and it was us to find the real reason.

… I appreciate all the support. It’s working very nicely again. I think I have a faulty 1.5 Tb drive (caution with those drives – I heard on the news that they’re failing).

By the way, the drive was Seagate Barracuda 7200.11 SATA 3Gb/s 1.5-TB Hard Drive (ST315003)

Crap Around the World – PICVideo MJPEG Decompressor

Yesterday I received a complaint from a Most Important Customer about a weird problem on a few of their digital video recording servers. The problem was that a new version of software, client part, would out of a sudden auto-close without any notice. The problem was quite persistent and basically of not a difficult kind because such fatal problems are automatically logged with a descriptive enough log to identify the cause in an extremely effective way. However the log files appeared to be empty. Another unexpected part was that a few systems showed the issue while the other did not and software worked in a quite expected and stable way there.

After a couple of phone calls and setting up remote access using TightVNC and port forwarding I could see this myself and it was obvious that there is an exception, such as memory access vioaltion, which takes place however on a thread created outside of my code and runnning without a proper guarding section to at the very least catch the exception and log its call stack. The visual symptoms led to supposition that it is something DirectShow related and chances are high that it is either a hardware acceleration issue, or a software compatibility issue. Luckily, hardware acceleration assumption is easy to eliminate by switching off, letting it run without and seeing if there is any difference. There was not.

Then it appeared that while these system were close to clean installation state, there was another DVR software installed also, to be used for tasks not covered by our software. And my first guess was if it installed certain DriectShow filter of the crappy kind, which could interfere with our award winning software, the best of the best. A quick test of renaming “C:\Program Files\Another-DVR” into a different name making all contained binaries unopenable by path showed that nothing changed essentially. So it was GraphEdit, which was downloaded there and a list of installed filters was insepected visually.

There were a few filters that was present in the system but which were obviously installed additionally to the system, as a part of Another-DVR product or in a different way. There was a few filters by I. and then my look stumbled on something which I immediately thought of “That’s It!”. Well, taking into consideration time spent on the problem it was rather “That’s Fucking It!”.

A rename of the hosting file pvmjpg21.dll in %WINDIR%\system32 immediately fixed the problem! Oo-omm-m “PICVideo MJPEG Decompressor” by Pegasus Imaging Corporation, crap! It was one of those moments sung of by Fort Minor:

This is twenty percent crap, eighty percent lame
And a hundred percent reason to remember the name!

However, let us what was going on there. A quick look at the registration information makes it clear the video decoding bastard registered itself under MERIT_PREFERRED (0x00800000) merit and generic MEDIATYPE_Video/MEDIASUBTYPE_NULL media type. Why on earth a properly made codec would claim to be able to decode any video as prefered software? It obviously adds overhead to the entire DirectShow subworld on that system by poking its pin into anything that moves without a proper luck to actually connect.

However, it would be just an overhead, maybe even unnoticable, if the bastard was a thread safe library. But it was unfortunately not. Since my software starts showing multiple video feeds simultaneously, this piece of junk was simultaneously instantiated in multiple threads and just crashed the entire process.

P.S. Bonus: “pvmjpg21.dll crash” on Google

DirectSound play buffer notification (IDirectSoundNotify8)

IDirectSoundNotify8 is an interface to get notified on playback on capture audio buffer reaching certain position in the buffer. It is a must thing when implementing ring buffers with new data continuously added to the buffer for seamless playback (continuously copied from in case of capture).

This project is a minimalistic C++ sample code to illustrate the API. To initialize the DirectSound subsystem it is required to provide a window handle, which is created using ATL’s CWindowImpl (CMessageOnlyWindowImpl).

...
ATLENSURE_SUCCEEDED(DirectSoundCreate8(NULL, &pDirectSound8, NULL));
...
ATLENSURE_SUCCEEDED(pDirectSound8->SetCooperativeLevel(Window, DSSCL_PRIORITY));
...
ATLENSURE_SUCCEEDED(pDirectSound8->CreateSoundBuffer(&BufferDescriptor, &pDirectSoundBuffer, NULL));
...
CComQIPtr<IDirectSoundNotify8, &IID_IDirectSoundNotify8> pDirectSoundNotify8 = pDirectSoundBuffer;
...
ATLENSURE_SUCCEEDED(pDirectSoundNotify8->SetNotificationPositions(g_nPositionCount, pPositionNotify));
ATLENSURE_SUCCEEDED(pDirectSoundBuffer->Play(0, 0, DSBPLAY_LOOPING));

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.