The IQualityControl interface defines quality messages and allows a quality manager to install itself as the sink for these messages. The following structures are defined for quality management.
The IQualityControl::Notify method receives a Quality message. A filter may call IQualityControl::Notify to send a Quality message to another filter to ask for help in managing the graph quality (typically to achieve graceful degradation on a processor that is not powerful enough to handle all the data). Quality messages usually flow upstream.
The IQualityControl::SetSink method tells a filter where to send it. If no sink has been explicitly set or if the last SetSink set the sink to NULL, the message should go upstream. The filter sends a message upstream by calling QueryInterface on the output pin to which its input pin is connected, in order to retrieve an IQualityControl interface. Filters export the IQualityControl interface through their pins.
Messages start with rendering filters, because these must run in real time. Other filters must run to keep the renderers supplied; these do not originate messages, but they can pass them on.
If a filter receives a quality message, it returns S_OK if it agrees to act on the quality message to handle the situation, or S_FALSE if it cannot handle it. For example, if the video renderer receives S_FALSE (or failure codes), it will readily drop frames to try to maintain synchronization. If it receives S_OK, it will trust the upstream filter; it also will allow frames to be played much earlier than their due time and will allow frames to be played much later without dropping them. Usually, the video renderer causes early frames to be blocked until their due time. But if this is the first frame after a dropped frame, the video renderer will play the frame as soon as possible so as not to lose time.
A reasonable implementation for a filter that cannot handle a message is to pass the message upstream and to pass on the result. For example:
HRESULT Notify(IBaseFilter * pSelf, QualityMessage qm) { if (m_QualitySink!=NULL) // note how pSelf has changed into Myself return m_QualitySink->ChangeQuality(pMyself, qm); else return m_Upstream->Notify(pMyself, qm); }
A quality managing component would typically set the sink for all filters to itself. It can identify filters by their IBaseFilter interface pointers in the Self parameters. A filter must always supply the same value for its IBaseFilter interface. (The official COM way of determining if two filters are the same is to use QueryInterface on them both for their IUnknown interfaces and compare those. However, because DirectShow™ is a real-time system, and because these calls are made during streaming, it is implemented this way for efficiency.)
A quality managing component (for example, an application) typically returns S_OK when called upon to help. However, it should be prepared to find that when it sends a message to a filter requesting help from that filter, it immediately gets a request from that filter for help, and that whatever return code it gives to that filter in response to the request immediately comes back from the filter as the reply to its original message. This happens if the filter uses the suggested default implementation of passing the messages upstream, but with the Quality managing component intercepting all the traffic.
The Quality message structure is:
typedef enum { Famine, Flood } QualityMessageType; typedef struct { QualityMessageType Type; long Proportion; REFERENCE_TIME Late; } Quality;
The Type member of the structure indicates which filter appears to have the problem. If set to Famine, it indicates that the renderer is not getting enough samples and the receiver of the message should speed up by any means possible. If set to Flood, the sender of the message cannot keep up with the data being sent and the receiver must send less data. Other methods of degradation are not appropriate.
The Proportion member gives a rate (expressed in parts per thousand) to be used by a recipient that cannot seek (dropping frames is equivalent to seeking) but can only control its rate. For example, a proportion of 823 means that it should degrade enough to go faster by a factor of 1000/823. Likewise, a proportion of 1200 means that it can improve its quality by 20 percent, even if this results in going slower. The numbers are not cumulative. In particular, if a filter can degrade only in steps of, say, 20 percent, and if it receives a series of Quality messages all with Proportion equal to 990, it should ignore them all. It should not multiply them (for example, it should not deduce that a 20 percent reduction is called for after the twenty-third message in this case).
The Late member says how late the application is running at the moment. Negative values mean that there is some slack (probably the renderer is waiting for this time before rendering the samples). A positive value from an audio renderer does not necessarily mean that there is an audio break; it means that the audio renderer's buffer queue is running low and is heading for a break.
When to Implement
Pins that are required to pass quality control messages upstream must implement this interface. The CBasePin class inherits IQualityControl and provides a pass-through implementation for output pins. Any filter that can act on a quality control message to adjust the rate of data flow should implement this interface. Any quality management component external to the filter graph should implement this interface to receive quality control messages.
When to Use
The rendering filter (usually the video renderer) is the primary user of this interface because it originates the quality control messages. Because the messages pass from one filter to another upstream, each downstream filter calls the IQualityControl::Notify method on the upstream output pin and so is a user.
Methods in Vtable Order
IUnknown methods | Description |
QueryInterface | Returns pointers to supported interfaces. |
AddRef | Increments the reference count. |
Release | Decrements the reference count. |
IQualityControl methods | Description |
Notify | Notifies the recipient that a quality change is requested. |
SetSink | Sets the IQualityControl object that will receive quality messages. |
Receives a notification that a quality change is requested.
HRESULT Notify(
IBaseFilter * pSelf,
Quality q
);
Returns an HRESULT value.
Sets the IQualityControl object that will receive quality messages.
HRESULT SetSink(
IQualityControl *piqc
);
Returns an HRESULT value.
The filter that receives a call to this method should record the piqc but should not add a reference count to it. The object pointed to will be a quality manager and will be a part of the filter graph (for example, a plug-in distributor). Adding a reference count to this could cause circular reference problems.
The reference to the object specified in piqc is guaranteed to be valid until this method is called with a null value.
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.