]> git.sesse.net Git - casparcg/commitdiff
2.0.2: auto-deinterlace when using MIXER fill scaling and/or translation.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sun, 4 Dec 2011 09:09:59 +0000 (09:09 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sun, 4 Dec 2011 09:09:59 +0000 (09:09 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.2@1773 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

15 files changed:
core/core.vcxproj
core/mixer/mixer.cpp
core/mixer/mixer.h
core/producer/frame_producer.h
core/producer/layer.cpp
core/producer/layer.h
core/producer/stage.cpp
core/producer/stage.h
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/filter/filter.cpp
modules/ffmpeg/producer/filter/filter.h
modules/ffmpeg/producer/muxer/frame_muxer.cpp
modules/ffmpeg/producer/muxer/frame_muxer.h
protocol/amcp/AMCPCommandsImpl.cpp
shell/casparcg.config

index cc1ca9ca7ed0649f09d0d7c591203fe403988016..01245498532d43fa5d0b1ccd21b922b5d91a908e 100644 (file)
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
     <ClCompile Include="mixer\image\shader\image_shader.cpp">\r
-      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../../StdAfx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
+      <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Develop|Win32'">../../../stdafx.h</PrecompiledHeaderFile>\r
     </ClCompile>\r
     <ClCompile Include="producer\playlist\playlist_producer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">../../stdafx.h</PrecompiledHeaderFile>\r
index 60666264e7d2ef5e92bf3a0bbc1d818a244ba777..dc130e2a89b6ecf31401fbdce9852f9cfdb64af0 100644 (file)
 \r
 namespace caspar { namespace core {\r
                \r
-template<typename T>\r
-class tweened_transform\r
-{\r
-       T source_;\r
-       T dest_;\r
-       int duration_;\r
-       int time_;\r
-       tweener_t tweener_;\r
-public:        \r
-       tweened_transform()\r
-               : duration_(0)\r
-               , time_(0)\r
-               , tweener_(get_tweener(L"linear")){}\r
-       tweened_transform(const T& source, const T& dest, int duration, const std::wstring& tween = L"linear")\r
-               : source_(source)\r
-               , dest_(dest)\r
-               , duration_(duration)\r
-               , time_(0)\r
-               , tweener_(get_tweener(tween)){}\r
-       \r
-       T fetch()\r
-       {\r
-               return time_ == duration_ ? dest_ : tween(static_cast<double>(time_), source_, dest_, static_cast<double>(duration_), tweener_);\r
-       }\r
-\r
-       T fetch_and_tick(int num)\r
-       {                                               \r
-               time_ = std::min(time_+num, duration_);\r
-               return fetch();\r
-       }\r
-};\r
-\r
 struct mixer::implementation : boost::noncopyable\r
 {              \r
        safe_ptr<diagnostics::graph>    graph_;\r
@@ -100,7 +68,6 @@ struct mixer::implementation : boost::noncopyable
        audio_mixer     audio_mixer_;\r
        image_mixer image_mixer_;\r
        \r
-       std::unordered_map<int, tweened_transform<core::frame_transform>> transforms_;  \r
        std::unordered_map<int, blend_mode::type> blend_modes_;\r
                        \r
        executor executor_;\r
@@ -131,19 +98,9 @@ public:
                                {\r
                                        auto blend_it = blend_modes_.find(frame.first);\r
                                        image_mixer_.begin_layer(blend_it != blend_modes_.end() ? blend_it->second : blend_mode::normal);\r
-                               \r
-                                       auto frame1 = make_safe<core::basic_frame>(frame.second);\r
-                                       frame1->get_frame_transform() = transforms_[frame.first].fetch_and_tick(1);\r
-\r
-                                       if(format_desc_.field_mode != core::field_mode::progressive)\r
-                                       {                               \r
-                                               auto frame2 = make_safe<core::basic_frame>(frame.second);\r
-                                               frame2->get_frame_transform() = transforms_[frame.first].fetch_and_tick(1);\r
-                                               frame1 = core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode);\r
-                                       }\r
-                                                                       \r
-                                       frame1->accept(audio_mixer_);                                   \r
-                                       frame1->accept(image_mixer_);\r
+                                                                                                       \r
+                                       frame.second->accept(audio_mixer_);                                     \r
+                                       frame.second->accept(image_mixer_);\r
 \r
                                        image_mixer_.end_layer();\r
                                }\r
@@ -167,45 +124,7 @@ public:
        {               \r
                return make_safe<write_frame>(ogl_, tag, desc);\r
        }\r
-                       \r
-       void set_transform(int index, const frame_transform& transform, unsigned int mix_duration, const std::wstring& tween)\r
-       {\r
-               executor_.begin_invoke([=]\r
-               {\r
-                       auto src = transforms_[index].fetch();\r
-                       auto dst = transform;\r
-                       transforms_[index] = tweened_transform<frame_transform>(src, dst, mix_duration, tween);\r
-               }, high_priority);\r
-       }\r
                                \r
-       void apply_transform(int index, const std::function<frame_transform(frame_transform)>& transform, unsigned int mix_duration, const std::wstring& tween)\r
-       {\r
-               executor_.begin_invoke([=]\r
-               {\r
-                       auto src = transforms_[index].fetch();\r
-                       auto dst = transform(src);\r
-                       transforms_[index] = tweened_transform<frame_transform>(src, dst, mix_duration, tween);\r
-               }, high_priority);\r
-       }\r
-\r
-       void clear_transforms(int index)\r
-       {\r
-               executor_.begin_invoke([=]\r
-               {\r
-                       transforms_.erase(index);\r
-                       blend_modes_.erase(index);\r
-               }, high_priority);\r
-       }\r
-\r
-       void clear_transforms()\r
-       {\r
-               executor_.begin_invoke([=]\r
-               {\r
-                       transforms_.clear();\r
-                       blend_modes_.clear();\r
-               }, high_priority);\r
-       }\r
-               \r
        void set_blend_mode(int index, blend_mode::type value)\r
        {\r
                executor_.begin_invoke([=]\r
@@ -242,11 +161,6 @@ mixer::mixer(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<target_t>
 void mixer::send(const std::pair<std::map<int, safe_ptr<core::basic_frame>>, std::shared_ptr<void>>& frames){ impl_->send(frames);}\r
 core::video_format_desc mixer::get_video_format_desc() const { return impl_->get_video_format_desc(); }\r
 safe_ptr<core::write_frame> mixer::create_frame(const void* tag, const core::pixel_format_desc& desc){ return impl_->create_frame(tag, desc); }                \r
-void mixer::set_frame_transform(int index, const core::frame_transform& transform, unsigned int mix_duration, const std::wstring& tween){impl_->set_transform(index, transform, mix_duration, tween);}\r
-void mixer::apply_frame_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const std::wstring& tween)\r
-{impl_->apply_transform(index, transform, mix_duration, tween);}\r
-void mixer::clear_transforms(int index){impl_->clear_transforms(index);}\r
-void mixer::clear_transforms(){impl_->clear_transforms();}\r
 void mixer::set_blend_mode(int index, blend_mode::type value){impl_->set_blend_mode(index, value);}\r
 void mixer::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
 boost::unique_future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}\r
index f745948465f09ca4c1e046779306ced678a7a95d..c01482527784c02081b934003bab95297ce836a8 100644 (file)
@@ -65,12 +65,7 @@ public:
        \r
        core::video_format_desc get_video_format_desc() const; // nothrow\r
        void set_video_format_desc(const video_format_desc& format_desc);\r
-\r
-       void set_frame_transform(int index, const core::frame_transform& transform, unsigned int mix_duration = 0, const std::wstring& tween = L"linear");\r
-       void apply_frame_transform(int index, const std::function<frame_transform(frame_transform)>& transform, unsigned int mix_duration = 0, const std::wstring& tween = L"linear");\r
-       void clear_transforms(int index);\r
-       void clear_transforms();\r
-\r
+       \r
        void set_blend_mode(int index, blend_mode::type value);\r
 \r
        boost::unique_future<boost::property_tree::wptree> info() const;\r
index 0e7e946e68862d68fafc152e3640b834fc29325b..b1f3aa5568d55b39f6adf36f8ab3b29d6a70bc0c 100644 (file)
@@ -50,7 +50,8 @@ public:
        enum hints\r
        {\r
                NO_HINT = 0,\r
-               ALPHA_HINT = 1\r
+               ALPHA_HINT = 1,\r
+               DEINTERLACE_HINT\r
        };\r
 \r
        virtual ~frame_producer(){}     \r
index 099e84e4c4b555613adc4ff49301521c49a6db21..05beee20beec995cd43bd6fa17bd65a7b334cd37 100644 (file)
@@ -66,7 +66,7 @@ public:
                if(preview) // Play the first frame and pause.\r
                {                       \r
                        play();\r
-                       receive();\r
+                       receive(frame_producer::NO_HINT);\r
                        pause();\r
                }\r
        }\r
@@ -96,14 +96,14 @@ public:
                is_paused_                      = true;\r
        }\r
                \r
-       safe_ptr<basic_frame> receive()\r
+       safe_ptr<basic_frame> receive(int hints)\r
        {               \r
                try\r
                {\r
                        if(is_paused_)\r
                                return disable_audio(foreground_->last_frame());\r
                \r
-                       auto frame = receive_and_follow(foreground_, frame_producer::NO_HINT);\r
+                       auto frame = receive_and_follow(foreground_, hints);\r
                        if(frame == core::basic_frame::late())\r
                                return foreground_->last_frame();\r
 \r
@@ -111,7 +111,7 @@ public:
                        if(auto_play_delta_ > -1 && frames_left < 1)\r
                        {\r
                                play();\r
-                               return receive();\r
+                               return receive(hints);\r
                        }\r
                                \r
                        return frame;\r
@@ -175,7 +175,7 @@ void layer::pause(){impl_->pause();}
 void layer::stop(){impl_->stop();}\r
 bool layer::is_paused() const{return impl_->is_paused_;}\r
 int64_t layer::frame_number() const{return impl_->frame_number_;}\r
-safe_ptr<basic_frame> layer::receive() {return impl_->receive();}\r
+safe_ptr<basic_frame> layer::receive(int hints) {return impl_->receive(hints);}\r
 safe_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}\r
 safe_ptr<frame_producer> layer::background() const { return impl_->background_;}\r
 bool layer::empty() const {return impl_->empty();}\r
index bc6475e0cc178dac9ea83cabc1235db0d6ae718c..38ccd43a6651e08c18ce3575f63d502e44da2b55 100644 (file)
@@ -59,7 +59,7 @@ public:
        safe_ptr<frame_producer> foreground() const; // nothrow\r
        safe_ptr<frame_producer> background() const; // nothrow\r
 \r
-       safe_ptr<basic_frame> receive(); // nothrow\r
+       safe_ptr<basic_frame> receive(int hints); // nothrow\r
 \r
        boost::property_tree::wptree info() const;\r
 private:\r
index 9117ab0fb58e34018931447f440ccfd8135af3d0..2396e7be6b2368fa75ae80737531b428cdd3ae48 100644 (file)
@@ -30,6 +30,8 @@
 \r
 #include <common/concurrency/executor.h>\r
 \r
+#include <core/producer/frame/frame_transform.h>\r
+\r
 #include <boost/foreach.hpp>\r
 #include <boost/timer.hpp>\r
 \r
 #include <map>\r
 \r
 namespace caspar { namespace core {\r
+       \r
+template<typename T>\r
+class tweened_transform\r
+{\r
+       T source_;\r
+       T dest_;\r
+       int duration_;\r
+       int time_;\r
+       tweener_t tweener_;\r
+public:        \r
+       tweened_transform()\r
+               : duration_(0)\r
+               , time_(0)\r
+               , tweener_(get_tweener(L"linear")){}\r
+       tweened_transform(const T& source, const T& dest, int duration, const std::wstring& tween = L"linear")\r
+               : source_(source)\r
+               , dest_(dest)\r
+               , duration_(duration)\r
+               , time_(0)\r
+               , tweener_(get_tweener(tween)){}\r
+       \r
+       T fetch()\r
+       {\r
+               return time_ == duration_ ? dest_ : tween(static_cast<double>(time_), source_, dest_, static_cast<double>(duration_), tweener_);\r
+       }\r
+\r
+       T fetch_and_tick(int num)\r
+       {                                               \r
+               time_ = std::min(time_+num, duration_);\r
+               return fetch();\r
+       }\r
+};\r
 \r
 struct stage::implementation : public std::enable_shared_from_this<implementation>\r
                                                         , boost::noncopyable\r
@@ -52,6 +86,7 @@ struct stage::implementation : public std::enable_shared_from_this<implementatio
        boost::timer                                    tick_timer_;\r
 \r
        std::map<int, layer>                    layers_;        \r
+       std::map<int, tweened_transform<core::frame_transform>> transforms_;    \r
 \r
        executor                                                executor_;\r
 public:\r
@@ -85,7 +120,31 @@ public:
 \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
+                               auto transform = transforms_[layer.first].fetch_and_tick(1);\r
+\r
+                               int hints = frame_producer::NO_HINT;\r
+                               if(format_desc_.field_mode != field_mode::progressive)\r
+                               {\r
+                                       hints |= std::abs(transform.fill_scale[1]  - 1.0) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT;\r
+                                       hints |= std::abs(transform.fill_translation[1]) > 0.0001 ? frame_producer::DEINTERLACE_HINT : frame_producer::NO_HINT;\r
+                               }\r
+\r
+                               if(transform.is_key)\r
+                                       hints |= frame_producer::ALPHA_HINT;\r
+\r
+                               auto frame = layer.second.receive(hints);       \r
+                               \r
+                               auto frame1 = make_safe<core::basic_frame>(frame);\r
+                               frame1->get_frame_transform() = transform;\r
+\r
+                               if(format_desc_.field_mode != core::field_mode::progressive)\r
+                               {                               \r
+                                       auto frame2 = make_safe<core::basic_frame>(frame);\r
+                                       frame2->get_frame_transform() = transforms_[layer.first].fetch_and_tick(1);\r
+                                       frame1 = core::basic_frame::interlace(frame1, frame2, format_desc_.field_mode);\r
+                               }\r
+\r
+                               frames[layer.first] = frame1;\r
                        });\r
                        \r
                        graph_->update_value("produce-time", produce_timer_.elapsed()*format_desc_.fps*0.5);\r
@@ -108,7 +167,42 @@ public:
                        CASPAR_LOG_CURRENT_EXCEPTION();\r
                }               \r
        }\r
+               void set_transform(int index, const frame_transform& transform, unsigned int mix_duration, const std::wstring& tween)\r
+       {\r
+               executor_.begin_invoke([=]\r
+               {\r
+                       auto src = transforms_[index].fetch();\r
+                       auto dst = transform;\r
+                       transforms_[index] = tweened_transform<frame_transform>(src, dst, mix_duration, tween);\r
+               }, high_priority);\r
+       }\r
+                               \r
+       void apply_transform(int index, const std::function<frame_transform(frame_transform)>& transform, unsigned int mix_duration, const std::wstring& tween)\r
+       {\r
+               executor_.begin_invoke([=]\r
+               {\r
+                       auto src = transforms_[index].fetch();\r
+                       auto dst = transform(src);\r
+                       transforms_[index] = tweened_transform<frame_transform>(src, dst, mix_duration, tween);\r
+               }, high_priority);\r
+       }\r
 \r
+       void clear_transforms(int index)\r
+       {\r
+               executor_.begin_invoke([=]\r
+               {\r
+                       transforms_.erase(index);\r
+               }, high_priority);\r
+       }\r
+\r
+       void clear_transforms()\r
+       {\r
+               executor_.begin_invoke([=]\r
+               {\r
+                       transforms_.clear();\r
+               }, high_priority);\r
+       }\r
+               \r
        void load(int index, const safe_ptr<frame_producer>& producer, bool preview, int auto_play_delta)\r
        {\r
                executor_.begin_invoke([=]\r
@@ -251,6 +345,10 @@ public:
 };\r
 \r
 stage::stage(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<target_t>& target, const video_format_desc& format_desc) : impl_(new implementation(graph, target, format_desc)){}\r
+void stage::set_frame_transform(int index, const core::frame_transform& transform, unsigned int mix_duration, const std::wstring& tween){impl_->set_transform(index, transform, mix_duration, tween);}\r
+void stage::apply_frame_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const std::wstring& tween){impl_->apply_transform(index, transform, mix_duration, tween);}\r
+void stage::clear_transforms(int index){impl_->clear_transforms(index);}\r
+void stage::clear_transforms(){impl_->clear_transforms();}\r
 void stage::spawn_token(){impl_->spawn_token();}\r
 void stage::load(int index, const safe_ptr<frame_producer>& producer, bool preview, int auto_play_delta){impl_->load(index, producer, preview, auto_play_delta);}\r
 void stage::pause(int index){impl_->pause(index);}\r
index ae3dc79cde20feef463347a4bc48a934868489b1..e6b989fcc93e9376ab9dbf34b8b156a4df5fce7a 100644 (file)
 #include <boost/property_tree/ptree_fwd.hpp>\r
 #include <boost/thread/future.hpp>\r
 \r
+#include <functional>\r
+\r
 namespace caspar { namespace core {\r
 \r
 struct video_format_desc;\r
+struct frame_transform;\r
 \r
 class stage : boost::noncopyable\r
 {\r
@@ -43,6 +46,11 @@ public:
        explicit stage(const safe_ptr<diagnostics::graph>& graph, const safe_ptr<target_t>& target, const video_format_desc& format_desc);\r
        \r
        // stage\r
+       \r
+       void set_frame_transform(int index, const frame_transform& transform, unsigned int mix_duration = 0, const std::wstring& tween = L"linear");\r
+       void apply_frame_transform(int index, const std::function<frame_transform(frame_transform)>& transform, unsigned int mix_duration = 0, const std::wstring& tween = L"linear");\r
+       void clear_transforms(int index);\r
+       void clear_transforms();\r
 \r
        void spawn_token();\r
                        \r
index 6638d0c2bab83d75d055cdb010ec45e0693e5ebe..923d6125f0cf5a6c62308520f7bf0b65ecaddc35 100644 (file)
@@ -142,6 +142,9 @@ public:
        virtual safe_ptr<core::basic_frame> receive(int hints) override\r
        {               \r
                frame_timer_.restart();\r
+\r
+               // TODO: buffered frame is not deinterlaced.\r
+               muxer_->force_deinterlacing(hints == core::frame_producer::DEINTERLACE_HINT);\r
                \r
                for(int n = 0; n < 16 && frame_buffer_.size() < 2; ++n)\r
                        try_decode_frame(hints);\r
index 6ab130890bf8350e8f0b84330a7c6506284014cd..19bc662e09fe12440eddc67d22942b600f546bb5 100644 (file)
@@ -115,7 +115,7 @@ struct filter::implementation
                                        std::stringstream args;\r
                                        args << frame->width << ":" << frame->height << ":" << frame->format << ":" << 0 << ":" << 0 << ":" << 0 << ":" << 0; // don't care about pts and aspect_ratio\r
                                        THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersrc_ctx_, avfilter_get_by_name("buffer"), "src", args.str().c_str(), NULL, graph_.get()), "[filter]");\r
-                                       
+                                       \r
 #if FF_API_OLD_VSINK_API\r
                                        THROW_ON_ERROR2(avfilter_graph_create_filter(&buffersink_ctx_, avfilter_get_by_name("buffersink"), "out", NULL, pix_fmts_.data(), graph_.get()), "[filter]");\r
 #else\r
@@ -234,7 +234,7 @@ filter::filter(filter&& other) : impl_(std::move(other.impl_)){}
 filter& filter::operator=(filter&& other){impl_ = std::move(other.impl_); return *this;}\r
 void filter::push(const std::shared_ptr<AVFrame>& frame){impl_->push(frame);}\r
 std::shared_ptr<AVFrame> filter::poll(){return impl_->poll();}\r
-std::string filter::filter_str() const{return impl_->filters_;}\r
+std::wstring filter::filter_str() const{return widen(impl_->filters_);}\r
 std::vector<safe_ptr<AVFrame>> filter::poll_all()\r
 {      \r
        std::vector<safe_ptr<AVFrame>> frames;\r
index 7c72e9d02cd4d96e0078a7a61cfc7a0b2c57dcda..88548a087bd02f7d99bd51993b17a3e04bbd6a55 100644 (file)
@@ -50,6 +50,14 @@ static bool is_deinterlacing(const std::wstring& filters)
        if(boost::to_upper_copy(filters).find(L"YADIF") != std::string::npos)\r
                return true;    \r
        return false;\r
+}      \r
+       \r
+static int filter_delay(const std::wstring& filters)\r
+{\r
+       if(is_double_rate(filters))\r
+               return 1;\r
+       \r
+       return 0;\r
 }\r
 \r
 static std::wstring append_filter(const std::wstring& filters, const std::wstring& filter)\r
@@ -68,7 +76,7 @@ public:
        std::shared_ptr<AVFrame> poll();\r
        std::vector<safe_ptr<AVFrame>> poll_all();\r
 \r
-       std::string filter_str() const;\r
+       std::wstring filter_str() const;\r
        \r
 private:\r
        struct implementation;\r
index 2506879751cdabbd6482978729c7d65ceae6f616..3faa47f833039b60ef52266f5c7f720eabe63290 100644 (file)
@@ -56,6 +56,7 @@ extern "C"
 \r
 #include <boost/foreach.hpp>\r
 #include <boost/range/algorithm_ext/push_back.hpp>\r
+#include <boost/algorithm/string/predicate.hpp>\r
 \r
 #include <deque>\r
 #include <queue>\r
@@ -74,27 +75,26 @@ struct frame_muxer::implementation : boost::noncopyable
        const double                                                                    in_fps_;\r
        const video_format_desc                                                 format_desc_;\r
        bool                                                                                    auto_transcode_;\r
+       bool                                                                                    auto_deinterlace_;\r
        \r
        std::vector<size_t>                                                             audio_cadence_;\r
-\r
-       size_t                                                                                  audio_sample_count_;\r
-       size_t                                                                                  video_frame_count_;\r
-               \r
+                       \r
        safe_ptr<core::frame_factory>                                   frame_factory_;\r
        \r
        filter                                                                                  filter_;\r
-       std::wstring                                                                    filter_str_;\r
+       const std::wstring                                                              filter_str_;\r
+       bool                                                                                    force_deinterlacing_;\r
                \r
        implementation(double in_fps, const safe_ptr<core::frame_factory>& frame_factory, const std::wstring& filter_str)\r
                : display_mode_(display_mode::invalid)\r
                , in_fps_(in_fps)\r
                , format_desc_(frame_factory->get_video_format_desc())\r
                , auto_transcode_(env::properties().get("configuration.auto-transcode", true))\r
+               , auto_deinterlace_(env::properties().get("configuration.auto-deinterlace", true))\r
                , audio_cadence_(format_desc_.audio_cadence)\r
-               , audio_sample_count_(0)\r
-               , video_frame_count_(0)\r
                , frame_factory_(frame_factory)\r
                , filter_str_(filter_str)\r
+               , force_deinterlacing_(false)\r
        {\r
                video_streams_.push(std::queue<safe_ptr<write_frame>>());\r
                audio_streams_.push(core::audio_buffer());\r
@@ -109,19 +109,17 @@ struct frame_muxer::implementation : boost::noncopyable
                \r
                if(video_frame == flush_video())\r
                {       \r
-                       video_frame_count_ = 0;\r
                        video_streams_.push(std::queue<safe_ptr<write_frame>>());\r
                }\r
                else if(video_frame == empty_video())\r
                {\r
                        video_streams_.back().push(make_safe<core::write_frame>(this));\r
-                       ++video_frame_count_;\r
                        display_mode_ = display_mode::simple;\r
                }\r
                else\r
                {\r
                        if(display_mode_ == display_mode::invalid)\r
-                               initialize_display_mode(*video_frame);\r
+                               update_display_mode(video_frame);\r
                                \r
                        if(hints & core::frame_producer::ALPHA_HINT)\r
                                video_frame->format = make_alpha_format(video_frame->format);\r
@@ -137,7 +135,6 @@ struct frame_muxer::implementation : boost::noncopyable
                                        av_frame->format = format;\r
 \r
                                video_streams_.back().push(make_write_frame(this, av_frame, frame_factory_, hints));\r
-                               ++video_frame_count_;\r
                        }\r
                }\r
 \r
@@ -152,18 +149,15 @@ struct frame_muxer::implementation : boost::noncopyable
 \r
                if(audio == flush_audio())\r
                {\r
-                       audio_sample_count_ = 0;\r
                        audio_streams_.push(core::audio_buffer());\r
                }\r
                else if(audio == empty_audio())\r
                {\r
                        boost::range::push_back(audio_streams_.back(), core::audio_buffer(audio_cadence_.front(), 0));\r
-                       audio_sample_count_ += audio->size();\r
                }\r
                else\r
                {\r
                        boost::range::push_back(audio_streams_.back(), *audio);\r
-                       audio_sample_count_ += audio->size();\r
                }\r
 \r
                if(audio_streams_.back().size() > 32*audio_cadence_.front())\r
@@ -290,12 +284,14 @@ struct frame_muxer::implementation : boost::noncopyable
                return samples;\r
        }\r
                                \r
-       void initialize_display_mode(const AVFrame& frame)\r
+       void update_display_mode(const std::shared_ptr<AVFrame>& frame)\r
        {\r
+               std::wstring filter_str = filter_str_;\r
+\r
                display_mode_ = display_mode::simple;\r
                if(auto_transcode_)\r
                {\r
-                       auto mode = get_mode(frame);\r
+                       auto mode = get_mode(*frame);\r
                        auto fps  = in_fps_;\r
 \r
                        if(is_deinterlacing(filter_str_))\r
@@ -306,17 +302,18 @@ struct frame_muxer::implementation : boost::noncopyable
                        \r
                        display_mode_ = get_display_mode(mode, fps, format_desc_.field_mode, format_desc_.fps);\r
                        \r
-                       if((frame.height != 480 || format_desc_.height != 486) && \r
-                               display_mode_ == display_mode::simple && mode != core::field_mode::progressive && format_desc_.field_mode != core::field_mode::progressive && \r
-                               frame.height != static_cast<int>(format_desc_.height))\r
+                       if(force_deinterlacing_ || \r
+                               ((frame->height != 480 || format_desc_.height != 486) && \r
+                                       display_mode_ == display_mode::simple && mode != core::field_mode::progressive && format_desc_.field_mode != core::field_mode::progressive && \r
+                                       frame->height != static_cast<int>(format_desc_.height)))\r
                        {\r
                                display_mode_ = display_mode::deinterlace_bob_reinterlace; // The frame will most likely be scaled, we need to deinterlace->reinterlace \r
                        }\r
 \r
                        if(display_mode_ == display_mode::deinterlace)\r
-                               filter_str_ = append_filter(filter_str_, L"YADIF=0:-1");\r
+                               filter_str = append_filter(filter_str, L"YADIF=0:-1");\r
                        else if(display_mode_ == display_mode::deinterlace_bob || display_mode_ == display_mode::deinterlace_bob_reinterlace)\r
-                               filter_str_ = append_filter(filter_str_, L"YADIF=1:-1");\r
+                               filter_str = append_filter(filter_str, L"YADIF=1:-1");\r
                }\r
 \r
                if(display_mode_ == display_mode::invalid)\r
@@ -325,9 +322,27 @@ struct frame_muxer::implementation : boost::noncopyable
                        display_mode_ = display_mode::simple;\r
                }\r
                        \r
-               filter_ = filter(filter_str_);\r
+               if(!boost::iequals(filter_.filter_str(), filter_str))\r
+               {\r
+                       for(int n = 0; n < filter_delay(filter_.filter_str()); ++n)\r
+                       {\r
+                               filter_.push(frame);\r
+                               auto av_frame = filter_.poll();\r
+                               if(av_frame)                                                    \r
+                                       video_streams_.back().push(make_write_frame(this, make_safe_ptr(av_frame), frame_factory_, 0));\r
+                       }\r
+                       filter_ = filter(filter_str);\r
+                       CASPAR_LOG(info) << "[frame_muxer] " << display_mode::print(display_mode_) << L" " << print_mode(frame->width, frame->height, in_fps_, frame->interlaced_frame > 0);\r
+               }\r
+       }\r
+\r
+       void force_deinterlacing(bool value)\r
+       {\r
+               if(!auto_deinterlace_ || value == force_deinterlacing_)\r
+                       return;\r
 \r
-               CASPAR_LOG(info) << "[frame_muxer] " << display_mode::print(display_mode_) << L" " << print_mode(frame.width, frame.height, in_fps_, frame.interlaced_frame > 0);\r
+               force_deinterlacing_ = value;\r
+               display_mode_ = display_mode::invalid;\r
        }\r
 \r
        int64_t calc_nb_frames(int64_t nb_frames) const\r
@@ -359,5 +374,6 @@ std::shared_ptr<basic_frame> frame_muxer::poll(){return impl_->poll();}
 int64_t frame_muxer::calc_nb_frames(int64_t nb_frames) const {return impl_->calc_nb_frames(nb_frames);}\r
 bool frame_muxer::video_ready() const{return impl_->video_ready();}\r
 bool frame_muxer::audio_ready() const{return impl_->audio_ready();}\r
+void frame_muxer::force_deinterlacing(bool value){impl_->force_deinterlacing(value);}\r
 \r
 }}
