searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Qt使用DirectShow解码视频的代码实例

2023-12-05 09:00:49
194
0

在 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() 方法开始播放视频。

0条评论
作者已关闭评论
张****恒
6文章数
0粉丝数
张****恒
6 文章 | 0 粉丝
原创

Qt使用DirectShow解码视频的代码实例

2023-12-05 09:00:49
194
0

在 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() 方法开始播放视频。

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0