当前位置: 首页 > news >正文

dxva2+ffmpeg硬件解码(Windows)终结发布

《dxva2超低延迟视频播放器》演示demo下载URL:

【免费】dxva2硬解码超低延迟网络+本地播放器资源-CSDN文库

本地播放 截图:

rtsp播放截图(推送内容为本地桌面,所以是这样的)

OK,进入主题:

前前后后写了4篇文章解决"dxva2+ffmpeg硬件解码"遇到的问题,这篇文章做个demo并发布直播流视频播放器正式测试版本:

播放器特点:

1、超低延迟播放器(100ms左右)

2、秒开技术(1秒)

3、各种流媒体网络协议支持,如rtmp,rtmp,rtp,udp,tcp,hls,http,srt等

4、超时断开重连机制

5、dxva2硬解码+软解码D3D显示,超低CPU占有率

6、支持4K视频,10bit视频,支持各种视频格式,如mp4,mkv,wmv,mov,ts等等

7、支持本地各种语言的文件路径及文件名(utf-8)

8、源码内把dxva2封装为类,可以在进程内打开多个播放器同时进行dxva2硬解码。

9、提供d3d高速渲染RGB32,I420,NV12数据,并封装为类

。。。

《dxva2超低延迟视频播放器》搭建环境:

windows下,服务器采用ZLMediaKit,推送端采用ffmpeg直接推送桌面,接收端播放器为本播放器

以下以源码+文字说明的形式一一说明:

1、超低延迟的实现:

其实就一句话:

fc->flags = AV_CODEC_FLAG_LOW_DELAY;

(fc的定义:AVFormatContext *fc)

这样设置后,解码器就没缓存了,有数据就直接可以获取

2、秒开技术:

就是首帧显示出来的时间。当然越短越好!

也是一句话:

fc->max_analyze_duration = 1 * AV_TIME_BASE;

最大分析持续时间,设置的1秒,这个只能根据经验设置。默认的话这个时间会很长很长。

3、各种流媒体网络协议支持:(打开URL超时设置)

支持的协议就不说明了,这是ffmpeg 的功劳,哈哈

第一点,这里不得不说下各种协议下的打开URL超时设置,如果URL不存在或者不通畅,程序会死掉很久时间,这里就必须要设置一个超时返回失败的设置,各个网络协议的设置不尽相同:

直接贴代码吧,简单易懂!

    const char *timeout = "1000000";if (wcsncmp(m_url, L"rtmp",4)==0)av_dict_set(&opts, "rw_timeout", timeout, 0);//rtmp设置超时1秒else if (wcsncmp(m_url, L"rtsp", 4) == 0)av_dict_set(&opts, "stimeout", timeout, 0);//rtsp设置超时1秒elseav_dict_set(&opts, "timeout", timeout, 0);//udp和http设置超时3秒

第二点说下,打开过程中的断开判断,直接贴代码:

    第一步,播放器初始化时:

    fc = avformat_alloc_context();
    fc->interrupt_callback.callback = CheckInterrupt;//播放中的超时回调
    fc->interrupt_callback.opaque = 0; 

m_ntime_timeout=0;

第二🙅步,获取数据的线程里面:        

m_ntime_timeout = ::GetTickCount();
        AVPacket pkt = { 0 };
        if (av_read_frame(fc, &pkt) == 0)

这样在回调函数CheckInterrupt里,如果数据读取超时或失败,那么

static int CheckInterrupt(void* ctx)
{
    if (m_ntime_timeout != 0 && ::GetTickCount() - m_ntime_timeout >= 3000)//超时了
    {
        m_bOpened = false;
        g_exitcode = 1;
    }
    else
        g_exitcode = 0;
    return g_exitcode;
}

我们就判定这个连接已经断开了,需要重连!接着看下面

4、超时断开重连机制:

由于avformat_open_input是同步方式打开URL的模式,所以打开前只能死等,由于没找到异步打开的方式,只能自己实现,其实原理不难,就是创建一个打开URL的线程,每隔1秒判断是否在打开状态,如果不是就尝试打开,一个死循环即可。

