RTSP/GB28181/HIKSDK/Ehome协议视频平台EasyCVR如何通过ffmpeg 将 H.264 I帧数据转换为 BGR 数据?
EasyCVR作为视频融合平台,能够支持除RTMP以外的大部分协议,包括海康SDK及Ehome私有协议,视频云网关不需要对现有监控架构做调整,支持CDN推流,灵活适应原有架构。
在 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视频上云网关
- 多终端兼容
支持传统网络摄像机、NVR、编码器、SDK等设备,最大程度的提高了硬件设备的兼容性; - 灵活扩展
按需灵活扩展、收缩资源,免去了插件安装、浏览器限定等条件,实现了无插件、多平台自由观看回放; - 快速接入云端
支持阿里云、腾讯云、华为云、七牛云等,支持S3和Swift接口的对象存储服务,简单配置,部署更高效。
如果大家还想了解更多关于EasyCVR相关内容,或有视频相关需求,欢迎在博客下方留言,联系我们。