原文链接:https://blog.csdn.net/jklinux/article/details/94432008
ffmpeg里的libswscale库用于图像数据格式的转换.
AVFrame 类型对象用于描述非压缩的音视频数据信息, 此对象本身不提供存储音视频数据的缓冲区,只用于记录数据格式,图像分辨率,数据缓冲区地址等信息.
typedef struct AVFrame {
#define AV_NUM_DATA_POINTERS 8
uint8_t *data[AV_NUM_DATA_POINTERS]; //此指针数组是用于存放数据缓冲区地址,因有可能是平面的数据,所有用了多个指针变量存放不同分量的数据缓冲区
int linesize[AV_NUM_DATA_POINTERS]; //存放每个缓冲区的一行数据的字节数
...
}AVFrame
所用的函数说明:
AVFrame *av_frame_alloc(void); //用于动态创建一个AVFrame对象
//因AVFrame本身不提供存储数据的缓冲区,所以需要创建出数据缓冲区后再使用下面函数配置AVFrame对象
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],
const uint8_t *src,
enum AVPixelFormat pix_fmt, int width, int height, int align);
struct SwsContext; //此类型对象用于描述原数据格式及目标格式, 原分辨率及目标分辨率等.
// sws_getContext函数根据指定的参数生成一个SwsContext对象
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);
// flags参数是原分辨率与目标分辨率不一致时使用哪种算法来调整.
// srcFilter, dstFilter设置原图形及生成的图像使用的过滤算法. 不会可设为NULL
// param参数指定调整图像缩放的算法. 可设为NULL使用默认算法.
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[]);
// c参数指定使用包含图像数据格式转换信息的struct SwsContext对象
// srcSlice参数用于指定的原图像数据缓冲区地址
// srcStride参数用于指定原数据缓冲区一行数据的大小
// srcSliceY参数用于指定从原图像的第几行开始转换
// srcSliceH参数用于指定转换到原图像的第几行.
// dst参数用于指定存放生成图像数据的缓冲区地址
// dstStride参数指定存放生成图像的一行数据大小的缓冲区
用法, 如yuv422转换成420p:
1. 创建AVFrame对象
AVFrame *frm422 = av_frame_alloc();
AVFrame *frm420p = av_frame_alloc();
2. 绑定数据缓冲区
av_image_fill_arrays(frm422->data, frm422->linesize, buf_422, AV_PIX_FMT_YUYV422, w, h, 16);
av_image_fill_arrays(frm420p->data, frm420p->linesize, buf_420p, AV_PIX_FMT_YUV420P, w, h, 16);
3. 指定原数据格式,分辨率及目标数据格式,分辨率
struct SwsContext *sws = sws_getContext(w, h, AV_PIX_FMT_YUYV422, w,h, AV_PIX_FMT_YUV420P,
SWS_BILINEAR, NULL, NULL, NULL);
4. 转换并调整分辨率
int ret = sws_scale(sws, frm422->data, frm422->linesize, 0, h, frm420p->data, frm420p->linesize);
5. 回收空间
av_frame_free(&frm422);
av_frame_free(&frm420p);
sws_freeContext(sws);
用法, argb转换成yuv420p:
int MyDataCovert::argb32Toyuv420p(uint8_t *buf_argb, uint8_t *buf_420p, int w, int h)
{
AVFrame *frmArgb = av_frame_alloc();
AVFrame *frm420p = av_frame_alloc();
//绑定数据缓冲区
avpicture_fill((AVPicture *)frmArgb, buf_argb, AV_PIX_FMT_BGRA, w, h);
avpicture_fill((AVPicture *)frm420p, buf_420p, AV_PIX_FMT_YUV420P, w, h);
//指定原数据格式,分辨率及目标数据格式,分辨率
struct SwsContext *sws = sws_getContext(w, h, AV_PIX_FMT_BGRA, w,h, AV_PIX_FMT_YUV420P,
SWS_BILINEAR, NULL, NULL, NULL);
//转换
int ret = sws_scale(sws, frmArgb->data, frmArgb->linesize, 0, h, frm420p->data, frm420p->linesize);
av_frame_free(&frmArgb);
av_frame_free(&frm420p);
sws_freeContext(sws);
return (ret == h) ? 0 : -1;
}