]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/filter/parallel_yadif.cpp
1727a4ce84a3c9c7ff2660c803467c9aa5dbbcfc
[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[1080];\r
55         int     index;\r
56         int last_index;\r
57 \r
58         parallel_yadif_context() : index(0){}\r
59 };\r
60 \r
61 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
62 \r
63 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
64 {\r
65         parallel_yadif_context::arg arg = {dst, prev, cur, next, w, prefs, mrefs, parity, mode};\r
66         ctx.args[ctx.index++] = arg;\r
67         \r
68         if(ctx.index == ctx.last_index)\r
69         {               \r
70                 tbb::parallel_for(tbb::blocked_range<size_t>(0, ctx.index), [=](const tbb::blocked_range<size_t>& r)\r
71                 {\r
72                         for(auto n = r.begin(); n != r.end(); ++n)\r
73                                 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
74                 });\r
75                 ctx.index = 0;\r
76         }\r
77 }\r
78 \r
79 namespace caspar {\r
80         \r
81 tbb::concurrent_bounded_queue<decltype(org_yadif_filter_line)> parallel_line_func_pool;\r
82 std::array<parallel_yadif_context, 18> ctxs;\r
83 \r
84 #define RENAME(a) f ## a\r
85 \r
86 #define ff(x) \\r
87 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
88 {\\r
89         parallel_yadif_filter_line(ctxs[x], dst, prev, cur, next, w, prefs, mrefs, parity, mode);\\r
90 }\r
91 \r
92 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
93 \r
94 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
95 {f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17};\r
96 \r
97 \r
98 void init_pool()\r
99 {\r
100         for(int n = 0; n < sizeof(fs)/sizeof(fs[0]); ++n)\r
101                 parallel_line_func_pool.push(fs[n]);\r
102 }\r
103 \r
104 void return_parallel_yadif(void* func)\r
105 {\r
106         if(func != nullptr)\r
107                 parallel_line_func_pool.push(reinterpret_cast<decltype(fs[0])>(func));\r
108 }\r
109 \r
110 std::shared_ptr<void> make_parallel_yadif(AVFilterContext* ctx)\r
111 {\r
112         static boost::once_flag flag = BOOST_ONCE_INIT;\r
113         boost::call_once(&init_pool, flag);\r
114 \r
115         YADIFContext* yadif = (YADIFContext*)ctx->priv;\r
116         org_yadif_filter_line = yadif->filter_line; // Data race is not a problem.\r
117         \r
118         decltype(org_yadif_filter_line) func = nullptr;\r
119         if(!parallel_line_func_pool.try_pop(func))      \r
120                 CASPAR_LOG(warning) << "Not enough scalable-yadif context instances. Running non-scalable";\r
121         else\r
122         {\r
123                 int index = 0;\r
124                 while(index < sizeof(fs)/sizeof(fs[0]) && fs[index] != func)\r
125                         ++index;\r
126 \r
127                 ctxs[index].last_index = 32;//ctx->inputs[0]->h;\r
128                 yadif->filter_line = func;\r
129         }\r
130 \r
131         return std::shared_ptr<void>(func, return_parallel_yadif);\r
132 }\r
133 \r
134 }