\r
next_audio_transforms_[tag] = next; // Store all active tags, inactive tags will be removed in end_pass.\r
\r
- auto next_gain = next.get_gain();\r
- auto prev_gain = prev.get_gain();\r
\r
- if(next_gain < 0.001 && prev_gain < 0.001)\r
+ if(next.get_gain() < 0.001 && prev.get_gain() < 0.001)\r
return;\r
+ \r
+ static const int BASE = 1<<15;\r
+\r
+ auto next_gain = static_cast<int>(next.get_gain()*BASE);\r
+ auto prev_gain = static_cast<int>(prev.get_gain()*BASE);\r
+ \r
+ int n_samples = audio_data_.back().size();\r
\r
tbb::parallel_for\r
(\r
{\r
for(size_t n = r.begin(); n < r.end(); ++n)\r
{\r
- double alpha = static_cast<double>(n)/static_cast<double>(audio_data_.back().size());\r
- double sample_gain = prev_gain * (1.0 - alpha) + next_gain * alpha;\r
- int sample = static_cast<int>(audio_data[n]);\r
- sample = (static_cast<int>(sample_gain*static_cast<double>(1<<15))*sample)>>15;\r
+ int sample_gain = (prev_gain - (prev_gain * n)/n_samples) + (next_gain * n)/n_samples;\r
+ \r
+ int sample = (static_cast<int>(audio_data[n])*sample_gain)/BASE;\r
+ \r
audio_data_.back()[n] = static_cast<short>((static_cast<int>(audio_data_.back()[n]) + sample) & 0xFFFF);\r
}\r
}\r
#include "tbb_avcodec.h"\r
\r
#include <common/log/log.h>\r
+#include <common/env.h>\r
\r
#include <tbb/task.h>\r
#include <tbb/atomic.h>\r
\r
+#include <regex>\r
+#include <boost/algorithm/string.hpp>\r
+\r
extern "C" \r
{\r
#define __STDC_CONSTANT_MACROS\r
CASPAR_LOG(info) << "Released ffmpeg tbb context.";\r
}\r
\r
+std::regex get_slice_regex()\r
+{\r
+ auto s = env::properties().get("configuration.ffmpeg.slice-threads-regex", "");\r
+ boost::algorithm::erase_all(s, " ");\r
+ boost::algorithm::erase_all(s, "\n");\r
+ return std::regex(s);\r
+}\r
+\r
+bool allow_slice_thread(int id)\r
+{\r
+ static std::regex e = get_slice_regex();\r
+ return std::regex_match(boost::lexical_cast<std::string>(id), e);\r
+}\r
+\r
int tbb_avcodec_open(AVCodecContext* avctx, AVCodec* codec)\r
{\r
+ auto id = codec->id;\r
avctx->thread_count = 1;\r
- if((codec->capabilities & CODEC_CAP_SLICE_THREADS) && (avctx->thread_type & FF_THREAD_SLICE))\r
+ if(allow_slice_thread(id) && // Some codecs don't like to have multiple multithreaded decoding instances. Only enable for those we know work.\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
<diagnostics>\r
<graphs>true</graphs>\r
</diagnostics>\r
+ <ffmpeg>\r
+ <slice-threads-regex>\r
+ <!-- Use slice threads only for tested codecs.-->\r
+ <!-- Match the provided regex expression against the codec-id.-->\r
+ 2 <!-- mpeg2 --> | 28 <!-- h264 --> | 102 <!-- dnxhd -->\r
+ </slice-threads-regex>\r
+ </ffmpeg>\r
<channels>\r
<channel>\r
<videomode>1080i5000</videomode>\r