]> git.sesse.net Git - casparcg/commitdiff
2.0.2: ffmped_producer: Added multithreaded prores decoding.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 23 Nov 2011 22:04:38 +0000 (22:04 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 23 Nov 2011 22:04:38 +0000 (22:04 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.2@1635 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

modules/ffmpeg/ffmpeg.vcxproj
modules/ffmpeg/ffmpeg.vcxproj.filters
modules/ffmpeg/producer/tbb_avcodec.cpp [new file with mode: 0644]
modules/ffmpeg/producer/tbb_avcodec.h [new file with mode: 0644]
modules/ffmpeg/producer/util/util.cpp

index ae25fb7121839652660e3d20a9ecce845faa7750..a5cb8baf4798931c48b6205f092984de8eef6ac5 100644 (file)
       <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
-      <ShowIncludes Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">false</ShowIncludes>\r
     </ClCompile>\r
     <ClCompile Include="producer\filter\filter.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|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\tbb_avcodec.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\util\flv.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\input\input.h" />\r
     <ClInclude Include="producer\muxer\display_mode.h" />\r
     <ClInclude Include="producer\muxer\frame_muxer.h" />\r
+    <ClInclude Include="producer\tbb_avcodec.h" />\r
     <ClInclude Include="producer\util\flv.h" />\r
     <ClInclude Include="producer\util\util.h" />\r
     <ClInclude Include="producer\video\video_decoder.h" />\r
index 2bfa0cd638ae98e9ece5f000873513c95397eed3..8e2e3ad4f2ac018751fdd3dde2b1ea3fc414e218 100644 (file)
@@ -30,9 +30,6 @@
     </Filter>\r
   </ItemGroup>\r
   <ItemGroup>\r
-    <ClCompile Include="producer\ffmpeg_producer.cpp">\r
-      <Filter>source\producer</Filter>\r
-    </ClCompile>\r
     <ClCompile Include="producer\video\video_decoder.cpp">\r
       <Filter>source\producer\video</Filter>\r
     </ClCompile>\r
     <ClCompile Include="producer\muxer\frame_muxer.cpp">\r
       <Filter>source\producer\muxer</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="producer\tbb_avcodec.cpp">\r
+      <Filter>source\producer</Filter>\r
+    </ClCompile>\r
+    <ClCompile Include="producer\ffmpeg_producer.cpp">\r
+      <Filter>source\producer</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="producer\ffmpeg_producer.h">\r
     <ClInclude Include="producer\muxer\display_mode.h">\r
       <Filter>source\producer\muxer</Filter>\r
     </ClInclude>\r
+    <ClInclude Include="producer\tbb_avcodec.h">\r
+      <Filter>source\producer</Filter>\r
+    </ClInclude>\r
   </ItemGroup>\r
 </Project>
\ No newline at end of file
diff --git a/modules/ffmpeg/producer/tbb_avcodec.cpp b/modules/ffmpeg/producer/tbb_avcodec.cpp
new file mode 100644 (file)
index 0000000..40babe0
--- /dev/null
@@ -0,0 +1,114 @@
+#include "../stdafx.h"\r
+\r
+#include "tbb_avcodec.h"\r
+\r
+#include <common/log/log.h>\r
+#include <common/env.h>\r
+#include <common/utility/assert.h>\r
+\r
+#include <tbb/task.h>\r
+#include <tbb/atomic.h>\r
+#include <tbb/parallel_for.h>\r
+#include <tbb/tbb_thread.h>\r
+\r
+#if defined(_MSC_VER)\r
+#pragma warning (push)\r
+#pragma warning (disable : 4244)\r
+#endif\r
+extern "C" \r
+{\r
+       #define __STDC_CONSTANT_MACROS\r
+       #define __STDC_LIMIT_MACROS\r
+       #include <libavformat/avformat.h>\r
+}\r
+#if defined(_MSC_VER)\r
+#pragma warning (pop)\r
+#endif\r
+\r
+namespace caspar {\r
+               \r
+int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)\r
+{\r
+       tbb::parallel_for(tbb::blocked_range<size_t>(0, count), [&](const tbb::blocked_range<size_t>& r)\r
+       {\r
+               for(size_t n = r.begin(); n != r.end(); ++n)            \r
+               {\r
+                       int r = func(s, reinterpret_cast<uint8_t*>(arg) + n*size);\r
+                       if(ret)\r
+                               ret[n] = r;\r
+               }\r
+       });\r
+\r
+       return 0;\r
+}\r
+\r
+int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)\r
+{      \r
+       tbb::atomic<int> counter;   \r
+    counter = 0;   \r
+\r
+       CASPAR_ASSERT(tbb::tbb_thread::hardware_concurrency() < 16);\r
+       // Note: this will probably only work when tbb::task_scheduler_init::num_threads() < 16.\r
+    tbb::parallel_for(tbb::blocked_range<int>(0, count, 2), [&](const tbb::blocked_range<int> &r)    \r
+    {   \r
+        int threadnr = counter++;   \r
+        for(int jobnr = r.begin(); jobnr != r.end(); ++jobnr)\r
+        {   \r
+            int r = func(s, arg, jobnr, threadnr);   \r
+            if (ret)   \r
+                ret[jobnr] = r;   \r
+        }\r
+        --counter;\r
+    });   \r
+\r
+    return 0;  \r
+}\r
+\r
+void thread_init(AVCodecContext* s)\r
+{\r
+       static const size_t MAX_THREADS = 16; // See mpegvideo.h\r
+       static int dummy_opaque;\r
+\r
+    s->active_thread_type = FF_THREAD_SLICE;\r
+       s->thread_opaque          = &dummy_opaque; \r
+    s->execute                   = thread_execute;\r
+    s->execute2                          = thread_execute2;\r
+    s->thread_count              = MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible. \r
+\r
+       CASPAR_LOG(info) << "Initialized ffmpeg tbb context.";\r
+}\r
+\r
+void thread_free(AVCodecContext* s)\r
+{\r
+       if(!s->thread_opaque)\r
+               return;\r
+\r
+       s->thread_opaque = nullptr;\r
+       \r
+       CASPAR_LOG(info) << "Released ffmpeg tbb context.";\r
+}\r
+\r
+int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)\r
+{\r
+       CodecID supported_codecs[] = {CODEC_ID_MPEG2VIDEO, CODEC_ID_PRORES};\r
+\r
+       avctx->thread_count = 1;\r
+       // Some codecs don't like to have multiple multithreaded decoding instances. Only enable for those we know work.\r
+       if(std::find(std::begin(supported_codecs), std::end(supported_codecs), codec->id) != std::end(supported_codecs) && \r
+         (codec->capabilities & CODEC_CAP_SLICE_THREADS) && \r
+         (avctx->thread_type & FF_THREAD_SLICE))\r
+       {\r
+               thread_init(avctx);\r
+       }       \r
+       // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.\r
+       return avcodec_open(avctx, codec); \r
+}\r
+\r
+int tbb_avcodec_close(AVCodecContext* avctx)\r
+{\r
+       thread_free(avctx);\r
+       // ff_thread_free will not be executed since thread_opaque == nullptr.\r
+       return avcodec_close(avctx); \r
+}\r
+\r
+}
\ No newline at end of file
diff --git a/modules/ffmpeg/producer/tbb_avcodec.h b/modules/ffmpeg/producer/tbb_avcodec.h
new file mode 100644 (file)
index 0000000..e2aa3e9
--- /dev/null
@@ -0,0 +1,11 @@
+#pragma once\r
+\r
+struct AVCodecContext;\r
+struct AVCodec;\r
+\r
+namespace caspar {\r
+       \r
+int tbb_avcodec_open(AVCodecContext *avctx, AVCodec *codec);\r
+int tbb_avcodec_close(AVCodecContext *avctx);\r
+\r
+}
\ No newline at end of file
index 5b9cd16b432f81fba0b6dae16033e1ccc3f19944..727246c31608a1247ab235b264d533f3798946c3 100644 (file)
@@ -4,6 +4,7 @@
 \r
 #include "flv.h"\r
 \r
+#include "../tbb_avcodec.h"\r
 #include "../../ffmpeg_error.h"\r
 \r
 #include <tbb/concurrent_unordered_map.h>\r
@@ -361,8 +362,8 @@ safe_ptr<AVCodecContext> open_codec(AVFormatContext& context, enum AVMediaType t
 {      \r
        AVCodec* decoder;\r
        index = THROW_ON_ERROR2(av_find_best_stream(&context, type, -1, -1, &decoder, 0), "");\r
-       THROW_ON_ERROR2(avcodec_open(context.streams[index]->codec, decoder), "");\r
-       return safe_ptr<AVCodecContext>(context.streams[index]->codec, avcodec_close);\r
+       THROW_ON_ERROR2(tbb_avcodec_open(context.streams[index]->codec, decoder), "");\r
+       return safe_ptr<AVCodecContext>(context.streams[index]->codec, tbb_avcodec_close);\r
 }\r
 \r
 safe_ptr<AVFormatContext> open_input(const std::wstring& filename)\r