IMediaSample to pass to encoder

IMediaSample to pass to encoder

Here is my setup:

H264 encoded video.mp4 ---> LAV splitter ---> IntelQuickSync Decoder filter ---> My Filter ---> IntelQuickSync Encoder filter --> Enhanced Video Renderer

In "My Filter", in the receive function, if we simply do:

HRESULT OutputFrameGenerator::ReceiveInputFrame( InputPin& inputPin, IMediaSample& inputSample )

{

return m_outputPin.Deliver( &inputSample );

}

everything works fine. However if I try to simply copy the inputSample to another IMediaSample object, the delivery is successful, but the encoder crashes. Here is some test code just meant to illustrate the issue:

HRESULT OutputFrameGenerator::ReceiveInputFrame( InputPin& inputPin, IMediaSample& inputSample )
{
HRESULT retVal = S_OK;

IMediaSample* outputSample = nullptr;
REFERENCE_TIME startTime = 0;
REFERENCE_TIME endTime = 0;
REFERENCE_TIME startMediaTime = 0;
REFERENCE_TIME endMediaTime = 0;

m_outputPin.GetDeliveryBuffer( &outputSample, nullptr, nullptr, 0 );

retVal = inputSample.GetTime( &startTime, &endTime );
switch( retVal )
{
case VFW_S_NO_STOP_TIME:
retVal = outputSample->SetTime(&startTime, NULL);
break;
case S_OK:
retVal = outputSample->SetTime(&startTime, &endTime);
break;
default:
break;
}
retVal = inputSample.GetMediaTime( &startMediaTime, &endMediaTime );
switch( retVal )
{
case VFW_E_MEDIA_TIME_NOT_SET:
retVal = outputSample->SetMediaTime( NULL, NULL );
break;
case S_OK:
retVal = outputSample->SetMediaTime( &startMediaTime, &endMediaTime );
break;
default:
break;
}

unsigned int length = inputSample.GetActualDataLength();

retVal = outputSample->SetActualDataLength( length );
retVal = outputSample->SetDiscontinuity( inputSample.IsDiscontinuity() );
retVal = outputSample->SetPreroll( inputSample.IsPreroll() );
retVal = outputSample->SetSyncPoint( inputSample.IsSyncPoint() );

BYTE* inputPtr;
BYTE* outputPtr;
inputSample.GetPointer( &inputPtr );
outputSample->GetPointer( &outputPtr );

memcpy( outputPtr, inputPtr, length );
retVal = m_outputPin.Deliver( outputSample );
outputSample->Release();

}

We get this output:

First-chance exception at 0x000000018041BA02 (libmfxhw64.dll) in graphedit_x64.exe: 0xC0000005: Access violation reading location 0x000000001900E000.
First-chance exception at 0x00000001801A4AC5 (libmfxhw64.dll) in graphedit_x64.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
The thread 0x2f90 has exited with code 1 (0x1).
The thread 0xe00 has exited with code 0 (0x0).

Thoughts?

5 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

This might also be of use:

HRESULT OutputPin::DecideBufferSize( IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties )

{
// Most of this code is straight out of the CBaseTransformFilter
// the allocator verification chunk of code is a bit odd, but it does work as expected, so I left it alone
const unsigned int NUM_BUFFERS = 6;

// Is the input pin connected?
HRESULT retVal = E_UNEXPECTED;
if( pAlloc != nullptr && pProperties != nullptr )
{
pProperties->cBuffers = NUM_BUFFERS;
pProperties->cbAlign = 1;

// make the buffer large enough for the entire output image we are going to generate
CMediaType mediaType;
if( GetMediaType(0, &mediaType) == S_OK )
{
pProperties->cbBuffer = mediaType.GetSampleSize();
ASSERT( pProperties->cbBuffer );
retVal = S_OK;
}

if( retVal == S_OK )
{
// Verify that the allocator actually works and an the allocator is functional
// (not sure why we need to do this, but sometimes the allocator fails on us)
ALLOCATOR_PROPERTIES Actual;
retVal = pAlloc->SetProperties( pProperties,&Actual );
if ( retVal == S_OK )
{
if ( pProperties->cBuffers > Actual.cBuffers ||
pProperties->cbBuffer > Actual.cbBuffer )
{
retVal = E_FAIL;
}
}
}
}
else
{
retVal = E_POINTER;
}

return retVal;
}

