]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2: Improved flash logging.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 26 Feb 2011 18:52:51 +0000 (18:52 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 26 Feb 2011 18:52:51 +0000 (18:52 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@483 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

common/diagnostics/graph.cpp
common/diagnostics/graph.h
core/producer/flash/FlashAxContainer.cpp
core/producer/flash/FlashAxContainer.h
core/producer/flash/cg_producer.cpp
core/producer/flash/flash_producer.cpp
core/video_format.h

index 9a6d7e9696f467c0e40826bc553191590884edcf..08ab5b7f06222f4e6c463ac6fc73da7f84ac63c1 100644 (file)
@@ -242,9 +242,10 @@ struct graph::implementation : public drawable
 {\r
        std::map<std::string, diagnostics::line> lines_;\r
        std::string name_;\r
+       std::string display_name_;\r
 \r
        implementation(const std::string& name) \r
-               : name_(name){}\r
+               : name_(name), display_name_(name_){}\r
 \r
        void update(const std::string& name, float value)\r
        {\r
@@ -286,6 +287,14 @@ struct graph::implementation : public drawable
                });\r
        }\r
 \r
+       void set_display_name(const std::string& name)\r
+       {\r
+               context::begin_invoke([=]\r
+               {\r
+                       display_name_ = name;\r
+               });     \r
+       }\r
+\r
 private:\r
        void render(sf::RenderTarget& target)\r
        {\r
@@ -293,7 +302,7 @@ private:
                const size_t text_margin = 2;\r
                const size_t text_offset = text_size+text_margin*2;\r
 \r
-               sf::String text(name_.c_str(), sf::Font::GetDefaultFont(), text_size);\r
+               sf::String text(display_name_.c_str(), sf::Font::GetDefaultFont(), text_size);\r
                text.SetStyle(sf::String::Italic);\r
                text.Move(text_margin, text_margin);\r
                \r
@@ -350,6 +359,7 @@ void graph::set(const std::string& name, float value){if(impl_)impl_->set(name,
 void graph::tag(const std::string& name){if(impl_)impl_->tag(name);}\r
 void graph::guide(const std::string& name, float value){if(impl_)impl_->guide(name, value);}\r
 void graph::set_color(const std::string& name, color c){if(impl_)impl_->set_color(name, c);}\r
+void graph::set_display_name(const std::string& name){if(impl_)impl_->set_display_name(name);}\r
 \r
 safe_ptr<graph> create_graph(const std::string& name)\r
 {\r
index 9ada47b222b0ead224759f15364972d997da52a6..bb6d6646003aa642885293bc1f7f4695261bca82 100644 (file)
@@ -30,6 +30,7 @@ public:
        void tag(const std::string& name);\r
        void guide(const std::string& name, float value);\r
        void set_color(const std::string& name, color c);\r
+       void set_display_name(const std::string& name);\r
 private:\r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
index 746d5997c9d1fc277d1d8f49dabee92bdfc2cf3b..fbd7886b8c53edc3d96a13a2874992548d4230fb 100644 (file)
@@ -474,7 +474,7 @@ HRESULT STDMETHODCALLTYPE FlashAxContainer::QueryService( REFGUID rsid, REFIID r
                        {\r
                                delete m_lpDD4;\r
                                m_lpDD4 = NULL;\r
-                               CASPAR_LOG(info) << "flash: DirectDraw not installed. Running without DirectDraw.";\r
+                               CASPAR_LOG(info) << print_() << " DirectDraw not installed. Running without DirectDraw.";\r
                                return E_NOINTERFACE;\r
                        }\r
                }\r
@@ -607,12 +607,12 @@ void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
        }\r
        else if(str.find(TEXT("OnCommand")) != std::wstring::npos) {\r
                //this is how templatehost 1.8 reports that a command has been received\r
-               CASPAR_LOG(info) << TEXT("TEMPLATEHOST: ") << str;\r
+               CASPAR_LOG(info)  << print_()  << L" Command: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
                bCallSuccessful_ = true;\r
        }\r
        else if(str.find(TEXT("Activity")) != std::wstring::npos)\r
        {\r
-               CASPAR_LOG(info) << TEXT("TEMPLATEHOST: ") << str;\r
+               CASPAR_LOG(info) << print_() << L" Activity: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
 \r
                //this is how templatehost 1.7 reports that a command has been received\r
                if(str.find(TEXT("Command recieved")) != std::wstring::npos)\r
@@ -626,7 +626,7 @@ void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
        }\r
        else if(str.find(TEXT("OnNotify")) != std::wstring::npos)\r
        {\r
-               CASPAR_LOG(info) << TEXT("TEMPLATEHOST: ") << str;\r
+               CASPAR_LOG(info) << print_() << L" Notification: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
 \r
                //if(pFlashProducer_ != 0 && pFlashProducer_->pMonitor_) {\r
                //      std::wstring::size_type pos = str.find(TEXT('@'));\r
@@ -636,12 +636,13 @@ void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
        }\r
        else if(str.find(TEXT("IsEmpty")) != std::wstring::npos)\r
        {\r
+               CASPAR_LOG(info) << print_() << L" Empty.";\r
                ATLTRACE(_T("ShockwaveFlash::IsEmpty\n"));\r
                bIsEmpty_ = true;\r
        }\r
        else if(str.find(TEXT("OnError")) != std::wstring::npos)\r
        {\r
-               CASPAR_LOG(error) << "FLASHERROR: " << str;\r
+               CASPAR_LOG(error) << print_() << L" Error: \n-------------------------------------------\n" << str << L"\n-------------------------------------------";\r
        }\r
 \r
        CComPtr<IShockwaveFlash> spFlash;\r
@@ -755,7 +756,7 @@ HRESULT FlashAxContainer::CreateAxControl()
                        if(hr2 == S_OK && spFlash)\r
                        {\r
                                if(FAILED(spFlash->put_WMode(TEXT("Transparent"))))\r
-                                       CASPAR_LOG(warning) << L"Failed to set flash container to transparent mode.";\r
+                                       CASPAR_LOG(warning) << print_() << L" Failed to set flash container to transparent mode.";\r
                                //spFlash->put_WMode(TEXT("GPU"));\r
                                hResultQuality = spFlash->put_Quality2(TEXT("Best"));\r
                        }\r
index e8abd5741e13988fbcd36a2581b03c8d6f4983ac..3bb9fbe5c92ca54209da90b7d532ac561538a2da 100644 (file)
@@ -26,9 +26,9 @@
 #include <atlbase.h>\r
 #include <atlcom.h>\r
 #include <atlhost.h>\r
-\r
-\r
 #include <ocmm.h>\r
+\r
+#include <functional>\r
 #include <vector>\r
 \r
 #include "../../video_format.h"\r
@@ -236,6 +236,8 @@ public:
        STDMETHOD(GetTime)(VARIANT *pvtime);\r
        double GetFPS();\r
 \r
+       void set_print(const std::function<std::wstring()>& print) { print_ = print;}\r
+\r
        HRESULT CreateAxControl();\r
        void DestroyAxControl();\r
        HRESULT QueryControl(REFIID iid, void** ppUnk);\r
@@ -263,6 +265,7 @@ public:
        ATL::CComPtr<IOleInPlaceObjectWindowless> m_spInPlaceObjectWindowless;\r
 \r
 private:\r
+       std::function<std::wstring()> print_;\r
        TimerHelper* pTimerHelper;\r
        volatile bool bInvalidRect_;\r
        volatile bool bCallSuccessful_;\r
index 79978512e9b3ef29db7367aa78f9e80783802e77..216fa7256f5fe1cd3149d3b3edb239635cc30248 100644 (file)
@@ -28,43 +28,43 @@ public:
 \r
        void add(int layer, const std::wstring& filename,  bool play_on_load, const std::wstring& label, const std::wstring& data)\r
        {\r
-               CASPAR_LOG(info) << "Invoking add-command";\r
+               CASPAR_LOG(info) << print() << " Invoking add-command";\r
                flash_producer_->param((boost::wformat(L"<invoke name=\"Add\" returntype=\"xml\"><arguments><number>%1%</number><string>%2%</string>%3%<string>%4%</string><string><![CDATA[%5%]]></string></arguments></invoke>") % layer % filename % (play_on_load?TEXT("<true/>"):TEXT("<false/>")) % label % data).str());\r
        }\r
 \r
        void remove(int layer)\r
        {\r
-               CASPAR_LOG(info) << "Invoking remove-command";\r
+               CASPAR_LOG(info) << print() << " Invoking remove-command";\r
                flash_producer_->param((boost::wformat(L"<invoke name=\"Delete\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str());\r
        }\r
 \r
        void play(int layer)\r
        {\r
-               CASPAR_LOG(info) << "Invoking play-command";\r
+               CASPAR_LOG(info) << print() << " Invoking play-command";\r
                flash_producer_->param((boost::wformat(L"<invoke name=\"Play\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str());\r
        }\r
 \r
        void stop(int layer, unsigned int)\r
        {\r
-               CASPAR_LOG(info) << "Invoking stop-command";\r
+               CASPAR_LOG(info) << print() << " Invoking stop-command";\r
                flash_producer_->param((boost::wformat(L"<invoke name=\"Stop\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><number>0</number></arguments></invoke>") % layer).str());\r
        }\r
 \r
        void next(int layer)\r
        {\r
-               CASPAR_LOG(info) << "Invoking next-command";\r
+               CASPAR_LOG(info) << print() << " Invoking next-command";\r
                flash_producer_->param((boost::wformat(L"<invoke name=\"Next\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array></arguments></invoke>") % layer).str());\r
        }\r
 \r
        void update(int layer, const std::wstring& data)\r
        {\r
-               CASPAR_LOG(info) << "Invoking update-command";\r
+               CASPAR_LOG(info) << print() <<" Invoking update-command";\r
                flash_producer_->param((boost::wformat(L"<invoke name=\"SetData\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><string><![CDATA[%2%]]></string></arguments></invoke>") % layer % data).str());\r
        }\r
 \r
        void invoke(int layer, const std::wstring& label)\r
        {\r
-               CASPAR_LOG(info) << "Invoking invoke-command";\r
+               CASPAR_LOG(info) << print() << " Invoking invoke-command";\r
                flash_producer_->param((boost::wformat(L"<invoke name=\"Invoke\" returntype=\"xml\"><arguments><array><property id=\"0\"><number>%1%</number></property></array><string>%2%</string></arguments></invoke>") % layer % label).str());\r
        }\r
 \r
@@ -81,7 +81,7 @@ public:
 \r
        std::wstring print() const\r
        {\r
-               return L"cg[" + flash_producer_->print() + L"]";\r
+               return flash_producer_->print();\r
        }\r
 \r
        safe_ptr<flash_producer> flash_producer_;\r
index 6344509e9c28121ec980844db1e769422bcea8bd..8c3b19f86c1a5ea90ef526ab58fa7974043b5ed9 100644 (file)
@@ -21,7 +21,6 @@
 #include "..\..\stdafx.h"\r
 \r
 #if defined(_MSC_VER)\r
-#pragma warning (disable : 4714) // marked as __forceinline not inlined\r
 #pragma warning (disable : 4146)\r
 #endif\r
 \r
@@ -40,7 +39,7 @@
 #include <boost/filesystem.hpp>\r
 \r
 namespace caspar { namespace core { namespace flash {\r
-       \r
+               \r
 class flash_renderer\r
 {\r
        struct co_init\r
@@ -64,10 +63,12 @@ class flash_renderer
        timer timer_;\r
 \r
        safe_ptr<diagnostics::graph> graph_;\r
-       timer diag_timer_;\r
-       bool underflow_;\r
+       timer perf_timer_;\r
+\r
+       std::function<std::wstring()> print_;\r
+\r
 public:\r
-       flash_renderer(const safe_ptr<diagnostics::graph>& graph, const std::shared_ptr<frame_factory>& frame_factory, const std::wstring& filename) \r
+       flash_renderer(const safe_ptr<diagnostics::graph>& graph, const std::shared_ptr<frame_factory>& frame_factory, const std::wstring& filename, const std::function<std::wstring()>& print\r
                : graph_(graph)\r
                , filename_(filename)\r
                , format_desc_(frame_factory->get_video_format_desc())\r
@@ -76,32 +77,33 @@ public:
                , hdc_(CreateCompatibleDC(0), DeleteDC)\r
                , ax_(nullptr)\r
                , head_(draw_frame::empty())\r
-               , underflow_(false)\r
+               , print_(print)\r
        {\r
                graph_->guide("frame-time", 0.5f);\r
                graph_->set_color("frame-time", diagnostics::color(1.0f, 0.0f, 0.0f));  \r
                graph_->set_color("param", diagnostics::color(1.0f, 0.5f, 0.0f));       \r
                graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));                   \r
-               CASPAR_LOG(info) << print() << L" Started";\r
                \r
                if(FAILED(CComObject<caspar::flash::FlashAxContainer>::CreateInstance(&ax_)))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to create FlashAxContainer"));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print_()) + "Failed to create FlashAxContainer"));\r
                \r
+               ax_->set_print(print_);\r
+\r
                if(FAILED(ax_->CreateAxControl()))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Create FlashAxControl"));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print_()) + "Failed to Create FlashAxControl"));\r
                \r
                CComPtr<IShockwaveFlash> spFlash;\r
                if(FAILED(ax_->QueryControl(&spFlash)))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Query FlashAxControl"));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print_()) + "Failed to Query FlashAxControl"));\r
                                                                                                \r
                if(FAILED(spFlash->put_Playing(true)) )\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to start playing Flash"));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print_()) + "Failed to start playing Flash"));\r
 \r
                if(FAILED(spFlash->put_Movie(CComBSTR(filename.c_str()))))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Load Template Host"));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print_()) + "Failed to Load Template Host"));\r
                                                                                \r
                if(FAILED(spFlash->put_ScaleMode(2)))  //Exact fit. Scale without respect to the aspect ratio.\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Set Scale Mode"));\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(narrow(print_()) + "Failed to Set Scale Mode"));\r
                                                                                                                \r
                ax_->SetFormat(format_desc_);\r
                \r
@@ -116,7 +118,7 @@ public:
 \r
                bmp_.reset(CreateDIBSection(static_cast<HDC>(hdc_.get()), &info, DIB_RGB_COLORS, reinterpret_cast<void**>(&bmp_data_), 0, 0), DeleteObject);\r
                SelectObject(static_cast<HDC>(hdc_.get()), bmp_.get()); \r
-               CASPAR_LOG(info) << print() << L" Started";\r
+               CASPAR_LOG(info) << print() << L" Thread started.";\r
        }\r
 \r
        ~flash_renderer()\r
@@ -126,13 +128,13 @@ public:
                        ax_->DestroyAxControl();\r
                        ax_->Release();\r
                }\r
-               CASPAR_LOG(info) << print() << L" Ended";\r
+               CASPAR_LOG(info) << print_() << L" Thread ended.";\r
        }\r
        \r
        void param(const std::wstring& param)\r
        {               \r
                if(!ax_->FlashCall(param))\r
-                       CASPAR_LOG(warning) << "Flash Function Call Failed. Param: " << param;\r
+                       CASPAR_LOG(warning) << print_() << " Flash function call failed. Param: " << param << ".";\r
                graph_->tag("param");\r
        }\r
        \r
@@ -142,26 +144,27 @@ public:
                        return draw_frame::empty();\r
 \r
                auto frame = render_simple_frame(has_underflow);\r
-               if(abs(ax_->GetFPS()/2.0 - format_desc_.fps) < 0.1)\r
+               if(interlaced(ax_->GetFPS(), format_desc_))\r
                        frame = draw_frame::interlace(frame, render_simple_frame(has_underflow), format_desc_.mode);\r
                return frame;\r
        }\r
-               \r
-       std::wstring print() const{ return L"flash[" + boost::filesystem::wpath(filename_).filename() + L"] Render thread"; }\r
-       std::string bprint() const{ return narrow(print()); }\r
+\r
+       double fps() const\r
+       {\r
+               return ax_->GetFPS();   \r
+       }\r
 \r
 private:\r
 \r
        safe_ptr<draw_frame> render_simple_frame(bool underflow)\r
        {\r
-               if(underflow_ != underflow)\r
+               if(underflow)\r
                        graph_->tag("underflow");\r
 \r
-               underflow_ = underflow;\r
-               double frame_time = 1.0/ax_->GetFPS()*(underflow ? 0.90 : 1.0); \r
+               double frame_time = 1.0/ax_->GetFPS()*(underflow ? 0.90 : 1.0); // Reduce sync-time if in underflow.\r
                timer_.tick(frame_time); // Tick doesnt work on nested timelines, force an actual sync\r
 \r
-               diag_timer_.reset();\r
+               perf_timer_.reset();\r
                ax_->Tick();\r
 \r
                if(ax_->InvalidRect())\r
@@ -174,7 +177,7 @@ private:
                        head_ = frame;\r
                }               \r
                \r
-               graph_->update("frame-time", static_cast<float>(diag_timer_.elapsed()/frame_time));\r
+               graph_->update("frame-time", static_cast<float>(perf_timer_.elapsed()/frame_time));\r
                return head_;\r
        }\r
 };\r
@@ -182,6 +185,7 @@ private:
 struct flash_producer::implementation\r
 {      \r
        const std::wstring filename_;   \r
+       tbb::atomic<int> fps_;\r
 \r
        safe_ptr<diagnostics::graph> graph_;\r
 \r
@@ -190,10 +194,24 @@ struct flash_producer::implementation
 \r
        std::shared_ptr<flash_renderer> renderer_;\r
        std::shared_ptr<frame_factory> frame_factory_;\r
-       \r
-       std::wstring print() const{ return L"flash[" + boost::filesystem::wpath(filename_).filename() + L"]"; } \r
-\r
+       video_format_desc format_desc_;\r
+                       \r
        executor executor_;\r
+               \r
+       std::wstring print() const\r
+       { \r
+               return L"flash[" + boost::filesystem::wpath(filename_).filename() + L", " + \r
+                                       boost::lexical_cast<std::wstring>(fps_) + \r
+                                       (interlaced(fps_, format_desc_) ? L"i" : L"p") + L"]";          \r
+       }       \r
+\r
+       void set_fps(double fps)\r
+       {\r
+               int fps100 = static_cast<int>(renderer_->fps()*100.0);\r
+               if(fps_.fetch_and_store(fps100) != fps100)\r
+                       graph_->set_display_name(narrow(print()));      \r
+       }\r
+       \r
 public:\r
        implementation(const std::wstring& filename) \r
                : filename_(filename)\r
@@ -204,6 +222,7 @@ public:
                if(!boost::filesystem::exists(filename))\r
                        BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename)));  \r
 \r
+               fps_ = 0;\r
                graph_->set_color("output-buffer", diagnostics::color(0.0f, 1.0f, 0.0f));       \r
        }\r
 \r
@@ -219,7 +238,8 @@ public:
        virtual void initialize(const safe_ptr<frame_factory>& frame_factory)\r
        {\r
                frame_factory_ = frame_factory;\r
-               frame_buffer_.set_capacity(static_cast<size_t>(frame_factory->get_video_format_desc().fps/4.0));\r
+               format_desc_ = frame_factory->get_video_format_desc();\r
+               frame_buffer_.set_capacity(static_cast<size_t>(format_desc_.fps/4.0));\r
                executor_.start();\r
        }\r
 \r
@@ -227,31 +247,30 @@ public:
        {               \r
                if(!renderer_)\r
                        return draw_frame::empty();\r
-\r
+               \r
                graph_->set("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));\r
                if(!frame_buffer_.try_pop(tail_))\r
-                       CASPAR_LOG(trace) << print() << " underflow";\r
-               else\r
+                       return tail_;\r
+\r
+               executor_.begin_invoke([=]\r
                {\r
-                       executor_.begin_invoke([=]\r
+                       if(!renderer_)\r
+                               return;\r
+\r
+                       try\r
                        {\r
-                               if(!renderer_)\r
-                                       return;\r
-\r
-                               try\r
-                               {\r
-                                       auto frame = draw_frame::empty();\r
-                                       do{frame = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity()-2);}\r
-                                       while(frame_buffer_.try_push(frame) && frame == draw_frame::empty());\r
-                                       graph_->set("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));\r
-                               }\r
-                               catch(...)\r
-                               {\r
-                                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                                       renderer_ = nullptr;\r
-                               }\r
-                       });     \r
-               }\r
+                               auto frame = draw_frame::empty();\r
+                               do{frame = renderer_->render_frame(frame_buffer_.size() < frame_buffer_.capacity()-2);}\r
+                               while(frame_buffer_.try_push(frame) && frame == draw_frame::empty());\r
+                               graph_->set("output-buffer", static_cast<float>(frame_buffer_.size())/static_cast<float>(frame_buffer_.capacity()));    \r
+                               set_fps(renderer_->fps());\r
+                       }\r
+                       catch(...)\r
+                       {\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                               renderer_ = nullptr;\r
+                       }\r
+               });                     \r
 \r
                return tail_;\r
        }\r
@@ -262,13 +281,13 @@ public:
                {\r
                        if(!renderer_)\r
                        {\r
-                               renderer_.reset(new flash_renderer(graph_, frame_factory_, filename_));\r
-                               while(frame_buffer_.try_push(draw_frame::empty())){}\r
+                               renderer_.reset(new flash_renderer(graph_, frame_factory_, filename_, [=]{return print();}));\r
+                               while(frame_buffer_.try_push(draw_frame::empty())){}            \r
                        }\r
 \r
                        try\r
                        {\r
-                               renderer_->param(param);\r
+                               renderer_->param(param);        \r
                        }\r
                        catch(...)\r
                        {\r
index 672e18f6076763367054bb75938c5d58e87fe5a5..ae5e45910d538a1d7cb1086cd586a1f6bf7099ac 100644 (file)
@@ -74,4 +74,9 @@ inline std::wostream& operator<<(std::wostream& out, const video_format_desc& fo
        return out;\r
 }\r
 \r
+inline bool interlaced(double fps, const video_format_desc& format_desc)\r
+{\r
+       return abs(fps/2.0 - format_desc.fps) < 0.1;\r
+}\r
+\r
 }}
\ No newline at end of file