//异步打开线程
unsigned int __stdcall OpenThread(void * pParam)
{
    for (;;)
    {
        if (!m_bOpenTheadRuning)
            break;
        if (!m_bOpened)//没打开就打开
        {
            Open2(m_hWnd);
        }

        Sleep(1000);
    }
    return 0;
}

5、dxva2硬解码+软解码D3D显示,超低CPU占有率:

没啥说的,dxva2反正就是爽,因为不需要指定显卡,只要支持dxva2协议的显卡都能进行硬解码。硬解码CPU占用肯定低啦。其他硬解码方式也行但是通用性不强,因为你事先不知道是何种显卡,比如常用的英伟达,intel,AMD,还有不常用的比如有些国产CPU如兆芯带的显卡等,所以DXVA2是通用的和最常用的硬解码方式之一。

6、支持4K视频,支持各种视频格式,如mp4,mkv,wmv,mov,ts等等

如果节目源为4K视频,单纯的用CPU解码占有率会很高,而且帧率也达不到30帧,甚至更低。所以此时DXVA2的优势即可体现,实测用INTEL HD630低端显卡,解码4K 10bit HEVC视频,最高解码帧率可以达到300帧左右,CPU占有率3%,GPU72%。

查看DXVA2协议,应该是支持10bit视频的,网上下载的源码是不支持的。

修改后支持10bit的核心代码:

