日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

FFmpeg源碼分析:SwsContext圖像轉(zhuǎn)換上下文

作者:LceChan 更新時(shí)間: 2022-09-25 編程語言

FFmpeg的libswscale模塊提供圖像縮放、圖像格式轉(zhuǎn)換功能。其中貫穿整個(gè)模塊的是SwsContext結(jié)構(gòu)體,方法包括sws_alloc_context分配、sws_init_context初始化、sws_getContext獲取上下文、sws_get_cachedContext獲取緩存,sws_freeContext釋放上下文的方法。

1、SwsContext

SwsContext結(jié)構(gòu)體位于libswscale模塊的swscale_internal.h頭文件,具體如下:

typedef struct SwsContext {
	
    const AVClass *av_class;
 
    SwsFunc swscale;
    int srcW;    // Width  of source      luma/alpha planes.
    int srcH;    // Height of source      luma/alpha planes.
    int dstH;    // Height of destination luma/alpha planes.
    int chrSrcW; // Width  of source      chroma     planes.
    int chrSrcH; // Height of source      chroma     planes.
    int chrDstW; // Width  of destination chroma     planes.
    int chrDstH; // Height of destination chroma     planes.
 
    // 級(jí)聯(lián)上下文,可以把scaler分解為幾步操作
    struct SwsContext *cascaded_context[3];
    int cascaded_tmpStride[4];
    uint8_t *cascaded_tmp[4];
    int cascaded1_tmpStride[4];
    uint8_t *cascaded1_tmp[4];
    int cascaded_mainindex;
 
    double gamma_value;
    int gamma_flag;
    int is_internal_gamma;
    uint16_t *gamma;
    uint16_t *inv_gamma;
    int numDesc;
    int descIndex[2];
    int numSlice;
    struct SwsSlice *slice;
    struct SwsFilterDescriptor *desc;
 
    uint32_t pal_yuv[256];
    uint32_t pal_rgb[256];
    float uint2float_lut[256];
 
    // 垂直縮放的環(huán)形緩沖區(qū)
    int lastInLumBuf;
    int lastInChrBuf;
 
    uint8_t *formatConvBuffer;
    int needAlpha;
 
    // 水平/垂直濾波器
    int16_t *hLumFilter;
    int16_t *hChrFilter;
    int16_t *vLumFilter;
    int16_t *vChrFilter;
    int32_t *hLumFilterPos;
    int32_t *hChrFilterPos;
    int32_t *vLumFilterPos;
    int32_t *vChrFilterPos;
    int hLumFilterSize;
    int hChrFilterSize;
    int vLumFilterSize;
    int vChrFilterSize;
 
    int canMMXEXTBeUsed;
    int warned_unuseable_bilinear;
    int dstY;
	// 選擇算法、優(yōu)化、子采樣的flag
    int flags; 
    // 指向yuv->rgb表的起始位置	
    void *yuvTable; 
	// 表格包含C和SIMD指令
    DECLARE_ALIGNED(16, int, table_gV)[256 + 2*YUVRGB_TABLE_HEADROOM];
    uint8_t *table_rV[256 + 2*YUVRGB_TABLE_HEADROOM];
    uint8_t *table_gU[256 + 2*YUVRGB_TABLE_HEADROOM];
    uint8_t *table_bU[256 + 2*YUVRGB_TABLE_HEADROOM];
    DECLARE_ALIGNED(16, int32_t, input_rgb2yuv_table)[16+40*4];
    int *dither_error[4];
 
    //顏色空間參數(shù)
    int contrast, brightness, saturation;
    int srcColorspaceTable[4];
    int dstColorspaceTable[4];
    int srcRange; // 0 = MPG YUV range, 1 = JPG YUV range
    int dstRange; // 0 = MPG YUV range, 1 = JPG YUV range
 
    const uint8_t *chrDither8, *lumDither8;
    int use_mmx_vfilter;
    int16_t *xyzgamma;
    int16_t *rgbgamma;
    int16_t *xyzgammainv;
    int16_t *rgbgammainv;
    int16_t xyz2rgb_matrix[3][4];
    int16_t rgb2xyz_matrix[3][4];
 
    //swscale()方法的函數(shù)指針
    yuv2planar1_fn yuv2plane1;
    yuv2planarX_fn yuv2planeX;
    yuv2interleavedX_fn yuv2nv12cX;
    yuv2packed1_fn yuv2packed1;
    yuv2packed2_fn yuv2packed2;
    yuv2packedX_fn yuv2packedX;
    yuv2anyX_fn yuv2anyX;
 
    void (*lumToYV12)(uint8_t *dst, const uint8_t *src, const uint8_t *src2, 
	                  const uint8_t *src3, int width, uint32_t *pal);
    void (*alpToYV12)(uint8_t *dst, const uint8_t *src, const uint8_t *src2, 
	                  const uint8_t *src3, int width, uint32_t *pal);
    void (*chrToYV12)(uint8_t *dstU, uint8_t *dstV,const uint8_t *src1, 
	                  const uint8_t *src2, const uint8_t *src3,
                      int width, uint32_t *pal);
 
    // 讀取輸入plane,比如RGB
    void (*readLumPlanar)(uint8_t *dst, const uint8_t *src[4], int width, int32_t *rgb2yuv);
    void (*readChrPlanar)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src[4],
                          int width, int32_t *rgb2yuv);
    void (*readAlpPlanar)(uint8_t *dst, const uint8_t *src[4], int width, int32_t *rgb2yuv);
 
    // 使用bilinear濾波器進(jìn)行縮放
    void (*hyscale_fast)(struct SwsContext *c,
                         int16_t *dst, int dstWidth,
                         const uint8_t *src, int srcW, int xInc);
    void (*hcscale_fast)(struct SwsContext *c,
                         int16_t *dst1, int16_t *dst2, int dstWidth,
                         const uint8_t *src1, const uint8_t *src2,
                         int srcW, int xInc);
 
    // 使用濾波器進(jìn)行水平縮放
    void (*hyScale)(struct SwsContext *c, int16_t *dst, int dstW,
                    const uint8_t *src, const int16_t *filter,
                    const int32_t *filterPos, int filterSize);
    void (*hcScale)(struct SwsContext *c, int16_t *dst, int dstW,
                    const uint8_t *src, const int16_t *filter,
                    const int32_t *filterPos, int filterSize);
 
    // luma平面的色彩空間轉(zhuǎn)換
    void (*lumConvertRange)(int16_t *dst, int width);
    // chroma平面的色彩空間轉(zhuǎn)換
    void (*chrConvertRange)(int16_t *dst1, int16_t *dst2, int width);
 
    int needs_hcscale;
    SwsDither dither;
    SwsAlphaBlend alphablend;
} SwsContext;

