记一次从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关键字声明)不可在文件外被调用。