当前位置:萝卜系统 > 硬件软件教程 > 详细页面

web前端需要播放视频设备出来的H265码流背景

web前端需要播放视频设备出来的H265码流背景

更新时间:2023-07-02 文章作者:未知 信息来源:网络 阅读次数:

显卡是个人计算机基础的组成部分之一,将计算机系统需要的显示信息进行转换驱动显示器,并向显示器提供逐行或隔行扫描信号,控制显示器的正确显示,是连接显示器和个人计算机主板的重要组件,是“人机”的重要设备之一,其内置的并行计算能力现阶段也用于深度学习等运算。

使用FFmpeg调用NVIDIA GPU以将H265转码为H264

背景

最近,该项目遇到了一个问题,即Web前端需要播放视频设备中的H265流,但是目前仅支持H264流,因此如果我想快速解决此问题,我就来了有两种解决方案。

方案1:通过RTMP将H265直接封装到自定义FLV中,然后将其发布到前端播放中。 Web前端必须支持解析H265回放的控制。如果使用这种解决方案,则目前很难找到适用的开源解决方案,而后端和后端的变化基本上可以说是被推翻了,因此这种方案很难实现。一会儿。

方案2:提供转码服务以解码H265,然后将其编码为H264。无需对Web前端播放方案进行任何更改。有两种方案,软件代码转换和硬件代码转换,因为软件代码转换非常消耗CPU资源,因此可以基本消除这种想法,因此仅考虑硬件代码转换方案。下面的文章将介绍硬件代码转换方案。

比较这两种方案,第二种方案比较合理,可以较快地解决H265播放问题。

H265和H264 1、 H265流nalu标头的一些基本知识

nuh_unit_type的值00 00 00 01 40 01为32,其语义是视频参数集VPS

nuh_unit_type的值00 00 00 01 42 01为33,其语义为序列参数集SPS

nuh_unit_type的值00 00 00 01 44 01为34,其语义是图像参数集PPS

nuh_unit_type的值00 00 00 01 4E 01为39,语义为补充增强信息SEI

nuh_unit_type的值00 00 00 01 26 01为19,其语义是可能具有RADL图像的IDR图像的SS编码数据IDR。

nuh_unit_type的值00 00 00 01 02 01为1,语义是引用的帖子图片,以及非TSA,非STSA SS编码的数据

2、 H264流nalu标头

00 00 00 01 06类型的值为06,NALU_TYPE_SEI语义是补充增强信息SEI

00 00 00 01 67 type的值为67,并且NALU_TYPE_SPS的语义是序列参数集SPS

00 00 00 01 68类型值是68,NALU_TYPE_PPS语义是图像参数集PPS

00 00 00 01 65类型值是65,NALU_TYPE_IDR语义是IDR图像中的IDR

3、补充:IDR帧和I帧之间的关系

IDR帧是I帧,但I帧不一定是IDR帧。在完整的视频流单元中,第一图像帧是IDR帧。 IDR帧为强制刷新帧。在解码过程中,当有IDR帧时,有必要更新sps,pps,原因是为了防止以前的I帧错误,导致无法通过参考I帧来校正sps,pps。

另一个流行的概念是GOP。 GOP的全名是“图片组”,它是两个I帧之间的距离。 GOP值越大,则I帧速率之间的P和B帧越多。 ,图像质量越好,如果GOP为120,分辨率为720P,帧频为60,则两个I帧的时间为120/60 = 2s。

转码的一些基础知识1、如何区分软编码和硬编码

软编码:使用CPU进行编码

硬编码:使用非CPU进行编码,例如图形卡GPU,专用DSP,FPGA芯片等。

2、软编码和硬编码的比较

软编码:实现直接,简单,参数调整方便,升级容易,但CPU负担重,性能低于硬编码,质量通常比硬编码低比特率。

硬编码:高性能,在低比特率下质量通常低于软编码器,但是某些产品已经在GPU硬件平台(例如X26 4))上移植了出色的软编码算法,其质量基本上相当于软编码。

3、当前的主流GPU加速平台

NVIDIA、INTEL、AMD等

4、当前主流GPU平台开发框架

CUDA:NVIDIA的封闭式编程框架,通过它可以调用GPU计算资源

