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

[讨论]利用多进程组流水线提高AVS处理速度

楼层直达
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
AVS很多滤镜没做多线程数据保护,MT版本的AVS很容易出现各种莫名奇妙的问题并且32版本容易爆内存

可以多开AVS,通过TCP协议通讯组建流水线,将某些滤镜放到单独的一个进程中去处理(甚至不同电脑上)
AVS脚本通过解析最终会组成一条filter chain(可以带有分支、多个起点),理论上都可以拆成多进程来处理

例如
脚本1:
  1. xxxSource("xxx")
  2. TCPServer(22050)

脚本2:
  1. TCPSource("127.0.0.1",22050,"None")#如果是在不同电脑上处理,最后一个参数根据网络状况选择
  2. xxxfilter()
  3. TCPServer(22051)

脚本3:
  1. TCPSource("127.0.0.1",22051,"None")
  2. xxxfilter()
  3. TCPServer(22052)


。。。。。。
脚本X:
  1. TCPSource("127.0.0.1",xxxx,"None")
  2. xxxfilter()


然后在诸如VirtualDub之类的程序中分别依次打开上述除最后一个脚本以外的所有脚本,x264压制时输入最后一个脚本
关于TCPServer/TCPSource请参考:
http://avisynth.org/mediawiki/TCPServer

这样还是会有一个问题,当某个滤镜速度极其慢的时候,整个流水线处理速度会受到影响
解决办法之一是实现这个滤镜的多线程版本,也可以尝试通过多进程提高这个滤镜处理速度(需要自己写程序)

嘛,各位大大可以通过自行编写程序自动实现上述过程

急着吃饭,写得比较简略



[ 此帖被linuxyouxia在2011-10-12 18:21重新编辑 ]

Fansubbing is a waste of time.
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
只看该作者 1楼 发表于: 2011-10-12
= =嘛,突然想到基于AVS的构架,这样效率也不会很高,只能解决32位下爆内存问题,并不能有效实现多进程同时处理

还是要自己写程序
比如
http://forum.doom9.org/showthread.php?t=139629
http://forum.doom9.org/showthread.php?p=1405205

把ThreadRequest()放到每个进程中去

希望各位大大一起来开发,顺便改下标题

看了一下AVS的TCPServer的代码,当没有收到请求的时候会提前fetch下一帧,我在想能不能改成提前fetch多帧
这样在收到TCPClient请求的时候,可以直接从Cache中取出来

TCP通讯还有一个问题,需要将整一帧数据发送过去,如果仅在一台电脑上处理,帧数据复制会占用额外的资源,如果滤镜处理速度不是很慢的话,可能用共享内存更好一些

[ 此帖被linuxyouxia在2011-10-12 20:59重新编辑 ]

Fansubbing is a waste of time.
级别: 精灵王
注册时间:
2008-04-08
在线时间:
44小时
发帖:
2855
只看该作者 2楼 发表于: 2011-10-12
AVS爆内存主要是脑残的缓存机制造成的。比较好的方法是每个滤镜必须在初始化完成后告诉AVS需要上游最多缓存多少帧,不然多了爆内存,少了影响效率。
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
只看该作者 3楼 发表于: 2011-10-12
avs确实令人感到很讨厌,最令人讨厌的地方是往往没有合适的替代品(我不能放弃avs社区积累到现在的那些脚本和滤镜),不得不用

Fansubbing is a waste of time.
级别: 精灵王
注册时间:
2008-04-08
在线时间:
44小时
发帖:
2855
只看该作者 4楼 发表于: 2011-10-12
引用
引用第3楼linuxyouxia于2011-10-12 21:55发表的  :
avs确实令人感到很讨厌,最令人讨厌的地方是往往没有合适的替代品(我不能放弃avs社区积累到现在的那些脚本和滤镜),不得不用   

你要只是会用,不会开发,那真是没办法。但如果会开发,那第一选择就是去改AVS,第二选择就是去移植。很多AVS的滤镜被移植到了ffmpeg和x264的filter system里去了。修改AVS也有可能使老的脚本或滤镜不兼容,但如果你的新版本真的能解决一些AVS的顽疾,那么那些滤镜或者脚本的作者自然也会来兼容你的新系统,不需要你自己动手的。
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
只看该作者 5楼 发表于: 2011-10-13
我之前看过avisynth 3.0的遗留代码,无从下手

和新版Boost库有很多不兼容的地方,C++没怎么学过

也有人尝试过将avisynth滤镜移植到gstreamer上面
https://github.com/LRN/gst-avsynth

= =感觉这几年大家都在对老旧的avisynth修修补补(毕竟比起再造轮子节省时间精力),没人真的去开发新版本
还有一个问题就是人的精力总归是有限的,如果没什么动力,还真未必能完成一项开发,avisynth 3.0估计就是这么死掉的

