X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fmixer%2Fmixer.cpp;h=c5b5e1fb31f71fad85dc306bd3c24080d909dcab;hb=2c415d7ecff14b69d4922bb608d434f0d52e045d;hp=39f2f3a947535796036eb23b84c1fd919e347a33;hpb=b707b045a0d8da56dfdd312fcebffef599bb3fd6;p=casparcg diff --git a/core/mixer/mixer.cpp b/core/mixer/mixer.cpp index 39f2f3a94..c5b5e1fb3 100644 --- a/core/mixer/mixer.cpp +++ b/core/mixer/mixer.cpp @@ -1,159 +1,183 @@ -/* -* 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 "mixer.h" - -#include "read_frame.h" -#include "write_frame.h" - -#include "audio/audio_mixer.h" -#include "image/image_mixer.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace caspar { namespace core { - -struct mixer::impl : boost::noncopyable -{ - safe_ptr target_; - - safe_ptr graph_; - boost::timer mix_timer_; - - video_format_desc format_desc_; - safe_ptr ogl_; - - audio_mixer audio_mixer_; - image_mixer image_mixer_; - - std::unordered_map blend_modes_; - - executor executor_; - -public: - impl(const safe_ptr& target, const safe_ptr& graph, const video_format_desc& format_desc, const safe_ptr& ogl) - : target_(target) - , graph_(graph) - , format_desc_(format_desc) - , ogl_(ogl) - , image_mixer_(ogl) - , audio_mixer_(graph_) - , executor_(L"mixer") - { - graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8)); - } - - void send(const std::pair>, std::shared_ptr>& packet) - { - executor_.begin_invoke([=] - { - try - { - mix_timer_.restart(); - - auto frames = packet.first; - - BOOST_FOREACH(auto& frame, frames) - { - auto blend_it = blend_modes_.find(frame.first); - image_mixer_.begin_layer(blend_it != blend_modes_.end() ? blend_it->second : blend_mode::normal); - - frame.second->accept(audio_mixer_); - frame.second->accept(image_mixer_); - - image_mixer_.end_layer(); - } - - auto image = image_mixer_(format_desc_); - auto audio = audio_mixer_(format_desc_); - - graph_->set_value("mix-time", mix_timer_.elapsed()*format_desc_.fps*0.5); - - target_->send(std::make_pair(make_safe(format_desc_.width, format_desc_.height, std::move(image), std::move(audio)), packet.second)); - } - catch(...) - { - CASPAR_LOG_CURRENT_EXCEPTION(); - } - }); - } - - void set_blend_mode(int index, blend_mode value) - { - executor_.begin_invoke([=] - { - auto it = blend_modes_.find(index); - if(it == blend_modes_.end()) - blend_modes_.insert(std::make_pair(index, value)); - else - it->second = value; - }, high_priority); - } - - void set_video_format_desc(const video_format_desc& format_desc) - { - executor_.begin_invoke([=] - { - format_desc_ = format_desc; - }); - } - - boost::unique_future info() const - { - boost::promise info; - info.set_value(boost::property_tree::wptree()); - return info.get_future(); - } -}; - -mixer::mixer(const safe_ptr& target, const safe_ptr& graph, const video_format_desc& format_desc, const safe_ptr& ogl) - : impl_(new impl(target, graph, format_desc, ogl)){} -void mixer::send(const std::pair>, std::shared_ptr>& frames){ impl_->send(frames);} -void mixer::set_blend_mode(int index, blend_mode value){impl_->set_blend_mode(index, value);} -void mixer::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);} -boost::unique_future mixer::info() const{return impl_->info();} -}} \ 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 "mixer.h" + +#include "../frame/frame.h" + +#include "audio/audio_mixer.h" +#include "image/image_mixer.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +namespace caspar { namespace core { + +struct mixer::impl : boost::noncopyable +{ + int channel_index_; + spl::shared_ptr graph_; + tbb::atomic current_mix_time_; + spl::shared_ptr monitor_subject_ = spl::make_shared("/mixer"); + audio_mixer audio_mixer_ { graph_ }; + spl::shared_ptr image_mixer_; + + bool straighten_alpha_ = false; + + executor executor_ { L"mixer " + boost::lexical_cast(channel_index_) }; + +public: + impl(int channel_index, spl::shared_ptr graph, spl::shared_ptr image_mixer) + : channel_index_(channel_index) + , graph_(std::move(graph)) + , image_mixer_(std::move(image_mixer)) + { + graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8f)); + current_mix_time_ = 0; + audio_mixer_.monitor_output().attach_parent(monitor_subject_); + } + + const_frame operator()(std::map frames, const video_format_desc& format_desc, const core::audio_channel_layout& channel_layout) + { + caspar::timer frame_timer; + + auto frame = executor_.invoke([=]() mutable -> const_frame + { + try + { + CASPAR_SCOPED_CONTEXT_MSG(L" '" + executor_.name() + L"' "); + + detail::set_current_aspect_ratio( + static_cast(format_desc.square_width) + / static_cast(format_desc.square_height)); + + for (auto& frame : frames) + { + frame.second.accept(audio_mixer_); + frame.second.transform().image_transform.layer_depth = 1; + frame.second.accept(*image_mixer_); + } + + auto image = (*image_mixer_)(format_desc, straighten_alpha_); + auto audio = audio_mixer_(format_desc, channel_layout); + + auto desc = core::pixel_format_desc(core::pixel_format::bgra); + desc.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4)); + return const_frame(std::move(image), std::move(audio), this, desc, channel_layout); + } + catch(...) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + return const_frame::empty(); + } + }); + + auto mix_time = frame_timer.elapsed(); + graph_->set_value("mix-time", mix_time * format_desc.fps * 0.5); + current_mix_time_ = static_cast(mix_time * 1000.0); + + return frame; + } + + void set_master_volume(float volume) + { + executor_.begin_invoke([=] + { + audio_mixer_.set_master_volume(volume); + }, task_priority::high_priority); + } + + float get_master_volume() + { + return executor_.invoke([=] + { + return audio_mixer_.get_master_volume(); + }, task_priority::high_priority); + } + + void set_straight_alpha_output(bool value) + { + executor_.begin_invoke([=] + { + straighten_alpha_ = value; + }, task_priority::high_priority); + } + + bool get_straight_alpha_output() + { + return executor_.invoke([=] + { + return straighten_alpha_; + }, task_priority::high_priority); + } + + std::future info() const + { + boost::property_tree::wptree info; + info.add(L"mix-time", current_mix_time_); + + return make_ready_future(std::move(info)); + } + + std::future delay_info() const + { + boost::property_tree::wptree info; + info.put_value(current_mix_time_); + + return make_ready_future(std::move(info)); + } +}; + +mixer::mixer(int channel_index, spl::shared_ptr graph, spl::shared_ptr image_mixer) + : impl_(new impl(channel_index, std::move(graph), std::move(image_mixer))){} +void mixer::set_master_volume(float volume) { impl_->set_master_volume(volume); } +float mixer::get_master_volume() { return impl_->get_master_volume(); } +void mixer::set_straight_alpha_output(bool value) { impl_->set_straight_alpha_output(value); } +bool mixer::get_straight_alpha_output() { return impl_->get_straight_alpha_output(); } +std::future mixer::info() const{return impl_->info();} +std::future mixer::delay_info() const{ return impl_->delay_info(); } +const_frame mixer::operator()(std::map frames, const video_format_desc& format_desc, const core::audio_channel_layout& channel_layout){ return (*impl_)(std::move(frames), format_desc, channel_layout); } +mutable_frame mixer::create_frame(const void* tag, const core::pixel_format_desc& desc, const core::audio_channel_layout& channel_layout) {return impl_->image_mixer_->create_frame(tag, desc, channel_layout);} +monitor::subject& mixer::monitor_output() { return *impl_->monitor_subject_; } +}}