From 9bd249256b11caa7912fb7cdbc7710251e8cd6f4 Mon Sep 17 00:00:00 2001 From: ronag Date: Wed, 18 May 2011 22:25:11 +0000 Subject: [PATCH] 2.0.0.2: Added only_key support to all consumers. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@782 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- core/consumer/frame_consumer.h | 1 + core/consumer/frame_consumer_device.cpp | 23 +++- .../bluefish/consumer/bluefish_consumer.cpp | 17 ++- .../decklink/consumer/decklink_consumer.cpp | 33 +---- modules/decklink/interop/DeckLinkAPI_h.h | 2 +- modules/decklink/interop/DeckLinkAPI_i.c | 2 +- modules/ffmpeg/consumer/ffmpeg_consumer.cpp | 130 +++++++++++------- modules/ffmpeg/consumer/ffmpeg_consumer.h | 23 +--- modules/ffmpeg/ffmpeg.cpp | 2 +- modules/ffmpeg/producer/input.cpp | 10 +- modules/ogl/consumer/ogl_consumer.cpp | 27 +++- modules/ogl/consumer/ogl_consumer.h | 8 -- shell/caspar.config | 6 +- shell/server.cpp | 8 +- 14 files changed, 171 insertions(+), 121 deletions(-) diff --git a/core/consumer/frame_consumer.h b/core/consumer/frame_consumer.h index 02e504dc9..cc972b3fc 100644 --- a/core/consumer/frame_consumer.h +++ b/core/consumer/frame_consumer.h @@ -38,6 +38,7 @@ struct frame_consumer : boost::noncopyable virtual void send(const safe_ptr& frame) = 0; virtual size_t buffer_depth() const {return 1;} + virtual bool key_only() const{ return false;} virtual void initialize(const video_format_desc& format_desc) = 0; virtual std::wstring print() const = 0; diff --git a/core/consumer/frame_consumer_device.cpp b/core/consumer/frame_consumer_device.cpp index 3a1dcbc1e..b32b3a771 100644 --- a/core/consumer/frame_consumer_device.cpp +++ b/core/consumer/frame_consumer_device.cpp @@ -26,21 +26,25 @@ #include "frame_consumer_device.h" #include "../video_format.h" +#include "../mixer/gpu/ogl_device.h" +#include "../mixer/read_frame.h" #include #include #include +#include #include #include #include #include +#include namespace caspar { namespace core { struct frame_consumer_device::implementation { - boost::circular_buffer> buffer_; + boost::circular_buffer,safe_ptr>> buffer_; std::map> consumers_; // Valid iterators after erase @@ -100,18 +104,31 @@ public: { diag_->set_value("input-buffer", static_cast(executor_.size())/static_cast(executor_.capacity())); frame_timer_.restart(); + + auto key_frame = read_frame::empty(); + + if(boost::range::find_if(consumers_, [](const decltype(*consumers_.begin())& p){return p.second->key_only();}) != consumers_.end()) + { + // Currently do key_only transform on cpu. Unsure if the extra 400MB/s (1080p50) overhead is worth it to do it on gpu. + auto key_data = ogl_device::create_host_buffer(frame->image_data().size(), host_buffer::write_only); + fast_memsfhl(key_data->data(), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303); + std::vector audio_data(frame->audio_data().begin(), frame->audio_data().end()); + key_frame = make_safe(std::move(key_data), std::move(audio_data)); + } - buffer_.push_back(std::move(frame)); + buffer_.push_back(std::make_pair(std::move(frame), std::move(key_frame))); if(!buffer_.full()) return; + auto it = consumers_.begin(); while(it != consumers_.end()) { try { - it->second->send(buffer_[it->second->buffer_depth()-1]); + auto p = buffer_[it->second->buffer_depth()-1]; + it->second->send(it->second->key_only() ? p.second : p.first); ++it; } catch(...) diff --git a/modules/bluefish/consumer/bluefish_consumer.cpp b/modules/bluefish/consumer/bluefish_consumer.cpp index 51c551bf9..f0bb889a4 100644 --- a/modules/bluefish/consumer/bluefish_consumer.cpp +++ b/modules/bluefish/consumer/bluefish_consumer.cpp @@ -357,11 +357,13 @@ struct bluefish_consumer_proxy : public core::frame_consumer std::unique_ptr consumer_; const size_t device_index_; const bool embedded_audio_; + bool key_only_; public: - bluefish_consumer_proxy(size_t device_index, bool embedded_audio) + bluefish_consumer_proxy(size_t device_index, bool embedded_audio, bool key_only) : device_index_(device_index) - , embedded_audio_(embedded_audio){} + , embedded_audio_(embedded_audio) + , key_only_(key_only){} virtual void initialize(const core::video_format_desc& format_desc) { @@ -377,6 +379,11 @@ public: { return consumer_->print(); } + + virtual bool key_only() const + { + return key_only_; + } }; std::wstring get_bluefish_version() @@ -427,16 +434,18 @@ safe_ptr create_bluefish_consumer(const std::vector(params[1], 1); bool embedded_audio = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end(); + bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end(); - return make_safe(device_index, embedded_audio); + return make_safe(device_index, embedded_audio, key_only); } safe_ptr create_bluefish_consumer(const boost::property_tree::ptree& ptree) { auto device_index = ptree.get("device", 0); auto embedded_audio = ptree.get("embedded-audio", false); + bool key_only = (ptree.get("output", "fill_and_key") == "key_only"); - return make_safe(device_index, embedded_audio); + return make_safe(device_index, embedded_audio, key_only); } } \ No newline at end of file diff --git a/modules/decklink/consumer/decklink_consumer.cpp b/modules/decklink/consumer/decklink_consumer.cpp index 42f92c6e4..89d817593 100644 --- a/modules/decklink/consumer/decklink_consumer.cpp +++ b/modules/decklink/consumer/decklink_consumer.cpp @@ -110,25 +110,6 @@ public: STDMETHOD(GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary)) {return S_FALSE;} }; -std::shared_ptr make_alpha_only_frame(const CComQIPtr& decklink, const safe_ptr& frame, const core::video_format_desc& format_desc) -{ - if(static_cast(frame->image_data().size()) != format_desc.size) - return std::make_shared(frame, format_desc); - - IDeckLinkMutableVideoFrame* result; - - if(FAILED(decklink->CreateVideoFrame(format_desc.width, format_desc.height, format_desc.size/format_desc.height, bmdFormat8BitBGRA, bmdFrameFlagDefault, &result))) - BOOST_THROW_EXCEPTION(caspar_exception()); - - void* bytes = nullptr; - if(FAILED(result->GetBytes(&bytes))) - BOOST_THROW_EXCEPTION(caspar_exception()); - - fast_memsfhl(reinterpret_cast(bytes), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303); - - return std::shared_ptr(result, [](IDeckLinkMutableVideoFrame* p) {p->Release();}); -} - struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable { const configuration config_; @@ -367,13 +348,7 @@ public: void schedule_next_video(const safe_ptr& frame) { - std::shared_ptr deck_frame; - if(config_.output == key_only) - deck_frame = make_alpha_only_frame(output_, frame, format_desc_); - else - deck_frame = std::make_shared(frame, format_desc_); - - frame_container_.push_back(deck_frame); + frame_container_.push_back(std::make_shared(frame, format_desc_)); if(FAILED(output_->ScheduleVideoFrame(frame_container_.back().get(), (frames_scheduled_++) * format_desc_.duration, format_desc_.duration, format_desc_.time_scale))) CASPAR_LOG(error) << print() << L" Failed to schedule video."; @@ -425,6 +400,11 @@ public: { return context_->print(); } + + virtual bool key_only() const + { + return (config_.output == caspar::key_only); + } }; safe_ptr create_decklink_consumer(const std::vector& params) @@ -448,6 +428,7 @@ safe_ptr create_decklink_consumer(const std::vector(config); } diff --git a/modules/decklink/interop/DeckLinkAPI_h.h b/modules/decklink/interop/DeckLinkAPI_h.h index 4707a945c..5d4c2fa7a 100644 --- a/modules/decklink/interop/DeckLinkAPI_h.h +++ b/modules/decklink/interop/DeckLinkAPI_h.h @@ -4,7 +4,7 @@ /* File created by MIDL compiler version 7.00.0555 */ -/* at Wed May 18 20:18:19 2011 +/* at Wed May 18 23:30:51 2011 */ /* Compiler settings for interop\DeckLinkAPI.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 diff --git a/modules/decklink/interop/DeckLinkAPI_i.c b/modules/decklink/interop/DeckLinkAPI_i.c index 529abda23..71e2e0f8b 100644 --- a/modules/decklink/interop/DeckLinkAPI_i.c +++ b/modules/decklink/interop/DeckLinkAPI_i.c @@ -6,7 +6,7 @@ /* File created by MIDL compiler version 7.00.0555 */ -/* at Wed May 18 20:18:19 2011 +/* at Wed May 18 23:30:51 2011 */ /* Compiler settings for interop\DeckLinkAPI.idl: Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 diff --git a/modules/ffmpeg/consumer/ffmpeg_consumer.cpp b/modules/ffmpeg/consumer/ffmpeg_consumer.cpp index 954b0d030..2bf444455 100644 --- a/modules/ffmpeg/consumer/ffmpeg_consumer.cpp +++ b/modules/ffmpeg/consumer/ffmpeg_consumer.cpp @@ -52,7 +52,7 @@ extern "C" namespace caspar { -struct ffmpeg_consumer::implementation : boost::noncopyable +struct ffmpeg_consumer : boost::noncopyable { std::string filename_; @@ -77,7 +77,7 @@ struct ffmpeg_consumer::implementation : boost::noncopyable executor executor_; public: - implementation(const std::string& filename) + ffmpeg_consumer(const std::string& filename, const core::video_format_desc& format_desc) : filename_(filename) , audio_st_(nullptr) , video_st_(nullptr) @@ -85,44 +85,15 @@ public: , img_convert_ctx_(nullptr) , video_outbuf_(1920*1080*4) , audio_outbuf_(48000) - , executor_(L"ffmpeg_consumer") - {} - - ~implementation() - { - executor_.invoke([]{}); - executor_.stop(); - - av_write_trailer(oc_.get()); - - // Close each codec. - if (video_st_) - avcodec_close(video_st_->codec); - - if (audio_st_) - avcodec_close(audio_st_->codec); - - // Free the streams. - for(size_t i = 0; i < oc_->nb_streams; ++i) - { - av_freep(&oc_->streams[i]->codec); - av_freep(&oc_->streams[i]); - } - - if (!(fmt_->flags & AVFMT_NOFILE)) - url_fclose(oc_->pb); // Close the output ffmpeg. - } - - void initialize(const core::video_format_desc& format_desc) + , format_desc_(format_desc) + , executor_(L"ffmpeg_consumer", true) { - format_desc_ = format_desc; - executor_.start(); active_ = executor_.begin_invoke([]{}); fmt_ = av_guess_format(nullptr, filename_.c_str(), nullptr); if (!fmt_) { - CASPAR_LOG(warning) << "Could not deduce output format from ffmpeg extension: using MPEG."; + CASPAR_LOG(info) << "Could not deduce output format from ffmpeg extension: using MPEG."; fmt_ = av_guess_format("mpeg", nullptr, nullptr); filename_ = filename_ + ".avi"; } @@ -189,9 +160,34 @@ public: av_write_header(oc_.get()); // write the stream header, if any - CASPAR_LOG(info) << print() << L" Successfully initialized."; + CASPAR_LOG(info) << print() << L" Successfully initialized."; } - + + ~ffmpeg_consumer() + { + executor_.invoke([]{}); + executor_.stop(); + + av_write_trailer(oc_.get()); + + // Close each codec. + if (video_st_) + avcodec_close(video_st_->codec); + + if (audio_st_) + avcodec_close(audio_st_->codec); + + // Free the streams. + for(size_t i = 0; i < oc_->nb_streams; ++i) + { + av_freep(&oc_->streams[i]->codec); + av_freep(&oc_->streams[i]); + } + + if (!(fmt_->flags & AVFMT_NOFILE)) + url_fclose(oc_->pb); // Close the output ffmpeg. + } + std::wstring print() const { return L"ffmpeg[" + widen(filename_) + L"]"; @@ -242,6 +238,9 @@ public: void encode_video_frame(const safe_ptr& frame) { + if(!video_st_) + return; + AVCodecContext* c = video_st_->codec; if (img_convert_ctx_ == nullptr) @@ -345,7 +344,10 @@ public: } bool encode_audio_packet() - { + { + if(!audio_st_) + return false; + auto c = audio_st_->codec; auto frame_bytes = c->frame_size * 2 * 2; // samples per frame * 2 channels * 2 bytes per sample @@ -395,17 +397,39 @@ public: size_t buffer_depth() const { return 1; } }; -ffmpeg_consumer::ffmpeg_consumer(const std::wstring& filename) : impl_(new implementation(narrow(filename))){} -ffmpeg_consumer::ffmpeg_consumer(ffmpeg_consumer&& other) : impl_(std::move(other.impl_)){} -void ffmpeg_consumer::send(const safe_ptr& frame){impl_->send(frame);} -size_t ffmpeg_consumer::buffer_depth() const{return impl_->buffer_depth();} -void ffmpeg_consumer::initialize(const core::video_format_desc& format_desc) +struct ffmpeg_consumer_proxy : public core::frame_consumer { - // TODO: Ugly - impl_.reset(new implementation(impl_->filename_)); - impl_->initialize(format_desc); -} -std::wstring ffmpeg_consumer::print() const {return impl_->print();} + const std::wstring filename_; + const bool key_only_; + + std::unique_ptr consumer_; + +public: + + ffmpeg_consumer_proxy(const std::wstring& filename, bool key_only) + : filename_(filename) + , key_only_(key_only){} + + virtual void initialize(const core::video_format_desc& format_desc) + { + consumer_.reset(new ffmpeg_consumer(narrow(filename_), format_desc)); + } + + virtual void send(const safe_ptr& frame) + { + consumer_->send(frame); + } + + virtual std::wstring print() const + { + return consumer_->print(); + } + + virtual bool key_only() const + { + return key_only_; + } +}; safe_ptr create_ffmpeg_consumer(const std::vector& params) { @@ -414,7 +438,17 @@ safe_ptr create_ffmpeg_consumer(const std::vector(env::media_folder() + params[1]); + bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end(); + + return make_safe(env::media_folder() + params[1], key_only); +} + +safe_ptr create_ffmpeg_consumer(const boost::property_tree::ptree& ptree) +{ + std::string filename = ptree.get("filename"); + bool key_only = (ptree.get("output", "fill_and_key") == "key_only"); + + return make_safe(env::media_folder() + widen(filename), key_only); } } diff --git a/modules/ffmpeg/consumer/ffmpeg_consumer.h b/modules/ffmpeg/consumer/ffmpeg_consumer.h index 281038da0..decc821a8 100644 --- a/modules/ffmpeg/consumer/ffmpeg_consumer.h +++ b/modules/ffmpeg/consumer/ffmpeg_consumer.h @@ -19,26 +19,17 @@ */ #pragma once -#include #include +#include + +#include + +#include +#include namespace caspar { -class ffmpeg_consumer : public core::frame_consumer -{ -public: - explicit ffmpeg_consumer(const std::wstring& filename); - ffmpeg_consumer(ffmpeg_consumer&& other); - - virtual void initialize(const core::video_format_desc& format_desc); - virtual void send(const safe_ptr&); - virtual size_t buffer_depth() const; - virtual std::wstring print() const; -private: - struct implementation; - std::shared_ptr impl_; -}; - safe_ptr create_ffmpeg_consumer(const std::vector& params); +safe_ptr create_ffmpeg_consumer(const boost::property_tree::ptree& ptree); } \ No newline at end of file diff --git a/modules/ffmpeg/ffmpeg.cpp b/modules/ffmpeg/ffmpeg.cpp index 26aec9664..49f55f78a 100644 --- a/modules/ffmpeg/ffmpeg.cpp +++ b/modules/ffmpeg/ffmpeg.cpp @@ -46,7 +46,7 @@ void init_ffmpeg() av_register_all(); avcodec_init(); - core::register_consumer_factory(create_ffmpeg_consumer); + core::register_consumer_factory([](const std::vector& params){return create_ffmpeg_consumer(params);}); core::register_producer_factory(create_ffmpeg_producer); } diff --git a/modules/ffmpeg/producer/input.cpp b/modules/ffmpeg/producer/input.cpp index 743ad94e4..8e0e0d76c 100644 --- a/modules/ffmpeg/producer/input.cpp +++ b/modules/ffmpeg/producer/input.cpp @@ -110,8 +110,8 @@ public: boost::errinfo_api_function("av_find_stream_info") << boost::errinfo_errno(AVUNERROR(errn))); } - - video_codec_context_ = open_stream(AVMEDIA_TYPE_VIDEO, video_s_index_); + + video_codec_context_ = open_stream(AVMEDIA_TYPE_VIDEO, video_s_index_, 4); if(!video_codec_context_) CASPAR_LOG(warning) << print() << " Could not open any video stream."; else @@ -122,7 +122,7 @@ public: CASPAR_LOG(warning) << print() << " Could not open any audio stream."; else fix_time_base(audio_codex_context_.get()); - + if(!video_codec_context_ && !audio_codex_context_) { BOOST_THROW_EXCEPTION( @@ -131,7 +131,7 @@ public: source_info(narrow(print())) << msg_info("No video or audio codec context found.")); } - + if(start_ != 0) seek_frame(start_); @@ -181,7 +181,7 @@ private: context->time_base.num = static_cast(std::pow(10.0, static_cast(std::log10(static_cast(context->time_base.den)))-1)); } - std::shared_ptr open_stream(int codec_type, int& s_index) const + std::shared_ptr open_stream(int codec_type, int& s_index, int thread_count = -1) const { const auto streams = boost::iterator_range(format_context_->streams, format_context_->streams+format_context_->nb_streams); const auto stream = boost::find_if(streams, [&](AVStream* stream) diff --git a/modules/ogl/consumer/ogl_consumer.cpp b/modules/ogl/consumer/ogl_consumer.cpp index a5ad15a6f..760191976 100644 --- a/modules/ogl/consumer/ogl_consumer.cpp +++ b/modules/ogl/consumer/ogl_consumer.cpp @@ -43,6 +43,14 @@ #include namespace caspar { + +enum stretch +{ + none, + uniform, + fill, + uniform_to_fill +}; struct ogl_consumer : boost::noncopyable { @@ -295,15 +303,17 @@ struct ogl_consumer_proxy : public core::frame_consumer size_t screen_index_; caspar::stretch stretch_; bool windowed_; + bool key_only_; std::unique_ptr consumer_; public: - ogl_consumer_proxy(size_t screen_index, stretch stretch, bool windowed) + ogl_consumer_proxy(size_t screen_index, stretch stretch, bool windowed, bool key_only) : screen_index_(screen_index) , stretch_(stretch) - , windowed_(windowed){} + , windowed_(windowed) + , key_only_(key_only){} virtual void initialize(const core::video_format_desc& format_desc) { @@ -319,6 +329,11 @@ public: { return consumer_->print(); } + + virtual bool key_only() const + { + return key_only_; + } }; safe_ptr create_ogl_consumer(const std::vector& params) @@ -336,7 +351,9 @@ safe_ptr create_ogl_consumer(const std::vector 2) windowed = lexical_cast_or_default(params[3], windowed); - return make_safe(screen_index, stretch, windowed); + bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end(); + + return make_safe(screen_index, stretch, windowed, key_only); } safe_ptr create_ogl_consumer(const boost::property_tree::ptree& ptree) @@ -351,7 +368,9 @@ safe_ptr create_ogl_consumer(const boost::property_tree::p else if(key_str == "uniform_to_fill") stretch = stretch::uniform_to_fill; - return make_safe(screen_index, stretch, windowed); + bool key_only = (ptree.get("output", "fill_and_key") == "key_only"); + + return make_safe(screen_index, stretch, windowed, key_only); } } \ No newline at end of file diff --git a/modules/ogl/consumer/ogl_consumer.h b/modules/ogl/consumer/ogl_consumer.h index 94cbcb254..6b5ca3a48 100644 --- a/modules/ogl/consumer/ogl_consumer.h +++ b/modules/ogl/consumer/ogl_consumer.h @@ -26,14 +26,6 @@ #include namespace caspar { - -enum stretch -{ - none, - uniform, - fill, - uniform_to_fill -}; safe_ptr create_ogl_consumer(const std::vector& params); safe_ptr create_ogl_consumer(const boost::property_tree::ptree& ptree); diff --git a/shell/caspar.config b/shell/caspar.config index 3f37c6288..4d0c84b45 100644 --- a/shell/caspar.config +++ b/shell/caspar.config @@ -12,7 +12,7 @@ - PAL + 1080i5000 1 @@ -25,7 +25,11 @@ 1 uniform true + key_only + + TESTING +