我给字幕组压片第一选择就是avisynth,这在短期内还没办法改变
最近又在折腾写个avs编辑器,已经搞定了OpenGL显示YUV数据 和 基于Scintilla代码高亮(Avs词法分析器从VirtualDubMod残留代码里挖出来改了一下)
[ 此帖被linuxyouxia在2011-10-13 08:54重新编辑 ]

Fansubbing is a waste of time.
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
只看该作者 6楼 发表于: 2011-10-13
嘛,发现扯远了,我想回到主题上,至少从我粗略测试来看这样的方法确实有效(除非我哪里弄错了),不过需要合理地将avs脚本切割成多分


Fansubbing is a waste of time.
级别: 骑士
注册时间:
2008-10-06
在线时间:
115小时
发帖:
319
只看该作者 7楼 发表于: 2011-10-13

Follow me: @06_taro

MediaFire links to:
Taro's tools (avs plugins & other useful tools' builds)
Taro's x264 builds (Latest build: x264 core:129 r2245+704_tMod (&tMod+10bit/MixAQ/OreAQ), Win & MacOS, built on 10 Jan 2012, gcc: 4.7.2)

nmm牆內鏡像(部分工具)
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
只看该作者 8楼 发表于: 2011-10-13
引用
引用第7楼06_taro于2011-10-13 10:20发表的  :
https://github.com/nielsmh/vsynth

期待逐步完善,不要像Avisynth 3.0那样通过Boost库自行实现一种脚本语言,bind到ruby、lua之类的脚本语言就行了

到时候来移植avisynth滤镜

[ 此帖被linuxyouxia在2011-10-13 11:09重新编辑 ]

Fansubbing is a waste of time.
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
只看该作者 9楼 发表于: 2011-10-13
写了一个简单的小程序用来载入运行TCPServer的avs脚本,支持文件拖放
http://dl.dbank.com/c0n1r9sisk

嘛,有需要的话,我可以加入关于TCPServer和TCPSource的选项和avisynth编辑文本框
[ 此帖被linuxyouxia在2011-10-13 16:35重新编辑 ]

Fansubbing is a waste of time.
级别: 精灵王
注册时间:
2008-04-08
在线时间:
44小时
发帖:
2855
只看该作者 10楼 发表于: 2011-10-13
要是连修修补补都不愿意,那就的确没救了。现在确实连修avs的人都没有。

