]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2:
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 30 Dec 2010 23:29:28 +0000 (23:29 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 30 Dec 2010 23:29:28 +0000 (23:29 +0000)
  - Rewrite of flashproducer
    - Replaced ITimerService and ITimer with internal flash timers. Nested time-lines could not be controlled.
    - Dynamic performance dependent switch between progressive and interlaced rendering.
    - Provides DirectDraw interface for hardware acceleration, instead of GDI. (avoids slow GetDIBits and SetDIBits calls).

git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@315 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

core/core.vcxproj
core/core.vcxproj.filters
core/processor/draw_frame.cpp
core/producer/flash/FlashAxContainer.cpp
core/producer/flash/FlashAxContainer.h
core/producer/flash/TimerHelper.h [deleted file]
core/producer/flash/flash_producer.cpp
shell/shell.vcxproj

index 76ee5cd0eb65d8648ce7d4f036bb68fbbb6ecbb3..dc303fc699091cfcecabf0039535abf8274c0d18 100644 (file)
@@ -64,7 +64,7 @@
       <MinimalRebuild>false</MinimalRebuild>\r
       <ExceptionHandling>Async</ExceptionHandling>\r
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
+      <SmallerTypeCheck>false</SmallerTypeCheck>\r
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
       <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\r
       <RuntimeTypeInfo>true</RuntimeTypeInfo>\r
       <PrecompiledHeader>Use</PrecompiledHeader>\r
       <WarningLevel>Level4</WarningLevel>\r
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <MultiProcessorCompilation>false</MultiProcessorCompilation>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
       <PreprocessorDefinitions>NDEBUG;_VC80_UPGRADE=0x0710;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
       <WholeProgramOptimization>true</WholeProgramOptimization>\r
       <TreatWarningAsError>true</TreatWarningAsError>\r
     <ClInclude Include="producer\flash\cg_producer.h" />\r
     <ClInclude Include="producer\flash\FlashAxContainer.h" />\r
     <ClInclude Include="producer\flash\flash_producer.h" />\r
-    <ClInclude Include="producer\flash\TimerHelper.h" />\r
     <ClInclude Include="producer\frame_producer.h" />\r
     <ClInclude Include="producer\image\image_loader.h" />\r
     <ClInclude Include="producer\image\image_producer.h" />\r
     </ClCompile>\r
     <ClCompile Include="producer\flash\Flash9e_i.c">\r
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>\r
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>\r
     </ClCompile>\r
     <ClCompile Include="producer\flash\FlashAxContainer.cpp">\r
       <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../stdAfx.h</PrecompiledHeaderFile>\r
     </Midl>\r
     <Midl Include="producer\flash\Flash9e.IDL">\r
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>\r
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>\r
     </Midl>\r
   </ItemGroup>\r
   <ItemGroup>\r
index 3703b6719be530e5ffae2cfa7e53ffb6778a2a31..ddd2f1c55e66e8e62af40a4d8e9d182b0840bbc0 100644 (file)
     <ClInclude Include="producer\flash\FlashAxContainer.h">\r
       <Filter>Source\channel\producer\flash\interop</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="producer\flash\TimerHelper.h">\r
-      <Filter>Source\channel\producer\flash\interop</Filter>\r
-    </ClInclude>\r
     <ClInclude Include="consumer\bluefish\util.h">\r
       <Filter>Source\channel\consumer\bluefish</Filter>\r
     </ClInclude>\r
index c30db48626b5046ca150a4b9e72314d52f43d9ac..d1aa708558d85d10db4ccedf8fc2f75e9e0394e5 100644 (file)
@@ -92,6 +92,9 @@ void draw_frame::alpha(double value){impl_->image_transform_.alpha = value;}
 \r
 safe_ptr<draw_frame> draw_frame::interlace(const safe_ptr<draw_frame>& frame1, const safe_ptr<draw_frame>& frame2, video_mode::type mode)\r
 {                      \r
+       if(frame1 == frame2)\r
+               return frame1;\r
+\r
        auto my_frame1 = make_safe<draw_frame>(frame1);\r
        auto my_frame2 = make_safe<draw_frame>(frame2);\r
        if(mode == video_mode::upper)\r
index d11f3275686fb169faaf0820c54fd14ab6030591..6357d69f8a6dcc462587d8e936ac5d14e9ef03d0 100644 (file)
@@ -23,7 +23,6 @@
 #include "FlashAxContainer.h"\r
 #include "..\..\format\video_format.h"\r
 #include "flash_producer.h"\r
-#include "TimerHelper.h"\r
 \r
 using namespace ATL;\r
 \r
@@ -39,20 +38,19 @@ CComBSTR FlashAxContainer::flashGUID_(_T("{D27CDB6E-AE6D-11CF-96B8-444553540000}
 _ATL_FUNC_INFO fnInfoFlashCallEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_BSTR } };\r
 _ATL_FUNC_INFO fnInfoReadyStateChangeEvent = { CC_STDCALL, VT_EMPTY, 1, { VT_I4 } };\r
 \r
-FlashAxContainer::FlashAxContainer() : pflash_producer_(0), bInPlaceActive_(FALSE), pTimerHelper(0), lastTime_(0)\r
+FlashAxContainer::FlashAxContainer() : bInPlaceActive_(FALSE), m_lpDD4(0)\r
 {\r
        bInvalidRect_ = false;\r
        bCallSuccessful_ = false;\r
        bReadyToRender_ = false;\r
-       bIsEmpty_ = false;\r
-       bHasNewTiming_ = false;\r
 }\r
 FlashAxContainer::~FlashAxContainer()\r
 {\r
-//     ReleaseAll();\r
-       if(pTimerHelper != 0)\r
-               delete pTimerHelper;\r
-\r
+       if(m_lpDD4)\r
+       {\r
+               m_lpDD4->Release();\r
+               m_lpDD4 = nullptr;\r
+       }\r
        CASPAR_LOG(info) << "[FlashAxContainer] Destroyed";\r
 }\r
 \r
@@ -411,34 +409,15 @@ HRESULT STDMETHODCALLTYPE FlashAxContainer::ShowPropertyFrame()
 }\r
 \r
 \r
-///////////////////\r
-// IAdviseSink\r
-///////////////////\r
-void STDMETHODCALLTYPE FlashAxContainer::OnDataChange(FORMATETC* pFormatetc, STGMEDIUM* pStgmed)\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnDataChange\n"));\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnViewChange(DWORD dwAspect, LONG lindex)\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnViewChange\n"));\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnRename(IMoniker* pmk)\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnRename\n"));\r
-}\r
-\r
-void STDMETHODCALLTYPE FlashAxContainer::OnSave()\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnSave\n"));\r
-}\r
+//DirectDraw GUIDS\r
 \r
