<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
<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
\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
#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
_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
}\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
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
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
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
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
#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
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
\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
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
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
}\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
+++ /dev/null
-/*\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
\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
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
\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
<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