1 #include "../stdafx.h"
\r
3 #include "tbb_avcodec.h"
\r
5 #include <common/log/log.h>
\r
6 #include <common/env.h>
\r
7 #include <common/utility/assert.h>
\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
14 #if defined(_MSC_VER)
\r
15 #pragma warning (push)
\r
16 #pragma warning (disable : 4244)
\r
20 #define __STDC_CONSTANT_MACROS
\r
21 #define __STDC_LIMIT_MACROS
\r
22 #include <libavformat/avformat.h>
\r
24 #if defined(_MSC_VER)
\r
25 #pragma warning (pop)
\r
30 int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)
\r
32 tbb::parallel_for(tbb::blocked_range<size_t>(0, count), [&](const tbb::blocked_range<size_t>& r)
\r
34 for(size_t n = r.begin(); n != r.end(); ++n)
\r
36 int r = func(s, reinterpret_cast<uint8_t*>(arg) + n*size);
\r
45 int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)
\r
47 tbb::atomic<int> counter;
\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
54 int threadnr = counter++;
\r
55 for(int jobnr = r.begin(); jobnr != r.end(); ++jobnr)
\r
57 int r = func(s, arg, jobnr, threadnr);
\r
67 void thread_init(AVCodecContext* s)
\r
69 static const size_t MAX_THREADS = 16; // See mpegvideo.h
\r
70 static int dummy_opaque;
\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
78 CASPAR_LOG(info) << "Initialized ffmpeg tbb context.";
\r
81 void thread_free(AVCodecContext* s)
\r
83 if(!s->thread_opaque)
\r
86 s->thread_opaque = nullptr;
\r
88 CASPAR_LOG(info) << "Released ffmpeg tbb context.";
\r
91 int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)
\r
93 CodecID supported_codecs[] = {CODEC_ID_MPEG2VIDEO, CODEC_ID_PRORES};
\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
101 thread_init(avctx);
\r
103 // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.
\r
104 return avcodec_open(avctx, codec);
\r
107 int tbb_avcodec_close(AVCodecContext* avctx)
\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