<ItemGroup>\r
<ClInclude Include="assert.h" />\r
<ClInclude Include="compiler\vs\disable_silly_warnings.h" />\r
- <ClInclude Include="concurrency\com_context.h" />\r
+ <ClInclude Include="concurrency\defer.h" />\r
<ClInclude Include="concurrency\executor.h" />\r
<ClInclude Include="concurrency\lock.h" />\r
<ClInclude Include="diagnostics\graph.h" />\r
<ClInclude Include="os\windows\system_info.h">\r
<Filter>source\os\windows</Filter>\r
</ClInclude>\r
- <ClInclude Include="concurrency\com_context.h">\r
- <Filter>source\concurrency</Filter>\r
- </ClInclude>\r
<ClInclude Include="memory\memshfl.h">\r
<Filter>source\memory</Filter>\r
</ClInclude>\r
<ClInclude Include="reactive.h">\r
<Filter>source</Filter>\r
</ClInclude>\r
+ <ClInclude Include="concurrency\defer.h">\r
+ <Filter>source\concurrency</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\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
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "executor.h"\r
-\r
-#include "../log.h"\r
-#include "../exception/exceptions.h"\r
-\r
-#define NOMINMAX\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include <Windows.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-#include <boost/thread/future.hpp>\r
-\r
-#include <functional>\r
-\r
-namespace caspar {\r
-\r
-template<typename T>\r
-class com_context : public executor\r
-{\r
- std::unique_ptr<T> instance_;\r
-public:\r
- com_context(const std::wstring& name) : executor(name)\r
- {\r
- executor::begin_invoke([]\r
- {\r
- ::CoInitialize(nullptr);\r
- });\r
- }\r
-\r
- ~com_context()\r
- {\r
- if(!executor::begin_invoke([&]\r
- {\r
- instance_.reset(nullptr);\r
- ::CoUninitialize();\r
- }).timed_wait(boost::posix_time::milliseconds(500)))\r
- {\r
- CASPAR_LOG(error) << L"[com_contex] Timer expired, deadlock detected and released, leaking resources.";\r
- }\r
- }\r
- \r
- void reset(const std::function<T*()>& factory = nullptr)\r
- {\r
- executor::invoke([&]\r
- {\r
- instance_.reset();\r
- if(factory)\r
- instance_.reset(factory());\r
- });\r
- }\r
-\r
- T& operator*() const \r
- {\r
- if(instance_ == nullptr)\r
- BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Tried to access null context."));\r
-\r
- return *instance_.get();\r
- } // noexcept\r
-\r
- T* operator->() const \r
- {\r
- if(instance_ == nullptr)\r
- BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("Tried to access null context."));\r
- return instance_.get();\r
- } // noexcept\r
-\r
- T* get() const\r
- {\r
- return instance_.get();\r
- } // noexcept\r
-\r
- operator bool() const {return get() != nullptr;}\r
-};\r
-\r
-}
\ No newline at end of file
--- /dev/null
+#pragma once\r
+\r
+#include <functional>\r
+#include <memory>\r
+\r
+#include <boost/thread/future.hpp>\r
+\r
+namespace caspar {\r
+ \r
+template<typename F>\r
+auto defer(F&& f) -> boost::unique_future<decltype(f())>\r
+{ \r
+ typedef boost::promise<decltype(f())> promise_t;\r
+ auto p = new promise_t();\r
+\r
+ auto func = [=](promise_t&) mutable\r
+ {\r
+ std::unique_ptr<promise_t> guard(p);\r
+ p->set_value(f());\r
+ };\r
+\r
+ p->set_wait_callback(std::function<void(promise_t&)>(func));\r
+\r
+ return p->get_future();\r
+}\r
+\r
+\r
+}
\ No newline at end of file
<ClInclude Include="mixer\gpu\image\image_mixer.h" />\r
<ClInclude Include="mixer\gpu\image\image_shader.h" />\r
<ClInclude Include="mixer\gpu\accelerator.h" />\r
- <ClInclude Include="mixer\gpu\read_frame.h" />\r
<ClInclude Include="mixer\gpu\shader.h" />\r
<ClInclude Include="mixer\gpu\write_frame.h" />\r
<ClInclude Include="mixer\image\blend_modes.h" />\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="mixer\gpu\read_frame.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
<ClCompile Include="mixer\gpu\shader.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../StdAfx.h</PrecompiledHeaderFile>\r
<ClInclude Include="frame\draw_frame.h">\r
<Filter>source\frame</Filter>\r
</ClInclude>\r
- <ClInclude Include="mixer\gpu\read_frame.h">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClInclude>\r
<ClInclude Include="mixer\gpu\write_frame.h">\r
<Filter>source\mixer\gpu</Filter>\r
</ClInclude>\r
<ClCompile Include="frame\data_frame.cpp">\r
<Filter>source\frame</Filter>\r
</ClCompile>\r
- <ClCompile Include="mixer\gpu\read_frame.cpp">\r
- <Filter>source\mixer\gpu</Filter>\r
- </ClCompile>\r
<ClCompile Include="mixer\gpu\write_frame.cpp">\r
<Filter>source\mixer\gpu</Filter>\r
</ClCompile>\r
GL(glReadPixels(0, 0, width_, height_, FORMAT[stride_], TYPE[stride_], NULL));\r
GL(glBindTexture(GL_TEXTURE_2D, 0));\r
dest->unbind();\r
+ GL(glFlush());\r
}, high_priority);\r
}\r
};\r
#include "../device_buffer.h"\r
\r
#include <common/gl/gl_check.h>\r
+#include <common/concurrency/defer.h>\r
\r
#include <core/frame/frame_transform.h>\r
#include <core/frame/pixel_format.h>\r
{\r
}\r
\r
- boost::unique_future<safe_ptr<host_buffer>> operator()(std::vector<layer> layers, const video_format_desc& format_desc)\r
+ boost::unique_future<safe_ptr<boost::iterator_range<const uint8_t*>>> operator()(std::vector<layer> layers, const video_format_desc& format_desc)\r
{ \r
- return ogl_->begin_invoke([=]() mutable -> safe_ptr<host_buffer>\r
+ boost::shared_future<safe_ptr<host_buffer>> buffer = ogl_->begin_invoke([=]() mutable -> safe_ptr<host_buffer>\r
{\r
auto draw_buffer = create_mixer_buffer(4, format_desc);\r
\r
draw_buffer->copy_to(result); \r
return result;\r
});\r
+\r
+ return defer([=]() mutable -> safe_ptr<boost::iterator_range<const uint8_t*>>\r
+ {\r
+ auto ptr = reinterpret_cast<const uint8_t*>(buffer.get()->data()); // ->data() can block OpenGL thread, defer it as long as possible.\r
+ return make_safe<boost::iterator_range<const uint8_t*>>(ptr, ptr + buffer.get()->size());\r
+ });\r
}\r
\r
private:\r
{ \r
}\r
\r
- boost::unique_future<safe_ptr<host_buffer>> render(const video_format_desc& format_desc)\r
+ boost::unique_future<safe_ptr<boost::iterator_range<const uint8_t*>>> render(const video_format_desc& format_desc)\r
{\r
return renderer_(std::move(layers_), format_desc);\r
}\r
void image_mixer::begin(draw_frame& frame){impl_->begin(frame);}\r
void image_mixer::visit(write_frame& frame){impl_->visit(frame);}\r
void image_mixer::end(){impl_->end();}\r
-boost::unique_future<safe_ptr<host_buffer>> image_mixer::operator()(const video_format_desc& format_desc){return impl_->render(format_desc);}\r
+boost::unique_future<safe_ptr<boost::iterator_range<const uint8_t*>>> image_mixer::operator()(const video_format_desc& format_desc){return impl_->render(format_desc);}\r
void image_mixer::begin_layer(blend_mode blend_mode){impl_->begin_layer(blend_mode);}\r
void image_mixer::end_layer(){impl_->end_layer();}\r
\r
void begin_layer(blend_mode blend_mode);\r
void end_layer();\r
\r
- virtual boost::unique_future<safe_ptr<class host_buffer>> operator()(const struct video_format_desc& format_desc) override;\r
+ virtual boost::unique_future<safe_ptr<boost::iterator_range<const uint8_t*>>> operator()(const struct video_format_desc& format_desc) override;\r
\r
private:\r
struct impl;\r
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\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
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "read_frame.h"\r
-\r
-#include "host_buffer.h"\r
-\r
-#include "../../video_format.h"\r
-#include "../../frame/pixel_format.h"\r
- \r
-namespace caspar { namespace core {\r
- \r
-struct read_frame::impl : boost::noncopyable\r
-{\r
- boost::unique_future<safe_ptr<gpu::host_buffer>> image_data_;\r
- const audio_buffer audio_data_;\r
- const video_format_desc video_desc_;\r
- pixel_format_desc pixel_desc_;\r
- const void* tag_;\r
-\r
-public:\r
- impl(const void* tag, boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
- : tag_(tag)\r
- , image_data_(std::move(image_data))\r
- , audio_data_(std::move(audio_data))\r
- , video_desc_(format_desc)\r
- , pixel_desc_(core::pixel_format::bgra)\r
- {\r
- pixel_desc_.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));\r
- } \r
- \r
- const boost::iterator_range<const uint8_t*> image_data(int)\r
- {\r
- auto ptr = static_cast<const uint8_t*>(image_data_.get()->data());\r
- return boost::iterator_range<const uint8_t*>(ptr, ptr + image_data_.get()->size());\r
- }\r
-};\r
-\r
-read_frame::read_frame(const void* tag, boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
- : impl_(new impl(tag, std::move(image_data), std::move(audio_data), format_desc)){}\r
-const boost::iterator_range<const uint8_t*> read_frame::image_data(int index) const{ return impl_->image_data(index);}\r
-const audio_buffer& read_frame::audio_data() const{ return impl_->audio_data_;}\r
-const pixel_format_desc& read_frame::get_pixel_format_desc() const{ return impl_->pixel_desc_;}\r
-double read_frame::get_frame_rate() const {return impl_->video_desc_.fps;}\r
-int read_frame::width() const {return impl_->video_desc_.width;}\r
-int read_frame::height() const {return impl_->video_desc_.height;}\r
-const void* read_frame::tag() const{return impl_->tag_;}\r
-\r
-//#include <tbb/scalable_allocator.h>\r
-//#include <tbb/parallel_for.h>\r
-//#include <tbb/enumerable_thread_specific.h>\r
-//#define CACHED_BUFFER_SIZE 4096 \r
-//typedef unsigned int UINT;\r
-//\r
-//struct cache_buffer\r
-//{\r
-// cache_buffer() : data(scalable_aligned_malloc(CACHED_BUFFER_SIZE, 64)){}\r
-// ~cache_buffer() {scalable_aligned_free(data);}\r
-// void* data;\r
-//};\r
-//\r
-//void CopyFrame( void * pSrc, void * pDest, UINT width, UINT height, UINT pitch );\r
-//\r
-//void* copy_frame(void* dest, const safe_ptr<const data_frame>& frame)\r
-//{\r
-// auto src = frame->image_data().begin();\r
-// auto height = 720;\r
-// auto width4 = frame->image_data().size()/height;\r
-//\r
-// CASPAR_ASSERT(frame->image_data().size() % height == 0);\r
-// \r
-// tbb::affinity_partitioner ap;\r
-// tbb::parallel_for(tbb::blocked_range<int>(0, height), [&](tbb::blocked_range<int>& r)\r
-// {\r
-// CopyFrame(const_cast<uint8_t*>(src)+r.begin()*width4, reinterpret_cast<uint8_t*>(dest)+r.begin()*width4, width4, r.size(), width4);\r
-// }, ap);\r
-//\r
-// return dest;\r
-//}\r
-//\r
-//// CopyFrame( )\r
-////\r
-//// COPIES VIDEO FRAMES FROM USWC MEMORY TO WB SYSTEM MEMORY VIA CACHED BUFFER\r
-//// ASSUMES PITCH IS A MULTIPLE OF 64B CACHE LINE SIZE, WIDTH MAY NOT BE\r
-//// http://software.intel.com/en-us/articles/copying-accelerated-video-decode-frame-buffers/\r
-//void CopyFrame( void * pSrc, void * pDest, UINT width, UINT height, UINT pitch )\r
-//{\r
-// tbb::enumerable_thread_specific<cache_buffer> cache_buffers;\r
-//\r
-// void * pCacheBlock = cache_buffers.local().data;\r
-//\r
-// __m128i x0, x1, x2, x3;\r
-// __m128i *pLoad;\r
-// __m128i *pStore;\r
-// __m128i *pCache;\r
-// UINT x, y, yLoad, yStore;\r
-// UINT rowsPerBlock;\r
-// UINT width64;\r
-// UINT extraPitch; \r
-//\r
-// rowsPerBlock = CACHED_BUFFER_SIZE / pitch;\r
-// width64 = (width + 63) & ~0x03f;\r
-// extraPitch = (pitch - width64) / 16;\r
-//\r
-// pLoad = (__m128i *)pSrc;\r
-// pStore = (__m128i *)pDest;\r
-//\r
-// // COPY THROUGH 4KB CACHED BUFFER\r
-// for( y = 0; y < height; y += rowsPerBlock )\r
-// {\r
-// // ROWS LEFT TO COPY AT END\r
-// if( y + rowsPerBlock > height )\r
-// rowsPerBlock = height - y;\r
-//\r
-// pCache = (__m128i *)pCacheBlock;\r
-//\r
-// _mm_mfence(); \r
-// \r
-// // LOAD ROWS OF PITCH WIDTH INTO CACHED BLOCK\r
-// for( yLoad = 0; yLoad < rowsPerBlock; yLoad++ )\r
-// {\r
-// // COPY A ROW, CACHE LINE AT A TIME\r
-// for( x = 0; x < pitch; x +=64 )\r
-// {\r
-// x0 = _mm_stream_load_si128( pLoad +0 );\r
-// x1 = _mm_stream_load_si128( pLoad +1 );\r
-// x2 = _mm_stream_load_si128( pLoad +2 );\r
-// x3 = _mm_stream_load_si128( pLoad +3 );\r
-//\r
-// _mm_store_si128( pCache +0, x0 );\r
-// _mm_store_si128( pCache +1, x1 );\r
-// _mm_store_si128( pCache +2, x2 );\r
-// _mm_store_si128( pCache +3, x3 );\r
-//\r
-// pCache += 4;\r
-// pLoad += 4;\r
-// }\r
-// }\r
-//\r
-// _mm_mfence();\r
-//\r
-// pCache = (__m128i *)pCacheBlock;\r
-//\r
-// // STORE ROWS OF FRAME WIDTH FROM CACHED BLOCK\r
-// for( yStore = 0; yStore < rowsPerBlock; yStore++ )\r
-// {\r
-// // copy a row, cache line at a time\r
-// for( x = 0; x < width64; x +=64 )\r
-// {\r
-// x0 = _mm_load_si128( pCache );\r
-// x1 = _mm_load_si128( pCache +1 );\r
-// x2 = _mm_load_si128( pCache +2 );\r
-// x3 = _mm_load_si128( pCache +3 );\r
-//\r
-// _mm_stream_si128( pStore, x0 );\r
-// _mm_stream_si128( pStore +1, x1 );\r
-// _mm_stream_si128( pStore +2, x2 );\r
-// _mm_stream_si128( pStore +3, x3 );\r
-//\r
-// pCache += 4;\r
-// pStore += 4;\r
-// }\r
-//\r
-// pCache += extraPitch;\r
-// pStore += extraPitch;\r
-// }\r
-// }\r
-//}\r
-\r
-}}
\ No newline at end of file
+++ /dev/null
-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\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
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#pragma once\r
-\r
-#include "../../frame/data_frame.h"\r
-\r
-#include <common/memory/safe_ptr.h>\r
-#include <common/forward.h>\r
-#include <common/exception/exceptions.h>\r
-\r
-#include <core/mixer/audio/audio_mixer.h>\r
-\r
-#include <boost/noncopyable.hpp>\r
-#include <boost/range/iterator_range.hpp>\r
-\r
-#include <stdint.h>\r
-#include <memory>\r
-#include <vector>\r
-\r
-FORWARD1(boost, template<typename> class unique_future);\r
-FORWARD3(caspar, core, gpu, class host_buffer);\r
-\r
-namespace caspar { namespace core {\r
- \r
-class read_frame sealed : public data_frame\r
-{\r
-public:\r
- read_frame(const void* tag, boost::unique_future<safe_ptr<gpu::host_buffer>>&& image_data, audio_buffer&& audio_data, const struct video_format_desc& format_desc);\r
- \r
- // data_frame\r
-\r
- virtual const struct pixel_format_desc& get_pixel_format_desc() const override;\r
-\r
- virtual const boost::iterator_range<const uint8_t*> image_data(int index) const override;\r
- virtual const audio_buffer& audio_data() const override;\r
- \r
- virtual double get_frame_rate() const override;\r
-\r
- virtual int width() const override;\r
- virtual int height() const override;\r
-\r
- virtual const boost::iterator_range<uint8_t*> image_data(int index) override\r
- {\r
- BOOST_THROW_EXCEPTION(invalid_operation());\r
- }\r
- virtual audio_buffer& audio_data() override\r
- {\r
- BOOST_THROW_EXCEPTION(invalid_operation());\r
- }\r
- \r
- virtual const void* tag() const override; \r
-private:\r
- struct impl;\r
- std::shared_ptr<impl> impl_;\r
-};\r
-\r
-}}
\ No newline at end of file
write_frame::write_frame(write_frame&& other) : impl_(std::move(other.impl_)){}\r
write_frame& write_frame::operator=(write_frame&& other)\r
{\r
- write_frame temp(std::move(other));\r
- temp.swap(*this);\r
+ impl_ = std::move(other.impl_);\r
return *this;\r
}\r
void write_frame::swap(write_frame& other){impl_.swap(other.impl_);}\r
-\r
void write_frame::accept(core::frame_visitor& visitor){impl_->accept(*this, visitor);}\r
-\r
const pixel_format_desc& write_frame::get_pixel_format_desc() const{return impl_->desc_;}\r
const boost::iterator_range<const uint8_t*> write_frame::image_data(int index) const{return impl_->image_data(index);}\r
const audio_buffer& write_frame::audio_data() const{return impl_->audio_data_;}\r
#include <core/frame/frame_visitor.h>\r
\r
FORWARD1(boost, template<typename> class unique_future);\r
-FORWARD3(caspar, core, gpu, class host_buffer);\r
\r
namespace caspar { namespace core {\r
\r
virtual void begin_layer(blend_mode blend_mode) = 0;\r
virtual void end_layer() = 0;\r
\r
- virtual boost::unique_future<safe_ptr<gpu::host_buffer>> operator()(const struct video_format_desc& format_desc) = 0;\r
+ virtual boost::unique_future<safe_ptr<boost::iterator_range<const uint8_t*>>> operator()(const struct video_format_desc& format_desc) = 0;\r
};\r
\r
}}
\ No newline at end of file
\r
#include "gpu/image/image_mixer.h"\r
#include "gpu/accelerator.h"\r
-#include "gpu/read_frame.h"\r
#include "gpu/write_frame.h"\r
\r
#include <common/env.h>\r
#include <vector>\r
\r
namespace caspar { namespace core {\r
+\r
+struct mixed_frame : public data_frame\r
+{\r
+ mutable boost::unique_future<safe_ptr<boost::iterator_range<const uint8_t*>>> image_data_;\r
+ const audio_buffer audio_data_;\r
+ const video_format_desc video_desc_;\r
+ pixel_format_desc pixel_desc_;\r
+ const void* tag_;\r
+\r
+public:\r
+ mixed_frame(const void* tag, boost::unique_future<safe_ptr<boost::iterator_range<const uint8_t*>>>&& image_data, audio_buffer&& audio_data, const video_format_desc& format_desc) \r
+ : tag_(tag)\r
+ , image_data_(std::move(image_data))\r
+ , audio_data_(std::move(audio_data))\r
+ , video_desc_(format_desc)\r
+ , pixel_desc_(core::pixel_format::bgra)\r
+ {\r
+ pixel_desc_.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));\r
+ } \r
+ \r
+ const boost::iterator_range<const uint8_t*> image_data(int index = 0) const override\r
+ {\r
+ return *image_data_.get();\r
+ }\r
+ \r
+ const boost::iterator_range<uint8_t*> image_data(int) override\r
+ {\r
+ BOOST_THROW_EXCEPTION(invalid_operation());\r
+ }\r
+ \r
+ virtual const struct pixel_format_desc& get_pixel_format_desc() const override\r
+ {\r
+ return pixel_desc_;\r
+ }\r
+\r
+ virtual const audio_buffer& audio_data() const override\r
+ {\r
+ return audio_data_;\r
+ }\r
+\r
+ virtual audio_buffer& audio_data() override\r
+ {\r
+ BOOST_THROW_EXCEPTION(invalid_operation());\r
+ }\r
+\r
+ virtual double get_frame_rate() const override\r
+ {\r
+ return video_desc_.fps;\r
+ }\r
+\r
+ virtual int width() const override\r
+ {\r
+ return video_desc_.width;\r
+ }\r
+\r
+ virtual int height() const override\r
+ {\r
+ return video_desc_.height;\r
+ }\r
+\r
+ virtual const void* tag() const override\r
+ {\r
+ return tag_;\r
+ }\r
+};\r
\r
struct mixer::impl : boost::noncopyable\r
{ \r
auto image = (*image_mixer_)(format_desc);\r
auto audio = audio_mixer_(format_desc);\r
\r
- return make_safe<read_frame>(this, std::move(image), std::move(audio), format_desc); \r
+ return make_safe<mixed_frame>(this, std::move(image), std::move(audio), format_desc); \r
}\r
catch(...)\r
{\r
#include "../../ffmpeg/producer/muxer/frame_muxer.h"\r
#include "../../ffmpeg/producer/muxer/display_mode.h"\r
\r
-#include <common/concurrency/com_context.h>\r
+#include <common/concurrency/executor.h>\r
#include <common/diagnostics/graph.h>\r
#include <common/exception/exceptions.h>\r
#include <common/log.h>\r
\r
class decklink_producer_proxy : public core::frame_producer\r
{ \r
- safe_ptr<core::draw_frame> last_frame_;\r
- com_context<decklink_producer> context_;\r
- const uint32_t length_;\r
+ safe_ptr<core::draw_frame> last_frame_;\r
+ std::unique_ptr<decklink_producer> producer_;\r
+ const uint32_t length_;\r
+ executor executor_;\r
public:\r
-\r
explicit decklink_producer_proxy(const safe_ptr<core::frame_factory>& frame_factory, const core::video_format_desc& format_desc, size_t device_index, const std::wstring& filter_str, uint32_t length)\r
- : context_(L"decklink_producer[" + boost::lexical_cast<std::wstring>(device_index) + L"]")\r
+ : executor_(L"decklink_producer[" + boost::lexical_cast<std::wstring>(device_index) + L"]")\r
, last_frame_(core::draw_frame::empty())\r
, length_(length)\r
{\r
- context_.reset([&]{return new decklink_producer(format_desc, device_index, frame_factory, filter_str);}); \r
+ executor_.invoke([=]\r
+ {\r
+ CoInitialize(nullptr);\r
+ producer_.reset(new decklink_producer(format_desc, device_index, frame_factory, filter_str));\r
+ });\r
+ }\r
+\r
+ ~decklink_producer_proxy()\r
+ { \r
+ executor_.invoke([=]\r
+ {\r
+ producer_.reset();\r
+ CoUninitialize();\r
+ });\r
}\r
\r
// frame_producer\r
\r
virtual safe_ptr<core::draw_frame> receive(int flags) override\r
{\r
- auto frame = context_->get_frame(flags);\r
+ auto frame = producer_->get_frame(flags);\r
if(frame != core::draw_frame::late())\r
last_frame_ = frame;\r
return frame;\r
\r
std::wstring print() const override\r
{\r
- return context_->print();\r
+ return producer_->print();\r
}\r
\r
virtual boost::property_tree::wptree info() const override\r
<data-path>D:\casparcg\_data\</data-path>\r
<template-path>D:\casparcg\_templates\</template-path>\r
</paths>\r
- <blend-modes>false</blend-modes>\r
+ <blend-modes>true</blend-modes>\r
<log-level>trace</log-level>\r
<channels>\r
<channel>\r