搜索 社区服务 统计排行 帮助
  • 5262阅读
  • 20回复

[讨论]自立更生 不愁吃穿? AVS filter 制作入门…

楼层直达
级别: 版主
注册时间:
2001-11-21
在线时间:
0小时
发帖:
2803
自立更生 不愁吃穿? AVS filter制作入门…

在21世纪的今天,相信大家都使用或听说过avisynth这个东西吧。这个软件有大量的第三方制作的filter供用户选择。不过,因为其中大部分是个人制作的开源代码的软件,使得质量参差不齐。 有时候会碰到一个很好的filter,但离自己需要的就是差了那么一点,这时候就会想如果这东西能这样改一下就好了。这篇文章就是和大家讨论AVS filter的制作入门的。


当然,要写AVS的filter必然要有基本的C++知识和对视频处理有一定的了解
大部分会看这篇文章的人估计都对视频处理有一定的了解了,而对C++不了解的朋友们可以在机器压制的空闲时间内学习一下C++.


下面将借用Avisynth网站上的入门程序范例来讲述AVS的基本结构。
(注:作者对C++的中文词汇不太了解,所以大家看的时候请谅解)

#include "windows.h"
#include "avisynth.h"


class Invert : public GenericVideoFilter {
public:
Invert(PClip _child) : GenericVideoFilter(_child) {}
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};

PVideoFrame __stdcall Invert::GetFrame(int n, IScriptEnvironment* env) {

PVideoFrame src = child->GetFrame(n, env);
PVideoFrame dst = env->NewVideoFrame(vi);

const unsigned char* srcp = src->GetReadPtr();
unsigned char* dstp = dst->GetWritePtr();

const int src_pitch = src->GetPitch();
const int dst_pitch = dst->GetPitch();
const int row_size = dst->GetRowSize();
const int height = dst->GetHeight();

for (int y = 0; y < height; y++) {
for (int x = 0; x < row_size; x++) {
dstp[x] = srcp[x] ^ 255;
}
srcp += src_pitch;
dstp += dst_pitch;
}

return dst;
}

AVSValue __cdecl Create_Invert(AVSValue args, void* user_data, IScriptEnvironment* env) {
return new Invert(args[0].AsClip());
}

extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) {
env->AddFunction("Invert", "c", Create_Invert, 0);
return "`Invert' sample plugin";
}

#include "avisynth.h"

这两句的意思很简单,就是让这个软件能使用avs的数据结构和接口,基本上放进去就行了。


class Invert : public GenericVideoFilter {

}

这里是建立Invert这个class,另外把Invert作为GenericVideoFilter这个Class的subclass,这样就可以让Invert使用AVS里面已经建立好的数据结构和接口。

Invert(PClip _child) : GenericVideoFilter(_child) {}
这是Invert的constructor, PClip _child是一个指向一段视频的pointer, 在GetFrame里面就可以对这段视频进行处理。

PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);

GetFrame 就是处理视频的function,每当AVS下游的程序(比如VirtualDub)向AVS要求 帧n 的时候,AVS就会运行这个function,然后把处理完的结果发给下游的程序。IScriptEnvironment* env 是记录和控制整个AVS脚本里面数据和filter流程的class.

下面开始讲如何在GetFrame 里面处理视频。

PVideoFrame src = child->GetFrame(n, env);

这里建立了一个pointer src, 它指向child->GetFrame(n, env) 返回的结果,也就是我们要处理的片源。

PVideoFrame dst = env->NewVideoFrame(vi);
这里又建立一个pointer dst, 并用env->NewVideoFrame(vi) 建立了一个新的帧, 这样我们可以把处理后的结果放在里面然后交给AVS. 这里新建立的帧使用的vi作为输入,vi里面包含了片源帧的数据,所以新建立的帧和片源在大小,格式上都是一样的。


const unsigned char* srcp = src->GetReadPtr();

建立一个pointer指向片源帧的第一个字节。注意这里是只读的pointer。如果用GetReadPtr(PLANAR_Y)的话就可以取得指向灰度plane的pointer.

unsigned char* dstp = dst->GetWritePtr();
这里建立一个可写的pointer到我们前面建立的新的要输出的帧。


const int src_pitch = src->GetPitch();

这里取得片源的pitch, pitch在avs里面的定义就是每一行所占的字节数。注意,如果是 GetPitch(PLANAR_Y)的话就是取得画面灰度plane的pitch, 同样还有PLANAR_U和PLANAR_V, 这在处理YV12等格式的时候需要用到。

const int dst_pitch = dst->GetPitch();
这里取得输出帧的pitch
const int row_size = dst->GetRowSize();

这里取得输出帧的行宽,注意这里还是字节数而不是像素,大部分时候这和pitch是一样的,但是在crop后会有区别。


