英特尔H264硬件MFT不遵守GOP设置

问题陈述:

Intel硬件MFT不遵守GOP设置,导致实时应用程序占用更多带宽。相同的代码在Nvidia硬件MFT上可以正常工作。

背景

我正在尝试使用Windows10计算机上的MediaFoundation H264硬件编码器将通过DesktopDuplication API捕获的NV12样本编码为视频流,并通过LAN进行实时流处理和渲染。

最初,我在编码器处面临太多缓冲,因为编码器在提供输出样本之前最多缓冲25帧(GOP大小)。经过一些研究,我发现设置CODECAPI_AVLowLatencyMode可以减少延迟,但要花一些质量和带宽。

设置CODECAPI_AVLowLatencyMode属性在某种程度上提高了性能,但没有达到实时要求。现在看来,编码器至少在生成样本之前仍至少缓冲15帧(在输出中引入大约2秒钟的延迟)。并且仅当配置了低帧速率时,此行为才明显。在60FPS时,输出几乎是实时的,没有视觉上明显的延迟。

实际上,只有当帧频设置为低于30FPS时,人眼才能注意到缓冲。而且,延迟与FPS配置成反比增加,在25FPS时,延迟在几百毫秒内,而当FPS配置为10(恒定速率)时,延迟会增加到3秒。我猜想,将FPS设置为大于30(说60FPS)实际上会导致编码器缓冲区足够快地溢出,以产生明显延迟的样本。

最近,我也尝试使用CODECAPI_AVEncCommonRealTime属性(https://docs.microsoft.com/en-us/windows/win32/directshow/avenccommonrealtime-property)来检查它在降低输入帧速率以避免带宽消耗时是否提高了性能,但是该调用失败,并出现“参数不正确” strong>错误。

我的实验

  

为了保持恒定的帧速率,并迫使编码器产生实时输出,我将相同的样本(以前保存的样本)提供给   编码器以30FPS / 60FPS的恒定速率传输。我正在这样做   最多只能捕获10FPS(或任何所需的FPS)并伪造30 / 60FPS   通过三次或完全按照   EMULATED_FRAME_RATE / actUAL_FRAME_RATE比率(例如:30 / 10、60 / 15、60 / 20),以恒定的间隔精确地填补空白。例如,如果10秒钟内没有任何变化,我将给编码器提供30 * 10次(30FPS)的相同样本。我从一些开源Github项目(从Chrome的实验代码示例中)学到了这种方法,还被告知(Primarily on SO,和其他论坛),这是推动编码器实现实时输出的唯一方法,而且没有办法解决。

上述方法产生近乎实时的输出,但消耗的数据却比我预期的要多,即使我仅将先前保存的样本馈入编码器。

无论屏幕内容是30FPS还是0F​​PS(空闲),输出比特率似乎在Intel MFT上始终保持在350KBps至500KBps之间,而在NVidia MFT上在80KBps至400KBps之间变化(具有30FPS和500KB比特率配置) )。在这种情况下,NVidia硬件编码器似乎要好一些。

实际上,在屏幕空闲期间,编码器每秒产生的数据量超过上述速率。我已经能够通过setting a larger GOP size减少NVidia设备上的数据消耗(当前配置的GOP大小为16K)。但是,在英特尔图形620硬件上,屏幕空闲时间数据消耗保持在300KBps左右,而在NVidia GTX 1070(配置:500KB比特率和30FPS)上,屏幕空闲时间数据消耗保持在50KBps至80KBps。我猜想,英特尔硬件MFT根本没有兑现GOP设置,或者改进并不明显。

通过设置非常低的比特率,我还能够将Intel和Nvidia硬件上的空闲时间数据消耗分别降低至〜130KBps和〜40KBps,但这仍然是不可接受的,这也会使视频质量下降。

当输入采样之间没有变化时,是否可以将编码器配置为产生小于10KBps的输出?当没有任何变化但〜10KBps可以接受时,我实际上的目标是〜0KB输出。

更新