2、sws_alloc_context

用于分配圖像轉(zhuǎn)換的上下文,首先是調(diào)用av_mallocz()分配結(jié)構(gòu)體內(nèi)存,然后賦值av_class,初始化默認(rèn)options參數(shù):

SwsContext *sws_alloc_context(void)
{
    SwsContext *c = av_mallocz(sizeof(SwsContext));
 
    av_assert0(offsetof(SwsContext, redDither) + DITHER32_INT == offsetof(SwsContext, dither32));
 
    if (c) {
        c->av_class = &ff_sws_context_class;
        av_opt_set_defaults(c);
    }
 
    return c;
}

3、sws_init_context

初始化圖像轉(zhuǎn)換的上下文,位于libswscale模塊的utils.c。步驟包括:檢查輸入輸出的像素格式是否支持;判斷有沒設(shè)置正確的濾波算法,如果沒有就指定為SWS_BICUBIC算法;檢查源圖像寬高、目標(biāo)圖像寬高是否有效;獲取圖像轉(zhuǎn)換函數(shù);初始化濾波器。代碼如下:

int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
                             SwsFilter *dstFilter)
{
    ......
	
	// 檢查是否支持輸入輸出像素格式
    if (!(unscaled && sws_isSupportedEndiannessConversion(srcFormat) &&
          av_pix_fmt_swap_endianness(srcFormat) == dstFormat)) {
		if (!sws_isSupportedInput(srcFormat)) {
			return AVERROR(EINVAL);
		}
		if (!sws_isSupportedOutput(dstFormat)) {
			return AVERROR(EINVAL);
		}
    }
    // 判斷flags有沒設(shè)置為其中一種算法
    i = flags & (SWS_POINT         |
                 SWS_AREA          |
                 SWS_BILINEAR      |
                 SWS_FAST_BILINEAR |
                 SWS_BICUBIC       |
                 SWS_X             |
                 SWS_GAUSS         |
                 SWS_LANCZOS       |
                 SWS_SINC          |
                 SWS_SPLINE        |
                 SWS_BICUBLIN);
 
    // 如果沒有設(shè)置算法,提供默認(rèn)的算法
    if (!i) {
        if (dstW < srcW && dstH < srcH)
            flags |= SWS_BICUBIC;
        else if (dstW > srcW && dstH > srcH)
            flags |= SWS_BICUBIC;
        else
            flags |= SWS_BICUBIC;
        c->flags = flags;
    } else if (i & (i - 1)) {
        return AVERROR(EINVAL);
    }
    // 檢查參數(shù)是否有效
    if (srcW < 1 || srcH < 1 || dstW < 1 || dstH < 1) {
        return AVERROR(EINVAL);
    }
    if (flags & SWS_FAST_BILINEAR) {
        if (srcW < 8 || dstW < 8) {
            flags ^= SWS_FAST_BILINEAR | SWS_BILINEAR;
            c->flags = flags;
        }
    }
	
    ......
 
    /* unscaled special cases */
    if (unscaled && !usesHFilter && !usesVFilter &&
        (c->srcRange == c->dstRange || isAnyRGB(dstFormat) ||
         isFloat(srcFormat) || isFloat(dstFormat))){
        ff_get_unscaled_swscale(c);
 
        if (c->swscale) {
            return 0;
        }
    }
    // 獲取swscale函數(shù)
    c->swscale = ff_getSwsFunc(c);
	// 初始化濾波器
    return ff_init_filters(c);
nomem:
    ret = AVERROR(ENOMEM);
fail:
    .....
    return ret;
}