const int height = dst->GetHeight();
取得输出帧的行数,这里是以像素的单位的。

for (int y = 0; y < height; y++) {
for (int x = 0; x < row_size; x++)
dstp[x] = srcp[x] ^ 255;
srcp += src_pitch;
dstp += dst_pitch;
}

这一段就是真正处理视频的程序。个像素的数值都被倒过来了。注意这里pointer每次移动的是pitch而不是rowsize. 就像上面说的,crop后pitch和rowsize会不一样,实际在内存里每行还是pitch个字节。


return dst;
把dst返回给AVS.


AVSValue __cdecl Create_Invert(AVSValue args, void* user_data, IScriptEnvironment* env) {
return new Invert(args[0].AsClip());
}


这个function是用来在script里面运行filter function的时候使用的。注意里面的
”return new Invert(args[0].AsClip()); “ 这里建立了一个Invert class的 instance. AVS脚本里面filter的argument也是从这里输入到filter里面来的。比如args[0] 就是clip, 要处理的片源。


extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)

这个function的功能就是让AVS知道Invert这个filter的存在。在loadplugin的时候AVS就会运行这个function.

env->AddFunction("Invert", "c", Create_Invert, 0);
这里就把这个function的名称,类型等在AVS注册,这样在AVS就可以识别和运行在脚本里面出现的Invert()了。


return "`Invert' sample plugin";
//这里作为loadplugin的返回值,一般被忽略掉。

希望在看完这个后对大家有一些启发.
英文好的可以看下面这个, 比我写的要详细许多.
AVS网站上的入门
http://www.avisynth.org/BensAviSynthDocs


暂时完了...........
等我多积累点经验后再继续写.....
可能吧........

大家有什么问题欢迎讨论..........
另外欢迎用中文学习过c++的人帮助我修正一些用词.

Version log:
Version 0.1 2/24 first draft with basic explanations

live id: liusu119@hotmail.com
email: liusu119@gmail.com
级别: 新手上路
注册时间:
2004-01-13
在线时间:
0小时
发帖:
658
只看该作者 1楼 发表于: 2006-02-25
……C++啊……,没有学过任何程序语言,这个会不会难啊?

羊骑车…[/KH]
级别: 新手上路
注册时间:
2003-06-23
在线时间:
1小时
发帖:
2882
只看该作者 2楼 发表于: 2006-02-25
汗..这是谁写的...- -|||

不学无术中..

eMule ID:[eDtoon][CHN]adamhj@eMule-Official
级别: 精灵王
注册时间:
2005-12-13
在线时间:
0小时
发帖:
3859
只看该作者 3楼 发表于: 2006-02-25
0_0

来MY快2年了.没见过LZ.

很华丽的东西
没学过C++ 看不懂

囧TL

= =
级别: 工作组
注册时间:
2003-10-27
在线时间:
0小时
发帖:
1529
只看该作者 4楼 发表于: 2006-02-25
正在学C++ OTL 看来要好好上课了


----------------------------------------
无论是黑底白字的TAB 还是白底黑字的TAB 大家 大家 齐心协力 组成了108键大家族 新新的TAB 一直处在幸福之中 被按坏的TAB 郁闷地眯上了眼睛 要好的TAB们手牵着手 围成了一个TABURISS 在PS2接口上 发出了信号 大家相视而笑
级别: 工作组
注册时间:
2003-11-07
在线时间:
1小时
发帖:
7032
只看该作者 5楼 发表于: 2006-02-25
俺就知道个getFrame

青空が眩しい 君がいる風景は
幸せのオーラ 溢れ出すの とまらないよ
駅前の噴水 虹を作っているよ
君を待つ時間さえも かけがえない プレシャスな時

=========================

FANSUB的历史,又翻过了新的一页
级别: 版主
注册时间:
2002-12-02
在线时间:
0小时
发帖:
3002
只看该作者 6楼 发表于: 2006-02-26
看是看的懂
只是要拿到 VC++裡編譯
好像還需要有安裝 DirectX 的 SDK
Invert 功能是蠻簡單的 XOR 一下每個像素就好了
只是其它...就要具備相當的 影音相關知識
所以要做出個像樣的東西
還真不容易呢~

等 skywalker 來實際示範一個哦 ~ ^^

级别: 版主
注册时间:
2001-11-21
在线时间:
0小时
发帖:
2803
只看该作者 7楼 发表于: 2006-02-26
引用
最初由 weilai 发布
看是看的懂
只是要拿到 VC++裡編譯
好像還需要有安裝 DirectX 的 SDK
Invert 功能是蠻簡單的 XOR 一下每個像素就好了
只是其它...就要具備相當的 影音相關知識
所以要做出個像樣的東西
還真不容易呢~