AMD APP:AMD为自己的GPU提出了一套通用的并行编程框架。该标准是开放的。通过在CPU和GPU上支持OpenCL框架,它可以集成计算能力。

c++ 利用ffmpeg解码播放h264文件_ffmpeg 解码h264文件_ffmpeg调用显卡编解码

OpenCL:开放计算语言,一种为异构平台编写程序的框架。异构平台可以包括CPU,GPU和其他计算处理器。目的是使同一计算能够支持不同平台上的硬件加速。

Inel QuickSync:集成在Intel图形卡中的专用视频编模块。

5、流程差异

硬件和软件:读取(ffmpeg)->(NVIDIA cuvid)->编码器(ffmpeg)

软解码和编辑:读取(ffmpeg)->(ffmpeg)->编码器(ffmpeg)

软硬代码:读取(ffmpeg)->(ffmpeg)->编码器(NVIDIA nvenc)

NVIDIA + ffmpeg硬件加速部署1、环境安装和部署:Windows10 + ffmpeg 4. 1. 3 + NVIDIA GeForce GTX 1660Ti

注意:您需要在计算机上安装以下NVIDIA图形卡之一。我本人使用GeForce GTX 1660Ti显卡(在NVIDIA tesla T4显卡上进行了验证,它可以同时对8个以上的通道进行转码)

1. 1 ffmpeg Windows版本下载

下载链接:

在这里插入图片描述

支持下载static / dev / shared

我使用的ffmpeg版本是4. 1. 3

1. 2下载NVIDIA驱动程序(GTX 1660Ti)

下载链接:

在这里插入图片描述

版本45 1. 77(1 1. 0)地址:

在这里插入图片描述

1. 3下载cuda工具包(GTX 1660Ti)

下载链接:

版本45 1. 48(1 1. 0)地址:

在这里插入图片描述

不会介绍安装。

1. 4使用ffmpeg.exe -hwaccels显示所有可用的硬件

我下载的FFmpeg已经包含Nvidia的硬件

在这里插入图片描述

1. 5使用ffmpeg.exe -codecs查看编支持

DEV.LS h264 H.264 / AVC / MPEG-4 AVC / MPEG-4第10部分(:h264 h264_qsv h264_cuvid)(编码器:libx264 libx264rgb h264_amf h264_nvenc h264_qsv nvenc nvenc_h264)

DEV.L。 hevc H.265 / HEVC(高效视频编码)(:hevc hevc_qsv hevc_cuvid)(编码器:libx265 nvenc_hevc hevc_amf hevc_nvenc hevc_qsv)

h264_cuvid:h264硬件

h264_nvenc:h264硬件编码器

hevc_cuvid:h265硬件

c++ 利用ffmpeg解码播放h264文件_ffmpeg调用显卡编解码_ffmpeg 解码h264文件

hevc_nvenc:h265硬件编码器

在这里插入图片描述

NVENC简介

NVENC是NVIDIA开发的API,允许使用NVIDIA GPU图形卡执行h.264和HEVC(即H.26 5)编码。FFmpeg通过h264_nvenc和hevc_nvenc编码器支持NVENC。

要在FFmpeg中启用它,您需要:

支持硬件编码和解码的NVIDIA GPU

NVIDIA GPU驱动程序

没有配置禁用nvenc的ffmpeg

使用示例:

ffmpeg -i input -c:v h264_nvenc -profile high444p -pixel_format yuv444p -preset default output.mp4

您可以通过ffmpeg -h编码器= h264_nvenc或ffmpeg -h编码器= hevc_nvenc来查看可用的预设,其他选项和编码器信息。

注意:如果在没有NVENC功能的设备中发现错误,请确保您的编码采用受支持的像素格式。请参阅上面显示的编码器信息。

CUDA / CUVID / NvDecode

CUVID现在也被Nvidia称为nvdec,可以在Windows和Linux上进行解码。与nvenc结合使用,可提供完整的硬件转码。

CUVID提供H264,HEVC,MJPEG,mpeg1 / 2/4,vp8 / 9,vc1。编支持因硬件而异。

1、使用CUVID。在此示例中,CUVID将帧复制到系统内存:

ffmpeg -c:v h264_cuvid -i input output.mkv

2、使用CUVID和NVENC来实现完整的硬件转码:

ffmpeg -hwaccel cuvid -c:v h264_cuvid -i input -c:v h264_nvenc -preset slow output.mkv

