Alex F
Alex F

Reputation: 43321

Bad performance of IMFSinkWriter WriteSample method, RGB32 format

Following the Microsoft tutorial "Using the Sink Writer to Encode Video" https://learn.microsoft.com/en-us/windows/win32/medfound/tutorial--using-the-sink-writer-to-encode-video I found that line hr = pWriter->WriteSample(streamIndex, pSample); has low performance. I print the execution time by changing the code:

std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

// Send the sample to the Sink Writer.
if (SUCCEEDED(hr))
{
    hr = pWriter->WriteSample(streamIndex, pSample);
}

std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << endl;

and get an average 225 ms execution time (Release configuration). So, I try to solve this problem by applying an attributes to IMFSinkWriter, this is the changed code:

HRESULT InitializeSinkWriter(IMFSinkWriter **ppWriter, DWORD *pStreamIndex)
{
    *ppWriter = NULL;
    *pStreamIndex = NULL;

    IMFSinkWriter   *pSinkWriter = NULL;
    IMFMediaType    *pMediaTypeOut = NULL;
    IMFMediaType    *pMediaTypeIn = NULL;
    IMFAttributes*  attr = NULL;
    DWORD           streamIndex;
    HRESULT hr;

    hr = MFCreateAttributes(&attr, 2);

    if (SUCCEEDED(hr))
    {
        hr = attr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
    }

    if (SUCCEEDED(hr))
    {
        hr = attr->SetUINT32(MF_SINK_WRITER_DISABLE_THROTTLING, TRUE);
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateSinkWriterFromURL(L"output.wmv", NULL, attr, &pSinkWriter);
    }
    // ... the same as in the code sample
}

However, MF_SINK_WRITER_DISABLE_THROTTLING attribute does not help, and WriteSample function still takes 225 ms. This is the serious problem to my real program, which needs to handle a high number of frames.

Additional information: I am using uncompressed frames

const GUID VIDEO_ENCODING_FORMAT = MFVideoFormat_RGB32;

instead of MFVideoFormat_WMV3. With MFVideoFormat_WMV3 WriteSample is really fast, but 225 ms seems to be too much even for uncompressed frames.

One more point. I have another program, which reads MFVideoFormat_RGB32 file and writes to another MFVideoFormat_RGB32 file. So, the sample is read from IMFSourceReader and added to IMFSinkWriter, without any performance problems.

Is there anything else I can do to improve the program performance?

Upvotes: 1

Views: 887

Answers (1)

Alex F
Alex F

Reputation: 43321

The following code solved the problem, added before pSinkWriter->AddStream line:

if (SUCCEEDED(hr))
{
    hr = pMediaTypeOut->SetUINT32(MF_MT_DEFAULT_STRIDE, VIDEO_WIDTH*4);
}

if (SUCCEEDED(hr))
{
    hr = pMediaTypeOut->SetUINT32(MF_MT_FIXED_SIZE_SAMPLES, TRUE);
}

if (SUCCEEDED(hr))
{
    hr = pMediaTypeOut->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
}

if (SUCCEEDED(hr))
{
    hr = pMediaTypeOut->SetUINT32(MF_MT_SAMPLE_SIZE, VIDEO_WIDTH*VIDEO_HEIGHT*4);
}

Specifically, WriteSample time was reduced to 20 ms once MF_MT_ALL_SAMPLES_INDEPENDENT is added. Note that these values are valid only for uncompressed fixed-sized frames.

Upvotes: 2

Related Questions