]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/tbb_avcodec.cpp
2.0.0.2: tbb_avcodec: Added better check for thread slicing support.
[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 \r
9 #include <tbb/task.h>\r
10 #include <tbb/atomic.h>\r
11 \r
12 extern "C" \r
13 {\r
14         #define __STDC_CONSTANT_MACROS\r
15         #define __STDC_LIMIT_MACROS\r
16         #include <libavformat/avformat.h>\r
17 }\r
18 \r
19 namespace caspar {\r
20         \r
21 int task_execute(AVCodecContext* s, std::function<int(void* arg, int arg_size, int jobnr, int threadnr)>&& func, void* arg, int* ret, int count, int size)\r
22 {       \r
23     tbb::atomic<int> counter;\r
24         counter = 0;\r
25                 \r
26         // Execute s->thread_count number of tasks in parallel.\r
27         tbb::parallel_for(0, s->thread_count, 1, [&](int threadnr) \r
28         {\r
29                 while(true)\r
30                 {\r
31                         int jobnr = counter++;\r
32                         if(jobnr >= count)\r
33                                 break;\r
34 \r
35                         int r = func(arg, size, jobnr, threadnr);\r
36                         if (ret)\r
37                                 ret[jobnr] = r;\r
38                 }\r
39         });\r
40         \r
41     return 0;\r
42 }\r
43         \r
44 int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)\r
45 {\r
46         return task_execute(s, [&](void* arg, int arg_size, int jobnr, int threadnr) -> int\r
47         {\r
48                 return func(s, reinterpret_cast<uint8_t*>(arg) + jobnr*size);\r
49         }, arg, ret, count, size);\r
50 }\r
51 \r
52 int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)\r
53 {\r
54         return task_execute(s, [&](void* arg, int arg_size, int jobnr, int threadnr) -> int\r
55         {\r
56                 return func(s, arg, jobnr, threadnr);\r
57         }, arg, ret, count, 0);\r
58 }\r
59 \r
60 void thread_init(AVCodecContext* s)\r
61 {\r
62         static const size_t MAX_THREADS = 16; // See mpegvideo.h\r
63         static int dummy_opaque;\r
64 \r
65     s->active_thread_type = FF_THREAD_SLICE;\r
66         s->thread_opaque          = &dummy_opaque; \r
67     s->execute                    = thread_execute;\r
68     s->execute2                   = thread_execute2;\r
69     s->thread_count               = MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible. \r
70 \r
71         CASPAR_LOG(info) << "Initialized ffmpeg tbb context.";\r
72 }\r
73 \r
74 void thread_free(AVCodecContext* s)\r
75 {\r
76         s->thread_opaque = nullptr;\r
77 \r
78         CASPAR_LOG(info) << "Released ffmpeg tbb context.";\r
79 }\r
80 \r
81 int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)\r
82 {\r
83         avctx->thread_count = 1;\r
84         if((codec->capabilities & CODEC_CAP_SLICE_THREADS) && (avctx->thread_type & FF_THREAD_SLICE))\r
85                 thread_init(avctx);\r
86         // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.\r
87         return avcodec_open(avctx, codec); \r
88 }\r
89 \r
90 int tbb_avcodec_close(AVCodecContext* avctx)\r
91 {\r
92         thread_free(avctx);\r
93         // ff_thread_free will not be executed since thread_opaque == nullptr.\r
94         return avcodec_close(avctx); \r
95 }\r
96 \r
97 }