Archive for the 'Seriously' Category

Published by Roman on 05 Aug 2009

Another third party DirectShow filter that may break your very own application

One of the DirectShow’s most important features is Intelligent Connect, which allows Filter Graph Manager to build graphs out of independent filters trying to connect them together including options to fall back to originally non-preferred alternatives and so on.

It is however important that filters are properly registered with the Filter Mapper. For the developers to do so, there are special guidelines for registering filters. Unfortunately it is not always the case that developers carefully take them into consideration, and so we have compatibility issues. In particular a faulty filter may break an application it is not intended to be used in in first place. Some examples were already mentioned: Ahead Nero NeResize Filter, FFDShow Video Decoder Filter, PICVideo MJPEG Decompressor Filter.

As we are moving on, the brilliant collection is expanding. New entry on the list:

MainConcept Color Space Converter Filter

Friendly Name: MainConcept Color Space Converter
File Name: mccsc.ax
File Version: 1.0.103.60203 (note that other versions might be hopefully free from this problem)
Merit: 0×00600000 (MERIT_NORMAL)

Symptoms: registers itself under higher merit and takes over standard Color Space Converter Filter. As such, might be used in various applications including those, where it is not supposed to appear. Does not fully implement functionality of the filter being replaced and can crash breaking expected operation of third party application.

Published by Roman on 31 Jul 2009

XviD video encoder and window messages from a worker thread

While encoding video, Xvid Video Encoder provides an optional status window displaying information on encoding progress.

Xvid Encoder Status Window

Since streaming typically takes place in a worker thread, with possibly no windows at all, and no message pump, the window is to be created on GUI thread and the encoder needs to synchronize progress updates with the window.

Such synchronization is a typical point where a deadlock can occur. Carelessly a window message may be sent in a blocking way so that worker thread is waiting while the message is processed on the window thread. If this sending happens at the moment of GUI thread trying to stop worker thread, a deadlock takes place. This problem often comes up when message sending takes place indirectly, e.g. being wrapped by an API call, such as SetWindowText, or as it can be seen below IsDlgButtonChecked.

In order to avoid deadlocks one should never SendMessage from a worker thread. Instead there should be a PostMessage with possibly a wait function which waits for either synchronization event (set by window) or worker thread termination request:

{
  CLock Lock(m_CriticalSection);
  m_sText = sText;
  m_SynchronizationEvent.Reset();
}
PostMessage(...);
HANDLE phObjects[] = { ThreadTerminationEvent, m_SynchronizationEvent };
const DWORD nWaitResult =  WaitForMultipleObjects(..., phObjects, ...);
if(nWaitResult == WAIT_OBJECT_0 + 1 ) // m_SynchronizationEvent
{
  CLock Lock(m_CriticalSection);
  // ...
}

Back to Xvid encoder: trying to abort encoding process, the application deadlocks. Thread checking shows worker thread state:

Xvid Video Encoder Deadlocked Thread Call Stack

That is, a described deadlock in action.

While it is already made this way letting deadlock occur, is there any workaround to avoid locking? Yes, there is. Stopping encoding, GUI thread should keep pumping messages while waiting for worker thread termination. Before closing worker thread handle, one needs to signal the thread to terminate and wait using thread handle with MsgWaitForMultipleObjects, so that messages possibly sent while terminating the thread are dispatched to target windows.

Published by Roman on 16 Jul 2009

Sharing Memory Allocators while at the same time Handling Dynamic Media Type Changes

Sharing memory allocators between input and output pins is an important concept to keep performance of filter graph. Unlike more frequent scenario with different allocators, a filter (referred to as “middle filter” below) which has equal media types on input and output pins has an advantage to avoid memory-to-memory copy operation for every frame processed, by delivering downstream the buffer obtained from an upstream filter. With a high resolution video, at high rate, multiple streams running simultaneously this is the expense one would try to avoid for performance reasons.

Memory allocators are (or can be) shared by well known filters, such as Sample Grabber Filter, Infinite Tee Pin Filter and in-place transformation base filters (CTransInPlaceFilter Class).

