热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

YUV像素格式转换

本文像素格式转换用到的库是FFmpeg的libswscale,将YUV像素格式数据转换成RGB像素格式数据。一、使用的相关函数说明:1、获取像素

本文像素格式转换用到的库是 FFmpeg 的 libswscale,将 YUV 像素格式数据转换成 RGB 像素格式数据。

一、使用的相关函数说明:

1、获取像素格式转换上下文函数:

struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param);

参数说明:

srcW, srcH, srcFormat:原始宽高和原始像素格式(我们这里原始像素格式是yuv420p);
dstW, dstH, dstFormat:目标宽高和目标像素格式(我们这里原始像素格式是rgb24),不仅可以转换像素格式,也可以转换宽高;
flag:指定使用何种算法,例如快速线性、差值和矩阵等等,不同的算法性能也不同,快速线性算法性能相对较高。只针对尺寸的变换。

/* values for the flags, the stuff on the command line is different */ #define SWS_FAST_BILINEAR 1 #define SWS_BILINEAR 2 #define SWS_BICUBIC 4 #define SWS_X 8 #define SWS_POINT 0x10 #define SWS_AREA 0x20 #define SWS_BICUBLIN 0x40 #define SWS_GAUSS 0x80 #define SWS_SINC 0x100 #define SWS_LANCZOS 0x200 #define SWS_SPLINE 0x400

srcFilter, stFilter:这两个参数是做过滤器用的,可以传 nullptr;
param:和 flag 算法相关,也可以传 nullptr;

返回值:成功返回转换格式上下文指针,失败返回 NULL;

注意:使用完格式转换上下文最后不要忘记调用函数 void sws_freeContext(struct SwsContext *swsContext) 释放上下文;有人可能会有疑问,调用的是 sws_getContext 函数,函数名里并没有 create 或者 alloc 字眼,也需要释放吗?我们可以参考一下源码:

YUV像素格式转换

发现源码当中调用了 sws_alloc_set_opts,所以最后是需要释放上下文的。我们也可以使用以下函数来创建上下文:

struct SwsContext *sws_alloc_context(void); int av_opt_set(void *obj, const char *name, const char *val, int search_flags);

2、转换函数:

int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[]);

参数说明:

struct SwsContext *c:像素格式转换上下文;
const uint8_t *const srcSlice[]:输入的数据,silice可以理解为一帧;
const int srcStride[]:输入数据的每一个平面的每一行的大小(linesize),而不是每一个平面的总大小;
int srcSliceY:从哪个位置开始处理,直接传0即可;
int srcSliceH:图像的高度;
uint8_t *const dst[]:输出的数据;
const int dstStride[]:输出数据的每一个平面的每一行的大小;

注意:sws_scale 函数不会为传入的输入数据和输出数据创建堆空间

3、创建输入输出缓冲区:

#include int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);

参数说明:

(uint8_t *pointers[4]:缓冲区数组(除了 Y、U 和 V 三个分量,可能会有透明度分量,所以数组 size 为 4);
int linesizes[4]:每个平面的每一行的大小数组;
int w, int h, enum AVPixelFormat pix_fmt:图片的宽、高和像素格式;
int align:是否对齐,一般传1;

创建的缓冲区数组指向堆空间,最后我们需要使用函数 av_pfree 释放它;不确定缓冲区是否需要释放的话,可以参考函数注释或者源码;源码内部是有调用 av_malloc 函数的,所以需要我们去释放。

二、示例代码:

示例代码中 inData 输入缓冲区分成了四块,每一块指向一个分量,为了兼容透明分量,指针数组size为4,以YUV420P为例,inData的第1个元素指向 Y 分量,第2个元素指向 U 分量,第3个元素指向 V 分量,一帧的 YUV 数据是连续的,如图:

YUV像素格式转换

在音频中没有行的概念 linesize 就是一个平面的大小,但是在视频中是有行的概念的,inStrides中存储的是一帧数据每一行中 Y、U 和 V 分量的长度,以 YUV420P 为例,Y 的长度是一帧的宽度,U 的长度是一帧的宽度的一半,V 的长度也是一帧的宽度的一半。outData 和 outStrides 是同样的道理。

#include "ffmpegutils.h" #include #include extern "C" { #include #include #include } FFmpegUtils::FFmpegUtils() { } //void FFmpegUtils::convretRawVideo(RawVideoFile &in, RawVideoFile &out) void FFmpegUtils::convretRawVideo(RawVideoFrame &in, RawVideoFrame &out) { int ret = 0; // 转换格式上下文 SwsContext *ctx = nullptr; // 输入输出缓冲区 // inData 和 outData 指向一帧的数据 uint8_t *inData[4], *outData[4]; // 每个平面一行的大小 int inStrides[4], outStrides[4]; // 每一帧图片的大小 int inFrameSize, outFrameSize; /* QFile inFile(in.filename); QFile outFile(out.filename); */ ret = av_image_alloc(inData, inStrides, in.width, in.height, in.format, 1); if (ret

推荐阅读
author-avatar
gerardlong
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有