-void STDMETHODCALLTYPE FlashAxContainer::OnClose()\r
-{\r
-       ATLTRACE(_T("IAdviseSink::OnClose\n"));\r
-}\r
+DEFINE_GUID2(CLSID_DirectDraw,0xD7B70EE0,0x4340,0x11CF,0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35);\r
+DEFINE_GUID2(CLSID_DirectDraw7,0x3c305196,0x50db,0x11d3,0x9c,0xfe,0x00,0xc0,0x4f,0xd9,0x30,0xc5);\r
 \r
+DEFINE_GUID2(IID_IDirectDraw,0x6C14DB80,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60);\r
+DEFINE_GUID2(IID_IDirectDraw3,0x618f8ad4,0x8b7a,0x11d0,0x8f,0xcc,0x0,0xc0,0x4f,0xd9,0x18,0x9d);\r
+DEFINE_GUID2(IID_IDirectDraw4,0x9c59509a,0x39bd,0x11d1,0x8c,0x4a,0x00,0xc0,0x4f,0xd9,0x30,0xc5);\r
+DEFINE_GUID2(IID_IDirectDraw7,0x15e65ec0,0x3b9c,0x11d2,0xb9,0x2f,0x00,0x60,0x97,0x97,0xea,0x5b);\r
 \r
 ///////////////////\r
 // IServiceProvider\r