Still handling Dynamic Format Changes (not only from video renderer filter) filters that share memory allocators may run into the problem of being notified of media type change. Because allocator are typically owned by another filter (e.g. Video Mixing Renderer Filter) and originally its buffer is queried by an upstream filter, the upstream filter obtains allocated buffer independently from the middle filter that shares memory allocators. If the upstream filter decides to never deliver this buffer, however the buffer has a media type attached (see AM_SAMPLE2_PROPERTIES::pMediaType), there is no way for the middle filter to learn about dynamic format change completed.

As a workaround for handling Format Changes from the Video Renderer, when resolution is not changed and it is only stride which might be extended, middle filter might be checking data size in lActual field and learn about the change from an increase in this value.

To be reliably notified on media type change the middle filter is to take extra measures while sharing the allocator. Instead using raw allocator obtained from one pin on another pin (typically output pin’s allocator to be used on an input pin), middle filter may be using an internal proxy object, which implements IMemAllocator interface and forward calls to internal IMemAllocator, obtained originally. Additionally to that, the proxy can check for attached media types on every buffer taken from the allocator, and once the change is noticed – at the moment upstream filter is requesting the buffer – the proxy has a timely chance to remember the new media type so that in the following IMemInputPin::Receive call this media type can be checked for the case upstream buffer decided to not deliver the buffer with attached media type.

if(IsSharingMemAllocators())
{
    // ...
    ATLASSERT((InputMediaSampleProperties.pMediaType != NULL) ^ !(InputMediaSampleProperties.dwSampleFlags & AM_SAMPLE_TYPECHANGED));
    {
        CRoCriticalSectionLock DataLock(GetDataCriticalSection());
        const CObjectPtr<CProxyMemAllocator>& pInputProxyMemAllocator = m_pInputPin->GetProxyMemAllocatorReference();
        CMediaType pMediaType;
        if(pInputProxyMemAllocator && pInputProxyMemAllocator->GetDynamicallyChangedMediaType(pMediaType, TRUE))
        {
            m_pInputPin->SetMediaType(pMediaType);
            m_pOutputPin->SetMediaType(pMediaType);
            // ...
        }
    }
    if(InputMediaSampleProperties.pMediaType)
    {
        m_pInputPin->SetMediaType(InputMediaSampleProperties.pMediaType);
        m_pOutputPin->SetMediaType(InputMediaSampleProperties.pMediaType);
        // ...
    }
    DeliverMediaSample(pMemInputPin, pInputMediaSample);
}

Published by Roman on 30 Jun 2009

Ahead Nero’s NeResize DirectShow Filter

Another example of a negligence with a cost of incompatibility and enormous amount of support time. Ahead Nero installs a number of DirectShow filters into $(Program Files)\Common Files\Ahead\DSFilter directory. One of the files is NeResize.ax and it hosts a Nero Resize filter. Let us take a closer look:

CLSID: {30002E0C-C574-481E-A5DE-90AE54A79E10}
Merit: 0×00400000 (MERIT_UNLIKELY)
Input Pin’s Media Type: major type GUID_NULL, subtype GUID_NULL
Output Pin’s Media Type: major type GUID_NULL, subtype GUID_NULL

The filter is clearly a video filter:

Ahead Nero Resize Filter's Property Page

So the filter register itself under a merit that allows taking it during Intelligent Connect, it registers using media type wildcard which is clearly widely than the filter can affectively operate with and the most interesting part is: with certain video media types the filter crashes (memory access violation) during pin connection negotiation process. That is, inaccurate filter may be crashing third party software it has nothing to deal with at all.

*** Unhandled Exception
Process: 0x000001d4, Thread: 0x00000ce4, Date: 6/29/2009, Time: 11:20:56 AM, Application: C:\Program Files\...
Module: C:\..., Product Version: 1.7.1.1, File Version: 1.7.1.20014, File Time: 23.06.2009, 19:02
Code: 0xc0000005, Flags: 0x00000000, Address: 0x05fc6c65
Parameters: 0x00000001, 0x15be9030

** Call Stack
NeResize!05fc6c65 DllUnregisterServer +21909 @05fc0000
NeResize!05fc7888 DllUnregisterServer +25016 @05fc0000
NeResize!05fc7204 DllUnregisterServer +23348 @05fc0000

