]> git.sesse.net Git - casparcg/commitdiff
2.0. filter: Yadif filter is scalable without extra delay for up to 16 instances...
authorRonag <Ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 30 Jul 2011 23:34:55 +0000 (23:34 +0000)
committerRonag <Ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 30 Jul 2011 23:34:55 +0000 (23:34 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1022 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

modules/decklink/producer/decklink_producer.cpp
modules/ffmpeg/ffmpeg.vcxproj
modules/ffmpeg/ffmpeg.vcxproj.filters
modules/ffmpeg/producer/filter/filter.cpp
modules/ffmpeg/producer/filter/filter.h
modules/ffmpeg/producer/filter/scalable_yadif.cpp [new file with mode: 0644]
modules/ffmpeg/producer/filter/scalable_yadif.h [new file with mode: 0644]

index 9d2e8a088d416f27530570f5683f6a8299093ed4..f48cfea4302db798554c1c8f905b14247c36f3be 100644 (file)
@@ -104,7 +104,7 @@ public:
                , device_index_(device_index)\r
                , frame_factory_(frame_factory)\r
                , tail_(core::basic_frame::empty())\r
-               , filter_(filter, filter::low_latency)\r
+               , filter_(filter)\r
                , muxer_(double_rate(filter) ? format_desc.fps * 2.0 : format_desc.fps, frame_factory->get_video_format_desc(), frame_factory)\r
        {\r
                frame_buffer_.set_capacity(2);\r
index 824c331463ddd14af4e4aff102325719e4f8871a..892ef7b713d7de68e07a7a2eb101c57e1458fcd0 100644 (file)
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
+    <ClCompile Include="producer\filter\scalable_yadif.cpp">\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
+    </ClCompile>\r
     <ClCompile Include="producer\frame_muxer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
     <ClInclude Include="producer\audio\audio_decoder.h" />\r
     <ClInclude Include="producer\ffmpeg_producer.h" />\r
     <ClInclude Include="producer\filter\filter.h" />\r
+    <ClInclude Include="producer\filter\scalable_yadif.h" />\r
     <ClInclude Include="producer\frame_muxer.h" />\r
     <ClInclude Include="producer\input.h" />\r
     <ClInclude Include="producer\util.h" />\r
index 1714bf5e681f8aae4aedb3209c06d0307f8ab5b6..2b2948849e54ed7437a5bac3d63e65166959d97b 100644 (file)
@@ -49,6 +49,9 @@
     <ClCompile Include="producer\frame_muxer.cpp">\r
       <Filter>source\producer</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="producer\filter\scalable_yadif.cpp">\r
+      <Filter>source\producer\filter</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="producer\ffmpeg_producer.h">\r
@@ -85,5 +88,8 @@
     <ClInclude Include="producer\frame_muxer.h">\r
       <Filter>source\producer</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="producer\filter\scalable_yadif.h">\r
+      <Filter>source\producer\filter</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
index 66b6f346141c82077b0c42b436717238692dd3c3..d5918f0b97c191a3128654e479716c096bfe2a67 100644 (file)
@@ -2,6 +2,8 @@
 \r
 #include "filter.h"\r
 \r
+#include "scalable_yadif.h"\r
+\r
 #include "../../ffmpeg_error.h"\r
 \r
 #include <common/exception/exceptions.h>\r
@@ -37,38 +39,24 @@ struct filter::implementation
        std::shared_ptr<AVFilterGraph>  graph_; \r
        AVFilterContext*                                buffersink_ctx_;\r
        AVFilterContext*                                buffersrc_ctx_;\r
-\r
-       filter::flags                                   flags_;\r
-       std::vector<safe_ptr<AVFrame>>  frames_;\r
-       tbb::task_group                                 tasks_;\r
-       \r
-       implementation(const std::wstring& filters, filter::flags filter_flags) \r
+       int                                                             scalable_yadif_tag_;\r
+               \r
+       implementation(const std::wstring& filters) \r
                : filters_(filters.empty() ? "null" : narrow(filters))\r
-               , flags_(filter_flags)\r
+               , scalable_yadif_tag_(-1)\r
        {\r
                std::transform(filters_.begin(), filters_.end(), filters_.begin(), ::tolower);\r
        }\r
 \r
-       std::vector<safe_ptr<AVFrame>> execute(const std::shared_ptr<AVFrame>& frame)\r
+       ~implementation()\r
        {\r
-               if((flags_ | filter::low_latency) != 0)\r
-               {\r
-                       push(frame);\r
-                       return poll();\r
-               }\r
+               release_scalable_yadif(scalable_yadif_tag_);\r
+       }\r
 \r
-               tasks_.wait();\r
-                       \r
+       std::vector<safe_ptr<AVFrame>> execute(const std::shared_ptr<AVFrame>& frame)\r
+       {\r
                push(frame);\r
-\r
-               auto frames = std::move(frames_);\r
-\r
-               tasks_.run([=]\r
-               {\r
-                       frames_ = poll();\r
-               });\r
-\r
-               return frames;\r
+               return poll();\r
        }\r
 \r
        void push(const std::shared_ptr<AVFrame>& frame)\r
@@ -143,6 +131,13 @@ struct filter::implementation
                                BOOST_THROW_EXCEPTION(caspar_exception() <<     msg_info(av_error_str(errn)) \r
                                        <<      boost::errinfo_api_function("avfilter_graph_config") << boost::errinfo_errno(AVUNERROR(errn)));\r
                        }\r
+\r
+                       for(size_t n = 0; n < graph_->filter_count; ++n)\r
+                       {\r
+                               auto filter_name = graph_->filters[n]->name;\r
+                               if(strstr(filter_name, "yadif") != 0)\r
+                                       scalable_yadif_tag_ = make_scalable_yadif(graph_->filters[n]);\r
+                       }\r
                }\r
        \r
                errn = av_vsrc_buffer_add_frame(buffersrc_ctx_, frame.get(), 0);\r