我能够通过以下方式减少NVidia MFT上的空闲时间数据消耗 调整一些参数,以〜20KBps(400KB比特率配置),以及〜10KBps(100KB比特率)以下 配置。这令人信服。但是,具有相同编码器配置的相同代码在Intel机器上产生的数据量将增加20至40倍。英特尔(英特尔图形620)肯定不遵守GOP设置。我什至尝试将GOP从256更改为INT_MAX,英特尔硬件MFT的输出似乎没有变化。

更新2:

尝试使用编码器属性后(我仅使用eAVEncCommonRateControlMode_UnconstrainedVBR而不是eAVEncCommonRateControlMode_CBR配置了CODECAPI_AVEncCommonRateControlMode),现在我可以看到Intel MFT在屏幕空闲时间产生了3KBps的数据,但仅在最初的几秒钟内(大约3到4秒)。 8秒),然后回到相同的故事。我猜想在几秒钟后,编码器将失去对关键帧的参考,无法将其与样本进行比较,并且在此之后似乎无法恢复。无论GOP是16/128/256/512/1024还是INT_MAX,行为都是相同的。

编码器配置:

参考:http://alax.info/blog/1586

const int EMULATED_FRAME_RATE = 30;//
const int TARGET_FPS = 10;
const int FPS_DENOMINATOR = 1;
const unsigned long long time_between_capture = 1000 / TARGET_FPS;
const unsigned long long nEmulatedWaitTime = 1000 / EMULATED_FRAME_RATE;
const unsigned long long TARGET_AVERAGE_BIT_RATE = 4000000; // Adjusting this affects the quality of the H264 bit stream.
const LONGLONG VIDEO_FRAME_DURATION = 10ll * 1000ll * 1000ll / ((long long)EMULATED_FRAME_RATE); // frame duration in 100ns units
const UINT32 KEY_FRAME_SPACING = 16384;
const UINT32 GOP_SIZE = 16384;
const UINT32 BPICTURECOUNT = 2;

VARIANT var = { 0 };

//no failure on both Nvidia & Intel,but Intel seems to be not behaving as expected
var.vt = VT_UI4;
var.lVal = GOP_SIZE;
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncMPVGOPSize,&var),"Failed to set GOP size");

var.vt = VT_BOOL;
var.ulVal = VARIANT_TRUE;
// fails with "parameter incorrect" error.
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncCommonRealTime,"Failed to set realtime mode");

var = { 0 };
var.vt = VT_BOOL;
var.ulVal = VARIANT_TRUE;
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVLowLatencyMode,"Failed to set low latency mode");

var = { 0 };
var.vt = VT_BOOL;
var.ulVal = VARIANT_TRUE;
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncCommonLowLatency,"Failed to set low latency mode");

var = { 0 };
var.vt = VT_UI4;
var.lVal = 2; // setting B-picture count to 0 to avoid latency and buffering at both encoder and decoder
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncMPVDefaultBPictureCount,"Failed to set B-Picture count");

var = { 0 };
var.vt = VT_UI4;
var.lVal = 100; //0 - 100 (100 for best quality,0 for low delay)
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncCommonQualityVsspeed,"Failed to set Quality-speed ratio");

var = { 0 };
var.vt = VT_UI4;
var.lVal = 20;
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncCommonQuality,"Failed to set picture quality");

var = { 0 };
var.vt = VT_UI4;
var.lVal = eAVEncCommonRateControlMode_CBR; // This too fails on some hardware
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncCommonRateControlMode,"Failed to set rate control");

var = { 0 };
var.vt = VT_UI4;
var.lVal = 4000000;
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncCommonmeanBitRate,"Failed to set Adaptive mode");

