-#include "../stdafx.h"\r
-\r
-#include "tbb_avcodec.h"\r
-\r
-#include <common/log/log.h>\r
-#include <common/env.h>\r
-#include <common/utility/assert.h>\r
-\r
-#include <tbb/task.h>\r
-#include <tbb/atomic.h>\r
-#include <tbb/parallel_for.h>\r
-#include <tbb/tbb_thread.h>\r
-\r
-#if defined(_MSC_VER)\r
-#pragma warning (push)\r
-#pragma warning (disable : 4244)\r
-#endif\r
-extern "C" \r
-{\r
- #define __STDC_CONSTANT_MACROS\r
- #define __STDC_LIMIT_MACROS\r
- #include <libavformat/avformat.h>\r
-}\r
-#if defined(_MSC_VER)\r
-#pragma warning (pop)\r
-#endif\r
-\r
-namespace caspar {\r
- \r
-int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)\r
-{\r
- tbb::parallel_for(tbb::blocked_range<size_t>(0, count), [&](const tbb::blocked_range<size_t>& r)\r
- {\r
- for(size_t n = r.begin(); n != r.end(); ++n) \r
- {\r
- int r = func(s, reinterpret_cast<uint8_t*>(arg) + n*size);\r
- if(ret)\r
- ret[n] = r;\r
- }\r
- });\r
-\r
- return 0;\r
-}\r
-\r
-int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)\r
-{ \r
- tbb::atomic<int> counter; \r
- counter = 0; \r
-\r
- CASPAR_ASSERT(tbb::tbb_thread::hardware_concurrency() < 16);\r
- // Note: this will probably only work when tbb::task_scheduler_init::num_threads() < 16.\r
- tbb::parallel_for(tbb::blocked_range<int>(0, count, 2), [&](const tbb::blocked_range<int> &r) \r
- { \r
- int threadnr = counter++; \r
- for(int jobnr = r.begin(); jobnr != r.end(); ++jobnr)\r
- { \r
- int r = func(s, arg, jobnr, threadnr); \r
- if (ret) \r
- ret[jobnr] = r; \r
- }\r
- --counter;\r
- }); \r
-\r
- return 0; \r
-}\r
-\r
-void thread_init(AVCodecContext* s)\r
-{\r
- static const size_t MAX_THREADS = 16; // See mpegvideo.h\r
- static int dummy_opaque;\r
-\r
- s->active_thread_type = FF_THREAD_SLICE;\r
- s->thread_opaque = &dummy_opaque; \r
- s->execute = thread_execute;\r
- s->execute2 = thread_execute2;\r
- s->thread_count = tbb::tbb_thread::hardware_concurrency(); // MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible. \r
-\r
- CASPAR_LOG(info) << "Initialized ffmpeg tbb context.";\r
-}\r
-\r
-void thread_free(AVCodecContext* s)\r
-{\r
- if(!s->thread_opaque)\r
- return;\r
-\r
- s->thread_opaque = nullptr;\r
- \r
- CASPAR_LOG(info) << "Released ffmpeg tbb context.";\r
-}\r
-\r
-int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)\r
-{\r
- CodecID supported_codecs[] = {CODEC_ID_MPEG2VIDEO, CODEC_ID_PRORES};\r
-\r
- avctx->thread_count = 1;\r
- // Some codecs don't like to have multiple multithreaded decoding instances. Only enable for those we know work.\r
- if(std::find(std::begin(supported_codecs), std::end(supported_codecs), codec->id) != std::end(supported_codecs) && \r
- (codec->capabilities & CODEC_CAP_SLICE_THREADS) && \r
- (avctx->thread_type & FF_THREAD_SLICE))\r
- {\r
- thread_init(avctx);\r
- } \r
- // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.\r
- return avcodec_open(avctx, codec); \r
-}\r
-\r
-int tbb_avcodec_close(AVCodecContext* avctx)\r
-{\r
- thread_free(avctx);\r
- // ff_thread_free will not be executed since thread_opaque == nullptr.\r
- return avcodec_close(avctx); \r
-}\r
-\r
-}
\ No newline at end of file
+/*
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Robert Nagy, ronag89@gmail.com
+*/
+
+#include "../StdAfx.h"
+
+#include "tbb_avcodec.h"
+
+#include <common/assert.h>
+#include <common/except.h>
+#include <common/log.h>
+#include <common/env.h>
+
+#include <tbb/atomic.h>
+#include <tbb/parallel_for.h>
+#include <tbb/tbb_thread.h>
+
+#if defined(_MSC_VER)
+#pragma warning (push)
+#pragma warning (disable : 4244)
+#endif
+extern "C"
+{
+ #define __STDC_CONSTANT_MACROS
+ #define __STDC_LIMIT_MACROS
+ #include <libavformat/avformat.h>
+}
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+
+namespace caspar {
+
+static const int MAX_THREADS = 16; // See mpegvideo.h
+
+int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)
+{
+ tbb::parallel_for(0, count, 1, [&](int i)
+ {
+ int r = func(s, (char*)arg + i*size);
+ if(ret)
+ ret[i] = r;
+ });
+
+ return 0;
+}
+
+int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)
+{
+ // TODO: Micro-optimize...
+
+ std::array<std::vector<int>, 16> jobs;
+
+ for(int n = 0; n < count; ++n)
+ jobs[(n*MAX_THREADS) / count].push_back(n);
+
+ tbb::parallel_for(0, MAX_THREADS, [&](int n)
+ {
+ for (auto k : jobs[n])
+ {
+ int r = func(s, arg, k, n);
+ if(ret)
+ ret[k]= r;
+ }
+ });
+
+ return 0;
+}
+
+void thread_init(AVCodecContext* s)
+{
+ static int dummy_opaque;
+
+ s->active_thread_type = FF_THREAD_SLICE;
+ s->opaque = &dummy_opaque;
+ s->execute = thread_execute;
+ s->execute2 = thread_execute2;
+ s->thread_count = MAX_THREADS; // We are using a task-scheduler, so use as many "threads/tasks" as possible.
+}
+
+void thread_free(AVCodecContext* s)
+{
+ if(!s->opaque)
+ return;
+
+ s->opaque = nullptr;
+}
+
+int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec, bool single_threaded)
+{
+ if(codec->capabilities & CODEC_CAP_EXPERIMENTAL)
+ CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Experimental codecs are not supported."));
+
+ avctx->thread_count = 1;
+
+ if(!single_threaded && codec->capabilities & CODEC_CAP_SLICE_THREADS)
+ thread_init(avctx);
+
+ // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1.
+ return avcodec_open2(avctx, codec, nullptr);
+}
+
+int tbb_avcodec_close(AVCodecContext* avctx)
+{
+ thread_free(avctx);
+ // ff_thread_free will not be executed since thread_opaque == nullptr.
+ return avcodec_close(avctx);
+}
+
+}