I wrote a screen video capture program in C++ /CLI. I capture the video 30 times a second and display it in a picture box. My idea was to copy the IMFSample to a reusable output sample then free the source sample to control memory usage.
Although I call sampleOut->RemoveAllBuffers() prior to sampleOut->AddBuffer(destBuf), it still consumes additional memory. It appears that RemoveAllBuffers doesn't actually free the memory from the prior video frame. Any idea how I can free the memory without having to release the sampleOut and recreate it?
HRESULT ScreenCapture::DuplicateSample(IMFSample* sample)
{
HRESULT hr = S_OK;
if (!sample)
{
hr = E_ABORT;
return hr;
}
DWORD sampleFlags = 0;
LONGLONG llVideoTimeStamp = 0;
LONGLONG llSampleDuration = 0;
IMFMediaBuffer* srcBuf;
IMFMediaBuffer* destBuf;
hr = sample->GetSampleFlags(&sampleFlags);
hr = sample->GetSampleTime(&llVideoTimeStamp);
hr = sample->GetSampleDuration(&llSampleDuration);
hr = sampleOut->SetSampleFlags(sampleFlags);
hr = sampleOut->SetSampleTime(llVideoTimeStamp);
hr = sampleOut->SetSampleDuration(llSampleDuration);
srcBuf = nullptr;
hr = sample->GetBufferByIndex(0, &srcBuf);
byte* srcByteBuffer = nullptr;
DWORD srcBuffCurrLen = 0;
DWORD srcBuffMaxLen = 0;
hr = srcBuf->Lock(&srcByteBuffer, &srcBuffMaxLen, &srcBuffCurrLen);
destBuf = nullptr;
hr = MFCreateMemoryBuffer(srcBuffCurrLen, &destBuf);
byte* destByteBuffer = nullptr;
hr = destBuf->Lock(&destByteBuffer, nullptr, nullptr);
memcpy(destByteBuffer, srcByteBuffer, srcBuffCurrLen);
hr = destBuf->Unlock();
hr = srcBuf->Unlock();
hr = destBuf->SetCurrentLength(srcBuffCurrLen);
SafeRelease(&srcBuf);
sampleOut->RemoveAllBuffers();
hr = sampleOut->AddBuffer(destBuf); //Memory issue here
SafeRelease(&destBuf);
return hr;
}
As you can see I also need a better way to handle the hr testing for each step. I figured I deal with that after I get the code working.
Thanks for your help!
The question you are interested in is how to reuse samples instead of allocating them each time. The primary call you want to avoid is MFCreateMemoryBuffer
because it is the actual memory consumer, not the buffer attachment/detachment from sample objects.
The ideal solution is along these lines:
MFCreateVideoSampleAllocatorEx
, just your own implementation)IMFSample
, it is considered as engaged and is not available for reuse from the poolThis is exactly how allocators provided by mentioned MFCreateVideoSampleAllocatorEx
work.