X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fffmpeg%2Fproducer%2Ftbb_avcodec.cpp;h=44857ccf3e93d96347b501f2af0b4e37138e9832;hb=e0e1a2b1fdcab66e8da72e3eaa2db5564f8f9d72;hp=40babe0834dff73f15670916dc7985d7b00b7bf5;hpb=ef302a3b7c7e22f010ca11174b9db7fe5689df4a;p=casparcg diff --git a/modules/ffmpeg/producer/tbb_avcodec.cpp b/modules/ffmpeg/producer/tbb_avcodec.cpp index 40babe083..44857ccf3 100644 --- a/modules/ffmpeg/producer/tbb_avcodec.cpp +++ b/modules/ffmpeg/producer/tbb_avcodec.cpp @@ -1,114 +1,127 @@ -#include "../stdafx.h" - -#include "tbb_avcodec.h" - -#include -#include -#include - -#include -#include -#include -#include - -#if defined(_MSC_VER) -#pragma warning (push) -#pragma warning (disable : 4244) -#endif -extern "C" -{ - #define __STDC_CONSTANT_MACROS - #define __STDC_LIMIT_MACROS - #include -} -#if defined(_MSC_VER) -#pragma warning (pop) -#endif - -namespace caspar { - -int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size) -{ - tbb::parallel_for(tbb::blocked_range(0, count), [&](const tbb::blocked_range& r) - { - for(size_t n = r.begin(); n != r.end(); ++n) - { - int r = func(s, reinterpret_cast(arg) + n*size); - if(ret) - ret[n] = r; - } - }); - - return 0; -} - -int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count) -{ - tbb::atomic counter; - counter = 0; - - CASPAR_ASSERT(tbb::tbb_thread::hardware_concurrency() < 16); - // Note: this will probably only work when tbb::task_scheduler_init::num_threads() < 16. - tbb::parallel_for(tbb::blocked_range(0, count, 2), [&](const tbb::blocked_range &r) - { - int threadnr = counter++; - for(int jobnr = r.begin(); jobnr != r.end(); ++jobnr) - { - int r = func(s, arg, jobnr, threadnr); - if (ret) - ret[jobnr] = r; - } - --counter; - }); - - return 0; -} - -void thread_init(AVCodecContext* s) -{ - static const size_t MAX_THREADS = 16; // See mpegvideo.h - static int dummy_opaque; - - s->active_thread_type = FF_THREAD_SLICE; - s->thread_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. - - CASPAR_LOG(info) << "Initialized ffmpeg tbb context."; -} - -void thread_free(AVCodecContext* s) -{ - if(!s->thread_opaque) - return; - - s->thread_opaque = nullptr; - - CASPAR_LOG(info) << "Released ffmpeg tbb context."; -} - -int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec) -{ - CodecID supported_codecs[] = {CODEC_ID_MPEG2VIDEO, CODEC_ID_PRORES}; - - avctx->thread_count = 1; - // Some codecs don't like to have multiple multithreaded decoding instances. Only enable for those we know work. - if(std::find(std::begin(supported_codecs), std::end(supported_codecs), codec->id) != std::end(supported_codecs) && - (codec->capabilities & CODEC_CAP_SLICE_THREADS) && - (avctx->thread_type & FF_THREAD_SLICE)) - { - thread_init(avctx); - } - // ff_thread_init will not be executed since thread_opaque != nullptr || thread_count == 1. - return avcodec_open(avctx, codec); -} - -int tbb_avcodec_close(AVCodecContext* avctx) -{ - thread_free(avctx); - // ff_thread_free will not be executed since thread_opaque == nullptr. - return avcodec_close(avctx); -} - -} \ No newline at end of file +/* +* Copyright (c) 2011 Sveriges Television AB +* +* 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 . +* +* Author: Robert Nagy, ronag89@gmail.com +*/ + +#include "../StdAfx.h" + +#include "tbb_avcodec.h" + +#include +#include +#include +#include + +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning (push) +#pragma warning (disable : 4244) +#endif +extern "C" +{ + #define __STDC_CONSTANT_MACROS + #define __STDC_LIMIT_MACROS + #include +} +#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, 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); +} + +}