]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/filter/parallel_yadif.cpp
b467bfae0e9cf694ecdae1759cc21270ccfd15e3
[casparcg] / modules / ffmpeg / producer / filter / parallel_yadif.cpp
1 #include "../../StdAfx.h"\r
2 \r
3 #include "parallel_yadif.h"\r
4 \r
5 #include <common/log/log.h>\r
6 \r
7 #if defined(_MSC_VER)\r
8 #pragma warning (push)\r
9 #pragma warning (disable : 4244)\r
10 #endif\r
11 extern "C" \r
12 {\r
13         #include <libavfilter/avfilter.h>\r
14 }\r
15 #if defined(_MSC_VER)\r
16 #pragma warning (pop)\r
17 #endif\r
18 \r
19 #include <tbb/parallel_for.h>\r
20 #include <tbb/concurrent_queue.h>\r
21 \r
22 #include <boost/thread/once.hpp>\r
23 \r
24 typedef struct {\r
25     int mode;\r
26     int parity;\r
27     int frame_pending;\r
28     int auto_enable;\r
29     AVFilterBufferRef *cur;\r
30     AVFilterBufferRef *next;\r
31     AVFilterBufferRef *prev;\r
32     AVFilterBufferRef *out;\r
33     void (*filter_line)(uint8_t *dst,\r
34                         uint8_t *prev, uint8_t *cur, uint8_t *next,\r
35                         int w, int prefs, int mrefs, int parity, int mode);\r
36     //const AVPixFmtDescriptor *csp;\r
37 } YADIFContext;\r
38 \r
39 struct parallel_yadif_context\r
40 {\r
41         struct arg\r
42         {\r
43                 uint8_t *dst;\r
44                 uint8_t *prev;\r
45                 uint8_t *cur; \r
46                 uint8_t *next; \r
47                 int w; \r
48                 int prefs; \r
49                 int mrefs;\r
50                 int parity;\r
51                 int mode;\r
52         };\r
53 \r
54         arg     args[64];\r
55         int     index;\r
56 \r
57         parallel_yadif_context() : index(0){}\r
58 };\r
59 \r
60 void (*org_yadif_filter_line)(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) = 0;\r
61 \r
62 void parallel_yadif_filter_line(parallel_yadif_context& ctx, uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode)\r
63 {\r
64         parallel_yadif_context::arg arg = {dst, prev, cur, next, w, prefs, mrefs, parity, mode};\r
65         ctx.args[ctx.index++] = arg;\r
66         \r
67         if(ctx.index == 64)\r
68         {               \r
69                 tbb::parallel_for(tbb::blocked_range<size_t>(0, ctx.index), [=](const tbb::blocked_range<size_t>& r)\r
70                 {\r
71                         for(auto n = r.begin(); n != r.end(); ++n)\r
72                                 org_yadif_filter_line(ctx.args[n].dst, ctx.args[n].prev, ctx.args[n].cur, ctx.args[n].next, ctx.args[n].w, ctx.args[n].prefs, ctx.args[n].mrefs, ctx.args[n].parity, ctx.args[n].mode);\r
73                 });\r
74                 ctx.index = 0;\r
75         }\r
76 }\r
77 \r
78 #define RENAME(a) f ## a\r
79 \r
80 #define ff(x) \\r
81 void RENAME(x)(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) \\r
82 {\\r
83         static parallel_yadif_context ctx;\\r
84         parallel_yadif_filter_line(ctx, dst, prev, cur, next, w, prefs, mrefs, parity, mode);\\r
85 }\r
86 \r
87 ff(0); ff(1); ff(2); ff(3); ff(4); ff(5); ff(6); ff(7); ff(8); ff(9); ff(10); ff(11); ff(12); ff(13); ff(14); ff(15); ff(16); ff(17);\r
88 \r
89 void (*fs[])(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode) = \r
90 {f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17};\r
91 \r
92 namespace caspar {\r
93         \r
94 tbb::concurrent_bounded_queue<decltype(org_yadif_filter_line)> parallel_line_func_pool;\r
95 \r
96 void init_pool()\r
97 {\r
98         for(int n = 0; n < sizeof(fs)/sizeof(fs[0]); ++n)\r
99                 parallel_line_func_pool.push(fs[n]);\r
100 }\r
101 \r
102 void return_parallel_yadif(void* func)\r
103 {\r
104         if(func != nullptr)\r
105                 parallel_line_func_pool.push(reinterpret_cast<decltype(fs[0])>(func));\r
106 }\r
107 \r
108 std::shared_ptr<void> make_parallel_yadif(AVFilterContext* ctx)\r
109 {\r
110         static boost::once_flag flag = BOOST_ONCE_INIT;\r
111         boost::call_once(&init_pool, flag);\r
112 \r
113         YADIFContext* yadif = (YADIFContext*)ctx->priv;\r
114         org_yadif_filter_line = yadif->filter_line; // Data race is not a problem.\r
115 \r
116         decltype(org_yadif_filter_line) func = nullptr;\r
117         if(!parallel_line_func_pool.try_pop(func))      \r
118                 CASPAR_LOG(warning) << "Not enough scalable-yadif context instances. Running non-scalable";\r
119         else\r
120                 yadif->filter_line = func;\r
121         \r
122         return std::shared_ptr<void>(func, return_parallel_yadif);\r
123 }\r
124 \r
125 }