3、硬件转码的一部分,该帧通过系统内存(这是对10位内容进行转码所必需的):

ffmpeg -c:v h264_cuvid -i input -c:v h264_nvenc -preset slow output.mkv

4、如果在编译ffmpeg时支持libnpp,则可以使用它在链中插入基于GPU的缩放器:

ffmpeg -hwaccel_device 0 -hwaccel cuvid -c:v h264_cuvid -i input -vf scale_npp=-1:720 -c:v h264_nvenc -preset slow output.mkv

hwaccel_device选项可用于指定ffmpeg:中的cuvid hwaccel使用的GPU。

FFmpeg命令行硬件对H265原始流文件进行代码转换

使用NVIDIA GTX1660ti图形卡+ ffmpeg 4. 1. 3

1、 H265软件解码,H264硬件编码

ffmpeg.exe -i h265toh264.h265 -vcodec h264_nvenc -r 30 -y h265toh264.h264

2、完整的硬件转码(H265硬件解码,H264硬件编码)

ffmpeg.exe -hwaccel cuvid -c:v hevc_cuvid -i h265toh264.h265 -c:v h264_nvenc -r 30 -y h265toh264.h264

用于将H265原始流文件转码为H264的FFmpeg API

在VS2017项目下,使用ffmpeg API将H265软件解码为YUV,并使用h264_nvenc(NVIDIA硬件编码器)或libx264(h264软件编码器)将YUV编码实现为H26 4.

c++ 利用ffmpeg解码播放h264文件_ffmpeg调用显卡编解码_ffmpeg 解码h264文件

直接转到源代码:

1、主要代码

#include "H265Decoder.h"
#include "H264Encoder.h"
#define ISSTORAGEYUV 0
int main()
{
	int fpts = 0;
	char frame_buf[1024] = { 0 };
	int H265Lenth = 0;
	char H265Buf[1024 * 512];
	H265Decoder h265Decoder;
	H264Encoder h264Encoder;
	//初始化编时需要把正确的分辨率送进去
	/*h265Decoder.Init(1920, 1080);
	h264Encoder.Init(1920, 1080);*/
	h265Decoder.Init(480, 272);
	h264Encoder.Init(480, 272);
	
	//读取文件
	FILE * InFile = fopen("h265toh264.h265", "rb");
	//输出文件
#if ISSTORAGEYUV
	FILE * OutFile = fopen("h265toYUV.YUV", "wb");
#else
	FILE * OutFile = fopen("h265toh264.h264", "wb");
#endif
	//打印ffmpeg输出日志等级
	printf("log level %d \n", av_log_get_level());
	//设置ffmpeg输出日志等级
	av_log_set_level(AV_LOG_INFO);
	
	while (true)
	{
		int iReadSize = fread(frame_buf, 1, 512, InFile);
		if (iReadSize <> 0)
		{
			break;
		}
		memcpy(H265Buf + H265Lenth, frame_buf, iReadSize);
		H265Lenth = H265Lenth + iReadSize;
		//获取一帧数据
		while (true)
		{
			bool OneFrame = false;
			if (H265Lenth <> 8)
			{
				break;
			}
			for (int i = 4; i  H265Lenth - 4; i++)
			{
				//解析H265的nalu头
				if (H265Buf[i] == 0x00 && H265Buf[i + 1] == 0x00 && H265Buf[i + 2] == 0x00 && H265Buf[i + 3] == 0x01)
				{
					h265Decoder.AddData(H265Buf, i);
					while (true)
					{
						char * pOutData = NULL;
						int OutSize = 0;
#if ISSTORAGEYUV
						//获取H265解码后的YUV并存文件
						if (!h265Decoder.GetYUVData(pOutData, OutSize))
						{
							break;
						}
						fwrite(pOutData, 1, OutSize, OutFile);
#else
						//获取H265解码frame并编码H264存文件
						AVFrame *frame = NULL;
						frame = h265Decoder.GetData();
						if (!frame) {
							break;
						}
						frame->pts = fpts++;
						h264Encoder.encode(frame, pOutData, OutSize);
						fwrite(pOutData, 1, OutSize, OutFile);
#endif
					}
					H265Lenth = H265Lenth - i;
					memcpy(H265Buf, H265Buf + i, H265Lenth);
					OneFrame = true;
					break;
				}
			}
			if (OneFrame)
			{
				continue;
			}
			else
			{
				break;
			}
		}
	}
	if (OutFile) {
		fclose(OutFile);
		OutFile = NULL;
	}
	if (InFile) {
		fclose(InFile);
		InFile = NULL;
	}
	printf("pasing end\r\n");
	return 0;
}

