From: ronag Date: Wed, 23 Nov 2011 22:04:38 +0000 (+0000) Subject: 2.0.2: ffmped_producer: Added multithreaded prores decoding. X-Git-Tag: 2.0.2~142 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=ef302a3b7c7e22f010ca11174b9db7fe5689df4a;p=casparcg 2.0.2: ffmped_producer: Added multithreaded prores decoding. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.2@1635 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- diff --git a/modules/ffmpeg/ffmpeg.vcxproj b/modules/ffmpeg/ffmpeg.vcxproj index ae25fb712..a5cb8baf4 100644 --- a/modules/ffmpeg/ffmpeg.vcxproj +++ b/modules/ffmpeg/ffmpeg.vcxproj @@ -297,7 +297,6 @@ ../StdAfx.h ../StdAfx.h ../StdAfx.h - false ../../StdAfx.h @@ -323,6 +322,12 @@ ../../StdAfx.h ../../StdAfx.h + + ../StdAfx.h + ../StdAfx.h + ../StdAfx.h + ../StdAfx.h + ../../StdAfx.h ../../StdAfx.h @@ -360,6 +365,7 @@ + diff --git a/modules/ffmpeg/ffmpeg.vcxproj.filters b/modules/ffmpeg/ffmpeg.vcxproj.filters index 2bfa0cd63..8e2e3ad4f 100644 --- a/modules/ffmpeg/ffmpeg.vcxproj.filters +++ b/modules/ffmpeg/ffmpeg.vcxproj.filters @@ -30,9 +30,6 @@ - - source\producer - source\producer\video @@ -67,6 +64,12 @@ source\producer\muxer + + source\producer + + + source\producer + @@ -112,5 +115,8 @@ source\producer\muxer + + source\producer + \ No newline at end of file diff --git a/modules/ffmpeg/producer/tbb_avcodec.cpp b/modules/ffmpeg/producer/tbb_avcodec.cpp new file mode 100644 index 000000000..40babe083 --- /dev/null +++ b/modules/ffmpeg/producer/tbb_avcodec.cpp @@ -0,0 +1,114 @@ +#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 diff --git a/modules/ffmpeg/producer/tbb_avcodec.h b/modules/ffmpeg/producer/tbb_avcodec.h new file mode 100644 index 000000000..e2aa3e9af --- /dev/null +++ b/modules/ffmpeg/producer/tbb_avcodec.h @@ -0,0 +1,11 @@ +#pragma once + +struct AVCodecContext; +struct AVCodec; + +namespace caspar { + +int tbb_avcodec_open(AVCodecContext *avctx, AVCodec *codec); +int tbb_avcodec_close(AVCodecContext *avctx); + +} \ No newline at end of file diff --git a/modules/ffmpeg/producer/util/util.cpp b/modules/ffmpeg/producer/util/util.cpp index 5b9cd16b4..727246c31 100644 --- a/modules/ffmpeg/producer/util/util.cpp +++ b/modules/ffmpeg/producer/util/util.cpp @@ -4,6 +4,7 @@ #include "flv.h" +#include "../tbb_avcodec.h" #include "../../ffmpeg_error.h" #include @@ -361,8 +362,8 @@ safe_ptr open_codec(AVFormatContext& context, enum AVMediaType t { AVCodec* decoder; index = THROW_ON_ERROR2(av_find_best_stream(&context, type, -1, -1, &decoder, 0), ""); - THROW_ON_ERROR2(avcodec_open(context.streams[index]->codec, decoder), ""); - return safe_ptr(context.streams[index]->codec, avcodec_close); + THROW_ON_ERROR2(tbb_avcodec_open(context.streams[index]->codec, decoder), ""); + return safe_ptr(context.streams[index]->codec, tbb_avcodec_close); } safe_ptr open_input(const std::wstring& filename)