@@ -452,101 +431,38 @@ HRESULT STDMETHODCALLTYPE FlashAxContainer::QueryService( REFGUID rsid, REFIID r
        if (ppvObj == NULL)\r
                return E_POINTER;\r
        *ppvObj = NULL;\r
+       \r
+       HRESULT hr;\r
 \r
-       //TODO: The fullscreen-consumer requires that ths does NOT return an ITimerService\r
-       HRESULT hr = QueryInterface(riid, ppvObj);//E_NOINTERFACE;\r
-\r
-       return hr;\r
-}\r
-\r
-\r
-///////////////////\r
-// ITimerService\r
-///////////////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::CreateTimer(ITimer *pReferenceTimer, ITimer **ppNewTimer)\r
-{\r
-       ATLTRACE(_T("ITimerService::CreateTimer\n"));\r
-       if(pTimerHelper != 0)\r
-       {\r
-               delete pTimerHelper;\r
-               pTimerHelper = 0;\r
-       }\r
-       pTimerHelper = new TimerHelper();\r
-       return QueryInterface(__uuidof(ITimer), (void**) ppNewTimer);\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetNamedTimer(REFGUID rguidName, ITimer **ppTimer)\r
-{\r
-       ATLTRACE(_T("ITimerService::GetNamedTimer"));\r
-       if(ppTimer == NULL)\r
-               return E_POINTER;\r
-       else\r
-               *ppTimer = NULL;\r
-\r
-       return E_FAIL;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::SetNamedTimerReference(REFGUID rguidName, ITimer *pReferenceTimer)\r
-{\r
-       ATLTRACE(_T("ITimerService::SetNamedTimerReference"));\r
-       return S_OK;\r
-}\r
-\r
-///////////\r
-// ITimer\r
-///////////\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::Advise(VARIANT vtimeMin, VARIANT vtimeMax, VARIANT vtimeInterval, DWORD dwFlags, ITimerSink *pTimerSink, DWORD *pdwCookie)\r
-{\r
-       ATLTRACE(_T("Timer::Advise\n"));\r
-       if(pdwCookie == 0)\r
-               return E_POINTER;\r
-\r
-       if(pTimerHelper != 0)\r
-       {\r
-               pTimerHelper->Setup(vtimeMin.ulVal, vtimeInterval.ulVal, pTimerSink);\r
-               *pdwCookie = pTimerHelper->ID;\r
-               bHasNewTiming_ = true;\r
-\r
-               return S_OK;\r
-       }\r
-       else\r
-               return E_OUTOFMEMORY;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::Unadvise(/* [in] */ DWORD dwCookie)\r
-{\r
-       ATLTRACE(_T("Timer::Unadvice\n"));\r
-       if(pTimerHelper != 0)\r
+       // Author: Makarov Igor\r
+       // Transparent Flash Control in Plain C++ \r
+       // http://www.codeproject.com/KB/COM/flashcontrol.aspx \r
+       if (IsEqualGUID(rsid, IID_IDirectDraw3))\r
        {\r
-               pTimerHelper->pTimerSink = 0;\r
-               return S_OK;\r
+               if (!m_lpDD4)\r
+               {\r
+                       m_lpDD4 = new IDirectDraw4Ptr;\r
+                       hr = m_lpDD4->CreateInstance(CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER); \r
+                       if (FAILED(hr))\r
+                       {\r
+                               delete m_lpDD4;\r
+                               m_lpDD4 = NULL;\r
+                               CASPAR_LOG(warning) << "[FlashAxContainer] Failed to query DirectDraw Service";\r
+                               return E_NOINTERFACE;\r
+                       }\r
+               }\r
+               if (m_lpDD4 && m_lpDD4->GetInterfacePtr())\r
+               {\r
+                       *ppvObj = m_lpDD4->GetInterfacePtr();\r
+                       m_lpDD4->AddRef();\r
+                       return S_OK;\r
+               }\r
        }\r
-       else\r
-               return E_FAIL;\r
-}\r
 \r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::Freeze(/* [in] */ BOOL fFreeze)\r
-{\r
-       ATLTRACE(_T("Timer::Freeze\n"));\r
-       return S_OK;\r
-}\r
-\r
-HRESULT STDMETHODCALLTYPE FlashAxContainer::GetTime(/* [out] */ VARIANT *pvtime)\r
-{\r
-       ATLTRACE(_T("Timer::GetTime\n"));\r
-       if(pvtime == 0)\r
-               return E_POINTER;\r
-\r
-//     return E_NOTIMPL;\r
-       pvtime->lVal = 0;\r
-       return S_OK;\r
-}\r
+       //TODO: The fullscreen-consumer requires that ths does NOT return an ITimerService\r
+       hr = QueryInterface(riid, ppvObj);//E_NOINTERFACE;\r
 \r
-int FlashAxContainer::GetFPS() {\r
-       if(pTimerHelper != 0 && pTimerHelper->interval > 0)\r
-               return (1000 / pTimerHelper->interval);\r
-       \r
-       return 0;\r
+       return hr;\r
 }\r
 \r
 bool FlashAxContainer::IsReadyToRender() const {\r
@@ -603,7 +519,6 @@ void STDMETHODCALLTYPE FlashAxContainer::OnFlashCall(BSTR request)
        else if(str.find(TEXT("IsEmpty")) != std::wstring::npos)\r
        {\r
                ATLTRACE(_T("ShockwaveFlash::IsEmpty\n"));\r
-               bIsEmpty_ = true;\r
        }\r
        else if(str.find(TEXT("OnError")) != std::wstring::npos)\r
        {\r
@@ -855,23 +770,8 @@ bool FlashAxContainer::InvalidRectangle() const
        return bInvalidRect_;\r
 }\r
 \r
-void FlashAxContainer::Tick()\r
-{\r
-       if(pTimerHelper)\r
-       {\r
-               HRESULT result;\r
-               DWORD time = pTimerHelper->Invoke(); // Tick flash\r
-               if(time - lastTime_ >= 400)\r
-               {\r
-                       m_spInPlaceObjectWindowless->OnWindowMessage(WM_TIMER, 3, 0, &result);\r
-                       lastTime_ = time;\r
-               }\r
-       }\r
-}\r
-\r
 bool FlashAxContainer::CallFunction(const std::wstring& param)\r
 {\r
-       bIsEmpty_ = false;\r
        bCallSuccessful_ = false;\r
 \r
        CComPtr<IShockwaveFlash> spFlash;\r
@@ -885,11 +785,6 @@ bool FlashAxContainer::CallFunction(const std::wstring& param)
        return false;\r
 }\r
 \r
-bool FlashAxContainer::IsEmpty() const\r
-{\r
-       return bIsEmpty_;\r
-}\r
-\r
 // Receives the following messages:\r
 // 0           0x0000 ?\r
 // 275         0x0113 WM_TIMER\r
index 0d02d006f18957d3aae0a675c4bfeb54047aa3c6..e397911aa71366405d582b4fa3a5cc4a36dc481e 100644 (file)
 #include <tbb\atomic.h>\r
 \r
 #include "axflash.h"\r
+\r
+#include <ddraw.h>\r
+#include <comdef.h>\r
+\r
+#ifndef DEFINE_GUID2\r
+#define DEFINE_GUID2(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\r
+        const GUID name \\r
+                = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }\r
+#endif    \r
+\r
+_COM_SMARTPTR_TYPEDEF(IDirectDraw4, IID_IDirectDraw4);\r
+\r
 //#import "progid:ShockwaveFlash.ShockwaveFlash.9" no_namespace, named_guids\r
 \r
 namespace caspar { namespace core { namespace flash {\r
        \r
-class flash_producer;\r
-\r
-class TimerHelper;\r
-struct DirtyRect {\r
-       DirtyRect(LONG l, LONG t, LONG r, LONG b, bool e) : bErase(e), bWhole(false) { \r
-               rect.left = l;\r
-               rect.top = t;\r
-               rect.right = r;\r
-               rect.bottom = b; \r
-       }\r
-       DirtyRect(const RECT& rc, bool e) : bErase(e), bWhole(false)  {\r
-               rect.left = rc.left;\r
-               rect.top = rc.top;\r
-               rect.right = rc.right;\r
-               rect.bottom = rc.bottom; \r
-       }\r
-       explicit DirtyRect(bool b) : bWhole(b) {}\r
-\r
-       RECT    rect;\r
-       bool    bErase;\r
-       bool    bWhole;\r
-};\r
-\r
 extern _ATL_FUNC_INFO fnInfoFlashCallEvent;\r
 extern _ATL_FUNC_INFO fnInfoReadyStateChangeEvent;\r
 \r
@@ -82,9 +71,6 @@ class ATL_NO_VTABLE FlashAxContainer :
                public IOleInPlaceSiteWindowless,\r
                public IObjectWithSiteImpl<FlashAxContainer>,\r
                public IServiceProvider,\r
-               public IAdviseSink,\r
-               public ITimerService,\r
-               public ITimer,\r
                public IDispatchImpl<IDispatch>,\r
                public IDispEventSimpleImpl<0, FlashAxContainer, &DIID__IShockwaveFlashEvents>\r
 {\r
@@ -112,11 +98,6 @@ public:
 \r
                COM_INTERFACE_ENTRY(IServiceProvider)\r
 \r
-               COM_INTERFACE_ENTRY(IAdviseSink)\r
-\r
-               COM_INTERFACE_ENTRY(ITimerService)\r
-\r
-               COM_INTERFACE_ENTRY(ITimer)\r
        END_COM_MAP()\r
 \r
        BEGIN_SINK_MAP(FlashAxContainer)\r
@@ -180,13 +161,6 @@ public:
        STDMETHOD(OnFocus)(BOOL fGotFocus);\r
        STDMETHOD(ShowPropertyFrame)();\r
 \r
-// IAdviseSink\r
-       STDMETHOD_(void, OnDataChange)(FORMATETC* pFormatetc, STGMEDIUM* pStgmed);\r
-       STDMETHOD_(void, OnViewChange)(DWORD dwAspect, LONG lindex);\r
-       STDMETHOD_(void, OnRename)(IMoniker* pmk);\r
-       STDMETHOD_(void, OnSave)();\r
-       STDMETHOD_(void, OnClose)();\r
-\r
 // IServiceProvider\r
        STDMETHOD(QueryService)( REFGUID rsid, REFIID riid, void** ppvObj);\r
 \r
@@ -219,18 +193,6 @@ public:
                ATLTRACENOTIMPL(_T("IOleContainer::LockContainer"));\r
        }\r
 \r
-//ITimerService\r
-       STDMETHOD(CreateTimer)(ITimer *pReferenceTimer, ITimer **ppNewTimer);\r
-       STDMETHOD(GetNamedTimer)(REFGUID rguidName, ITimer **ppTimer);\r
-       STDMETHOD(SetNamedTimerReference)(REFGUID rguidName, ITimer *pReferenceTimer);\r
-\r
-//ITimer\r
-       STDMETHOD(Advise)(VARIANT vtimeMin, VARIANT vtimeMax, VARIANT vtimeInterval, DWORD dwFlags, ITimerSink *pTimerSink, DWORD *pdwCookie);\r
-       STDMETHOD(Unadvise)(DWORD dwCookie);\r
-       STDMETHOD(Freeze)(BOOL fFreeze);\r
-       STDMETHOD(GetTime)(VARIANT *pvtime);\r
-       int GetFPS();\r
-\r
        HRESULT CreateAxControl();\r
        void DestroyAxControl();\r
        HRESULT QueryControl(REFIID iid, void** ppUnk);\r
@@ -242,32 +204,25 @@ public:
        }\r
 \r
        bool InvalidRectangle() const;\r
-       void Tick();\r
        bool CallFunction(const std::wstring& param);\r
-       bool IsEmpty() const;\r
 \r
 //     static ATL::CComObject<FlashAxContainer>* CreateInstance();\r
 \r
        bool DrawControl(HDC targetDC);\r
 \r
-       TimerHelper* pTimerHelper;\r
-       tbb::atomic<bool> bInvalidRect_;\r
-       tbb::atomic<bool> bCallSuccessful_;\r
-       tbb::atomic<bool> bReadyToRender_;\r
-       tbb::atomic<bool> bIsEmpty_;\r
-       tbb::atomic<bool> bHasNewTiming_;\r
-       flash::flash_producer* pflash_producer_;\r
-       std::vector<DirtyRect> bDirtyRects_;\r
-\r
        HRESULT SetFormat(const video_format_desc&);\r
        bool IsReadyToRender() const;\r
        void EnterFullscreen();\r
 \r
        static bool CheckForFlashSupport();\r
 private:\r
+       IDirectDraw4Ptr *m_lpDD4;\r
        static CComBSTR flashGUID_;\r
 \r
-       DWORD lastTime_;\r
+       tbb::atomic<bool> bInvalidRect_;\r
+       tbb::atomic<bool> bCallSuccessful_;\r
+       tbb::atomic<bool> bReadyToRender_;\r
+\r
 //     state\r
        bool            bUIActive_;\r
        bool            bInPlaceActive_;\r
diff --git a/core/producer/flash/TimerHelper.h b/core/producer/flash/TimerHelper.h
deleted file mode 100644 (file)
index b409d13..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*\r
-* copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
-*\r
-*  This file is part of CasparCG.\r
-*\r
-*    CasparCG is free software: you can redistribute it and/or modify\r
-*    it under the terms of the GNU General Public License as published by\r
-*    the Free Software Foundation, either version 3 of the License, or\r
-*    (at your option) any later version.\r
-*\r
-*    CasparCG is distributed in the hope that it will be useful,\r
-*    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-*    GNU General Public License for more details.\r
-\r
-*    You should have received a copy of the GNU General Public License\r
-*    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
-*\r
-*/\r
-#pragma once\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-namespace caspar { namespace core { namespace flash {\r
-\r
-class TimerHelper : boost::noncopyable\r
-{\r
-public:\r
-       TimerHelper(){}\r
-       TimerHelper(DWORD first, DWORD interv, ITimerSink* pTS) : firstTime(first), interval(interv), currentTime(first), pTimerSink(pTS), ID(first){}\r
-       void Setup(DWORD first, DWORD interv, ITimerSink* pTS)\r
-       {\r
-               firstTime = first;\r
-               interval = interv;\r
-               currentTime = first;\r
-               pTimerSink = pTS;\r
-               ID = first;\r
-       }\r
-\r
-       DWORD Invoke()\r
-       {\r
-               if(pTimerSink != 0)\r
-               {\r
-                       VARIANT value;\r
-                       value.vt = VT_UI4;\r
-                       value.ulVal = currentTime;\r
-\r
-                       pTimerSink->OnTimer(value);\r
-                       currentTime += interval;\r
-               }\r
-               return currentTime;\r
-       }\r
-\r
-       DWORD firstTime;\r
-       DWORD interval;\r
-       DWORD currentTime;\r
-       ATL::CComPtr<ITimerSink> pTimerSink;\r
-       DWORD ID;\r
-};\r
-\r
-}}}
\ No newline at end of file
index 39a8bc36320518287cf1359c6702e745dccb7265..03d788170dfdc85fbcd6abe0cfeee90fe4ac9eda 100644 (file)
 \r
 #if defined(_MSC_VER)\r
 #pragma warning (disable : 4714) // marked as __forceinline not inlined\r
+#pragma warning(disable:4146)\r
 #endif\r
 \r
 #include "flash_producer.h"\r
 #include "FlashAxContainer.h"\r
-#include "TimerHelper.h"\r
 \r
 #include "../../format/video_format.h"\r
 \r
 #include "../../processor/draw_frame.h"\r
+#include "../../processor/frame_processor_device.h"\r
 \r
 #include <common/concurrency/executor.h>\r
 \r
@@ -45,21 +46,27 @@ extern __declspec(selectany) CAtlModule* _pAtlModule = &_AtlModule;
 class flash_renderer\r
 {\r
 public:\r
-       flash_renderer(const safe_ptr<frame_processor_device>& frame_processor, const std::wstring& filename) \r
-               : last_frame_(draw_frame::empty()), current_frame_(draw_frame::empty()), frame_processor_(frame_processor), filename_(filename),\r
-               hdc_(CreateCompatibleDC(0), DeleteDC), format_desc_(frame_processor->get_video_format_desc())\r
+       flash_renderer() : last_frame_(draw_frame::empty()), current_frame_(draw_frame::empty()), bmp_data_(nullptr), ax_(nullptr) {}\r
 \r
+       ~flash_renderer()\r
+       {               \r
+               if(ax_)\r
+               {\r
+                       ax_->DestroyAxControl();\r
+                       ax_->Release();\r
+               }\r
+               CASPAR_LOG(info) << print() << L" Ended";\r
+       }\r
+\r
+       void load(const std::shared_ptr<frame_processor_device>& frame_processor, const std::wstring& filename)\r
        {\r
+               filename_ = filename;\r
+               hdc_.reset(CreateCompatibleDC(0), DeleteDC);\r
+               frame_processor_ = frame_processor;\r
                CASPAR_LOG(info) << print() << L" Started";\r
-\r
-               ::OleInitialize(nullptr);\r
-\r
-               CComObject<FlashAxContainer>* object;           \r
-               if(FAILED(CComObject<FlashAxContainer>::CreateInstance(&object)))\r
-                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to create FlashAxContainer"));\r
                \r
-               object->AddRef();\r
-               ax_.Attach(object);\r
+               if(FAILED(CComObject<FlashAxContainer>::CreateInstance(&ax_)))\r
+                       BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to create FlashAxContainer"));\r
                \r
                if(FAILED(ax_->CreateAxControl()))\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Create FlashAxControl"));\r
@@ -79,174 +86,167 @@ public:
                                                                                                                \r
                if(FAILED(ax_->SetFormat(frame_processor_->get_video_format_desc())))  // stop if failed\r
                        BOOST_THROW_EXCEPTION(caspar_exception() << msg_info(bprint() + "Failed to Set Format"));\r
+               \r
+               format_desc_ = frame_processor->get_video_format_desc();\r
 \r
                BITMAPINFO info;\r
                memset(&info, 0, sizeof(BITMAPINFO));\r
                info.bmiHeader.biBitCount = 32;\r
                info.bmiHeader.biCompression = BI_RGB;\r
-#ifdef _MSC_VER\r
-       #pragma warning(disable:4146)\r
-#endif\r
                info.bmiHeader.biHeight = -format_desc_.height;\r
-#ifdef _MSC_VER\r
-       #pragma warning(default:4146)\r
-#endif\r
                info.bmiHeader.biPlanes = 1;\r
                info.bmiHeader.biSize = sizeof(BITMAPINFO);\r
                info.bmiHeader.biWidth = format_desc_.width;\r
 \r
-               bmp_.reset(CreateDIBSection((HDC)hdc_.get(), &info, DIB_RGB_COLORS, reinterpret_cast<void**>(&bmp_data_), 0, 0), DeleteObject);\r
-               SelectObject((HDC)hdc_.get(), bmp_.get());      \r
-       }\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
 \r
-       ~flash_renderer()\r
-       {\r
-               try\r
-               {\r
-                       ax_->DestroyAxControl();\r
-                       ax_.Release();\r
-               }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
-               \r
-               ::OleUninitialize();\r
-               CASPAR_LOG(info) << print() << L" Ended";\r
+               frame_buffer_.set_capacity(20);\r
+               for(int n = 0; n < frame_buffer_.capacity()/2; ++n)\r
+                       frame_buffer_.try_push(draw_frame::empty());\r
+               is_running_ = true;\r
        }\r
 \r
        void param(const std::wstring& param) \r
-       {                       \r
-               for(size_t retries = 0; !ax_->CallFunction(param); ++retries)\r
-               {\r
-                       CASPAR_LOG(debug) << print() << L" Retrying. Count: " << retries;\r
-                       if(retries > 3)\r
-                               BOOST_THROW_EXCEPTION(operation_failed() << arg_name_info("param") << arg_value_info(narrow(param)) << msg_info(narrow(print())));\r
-               }\r
+       {               \r
+               params_.push(param);\r
        }\r
                \r
-       void render()\r
-       {                \r
-               bool is_progressive = format_desc_.mode == video_mode::progressive || (ax_->GetFPS() - format_desc_.fps/2 == 0);\r
-               \r
-               safe_ptr<draw_frame> frame = render_frame();\r
-               if(!is_progressive)\r
-                       frame = draw_frame::interlace(frame, render_frame(), format_desc_.mode);\r
-                       \r
-               frame_buffer_.try_push(std::move(frame));\r
+       void tick()\r
+       {               \r
+               std::wstring param;\r
+               if(params_.try_pop(param))\r
+               {\r
+                       for(size_t retries = 0; !ax_->CallFunction(param); ++retries)\r
+                       {\r
+                               CASPAR_LOG(debug) << print() << L" Retrying. Count: " << retries;\r
+                               if(retries > 3)\r
+                                       CASPAR_LOG(warning) << "Flash Function Call Failed. Param: " << param;\r
+                       }\r
+               }       \r
+\r
+               if(!is_running_)\r
+                       PostQuitMessage(0);\r
        }\r
 \r
-       safe_ptr<draw_frame> render_frame()\r
+       void render()\r
        {\r
-               if(!ax_->IsEmpty())\r
-                       ax_->Tick();\r
-               \r
                if(ax_->IsReadyToRender() && ax_->InvalidRectangle())\r
-               {\r
-                       std::fill_n(bmp_data_, format_desc_.size, 0);                   \r
-                       ax_->DrawControl((HDC)hdc_.get());\r
+               {                       \r
+                       std::fill_n(bmp_data_, format_desc_.size, 0);\r
+                       ax_->DrawControl(static_cast<HDC>(hdc_.get()));\r
                \r
                        auto frame = frame_processor_->create_frame();\r
                        std::copy_n(bmp_data_, format_desc_.size, frame->image_data().begin());\r
                        current_frame_ = frame;\r
+               }                               \r
+               frame_buffer_.try_push(current_frame_);\r
+       }\r
+               \r
+       safe_ptr<draw_frame> get_frame(video_mode::type mode)\r
+       {               \r
+               frame_buffer_.try_pop(last_frame_);\r
+               auto frame1 = last_frame_;\r
+               auto frame2 = frame1;\r
+               if(mode != video_mode::progressive && frame_buffer_.size() > frame_buffer_.capacity()/2) // Regulate between interlaced and progressive\r
+               {\r
+                       frame_buffer_.try_pop(last_frame_);\r
+                       frame2 = last_frame_;\r
                }\r
-               return current_frame_;\r
+               return draw_frame::interlace(frame1, frame2, mode);\r
        }\r
        \r
-       bool try_pop(safe_ptr<draw_frame>& dest)\r
+       void stop()\r
        {\r
-               std::shared_ptr<draw_frame> temp;\r
-               bool result = frame_buffer_.try_pop(temp);\r
-               if(temp)\r
-                       last_frame_ = safe_ptr<draw_frame>(std::move(temp));\r
-               dest = last_frame_;\r
-               return result;\r
+               is_running_ = false;\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
 private:\r
-       const std::wstring filename_;\r
-       const safe_ptr<frame_processor_device> frame_processor_;\r
-       const video_format_desc format_desc_;\r
+       tbb::atomic<bool> is_running_;\r
+       std::wstring filename_;\r
+       std::shared_ptr<frame_processor_device> frame_processor_;\r
+       video_format_desc format_desc_;\r
        \r
        unsigned char* bmp_data_;\r
        \r
        std::shared_ptr<void> hdc_;\r
        std::shared_ptr<void> bmp_;\r
 \r
-       CComPtr<FlashAxContainer> ax_;\r
-       tbb::concurrent_bounded_queue<std::shared_ptr<draw_frame>> frame_buffer_;       \r
+       CComObject<FlashAxContainer>* ax_;\r
+       tbb::concurrent_bounded_queue<safe_ptr<draw_frame>> frame_buffer_;      \r
        safe_ptr<draw_frame> last_frame_;\r
        safe_ptr<draw_frame> current_frame_;\r
+\r
+       tbb::concurrent_queue<std::wstring> params_;\r
 };\r
 \r
 struct flash_producer::implementation\r
 {      \r
-       implementation(const std::wstring& filename) : filename_(filename)\r
+       implementation(const std::wstring& filename) : filename_(filename), renderer_(std::make_shared<flash_renderer>())\r
        {       \r
                if(!boost::filesystem::exists(filename))\r
                        BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename)));\r
        }\r
 \r
-       ~implementation() \r
+       ~implementation()\r
        {\r
-               executor_.invoke([this]{renderer_.reset();});\r
+               renderer_->stop();\r
        }\r
        \r
        void param(const std::wstring& param) \r
        {       \r
-               executor_.begin_invoke([=]\r
-               {\r
-                       if(!factory_)\r
-                               BOOST_THROW_EXCEPTION(invalid_operation() << msg_info(narrow(print()) + "Uninitialized."));\r
-                       if(!renderer_)\r
-                       {\r
-                               renderer_.reset(factory_());\r
-                               for(int n = 0; n < 8; ++n)\r
-                                       render_frame();\r
-                       }\r
-                       renderer_->param(param);\r
-               });\r
+               renderer_->param(param);\r
        }\r
        \r
-       virtual safe_ptr<draw_frame> receive()\r
+       void run()\r
        {\r
-               auto frame = draw_frame::empty();\r
-               if(renderer_ && renderer_->try_pop(frame)) // Only render again if frame was removed from buffer.               \r
-                       executor_.begin_invoke([this]{render_frame();});        \r
-               else\r
-                       CASPAR_LOG(trace) << print() << " underflow.";\r
-               return frame;\r
-       }\r
+               CASPAR_LOG(info) << print() << " started.";\r
 \r
-       virtual void render_frame()\r
-       {\r
-               try\r
-               {\r
-                       renderer_->render();\r
-               }\r
-               catch(...)\r
-               {\r
-                       renderer_.reset();\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
+               ::OleInitialize(nullptr);\r
+               \r
+               volatile auto keep_alive = renderer_;\r
+               renderer_->load(frame_processor_, filename_);\r
+\r
+               MSG msg;\r
+               while(GetMessage(&msg, 0, 0, 0))\r
+               {               \r
+                       if(msg.message == WM_USER + 1)\r
+                               renderer_->render();\r
+\r
+                       TranslateMessage(&msg);\r
+                       DispatchMessage(&msg);\r
+\r
+                       renderer_->tick();              \r
                }\r
+\r
+               renderer_ = nullptr;\r
+\r
+               ::OleUninitialize();\r
+\r
+               CASPAR_LOG(info) << print() << " ended.";\r
        }\r
 \r
        virtual void initialize(const safe_ptr<frame_processor_device>& frame_processor)\r
        {\r
-               factory_ = [=]{return new flash_renderer(frame_processor, filename_);};\r
-               executor_.start();\r
+               frame_processor_ = frame_processor;\r
+               thread_ = boost::thread([this]{run();});\r
+       }\r
+\r
+       virtual safe_ptr<draw_frame> receive()\r
+       {\r
+               return renderer_->get_frame(frame_processor_->get_video_format_desc().mode);\r
        }\r
        \r
-       std::wstring print() const{ return L"flash[" + boost::filesystem::wpath(filename_).filename() + L"]"; }\r
+       boost::thread thread_;\r
+\r
+       std::shared_ptr<flash_renderer> renderer_;\r
+       std::shared_ptr<frame_processor_device> frame_processor_;\r
        \r
+       std::wstring print() const{ return L"flash[" + boost::filesystem::wpath(filename_).filename() + L"]"; } \r
        std::wstring filename_;\r
-       std::function<flash_renderer*()> factory_;\r
-\r
-       std::unique_ptr<flash_renderer> renderer_;\r
-       executor executor_;\r
 };\r
 \r
 flash_producer::flash_producer(flash_producer&& other) : impl_(std::move(other.impl_)){}\r
index 173f8cbd71bb0613e13da545a35f075a677cd949..61643c975d44f2ffa7e90ef48d1473a2e6c3c2c5 100644 (file)
@@ -92,7 +92,7 @@
       <MinimalRebuild>false</MinimalRebuild>\r
       <ExceptionHandling>Async</ExceptionHandling>\r
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
+      <SmallerTypeCheck>false</SmallerTypeCheck>\r
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
       <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>\r
       <RuntimeTypeInfo>true</RuntimeTypeInfo>\r
       <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
     </ClCompile>\r
     <Link>\r
-      <AdditionalDependencies>BlueHancUtils_d.lib;sfml-audio-d.lib;sfml-window-d.lib;sfml-graphics-d.lib;OpenGL32.lib;FreeImage.lib;GLee.lib;Winmm.lib;Ws2_32.lib;BlueVelvet3_d.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;swscale-0.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+      <AdditionalDependencies>dxguid.lib;BlueHancUtils_d.lib;sfml-audio-d.lib;sfml-window-d.lib;sfml-graphics-d.lib;OpenGL32.lib;FreeImage.lib;GLee.lib;Winmm.lib;Ws2_32.lib;BlueVelvet3_d.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;swscale-0.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
       <Version>\r
       </Version>\r
       <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
       </Command>\r
     </PreLinkEvent>\r
     <Link>\r
-      <AdditionalDependencies>BlueHancUtils.lib;sfml-audio.lib;sfml-window.lib;sfml-graphics.lib;OpenGL32.lib;FreeImage.lib;Winmm.lib;Ws2_32.lib;Bluevelvet3.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;SWSCALE-0.lib;tbb.lib;Glee.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
+      <AdditionalDependencies>dxguid.lib; BlueHancUtils.lib;sfml-audio.lib;sfml-window.lib;sfml-graphics.lib;OpenGL32.lib;FreeImage.lib;Winmm.lib;Ws2_32.lib;Bluevelvet3.lib;avformat-52.lib;avcodec-52.lib;avutil-50.lib;SWSCALE-0.lib;tbb.lib;Glee.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
       <Version>\r
       </Version>\r
       <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r