winapivideodirectshowwmvdmo

How to connect a source filter to an encoder DMO?


I have a DirectShow app for generating silent videos, whose filter graph is

my video frame generator -> selectable video compressor -> AVI mux -> file writer

or just

my video frame generator -> AVI mux -> file writer

This mostly works as expected, unless the selected compressor is a DMO, in which case the pFilterGraph->Connect() call from source to compressor fails - typically with VFW_E_TYPE_NOT_ACCEPTED or VFW_E_CANNOT_CONNECT. I would like to make DMOs work too. I found a deprecated sample (AVIEncoderDShow) that I was able to tweak to compress an input AVI file with the WMV9 DMO, which seemed promising on this score. Its filter graph is

pFilterGraph->AddSourceFilter(AVI file) -> AVI splitter -> DMO wrapper for WMV -> AVI mux -> file writer

so I thought I could just swap out the source filter for my filter (or the bouncing ball DirectShow sample that it's based on). Trying that just gives the same connection failures though. The source I'm supplying is 32 bit RGB, which WMV9 should accept. What might it be stumbling on?

EDIT: The details of my preferred media type are:

majortype: MEDIATYPE_Video
subtype: MEDIASUBTYPE_RGB32
bFixedSizeSamples: 1
bTemporalCompression: 0
lSampleSize: 3145728
formattype: CLSID_KsDataTypeHandlerVideo
pUnk: NULL
cbFormat: 1128
pbFormat: 0x12ce4bf0

and the exact point of failure with VFW_E_TYPE_NOT_ACCEPTED is

hr = pReceivePin->ReceiveConnection((IPin *)this, pmt);
CBasePin::AttemptConnection(IPin * pReceivePin, const CMediaType * pmt) Line 1796   C++
CBasePin::AgreeMediaType(IPin * pReceivePin, const CMediaType * pmt) Line 1939  C++
CBasePin::Connect(IPin * pReceivePin, const _AMMediaType * pmt) Line 1728   C++
CFilterGraph::ConnectDirectInternal(struct IPin *,struct IPin *,struct _AMMediaType const *)    Unknown
CFilterGraph::ConnectDirect(struct IPin *,struct IPin *,struct _AMMediaType const *)    Unknown
ConnectFilters(IBaseFilter * pUpstream, IBaseFilter * pDownstream, IGraphBuilder * pGraph, _AMMediaType * pmt) Line 332 C++

My media type's pbFormat is set up as a VIDEOINFO, which seems to have the same structure as a VIDEOINFOHEADER but with additional data tacked on the end of it. It looks like this:

rcSource    {LT(0, 0) RB(0, 0)  [0 x 0]}    tagRECT
rcTarget    {LT(0, 0) RB(0, 0)  [0 x 0]}    tagRECT
dwBitRate   0   unsigned long
dwBitErrorRate  0   unsigned long
AvgTimePerFrame 0   __int64
bmiHeader   {biSize=40 biWidth=1024 biHeight=768 ...}   tagBITMAPINFOHEADER
    biSize  40  unsigned long
    biWidth 1024    long
    biHeight    768 long
    biPlanes    1   unsigned short
    biBitCount  32  unsigned short
    biCompression   0   unsigned long
    biSizeImage 3145728 unsigned long
    biXPelsPerMeter 0   long
    biYPelsPerMeter 0   long
    biClrUsed   0   unsigned long
    biClrImportant  0   unsigned long
bmiColors   0x0d381c60 {{rgbBlue=0 '\0' rgbGreen=0 '\0' rgbRed=0 '\0' ...}, {rgbBlue=0 '\0' rgbGreen=0 '\0' rgbRed=...}, ...}   tagRGBQUAD[256]
dwBitMasks  0x0d381c60 {0, 0, 0}    unsigned long[3]
    [0] 0   unsigned long
    [1] 0   unsigned long
    [2] 0   unsigned long
TrueColorInfo   {dwBitMasks=0x0d381c60 {0, 0, 0} bmiColors=0x0d381c6c {{rgbBlue=0 '\0' rgbGreen=0 '\0' rgbRed=0 '\0' ...}, ...} }

Solution

  • Some filters, especially multiplexers and sometimes encoders, require that you specify frame rate of the video stream. And otherwise the media types are rejected with generic error code, without a mention that frame rate is the cause.

    WMV9 Encoder DMO does accept 32-bit RGB on the input, so you should try it out with a positive AvgTimePerFrame value in VIDEOINFOHEADER structure of the media type:

    enter image description here