在 Windows 平台上,Qt 可以使用 DirectShow、Media Foundation 或 Video for Windows (VFW) 等多种方式进行视频硬件解码和硬件渲染。这些方式都可以实现 CPU 的 0 拷贝操作,提高视频播放性能。
要启用视频硬件解码和硬件渲染能力,请在 Qt 中使用 QMediaPlayer 类。QMediaPlayer 类封装了各种平台特定的媒体播放器框架,并提供了简单易用的接口。
// 创建 QMediaPlayer 实例并设置 media 内容为 mp4 视频文件
QMediaPlayer *player = new QMediaPlayer(this);
player->setMedia(QUrl("C:/path/to/video.mp4"));
// 配置 DirectShow 或 Media Foundation
#if defined(Q_OS_WIN)
// 获取 QMediaPlayer 对应的 Windows 视频窗口
WId videoWindow = (WId)player->videoSurface()->nativeResourceForIntegration("qwindow");
if(videoWindow) {
// 获取直接渲染到该窗口的视频渲染器
IUnknown *renderer = nullptr;
HRESULT hr = S_OK;
if(qstrcmp(MF_VIDEO_RENDERER_DEFAULT, "EVR") == 0) {
// Media Foundation 框架
IMFVideoDisplayControl *displayCtrl = nullptr;
hr = player->service(QMediaPlayer::ServiceMedia, IID_PPV_ARGS(&displayCtrl));
if(SUCCEEDED(hr)) {
hr = displayCtrl->GetVideoWindow(videoWindow, &renderer);
displayCtrl->Release();
}
} else {
// DirectShow 框架
IVideoWindow *videoWin = nullptr;
hr = player->service("IVideoWindow", IID_PPV_ARGS(&videoWin));
if(SUCCEEDED(hr)) {
hr = videoWin->put_Owner((OAHWND)videoWindow);
if(SUCCEEDED(hr)) hr = videoWin->QueryInterface(IID_PPV_ARGS(&renderer));
videoWin->Release();
}
}
// 开启硬件加速
if(renderer) {
if(qstrcmp(MF_VIDEO_RENDERER_DEFAULT, "EVR") == 0) {
// Media Foundation 框架
IMFVideoRenderer *videoRenderer = nullptr;
hr = renderer->QueryInterface(IID_PPV_ARGS(&videoRenderer));
if(SUCCEEDED(hr)) {
IMFTransform *transform = nullptr;
hr = videoRenderer->GetVideoProcessor(&transform);
if(SUCCEEDED(hr)) {
MFT_OUTPUT_STREAM_INFO outInfo = {};
hr = transform->GetOutputStreamInfo(0, &outInfo);
if(SUCCEEDED(hr)) {
MFT_INPUT_STREAM_INFO inInfo = {};
BOOL processAlways = FALSE;
hr = transform->GetInputStreamInfo(0, &inInfo);
if(SUCCEEDED(hr)) {
processAlways = (inInfo.dwFlags & MFT_INPUT_STREAM_INFO_PROCESS_MESSAGE) != 0;
inInfo.dwFlags &= ~MFT_INPUT_STREAM_INFO_PROCESS_MESSAGE;
hr = transform->SetInputStreamInfo(0, &inInfo);
}
if(processAlways) {
MFT_MESSAGE_TYPE msgType = MFT_MESSAGE_COMMAND_FLUSH;
hr = transform->ProcessMessage(msgType, 0);
}
IMFVideoProcessorControl *procCtrl = nullptr;
hr = transform->QueryInterface(IID_PPV_ARGS(&procCtrl));
if(SUCCEEDED(hr)) {
BOOL enableD3D11 = TRUE;
procCtrl->SetVideoProcessorMode(enableD3D11 ? MFT_VIDEO_PROCESSOR_MODE_D3D11_DEVICE_MANAGER : MFT_VIDEO_PROCESSOR_MODE_DEVICE_HANDLE, 0);
procCtrl->Release();
}
}
transform->Release();
}
videoRenderer->Release();
}
} else {
// DirectShow 框架
IVMRSurfaceAllocator9 *allocator = nullptr;
hr = renderer->QueryInterface(IID_PPV_ARGS(&allocator));
if(SUCCEEDED(hr)) {
IDirect3DDevice9 *device = nullptr;
hr = allocator->GetDirect3DDeviceManager(&device);
if(SUCCEEDED(hr)) {
hr = QGstUtils::setDirect3DDevice(device);
if(FAILED(hr)) qDebug() << "Failed to set device";
device->Release();
}
allocator->Release();
}
}
renderer->Release();
}
}
#endif
// 开始播放视频
player->play();
在上述代码片段中,我们首先创建了一个 QMediaPlayer 实例,并设置 media 内容为 mp4 视频文件。然后,根据当前平台类型使用 DirectShow 或 Media Foundation 框架进行配置。将 videoSurface() 函数返回的原生视频窗口转换为 Windows 平台下可用的 WId 类型,获取直接渲染到该窗口的视频渲染器,最后开启硬件加速功能。完成硬件加速配置后,调用 play() 方法开始播放视频。