Step 4. Set Allocator Properties

This is step 4 of the tutorial Writing Transform Filters.

Note  This step is not required for filters that derive from CTransInPlaceFilter.

After two pins agree on a media type, they select an allocator for the connection and negotiate allocator properties, such as the buffer size and the number of buffers.

In the CTransformFilter class, there are two allocators, one for the upstream pin connection and one for the downstream pin connection. The upstream filter selects the upstream allocator and also chooses the allocator properties. The input pin accepts whatever the upstream filter decides. If you need to modify this behavior, override the CBaseInputPin::NotifyAllocator method.

The transform filter's output pin selects the downstream allocator. It performs the following steps:

  1. If the downstream filter can provide an allocator, the output pin uses that one. Otherwise, the output pin creates a new allocator.
  2. The output pin gets the downstream filter's allocator requirements (if any) by calling IMemInputPin::GetAllocatorRequirements.
  3. The output pin calls the transform filter's CTransformFilter::DecideBufferSize method, which is pure virtual. The parameters to this method are a pointer to the allocator and an ALLOCATOR_PROPERTIES structure with the downstream filter's requirements. If the downstream filter has no allocator requirements, the structure is zeroed out.
  4. In the DecideBufferSize method, the derived class sets the allocator properties by calling IMemAllocator::SetProperties.

Generally, the derived class will select allocator properties based on the output format, the downstream filter's requirements, and the filter's own requirements. Try to select properties that are compatible with the downstream filter's request. Otherwise, the downstream filter might reject the connection.

In the following example, the RLE encoder sets minimum values for the buffer size, buffer alignment, and buffer count. For the prefix, it uses whatever value the downstream filter requested. The prefix is typically zero bytes, but some filters require it. For example, the AVI Mux filter uses the prefix to write RIFF headers.

HRESULT CRleFilter::DecideBufferSize(
    IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp)
    HRESULT hr = m_pOutput->ConnectionMediaType(&mt);
    if (FAILED(hr))
        return hr;

    ASSERT(mt.formattype == FORMAT_VideoInfo);
    BITMAPINFOHEADER *pbmi = HEADER(mt.pbFormat);
    pProp->cbBuffer = DIBSIZE(*pbmi) * 2; 
    if (pProp->cbAlign == 0)
        pProp->cbAlign = 1;
    if (pProp->cBuffers == 0)
        pProp->cBuffers = 1;
    // Release the format block.

    // Set allocator properties.
    hr = pAlloc->SetProperties(pProp, &Actual);
    if (FAILED(hr)) 
        return hr;
    // Even when it succeeds, check the actual result.
    if (pProp->cbBuffer > Actual.cbBuffer) 
        return E_FAIL;
    return S_OK;

The allocator may not be able to match your request exactly. Therefore, the SetProperties method returns the actual result in a separate ALLOCATOR_PROPERTIES structure (the Actual parameter, in the previous example). Even when SetProperties succeeds, you should check the result to make sure they meet your filter's minimum requirements.

Custom Allocators

By default, all of the filter classes use the CMemAllocator class for their allocators. This class allocates memory from the virtual address space of the client process (using VirtualAlloc). If your filter needs to use some other kind of memory, such as DirectDraw surfaces, you can implement a custom allocator. You can use the CBaseAllocator class or write an entirely new allocator class. If your filter has a custom allocator, override the following methods, depending on which pin uses the allocator:

If the other filter refuses to connect using your custom allocator, your filter can either fail the connection, or else connect with the other filter's allocator. In the latter case, you might need to set an internal flag indicating the type of allocator. For an example of this approach, see CDrawImage Class.

Next: Step 5. Transform the Image.

Related topics

Writing DirectShow Filters