\ No newline at end of file
index e39aecfa8d69235675f49a8dbae87e267f23e90a..10e6d9c12952ed663e20ace250abad0960a15cb3 100644 (file)
@@ -58,6 +58,8 @@ public:
 \r
        int64_t calc_nb_frames(int64_t nb_frames) const;\r
 \r
+       void force_deinterlacing(bool value);\r
+\r
 private:\r
        struct implementation;\r
        safe_ptr<implementation> impl_;\r
index 2f464b5108c63eb3f4d8f0f8eaf6dae0999e45ce..f2eac0ea3cc93fa92ef4fec879867abfa03ec8c0 100644 (file)
@@ -271,7 +271,7 @@ bool MixerCommand::DoExecute()
                        };\r
 \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform);\r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform);\r
                }\r
                else if(_parameters[0] == L"OPACITY")\r
                {\r
@@ -287,7 +287,7 @@ bool MixerCommand::DoExecute()
                        };\r
 \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);\r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);\r
                }\r
                else if(_parameters[0] == L"FILL" || _parameters[0] == L"FILL_RECT")\r
                {\r
@@ -312,7 +312,7 @@ bool MixerCommand::DoExecute()
                        };\r
                                \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);\r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);\r
                }\r
                else if(_parameters[0] == L"CLIP" || _parameters[0] == L"CLIP_RECT")\r
                {\r
@@ -333,7 +333,7 @@ bool MixerCommand::DoExecute()
                        };\r
                                \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);\r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);\r
                }\r
                else if(_parameters[0] == L"GRID")\r
                {\r
@@ -358,7 +358,7 @@ bool MixerCommand::DoExecute()
                                                transform.clip_scale[1]                 = delta;                        \r
                                                return transform;\r
                                        };\r
