『漫游』酷论坛>『影音数码技术学习交流』>[讨论]利用多进程组流 ..

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

linuxyouxia@2011-10-12 17:38

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重新编辑 ]
引用

linuxyouxia@2011-10-12 18:08

= =嘛,突然想到基于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重新编辑 ]
引用

roozhou@2011-10-12 21:15

AVS爆内存主要是脑残的缓存机制造成的。比较好的方法是每个滤镜必须在初始化完成后告诉AVS需要上游最多缓存多少帧,不然多了爆内存,少了影响效率。
引用

linuxyouxia@2011-10-12 21:55

avs确实令人感到很讨厌,最令人讨厌的地方是往往没有合适的替代品(我不能放弃avs社区积累到现在的那些脚本和滤镜),不得不用
引用

roozhou@2011-10-12 22:32

引用
引用第3楼linuxyouxia于2011-10-12 21:55发表的  :
avs确实令人感到很讨厌,最令人讨厌的地方是往往没有合适的替代品(我不能放弃avs社区积累到现在的那些脚本和滤镜),不得不用   

你要只是会用,不会开发,那真是没办法。但如果会开发,那第一选择就是去改AVS,第二选择就是去移植。很多AVS的滤镜被移植到了ffmpeg和x264的filter system里去了。修改AVS也有可能使老的脚本或滤镜不兼容,但如果你的新版本真的能解决一些AVS的顽疾,那么那些滤镜或者脚本的作者自然也会来兼容你的新系统,不需要你自己动手的。
引用

linuxyouxia@2011-10-13 08:34

我之前看过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重新编辑 ]
引用

linuxyouxia@2011-10-13 09:29

嘛,发现扯远了,我想回到主题上,至少从我粗略测试来看这样的方法确实有效(除非我哪里弄错了),不过需要合理地将avs脚本切割成多分

引用

06_taro@2011-10-13 10:20

https://github.com/nielsmh/vsynth
引用

linuxyouxia@2011-10-13 10:40

引用
引用第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重新编辑 ]
引用

linuxyouxia@2011-10-13 16:14

写了一个简单的小程序用来载入运行TCPServer的avs脚本,支持文件拖放
http://dl.dbank.com/c0n1r9sisk

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

roozhou@2011-10-13 21:18

要是连修修补补都不愿意,那就的确没救了。现在确实连修avs的人都没有。

avs 2.x里的buffer问题完全是可以改的,可以参考ffdshow的做法。给每一个滤镜增加一组参数指定需要前后buffer多少帧(可以在脚本中手工指定),这样avs就不会去额外的保存那么多buffer了。
引用

linuxyouxia@2011-10-14 00:58

复制代码
  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帧
引用

MeteorRain@2011-10-15 01:26

字幕组压片,不内嵌字幕的话最近还真没怎么用avs了……
引用

linuxyouxia@2011-10-15 01:31

= =内嵌我可以不用avs,很多时候我就是这么做的(拿720p raw压PSP 480p)

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

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

06_taro@2011-10-16 00:40

复制代码
  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能增加同時多開的功能……
引用

«12»共2页

| TOP