记一次从AviSynth到VapourSynth的迁移(2):感受不同的API 下
距离写上一篇博文已经过去几天了(事实上那篇博文在更早的几天就写了草稿)。这几天学到了不少东西,硬塞到上一篇博文中好像不太合适;而且上一篇博文就是在思路不太清时写,有点混乱。总之,干脆新写一篇。
为了加强理解、尽量全面,可能会有些重复的话。
srcp
、dstp
的理解
约定俗成的变量命名,src
已经习惯,是输入,而dsp
则是结果。
关于srcp
和dstp
,通常这样定义
1 |
|
getReadPtr()
和getWritePte()
均是uint8_t *
型,为满足不同位深的输入输出,也就是能够给不同类型的变量赋值,用reinterpret_cast
做类型转换,转换为模版中的T
。- 需要注意到,
srcp
和dstp
已经包含了平面信息,或者说代表了特定平面,在滤镜核心处理函数中,用for循环遍历各个平面,for循环内就会基于srcp
和dstp
,对单个平面做处理。 - 注意
srcp
、dstp
是指针,这个在稍后会继续说。
stride
的理解
avs api和vs api的一大区别,就是隐藏在习惯变量名不同(pitch
与stride
)之下的单位问题。
从Doc上看,avs api获取的pitch
和vs api获取的stride
都是以字节为单位。在使用中,vs框架下要除以变量所占的字节,即
1 |
|
但我读过的几份avs滤镜代码,都是直接用的,没有除sizeof
。
突然明白,我忘了一个事情,**sizeof(uint8_t)
= 1啊**,所以不需要除sizeof
,是不是以字节为单位,都是一样的啊。
疑问的解释
我一直在纠结下面的avs与vs代码会不会有区别。
1 |
|
但其实这个问题是不存在的。对于avs,基于全程8bit的假设,sizeof
= 1,虽然src_pitch
是以字节为单位,但数值上与target_width
是同级的;对于vs,src_stride
是除过sizof
的,与target_width
单位一致。
所以无论vs怎么写,与avs都是一致的,且srcp
与dstp
数值都是同级的。
stride
与dstp
的共同作用
类似dstp += dst_stride;
这样的语句,实现了指针的移动,让继续处理下一帧?是处理同列中个下个像素。
而这话也没有错,但有种误导的感觉,其实和上面是一个意思,只不过上面单独处理列,这个是行和列同时处理。dstp[y + x * dst_stride]
应该是二维平面上的指针移动。
详情在另一篇博文里写了。
VapourSynth数据结构的猜测
(有人说编程是算法+数据结构,现在终于能理解到这句话了)
简单地说,是像一维数组那样横着排的?对dstp
加上一个width
就到下一帧?
但这样想,上面那样的dstp[y + x * dst_stride]
又说不通了。
void
函数做了什么
这个问题看上去很蠢,但也许是我上半年写Python留下的后遗症。总以为函数后要return
个什么东西,仿佛把封装好的函数当成一个计算黑箱。这样理解也谈不上错吧,但却让我在一开始读vs滤镜代码时一头雾水。
经过了一个void
函数,函数内的全局变量(或者是生存期大过该函数的变量)已经被改变。简单地说,就是“酒肉穿肠过,该变的都变了”的意思。
vsapi
的理解
可以将滤镜分为两类:一类是resize型滤镜,输入输出的尺寸不一致;一类是非resize型滤镜,输入输出的尺寸一致。
对于后者,在初始化函数FilterInit()
中,只需原样写下vi
即可
1 |
|
对于前者,要在初始化中将尺寸改写为输出尺寸
1 |
|
这样就保证了输出的dst
是resize后的尺寸,否则照上面那样写,(与输入源不一样的尺寸)会报错。
写法不是唯一的,也可以在FilterCreate()
函数里写,只是我还不太会…
遇事不决用double
emmm困扰了我一整天的颜色问题,把函数内部处理全变成double,直到输出时再改成所需的类型,颜色终于正常了。
现在毕竟还在起步阶段,先把能正常运行的程序写出来,再考虑提升性能的事情。
关于编译与调用
要保持编译时用的头文件与VapourSynth SDK文件夹中的头文件一致,否则无法调用。
(所以在配置编译文件时需要动点脑子)
C++的基础
进一步理解C++的类型转换
编译相关
两次编译的结果,hash不会一样的,但二进制文件大小一样。
零散的知识点
递归函数(调用了自身的函数)没法内联。
静态函数(用static
关键字声明)不可在文件外被调用。