-                                       GetChannel()->mixer()->apply_frame_transform(index, transform, duration, tween);\r
+                                       GetChannel()->stage()->apply_frame_transform(index, transform, duration, tween);\r
                                }\r
                        }\r
                }\r
@@ -380,7 +380,7 @@ bool MixerCommand::DoExecute()
                        };\r
                                \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);      \r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);      \r
                }\r
                else if(_parameters[0] == L"SATURATION")\r
                {\r
@@ -394,7 +394,7 @@ bool MixerCommand::DoExecute()
                        };\r
                                \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);      \r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);      \r
                }\r
                else if(_parameters[0] == L"CONTRAST")\r
                {\r
@@ -408,7 +408,7 @@ bool MixerCommand::DoExecute()
                        };\r
                                \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);      \r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);      \r
                }\r
                else if(_parameters[0] == L"LEVELS")\r
                {\r
@@ -428,7 +428,7 @@ bool MixerCommand::DoExecute()
                        };\r
                                \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);      \r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);      \r
                }\r
                else if(_parameters[0] == L"VOLUME")\r
                {\r
@@ -443,15 +443,15 @@ bool MixerCommand::DoExecute()
                        };\r
                                \r
                        int layer = GetLayerIndex();\r
-                       GetChannel()->mixer()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);\r
+                       GetChannel()->stage()->apply_frame_transform(GetLayerIndex(), transform, duration, tween);\r
                }\r
                else if(_parameters[0] == L"CLEAR")\r
                {\r
                        int layer = GetLayerIndex(std::numeric_limits<int>::max());\r
                        if(layer ==     std::numeric_limits<int>::max())\r
-                               GetChannel()->mixer()->clear_transforms();\r
+                               GetChannel()->stage()->clear_transforms();\r
                        else\r
-                               GetChannel()->mixer()->clear_transforms(layer);\r
+                               GetChannel()->stage()->clear_transforms(layer);\r
                }\r
                else\r
                {\r
index 092fa0334fec5ec661480540c7b3a3c7b3a2d5a8..4d3d10108d3c4062f8facce97dd12f1ed508f111 100644 (file)
@@ -8,12 +8,11 @@
   </paths>\r
   <channels>\r
     <channel>\r
-      <video-mode>720p5000</video-mode>\r
+      <video-mode>PAL</video-mode>\r
       <consumers>\r
-        <screen>\r
-          <device>2</device>\r
-        </screen>\r
-        <system-audio></system-audio>\r
+        <decklink>\r
+          <embedded-audio>true</embedded-audio>\r
+        </decklink>\r
       </consumers>\r
     </channel>\r
   </channels>\r