RTSP/GB28181/HIKSDK/Ehome协议视频平台EasyCVR如何通过ffmpeg 将 H.264 I帧数据转换为 BGR 数据?

EasyCVR作为视频融合平台,能够支持除RTMP以外的大部分协议,包括海康SDK及Ehome私有协议,视频云网关不需要对现有监控架构做调整,支持CDN推流,灵活适应原有架构。

EasyCVR.png

在 EasyCVR 视频处理中,对于部分视频数据需要转换成 BGR 数据才能够使用。

I 帧数据为采用视频压缩算法已经压缩后的数据。数据量小,便于存储和传输。在正式使用时,如播放视频等功能,都需要重新将压缩后的数据还原成YUV 或者 RGB 等模型的程序才可以显示使用。

BGR 数据为和 RGB 相同的数据,仅是顺序不同,RGB 数据时红色、绿色和蓝色的顺序,BGR 是蓝色、绿色和红色的顺序模型。

使用 ffmpeg 代码将 H.264 一帧数据转换成 BGR 数据的功能代码如下。因为 ffmpeg 的代码在 3.x 后,部分接口进行了修改,以下代码在 ffmpeg4.2 中可正常运行。

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
// 将 H.264 帧转换为 BGR 数据
void H264ToBGR(char* data, int dataSize, char* outBuffer) {
	// 1. 将元数据装填到packet
	AVPacket* avPkt = av_packet_alloc();
	avPkt->size = dataSize;
	avPkt->data = (unsigned char*)data;
	static AVCodecContext* codecCtx = nullptr;
	// 2. 创建并配置codecContext
	if (codecCtx == nullptr) {
		AVCodec* h264Codec = avcodec_find_decoder(AV_CODEC_ID_H264);
		codecCtx = avcodec_alloc_context3(h264Codec);
		avcodec_get_context_defaults3(codecCtx, h264Codec);
		avcodec_open2(codecCtx, h264Codec, nullptr);
	}
	// 3. 解码
	auto ret = avcodec_send_packet(codecCtx, avPkt);
	if (ret >= 0) {
		AVFrame* YUVFrame = av_frame_alloc();
		ret = avcodec_receive_frame(codecCtx, YUVFrame);
		if (ret >= 0) {
			// 4.YUV转BGR24
			AVFrame* RGB24Frame = av_frame_alloc();
			AVPixelFormat yuvFmt = convertDeprecatedFormat(codecCtx->pix_fmt);
			struct SwsContext* convertCxt = sws_getContext(
				YUVFrame->width, YUVFrame->height, yuvFmt,
				YUVFrame->width, YUVFrame->height, AV_PIX_FMT_BGR24,
				SWS_POINT, NULL, NULL, NULL);
			printf("yuv 数据的编码格式为 %d\n", yuvFmt);
			// outBuffer将会分配给RGB24Frame->data,AV_PIX_FMT_RGB24格式只分配到RGB24Frame->data[0]
			av_image_fill_arrays(RGB24Frame->data, RGB24Frame->linesize, (unsigned char*)outBuffer,
				AV_PIX_FMT_BGR24, YUVFrame->width, YUVFrame->height, 1);
			sws_scale(convertCxt, YUVFrame->data, YUVFrame->linesize, 0, YUVFrame->height, RGB24Frame->data, RGB24Frame->linesize);
			// 5.清除各对象/context -> 释放内存
			// free context and avFrame
			sws_freeContext(convertCxt);
			av_frame_free(&RGB24Frame);             // RGB24Frame.
		}
		// free context and avFrame
		av_frame_free(&YUVFrame);
	}
	// free context and avFrame
	av_packet_unref(avPkt);
	av_packet_free(&avPkt);
	avcodec_free_context(&codecCtx);
}


// 把已经废除的格式转换成新的格式,防止报 "deprecated pixel format used, make sure you did set range correctly" 错误
AVPixelFormat convertDeprecatedFormat(enum AVPixelFormat format)
{
	switch (format)
	{
	case AV_PIX_FMT_YUVJ420P:
		return AV_PIX_FMT_YUV420P;
		break;
	case AV_PIX_FMT_YUVJ422P:
		return AV_PIX_FMT_YUV422P;
		break;
	case AV_PIX_FMT_YUVJ444P:
		return AV_PIX_FMT_YUV444P;
		break;
	case AV_PIX_FMT_YUVJ440P:
		return AV_PIX_FMT_YUV440P;
		break;
	default:
		return format;
		break;
	}
}

在上述代码中convertDeprecatedFormat主要是转换格式的函数。随着 ffmpeg 程序的升级,很多原有的代码不再建议使用,如果想兼容原有的程序需要做一些处理,否则程序中就会报 warning 警告,虽然不影响使用,但是消除 warning 代码结构会更清晰。

关于EasyCVR视频上云网关

EasyCVR1.png

  • 多终端兼容
    支持传统网络摄像机、NVR、编码器、SDK等设备,最大程度的提高了硬件设备的兼容性;
  • 灵活扩展
    按需灵活扩展、收缩资源,免去了插件安装、浏览器限定等条件,实现了无插件、多平台自由观看回放;
  • 快速接入云端
    支持阿里云、腾讯云、华为云、七牛云等,支持S3和Swift接口的对象存储服务,简单配置,部署更高效。

如果大家还想了解更多关于EasyCVR相关内容,或有视频相关需求,欢迎在博客下方留言,联系我们。

猜你喜欢

转载自blog.csdn.net/TsingSee/article/details/109032720
今日推荐