This issue seems to be source content dependant.

reproducable with the Big Buck Bunny 1080p video, happens with other videos as well

http://www.bigbuckbunny.org/index.php/download/

Hi Randy,

We discussed this, and the issue may be related to incorrect buffer size of MediaSample. The encode filter requires the buffer to be aligned at 32 bytes by height (see Media SDK samples for details regarding alignment). So, if the upstream filter ignores this requirement and allocates a non aligned chunk of memory the encoder will try to access it as if it was bigger, thus the memory access crash.

This hypothesis corresponds well with the fact that you're seeing the issue for some clips but not for others.

Let us know what you find.

Regards,
Petter 

Hi Petter, 

Thank you kindly for the response. I believe are on the right track. I was looking at the same thing yesterday. Out of curiosity, I modified

switch (pmfxSurface->Info.FourCC)
{
case MFX_FOURCC_NV12:
pmfxSurface->Data.Y = pBuffer;
pmfxSurface->Data.UV = pBuffer + pmfxSurface->Data.Pitch * lConnectionHeight;

}

to simply be pmfxSurface->Data.UV  = pBuffer (for testing sake) and the crashing no longer occurs, which proves your hypothesis to be correct that it is something up with the UV buffer offset. The image is junk of course, but the key is it no longer crashes. To remove any potential issues in my filter, I challenge you to consider the following setup:

Big Buck Bunny Source 1080p -> LAV splitter -> Intel .H264 Decoder -> Intel .H264 Encoder -> LAV Decoder -> Enhanced Video Rendering

Using the original Intel source code, comment out the IMFXSample check (which should still work, to emulate receiving an regular IMediaSample that is not an IMFXSample from a non-Intel filter):

/*

CComPtr<IMFXSample> pMFXSample(NULL);
hr = pSample->QueryInterface(IID_IMFXSample, reinterpret_cast<void**>(&pMFXSample));

if (SUCCEEDED(hr))
{
hr = pMFXSample->GetMfxSurfacePointer(&pmfxSurface);
CHECK_RESULT_FAIL(hr);
m_pEncoder->m_bmfxSample = true;
}

*/

it still crashes. If you have a look at pmfxSurface->Data.Pitch and lConnectionHeight, they come out as 1088 and 1934 respecitively. The 1088 makes sense, but the 1934 does not.

Taking this a step further to see where 1934 is calculated, we have a look at this line:

sts = InitMfxFrameSurface(pmfxSurface, &m_mfxParamsVideo.mfx.FrameInfo, pSample);

which calculates the pitch using:

pSurface->Data.Pitch = (mfxU16)(nSurfaceSize / pSurface->Info.CropH / 3 * 2);  //factor = 1 for NV12 and YV12

where nSurfaceSize = 3133440, pSurface->Info.CropH = 1080 (seems like this should be using a value of 1088 here, which would make the pitch 1920, the value we want). Tracing back to where pSurface->Info.CropH is set in:

 

HRESULT CEncVideoFilter::CheckInputType(const CMediaType* mtIn)

{

m_mfxParamsVideo.mfx.FrameInfo.Width = (frameWidth + 15) &~ 15;

    m_mfxParamsVideo.mfx.FrameInfo.Height = (frameHeight + 31) &~ 31;

    m_mfxParamsVideo.mfx.FrameInfo.CropW = frameWidth;

    m_mfxParamsVideo.mfx.FrameInfo.CropH = frameHeight;

 

 

seems like either CropW and cropH need to be modulus 16/32, or the calculation for DataPitch should be Height instead of CropH.

 Thoughts?

Leave a Comment

Please sign in to add a comment. Not a member? Join today