其中,ff_getSwsFunc()位于swscale.c,根據(jù)不同平臺(tái)來初始化swscale:

SwsFunc ff_getSwsFunc(SwsContext *c)
{
    sws_init_swscale(c);
 
    if (ARCH_PPC)
        ff_sws_init_swscale_ppc(c);
    if (ARCH_X86)
        ff_sws_init_swscale_x86(c);
    if (ARCH_AARCH64)
        ff_sws_init_swscale_aarch64(c);
    if (ARCH_ARM)
        ff_sws_init_swscale_arm(c);
 
    return swscale;
}

ff_init_filters()負(fù)責(zé)對(duì)濾波器進(jìn)行初始化,濾波器算法包括:均值濾波、雙三次插值濾波、亮度雙三次插值/色度雙線性插值、雙線性濾波、快速雙線性濾波高斯濾波、正交相似變換濾波、最近鄰濾波、正弦濾波、三次樣本插值濾波、內(nèi)部濾波。具體列表如下:

static const ScaleAlgorithm scale_algorithms[] = {
    { SWS_AREA,          "area averaging",                  1 },
    { SWS_BICUBIC,       "bicubic",                         4 },
    { SWS_BICUBLIN,      "luma bicubic / chroma bilinear", -1 },
    { SWS_BILINEAR,      "bilinear",                        2 },
    { SWS_FAST_BILINEAR, "fast bilinear",                  -1 },
    { SWS_GAUSS,         "Gaussian",                        8 },
    { SWS_LANCZOS,       "Lanczos",                        -1 },
    { SWS_POINT,         "nearest neighbor / point",       -1 },
    { SWS_SINC,          "sinc",                           20 },
    { SWS_SPLINE,        "bicubic spline",                 20 },
    { SWS_X,             "experimental",                    8 },
};

4、sws_getContext

獲取圖像轉(zhuǎn)換的上下文,首先設(shè)置相關(guān)參數(shù),然后調(diào)用sws_init_context()來初始化上下文:

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)
{
    SwsContext *c;
 
    c = sws_alloc_set_opts(srcW, srcH, srcFormat,
                           dstW, dstH, dstFormat,
                           flags, param);
    if (!c)
        return NULL;
 
    if (sws_init_context(c, srcFilter, dstFilter) < 0) {
        sws_freeContext(c);
        return NULL;
    }
 
    return c;
}

5、sws_getCachedContext

