網(wǎng)站首頁 編程語言 正文
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
- 上一篇:FFmpeg源碼分析:圖像常用操作
- 下一篇:判斷單鏈表保存的字符串是否是回文字符串
相關(guān)推薦
- 2022-08-14 Android實(shí)現(xiàn)顯示和隱藏密碼功能的示例代碼_Android
- 2022-05-21 云原生要素配置分離ConfigMap創(chuàng)建方式_云其它
- 2022-04-10 python?tkinter實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能_python
- 2022-09-06 C#面向?qū)ο缶幊讨欣锸咸鎿Q原則的示例詳解_C#教程
- 2022-04-01 LC_CTYPE: cannot change locale (en_US.UTF-8): No s
- 2022-08-20 Python超細(xì)致探究面向?qū)ο骭python
- 2022-06-10 利用Python實(shí)現(xiàn)RSA加密解密方法實(shí)例_python
- 2022-06-21 C語言超全面講解函數(shù)的使用方法上_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支