FFmpeg源码分析:SwsContext图像转换上下文

编程入门 行业动态 更新时间:2024-10-15 02:24:16

FFmpeg源码分析:SwsContext图像转换<a href=https://www.elefans.com/category/jswz/34/1770489.html style=上下文"/>

FFmpeg源码分析:SwsContext图像转换上下文

FFmpeg的libswscale模块提供图像缩放、图像格式转换功能。其中贯穿整个模块的是SwsContext结构体,方法包括sws_alloc_context分配、sws_init_context初始化、sws_getContext获取上下文、sws_get_cachedContext获取缓存,sws_freeContext释放上下文的方法。

1、SwsContext

SwsContext结构体位于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.// 级联上下文,可以把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];// 垂直缩放的环形缓冲区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;// 选择算法、优化、子采样的flagint 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];//颜色空间参数int contrast, brightness, saturation;int srcColorspaceTable[4];int dstColorspaceTable[4];int srcRange; // 0 = MPG YUV range, 1 = JPG YUV rangeint dstRange; // 0 = MPG YUV range, 1 = JPG YUV rangeconst 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()方法的函数指针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,比如RGBvoid (*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滤波器进行缩放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);// 使用滤波器进行水平缩放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平面的色彩空间转换void (*lumConvertRange)(int16_t *dst, int width);// chroma平面的色彩空间转换void (*chrConvertRange)(int16_t *dst1, int16_t *dst2, int width);int needs_hcscale;SwsDither dither;SwsAlphaBlend alphablend;
} SwsContext;

2、sws_alloc_context

用于分配图像转换的上下文,首先是调用av_mallocz()分配结构体内存,然后赋值av_class,初始化默认options参数:

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

初始化图像转换的上下文,位于libswscale模块的utils.c。步骤包括:检查输入输出的像素格式是否支持;判断有没设置正确的滤波算法,如果没有就指定为SWS_BICUBIC算法;检查源图像宽高、目标图像宽高是否有效;获取图像转换函数;初始化滤波器。代码如下:

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有没设置为其中一种算法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);// 如果没有设置算法,提供默认的算法if (!i) {if (dstW < srcW && dstH < srcH)flags |= SWS_BICUBIC;else if (dstW > srcW && dstH > srcH)flags |= SWS_BICUBIC;elseflags |= SWS_BICUBIC;c->flags = flags;} else if (i & (i - 1)) {return AVERROR(EINVAL);}// 检查参数是否有效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函数c->swscale = ff_getSwsFunc(c);// 初始化滤波器return ff_init_filters(c);
nomem:ret = AVERROR(ENOMEM);
fail:.....return ret;
}

其中,ff_getSwsFunc()位于swscale.c,根据不同平台来初始化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()负责对滤波器进行初始化,滤波器算法包括:均值滤波、双三次插值滤波、亮度双三次插值/色度双线性插值、双线性滤波、快速双线性滤波高斯滤波、正交相似变换滤波、最近邻滤波、正弦滤波、三次样本插值滤波、内部滤波。具体列表如下:

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

获取图像转换的上下文,首先设置相关参数,然后调用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

获取缓存的图像转换上下文。首先校验参数是否一致,如果校验不通过就释放资源;然后判断上下文是否存在,如果存在直接复用,如不存在进行分配、初始化操作:

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;// 校验参数,如果不通过直接释放资源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;}// 如果上下文不存在,进行分配、初始化操作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

用于释放图像转换上下文,各种释放操作:

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);
}

更多推荐

FFmpeg源码分析:SwsContext图像转换上下文

本文发布于:2024-03-04 18:22:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1710039.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:上下文   源码   图像   FFmpeg   SwsContext

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!