size_t last_width_;\r
size_t last_height_;\r
\r
- std::string get_blend_color_func()\r
- {\r
- return \r
- \r
- get_blend_glsl()\r
- \r
- +\r
- \r
- "vec3 get_blend_color(vec3 back, vec3 fore) \n"\r
- "{ \n"\r
- " switch(blend_mode) \n"\r
- " { \n"\r
- " case 0: return BlendNormal(back, fore); \n"\r
- " case 1: return BlendLighten(back, fore); \n"\r
- " case 2: return BlendDarken(back, fore); \n"\r
- " case 3: return BlendMultiply(back, fore); \n"\r
- " case 4: return BlendAverage(back, fore); \n"\r
- " case 5: return BlendAdd(back, fore); \n"\r
- " case 6: return BlendSubstract(back, fore); \n"\r
- " case 7: return BlendDifference(back, fore); \n"\r
- " case 8: return BlendNegation(back, fore); \n"\r
- " case 9: return BlendExclusion(back, fore); \n"\r
- " case 10: return BlendScreen(back, fore); \n"\r
- " case 11: return BlendOverlay(back, fore); \n"\r
- //" case 12: return BlendSoftLight(back, fore); \n"\r
- " case 13: return BlendHardLight(back, fore); \n"\r
- " case 14: return BlendColorDodge(back, fore); \n"\r
- " case 15: return BlendColorBurn(back, fore); \n"\r
- " case 16: return BlendLinearDodge(back, fore); \n"\r
- " case 17: return BlendLinearBurn(back, fore); \n"\r
- " case 18: return BlendLinearLight(back, fore); \n"\r
- " case 19: return BlendVividLight(back, fore); \n"\r
- " case 20: return BlendPinLight(back, fore); \n"\r
- " case 21: return BlendHardMix(back, fore); \n"\r
- " case 22: return BlendReflect(back, fore); \n"\r
- " case 23: return BlendGlow(back, fore); \n"\r
- " case 24: return BlendPhoenix(back, fore); \n"\r
- " case 25: return BlendHue(back, fore); \n"\r
- " case 26: return BlendSaturation(back, fore); \n"\r
- " case 27: return BlendColor(back, fore); \n"\r
- " case 28: return BlendLuminosity(back, fore); \n"\r
- " } \n"\r
- " return BlendNormal(back, fore); \n"\r
- "} \n"\r
- " \n" \r
- "vec4 blend_color(vec4 fore) \n"\r
- "{ \n"\r
- " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
- " if(levels) \n"\r
- " fore.rgb = LevelsControl(fore.rgb, min_input, max_input, gamma, min_output, max_output); \n"\r
- " if(csb) \n"\r
- " fore.rgb = ContrastSaturationBrightness(fore.rgb, brt, sat, con); \n"\r
- " fore.rgb = get_blend_color(back.bgr, fore.rgb); \n"\r
- " \n"\r
- " return vec4(mix(back.rgb, fore.rgb, fore.a), back.a + fore.a); \n"\r
- "} \n";\r
- }\r
- \r
- std::string get_simple_blend_color_func()\r
- {\r
- return \r
-\r
- "vec4 blend_color(vec4 fore) \n"\r
- "{ \n"\r
- " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
- " return vec4(mix(back.rgb, fore.rgb, fore.a), back.a + fore.a); \n"\r
- "} \n";\r
- }\r
+ //std::string get_blend_color_func()\r
+ //{\r
+ // return \r
+ // \r
+ // get_blend_glsl()\r
+ // \r
+ // +\r
+ // \r
+ // "vec3 get_blend_color(vec3 back, vec3 fore) \n"\r
+ // "{ \n"\r
+ // " switch(blend_mode) \n"\r
+ // " { \n"\r
+ // " case 0: return BlendNormal(back, fore); \n"\r
+ // " case 1: return BlendLighten(back, fore); \n"\r
+ // " case 2: return BlendDarken(back, fore); \n"\r
+ // " case 3: return BlendMultiply(back, fore); \n"\r
+ // " case 4: return BlendAverage(back, fore); \n"\r
+ // " case 5: return BlendAdd(back, fore); \n"\r
+ // " case 6: return BlendSubstract(back, fore); \n"\r
+ // " case 7: return BlendDifference(back, fore); \n"\r
+ // " case 8: return BlendNegation(back, fore); \n"\r
+ // " case 9: return BlendExclusion(back, fore); \n"\r
+ // " case 10: return BlendScreen(back, fore); \n"\r
+ // " case 11: return BlendOverlay(back, fore); \n"\r
+ // //" case 12: return BlendSoftLight(back, fore); \n"\r
+ // " case 13: return BlendHardLight(back, fore); \n"\r
+ // " case 14: return BlendColorDodge(back, fore); \n"\r
+ // " case 15: return BlendColorBurn(back, fore); \n"\r
+ // " case 16: return BlendLinearDodge(back, fore); \n"\r
+ // " case 17: return BlendLinearBurn(back, fore); \n"\r
+ // " case 18: return BlendLinearLight(back, fore); \n"\r
+ // " case 19: return BlendVividLight(back, fore); \n"\r
+ // " case 20: return BlendPinLight(back, fore); \n"\r
+ // " case 21: return BlendHardMix(back, fore); \n"\r
+ // " case 22: return BlendReflect(back, fore); \n"\r
+ // " case 23: return BlendGlow(back, fore); \n"\r
+ // " case 24: return BlendPhoenix(back, fore); \n"\r
+ // " case 25: return BlendHue(back, fore); \n"\r
+ // " case 26: return BlendSaturation(back, fore); \n"\r
+ // " case 27: return BlendColor(back, fore); \n"\r
+ // " case 28: return BlendLuminosity(back, fore); \n"\r
+ // " } \n"\r
+ // " return BlendNormal(back, fore); \n"\r
+ // "} \n"\r
+ // " \n" \r
+ // "vec4 blend_color(vec4 fore) \n"\r
+ // "{ \n"\r
+ // " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
+ // " if(levels) \n"\r
+ // " fore.rgb = LevelsControl(fore.rgb, min_input, max_input, gamma, min_output, max_output); \n"\r
+ // " if(csb) \n"\r
+ // " fore.rgb = ContrastSaturationBrightness(fore.rgb, brt, sat, con); \n"\r
+ // " fore.rgb = get_blend_color(back.bgr, fore.rgb); \n"\r
+ // " \n"\r
+ // " return vec4(mix(back.rgb, fore.rgb, fore.a), back.a + fore.a); \n"\r
+ // "} \n";\r
+ //}\r
+ // \r
+ //std::string get_simple_blend_color_func()\r
+ //{\r
+ // return \r
+\r
+ // "vec4 blend_color(vec4 fore) \n"\r
+ // "{ \n"\r
+ // " vec4 back = texture2D(background, gl_TexCoord[1].st); \n"\r
+ // " return vec4(mix(back.rgb, fore.rgb, fore.a), back.a + fore.a); \n"\r
+ // "} \n";\r
+ //}\r
\r
std::string get_vertex()\r
{\r
"uniform float brt; \n"\r
"uniform float sat; \n"\r
"uniform float con; \n"\r
- " \n"\r
-\r
- +\r
-\r
- (compability_mode ? get_simple_blend_color_func() : get_blend_color_func())\r
- \r
- +\r
+ " \n" \r
"//http://slouken.blogspot.com/2011/02/mpeg-acceleration-with-glsl.html \n"\r
"vec4 ycbcra_to_rgba_sd(float y, float cb, float cr, float a) \n"\r
"{ \n"\r
" color.a *= texture2D(local_key, gl_TexCoord[1].st).r; \n"\r
" if(has_layer_key) \n"\r
" color.a *= texture2D(layer_key, gl_TexCoord[1].st).r; \n"\r
- " gl_FragColor = blend_color(color.bgra * gl_Color); \n"\r
+ " gl_FragColor = color.bgra * gl_Color; \n"\r
"} \n";\r
}\r
\r
CASPAR_LOG(warning) << "Failed to compile shader. Trying to compile without blend-modes.";\r
shader_.reset(new shader(get_vertex(), get_fragment(true)));\r
}\r
+ \r
+ GL(glEnable(GL_BLEND));\r
+ GL(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE));\r
\r
GL(glEnable(GL_TEXTURE_2D));\r
}\r
channel_.ogl().yield(); // Try to give it some more time.\r
} \r
\r
- targets[1]->attach();\r
- \r
+ targets[0]->attach();\r
kernel_.draw(item, make_safe(targets[0]), local_key, layer_key);\r
+\r
+ //targets[1]->attach();\r
+ \r
+ //kernel_.draw(item, make_safe(targets[0]), local_key, layer_key);\r
\r
- targets[0]->bind();\r
+ //targets[0]->bind();\r
\r
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, targets[0]->width(), targets[0]->height());\r
+ //glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, targets[0]->width(), targets[0]->height());\r
\r
- std::swap(targets[0], targets[1]);\r
+ //std::swap(targets[0], targets[1]);\r
}\r
\r
safe_ptr<write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc)\r
#include <common/exception/exceptions.h>\r
#include <common/concurrency/executor.h>\r
#include <common/utility/tweener.h>\r
+#include <common/env.h>\r
\r
#include <core/mixer/read_frame.h>\r
#include <core/mixer/write_frame.h>\r
boost::fusion::map<boost::fusion::pair<core::image_transform, image_transforms>,\r
boost::fusion::pair<core::audio_transform, audio_transforms>> transforms_;\r
\r
+ std::queue<std::pair<boost::unique_future<safe_ptr<host_buffer>>, std::vector<int16_t>>> buffer_;\r
+ \r
+ const size_t buffer_size_;\r
+\r
public:\r
implementation(video_channel_context& video_channel) \r
: channel_(video_channel)\r
, audio_mixer_(channel_.get_format_desc())\r
, image_mixer_(channel_)\r
+ , buffer_size_(env::properties().get("configuration.producers.buffer-depth", 1))\r
{ \r
CASPAR_LOG(info) << print() << L" Successfully initialized."; \r
}\r
[&]{image = mix_image(frames);}, \r
[&]{audio = mix_audio(frames);});\r
\r
- return make_safe<read_frame>(channel_.ogl(), channel_.get_format_desc().size, std::move(image.get()), std::move(audio));\r
+ buffer_.push(std::make_pair(std::move(image), audio));\r
}\r
catch(...)\r
{\r
channel_.ogl().gc().wait();\r
\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
- return make_safe<read_frame>();\r
}\r
+\r
+ if(buffer_.size() > buffer_size_)\r
+ {\r
+ auto res = std::move(buffer_.front());\r
+ buffer_.pop();\r
+ \r
+ return make_safe<read_frame>(channel_.ogl(), channel_.get_format_desc().size, std::move(res.first.get()), std::move(res.second));\r
+ }\r
+ \r
+ return make_safe<read_frame>();\r
}\r
\r
safe_ptr<core::write_frame> create_frame(const void* tag, const core::pixel_format_desc& desc)\r
\r
#include <core/producer/frame/basic_frame.h>\r
\r
+#include <tbb/parallel_invoke.h>\r
+\r
namespace caspar { namespace core { \r
\r
struct separated_producer : public frame_producer\r
\r
virtual safe_ptr<basic_frame> receive(int hints)\r
{\r
- if(fill_ == core::basic_frame::late())\r
- fill_ = receive_and_follow(fill_producer_, hints);\r
- \r
- if(key_ == core::basic_frame::late())\r
- key_ = receive_and_follow(key_producer_, hints | ALPHA_HINT);\r
+ tbb::parallel_invoke(\r
+ [&]\r
+ {\r
+ if(fill_ == core::basic_frame::late())\r
+ fill_ = receive_and_follow(fill_producer_, hints);\r
+ },\r
+ [&]\r
+ {\r
+ if(key_ == core::basic_frame::late())\r
+ key_ = receive_and_follow(key_producer_, hints | ALPHA_HINT);\r
+ });\r
\r
if(fill_ == basic_frame::eof() || key_ == basic_frame::eof())\r
return basic_frame::eof();\r
\r
#include <boost/foreach.hpp>\r
\r
+#include <tbb/parallel_for_each.h>\r
+\r
#include <map>\r
#include <set>\r
\r
std::map<int, safe_ptr<basic_frame>> frames;\r
\r
try\r
- {\r
- BOOST_FOREACH(auto& layer, layers_)\r
+ { \r
+ BOOST_FOREACH(auto& layer, layers_) \r
+ frames[layer.first] = basic_frame::empty(); \r
+\r
+ tbb::parallel_for_each(layers_.begin(), layers_.end(), [&](std::map<int, layer>::value_type& layer) \r
{\r
- frames[layer.first] = layer.second.receive();\r
- channel_.execution().yield();\r
- }\r
+ frames[layer.first] = layer.second.receive(); \r
+ });\r
}\r
catch(...)\r
{\r
#include <core/producer/frame/image_transform.h>\r
#include <core/producer/frame/audio_transform.h>\r
\r
+#include <tbb/parallel_invoke.h>\r
+\r
namespace caspar { namespace core { \r
\r
struct transition_producer : public frame_producer\r
if(current_frame_++ >= info_.duration)\r
return basic_frame::eof();\r
\r
- auto dest = receive_and_follow(dest_producer_, hints);\r
- if(dest == core::basic_frame::late())\r
- dest = dest_producer_->last_frame();\r
+ auto dest = basic_frame::empty();\r
+ auto source = basic_frame::empty();\r
\r
- auto source = receive_and_follow(source_producer_, hints);\r
- if(source == core::basic_frame::late())\r
- source = source_producer_->last_frame();\r
+ tbb::parallel_invoke(\r
+ [&]\r
+ {\r
+ dest = receive_and_follow(dest_producer_, hints);\r
+ if(dest == core::basic_frame::late())\r
+ dest = dest_producer_->last_frame();\r
+ },\r
+ [&]\r
+ {\r
+ source = receive_and_follow(source_producer_, hints);\r
+ if(source == core::basic_frame::late())\r
+ source = source_producer_->last_frame();\r
+ });\r
\r
return last_frame_ = compose(dest, source);\r
}\r
#include <boost/range/algorithm/find_if.hpp>\r
#include <boost/range/algorithm/find.hpp>\r
\r
-#include <tbb/task_group.h>\r
+#include <tbb/parallel_invoke.h>\r
\r
namespace caspar {\r
\r
const bool loop_;\r
\r
safe_ptr<core::basic_frame> last_frame_;\r
-\r
- tbb::task_group tasks_;\r
+ bool eof_;\r
\r
public:\r
explicit ffmpeg_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filename, const std::wstring& filter, bool loop, int start, int length) \r
, start_(start)\r
, loop_(loop)\r
, last_frame_(core::basic_frame::empty())\r
+ , eof_(false)\r
{\r
graph_->add_guide("frame-time", 0.5);\r
graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));\r
for(int n = 0; n < 32 && muxer_.size() < 2; ++n)\r
decode_frame(0);\r
}\r
-\r
- ~ffmpeg_producer()\r
- {\r
- try\r
- {\r
- tasks_.cancel();\r
- tasks_.wait();\r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- }\r
- }\r
- \r
+ \r
virtual safe_ptr<core::basic_frame> receive(int hints)\r
{\r
+ if(eof_)\r
+ return last_frame();\r
+\r
auto frame = core::basic_frame::late();\r
\r
frame_timer_.restart();\r
else\r
{\r
if(input_.eof())\r
+ {\r
+ eof_ = true;\r
return last_frame();\r
+ }\r
else\r
{\r
graph_->add_tag("underflow"); \r
\r
void decode_frame(int hints)\r
{\r
- tasks_.wait();\r
-\r
- muxer_.commit();\r
-\r
for(int n = 0; n < 16 && ((!muxer_.video_ready() && !video_decoder_.ready()) || (!muxer_.audio_ready() && !audio_decoder_.ready())); ++n) \r
{\r
std::shared_ptr<AVPacket> pkt;\r
}\r
}\r
\r
- if(!muxer_.video_ready())\r
+ tbb::parallel_invoke(\r
+ [&]\r
{\r
- tasks_.run([=]\r
+ if(!muxer_.video_ready())\r
{\r
video_timer_.restart();\r
\r
muxer_.push(video, hints); \r
\r
graph_->update_value("video-time", static_cast<float>(video_timer_.elapsed()*format_desc_.fps*0.5));\r
- });\r
- } \r
-\r
- if(!muxer_.audio_ready())\r
+ }\r
+ },\r
+ [&]\r
{\r
- tasks_.run([=]\r
+ if(!muxer_.audio_ready())\r
{\r
audio_timer_.restart();\r
\r
muxer_.push(audio); \r
\r
graph_->update_value("audio-time", static_cast<float>(audio_timer_.elapsed()*format_desc_.fps*0.5));\r
- }); \r
- }\r
+ }\r
+ });\r
+\r
+ muxer_.commit();\r
}\r
\r
virtual int64_t nb_frames() const \r
namespace caspar {\r
\r
static const size_t MAX_BUFFER_COUNT = 128;\r
-static const size_t MAX_BUFFER_SIZE = 32 * 1000000;\r
+static const size_t MAX_BUFFER_SIZE = 16 * 1000000;\r
\r
struct input::implementation : boost::noncopyable\r
{ \r
\r
format_context_.reset(weak_format_context_, av_close_input_file);\r
\r
- //av_dump_format(weak_format_context_, 0, narrow(filename).c_str(), 0);\r
+ av_dump_format(weak_format_context_, 0, narrow(filename).c_str(), 0);\r
\r
THROW_ON_ERROR2(avformat_find_stream_info(format_context_.get(), nullptr), print());\r
\r
\r
if(loop_)\r
{\r
- seek_frame(start_, AVSEEK_FLAG_BACKWARD);\r
+ int flags = AVSEEK_FLAG_BACKWARD;\r
+\r
+ int vid_stream_index = av_find_best_stream(format_context_.get(), AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);\r
+ if(vid_stream_index >= 0)\r
+ {\r
+ auto codec_id = format_context_->streams[vid_stream_index]->codec->codec_id;\r
+ if(codec_id == CODEC_ID_VP6A || codec_id == CODEC_ID_VP6F || codec_id == CODEC_ID_VP6)\r
+ flags |= AVSEEK_FLAG_BYTE;\r
+ }\r
+\r
+ seek_frame(start_, flags);\r
graph_->add_tag("seek"); \r
CASPAR_LOG(trace) << print() << " Looping."; \r
} \r
\r
codec_context_.reset(context->streams[index_]->codec, tbb_avcodec_close);\r
\r
+ CASPAR_LOG(debug) << "[video_decoder] " << context->streams[index_]->codec->codec->long_name;\r
+\r
// Some files give an invalid time_base numerator, try to fix it.\r
if(codec_context_ && codec_context_->time_base.num == 1)\r
codec_context_->time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(codec_context_->time_base.den)))-1)); \r
<graphs>true</graphs>\r
</diagnostics>\r
<consumers>\r
- <buffer-depth>3</buffer-depth>\r
+ <buffer-depth>6</buffer-depth>\r
</consumers>\r
<producers>\r
+ <buffer-depth>2</buffer-depth>\r
<auto-transcode>true</auto-transcode>\r
<template-hosts>\r
<template-host>\r
<width>1280</width>\r
<height>720</height>\r
</template-host>\r
+ <template-host>\r
+ <video-mode>1080i5000</video-mode>\r
+ <filename>cg.fth.18</filename>\r
+ <width>1280</width>\r
+ <height>720</height>\r
+ </template-host>\r
<template-host>\r
<video-mode>PAL</video-mode>\r
<filename>cg.fth.18</filename>\r
<consumers>\r
<decklink>\r
<device>1</device>\r
- <embedded-audio>true</embedded-audio>\r
<low-latency>true</low-latency>\r
+ <embedded-audio>true</embedded-audio>\r
</decklink>\r
- <screen>\r
- <device>1</device>\r
- </screen>\r
</consumers>\r
</channel>\r
<channel>\r
<consumers>\r
<decklink>\r
<device>2</device>\r
- <embedded-audio>true</embedded-audio>\r
<low-latency>true</low-latency>\r
+ <embedded-audio>true</embedded-audio>\r
</decklink>\r
</consumers>\r
</channel>\r
wcmd = L"CG 1-2 ADD 1 BBTELEFONARE 1";\r
else if(wcmd.substr(0, 1) == L"4")\r
wcmd = L"PLAY 1-1 DV FILTER yadif=1:-1 LOOP";\r
+ else if(wcmd.substr(0, 1) == L"5")\r
+ {\r
+ auto file = wcmd.substr(2, wcmd.length()-1);\r
+ wcmd = L"PLAY 1-1 " + file + L" LOOP\r\n" \r
+ L"PLAY 1-2 " + file + L" LOOP\r\n" \r
+ L"PLAY 1-3 " + file + L" LOOP\r\n"\r
+ L"PLAY 2-1 " + file + L" LOOP\r\n" \r
+ L"PLAY 2-2 " + file + L" LOOP\r\n" \r
+ L"PLAY 2-3 " + file + L" LOOP\r\n";\r
+ }\r
else if(wcmd.substr(0, 1) == L"X")\r
{\r
int num = 0;\r