X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fproducer%2Fframe_producer.cpp;h=066f7fce618b4764c2b4e39fb6d034adde925be1;hb=a3bcf2e33433f4163bce96dd63c09ce7b1e23d61;hp=d1ffab291489ec2d657d52cd260eca0aae5069c1;hpb=2f5ecd52bbf1aa3615a645ccd358fd212640ef5c;p=casparcg diff --git a/core/producer/frame_producer.cpp b/core/producer/frame_producer.cpp index d1ffab291..066f7fce6 100644 --- a/core/producer/frame_producer.cpp +++ b/core/producer/frame_producer.cpp @@ -1,77 +1,234 @@ /* -* copyright (c) 2010 Sveriges Television AB +* Copyright 2013 Sveriges Television AB http://casparcg.com/ * -* This file is part of CasparCG. +* 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 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 . +* 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 "frame_producer.h" #include "frame/basic_frame.h" +#include "frame/frame_transform.h" + +#include "../parameters/parameters.h" #include "color/color_producer.h" #include "separated/separated_producer.h" #include +#include +#include +#include namespace caspar { namespace core { std::vector g_factories; +std::vector g_thumbnail_factories; + +class destroy_producer_proxy : public frame_producer +{ + std::unique_ptr> producer_; +public: + destroy_producer_proxy(safe_ptr&& producer) + : producer_(new std::shared_ptr(std::move(producer))) + { + } -const safe_ptr& frame_producer::empty() // nothrow + ~destroy_producer_proxy() + { + static auto destroyers = std::make_shared>>(); + static tbb::atomic destroyer_count; + + try + { + std::shared_ptr destroyer; + if(!destroyers->try_pop(destroyer)) + { + destroyer.reset(new executor(L"destroyer")); + destroyer->set_priority_class(below_normal_priority_class); + if(++destroyer_count > 16) + CASPAR_LOG(warning) << L"Potential destroyer dead-lock detected."; + CASPAR_LOG(trace) << "Created destroyer: " << destroyer_count; + } + + auto producer = producer_.release(); + auto pool = destroyers; + destroyer->begin_invoke([=] + { + std::unique_ptr> producer2(producer); + + auto str = (*producer2)->print(); + try + { + if(!producer->unique()) + CASPAR_LOG(trace) << str << L" Not destroyed on asynchronous destruction thread: " << producer->use_count(); + else + CASPAR_LOG(trace) << str << L" Destroying on asynchronous destruction thread."; + } + catch(...){} + + producer2.reset(); + pool->push(destroyer); + }); + } + catch(...) + { + CASPAR_LOG_CURRENT_EXCEPTION(); + try + { + producer_.reset(); + } + catch(...){} + } + } + + virtual safe_ptr receive(int hints) override {return (*producer_)->receive(hints);} + virtual safe_ptr last_frame() const override {return (*producer_)->last_frame();} + virtual safe_ptr create_thumbnail_frame() override {return (*producer_)->create_thumbnail_frame();} + virtual std::wstring print() const override {return (*producer_)->print();} + virtual boost::property_tree::wptree info() const override {return (*producer_)->info();} + virtual boost::unique_future call(const std::wstring& str) override {return (*producer_)->call(str);} + virtual safe_ptr get_following_producer() const override {return (*producer_)->get_following_producer();} + virtual void set_leading_producer(const safe_ptr& producer) override {(*producer_)->set_leading_producer(producer);} + virtual uint32_t nb_frames() const override {return (*producer_)->nb_frames();} + virtual monitor::source& monitor_output() {return (*producer_)->monitor_output();} +}; + +safe_ptr create_producer_destroy_proxy(safe_ptr producer) { - struct empty_frame_producer : public frame_producer - { - virtual safe_ptr receive(){return basic_frame::empty();} - virtual void set_frame_factory(const safe_ptr&){} - virtual std::wstring print() const { return L"empty";} - }; - static safe_ptr producer = make_safe(); - return producer; -} + return make_safe(std::move(producer)); +} -safe_ptr receive_and_follow(safe_ptr& producer) +class print_producer_proxy : public frame_producer { - if(producer == frame_producer::empty()) - return basic_frame::eof(); + std::shared_ptr producer_; +public: + print_producer_proxy(safe_ptr&& producer) + : producer_(std::move(producer)) + { + CASPAR_LOG(info) << producer_->print() << L" Initialized."; + } - auto frame = basic_frame::eof(); - try + ~print_producer_proxy() + { + auto str = producer_->print(); + CASPAR_LOG(trace) << str << L" Uninitializing."; + producer_.reset(); + CASPAR_LOG(info) << str << L" Uninitialized."; + } + + virtual safe_ptr receive(int hints) override {return (producer_)->receive(hints);} + virtual safe_ptr last_frame() const override {return (producer_)->last_frame();} + virtual safe_ptr create_thumbnail_frame() override {return (producer_)->create_thumbnail_frame();} + virtual std::wstring print() const override {return (producer_)->print();} + virtual boost::property_tree::wptree info() const override {return (producer_)->info();} + virtual boost::unique_future call(const std::wstring& str) override {return (producer_)->call(str);} + virtual safe_ptr get_following_producer() const override {return (producer_)->get_following_producer();} + virtual void set_leading_producer(const safe_ptr& producer) override {(producer_)->set_leading_producer(producer);} + virtual uint32_t nb_frames() const override {return (producer_)->nb_frames();} + virtual monitor::source& monitor_output() {return (producer_)->monitor_output();} +}; + +safe_ptr create_producer_print_proxy(safe_ptr producer) +{ + return make_safe(std::move(producer)); +} + +class last_frame_producer : public frame_producer +{ + const std::wstring print_; + const safe_ptr frame_; + const uint32_t nb_frames_; +public: + last_frame_producer(const safe_ptr& producer) + : print_(producer->print()) + , frame_(producer->last_frame() != basic_frame::eof() ? producer->last_frame() : basic_frame::empty()) + , nb_frames_(producer->nb_frames()) { - frame = producer->receive(); } - catch(...) + + virtual safe_ptr receive(int){return frame_;} + virtual safe_ptr last_frame() const{return frame_;} + virtual safe_ptr create_thumbnail_frame() {return frame_;} + virtual std::wstring print() const{return L"dummy[" + print_ + L"]";} + virtual uint32_t nb_frames() const {return nb_frames_;} + virtual boost::property_tree::wptree info() const override { - try - { - // Producer will be removed since frame == basic_frame::eof. - CASPAR_LOG_CURRENT_EXCEPTION(); - CASPAR_LOG(warning) << producer->print() << " Failed to receive frame. Removing producer."; - } - catch(...){} + boost::property_tree::wptree info; + info.add(L"type", L"last-frame-producer"); + return info; + } + virtual monitor::source& monitor_output() + { + static monitor::subject monitor_subject(""); + return monitor_subject; + } +}; + +struct empty_frame_producer : public frame_producer +{ + virtual safe_ptr receive(int){return basic_frame::empty();} + virtual safe_ptr last_frame() const{return basic_frame::empty();} + virtual void set_frame_factory(const safe_ptr&){} + virtual uint32_t nb_frames() const {return 0;} + virtual std::wstring print() const { return L"empty";} + + virtual boost::property_tree::wptree info() const override + { + boost::property_tree::wptree info; + info.add(L"type", L"empty-producer"); + return info; + } + + virtual monitor::source& monitor_output() + { + static monitor::subject monitor_subject(""); + return monitor_subject; } +}; +const safe_ptr& frame_producer::empty() // nothrow +{ + static safe_ptr producer = make_safe(); + return producer; +} + +safe_ptr frame_producer::create_thumbnail_frame() +{ + return basic_frame::empty(); +} + +safe_ptr receive_and_follow(safe_ptr& producer, int hints) +{ + auto frame = producer->receive(hints); if(frame == basic_frame::eof()) { + CASPAR_LOG(info) << producer->print() << " End Of File."; auto following = producer->get_following_producer(); - following->set_leading_producer(producer); - producer = std::move(following); + if(following != frame_producer::empty()) + { + following->set_leading_producer(producer); + producer = std::move(following); + } + else + producer = make_safe(producer); - return receive_and_follow(producer); + return receive_and_follow(producer, hints); } return frame; } @@ -81,13 +238,18 @@ void register_producer_factory(const producer_factory_t& factory) g_factories.push_back(factory); } -safe_ptr do_create_producer(const safe_ptr& my_frame_factory, const std::vector& params) +void register_thumbnail_producer_factory(const producer_factory_t& factory) +{ + g_thumbnail_factories.push_back(factory); +} + +safe_ptr do_create_producer(const safe_ptr& my_frame_factory, const core::parameters& params, const std::vector& factories, bool throw_on_fail = false) { if(params.empty()) BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info("")); auto producer = frame_producer::empty(); - std::any_of(g_factories.begin(), g_factories.end(), [&](const producer_factory_t& factory) -> bool + std::any_of(factories.begin(), factories.end(), [&](const producer_factory_t& factory) -> bool { try { @@ -95,41 +257,98 @@ safe_ptr do_create_producer(const safe_ptr& } catch(...) { - CASPAR_LOG_CURRENT_EXCEPTION(); + if (throw_on_fail) + throw; + else + CASPAR_LOG_CURRENT_EXCEPTION(); } return producer != frame_producer::empty(); }); if(producer == frame_producer::empty()) producer = create_color_producer(my_frame_factory, params); - - if(producer == frame_producer::empty()) - BOOST_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax.")); - return producer; } - -safe_ptr create_producer(const safe_ptr& my_frame_factory, const std::vector& params) +safe_ptr create_producer(const safe_ptr& my_frame_factory, const core::parameters& params) { - auto producer = do_create_producer(my_frame_factory, params); + auto producer = do_create_producer(my_frame_factory, params, g_factories); auto key_producer = frame_producer::empty(); + std::wstring resource_name = L""; + auto tokens = parameters::protocol_split(params.at_original(0)); + if (tokens[0].empty()) + { + resource_name = params.at_original(0); + } + + if(!resource_name.empty()) { try // to find a key file. { auto params_copy = params; if(params_copy.size() > 0) { - params_copy[0] += L"_A"; - key_producer = do_create_producer(my_frame_factory, params_copy); + auto resource_name = params_copy.at_original(0); + params_copy.set(0, resource_name + L"_A"); + key_producer = do_create_producer(my_frame_factory, params_copy, g_factories); + if(key_producer == frame_producer::empty()) + { + params_copy.set(0, resource_name + L"_ALPHA"); + key_producer = do_create_producer(my_frame_factory, params_copy, g_factories); + } } } catch(...){} + } - if(key_producer != frame_producer::empty()) + if(producer != frame_producer::empty() && key_producer != frame_producer::empty()) return create_separated_producer(producer, key_producer); + + if(producer == frame_producer::empty()) + { + std::wstring str = params.get_original_string(); + BOOST_THROW_EXCEPTION(file_not_found() << msg_info("No match found for supplied commands. Check syntax.") << arg_value_info(narrow(str))); + } + + return producer; +} + +safe_ptr create_thumbnail_producer(const safe_ptr& my_frame_factory, const std::wstring& media_file) +{ + core::parameters params; + params.push_back(media_file); + + auto producer = do_create_producer(my_frame_factory, params, g_thumbnail_factories, true); + auto key_producer = frame_producer::empty(); + + try // to find a key file. + { + auto params_copy = params; + if (params_copy.size() > 0) + { + auto resource_name = params_copy.at_original(0); + params_copy.set(0, resource_name + L"_A"); + key_producer = do_create_producer(my_frame_factory, params_copy, g_thumbnail_factories, true); + if (key_producer == frame_producer::empty()) + { + params_copy.set(0, resource_name + L"_ALPHA"); + key_producer = do_create_producer(my_frame_factory, params_copy, g_thumbnail_factories, true); + } + } + } + catch(...){} + if (producer != frame_producer::empty() && key_producer != frame_producer::empty()) + return create_separated_thumbnail_producer(producer, key_producer); + return producer; } +safe_ptr create_producer(const safe_ptr& factory, const std::wstring& param) +{ + parameters params; + params.push_back(param); + return create_producer(factory, params); +} + }} \ No newline at end of file