@@ -194,6 +189,6 @@ struct filter::implementation
        }\r
 };\r
 \r
-filter::filter(const std::wstring& filters, flags filter_flags) : impl_(new implementation(filters, filter_flags)){}\r
+filter::filter(const std::wstring& filters) : impl_(new implementation(filters)){}\r
 std::vector<safe_ptr<AVFrame>> filter::execute(const std::shared_ptr<AVFrame>& frame) {return impl_->execute(frame);}\r
 }
\ No newline at end of file
index 98d52a59d0127480bd7462491ec5d75b97c7e125..ef6aed320e5a30c5d93666692d88a2f7be35d81d 100644 (file)
@@ -23,13 +23,7 @@ static bool double_rate(const std::wstring& filters)
 class filter\r
 {\r
 public:\r
-       enum flags\r
-       {\r
-               none = 0,\r
-               low_latency = 2\r
-       };\r
-\r
-       filter(const std::wstring& filters, flags filter_flags = none);\r
+       filter(const std::wstring& filters);\r
 \r
        std::vector<safe_ptr<AVFrame>> execute(const std::shared_ptr<AVFrame>& frame);\r
 \r
diff --git a/modules/ffmpeg/producer/filter/scalable_yadif.cpp b/modules/ffmpeg/producer/filter/scalable_yadif.cpp
new file mode 100644 (file)
index 0000000..8051960
--- /dev/null
@@ -0,0 +1,117 @@
+#include "../../StdAfx.h"\r
+\r
+#include "scalable_yadif.h"\r
+\r
+extern "C" \r
+{\r
+       #define __STDC_CONSTANT_MACROS\r
+       #define __STDC_LIMIT_MACROS\r
+       #include <libavutil/avutil.h>\r
+       #include <libavutil/imgutils.h>\r
+       #include <libavfilter/avfilter.h>\r
+       #include <libavfilter/avcodec.h>\r
+       #include <libavfilter/avfiltergraph.h>\r
+       #include <libavfilter/vsink_buffer.h>\r
+       #include <libavfilter/vsrc_buffer.h>\r
+}\r
+\r
+#include <boost/thread/once.hpp>\r
+
+typedef struct {
+    int mode;
+    int parity;
+    int frame_pending;
+    int auto_enable;
+    AVFilterBufferRef *cur;
+    AVFilterBufferRef *next;
+    AVFilterBufferRef *prev;
+    AVFilterBufferRef *out;
+    void (*filter_line)(uint8_t *dst,
+                        uint8_t *prev, uint8_t *cur, uint8_t *next,
+                        int w, int prefs, int mrefs, int parity, int mode);
+    const AVPixFmtDescriptor *csp;
+} YADIFContext;\r
+\r
+struct scalable_yadif_context\r
+{\r
+       std::vector<std::function<void()>> calls;\r
+       int end_prefs;\r
+\r
+       scalable_yadif_context() : end_prefs(std::numeric_limits<int>::max()){}\r
+};\r
+\r
+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
+\r
+void scalable_yadif_filter_line(scalable_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
+{\r
+       if(ctx.end_prefs == std::numeric_limits<int>::max())\r
+               ctx.end_prefs = -prefs;\r
+\r
+       ctx.calls.push_back([=]\r
+       {\r
+               org_yadif_filter_line(dst, prev, cur, next, w, prefs, mrefs, parity, mode);\r
+       });\r
+\r
+       if(prefs == ctx.end_prefs)\r
+       {               \r
+               tbb::parallel_for(tbb::blocked_range<size_t>(0, ctx.calls.size()), [=](const tbb::blocked_range<size_t>& r)\r
+               {\r
+                       for(auto n = r.begin(); n != r.end(); ++n)\r
+                               ctx.calls[n]();\r
+               });\r
+               ctx.calls     = std::vector<std::function<void()>>();\r
+               ctx.end_prefs = std::numeric_limits<int>::max();\r
+       }\r
+}\r
+\r
+#define RENAME(a) f ## a\r
+\r
+#define ff(x) \\r
+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
+{\\r
+       static scalable_yadif_context ctx;\\r
+       scalable_yadif_filter_line(ctx, dst, prev, cur, next, w, prefs, mrefs, parity, mode);\\r
+}\r
+\r
+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
+\r
+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
+\r
+{f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, f17};\r
+\r
+namespace caspar {\r
+       \r
+tbb::concurrent_bounded_queue<int> tags;\r
+\r
+void init()\r
+{\r
+       for(int n = 0; n < 18; ++n)\r
+               tags.push(n);\r
+}\r
+\r
+int make_scalable_yadif(AVFilterContext* ctx)\r
+{\r
+       static boost::once_flag flag = BOOST_ONCE_INIT;\r
+       boost::call_once(&init, flag);\r
+\r
+       YADIFContext* yadif = (YADIFContext*)ctx->priv;\r
+       org_yadif_filter_line = yadif->filter_line;\r
+\r
+       int tag;\r
+       if(!tags.try_pop(tag))\r
+       {\r
+               CASPAR_LOG(warning) << "Not enough scalable-yadif instances. Running non-scalable";\r
+               return -1;\r
+       }\r
+\r
+       yadif->filter_line = fs[tag]; // hmm, will only work for one concurrent instance...\r
+       return tag;\r
+}\r
+\r
+void release_scalable_yadif(int tag)\r
+{\r
+       if(tag != -1)\r
+               tags.push(tag);\r
+}\r
+\r
+}
\ No newline at end of file
diff --git a/modules/ffmpeg/producer/filter/scalable_yadif.h b/modules/ffmpeg/producer/filter/scalable_yadif.h
new file mode 100644 (file)
index 0000000..0b61b8d
--- /dev/null
@@ -0,0 +1,10 @@
+#pragma once\r
+\r
+struct AVFilterContext;\r
+\r
+namespace caspar {\r
+       \r
+int make_scalable_yadif(AVFilterContext* ctx);\r
+void release_scalable_yadif(int tag);\r
+\r
+}
\ No newline at end of file