Search code examples
c++directshow

Problems understanding and using double pointers


I am not sure how to use double pointers.

The function i need to use looks as following:

HRESULT GetBuffer(
  [out]  IMediaSample **ppBuffer,
  [in]   REFERENCE_TIME *pStartTime,
  [in]   REFERENCE_TIME *pEndTime,
  [in]   DWORD dwFlags
);

Documentation says:

ppBuffer [out]

Receives a pointer to the buffer's IMediaSample interface. The caller must release the interface.

This is what i tried using it:

HRESULT MCMyOutputPin::Deliver(IMediaSample* sample)
{
    HRESULT hr = NO_ERROR;
    myLogger->LogDebug("In Outputpin Deliver", L"D:\\TEMP\\yc.log");
    if (sample->GetActualDataLength() > 0)
    {
        IMediaSample **outsample;



        m_pAllocator->GetBuffer(outsample, NULL, NULL, NULL); //Access violation here
        BYTE** sampleBuffer;
        BYTE** newBuffer;
        sample->GetPointer(sampleBuffer);

        (*outsample)->GetPointer(newBuffer);

        memcpy((void *)newBuffer, (void *)sampleBuffer, sizeof(**sampleBuffer));

        m_pInputPin->Receive(*outsample);

        sample->AddRef();
    }

    return hr;
    //Forward to filter
}

Which gives me an:

Access violation reading location 0xFFFFFFFFFFFFFFFF.

Then i tried using the address operator:

hr = m_pAllocator->GetBuffer(&outsample, NULL, NULL, NULL); //outsample is set to NULL
    BYTE* sampleBuffer = NULL;
    BYTE*  newBuffer = NULL;
    sample->GetPointer(&sampleBuffer);

    outsample->GetPointer(&newBuffer);

    memcpy((void *)newBuffer, (void *)sampleBuffer, sizeof(*sampleBuffer));

    m_pInputPin->Receive(outsample);

This sets outsample to NULL.

So what is the correct syntax to handle double pointers?


Solution

  • My first, high-level comment, is that you are not checking the return values of the functions that you call. It's a mistake to neglect error checking. Your first step is to add the necessary error checking.


    HRESULT GetBuffer(
      [out]  IMediaSample **ppBuffer,
      [in]   REFERENCE_TIME *pStartTime,
      [in]   REFERENCE_TIME *pEndTime,
      [in]   DWORD dwFlags
    );
    

    The first parameter is used to return a IMediaSample* to the caller. You need to declare a variable of type IMediaSample*, and pass its address:

    IMediaSample* sample;
    ....
    hr = m_pAllocator->GetBuffer(&outsample, ...);
    // check hr
    ....
    

    So, outsample is of type IMediaSample*. When you take its address, with &outsample, you now have something of type IMediaSample**, which is what you need.

    Remember that when working with interfaces, you always work with a pointer to the interface.


    You've made the same mistake with the BYTE** parameters. Again, declare variables of type BYTE*, and pass the address of these variables to the functions that you call.

    BYTE* sampleBuffer;
    BYTE* newBuffer;
    ....
    hr = sample->GetPointer(&sampleBuffer);
    // check hr
    hr = outsample->GetPointer(newBuffer);
    // check hr
    

    Using sizeof(**sampleBuffer) in your call to memcpy is wrong. In your code, where sampleBuffer is wrongly declared as BYTE**, sizeof(**sampleBuffer) is just sizeof(BYTE) which is always 1.

    In fact you can conclude that any use of sizeof is incorrect here because sizeof is evaluated at compile time. You need to find the actual size of the dynamic buffer at runtime using whatever functionality these interfaces provide.


    The call to sample->AddRef() looks a little suspect. I don't see any evidence that anything has taken a new reference to the interface.