原文鏈接: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;
}