]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/tbb_avcodec.cpp
2.0.0.2: - tbb_avcodec: Multithreading only enabled from MPEG2 until other codecs...
[casparcg] / modules / ffmpeg / tbb_avcodec.cpp
1 // Author Robert Nagy\r
2 \r
3 #include "stdafx.h"\r
4 \r
5 #include "tbb_avcodec.h"\r
6 \r
7 #include <common/log/log.h>\r
8 #include <common/env.h>\r
9 \r
10 #include <tbb/task.h>\r
11 #include <tbb/atomic.h>\r
12 \r
13 #include <regex>\r
14 #include <boost/algorithm/string.hpp>\r
15 \r
16 extern "C" \r
17 {\r
18         #define __STDC_CONSTANT_MACROS\r
19         #define __STDC_LIMIT_MACROS\r
20         #include <libavformat/avformat.h>\r
21 }\r
22 \r
23 namespace caspar {\r
24                 \r
25 int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)\r
26 {\r
27         tbb::parallel_for(tbb::blocked_range<size_t>(0, count), [&](const tbb::blocked_range<size_t>& r)\r
28         {\r
29                 for(size_t n = r.begin(); n != r.end(); ++n)            \r
30                 {\r
31                         int r = func(s, reinterpret_cast<uint8_t*>(arg) + n*size);\r
32                         if(ret)\r
33                                 ret[n] = r;\r
34                 }\r
35         });\r
36 \r
37         return 0;\r
38 }\r
39 \r
40 int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)\r
41 {       \r
42     tbb::atomic<int> counter;\r
43         counter = 0;\r
44                 \r
45         // Execute s->thread_count number of tasks in parallel.\r
46         tbb::parallel_for(0, s->thread_count, 1, [&](int threadnr) \r
47         {\r
48                 while(true)\r
49                 {\r
50                         int jobnr = counter++;\r
51                         if(jobnr >= count)\r
52                                 break;\r
53 \r
54                         int r = func(s, arg, jobnr, threadnr);\r
55                         if (ret)\r
56                                 ret[jobnr] = r;\r
57                 }\r
58         });\r
59 \r
60         return 0;\r
61 }\r
62 \r
63 void thread_init(AVCodecContext* s)\r
64 {\r
65         static const size_t MAX_THREADS = 16; // See mpegvideo.h\r
66         static int dummy_opaque;\r
67 \r
68     s->active_thread_type = FF_THREAD_SLICE;\r
69         s->thread_opaque          = &dummy_opaque; \r
70     s->execute                    = thread_execute;\r
71     s->execute2                   = thread_execute2;\r
72     s->thread_count               = MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible. \r
73 \r
74         CASPAR_LOG(info) << "Initialized ffmpeg tbb context.";\r
75 }\r
76 \r
77 void thread_free(AVCodecContext* s)\r
78 {\r
79         s->thread_opaque = nullptr;\r
80 \r
81         CASPAR_LOG(info) << "Released ffmpeg tbb context.";\r
82 }\r
83 \r
84 int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)\r
85 {\r
86         avctx->thread_count = 1;\r
87         // Some codecs don't like to have multiple multithreaded decoding instances. Only enable for those we know work.\r
88         if(codec->id == CODEC_ID_MPEG2VIDEO && \r
89           (codec->capabilities & CODEC_CAP_SLICE_THREADS) && \r
90           (avctx->thread_type & FF_THREAD_SLICE))\r
91         {\r
92                 thread_init(avctx);\r
93         }       \r
94         // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.\r
95         return avcodec_open(avctx, codec); \r
96 }\r
97 \r
98 int tbb_avcodec_close(AVCodecContext* avctx)\r
99 {\r
100         thread_free(avctx);\r
101         // ff_thread_free will not be executed since thread_opaque == nullptr.\r
102         return avcodec_close(avctx); \r
103 }\r
104 \r
105 }