Handling Dynamic Format Changes
Microsoft DirectShow 9.0 |
Handling Dynamic Format Changes
Video renderers in DirectShow accept only video formats that can be drawn efficiently. For example, the Video Renderer filter accepts only the RGB format that matches the current display device mode (for example, RGB565 when the display is set to 16-bit color. As a last resort, it also accepts 8-bit palettized formats, as most display cards can draw this format efficiently. When the renderer has Microsoft® DirectDraw® loaded, it might later ask the source filter to switch to something that can be written onto a DirectDraw surface and drawn directly through display hardware. In some cases, the renderer's upstream filter might try to change the video format while the video is playing. This often occurs when a video stream has a palette change. It is most often the video decompressor that initiates a dynamic format change.
An upstream filter attempting to change formats dynamically should always call the IPin::QueryAccept method on the renderer input pin. A video renderer has some leeway as to what kinds of dynamic format changes it should support. At a minimum, it should allow the upstream filter to change palettes. When an upstream filter changes media types, it attaches the media type to the first sample delivered in the new format. If the renderer holds samples in a queue for rendering, it should not change the format until it renders the sample with the type change.
A video renderer can also request a format change from the decoder. For example, it might ask the decoder to provide a DirectDraw-compatible format with a negative biHeight. When the renderer is paused, it should call QueryAccept on the upstream pin to see which formats the decoder can provide. The decoder might not enumerate all of the types that it can accept, however, so the renderer should offer some types even if the decoder does not advertise them.
If the decoder can switch to the requested format, it returns S_OK from QueryAccept. The renderer then attaches the new media type to the next media sample on the upstream allocator. For this to work, the renderer must provide a custom allocator that implements a private method for attaching the media type to the next sample. (Within this private method, call IMediaSample::SetMediaType to set the type.)
The renderer's input pin should return the renderer's custom allocator in the IMemInputPin::GetAllocator method. Override IMemInputPin::NotifyAllocator so that it fails if the upstream filter does not use the renderer's allocator.
With some decoders, setting biHeight to a positive number on YUV types causes the decoder to draw the image upside down. (This is incorrect, and should be considered a bug in the decoder.)
Whenever a format change is detected by the video renderer, it should send an EC_DISPLAY_CHANGED notification. Most video renderers pick a format during connection so that the format can be drawn efficiently through GDI. If the user changes the current display mode without restarting the computer, a renderer might find itself with a bad image format connection and should send this notification. The first parameter should be the pin that needs reconnecting. The Filter Graph Manager will arrange for the filter graph to be stopped and the pin reconnected. During the subsequent reconnection, the renderer can accept a more appropriate format.
Whenever a video renderer detects a palette change in the stream it should send the EC_PALETTE_CHANGED notification to the Filter Graph Manager. The DirectShow video renderers detect whether a palette has really changed in dynamic format or not. The video renderers do this not only to filter out the number of EC_PALETTE_CHANGED notifications sent but also to reduce the amount of palette creation, installation, and deletion required.
Finally, the video renderer might also detect that the size of the video has changed, in which case, it should send the EC_VIDEO_SIZE_CHANGED notification. An application might use this notification to negotiate space in a compound document. The actual video dimensions are available through the IBasicVideo control interface. The DirectShow renderers detect whether the video has actually changed size or not prior to sending these events.