獲取緩存的圖像轉(zhuǎn)換上下文。首先校驗(yàn)參數(shù)是否一致,如果校驗(yàn)不通過就釋放資源;然后判斷上下文是否存在,如果存在直接復(fù)用,如不存在進(jìn)行分配、初始化操作:

struct SwsContext *sws_getCachedContext(struct SwsContext *context, int srcW,
                                        int srcH, enum AVPixelFormat srcFormat,
                                        int dstW, int dstH,
                                        enum AVPixelFormat dstFormat, int flags,
                                        SwsFilter *srcFilter,
                                        SwsFilter *dstFilter,
                                        const double *param)
{
    static const double default_param[2] = { SWS_PARAM_DEFAULT,
                                             SWS_PARAM_DEFAULT };
    int64_t src_h_chr_pos = -513, dst_h_chr_pos = -513,
            src_v_chr_pos = -513, dst_v_chr_pos = -513;
 
    if (!param)
        param = default_param;
    // 校驗(yàn)參數(shù),如果不通過直接釋放資源
    if (context &&
        (context->srcW      != srcW      ||
         context->srcH      != srcH      ||
         context->srcFormat != srcFormat ||
         context->dstW      != dstW      ||
         context->dstH      != dstH      ||
         context->dstFormat != dstFormat ||
         context->flags     != flags     ||
         context->param[0]  != param[0]  ||
         context->param[1]  != param[1])) {
 
        av_opt_get_int(context, "src_h_chr_pos", 0, &src_h_chr_pos);
        av_opt_get_int(context, "src_v_chr_pos", 0, &src_v_chr_pos);
        av_opt_get_int(context, "dst_h_chr_pos", 0, &dst_h_chr_pos);
        av_opt_get_int(context, "dst_v_chr_pos", 0, &dst_v_chr_pos);
        sws_freeContext(context);
        context = NULL;
    }
    // 如果上下文不存在,進(jìn)行分配、初始化操作
    if (!context) {
        if (!(context = sws_alloc_context()))
            return NULL;
        context->srcW      = srcW;
        context->srcH      = srcH;
        context->srcFormat = srcFormat;
        context->dstW      = dstW;
        context->dstH      = dstH;
        context->dstFormat = dstFormat;
        context->flags     = flags;
        context->param[0]  = param[0];
        context->param[1]  = param[1];
 
        av_opt_set_int(context, "src_h_chr_pos", src_h_chr_pos, 0);
        av_opt_set_int(context, "src_v_chr_pos", src_v_chr_pos, 0);
        av_opt_set_int(context, "dst_h_chr_pos", dst_h_chr_pos, 0);
        av_opt_set_int(context, "dst_v_chr_pos", dst_v_chr_pos, 0);
 
        if (sws_init_context(context, srcFilter, dstFilter) < 0) {
            sws_freeContext(context);
            return NULL;
        }
    }
    return context;
}

6、sws_freeContext

用于釋放圖像轉(zhuǎn)換上下文,各種釋放操作:

void sws_freeContext(SwsContext *c)
{
    int i;
    if (!c)
        return;
 
    for (i = 0; i < 4; i++)
        av_freep(&c->dither_error[i]);
 
    av_freep(&c->vLumFilter);
    av_freep(&c->vChrFilter);
    av_freep(&c->hLumFilter);
    av_freep(&c->hChrFilter);
 
    av_freep(&c->vLumFilterPos);
    av_freep(&c->vChrFilterPos);
    av_freep(&c->hLumFilterPos);
    av_freep(&c->hChrFilterPos);
    av_freep(&c->yuvTable);
    av_freep(&c->formatConvBuffer);
 
    sws_freeContext(c->cascaded_context[0]);
    sws_freeContext(c->cascaded_context[1]);
    sws_freeContext(c->cascaded_context[2]);
    memset(c->cascaded_context, 0, sizeof(c->cascaded_context));
    av_freep(&c->cascaded_tmp[0]);
    av_freep(&c->cascaded1_tmp[0]);
 
    av_freep(&c->gamma);
    av_freep(&c->inv_gamma);
    ff_free_filters(c);
    av_free(c);
}

原文鏈接:https://blog.csdn.net/tonychan129/article/details/127025453

欄目分類
最近更新