Search code examples
c++memory-managementms-media-foundation

Should I release the returned IMFSample of an internally allocated MFT output buffer?


Media Foundation Transform objects (MFT) may implement an output buffer allocation model where the buffers are allocated internally by the MFT object.

If this is the case, the internally allocated buffer is returned via the pSample member of an MFT_OUTPUT_DATA_BUFFER structure that is passed to the IMFTransform::ProcessOutput() method.

From the MFT_OUTPUT_DATA_BUFFER structure documentation:

typedef struct _MFT_OUTPUT_DATA_BUFFER {
  DWORD         dwStreamID;
  IMFSample     *pSample;
  DWORD         dwStatus;
  IMFCollection *pEvents;
} MFT_OUTPUT_DATA_BUFFER;

pSample

Pointer to the IMFSample interface. Before calling ProcessOutput, set this member equal to a valid IMFSample pointer or NULL. See Remarks for more information.

From the IMFTransform::ProcessOutput documentation:

Output Buffers

The MFT returns output data for a stream through the pSample member of the MFT_OUTPUT_DATA_BUFFER structure. This structure member is a pointer to the IMFSample interface of a media sample. (See Media Samples.) The media sample is allocated either by the caller or by the MFT, depending on the MFT's allocation model. To find the allocation model, call IMFTransform::GetOutputStreamInfo and examine the dwFlags member of the MFT_OUTPUT_STREAM_INFO structure

...

If pSample is NULL and dwFlags does not contain the MFT_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER, the MFT provides a sample for the output data. The MFT sets pSample to point to the sample that it provides. The MFT can either allocate a new sample or re-use an input sample.

The documentation does not mention if the returned IMFSample interface in this case should be released. It seems this is not the case, since the documentation is very explicit that any events returned via the same struct should be released by the caller.

From the MFT_OUTPUT_DATA_BUFFER structure documentation:

pEvents

Before calling ProcessOutput, set this member to NULL. On output, the MFT might set this member to a valid IMFCollection interface pointer. The pointer represents a collecton that contains zero or more events. To get each event, call IMFCollection::GetElement and query the returned IUnknown pointer for the IMFMediaEvent interface. When the ProcessOutput method returns, the caller is responsible for releasing the IMFCollection pointer if the pointer is not NULL.

Can somebody confirm if the returned IMFSample interface should be released or not?

I think that If we should not release the returned interface, it should be documented explicitly, as it goes against the established COM way of releasing the interface once we have finished using it.


Solution

  • The caller is responsible to release the sample if the pointer was initialized with a non-NULL value by the MFT (as opposed to buffer allocated by the caller - in which case the MFT uses it but does not need to AddRef it in the structure).

    Code snippet below is good for all three models:

    • If the MFT_OUTPUT_STREAM_PROVIDES_SAMPLES flag is present, the MFT allocates the media sample.
    • If the MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES flag is present, the caller can optionally provide a media sample. If pSample is NULL, the MFT will allocate the media sample.
    • If neither of these two flags is present, the caller must allocate the media sample.

    Note that the documentation does not mention a scenario where caller provides a sample pointer, and MFT replaces it with its own.

    (the code is not to be perfect though, just an illustration of reference counting; if there is a priori information that samples are caller's then there is no need to do Attach/Detach thing, of course)

    CComPtr<IMFSample> pSample;
    // pSample is NULL or not
    MFT_OUTPUT_DATA_BUFFER Buffer;
    Buffer.pSample = pSample.Detach();
    // ...
    const HRESULT nResult = pTransform->ProcessOutput(..., &Buffer, ...);
    pSample.Attach(Buffer.pSample);
    // pSample holds a valid properly ref'fed pointer
    // No need to use Buffer.pSample below