]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2: Added only_key support to all consumers.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 18 May 2011 22:25:11 +0000 (22:25 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 18 May 2011 22:25:11 +0000 (22:25 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@782 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

14 files changed:
core/consumer/frame_consumer.h
core/consumer/frame_consumer_device.cpp
modules/bluefish/consumer/bluefish_consumer.cpp
modules/decklink/consumer/decklink_consumer.cpp
modules/decklink/interop/DeckLinkAPI_h.h
modules/decklink/interop/DeckLinkAPI_i.c
modules/ffmpeg/consumer/ffmpeg_consumer.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.h
modules/ffmpeg/ffmpeg.cpp
modules/ffmpeg/producer/input.cpp
modules/ogl/consumer/ogl_consumer.cpp
modules/ogl/consumer/ogl_consumer.h
shell/caspar.config
shell/server.cpp

index 02e504dc967fac8ab04e22c8e7e4216d18e0c15f..cc972b3fc06f4fe9e8173938e6d1dc5be674ed5d 100644 (file)
@@ -38,6 +38,7 @@ struct frame_consumer : boost::noncopyable
        \r
        virtual void send(const safe_ptr<const read_frame>& frame) = 0;\r
        virtual size_t buffer_depth() const {return 1;}\r
+       virtual bool key_only() const{ return false;}\r
        virtual void initialize(const video_format_desc& format_desc) = 0;\r
        virtual std::wstring print() const = 0;\r
 \r
index 3a1dcbc1e54698afeddaba050378fbd313e826b1..b32b3a771e2f6e6ec2ff82e2aea4935c773e343f 100644 (file)
 #include "frame_consumer_device.h"\r
 \r
 #include "../video_format.h"\r
+#include "../mixer/gpu/ogl_device.h"\r
+#include "../mixer/read_frame.h"\r
 \r
 #include <common/concurrency/executor.h>\r
 #include <common/diagnostics/graph.h>\r
 #include <common/utility/assert.h>\r
+#include <common/memory/memshfl.h>\r
 \r
 #include <boost/range/algorithm_ext/erase.hpp>\r
 #include <boost/range/algorithm.hpp>\r
 #include <boost/circular_buffer.hpp>\r
 #include <boost/timer.hpp>\r
+#include <boost/range/algorithm.hpp>\r
 \r
 namespace caspar { namespace core {\r
        \r
 struct frame_consumer_device::implementation\r
 {      \r
-       boost::circular_buffer<safe_ptr<const read_frame>> buffer_;\r
+       boost::circular_buffer<std::pair<safe_ptr<const read_frame>,safe_ptr<const read_frame>>> buffer_;\r
 \r
        std::map<int, std::shared_ptr<frame_consumer>> consumers_; // Valid iterators after erase\r
        \r
@@ -100,18 +104,31 @@ public:
                {\r
                        diag_->set_value("input-buffer", static_cast<float>(executor_.size())/static_cast<float>(executor_.capacity()));\r
                        frame_timer_.restart();\r
+                       \r
+                       auto key_frame = read_frame::empty();\r
+\r
+                       if(boost::range::find_if(consumers_, [](const decltype(*consumers_.begin())& p){return p.second->key_only();}) != consumers_.end())\r
+                       {\r
+                               // Currently do key_only transform on cpu. Unsure if the extra 400MB/s (1080p50) overhead is worth it to do it on gpu.\r
+                               auto key_data = ogl_device::create_host_buffer(frame->image_data().size(), host_buffer::write_only);                            \r
+                               fast_memsfhl(key_data->data(), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
+                               std::vector<short> audio_data(frame->audio_data().begin(), frame->audio_data().end());\r
+                               key_frame = make_safe<const read_frame>(std::move(key_data), std::move(audio_data));\r
+                       }\r
 \r
-                       buffer_.push_back(std::move(frame));\r
+                       buffer_.push_back(std::make_pair(std::move(frame), std::move(key_frame)));\r
 \r
                        if(!buffer_.full())\r
                                return;\r
+\r
        \r
                        auto it = consumers_.begin();\r
                        while(it != consumers_.end())\r
                        {\r
                                try\r
                                {\r
-                                       it->second->send(buffer_[it->second->buffer_depth()-1]);\r
+                                       auto p = buffer_[it->second->buffer_depth()-1];\r
+                                       it->second->send(it->second->key_only() ? p.second : p.first);\r
                                        ++it;\r
                                }\r
                                catch(...)\r
index 51c551bf904af967c04b28232ff4b19e5bba30b1..f0bb889a40545b17164232c51f899b1097833b3b 100644 (file)
@@ -357,11 +357,13 @@ struct bluefish_consumer_proxy : public core::frame_consumer
        std::unique_ptr<bluefish_consumer> consumer_;\r
        const size_t device_index_;\r
        const bool embedded_audio_;\r
+       bool key_only_;\r
 public:\r
 \r
-       bluefish_consumer_proxy(size_t device_index, bool embedded_audio)\r
+       bluefish_consumer_proxy(size_t device_index, bool embedded_audio, bool key_only)\r
                : device_index_(device_index)\r
-               , embedded_audio_(embedded_audio){}\r
+               , embedded_audio_(embedded_audio)\r
+               , key_only_(key_only){}\r
        \r
        virtual void initialize(const core::video_format_desc& format_desc)\r
        {\r
@@ -377,6 +379,11 @@ public:
        {\r
                return consumer_->print();\r
        }\r
+\r
+       virtual bool key_only() const\r
+       {\r
+               return key_only_;\r
+       }\r
 };     \r
 \r
 std::wstring get_bluefish_version()\r
@@ -427,16 +434,18 @@ safe_ptr<core::frame_consumer> create_bluefish_consumer(const std::vector<std::w
                device_index = lexical_cast_or_default<int>(params[1], 1);\r
 \r
        bool embedded_audio = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end();\r
+       bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
 \r
-       return make_safe<bluefish_consumer_proxy>(device_index, embedded_audio);\r
+       return make_safe<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);\r
 }\r
 \r
 safe_ptr<core::frame_consumer> create_bluefish_consumer(const boost::property_tree::ptree& ptree) \r
 {      \r
        auto device_index = ptree.get("device", 0);\r
        auto embedded_audio  = ptree.get("embedded-audio", false);\r
+       bool key_only = (ptree.get("output", "fill_and_key") == "key_only");\r
 \r
-       return make_safe<bluefish_consumer_proxy>(device_index, embedded_audio);\r
+       return make_safe<bluefish_consumer_proxy>(device_index, embedded_audio, key_only);\r
 }\r
 \r
 }
\ No newline at end of file
index 42f92c6e48c3c2f28df8d707baf15d32f4ecad69..89d8175932f3563e04be3f2c5f32d2da66dbe673 100644 (file)
@@ -110,25 +110,6 @@ public:
     STDMETHOD(GetAncillaryData(IDeckLinkVideoFrameAncillary** ancillary))                {return S_FALSE;}\r
 };\r
 \r
-std::shared_ptr<IDeckLinkVideoFrame> make_alpha_only_frame(const CComQIPtr<IDeckLinkOutput>& decklink, const safe_ptr<const core::read_frame>& frame, const core::video_format_desc& format_desc)\r
-{\r
-       if(static_cast<size_t>(frame->image_data().size()) != format_desc.size)\r
-               return std::make_shared<decklink_frame_adapter>(frame, format_desc);\r
-\r
-       IDeckLinkMutableVideoFrame* result;\r
-\r
-       if(FAILED(decklink->CreateVideoFrame(format_desc.width, format_desc.height, format_desc.size/format_desc.height, bmdFormat8BitBGRA, bmdFrameFlagDefault, &result)))\r
-               BOOST_THROW_EXCEPTION(caspar_exception());\r
-\r
-       void* bytes = nullptr;\r
-       if(FAILED(result->GetBytes(&bytes)))\r
-               BOOST_THROW_EXCEPTION(caspar_exception());\r
-                       \r
-       fast_memsfhl(reinterpret_cast<unsigned char*>(bytes), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
-\r
-       return std::shared_ptr<IDeckLinkVideoFrame>(result, [](IDeckLinkMutableVideoFrame* p) {p->Release();});\r
-}\r
-\r
 struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
 {              \r
        const configuration config_;\r
@@ -367,13 +348,7 @@ public:
                        \r
        void schedule_next_video(const safe_ptr<const core::read_frame>& frame)\r
        {\r
-               std::shared_ptr<IDeckLinkVideoFrame> deck_frame;\r
-               if(config_.output == key_only)\r
-                       deck_frame = make_alpha_only_frame(output_, frame, format_desc_);\r
-               else \r
-                       deck_frame = std::make_shared<decklink_frame_adapter>(frame, format_desc_);\r
-\r
-               frame_container_.push_back(deck_frame);\r
+               frame_container_.push_back(std::make_shared<decklink_frame_adapter>(frame, format_desc_));\r
                if(FAILED(output_->ScheduleVideoFrame(frame_container_.back().get(), (frames_scheduled_++) * format_desc_.duration, format_desc_.duration, format_desc_.time_scale)))\r
                        CASPAR_LOG(error) << print() << L" Failed to schedule video.";\r
 \r
@@ -425,6 +400,11 @@ public:
        {\r
                return context_->print();\r
        }\r
+\r
+       virtual bool key_only() const\r
+       {\r
+               return (config_.output == caspar::key_only);\r
+       }\r
 };     \r
 \r
 safe_ptr<core::frame_consumer> create_decklink_consumer(const std::vector<std::wstring>& params) \r
@@ -448,6 +428,7 @@ safe_ptr<core::frame_consumer> create_decklink_consumer(const std::vector<std::w
                config.latency = normal_latency;\r
                \r
        config.embedded_audio = std::find(params.begin(), params.end(), L"EMBEDDED_AUDIO") != params.end();\r
+       config.output = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end() ? key_only : fill_and_key;\r
 \r
        return make_safe<decklink_consumer_proxy>(config);\r
 }\r
index 4707a945ceff19bdac62c043528c4bcf0147793b..5d4c2fa7a15dfd8aa7b4b318544531db2d45c9af 100644 (file)
@@ -4,7 +4,7 @@
 \r
 \r
  /* File created by MIDL compiler version 7.00.0555 */\r
-/* at Wed May 18 20:18:19 2011\r
+/* at Wed May 18 23:30:51 2011\r
  */\r
 /* Compiler settings for interop\DeckLinkAPI.idl:\r
     Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 \r
index 529abda234127f293eec48295be0d2c447ae7755..71e2e0f8bb275903da5f9cda83cf1b464c22132c 100644 (file)
@@ -6,7 +6,7 @@
 \r
 \r
  /* File created by MIDL compiler version 7.00.0555 */\r
-/* at Wed May 18 20:18:19 2011\r
+/* at Wed May 18 23:30:51 2011\r
  */\r
 /* Compiler settings for interop\DeckLinkAPI.idl:\r
     Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555 \r
index 954b0d0309ed18588957e4cc94bcc6aa1d428b10..2bf4444557b1cb2269d4a67acabe40464c3f20b4 100644 (file)
@@ -52,7 +52,7 @@ extern "C"
 \r
 namespace caspar { \r
        \r
-struct ffmpeg_consumer::implementation : boost::noncopyable\r
+struct ffmpeg_consumer : boost::noncopyable\r
 {              \r
        std::string filename_;\r
 \r
@@ -77,7 +77,7 @@ struct ffmpeg_consumer::implementation : boost::noncopyable
 \r
        executor executor_;\r
 public:\r
-       implementation(const std::string& filename)\r
+       ffmpeg_consumer(const std::string& filename, const core::video_format_desc& format_desc)\r
                : filename_(filename)\r
                , audio_st_(nullptr)\r
                , video_st_(nullptr)\r
@@ -85,44 +85,15 @@ public:
                , img_convert_ctx_(nullptr)\r
                , video_outbuf_(1920*1080*4)\r
                , audio_outbuf_(48000)\r
-               , executor_(L"ffmpeg_consumer")\r
-       {}\r
-\r
-       ~implementation()\r
-       {    \r
-               executor_.invoke([]{});\r
-               executor_.stop();\r
-\r
-               av_write_trailer(oc_.get());\r
-\r
-               // Close each codec.\r
-               if (video_st_)          \r
-                       avcodec_close(video_st_->codec);\r
-               \r
-               if (audio_st_)\r
-                       avcodec_close(audio_st_->codec);\r
-                               \r
-               // Free the streams.\r
-               for(size_t i = 0; i < oc_->nb_streams; ++i) \r
-               {\r
-                       av_freep(&oc_->streams[i]->codec);\r
-                       av_freep(&oc_->streams[i]);\r
-               }\r
-\r
-               if (!(fmt_->flags & AVFMT_NOFILE)) \r
-                       url_fclose(oc_->pb); // Close the output ffmpeg.\r
-       }\r
-\r
-       void initialize(const core::video_format_desc& format_desc)\r
+               , format_desc_(format_desc)\r
+               , executor_(L"ffmpeg_consumer", true)\r
        {\r
-               format_desc_ = format_desc;\r
-               executor_.start();\r
                active_ = executor_.begin_invoke([]{});\r
 \r
                fmt_ = av_guess_format(nullptr, filename_.c_str(), nullptr);\r
                if (!fmt_) \r
                {\r
-                       CASPAR_LOG(warning) << "Could not deduce output format from ffmpeg extension: using MPEG.";\r
+                       CASPAR_LOG(info) << "Could not deduce output format from ffmpeg extension: using MPEG.";\r
                        fmt_ = av_guess_format("mpeg", nullptr, nullptr);\r
                        filename_ = filename_ + ".avi"; \r
                }\r
@@ -189,9 +160,34 @@ public:
                \r
                av_write_header(oc_.get()); // write the stream header, if any \r
 \r
-               CASPAR_LOG(info) << print() << L" Successfully initialized.";\r
+               CASPAR_LOG(info) << print() << L" Successfully initialized.";   \r
        }\r
-       \r
+\r
+       ~ffmpeg_consumer()\r
+       {    \r
+               executor_.invoke([]{});\r
+               executor_.stop();\r
+\r
+               av_write_trailer(oc_.get());\r
+\r
+               // Close each codec.\r
+               if (video_st_)          \r
+                       avcodec_close(video_st_->codec);\r
+               \r
+               if (audio_st_)\r
+                       avcodec_close(audio_st_->codec);\r
+                               \r
+               // Free the streams.\r
+               for(size_t i = 0; i < oc_->nb_streams; ++i) \r
+               {\r
+                       av_freep(&oc_->streams[i]->codec);\r
+                       av_freep(&oc_->streams[i]);\r
+               }\r
+\r
+               if (!(fmt_->flags & AVFMT_NOFILE)) \r
+                       url_fclose(oc_->pb); // Close the output ffmpeg.\r
+       }\r
+               \r
        std::wstring print() const\r
        {\r
                return L"ffmpeg[" + widen(filename_) + L"]";\r
@@ -242,6 +238,9 @@ public:
   \r
        void encode_video_frame(const safe_ptr<const core::read_frame>& frame)\r
        { \r
+               if(!video_st_)\r
+                       return;\r
+\r
                AVCodecContext* c = video_st_->codec;\r
  \r
                if (img_convert_ctx_ == nullptr) \r
@@ -345,7 +344,10 @@ public:
        }\r
 \r
        bool encode_audio_packet()\r
-       {                               \r
+       {               \r
+               if(!audio_st_)\r
+                       return false;\r
+\r
                auto c = audio_st_->codec;\r
 \r
                auto frame_bytes = c->frame_size * 2 * 2; // samples per frame * 2 channels * 2 bytes per sample\r
@@ -395,17 +397,39 @@ public:
        size_t buffer_depth() const { return 1; }\r
 };\r
 \r
-ffmpeg_consumer::ffmpeg_consumer(const std::wstring& filename) : impl_(new implementation(narrow(filename))){}\r
-ffmpeg_consumer::ffmpeg_consumer(ffmpeg_consumer&& other) : impl_(std::move(other.impl_)){}\r
-void ffmpeg_consumer::send(const safe_ptr<const core::read_frame>& frame){impl_->send(frame);}\r
-size_t ffmpeg_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
-void ffmpeg_consumer::initialize(const core::video_format_desc& format_desc)\r
+struct ffmpeg_consumer_proxy : public core::frame_consumer\r
 {\r
-       // TODO: Ugly\r
-       impl_.reset(new implementation(impl_->filename_));\r
-       impl_->initialize(format_desc);\r
-}\r
-std::wstring ffmpeg_consumer::print() const {return impl_->print();}\r
+       const std::wstring filename_;\r
+       const bool key_only_;\r
+\r
+       std::unique_ptr<ffmpeg_consumer> consumer_;\r
+\r
+public:\r
+\r
+       ffmpeg_consumer_proxy(const std::wstring& filename, bool key_only)\r
+               : filename_(filename)\r
+               , key_only_(key_only){}\r
+       \r
+       virtual void initialize(const core::video_format_desc& format_desc)\r
+       {\r
+               consumer_.reset(new ffmpeg_consumer(narrow(filename_), format_desc));\r
+       }\r
+       \r
+       virtual void send(const safe_ptr<const core::read_frame>& frame)\r
+       {\r
+               consumer_->send(frame);\r
+       }\r
+       \r
+       virtual std::wstring print() const\r
+       {\r
+               return consumer_->print();\r
+       }\r
+\r
+       virtual bool key_only() const\r
+       {\r
+               return key_only_;\r
+       }\r
+};     \r
 \r
 safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params)\r
 {\r
@@ -414,7 +438,17 @@ safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const std::vector<std::wst
        \r
        // TODO: Ask stakeholders about case where file already exists.\r
        boost::filesystem::remove(boost::filesystem::wpath(env::media_folder() + params[1])); // Delete the file if it exists\r
-       return make_safe<ffmpeg_consumer>(env::media_folder() + params[1]);\r
+       bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
+\r
+       return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + params[1], key_only);\r
+}\r
+\r
+safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const boost::property_tree::ptree& ptree)\r
+{\r
+       std::string filename = ptree.get<std::string>("filename");\r
+       bool key_only = (ptree.get("output", "fill_and_key") == "key_only");\r
+       \r
+       return make_safe<ffmpeg_consumer_proxy>(env::media_folder() + widen(filename), key_only);\r
 }\r
 \r
 }\r
index 281038da0b8eb43d47aed96bff52858ff7c6a571..decc821a88210a00da6236466c98b614d2333496 100644 (file)
 */\r
 #pragma once\r
 \r
-#include <core/video_format.h>\r
 #include <core/consumer/frame_consumer.h>\r
+#include <core/video_format.h>\r
+\r
+#include <boost/property_tree/ptree.hpp>\r
+\r
+#include <string>\r
+#include <vector>\r
 \r
 namespace caspar { \r
        \r
-class ffmpeg_consumer : public core::frame_consumer\r
-{\r
-public:        \r
-       explicit ffmpeg_consumer(const std::wstring& filename);\r
-       ffmpeg_consumer(ffmpeg_consumer&& other);\r
-       \r
-       virtual void initialize(const core::video_format_desc& format_desc);\r
-       virtual void send(const safe_ptr<const core::read_frame>&);\r
-       virtual size_t buffer_depth() const;\r
-       virtual std::wstring print() const;\r
-private:\r
-       struct implementation;\r
-       std::shared_ptr<implementation> impl_;\r
-};\r
-\r
 safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params);\r
+safe_ptr<core::frame_consumer> create_ffmpeg_consumer(const boost::property_tree::ptree& ptree);\r
 \r
 }
\ No newline at end of file
index 26aec9664b726b36e6f7b8856a5d83f6b5b89944..49f55f78a07d198d45957c756206f938be130f7b 100644 (file)
@@ -46,7 +46,7 @@ void init_ffmpeg()
        av_register_all();\r
        avcodec_init();\r
        \r
-       core::register_consumer_factory(create_ffmpeg_consumer);\r
+       core::register_consumer_factory([](const std::vector<std::wstring>& params){return create_ffmpeg_consumer(params);});\r
        core::register_producer_factory(create_ffmpeg_producer);\r
 }\r
 \r
index 743ad94e4fb976bd45de798e1f99d8b84e81ace6..8e0e0d76c4dedeecf7235566d7972999d60c4abf 100644 (file)
@@ -110,8 +110,8 @@ public:
                                boost::errinfo_api_function("av_find_stream_info") <<\r
                                boost::errinfo_errno(AVUNERROR(errn)));\r
                }\r
-\r
-               video_codec_context_ = open_stream(AVMEDIA_TYPE_VIDEO, video_s_index_);\r
+               \r
+               video_codec_context_ = open_stream(AVMEDIA_TYPE_VIDEO, video_s_index_, 4);\r
                if(!video_codec_context_)\r
                        CASPAR_LOG(warning) << print() << " Could not open any video stream.";\r
                else\r
@@ -122,7 +122,7 @@ public:
                        CASPAR_LOG(warning) << print() << " Could not open any audio stream.";\r
                else\r
                        fix_time_base(audio_codex_context_.get());\r
-\r
+               \r
                if(!video_codec_context_ && !audio_codex_context_)\r
                {       \r
                        BOOST_THROW_EXCEPTION(\r
@@ -131,7 +131,7 @@ public:
                                source_info(narrow(print())) << \r
                                msg_info("No video or audio codec context found."));    \r
                }\r
-\r
+               \r
                if(start_ != 0)                 \r
                        seek_frame(start_);\r
                                        \r
@@ -181,7 +181,7 @@ private:
                        context->time_base.num = static_cast<int>(std::pow(10.0, static_cast<int>(std::log10(static_cast<float>(context->time_base.den)))-1));\r
        }\r
 \r
-       std::shared_ptr<AVCodecContext> open_stream(int codec_type, int& s_index) const\r
+       std::shared_ptr<AVCodecContext> open_stream(int codec_type, int& s_index, int thread_count = -1) const\r
        {               \r
                const auto streams = boost::iterator_range<AVStream**>(format_context_->streams, format_context_->streams+format_context_->nb_streams);\r
                const auto stream = boost::find_if(streams, [&](AVStream* stream) \r
index a5ad15a6f47a862bd5117a413b65bb3b7320e036..76019197677c76ced6fe134bcd65ccca7ae6de2b 100644 (file)
 #include <array>\r
 \r
 namespace caspar {\r
+               \r
+enum stretch\r
+{\r
+       none,\r
+       uniform,\r
+       fill,\r
+       uniform_to_fill\r
+};\r
 \r
 struct ogl_consumer : boost::noncopyable\r
 {              \r
@@ -295,15 +303,17 @@ struct ogl_consumer_proxy : public core::frame_consumer
        size_t screen_index_;\r
        caspar::stretch stretch_;\r
        bool windowed_;\r
+       bool key_only_;\r
 \r
        std::unique_ptr<ogl_consumer> consumer_;\r
 \r
 public:\r
 \r
-       ogl_consumer_proxy(size_t screen_index, stretch stretch, bool windowed)\r
+       ogl_consumer_proxy(size_t screen_index, stretch stretch, bool windowed, bool key_only)\r
                : screen_index_(screen_index)\r
                , stretch_(stretch)\r
-               , windowed_(windowed){}\r
+               , windowed_(windowed)\r
+               , key_only_(key_only){}\r
        \r
        virtual void initialize(const core::video_format_desc& format_desc)\r
        {\r
@@ -319,6 +329,11 @@ public:
        {\r
                return consumer_->print();\r
        }\r
+\r
+       virtual bool key_only() const\r
+       {\r
+               return key_only_;\r
+       }\r
 };     \r
 \r
 safe_ptr<core::frame_consumer> create_ogl_consumer(const std::vector<std::wstring>& params)\r
@@ -336,7 +351,9 @@ safe_ptr<core::frame_consumer> create_ogl_consumer(const std::vector<std::wstrin
        if(params.size() > 2) \r
                windowed = lexical_cast_or_default<bool>(params[3], windowed);\r
 \r
-       return make_safe<ogl_consumer_proxy>(screen_index, stretch, windowed);\r
+       bool key_only = std::find(params.begin(), params.end(), L"KEY_ONLY") != params.end();\r
+\r
+       return make_safe<ogl_consumer_proxy>(screen_index, stretch, windowed, key_only);\r
 }\r
 \r
 safe_ptr<core::frame_consumer> create_ogl_consumer(const boost::property_tree::ptree& ptree) \r
@@ -351,7 +368,9 @@ safe_ptr<core::frame_consumer> create_ogl_consumer(const boost::property_tree::p
        else if(key_str == "uniform_to_fill")\r
                stretch = stretch::uniform_to_fill;\r
 \r
-       return make_safe<ogl_consumer_proxy>(screen_index, stretch, windowed);\r
+       bool key_only = (ptree.get("output", "fill_and_key") == "key_only");\r
+\r
+       return make_safe<ogl_consumer_proxy>(screen_index, stretch, windowed, key_only);\r
 }\r
 \r
 }
\ No newline at end of file
index 94cbcb2541b1ee11a3df61abccdcc9470fb9eba9..6b5ca3a48c0033c131b39f2fc8aa012c06fb5c78 100644 (file)
 #include <boost/property_tree/ptree.hpp>\r
 \r
 namespace caspar {\r
-       \r
-enum stretch\r
-{\r
-       none,\r
-       uniform,\r
-       fill,\r
-       uniform_to_fill\r
-};\r
 \r
 safe_ptr<core::frame_consumer> create_ogl_consumer(const std::vector<std::wstring>& params);\r
 safe_ptr<core::frame_consumer> create_ogl_consumer(const boost::property_tree::ptree& ptree);\r
index 3f37c628865cf7cec4d5c4922db6b412c0dd5186..4d0c84b454424a9783e129a7da75ec93f25e7b65 100644 (file)
@@ -12,7 +12,7 @@
   </diagnostics>\r
   <channels>\r
     <channel>\r
-      <videomode>PAL</videomode>\r
+      <videomode>1080i5000</videomode>\r
       <consumers>\r
         <decklink>\r
           <device>1</device>\r
           <device>1</device>\r
           <stretch>uniform</stretch>\r
           <windowed>true</windowed>\r
+          <output>key_only</output>\r
         </ogl>\r
+        <file>\r
+          <filename>TESTING</filename>\r
+        </file>\r
         <!--<audio/>-->\r
         <!--<bluefish>\r
           <device>1</device>\r
index 145008381913e64ad03229d76506c9b46b357127..747d1adb60ddc4fe28acd0eb5382c657782f013a 100644 (file)
@@ -106,11 +106,13 @@ struct server::implementation : boost::noncopyable
                                        else if(name == "bluefish")                                     \r
                                                channels_.back()->consumer()->add(index++, create_bluefish_consumer(xml_consumer.second));                                      \r
                                        else if(name == "decklink")                                     \r
-                                               channels_.back()->consumer()->add(index++, create_decklink_consumer(xml_consumer.second));                                      \r
+                                               channels_.back()->consumer()->add(index++, create_decklink_consumer(xml_consumer.second));                              \r
+                                       else if(name == "file")                                 \r
+                                               channels_.back()->consumer()->add(index++, create_ffmpeg_consumer(xml_consumer.second));                                                \r
                                        else if(name == "audio")\r
                                                channels_.back()->consumer()->add(index++, oal_consumer());             \r
-                               else\r
-                                       CASPAR_LOG(warning) << "Invalid consumer: " << widen(name);     \r
+                                       else if(name != "<xmlcomment>")\r
+                                               CASPAR_LOG(warning) << "Invalid consumer: " << widen(name);     \r
                                }\r
                                catch(...)\r
                                {\r