static int dxva2_create_decoder(AVCodecContext *s)
{InputStream  *ist = (InputStream *)s->opaque;int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;struct dxva_context *dxva_ctx = (dxva_context *)s->hwaccel_context;GUID *guid_list = NULL;unsigned guid_count = 0, i, j;GUID device_guid = GUID_NULL;D3DFORMAT target_format = D3DFMT_UNKNOWN;DXVA2_VideoDesc desc = { 0 };DXVA2_ConfigPictureDecode config;HRESULT hr;int surface_alignment;int ret;hr = ctx->decoder_service->GetDecoderDeviceGuids(&guid_count, &guid_list);if (FAILED(hr)) {av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n");goto fail;}for (i = 0; dxva2_modes[i].guid; i++) {D3DFORMAT *target_list = NULL;unsigned target_count = 0;const dxva2_mode *mode = &dxva2_modes[i];if (mode->codec != s->codec_id)continue;for (j = 0; j < guid_count; j++) {//if (IsEqualGUID(*mode->guid, guid_list[j]))//    break;if (IsEqualGUID(*mode->guid, guid_list[j])){if (s->pix_fmt == AV_PIX_FMT_YUV420P10LE || s->pix_fmt ==AV_PIX_FMT_YUV420P10BE){if (*mode->guid == DXVA2_ModeHEVC_VLD_Main10)break;continue;}elsebreak;}}if (j == guid_count)continue;hr = ctx->decoder_service->GetDecoderRenderTargets(*mode->guid, &target_count, &target_list);if (FAILED(hr)) {continue;}//for (j = 0; j < target_count; j++) {//    const D3DFORMAT format = target_list[j];//    if (format == MKTAG('N', 'V', '1', '2')) {//        target_format = format;//        break;//    }//}for (j = 0; j < target_count; j++) {const D3DFORMAT format = target_list[j];D3DFORMAT f0 = (D3DFORMAT)MKTAG('N', 'V', '1', '2');D3DFORMAT f1 = (D3DFORMAT)MKTAG('P', '0', '1', '0');if (format == MKTAG('N', 'V', '1', '2') || format == MKTAG('P', '0', '1', '0')){target_format = format;break;}}CoTaskMemFree(target_list);if (target_format) {device_guid = *mode->guid;break;}}CoTaskMemFree(guid_list);if (IsEqualGUID(device_guid, GUID_NULL)) {av_log(NULL, loglevel, "No decoder device for codec found\n");goto fail;}desc.SampleWidth = s->coded_width;desc.SampleHeight = s->coded_height;desc.Format = target_format;ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config);if (ret < 0) {goto fail;}/* decoding MPEG-2 requires additional alignment on some Intel GPUs,but it causes issues for H.264 on certain AMD GPUs..... */if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO)surface_alignment = 32;/* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensureall coding features have enough room to work with */else if (s->codec_id == AV_CODEC_ID_HEVC)//surface_alignment = 128;surface_alignment = 16;elsesurface_alignment = 16;/* 4 base work surfaces */ctx->num_surfaces = 4;/* add surfaces based on number of possible refs */if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC)ctx->num_surfaces += 16;else if (s->codec_id == AV_CODEC_ID_VP9)ctx->num_surfaces += 8;elsectx->num_surfaces += 2;/* add extra surfaces for frame threading */if (s->active_thread_type & FF_THREAD_FRAME)ctx->num_surfaces += s->thread_count;ctx->surfaces = (LPDIRECT3DSURFACE9 *)av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces));ctx->surface_infos = (surface_info *)av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos));if (!ctx->surfaces || !ctx->surface_infos) {av_log(NULL, loglevel, "Unable to allocate surface arrays\n");goto fail;}hr = ctx->decoder_service->CreateSurface(FFALIGN(s->coded_width, surface_alignment),FFALIGN(s->coded_height, surface_alignment),ctx->num_surfaces - 1,target_format, D3DPOOL_DEFAULT, 0,DXVA2_VideoDecoderRenderTarget,ctx->surfaces, NULL);if (FAILED(hr)) {printf( "Failed to create %d video surfaces\n", ctx->num_surfaces);goto fail;}hr = ctx->decoder_service->CreateVideoDecoder(device_guid,&desc, &config, ctx->surfaces,ctx->num_surfaces, &ctx->decoder);if (FAILED(hr)) {printf("Failed to create DXVA2 video decoder\n");goto fail;}ctx->decoder_guid = device_guid;ctx->decoder_config = config;dxva_ctx->cfg = &ctx->decoder_config;dxva_ctx->decoder = ctx->decoder;dxva_ctx->surface = ctx->surfaces;dxva_ctx->surface_count = ctx->num_surfaces;if (IsEqualGUID(ctx->decoder_guid, DXVADDI_Intel_ModeH264_E))dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;return 0;
fail:dxva2_destroy_decoder(s);return AVERROR(EINVAL);
}

7、支持本地各种语言的文件路径及文件名(utf-8)

这个其实不算什么特点,单独列出来,只是有些初学开发者不知道avformat_open_input的URL路径的字符编码,很多人以为是ansi码,在中文系统下的中文字符没问题,但是你遇到日语,韩语,越南语等其他小语种路径时,却打开失败!其实这里的字符编码应该为UTF-8,需要将unicode转为utf-8字符串,贴代码:

static int U2UTF(WCHAR* szUnicode, char* pDesBuf)
{DWORD dwNum = WideCharToMultiByte(CP_UTF8, NULL, szUnicode, -1, NULL, 0, NULL, FALSE);char* psText = new char[dwNum];if (!psText){delete[]psText;}memset(psText, 0, dwNum);WideCharToMultiByte(CP_UTF8, NULL, szUnicode, -1, psText, dwNum, NULL, FALSE);memcpy(pDesBuf, psText, dwNum);delete[]psText;return dwNum;
}

打开越南语路径的截图:

8、源码内把dxva2封装为类,可以在进程内打开多个播放器同时进行dxva2硬解码:

封装优化后,只有3个接口:

    int Init(AVCodecContext *s, HWND hwnd);
    int    RenderData(AVCodecContext *s,AVFrame *pFrame,RECT *sourceRect=0);
    void dxva2_uninit(AVCodecContext *s) ;

9、提供d3d高速渲染RGB32,I420,NV12数据,并封装为类:

对于软解码或者硬解码后获取数据到CPU内存,就需要提供D3D高速渲染显示:

#pragma once
#include "stdafx.h"
#include "d3d9.h"
#include "d3dx9.h"class CD3DVidRender
{
public:CD3DVidRender(void);~CD3DVidRender(void);void Cleanup();BOOL InitD3D_RGB32(HWND hwnd, int img_width, int img_height);BOOL InitD3D_YUV(HWND hwnd, int img_width, int img_height);BOOL InitD3D_NV12(HWND hwnd, int img_width, int img_height);BOOL Render_RGB32(unsigned char* pdata, int width, int height);BOOL Render_YUV(unsigned char * pdata, int img_width, int img_height);BOOL Render_NV12(unsigned char * pdata, int img_width, int img_height);void calculate_display_rect(RECT *rect,int img_width, int img_height, int scr_width, int scr_height) ;public:RECT m_rtViewport;D3DPRESENT_PARAMETERS d3dpp; IDirect3D9 * m_pDirect3D9;  IDirect3DDevice9 * m_pDirect3DDevice;  IDirect3DSurface9 * m_pDirect3DSurfaceRender; IDirect3DSurface9 * m_pBackBuffer;RECT m_rtFont;ID3DXFont* m_pD3DXFont;D3DXFONT_DESC m_font_desc;
};

《dxva2超低延迟视频播放器》演示demo下载URL:

【免费】dxva2硬解码超低延迟网络+本地播放器资源-CSDN文库icon-default.png?t=N7T8https://download.csdn.net/download/xjb2006/88554080

可能以后会适时上传源码。不过授之以鱼不如授之以渔,知道了原理和方法,这些问题都迎刃而解!

相关文章:

dxva2+ffmpeg硬件解码(Windows)终结发布

《dxva2超低延迟视频播放器》演示demo下载URL&#xff1a; 【免费】dxva2硬解码超低延迟网络本地播放器资源-CSDN文库 本地播放 截图&#xff1a; rtsp播放截图&#xff08;推送内容为本地桌面&#xff0c;所以是这样的&#xff09; OK&#xff0c;进入主题&#xff1a; 前前…...

C#密封类、偏类

C#密封类 在C#中&#xff0c;密封类&#xff08;Sealed Class&#xff09;是一种特殊的类&#xff0c;它阻止其他类继承它。你可以通过在类定义前面加上 sealed 关键字来创建一个密封类。 以下是一个密封类的例子&#xff1a; public sealed class MyClass {// Class member…...

C++菱形继承问题

总结&#xff1a; 菱形继承带来的主要问题是子类继承两份相同的数据&#xff0c;导致资源浪费以及毫无意义利用虚继承 virtual 可以解决菱形继承问题 #include <iostream> #include <string> using namespace std; class Animal { public:int m_Age; };//继承前加…...

第20章 数据库编程

通过本章需要理解JDBC的核心设计思想以及4种数据库访问机制&#xff0c;理解数据库连接处理流程&#xff0c;并且可以使用JDBC进行Oracle数据库的连接&#xff0c;理解工厂设计模式在JDBC中的应用&#xff0c;清楚地理解DriverManager类的作用&#xff0c;掌握Connection、Prep…...

PS学习笔记——初识PS界面

文章目录 PS界面 PS界面 我使用的是PS2021&#xff0c;可能不同版本界面有所不同&#xff0c;但大体来说没有太多差异 可以看到下面这个图就是ps的主界面&#xff0c;大体分为菜单栏、选项栏、工具栏、面板、以及最中央的工作区。 ps中的操作基本都能在菜单栏中找到 可以从菜…...

JDBC,Java连接数据库

下载 JDBC https://mvnrepository.com/ 创建项目&#xff0c;然后创建一个目录并将下载好的 jar 包拷贝进去 选择 Add as Library&#xff0c;让这个目录能被项目识别 连接数据库服务器 在 JDBC 里面&#xff0c;使用 DataSource 类来描述数据库的位置 import com.mysql.cj.…...

java智慧校园信息管理系统源码带微信小程序

一、智慧校园的定义 智慧校园指的是以云计算和物联网为基础的智慧化的校园工作、学习和生活一体化环境。以各种应用服务系统为载体&#xff0c;将教学、科研、管理和校园生活进行充分融合&#xff0c;让校园实现无处不在的网络学习、融合创新的网络科研、透明高效的校务治理、…...

智能电销机器人好做吗?ai机器人有没有用?

电销机器人是基于深度神经学算法和卷积神经网络算法&#xff0c;将网络电话、语音识别、自然语言理解、多轮对话、知识图谱等多个门类集于一身的智能产品。不但能与客户智能交流&#xff0c;更能根据已经设定好的专业话术进行业务描述和问题解答&#xff0c;在电销行业是不可多…...

吴恩达《机器学习》9-1:代价函数

一、引入新标记方法 首先&#xff0c;引入一些新的标记方法&#xff0c;以便更好地讨论神经网络的代价函数。考虑神经网络的训练样本&#xff0c;其中每个样本包含输入 x 和输出信号 y。我们用 L 表示神经网络的层数&#xff0c;表示每层的神经元个数&#xff08;表示输出层神…...

代码随想录算法训练营第五十九天 | LeetCode 739. 每日温度、496. 下一个更大元素 I

代码随想录算法训练营第五十九天 | LeetCode 503. 下一个更大元素 II、42. 接雨水 文章链接&#xff1a;下一个更大元素 II、接雨水 视频链接&#xff1a;下一个更大元素 II、接雨水 1. LeetCode 503. 下一个更大元素 II 1.1 思路 本题是给一个数组求右边第一个比当前元素大的…...

mybatisPlus的简单使用

封装实体类 编写Mapper service层 controller层...

vue+element实现多级表头加树结构

标题两种展示方式 方式一 完整代码: <template><div class"box"><el-tableref"areaPointTable":data"tableData"border:span-method"objectSpanMethod":header-cell-style"tableHeaderMerge"><el-ta…...

internet download manager2024中文绿色版(IDM下载器)

在现代互联网时代&#xff0c;文件下载已经成为我们日常生活中必不可少的一项技能。无论是下载软件、音乐、视频还是其他文件&#xff0c;一个高效的下载方法能够为我们节省时间和精力。本文将为您提供一份简明扼要的下载教程&#xff0c;让您轻松掌握文件下载的技巧。 intern…...

(二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、数据集二、导入数据以及展示部分1.导入数据集以及对数据集进行处理2.展示数据&#xff08;看看就好&#xff09; 三&#xff08;1&#xff09;、搭建网络进…...

markdown 公式编辑

参考&#xff1a;https://blog.csdn.net/qq_36584673/article/details/117167861...

20231117在ubuntu20.04下使用ZIP命令压缩文件夹

20231117在ubuntu20.04下使用ZIP命令压缩文件夹 2023/11/17 17:01 百度搜索&#xff1a;Ubuntu zip 压缩 https://blog.51cto.com/u_64214/7641253 Ubuntu压缩文件夹zip命令 原创 chenglei1208 2023-09-28 17:21:58博主文章分类&#xff1a;LINUX 小工具 文章标签命令行压缩包U…...

IPKISS Tutorials 1------导入 pdk

IPKISS Tutorials 1------导入 pdk 方法1方法2今天给大家介绍一下如何在 IPKISS 中导入想要使用的 pdk 文件。 方法1 # 导入IPKISS 自带 si_fab PDK from si_fab import all as pdk # 导入amf PDK from amfsip import all as pdk方法2 # 导入IPKISS 自带 si_fab PDK import …...

使用ChatGPT进行数据分析案例——贷款数据分析

目录 数据数据 每一行是一个记录,代表着一笔贷款,每一列是一个特征,一共1万多条数据,最后一列非常重要save_loans是否成功收回...

【数字图像处理】Gamma 变换

在数字图像处理中&#xff0c;Gamma 变换是一种重要的灰度变换方法&#xff0c;可以用于图像增强与 Gamma 校正。本文主要介绍数字图像 Gamma 变换的基本原理&#xff0c;并记录在紫光同创 PGL22G FPGA 平台的布署与实现过程。 目录 1. Gamma 变换原理 2. FPGA 布署与实现 2…...

ChatGPT + DALL·E 3

参考链接&#xff1a; https://chat.xutongbao.top/...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...