Media Foundation: Why does setting MF_MT_DEFAULT_STRIDE on a RGB24 output type prevent vertical flipping?

1 week ago 4
ARTICLE AD BOX

I am relatively new to Media Foundation and I’m working with a video processing pipeline consisting of several IMFTransform components.The last stage in this pipeline converts an NV12 stream into RGB24. When inspecting the output, I noticed that the RGB24 frame is vertically flipped aka. mirrored at the horizon compared to the NV12 input.

Based on my own experience and some research, I suspect this is related to top-down vs. bottom-up bitmap layouts, which in Media Foundation is typically controlled by the stride aka. pitch.

While following the suggestions here, I attempted to query a valid stride using:

MFGetStrideForBitmapInfoHeader(...)

However, this call always returns a "Failure"-HRESULT.

Because of this, I tried to manually set the stride in the output MF_MT_SUBTYPE_RGB24 format. To my surprise, any positive value (including 0) removes the vertical flip.
The output image suddenly becomes correct, even when the stride is obviously incorrect. I mean if, the stride were really 0, the transform could only copy a single row — which obviously does not happen. This behaviour does not match my understanding of how stride should work.

My questions:

What exactly does MF_MT_DEFAULT_STRIDE on and input and/or output format control? Is it merely a suggestion about the direction or used determin a strict "copy-order" from input to output? What is the correct stride for RGB24 in Media Foundation? Is it simply: "stride = width * 3" or must I also consider alignment rules, such as DWORD alignment? In other words: Does MF require 4-byte alignment for RGB24 strides?

Here the relevant part of my code:

const DWORD UPPER_TYPE_LIMIT = 1024; for (DWORD inputTypeIndex = 0; inputTypeIndex < UPPER_TYPE_LIMIT; ++inputTypeIndex) { Native::Ref<IMFMediaType> inType; Native::HresultAssertable{transformer->GetInputAvailableType(0, inputTypeIndex, &inType)}; GUID subType; Native::HresultAssertable{inType->GetGUID(MF_MT_SUBTYPE, &subType)}; if (subType == MFVideoFormat_NV12) { Native::HresultAssertable{MFSetAttributeSize(inType, MF_MT_FRAME_SIZE, m_cameraSettings.videoWidth, m_cameraSettings.videoHeight)}; Native::HresultAssertable{transformer->SetInputType(0, inType, 0)}; for (DWORD outputTypeIndex = 0; outputTypeIndex < UPPER_TYPE_LIMIT; ++outputTypeIndex) { Native::Ref<IMFMediaType> outType; transformer->GetOutputAvailableType(0, outputTypeIndex, &outType); Native::HresultAssertable{outType->GetGUID(MF_MT_SUBTYPE, &subType)}; if (subType == MFVideoFormat_RGB24) { Native::HresultAssertable{outType->SetUINT32(MF_MT_DEFAULT_STRIDE, 0)}; Native::HresultAssertable{MFSetAttributeSize(outType, MF_MT_FRAME_SIZE, m_cameraSettings.videoWidth, m_cameraSettings.videoHeight)}; Native::HresultAssertable{transformer->SetOutputType(0, outType, 0)}; break; } } break; } }
Read Entire Article