]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/tbb_avcodec.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[casparcg] / modules / ffmpeg / producer / tbb_avcodec.cpp
1 #include "../stdafx.h"\r
2 \r
3 #include "tbb_avcodec.h"\r
4 \r
5 #include <common/log/log.h>\r
6 #include <common/env.h>\r
7 #include <common/utility/assert.h>\r
8 \r
9 #include <tbb/task.h>\r
10 #include <tbb/atomic.h>\r
11 #include <tbb/parallel_for.h>\r
12 #include <tbb/tbb_thread.h>\r
13 \r
14 #if defined(_MSC_VER)\r
15 #pragma warning (push)\r
16 #pragma warning (disable : 4244)\r
17 #endif\r
18 extern "C" \r
19 {\r
20         #define __STDC_CONSTANT_MACROS\r
21         #define __STDC_LIMIT_MACROS\r
22         #include <libavformat/avformat.h>\r
23 }\r
24 #if defined(_MSC_VER)\r
25 #pragma warning (pop)\r
26 #endif\r
27 \r
28 namespace caspar {\r
29                 \r
30 int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)\r
31 {\r
32         tbb::parallel_for(tbb::blocked_range<size_t>(0, count), [&](const tbb::blocked_range<size_t>& r)\r
33         {\r
34                 for(size_t n = r.begin(); n != r.end(); ++n)            \r
35                 {\r
36                         int r = func(s, reinterpret_cast<uint8_t*>(arg) + n*size);\r
37                         if(ret)\r
38                                 ret[n] = r;\r
39                 }\r
40         });\r
41 \r
42         return 0;\r
43 }\r
44 \r
45 int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)\r
46 {       \r
47         tbb::atomic<int> counter;   \r
48     counter = 0;   \r
49 \r
50         CASPAR_ASSERT(tbb::tbb_thread::hardware_concurrency() < 16);\r
51         // Note: this will probably only work when tbb::task_scheduler_init::num_threads() < 16.\r
52     tbb::parallel_for(tbb::blocked_range<int>(0, count, 2), [&](const tbb::blocked_range<int> &r)    \r
53     {   \r
54         int threadnr = counter++;   \r
55         for(int jobnr = r.begin(); jobnr != r.end(); ++jobnr)\r
56         {   \r
57             int r = func(s, arg, jobnr, threadnr);   \r
58             if (ret)   \r
59                 ret[jobnr] = r;   \r
60         }\r
61         --counter;\r
62     });   \r
63 \r
64     return 0;  \r
65 }\r
66 \r
67 void thread_init(AVCodecContext* s)\r
68 {\r
69         static const size_t MAX_THREADS = 16; // See mpegvideo.h\r
70         static int dummy_opaque;\r
71 \r
72     s->active_thread_type = FF_THREAD_SLICE;\r
73         s->thread_opaque          = &dummy_opaque; \r
74     s->execute                    = thread_execute;\r
75     s->execute2                   = thread_execute2;\r
76     s->thread_count               = MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible. \r
77 \r
78         CASPAR_LOG(info) << "Initialized ffmpeg tbb context.";\r
79 }\r
80 \r
81 void thread_free(AVCodecContext* s)\r
82 {\r
83         if(!s->thread_opaque)\r
84                 return;\r
85 \r
86         s->thread_opaque = nullptr;\r
87         \r
88         CASPAR_LOG(info) << "Released ffmpeg tbb context.";\r
89 }\r
90 \r
91 int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)\r
92 {\r
93         CodecID supported_codecs[] = {CODEC_ID_MPEG2VIDEO, CODEC_ID_PRORES, CODEC_ID_FFV1};\r
94 \r
95         avctx->thread_count = 1;\r
96         // Some codecs don't like to have multiple multithreaded decoding instances. Only enable for those we know work.\r
97         if(std::find(std::begin(supported_codecs), std::end(supported_codecs), codec->id) != std::end(supported_codecs) && \r
98           (codec->capabilities & CODEC_CAP_SLICE_THREADS) && \r
99           (avctx->thread_type & FF_THREAD_SLICE))\r
100         {\r
101                 thread_init(avctx);\r
102         }       \r
103         // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.\r
104         return avcodec_open(avctx, codec); \r
105 }\r
106 \r
107 int tbb_avcodec_close(AVCodecContext* avctx)\r
108 {\r
109         thread_free(avctx);\r
110         // ff_thread_free will not be executed since thread_opaque == nullptr.\r
111         return avcodec_close(avctx); \r
112 }\r
113 \r
114 }