- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
问题陈述:
英特尔硬件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)来检查它在降低输入帧频以避免带宽消耗时是否提高了性能,但是该调用失败,并出现“ parametercorrect”错误。
我的实验:
为了保持恒定的帧速率,并迫使编码器产生实时输出,我将相同的样本(以前保存的样本)馈送到
编码器以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还是0FPS(空闲)下变化,Intel MFT上的输出比特率似乎始终保持在350KBps至500KBps之间,而NVidia MFT(具有30FPS和500KB比特率配置)上的输出比特率则介于80KBps至400KBps之间。在这种情况下,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上的空闲时间数据消耗
调整一些参数,以400KB比特率配置将其调整为〜20KBps以下,以100KB比特率将其调整为〜10KBps以下
组态。这令人信服。但是,具有相同编码器配置的相同代码在Intel机器上产生的数据量将增加20至40倍。英特尔(英特尔图形620)肯定不遵守GOP设置。我什至尝试将GOP从256更改为INT_MAX,英特尔硬件MFT的输出似乎没有变化。
更新2:
在试用了编码器属性之后(我仅使用eAVEncCommonRateControlMode_UnconstrainedVBR而不是eAVEncCommonRateControlMode_CBR配置了CODECAPI_AVEncCommonRateControlMode),现在我可以看到Intel MFT在屏幕空闲时间内产生了3KBps的数据,但是仅在最初的几秒钟(大约3至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, &var), "Failed to set realtime mode");
var = { 0 };
var.vt = VT_BOOL;
var.ulVal = VARIANT_TRUE;
CHECK_HR(mpCodecAPI->SetValue(&CODECAPI_AVLowLatencyMode, &var), "Failed to set low latency mode");
var = { 0 };
var.vt = VT_BOOL;
var.ulVal = VARIANT_TRUE;
CHECK_HR(mpCodecAPI->SetValue(&CODECAPI_AVEncCommonLowLatency, &var), "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, &var), "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, &var), "Failed to set Quality-speed ratio");
var = { 0 };
var.vt = VT_UI4;
var.lVal = 20;
CHECK_HR(mpCodecAPI->SetValue(&CODECAPI_AVEncCommonQuality, &var), "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, &var), "Failed to set rate control");
var = { 0 };
var.vt = VT_UI4;
var.lVal = 4000000;
CHECK_HR(mpCodecAPI->SetValue(&CODECAPI_AVEncCommonMeanBitRate, &var), "Failed to set Adaptive mode");
var = { 0 };
var.vt = VT_UI4;
var.lVal = eAVEncAdaptiveMode_FrameRate;
CHECK_HR(mpCodecAPI->SetValue(&CODECAPI_AVEncAdaptiveMode, &var), "Failed to set Adaptive mode");
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);
最佳答案
发生了一些奇迹。在同时使用编码器配置的同时,我不小心将主显示器更改为机器上的另一台显示器,现在问题已解决。切换回先前选择的主监视器会导致相同的问题。我怀疑d3ddevice会造成麻烦。我不确定为什么仅在该设备/显示器上会发生这种情况,因此必须进行更多实验。
注意:由于我尚未找出仅在该monitor / d3d设备上发生问题的原因,因此我未将其标记为答案。只是将其发布为可能遇到类似情况的其他人的参考。一旦能够找到特定d3d11device实例上异常行为的原因,我将更新答案。
这就是我创建d3ddevice的方式,并将其重复用于桌面复制图像捕获器,视频处理器以进行颜色转换以及通过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);
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;
}
}
}
}
关于video-streaming - 英特尔H264硬件MFT不支持GOP设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59051443/
我在一个项目中工作,我必须从驱动器中枚举文件名。我尝试了两种方法 MFT 解析和 使用 FindFirstFile 进行多线程处理。我比较了两种实现的执行时间,它显示较小的 MFT 大小执行速度更快,
我正在使用 DesktopDuplication API 捕获桌面并将样本从 RGBA 转换为 GPU 中的 NV12,并将其提供给 MediaFoundation 硬件 H264 MFT。这适用于
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我正在编写一些代码来解析 NTFS 卷中磁盘上的 MFT。这很简单,但是一个特殊的极端案例引起了我的注意,我在互联网上的任何地方都找不到明确的答案。 对于 NTFS 中的普通文件,如果文件的属性多于单
我正在尝试提取主文件表(MFT)的内容。我已从 NTFS 卷复制 MFT 并将其另存为 .bin 文件。现在我尝试使用Python中提供的unpack函数来读取这个文件。我正在读取为存储在文件记录的文
对于我正在做的一些商业项目,我需要能够读取存储在 $mft 文件中的实际数据。 我找到了一个 gpl lib这可能会有所帮助,但由于它是 gpl,我无法将它集成到我的代码中。 有人可以指点我可以使用的
我正在编写一个程序来删除 Windows NTFS 卷中的文件和所有相关属性(包括 0x30 $FILE_NAME、0x80 $DATA、0x90 $INDEX_ROOT 和 0xA0 $INDEX_
在网上寻找有关如何读/写 MFT 的解释时,我发现了以下部分:( http://www.installsetupconfig.com/win32programming/1996%20AppE_apni
我正在使用 Windows Media Foundation 创建视频播放应用程序。 我使用 IMFTransform 接口(interface)和下面链接中提到的其他一些强制接口(interface
我也是媒体基础编程和 Windows 编程的新手。 这个问题看起来可能很愚蠢,但我在任何地方都没有得到明确的答案。 我的应用程序是捕获屏幕、缩放、编码并将数据发送到网络。我希望提高管道的性能。所以我想
有什么方法可以用 Python 或 JavaScript 访问 NTFS 主文件表 (MFT)? 最佳答案 您需要一个库来分析 NTFS 文件系统中的主文件表 ($MFT)。 对于 Python,有
我正在尝试从 MFT 中删除一个文件记录,如果我打开原始分区并通过解析 MFT 文件到达所需的文件记录,我就成功了。这种方法的问题是我必须首先锁定卷,以便我可以在任何 MFT 文件记录上写入零,如果其
要使用 Windows Media Foundation Transform 解码 H264 流,目前的工作流程是这样的: IMFSample sample; sample->SetTime(time
在我的 C# 应用程序中,我已经有了一种检查文件系统的方法,但我想利用从主文件表 (MFT) 读取的优势,因为它要快得多。我了解 1) 它是专有规范,因此如有更改,恕不另行通知,以及 2) 只有当应用
有人遇到过 VideoToolbox 无法正确解码媒体基础变换 (MFT) 编码的 H264 的问题吗?解码帧的一半以上具有绿色 block 失真。我试过Livy Stork's example用于解
我现在尝试在 Win10 pro Insider 预览版上使用 MP3 编码器 mft,但无法设置输出媒体类型。 下面是我的代码: // Fill in MPEGLAYER3WAVEFORMAT da
我正在努力将两个音频流混合成一个输出流。 MFNode 有一个 AudioMixerMFT,但当我尝试构建这样的拓扑并执行它时 TopoEdit 崩溃: 注意:我尝试了 Windows SDK 7.1
我正在编写一个工具,用于查找 iTunes 库中丢失的文件,适用于 Mac 和 Windows。在 Mac 上,我可以使用神奇的“目录搜索”功能通过命名快速查找文件。 但是,在 Windows 上,似
媒体基础转换对象 (MFT) 可以实现输出缓冲区分配模型,其中缓冲区由 MFT 对象在内部分配。 如果是这种情况,内部分配的缓冲区将通过传递给 IMFTransform::ProcessOutput(
我想使用“英特尔® 快速同步视频 H.264 编码器 MFT”对视频进行编码。如果我从系统缓冲区创建 IMFSample,它运行良好。就像下面这样: IMFMediaBuffer *pBuffer =
我是一名优秀的程序员,十分优秀!