Additionally to that the filter does not allow its insertion in debugging environment, and it seems even with Visual Studio running without a debugging session active. Which means that developer may be unaware of issues until incompatibility comes up at a later stage such as testing, or at production site.

It is not the first Nero filter which is bringing real problems. Basically any user who want to keep his system far from issues while still having Nero installed, needs to do find $(Program Files)\Common Files\Ahead\DSFilter directory and immediately rename it to some ~DSFilter in order to invalidate all Nero filters registration.

A few quotes from Guidelines for Registering Filters:

Avoid specifying MEDIATYPE_None, MEDIASUBTYPE_None, or GUID_NULL in the AMOVIESETUP_MEDIATYPE information for a pin. IFilterMapper2 treats these as wildcards, which can slow the graph-building process.

Nero Resize does specify and obviously slows the system down.

Choose the lowest merit value possible. Here are some guidelines:

Special purpose filter; any filter that is created directly by the application: MERIT_DO_NOT_USE

Nero Resize uses higher value and thus affects proper applications.

Software developers will be safer to prevent from DirectShow Filter Graph Manager considering the buggy filter to be used during Intelligent Connect by implementing IAMGraphBuilderCallback interface.

Published by Roman on 27 May 2009

IFSEC 2009

From IFSEC 2009, the meeting place for security industry:

cctvdirect.com at IFSEC 2009

spacecom.com.au at IFSEC 2009

Published by Roman on 21 Feb 2009

Confusing AUDIO_STREAM_CONFIG_CAPS

I don’t have any idea who makes software nowadays, but how can it expected to be reliable?

Intel DG33FBC motherboard, onboard Realtek ALC888 High Definition Audio. I am tracing AUDIO_STREAM_CONFIG_CAPS capabilities reported by onboard audio capture board, one of them:

AM_MEDIA_TYPE:

majortype {73647561-0000-0010-8000-00AA00389B71}, subtype {00000001-0000-0010-8000-00AA00389B71}, pUnk 0x00000000
bFixedSizeSamples 1, bTemporalCompression 0, lSampleSize 4
formattype {05589F81-C356-11CE-BF01-00AA0055595A}, cbFormat 18, pbFormat 0x002911a8
pbFormat as WAVEFORMATEX:
  wFormatTag 1
  nChannels 2
  nSamplesPerSec 8000
  nAvgBytesPerSec 32000
  nBlockAlign 4
  wBitsPerSample 16
  cbSize 0

AUDIO_STREAM_CONFIG_CAPS:

guid {73647561-0000-0010-8000-00AA00389B71}
MinimumChannels 1, MaximumChannels 2, ChannelsGranularity 1
MinimumBitsPerSample 8, MaximumBitsPerSample 16, BitsPerSampleGranularity 8
MinimumSampleFrequency 11025, MaximumSampleFrequency 44100, SampleFrequencyGranularity 11025

Media type sampling frequency is 8 KHz (correct) but associated capabilities structure still report different sampling rates and granularity (crap), it is in fact 11025..44100 Hz for all capabilities, including those with sampling frequencies from a different row.

Published by Roman on 16 Feb 2009

Visual Studio .NET 2008 freeze on opening a setup project

Some time ago I faced an annoying problem with a freeze of Visual Studio opening a solution with a Setup Project. I found that the problem was related to setup projects (.vdproj) that time and it was something with Visual Studio update, but I was of an opinion that Visual Studio .NET 2008 has problems opening projects created by version 2005. Compatibility or something… however the problem appeared that it cannot even create a new Setup Project with again a freeze.

Luckily, I found a hint on MSDN Forums, and although the solution/workaround was not detailed enough, it worked for me from the first guess. Here it goes:

  1. Start Component Services (dcomcnfg) from command line
  2. Right-click My Computer, and click Properties:

    Component Services, My Computer, Properties

    In the popped up window uncheck additional security box:

    My Computer Properties

It appears to be sufficient for the Visual Studio .NET 2008 to start loading .vdproj projects again.

Next »