Older posts Newer posts Buggy VirtualDub filters
August 16, 2012
The same day I was dealing with VDFilter issue described in previous post
I ran Video Enhancer (which also uses VDFilter), picked a random VirtualDub
plugin and tried to process one file. Suddenly I've got a message telling me
about an exception arised inside that VirtualDub plugin. Most VD plugins have
been here for a while and are known for thair speed, stability and high quality,
so I immediately decided the problem was in VDFilter, our DirectShow wrapper
for those plugins. I started a debug session to find what caused the exception
and luckily the source code for that plugin was available on its web page.
The plugin is called Flip 1.1 (ef_flip.vdf from the big collection of filters by
Emiliano Ferrari). To my surprise however I've found the bug quite fast and it was
not in VDFilter, this time it was in the plugin itself. Source code of the main
routine is pretty short:
void Rotate180 (Pixel32 *dst,Pixel32 *tmp,const int pitch,const int w,const int h,
const FilterFunctions *ff)
{
Pixel32 *a,*b;
int i;
a= dst;
b= dst + (h*pitch);
int alf = h/2;
if (h&1) alf++;
for (int j=0; j<alf; j++)
{
_memcpy (tmp,a,w*sizeof(Pixel32)); // tmp= a;
a+= w;
for (i=0; i<w; i++) *a--= *b++; // a=b
for (i=0; i<w; i++) *b--= *tmp++; // b=tmp
tmp-= w;
a+= pitch;
b-= pitch;
}
if (!(h&1)) // even lines
{
_memcpy (tmp,a,w*sizeof(Pixel32));
a+= w;
for (i=0; i<w; i++) *a--= *tmp++;
}
}
Take a look at the two red lines. h is the image height
and pitch here is equal to the number of Pixel32 values in one row of image, so
h*pitch is the number of pixels in whole image. At first pointer b points
to dst + (h*pitch), i.e. the first byte outside the image buffer! And then
in the loop it's being read and then incremented to point even farther from the end
of the buffer. It didn't cause crashes in VirtualDub because for some reason memory
after the image buffer always belonged to the application, however it did read garbage
there so the first line of "rotated" image should contain garbage after applying this
filter. In case of VDFilter and its use in Video Enhancer one line of memory after the
image buffer not always completely belonged to the program, so for small frames it
worked ok but with a larger frame the b pointer walked too far and caused
a segmentation fault which was caught as an exception and caused our wrapper to
show the message box.
It may be the case that author assumed pitch to be a negative value, however
this assumption doesn't look correct. Here's a quote from VirtualDub Plugin SDK:
"Bitmaps can be stored top-down as well as bottom-up. The pitch value value is positive
if the image is stored bottom-up in memory and negative if the image is stored top-down.
This is only permitted if the filter declares support for flexible formats by returning
FILTERPARAM_SUPPORTS_ALTFORMATS from paramProc; otherwise, the host ensures that the
filter receives a bottom-up orientation with a positive pitch, flipping the bitmap
beforehand if necessary."
Lessons learned: 1) some VirtualDub plugins, even very simple ones, may contain bugs.
2) pointer arithmetic requires a lot of attention to be used correctly.
tags: video_enhancer
Working with old Video Renderer
August 15, 2012
There are several different video renderers available in DirectShow. When you look at
the list of DirectShow filters you can see two filters named "Video Renderer" among
others.
One of them, with GUID starting with "6BC1..", is VMR-7 (video mixing renderer),
it is the default video renderer on Windows XP and later. The other, with GUID
starting with "70E1..", is the old Video Renderer used by default on earlier versions
of Windows. This filter may bring some surprises even today.
Recently someone reported a crash in VDFilter, our
DirectShow wrapper for VirtualDub filters. He sent us a .grf file, a saved graph
which forced the crash when run. In that graph our filter was connected directly to
the old Video Renderer. After building a similar graph I could reproduce the case,
indeed something went wrong there. First minutes of debugging showed that memory buffer
of a media sample provided by video renderer to upstream filter was smaller than
size of data our filter tried to write here. How could this happen? Usually when two filters
agree on connection at some point the downstream filter (which will receive data) calls
upstream filter's DecideBufferSize() method to ask how big the data samples will be.
It uses this value to create buffers for the samples and provide the buffers to upstream
filter to fill with data. Video Renderer does that, however during playback if its
window doesn't fit into the screen or gets resized Video Renderer tries to renegotiate
connection type and offers media type for the connection with different video dimensions
- according to its window size. If upstream filter accepts such media type then
Video Renderer starts to provide buffers of changed size even without calling
DecideBufferSize(). Our filter wasn't ready for this sneaky behaviour, it continued
to provide amount of data specified in last call to DecideBufferSize(), which caused
overflow of the new shrinked buffers provided by Video Renderer. We had to change
our filter to refuse connection type changes while running (otherwise it would have
to include a resizer to rescale output images to the new dimensions given by
Video Renderer).
Moral of this story: when you create a DirectShow transform filter don't expect output samples
to be the same size you requested in DecideBufferSize() and be ready to be asked for
connection type change during playback!
tags: directshow
Deciphering .grf files
August 10, 2012
In DirectShow we work with graphs of filters. We build them in tools like GraphEdit
or GraphEditPlus while
experimenting and then we build them in our own code. Some parts of graph can be
built automatically by DirectShow's intelligent connect procedure which selects
filters according to their ability to handle given mediatypes and their priorities.
To see details of graph built by our code we can save the graph to a file and then
open it in an editor. Loading a graph from a file is done by calling
IPersistStream::Load() method which performs all the loading logic and either succeeds
or fails, there's not much control over its actions. If the graph was created on a
different machine or the same machine but in different circumstances and
it mentions some filters, devices or even files not available at the moment of
loading, then loading fails and the graph file is pretty much worthless.
Not anymore! Here is a small utility which can read a .grf file and translate it
to plain text containing most of useful information. Now you can easily see
graph details (filters, connections, mediatypes, including all basic info for video
and audio streams) even if you don't have all the mentioned filters and files.
grfdump.zip (134 KB)
It's a command line tool, you run it like
grfdump.exe file.grf > plain_text.txt
and get something like:
Read more...
tags: directshow
Reviving this blog
August 09, 2012
It's been a while since I wrote something meaningful here. Partly because
I've already got a personal blog
here (in Russian language)
and partly because I wanted to upgrade the blog engine first to include
tags and pagination at least. Now it's finally done (blog engine has doubled
its size and reached a whole hundred lines of OCaml code ;) ) and I'm going
to write here more often. Mainly programmer stuff about DirectShow, video
processing, compression etc.
Sales continued
June 25, 2011
We have switched our payments processor and now use Avangate to accept
payments in different forms. All the products can now be purchased online
without any delays.
Sales through RegNow temporarily unavailable
June 23, 2011
Due to a temporal problem all retail sales through RegNow (payments processor
we've been using for last 5 years) are currently unavailable. We're working
on a solution. Our products are try-before-you-buy, so don't be in a hurry,
take your time to evaluate them, and when sales will be active again you'll
be able to purchase licenses for full versions.
How many frames super resolution needs?
December 27, 2010
As you already know, super resolution is a method to upsample video which for each frame
uses information from neighbour frames. I was asked many times: how many frames does it use?
Well, our SR implementation is "streaming": frame in - frame out. Internally for each new frame
it uses its own result for previous frame, i.e. to upsample frame N it uses upsampled frame N-1
for which frame N-2 was used, for which frame N-3 was used and so on. In this sense all previous
frames are used to make the current one. However video is changing from frame to frame and as
new information gets accumulated old information gets forgotten. And when processing frame 100
there is hardly anything left from frame 1. So how many frames are really used?
To answer this question we took some files from our
video resize shootout
and upsized them 2 times first the whole files, then starting from frame 20, then starting from frame 40 etc.
Then we measured PSNR for each frame and looked at the charts.
Read more...
tags: super_resolution
Resizing video 4x
December 14, 2010
Our super resolution implementation internally upscales video 2 times.
If you ask
Video Enhancer
or
Super Resolution plugin
to upsize video 4 times
using one instance of SR, it will upsize it 2x with super resolution approach
and then 2x more using just a high quality image resampling method. For this
reason we usually recommended to make a chain of 2 SR instances, each upsizing
2 times. This is what we did in our
comparison.
But are two instances really required?
To answer this question we took 10 videos from the comparison and upsized them
4 times using just one instance of SR. Here are the results in terms of PSNR:
Read more...
tags: super_resolution
Digital Video and Audio in 30 minutes
November 1, 2010
A very good explanation of digital video and audio basics in just
30 minutes of video:
https://xiph.org/video/vid1.shtml
Requires a modern browser to watch, I guess (it plays fine in my Firefox 3.6).
Disabling Windows Media Player
October 26, 2010
On my office PC I'm running Windows 7 with automatic updates turned on.
It seems that recently it updated Windows Media Player (WMP) and when I tried
to play an AVI file, instead of my usual player of choice (Media Player Classic
installed with K-Lite Codec Pack) WMP popped up and offered to configure
itself. It showed a list of different file extensions which it could play
and some of them, including AVI, were checked by default and were impossible
to uncheck! Moreover, when I ran Media Player Classic and asked it to be
the default player for AVI files it couldn't do it anymore: the system returned
WMP to be the default AVI player. That was horrible because I can't stand
Windows Media Player. So I looked for a way to uninstall it, but it's not
in the list of programs to uninstall. Luckily, everything's not lost yet
because there is an easy way to disable WMP without any registry hacks.
Read more...
Older posts Newer posts
|