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