Processing a Sample (Windows CE 5.0)

Send Feedback

When a filter's input pin receives a sample, the filter processes the data in the sample and then delivers the sample to the next downstream filter. As the previous section described, the filter can do all of its processing while inside the IMemInputPin::Receive on the downstream input pin, passing it a pointer to the sample's method, or it can hold the sample and process it afterward.

Within the call to Receive, the input pin has the option of blocking the upstream filter's calling thread. You can query the input pin's behavior by calling the IMemInputPin::ReceiveCanBlock method. If the return value is S_OK, the pin might block on a call to Receive. If the return value is S_FALSE, the pin will never block on calls to Receive. Based on the return value, the upstream filter might use a separate worker thread to deliver samples.

Some filters process samples in place, without copying any data. Other filters copy the data before processing it. Obviously, it is better to process samples in place whenever possible, to avoid the overhead of unneeded copy operations.

The input pin can reject samples by returning an error code or S_FALSE in its Receive method. The value S_FALSE indicates that the pin is flushing data (see "Flushing" below). An error code indicates some other problem. For example, if the filter is stopped, the return value is VFW_E_WRONG_STATE. If a pin rejects a sample, the upstream filter calls the IPin::EndOfStream method and stops sending data. If the pin returned an error code, the upstream filter also signals EC_ERRORABORT to the filter graph manager.

The upstream filter must serialize all of its Receive calls to a given input pin.

Parsing Media Data

If your filter parses media data, do not trust headers or other self-describing data in the content. For example, do not trust size values that appear in AVI RIFF chunks or MPEG packets. The following list shows common examples of this kind of error:

  • Reading N bytes of data, where the value of N came from the content, without checking N against the actual size of your buffer.
  • Jumping to a byte offset within a buffer, without verifying that the offset falls within the buffer.

Another common class of errors involves not validating format descriptions that are found in the content. The following list shows common examples of this kind of error::

  • A BITMAPINFOHEADER structure can be followed by a color table. The BITMAPINFO structure is defined as a BITMAPINFOHEADER structure followed by an array of RGBQUAD values that make up the color table. The size of the array is determined by the value of biClrUsed. Never copy a color table into a BITMAPINFO without first checking the size of the buffer that was allocated for the BITMAPINFO structure.
  • A WAVEFORMATEX structure might have extra format information appended to the structure. The cbSize member specifies the size of the extra information.

During pin connection, a filter should verify that all format structures are well-formed and contain reasonable values. If not, you should reject the connection. In the code that validates the format structure, be especially careful about arithmetic overflow. For example, in a BITMAPINFOHEADER, the width and height are 32-bit long values but the image size (which is a function of the product of the two) is only a DWORD value.

If format data from the source is larger than your allocated buffer, do not truncate the source data in order to copy it into your buffer. Doing so can create a structure with an implicit size larger than its actual size. For example, a bitmap header might specify a palette table that no longer exists. Instead of truncating the source data, reallocate the buffer or simply fail the connection.

Errors during Streaming

Your filter should terminate streaming if it receives malformed content while it is running in a filter graph. The following list describes the steps that your filter should take when it terminates streaming.

  • Return an error code from Receive.
  • Call IPin::EndOfStream on the downstream filter.
  • Post an EC_ERROR_ABORT event.

Dynamic Format Changes

Several mechanisms exist for filters to change formats mid-stream. Each of these mechanisms involves more than one step. This creates the potential for false acceptances of the dynamic format change. If your filter gets a request for a dynamic format change from another filter, then it must either reject the request, or else honor the new format when it arrives. Similar results will occur if your filter, changes formats without confirming that the downstream filter agrees.

End of Stream

When a source filter has no more data to send, it calls the IPin::EndOfStream method on the downstream input pin. The downstream filter propagates the call to the next filter. Eventually the EndOfStream call reaches the renderer filter. The renderer filter signals EC_COMPLETE to the filter graph manager.

Before posting an EC_COMPLETE notification to the application, the filter graph manager waits until all the streams signal EC_COMPLETE. The application does not receive an EC_COMPLETE notice until all the streams have completed. To determine the number of streams in the graph, the filter graph manager counts the number of filters that support IMediaSeeking or IMediaPosition and have a rendered input pin. A rendered input pin is an input pin with no corresponding outputs. The IPin::QueryInternalConnections method returns zero for a rendered input pin.

Filters must serialize EndOfStream calls with IMemInputPin::Receive calls.

Flushing

Flushing is the process of discarding all the pending samples in the graph. Flushing enables the graph to be more responsive when events alter the normal data flow. For example, in a seek operation, pending data is flushed from the graph before new data is introduced. If the graph contains multiple streams, it is possible to flush individual streams separately.

Flushing is a two-stage process:

  • The source filter calls IPin::BeginFlush on a downstream input pin. The downstream filter flushes any pending data and calls BeginFlush on the next input pin. The call propagates downstream until it reaches the renderer.
  • The source filter calls IPin::EndFlush on the downstream input pin. Again, the downstream filter propagates this call.

When the BeginFlush method is called on a filter's input pin, the filter performs the following actions:

  • Returns from any blocking calls to the input pin's IMemInputPin::Receive method.
  • Rejects any further samples in calls to Receive, until the EndFlush method is called.
  • Discards any samples that were queued for delivery to downstream filters.
  • Clears any pending calls to IPin::EndOfStream.
  • Clears any pending EC_COMPLETE notifications.
  • Calls BeginFlush on downstream input pins.

When the EndFlush method is called, the filter performs the following actions:

  • Waits for queued samples to be discarded.
  • Calls EndFlush downstream.

At this point, the filter can accept samples again.

In the pull model, the parser filter initiates flushing rather than the source filter. The sequence of events is the same, except that the parser also calls BeginFlush and EndFlush on the source filter's output pin.

Critical Sections in Filters

Because filter operations are multithreaded, it is crucial that a filter serialize certain operations. Otherwise, race conditions can result. For example, the filter might try to use an allocator that is already decommitted. Filters use two critical sections, one to hold a streaming lock and the other to hold a filter state lock.

The streaming lock serializes streaming operations. The filter holds this lock when it processes the following method calls:

The filter state lock serializes state changes. The filter holds this lock when it processes the following method calls:

Within the Stop and EndFlush methods, the filter must synchronize its filter state with its streaming state. In the Stop method, the filter holds the filter state lock and decommits the input pin's allocator. Then it holds the streaming lock and decommits the output pin's allocator.

Base Classes for Data Flow

The following base classes are useful for implementing data flow in a filter.

Class Description
COutputQueue Queues data to be delivered downstream. Uses a worker thread for delivering samples.
CPullPin Input pin on a parser filter. Uses a worker thread to pull data from a source filter.
CSourceStream Output pin on a source filter. Uses a worker thread to push data downstream.

Send Feedback on this topic to the authors

Feedback FAQs

© 2006 Microsoft Corporation. All rights reserved.