DirectShow filters pass data between their pins using COM interfaces. In theory any transport interface can be established between two pins: the data does not need to pass through main memory if there is a more efficient route. Four transport mechanisms are in common use:
- IMemInputPin: the normal transport in use between most pins. The output pin queries for this interface on the input pin and calls the Receive method to deliver buffers. Both buffers and buffer allocators are described by COM interfaces (see below).
- IAsyncReader: a pull interface used between parsers and source filters in which buffers can be requested out of order by the receiving filter instead of pushed by the source. See the Q & A section for more details.
- Kernel streaming: WDM streaming filters are represented by proxy filters in DirectShow filter graphs: two of these filters can agree to transport data directly between their corresponding kernel-mode components when they are connected directly together.
- IOverlay: used when the image is overlaid onto the video window instead of delivered to the renderer. In this case the video renderer filter will still own the video window, and the upstream filter uses IOverlay to control its overlay of the decoded image onto the video window.
This was originally for hardware decoders; it has now largely been superseded by DXVA.
DirectShow is designed to make filters as lightweight as possible so developers can make use of several components where previously a monolithic solution was required. To this end, the connection and streaming architecture has to minimise the cost of additional connections: in particular, unnecessary data copies must be avoided.
DirectShow achieves this by making both the buffer allocator and the buffer itself a COM object and providing negotiation of both allocator properties and the allocator itself. The output pin receives suggestions about allocator properties such as buffer size, number of available buffers and buffer alignment from the input pin, and then decides whether to use the input pin's allocator or its own. The application can also provide allocator properties if it wishes to control latency, for example. Having selected an allocator, the output pin will call the allocator's GetBuffer method to get a buffer, represented by an IMediaSample interface. This object contains properties associated with the buffer (such as start and end time stamps) and buffer location and size.
As an example, consider the case of video decompression to a DirectDraw surface. In this case, buffer negotiation will result in the following behaviour
- the source filter will define a series of large, sequential buffers and will fill these from the file and pass them to the parser
- the parser will find the chunks of video data in the buffers, and will pass to the decoder IMediaSample objects that point into the larger buffer, without copying the data
- the decoder will obtain an output buffer from the video renderer: this will be a pointer to the DirectDraw surface
- the decoder will decode from its source buffer (where the file was read) into the DirectDraw surface that is its output buffer.
- An overview of the DirectShow filter architecture
- The filter graph manager and plug-in distributors
- How the filtergraph manager builds graphs
- Media types
- Data transports
- A technical Q & A for developers
- What is IAsyncReader?
- WDM Streaming