avs 2.x里的buffer问题完全是可以改的,可以参考ffdshow的做法。给每一个滤镜增加一组参数指定需要前后buffer多少帧(可以在脚本中手工指定),这样avs就不会去额外的保存那么多buffer了。
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
只看该作者 11楼 发表于: 2011-10-14
  1. ---------------------------------- cache.cpp ----------------------------------
  2. index 87cc346..f813ae4 100644
  3. @@ -54,6 +54,7 @@ struct {
  4. extern const AVSFunction Cache_filters[] = {
  5.    { "Cache", "c", Cache::Create_Cache },
  6.    { "InternalCache", "c", Cache::Create_Cache },
  7. +  { "SetCache", "c[range]i", Cache::Create_Cache2 },
  8.    { 0 }
  9. };
  10. @@ -81,7 +82,10 @@ Cache::Cache(PClip _child, IScriptEnvironment* env)
  11. //  InitializeCriticalSectionAndSpinCount(&cs_cache_V, 4000);
  12. //  InitializeCriticalSectionAndSpinCount(&cs_cache_A, 4000);
  13. -  h_policy = CACHE_ALL;  // Since hints are not used per default, this is to describe the lowest default cache mode.
  14. +  max_tracked_frame = 30;
  15. +  max_tracked_vf_scaled = max_tracked_frame << CACHE_SCALE_SHIFT;
  16. +  max_tracked_misses = max_tracked_frame/2;
  17. +  h_policy = CACHE_NOTHING;  // Since hints are not used per default, this is to describe the lowest default cache mode.
  18.    h_audiopolicy = CACHE_NOTHING;  // Don't cache audio per default.
  19.    cache_limit = CACHE_SCALE_FACTOR / 2;  // Start half way towards 1 buffer
  20. @@ -411,14 +415,14 @@ PVideoFrame __stdcall Cache::GetFrame(int n, IScriptEnvironment* env)
  21.        minframe = iminframe;
  22.      }
  23. -    if (cache_limit > MAX_CACHED_VF_SCALED) cache_limit = MAX_CACHED_VF_SCALED;
  24. +    if (cache_limit > max_tracked_vf_scaled) cache_limit = max_tracked_vf_scaled;
  25.      _RPT4(0, "Cache:%x: size %d, limit %d, fault %d\n", this, c, cache_limit, fault_rate);
  26.    } // if (n>=minframe
  27.    else { // This frame is not in the range we are currently tracking
  28.      InterlockedIncrement(&g_Cache_stats.vfb_never);
  29. -    if (InterlockedIncrement(&miss_count) > MAX_CACHE_MISSES) {
  30. +    if (InterlockedIncrement(&miss_count) > max_tracked_misses) {
  31.        ResetCache(env);  // The cache isn't being accessed, reset it!
  32.        miss_count = 0x80000000; // Hugh negative
  33.      }
  34. @@ -535,7 +539,7 @@ Cache::CachedVideoFrame* Cache::GetACachedVideoFrame(const PVideoFrame& frame, I
  35.      ReturnVideoFrameBuffer(j, env); // Return out of range vfb to vfb pool for early reuse
  36.    }
  37. -  if (count >= MAX_CACHED_VIDEO_FRAMES) return video_frames.prev; // to many entries just steal the oldest CachedVideoFrame
  38. +  if (count >= max_tracked_frame) return video_frames.prev; // to many entries just steal the oldest CachedVideoFrame
  39.    return new CachedVideoFrame; // need a new one
  40. }
  41. @@ -833,7 +837,7 @@ int __stdcall Cache::SetCacheHints(int cachehints, int frame_range) {
  42.    if (cachehints == CACHE_ALL) {
  43. -    int _cache_init = min(MAX_CACHED_VIDEO_FRAMES, frame_range);
  44. +    int _cache_init = min(max_tracked_frame, frame_range);
  45.      if (_cache_init > cache_init) // The max of all requests
  46.        cache_init  = _cache_init;
  47. @@ -852,14 +856,14 @@ int __stdcall Cache::SetCacheHints(int cachehints, int frame_range) {
  48.    }
  49.    else if (cachehints == CACHE_RANGE) {
  50. -
  51. +    max_tracked_frame = frame_range*2+1;
  52. +    max_tracked_vf_scaled = max_tracked_frame << CACHE_SCALE_SHIFT;
  53. +    max_tracked_misses = max_tracked_frame/2;
  54.      if (frame_range > h_span)  // Use the largest size when we have multiple clients
  55. -      h_span = min(MAX_CACHE_RANGE, frame_range);
  56. +      h_span = min(max_tracked_frame, frame_range);
  57.      h_policy = CACHE_RANGE;  // An explicit cache of radius "frame_range" around the current frame, n.
  58. -
  59.    }
  60. -
  61.    return 0;
  62. }
  63. @@ -912,3 +916,27 @@ AVSValue __cdecl Cache::Create_Cache(AVSValue args, void*, IScriptEnvironment* e
  64.    return p;
  65. }
  66. +AVSValue __cdecl Cache::Create_Cache2(AVSValue args, void*, IScriptEnvironment* env)
  67. +{
  68. +  PClip p=0;
  69. +  PClip r=0;
  70. +  int _framerange;
  71. +
  72. +  p = args[0].AsClip();
  73. +  _framerange = args[1].AsInt(1);
  74. +
  75. +  if (p) {
  76. +    int q = 0;
  77. +
  78. +    if (p->GetVersion() >= 5) // AVISYNTH_INTERFACE_VERSION which supports this
  79. +      q = p->SetCacheHints(GetMyThis, 0); // Check if "p" is a cache instance
  80. +
  81. +    // Do not cache another cache!
  82. +    if (q != (int)(void *)p) {
  83. +        r = new Cache(p, env);
  84. +        r->SetCacheHints(CACHE_RANGE, _framerange);
  85. +        return r;
  86. +    }
  87. +  }
  88. +  return p;
  89. +}
  90. \ No newline at end of file
  91. ----------------------------------- cache.h -----------------------------------
  92. index 2f02bed..8c0f989 100644
  93. @@ -55,6 +55,7 @@ public:
  94.    PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
  95.    int __stdcall SetCacheHints(int cachehints,int frame_range);
  96.    static AVSValue __cdecl Create_Cache(AVSValue args, void*, IScriptEnvironment* env);
  97. +  static AVSValue __cdecl Create_Cache2(AVSValue args, void*, IScriptEnvironment* env);
  98.    void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env);
  99. protected:
  100. @@ -131,6 +132,9 @@ private:
  101.    // Cached range limits
  102.    int minframe, maxframe;
  103. +  int max_tracked_frame;
  104. +  int max_tracked_vf_scaled;
  105. +  int max_tracked_misses;
  106.    int cache_init;   // The Initial cache size
  107.    long cache_limit;  // 16 time the current maximum number of CachedVideoFrame entries
  108.    long fault_rate;   // A decaying average of 100 times the peak fault count, used to control vfb auto-locking
  109. ----------------------------------- main.cpp -----------------------------------
  110. index 1b82226..2324e60 100644
  111. @@ -648,10 +648,10 @@ bool CAVIFileSynth::DelayInit2() {
  112.            if (!AllowFloatAudio) // Ensure samples are int    
  113.              filter_graph = ConvertAudio::Create(filter_graph, SAMPLE_INT8|SAMPLE_INT16|SAMPLE_INT24|SAMPLE_INT32, SAMPLE_INT16);
  114. -          filter_graph = Cache::Create_Cache(AVSValue(filter_graph), 0, env).AsClip();
  115. +          /*filter_graph = Cache::Create_Cache(AVSValue(filter_graph), 0, env).AsClip();
  116. -          filter_graph->SetCacheHints(CACHE_ALL, 999); // Give the top level cache a big head start!!
  117. -        }
  118. +          filter_graph->SetCacheHints(CACHE_ALL, 999); // Give the top level cache a big head start!!*/
  119. +        }
  120.          else
  121.            throw AvisynthError("The script's return value was not a video clip");
  122. ---------------------------- parser/expression.cpp ----------------------------
  123. index 07e212f..b7b86cd 100644
  124. @@ -508,9 +508,9 @@ AVSValue ExpVariableReference::Evaluate(IScriptEnvironment* env)
  125.      }
  126.    }
  127.    // Add cache to Bracketless call of argless function
  128. -  if (result.IsClip()) { // Tritical Jan 2006
  129. +/*  if (result.IsClip()) { // Tritical Jan 2006
  130.      return Cache::Create_Cache(result, 0, env);
  131. -  }
  132. +  }*/
  133.    return result;
  134. }
  135. @@ -603,9 +603,9 @@ AVSValue ExpFunctionCall::Evaluate(IScriptEnvironment* env)
  136. {
  137.    AVSValue result = Call(env);
  138. -  if (result.IsClip()) {
  139. +/*  if (result.IsClip()) {
  140.      return Cache::Create_Cache(result, 0, env);
  141. -  }
  142. +  }*/
  143.    return result;
  144. }

懒得检查有没有问题,不会自动插入cache,可以用SetCache(int range)在脚本里手动插入,每个Cache最大存range*2+1帧

Fansubbing is a waste of time.
级别: 工作组
注册时间:
2003-08-26
在线时间:
13小时
发帖:
6600
只看该作者 12楼 发表于: 2011-10-15
字幕组压片,不内嵌字幕的话最近还真没怎么用avs了……

催片请点此处: http://bbs.popgo.org/bbs/read.php?tid=502402&displayMode=1#19103164
级别: 圣骑士
注册时间:
2006-08-17
在线时间:
146小时
发帖:
215
只看该作者 13楼 发表于: 2011-10-15
= =内嵌我可以不用avs,很多时候我就是这么做的(拿720p raw压PSP 480p)

avs的ConditionalFilter分段处理和TIVTC手动指定pattern,我暂时没实现更好的办法
并且我拿到的ts往往存在锯齿、halo之类的问题,我需要用avs的那些脚本和滤镜处理下

别吐槽avisynth了,我也不喜欢
[ 此帖被linuxyouxia在2011-10-15 02:05重新编辑 ]

Fansubbing is a waste of time.
级别: 骑士
注册时间:
2008-10-06
在线时间:
115小时
发帖:
319
只看该作者 14楼 发表于: 2011-10-16
  1. xxxSource
  2. xxxFilter()
  3. SelectEvery(3, 0)
  4. TCPServer(22050)


  1. xxxSource
  2. xxxFilter()
  3. SelectEvery(3, 1)
  4. TCPServer(22051)


  1. xxxSource
  2. xxxFilter()
  3. SelectEvery(3, 2)
  4. TCPServer(22052)


開上面三個,然後跑下面這個:
  1. Interleave(
  2. \ TCPSource("127.0.0.1",22050,"None"),
  3. \ TCPSource("127.0.0.1",22051,"None"),
  4. \ TCPSource("127.0.0.1",22052,"None") )


對單線程濾鏡能有非常好的提速效果
所以希望AVSTCP能增加同時多開的功能……

Follow me: @06_taro

MediaFire links to:
Taro's tools (avs plugins & other useful tools' builds)
Taro's x264 builds (Latest build: x264 core:129 r2245+704_tMod (&tMod+10bit/MixAQ/OreAQ), Win & MacOS, built on 10 Jan 2012, gcc: 4.7.2)

nmm牆內鏡像(部分工具)
快速回复

限150 字节
上一个 下一个