sws_getContext和sws_scale分析

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参数是指选择的转换算法,如果没有精准的要求,这些算法差别不大,一般用SWS_BILINEAR参数,可选类型定义在//libswscale/swscale.h内,如下:
Intel® Pentium® Silver N6000 @ 1.10GHz 4
Thread(s) per core: 1 Core(s) per socket: 4
1920x1080p25 UYVY422–>NV12
SWS_BILINEAR–>30-40ms
SWS_FAST_BILINEAR–>10ms

#define SWS_FAST_BILINEAR 1
#define SWS_BILINEAR 2
#define SWS_BICUBIC 4
#define SWS_X 8
#define SWS_POINT 0x10
#define SWS_AREA 0x20
#define SWS_BICUBLIN 0x40
#define SWS_GAUSS 0x80
#define SWS_SINC 0x100
#define SWS_LANCZOS 0x200
#define SWS_SPLINE 0x400

i9-9900KF CPU @ 3.60GHz 8核16线程下 3840x2160时,yuv420p->uyvy422,用SWS_BILINEAR转化一帧视频消耗31ms,用SWS_POINT消耗3ms。以上各个参数分析
AV_PIX_FMT_UYVY422 1080p50转成AV_PIX_FMT_UYVY422 720p50时,SWS_FAST_BILINEAR和SWS_AREA消耗cpu最小,并且负载均衡,其内部应该开启多个线程一起转换了。其他几个参数负载极不均衡而且对cpu消耗很大。

srcFilter, 输入图像的滤波器信息, 如果不用赋值NULL
dstFilter, 输出图像的滤波器信息, 如果不用赋值NULL
param 特定缩放算法需要的参数,如果不用赋值NULL

int attribute_align_arg sws_scale(struct SwsContext *c,
const uint8_t * const srcSlice[],
const int srcStride[], int srcSliceY,
int srcSliceH, uint8_t *const dst[],
const int dstStride[])

真正做转换的函数,参数分析:
这个转换是深拷贝,需要给dst申请空间,实测yuv420->uyvy422每执行一次就输出一帧,开始不需要多帧输入填充缓存。
sws_scale转换包含像素格式转换和缩放拉伸转换,输入输出可以是rgb或yuv中的任意一种。

srcSlice对应frame->data
yuv各种格式在AVFrame::data[]中的存储方式,另一篇博客:YUV的plannar,packet及semi-planar格式

srcStride这个参数填入frame->linesize linesize[]
数组中保存的是对应通道的数据宽度
linesize[0]——-Y分量的宽度
linesize[1]——-U分量的宽度
linesize[2]——-V分量的宽度
linesize[0]的值并不一定等于图片的宽度,有时候为了对齐各解码器的CPU(32位/64位),实际尺寸会大于图片的宽度,这点在我们编程时(比如OpengGL硬件转换/渲染)要特别注意,否则解码出来的图像会异常,增加linesize[0]的值使得,linesize[0]/32或linesize[0]/64为整数,叫做对齐cpu字节。
以上是planner格式,如果是packet格式,如1920x1080 uyvy422,linesize[1],linesize[2]都为0,因为只有一个分量了,此时linesize[0]为1920*2 = 3840
实测yuv422格式,1080i50视频,在x86上没有格式对齐, frame->linesize[0]为1920x2。此时frame->linesize[0] x frame->width即为此帧frame数据大小。
如果是planner格式的像素,frame的大小应该是(frame->linesize[0]+frame->linesize[1]+frame->linesize[2]) x frame->width。如果用宽x高x像素格式字节数算的话,当像需要补齐字节时,得到的值会小于frame包含的真实值,进行memcpy赋值时会少复制内容。

参数int srcSliceY, int srcSliceH,定义在输入图像上处理区域
srcSliceY是起始位置,srcSliceH是处理多少行。如果srcSliceY=0,srcSliceH=height,表示一次性处理完整个图像。这种设置是为了多线程并行,例如可以创建两个线程,第一个线程处理 [0, h/2-1]行,第二个线程处理 [h/2, h-1]行。并行处理加快速度。

参数uint8_t *const dst[], const int dstStride[]定义输出图像信息(输出的每个颜色通道数据指针,每个颜色通道行字节数)

与其类似的函数还有: sws_getCachedContext ,区别在于: sws_getContext 可以用于多路码流转换,为每个不同的码流都指定一个不同的转换上下文,而 sws_getCachedContext 只能用于一路码流转换。

/**
 * Free the swscaler context swsContext.
 * If swsContext is NULL, then does nothing.
 */
void sws_freeContext(struct SwsContext *swsContext);

释放sws_scale

字节对齐解释:比如704*576分辨率的视频,它的width=704,height=576,摄像机芯片一般会要求64或者128对齐,当128位对齐时,704不能被128整除,需要在每一行结尾补64字节0x00占位,它的linesize也就是每一行的长度768。

参考:https://blog.csdn.net/weixin_30401605/article/details/94875795?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163635474716780357220302%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163635474716780357220302&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-13-94875795.pc_search_result_cache&utm_term=yuv420%E5%9C%A8AVFrame-%3Edata%E4%B8%AD%E6%80%8E%E4%B9%88%E5%AD%98%E5%82%A8%E7%9A%84&spm=1018.2226.3001.4187

参考:https://blog.csdn.net/m0_37346206/article/details/106634388

ffmpeg是音视频必备,但即使从业数年,它似乎依然有无穷的秘密,感兴趣添加笔者微信:YQW1163720468,加入ffmpeg微信群讨论。但记得备注:ffmpeg爱好者

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
sws_getContextFFmpeg中用于图像转换的函数,其函数原型为: ``` 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); ``` 参数说明: - srcW:源图像宽度 - srcH:源图像高度 - srcFormat:源图像像素格式 - dstW:目标图像宽度 - dstH:目标图像高度 - dstFormat:目标图像像素格式 - flags:转换标志,可以为0或SWS_FAST_BILINEAR等 - srcFilter:源图像滤波器 - dstFilter:目标图像滤波器 - param:其它参数 使用示例: ``` // 初始化源图像和目标图像的宽度、高度和像素格式 int src_width = 640; int src_height = 480; AVPixelFormat src_pix_fmt = AV_PIX_FMT_RGB24; int dst_width = 320; int dst_height = 240; AVPixelFormat dst_pix_fmt = AV_PIX_FMT_YUV420P; // 分配输入图像和输出图像所需的内存 uint8_t *src_data[4]; int src_linesize[4]; av_image_alloc(src_data, src_linesize, src_width, src_height, src_pix_fmt, 1); uint8_t *dst_data[4]; int dst_linesize[4]; av_image_alloc(dst_data, dst_linesize, dst_width, dst_height, dst_pix_fmt, 1); // 创建SwsContext struct SwsContext *sws_ctx = sws_getContext(src_width, src_height, src_pix_fmt, dst_width, dst_height, dst_pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL); // 转换图像 sws_scale(sws_ctx, src_data, src_linesize, 0, src_height, dst_data, dst_linesize); // 释放资源 sws_freeContext(sws_ctx); av_freep(&src_data[0]); av_freep(&dst_data[0]); ``` 该示例代码中,首先初始化源图像和目标图像的宽度、高度和像素格式,并分配输入图像和输出图像所需的内存。然后创建SwsContext,调用sws_scale函数实现图像转换,并最后释放资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

、、、、燕庆伟、、、、

分享对你有帮助,打赏一下吧!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值