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