2、过程分析

1、要初始化编,需要发送正确的H265分辨率格式进行初始化

	h265Decoder.Init(480, 272);
	h264Encoder.Init(480, 272);

2、循环读取H265文件以形成完整的H265帧(根据H265的nalu标头00 00 00 01判断)

	if (H265Buf[i] == 0x00 && H265Buf[i + 1] == 0x00 && H265Buf[i + 2] == 0x00 && H265Buf[i + 3] == 0x01)

3、将H265的帧发送到H265以进行软件解码

	h265Decoder.AddData(H265Buf, i);

4、要获取由H265解码的YUV,可以选择保存YUV文件或将其发送到H264编码器进行编码并将其另存为H264文件

#if ISSTORAGEYUV
			//获取H265解码后的YUV并存文件
			if (!h265Decoder.GetYUVData(pOutData, OutSize))
			{
				break;
			}
			fwrite(pOutData, 1, OutSize, OutFile);
#else
			//获取H265解码frame并编码H264存文件
			AVFrame *frame = NULL;
			frame = h265Decoder.GetData();
			if (!frame) {
				break;
			}
			frame->pts = fpts++;
			h264Encoder.encode(frame, pOutData, OutSize);
			fwrite(pOutData, 1, OutSize, OutFile);
#endif

3、遇到的问题

在调试过程中,调用h264_nvenc硬件编码器时遇到错误。经调查,发现H265解码后的原始视频格式为YUVJ420P。原因是来自某些视频设备的H265视频流,编码前的数据是YUVJ420P,并非全部都是YUV420P。如果将此原始YUVJ420P直接发送到NVIDIA硬件编码器,则将直接导致程序崩溃。经过调查,发现NVIDIA不支持YUVJ420P的直接编码,如下所示。如图所示,仅YUV420P或YUV444P支持H264编码。

在这里插入图片描述

要解决此问题,只能使用ffmpeg的sws_scale将YUVJ420P转换为YUV420P,然后将其发送到h264_nvenc硬件编码器进行编码。

#if ISCHANGEFRAME
	if (frame->format == AV_PIX_FMT_YUVJ420P) {
		sws_scale(convert_ctx,frame->data, frame->linesize, 0, Height, frameYUV->data, frameYUV->linesize);
		frameYUV->format = AV_PIX_FMT_YUV420P;
		frameYUV->width = Width;
		frameYUV->height = Height;
		return frameYUV;
	}
#endif

4、补充

1、 libx264可以直接用264编码YUVJ420P,而无需进行格式转换。

2、 YUVJ420P和YUV420P简介

YUVJ420P的字面意思是“使用JPEG颜色范围的YUV420P,并且像素使用的颜色的值范围已更改。

YUV420p的像素颜色范围是[16,235],16表示黑色,235表示白色

YUVJ420P的像素颜色范围是[0,255]。 0表示黑色,255表示白色

FFmpeg的定义和解释:

AV_PIX_FMT_YUV420P,   ///< planar="" yuv="" 4:2:0,="" 12bpp,="" (1="" cr="" &="" cb="" sample="" per="" 2x2="" y="" samples)="" av_pix_fmt_yuvj420p,="">< planar="" yuv="" 4:2:0,="" 12bpp,="" full="" scale="" (jpeg),="" deprecated="" in="" favor="" of="" av_pix_fmt_yuv420p="" and="" setting="" color_range="">

下载

1、测试视频

2、 FFmpeg API H265转码H264源代码

参考

1、

2、 ffmpeg nvidia硬件加速解决方案(参考博客)

3、 ffmpeg一些有关硬解码和软解码的参考

4、 YUV420P和YUVJ420P简介


本文来自本站,转载请注明本文网址:
http://www.pc-fly.com/a/shenmilingyu/article-372913-1.html



温馨提示:喜欢本站的话,请收藏一下本站!

本类教程下载

系统下载排行

网站地图xml | 网站地图html