var = { 0 };
var.vt = VT_UI4;
var.lVal = eAVEncAdaptiveMode_FrameRate;
CHECK_HR(mpCodecAPI->Setvalue(&CODECAPI_AVEncAdaptiveMode,"Failed to set Adaptive mode");

我尝试使用以下代码检索GOP大小支持的参数范围,但它只会返回E_NOTIMPL错误。

VARIANT ValueMin = { 0 };
VARIANT ValueMax = { 0 };
VARIANT SteppingDelt = { 0 };
HRESULT hr = S_OK;

if (!mpCodecAPI) {
    CHECK_HR(_pTransform->QueryInterface(IID_PPV_ARGS(&mpCodecAPI)),"Failed to get codec api");
}

hr = mpCodecAPI->GetParameterRange(&CODECAPI_AVEncMPVGOPSize,&ValueMin,&ValueMax,&SteppingDelt);
CHECK_HR(hr,"Failed to get GOP range");

VariantClear(&ValueMin);
VariantClear(&ValueMax);
VariantClear(&SteppingDelt);

我想念什么吗?在没有屏幕内容更改的情况下,我还可以尝试使用其他任何属性来获得实时性能同时消耗尽可能少的带宽吗?

yegenting1 回答:英特尔H264硬件MFT不遵守GOP设置

一些奇迹发生了。在尝试编码器配置的同时,我不小心将主显示器更改为机器上的另一台显示器,现在问题已经解决了。切换回先前选择的主监视器会导致相同的问题。我怀疑d3ddevice会造成麻烦。我不确定为什么仅在该设备/显示器上会发生这种情况,所以必须进行更多实验。

注意:由于我尚未找出仅在该Monitor / d3d设备上发生问题的原因,因此我未将其标记为答案。只是将其发布为可能遇到类似情况的其他人的参考。一旦能够找到特定d3d11设备实例上异常行为的原因,我将更新答案。

这是我创建d3d设备的方式,并将其用于桌面复制图像捕获器,视频处理器以进行颜色转换以及通过 MFT_MESSAGE_SET_D3D_MANAGER 属性进行硬件转换。

选项:

const D3D_DRIVER_TYPE m_DriverTypes[] = {

    //Hardware based Rasterizer
    D3D_DRIVER_TYPE_HARDWARE,//High performance Software Rasterizer
    D3D_DRIVER_TYPE_WARP,//Software Rasterizer (Low performance but more accurate)
    D3D_DRIVER_TYPE_REFERENCE,//TODO: Explore other driver types
};

const D3D_FEATURE_LEVEL m_FeatureLevel[] = {

    D3D_FEATURE_LEVEL_11_1,D3D_FEATURE_LEVEL_11_0,D3D_FEATURE_LEVEL_10_1,D3D_FEATURE_LEVEL_10_0,D3D_FEATURE_LEVEL_9_3,D3D_FEATURE_LEVEL_9_2,D3D_FEATURE_LEVEL_9_1

    //TODO: Explore other features levels as well
};

int m_DriversCount = ARRAYSIZE(m_DriverTypes);
int m_FeatureLevelsCount = ARRAYSIZE(m_FeatureLevel);

创建d3d设备:

DWORD errorCode = ERROR_SUCCESS;

if (m_FnD3D11CreateDevice == NULL)
{
    errorCode = loadD3D11FunctionsFromDll();
}

if (m_Id3d11Device)
{
    m_Id3d11Device = NULL;
    m_Id3d11DeviceContext = NULL;
}

UINT uiD3D11CreateFlag = (0 * D3D11_CREATE_DEVICE_SINGLETHREADED) | D3D11_CREATE_DEVICE_VIDEO_SUPPORT;

if (errorCode == ERROR_SUCCESS)
{
    if (m_FnD3D11CreateDevice) {

        for (UINT driverTypeIndex = 0; driverTypeIndex < m_DriversCount; ++driverTypeIndex)
        {
            m_LastErrorCode = D3D11CreateDevice(nullptr,m_DriverTypes[driverTypeIndex],nullptr,uiD3D11CreateFlag,m_FeatureLevel,m_FeatureLevelsCount,D3D11_SDK_VERSION,&m_Id3d11Device,&m_SelectedFeatureLevel,&m_Id3d11DeviceContext);

            if (SUCCEEDED(m_LastErrorCode))
            {
                break;
            }
        }
    }
}
本文链接:https://www.f2er.com/3029025.html

大家都在问