Thursday, 18 April 2013

Working with D3D9 device Reset()

...lost context and going fullscreen!

At work I got the opportunity (sigh) to work with some DirectX rendering for video pipelines.

A lot of fun was spent in trying to make the graphics card behave correctly during a context restore. When switching fullscreen or changing modes there are very precise steps you must follow or you get very cryptic error messages (by the way using M$ tools is no fun at all and I'll explain why) .

First of all when you switch to fullscreen you need to call Reset() on your device with the new backbuffer size, which *must* correspond to one of the resolution supported by your device (and don't forget to set the refresh rate too).

Before doing so you absolutely need to delete any surface, shader and whatever you allocated with a Get* method, using a proper Release() call. Beware *not* to delete your d3ddevice [1]. Then you just recreate all surfaces and you are done, it make sense to reuse the same initialization code for this purpose.

If you don't do this procedure you can get different results, but usually you'll just get a lot of D3DERR_DEVICELOST after a Present(), and only after it (so don't bother checking for this error anywhere else). Other rendering functions such as StretchRect() will just silently fail.

In order to avoid leaks of any kind and check for other errors you might be tempted to use DirectX Control Panel and turn on the Debug version of DirectX. This might work, but beware that on some architectures (I'm looking at you, NVIDIA ION) you might get a lot of exceptions (especially in within Reset()) that make no sense at all [2]. While normally these reports are useful and the breaks help you find mistakes, sometime it just get frustrating when there is a bug on someone else's code.

So if you get desperate in debugging a perfectly working restoration code, just try disabling debug mode or run your code on another architecture...

[1] Actually you can delete the d3ddevice, but then you don't have to call Reset() and have to recreate both the device and the surfaces again. It works but screen glitches a lot and it's a plain waste of resources.
[2] Error such as "Lost Device Due to Display Uniqueness Change" and "Could not get exclusive mode when we thought we could". If you Google them you'll get a lot of information on how to properly do a context restore, but the solution might be closer than you thing.

Tuesday, 16 April 2013

Finally one libvlc_video_set_format_callbacks() example

libVLC new (2.0) API for video size and chroma (libvlc_video_set_format_callbacks) is much more powerful than libvlc_video_set_format. It allows either to get video size and chroma dynamically so that your rendering pipeline can adapt, or to modify such values to get the values you need.

However, I find it a little more complicated to use and spent some time looking for an example. Apparently I am not alone, so I'll share my finding.

The main source example I found is from FBVLC, a web browser plugin based on VLC. You can read the full source here:

Basically you need to create two functions with this exact signature
static unsigned video_setup_cb(void **opaque, char *chroma, unsigned *width, unsigned *height, unsigned *pitches, unsigned *lines);

static void video_cleanup_cb(void *opaque);

and as the names go initialize all variables in the first function and cleanup in the second one. You can find sample implementation in the previous source code, under the name of
video_format_cb and video_cleanup_cb.

I spent some time in selecting the right chroma to adopt (and missed the fact that you had to memcpy there) for my standard h264 420 file "RV32" was working fine. Also the pitches variable is important, it represents the the video width in luma components, so for 420 it corresponds to width * 4.

All the projects here are under a Creative Commons 3.0 licence! You can use and distribute them as you like (just quote the author so he knows his work is not useless)!

If you wish to get in touch with me write at