1 // Author Robert Nagy
\r
5 #include "tbb_avcodec.h"
\r
7 #include <common/log/log.h>
\r
9 #include <tbb/task.h>
\r
10 #include <tbb/atomic.h>
\r
14 #define __STDC_CONSTANT_MACROS
\r
15 #define __STDC_LIMIT_MACROS
\r
16 #include <libavformat/avformat.h>
\r
21 struct thread_context{};
\r
23 int task_execute(AVCodecContext* s, const std::function<int(void* arg, int arg_size, int jobnr, int threadnr)>& func, void* arg, int* ret, int count, int size)
\r
25 // jobnr global for all threads? Doesn't order matter?
\r
26 tbb::atomic<int> counter;
\r
29 // Execute s->thread_count number of tasks in parallel.
\r
30 tbb::parallel_for(0, s->thread_count, 1, [&](int threadnr)
\r
34 int jobnr = counter++;
\r
38 int r = func(arg, size, jobnr, threadnr);
\r
47 int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)
\r
49 return task_execute(s, [&](void* arg, int arg_size, int jobnr, int threadnr) -> int
\r
51 return func(s, reinterpret_cast<uint8_t*>(arg) + jobnr*size);
\r
52 }, arg, ret, count, size);
\r
55 int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)
\r
57 return task_execute(s, [&](void* arg, int arg_size, int jobnr, int threadnr) -> int
\r
59 return func(s, arg, jobnr, threadnr);
\r
60 }, arg, ret, count, 0);
\r
63 int thread_init(AVCodecContext *s)
\r
65 // Only makes sense for slicing since decode is already called through task scheduler.
\r
66 if(!(s->thread_type & FF_THREAD_SLICE))
\r
69 static const size_t MAX_THREADS = 16; // See mpegvideo.h
\r
71 s->active_thread_type = FF_THREAD_SLICE;
\r
72 s->thread_opaque = malloc(sizeof(thread_context));
\r
73 s->execute = thread_execute;
\r
74 s->execute2 = thread_execute2;
\r
75 s->thread_count = MAX_THREADS; // We are using a taskscheduler, so use as many "threads/tasks" as possible.
\r
77 CASPAR_LOG(info) << "Initialized ffmpeg tbb context.";
\r
82 void thread_free(AVCodecContext* s)
\r
84 if(!s->thread_opaque)
\r
87 free(s->thread_opaque);
\r
88 s->thread_opaque = nullptr;
\r
90 CASPAR_LOG(info) << "Released ffmpeg tbb context.";
\r
93 int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)
\r
96 // ff_thread_init will not be executed since thread_opaque != nullptr.
\r
97 return avcodec_open(avctx, codec);
\r
100 int tbb_avcodec_close(AVCodecContext* avctx)
\r
102 thread_free(avctx);
\r
103 // ff_thread_free will not be executed since thread_opaque == nullptr.
\r
104 return avcodec_close(avctx);
\r