ffmpeg rgb與yuv的轉換

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章