等 skywalker 來實際示範一個哦 ~ ^^



应该不需要装directX的SDK的........
除非要用到directShow的东西.......

其实avs的filter很多都是opensource的.......
自己不用从头开始做的......
找一个做还的再改就行了.......

其实我之所以突然去看filter的制作就是我CPU速度太慢, 平时用limitsharpen + dehalo_alpha + AVC就慢死了......
所以才想自己弄一个然后用GPU来处理, 据说GPU比CPU快多了......
现在终于弄出来一个效果接近limitsharpen + dehalo_alpha的, 虽然有很严重的bug, 但是小心点使用已经没问题了............

所以只有下次有足够动力的时候我才会再弄了......
只要会C++再学点信号处理的知识就可以改别人的filter来学习了........

live id: liusu119@hotmail.com
email: liusu119@gmail.com
级别: 新手上路
注册时间:
2003-06-23
在线时间:
1小时
发帖:
2882
只看该作者 8楼 发表于: 2006-02-26
偶觉得其实看avisynth网站上那几篇文+那个simple sample更简单些...

不学无术中..

eMule ID:[eDtoon][CHN]adamhj@eMule-Official
级别: 工作组
注册时间:
2003-11-07
在线时间:
1小时
发帖:
7032
只看该作者 9楼 发表于: 2006-02-26
引用
最初由 skywalker 发布
所以只有下次有足够动力的时候我才会再弄了......
只要会C++再学点信号处理的知识就可以改别人的filter来学习了........


不止吧老大,貌似还要学汇编.那些涉及图像处理的filter,个个都带asm代码

青空が眩しい 君がいる風景は
幸せのオーラ 溢れ出すの とまらないよ
駅前の噴水 虹を作っているよ
君を待つ時間さえも かけがえない プレシャスな時

=========================

FANSUB的历史,又翻过了新的一页
级别: 新手上路
注册时间:
2003-06-23
在线时间:
1小时
发帖:
2882
只看该作者 10楼 发表于: 2006-02-26
引用
最初由 wolfsoft 发布


不止吧老大,貌似还要学汇编.那些涉及图像处理的filter,个个都带asm代码


一般asm的都是功能很基础的功能,既然只是在别人代码的基础上改的话,你直接调用就是了,不用管

不学无术中..

eMule ID:[eDtoon][CHN]adamhj@eMule-Official
级别: 工作组
注册时间:
2003-11-07
在线时间:
1小时
发帖:
7032
只看该作者 11楼 发表于: 2006-02-26
引用
最初由 adamhj 发布


一般asm的都是功能很基础的功能,既然只是在别人代码的基础上改的话,你直接调用就是了,不用管


那改啥呢?我觉得对于那种filter就这些asm,尤其是里面的矩阵才是核心,也是最需要做出修改的地方啊

青空が眩しい 君がいる風景は
幸せのオーラ 溢れ出すの とまらないよ
駅前の噴水 虹を作っているよ
君を待つ時間さえも かけがえない プレシャスな時

=========================

FANSUB的历史,又翻过了新的一页
级别: 版主
注册时间:
2001-11-21
在线时间:
0小时
发帖:
2803
只看该作者 12楼 发表于: 2006-02-27
用asm只是让filter速度更快而已.........
用好的编译器的话不会比asm慢很多的.........
我看也有很多filter没带asm的........
毕竟正常人哪有这么多时间去写asm..........

live id: liusu119@hotmail.com
email: liusu119@gmail.com
级别: 新手上路
注册时间:
2003-06-23
在线时间:
1小时
发帖:
2882
只看该作者 13楼 发表于: 2006-02-27
引用
最初由 skywalker 发布
用asm只是让filter速度更快而已.........
用好的编译器的话不会比asm慢很多的.........
我看也有很多filter没带asm的........
毕竟正常人哪有这么多时间去写asm..........


很多asm都是用mmx、sse、sse2的..一般编译器优化哪里作得到这步..

不学无术中..

eMule ID:[eDtoon][CHN]adamhj@eMule-Official
级别: 版主
注册时间:
2001-11-21
在线时间:
0小时
发帖:
2803
只看该作者 14楼 发表于: 2006-02-28
引用
最初由 adamhj 发布


很多asm都是用mmx、sse、sse2的..一般编译器优化哪里作得到这步..


asm优化只是提高一点速度而已, 并不能提高filter本身的效果. 就算要用asm优化, 也要先用c++写的. 如果做出来的filter效果好, 自然可以找到人来帮你写asm.........

live id: liusu119@hotmail.com
email: liusu119@gmail.com
快速回复

限150 字节
上一个 下一个