</ItemDefinitionGroup>\r
<ItemGroup>\r
<ClInclude Include="compiler\vs\disable_silly_warnings.h" />\r
- <ClInclude Include="concurrency\concurrent_queue.h" />\r
<ClInclude Include="concurrency\executor.h" />\r
<ClInclude Include="concurrency\Thread.h" />\r
<ClInclude Include="config.h" />\r
<ClInclude Include="log\log.h" />\r
<ClInclude Include="stdafx.h" />\r
<ClInclude Include="utility\safe_ptr.h" />\r
- <ClInclude Include="utility\scope_exit.h" />\r
<ClInclude Include="utility\singleton_pool.h" />\r
<ClInclude Include="utility\string_convert.h" />\r
</ItemGroup>\r
<Filter Include="Source\exception">\r
<UniqueIdentifier>{35ca385e-c4db-4fe7-858b-0a0bb678675f}</UniqueIdentifier>\r
</Filter>\r
- <Filter Include="Source\io">\r
- <UniqueIdentifier>{f4b0d63f-3cb3-4ab4-a6b9-3f249204dd3f}</UniqueIdentifier>\r
- </Filter>\r
<Filter Include="Source\log">\r
<UniqueIdentifier>{3b529e9b-c729-4c8a-8166-0cb8d8030973}</UniqueIdentifier>\r
</Filter>\r
<Filter Include="Source\compiler\vs">\r
<UniqueIdentifier>{28c25c8a-1277-4d2c-9e85-5af33f9938ea}</UniqueIdentifier>\r
</Filter>\r
+ <Filter Include="Source\io">\r
+ <UniqueIdentifier>{f4b0d63f-3cb3-4ab4-a6b9-3f249204dd3f}</UniqueIdentifier>\r
+ </Filter>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="stdafx.cpp">\r
<ClCompile Include="exception\win32_exception.cpp">\r
<Filter>Source\exception</Filter>\r
</ClCompile>\r
- <ClCompile Include="concurrency\Thread.cpp">\r
- <Filter>Source\concurrency</Filter>\r
- </ClCompile>\r
<ClCompile Include="gl\frame_buffer_object.cpp">\r
<Filter>Source\gl</Filter>\r
</ClCompile>\r
<ClCompile Include="gl\shader_program.cpp">\r
<Filter>Source\gl</Filter>\r
</ClCompile>\r
+ <ClCompile Include="concurrency\Thread.cpp">\r
+ <Filter>Source\concurrency</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="stdafx.h">\r
<ClInclude Include="exception\win32_exception.h">\r
<Filter>Source\exception</Filter>\r
</ClInclude>\r
- <ClInclude Include="concurrency\Thread.h">\r
- <Filter>Source\concurrency</Filter>\r
- </ClInclude>\r
<ClInclude Include="concurrency\executor.h">\r
<Filter>Source\concurrency</Filter>\r
</ClInclude>\r
<ClInclude Include="utility\string_convert.h">\r
<Filter>Source\utility</Filter>\r
</ClInclude>\r
- <ClInclude Include="utility\scope_exit.h">\r
- <Filter>Source\utility</Filter>\r
- </ClInclude>\r
<ClInclude Include="gl\pixel_buffer_object.h">\r
<Filter>Source\gl</Filter>\r
</ClInclude>\r
<ClInclude Include="utility\safe_ptr.h">\r
<Filter>Source\utility</Filter>\r
</ClInclude>\r
- <ClInclude Include="concurrency\concurrent_queue.h">\r
+ <ClInclude Include="concurrency\Thread.h">\r
<Filter>Source\concurrency</Filter>\r
</ClInclude>\r
</ItemGroup>\r
+++ /dev/null
-#pragma once\r
-\r
-namespace caspar {\r
-\r
-template<typename T>\r
-class concurrent_bounded_queue_r\r
-{\r
- typedef tbb::concurrent_bounded_queue<std::shared_ptr<T>> queue_t;\r
-public:\r
- void push(T&& source) \r
- {\r
- queue_.push(std::make_shared<T>(std::forward<T>(source)));\r
- }\r
-\r
- void pop(T& destination)\r
- {\r
- std::shared_ptr<T> container;\r
- queue_.pop(container);\r
- destination = std::move(*container);\r
- }\r
-\r
- bool try_push(T&& source) \r
- {\r
- auto container = std::make_shared<T>(std::forward<T>(source));\r
- bool pushed = queue_.try_push(container);\r
- if(!pushed)\r
- source = std::move(*container);\r
- return pushed;\r
- }\r
-\r
- bool try_pop(T& destination) \r
- {\r
- std::shared_ptr<T> container;\r
- bool popped = queue_.try_pop(container);\r
- if(popped)\r
- destination = std::move(*container);\r
- return popped;\r
- }\r
-\r
- typename queue_t::size_type size() const {return queue_.size();}\r
-\r
- bool empty() const {return queue_.empty();}\r
-\r
- typename queue_t::size_type capacity() const \r
- {\r
- return queue_.capacity();\r
- }\r
-\r
- void set_capacity(typename queue_t::size_type new_capacity) \r
- {\r
- queue_.set_capacity(new_capacity);\r
- }\r
-\r
- void clear()\r
- {\r
- queue_.clear();\r
- }\r
-\r
- typename queue_t::allocator_type get_allocator() const { return queue_.get_allocator(); }\r
-\r
-private:\r
- queue_t queue_;\r
-};\r
-\r
-}
\ No newline at end of file
+++ /dev/null
-#pragma once\r
-\r
-#include <utility>\r
-#include <functional>\r
-\r
-#include <boost/noncopyable.hpp>\r
-\r
-namespace caspar\r
-{\r
- namespace detail \r
- {\r
- template<typename T>\r
- class scope_exit : boost::noncopyable\r
- {\r
- public: \r
- explicit scope_exit(T&& exitScope) : exitScope_(std::forward<T>(exitScope)){}\r
- ~scope_exit()\r
- {\r
- try\r
- {\r
- exitScope_();\r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- }\r
- }\r
- private:\r
- T exitScope_;\r
- }; \r
-\r
- template <typename T>\r
- scope_exit<T> create_scope_exit(T&& exitScope)\r
- {\r
- return scope_exit<T>(std::forward<T>(exitScope));\r
- }\r
- }\r
-}\r
-\r
-#define _CASPAR_EXIT_SCOPE_LINENAME_CAT(name, line) name##line\r
-#define _CASPAR_EXIT_SCOPE_LINENAME(name, line) _CASPAR_EXIT_SCOPE_LINENAME_CAT(name, line)\r
-#define CASPAR_SCOPE_EXIT(f) const auto& _CASPAR_EXIT_SCOPE_LINENAME(EXIT, __LINE__) = caspar::detail::create_scope_exit(f); _CASPAR_EXIT_SCOPE_LINENAME(EXIT, __LINE__)
\ No newline at end of file
//}\r
\r
template <typename T>\r
-inline T lexical_cast_or_default(const std::wstring str, T defaultValue = T())\r
+inline T lexical_cast_or_default(const std::wstring str, T fail_value = T())\r
{\r
try\r
{\r
- if(!str.empty())\r
- return boost::lexical_cast<T>(str);\r
+ return boost::lexical_cast<T>(str);\r
+ }\r
+ catch(boost::bad_lexical_cast&)\r
+ {\r
+ return fail_value;\r
}\r
- catch(...){}\r
- return defaultValue;\r
}\r
\r
}
\ No newline at end of file
#include "../common/utility/string_convert.h"\r
#include "../common/utility/safe_ptr.h"\r
//#include "../common/concurrency/executor.h" // Can't include this due to MSVC lambda bug\r
-#include "../common/concurrency/concurrent_queue.h"\r
\r
#include "../common/log/Log.h"\r
#include "../common/exception/exceptions.h"\r
\r
#include "channel.h"\r
\r
+#include "producer/layer.h"\r
+\r
+#include "consumer/frame_consumer_device.h"\r
+\r
+#include "processor/composite_frame.h"\r
+#include "processor/draw_frame.h"\r
+#include "processor/frame_processor_device.h"\r
+\r
+#include <common/concurrency/executor.h>\r
+\r
+#include <boost/thread.hpp>\r
+#include <boost/range/algorithm_ext/erase.hpp>\r
+\r
+#include <tbb/parallel_for.h>\r
+\r
#include <boost/noncopyable.hpp>\r
\r
#include <memory>\r
namespace caspar { namespace core {\r
\r
struct channel::implementation : boost::noncopyable\r
-{\r
-public:\r
- implementation(const safe_ptr<frame_producer_device>& producer_device, const safe_ptr<frame_processor_device>& processor_device, const safe_ptr<frame_consumer_device>& consumer_device)\r
- : producer_device_(producer_device), processor_device_(processor_device), consumer_device_(consumer_device)\r
+{ \r
+ implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) \r
+ : format_desc_(format_desc), processor_device_(frame_processor_device(format_desc)), consumer_device_(format_desc, consumers)\r
{\r
+ executor_.start();\r
+ executor_.begin_invoke([=]{tick();});\r
}\r
-\r
- ~implementation()\r
- {\r
- producer_device_->clear();\r
+ \r
+ void tick()\r
+ { \r
+ auto drawed_frame = draw();\r
+ auto future_frame = processor_device_->process(std::move(drawed_frame));\r
+ consumer_device_.consume(std::move(future_frame));\r
+\r
+ executor_.begin_invoke([=]{tick();});\r
}\r
\r
+ safe_ptr<draw_frame> draw()\r
+ { \r
+ std::vector<safe_ptr<draw_frame>> frames(layers_.size(), draw_frame::empty());\r
+ tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size()), \r
+ [&](const tbb::blocked_range<size_t>& r)\r
+ {\r
+ auto it = layers_.begin();\r
+ std::advance(it, r.begin());\r
+ for(size_t i = r.begin(); i != r.end(); ++i, ++it)\r
+ frames[i] = it->second.receive();\r
+ }); \r
+ boost::range::remove_erase(frames, draw_frame::eof());\r
+ boost::range::remove_erase(frames, draw_frame::empty());\r
+ return composite_frame(frames);\r
+ }\r
+\r
void load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay)\r
{\r
- producer_device_->load(render_layer, producer, autoplay);\r
+ producer->initialize(processor_device_);\r
+ executor_.begin_invoke([=]\r
+ {\r
+ auto it = layers_.insert(std::make_pair(render_layer, layer(render_layer))).first;\r
+ it->second.load(producer, autoplay);\r
+ });\r
}\r
-\r
+ \r
void preview(int render_layer, const safe_ptr<frame_producer>& producer)\r
{\r
- producer_device_->preview(render_layer, producer);\r
+ producer->initialize(processor_device_);\r
+ executor_.begin_invoke([=]\r
+ {\r
+ auto it = layers_.insert(std::make_pair(render_layer, layer(render_layer))).first;\r
+ it->second.preview(producer);\r
+ });\r
}\r
\r
void pause(int render_layer)\r
- {\r
- producer_device_->pause(render_layer);\r
+ { \r
+ executor_.begin_invoke([=]\r
+ { \r
+ auto it = layers_.find(render_layer);\r
+ if(it != layers_.end())\r
+ it->second.pause(); \r
+ });\r
}\r
\r
void play(int render_layer)\r
- {\r
- producer_device_->play(render_layer);\r
+ { \r
+ executor_.begin_invoke([=]\r
+ {\r
+ auto it = layers_.find(render_layer);\r
+ if(it != layers_.end())\r
+ it->second.play(); \r
+ });\r
}\r
\r
void stop(int render_layer)\r
- {\r
- producer_device_->stop(render_layer);\r
+ { \r
+ executor_.begin_invoke([=]\r
+ {\r
+ auto it = layers_.find(render_layer);\r
+ if(it != layers_.end()) \r
+ {\r
+ it->second.stop(); \r
+ if(it->second.empty())\r
+ layers_.erase(it);\r
+ }\r
+ });\r
}\r
\r
void clear(int render_layer)\r
{\r
- producer_device_->clear(render_layer);\r
+ executor_.begin_invoke([=]\r
+ { \r
+ auto it = layers_.find(render_layer);\r
+ if(it != layers_.end())\r
+ {\r
+ it->second.clear(); \r
+ layers_.erase(it);\r
+ }\r
+ });\r
}\r
-\r
+ \r
void clear()\r
{\r
- producer_device_->clear();\r
- }\r
- \r
+ executor_.begin_invoke([=]\r
+ { \r
+ layers_.clear();\r
+ });\r
+ } \r
+\r
boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const\r
{\r
- return producer_device_->foreground(render_layer);\r
+ return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>\r
+ { \r
+ auto it = layers_.find(render_layer);\r
+ return it != layers_.end() ? it->second.foreground() : frame_producer::empty();\r
+ });\r
}\r
-\r
+ \r
boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const\r
{\r
- return producer_device_->background(render_layer);\r
+ return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>\r
+ {\r
+ auto it = layers_.find(render_layer);\r
+ return it != layers_.end() ? it->second.background() : frame_producer::empty();\r
+ });\r
}\r
\r
- const video_format_desc& get_video_format_desc() const\r
- {\r
- return processor_device_->get_video_format_desc();\r
- }\r
+ mutable executor executor_;\r
+ \r
+ safe_ptr<frame_processor_device> processor_device_;\r
+ frame_consumer_device consumer_device_;\r
+ \r
+ std::map<int, layer> layers_; \r
\r
-private:\r
- const safe_ptr<frame_processor_device> processor_device_; // Destroyed last inorder to have all frames returned to their pools.\r
- const safe_ptr<frame_producer_device> producer_device_;\r
- const safe_ptr<frame_consumer_device> consumer_device_;\r
+ const video_format_desc format_desc_;\r
};\r
\r
channel::channel(channel&& other) : impl_(std::move(other.impl_)){}\r
-channel::channel(const safe_ptr<frame_producer_device>& producer_device, const safe_ptr<frame_processor_device>& processor_device, const safe_ptr<frame_consumer_device>& consumer_device)\r
- : impl_(new implementation(producer_device, processor_device, consumer_device)){}\r
+channel::channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers)\r
+ : impl_(new implementation(format_desc, consumers)){}\r
void channel::load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay){impl_->load(render_layer, producer, autoplay);}\r
void channel::preview(int render_layer, const safe_ptr<frame_producer>& producer){impl_->preview(render_layer, producer);}\r
void channel::pause(int render_layer){impl_->pause(render_layer);}\r
void channel::clear(){impl_->clear();}\r
boost::unique_future<safe_ptr<frame_producer>> channel::foreground(int render_layer) const{ return impl_->foreground(render_layer);}\r
boost::unique_future<safe_ptr<frame_producer>> channel::background(int render_layer) const{return impl_->background(render_layer);}\r
-const video_format_desc& channel::get_video_format_desc() const{ return impl_->get_video_format_desc();}\r
+const video_format_desc& channel::get_video_format_desc() const{ return impl_->format_desc_;}\r
\r
}}
\ No newline at end of file
#pragma once\r
\r
-#include "producer/frame_producer_device.h"\r
-#include "consumer/frame_consumer_device.h"\r
-#include "processor/frame_processor_device.h"\r
+#include "consumer/frame_consumer.h"\r
+#include "producer/frame_producer.h"\r
\r
#include <boost/noncopyable.hpp>\r
\r
{\r
public:\r
channel(channel&& other);\r
- channel(const safe_ptr<frame_producer_device>& producer_device, const safe_ptr<frame_processor_device>& processor_device, const safe_ptr<frame_consumer_device>& consumer_device);\r
+ channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
\r
void load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay = false);\r
void preview(int render_layer, const safe_ptr<frame_producer>& producer);\r
#include "DeckLinkAPI_h.h"\r
\r
#include "../../format/video_format.h"\r
-#include "../../producer/frame_producer_device.h"\r
\r
-#include "../../../common/concurrency/executor.h"\r
-#include "../../../common/exception/exceptions.h"\r
-#include "../../../common/utility/scope_exit.h"\r
+#include <common/concurrency/executor.h>\r
+#include <common/exception/exceptions.h>\r
\r
#include <tbb/concurrent_queue.h>\r
#include <boost/thread.hpp>\r
#include "frame_consumer_device.h"\r
\r
#include "../format/video_format.h"\r
-#include "../processor/write_frame.h"\r
-#include "../processor/frame_processor_device.h"\r
-#include "../../common/concurrency/executor.h"\r
+\r
+#include <common/concurrency/executor.h>\r
\r
#include <tbb/concurrent_queue.h>\r
#include <tbb/atomic.h>\r
\r
struct frame_consumer_device::implementation\r
{\r
+ typedef safe_ptr<const read_frame> frame_type;\r
public:\r
- implementation(const safe_ptr<frame_processor_device>& frame_processor, const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) \r
- : frame_processor_(frame_processor), consumers_(consumers), fmt_(format_desc)\r
+ implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) : consumers_(consumers), fmt_(format_desc)\r
{ \r
std::vector<size_t> depths;\r
boost::range::transform(consumers_, std::back_inserter(depths), std::mem_fn(&frame_consumer::buffer_depth));\r
max_depth_ = *boost::range::max_element(depths);\r
+ input_.set_capacity(3);\r
executor_.start();\r
executor_.begin_invoke([=]{tick();});\r
}\r
\r
void tick()\r
{\r
- process(frame_processor_->receive()); \r
- if(!consumers_.empty())\r
- executor_.begin_invoke([=]{tick();});\r
- }\r
+ boost::shared_future<frame_type> future_frame;\r
+ input_.pop(future_frame);\r
+ \r
+ auto frame = future_frame.get();\r
\r
- void process(const safe_ptr<const read_frame>& frame)\r
- { \r
buffer_.push_back(frame);\r
\r
clock_sync clock;\r
buffer_.pop_front();\r
}\r
\r
+ void consume(boost::unique_future<frame_type>&& frame)\r
+ { \r
+ input_.push(boost::shared_future<frame_type>(std::move(frame)));\r
+ }\r
+\r
+ tbb::concurrent_bounded_queue<boost::shared_future<frame_type>> input_;\r
+\r
executor executor_; \r
\r
size_t max_depth_;\r
\r
std::vector<safe_ptr<frame_consumer>> consumers_;\r
\r
- safe_ptr<frame_processor_device> frame_processor_;\r
-\r
const video_format_desc& fmt_;\r
};\r
\r
frame_consumer_device::frame_consumer_device(frame_consumer_device&& other) : impl_(std::move(other.impl_)){}\r
-frame_consumer_device::frame_consumer_device(const safe_ptr<frame_processor_device>& frame_processor, const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers)\r
- : impl_(new implementation(frame_processor, format_desc, consumers)){}\r
+frame_consumer_device::frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers)\r
+ : impl_(new implementation(format_desc, consumers)){}\r
+void frame_consumer_device::consume(boost::unique_future<safe_ptr<const read_frame>>&& future_frame) { impl_->consume(std::move(future_frame)); }\r
}}
\ No newline at end of file
\r
#include "../consumer/frame_consumer.h"\r
\r
+#include <common/utility/safe_ptr.h>\r
+\r
#include <vector>\r
\r
#include <boost/noncopyable.hpp>\r
\r
-namespace caspar { namespace core {\r
+#include <tbb/concurrent_queue.h>\r
\r
+#include <boost/thread/future.hpp>\r
+\r
+namespace caspar { namespace core {\r
+ \r
class frame_processor_device;\r
+class draw_frame;\r
\r
class frame_consumer_device : boost::noncopyable\r
{\r
public:\r
frame_consumer_device(frame_consumer_device&& other);\r
- frame_consumer_device(const safe_ptr<frame_processor_device>& frame_processor, const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
+ frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
+ void consume(boost::unique_future<safe_ptr<const read_frame>>&& future_frame);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
<ClInclude Include="producer\image\image_producer.h" />\r
<ClInclude Include="producer\image\image_scroll_producer.h" />\r
<ClInclude Include="producer\layer.h" />\r
- <ClInclude Include="producer\frame_producer_device.h" />\r
<ClInclude Include="producer\transition\transition_producer.h" />\r
<ClInclude Include="protocol\amcp\AMCPCommand.h" />\r
<ClInclude Include="protocol\amcp\AMCPCommandQueue.h" />\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\r
- <ClCompile Include="producer\frame_producer_device.cpp">\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- <PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
- </ClCompile>\r
<ClCompile Include="producer\transition\transition_producer.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<ClInclude Include="producer\flash\bitmap.h">\r
<Filter>Source\channel\producer\flash</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\layer.h">\r
- <Filter>Source\channel\producer</Filter>\r
- </ClInclude>\r
<ClInclude Include="consumer\frame_consumer_device.h">\r
<Filter>Source\channel\consumer</Filter>\r
</ClInclude>\r
- <ClInclude Include="producer\frame_producer_device.h">\r
- <Filter>Source\channel\producer</Filter>\r
- </ClInclude>\r
<ClInclude Include="server.h">\r
<Filter>Source</Filter>\r
</ClInclude>\r
<ClInclude Include="producer\ffmpeg\video\video_decoder.h">\r
<Filter>Source\channel\producer\ffmpeg\video</Filter>\r
</ClInclude>\r
+ <ClInclude Include="producer\layer.h">\r
+ <Filter>Source\channel</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ClCompile Include="StdAfx.cpp">\r
<ClCompile Include="producer\flash\bitmap.cpp">\r
<Filter>Source\channel\producer\flash</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\layer.cpp">\r
- <Filter>Source\channel\producer</Filter>\r
- </ClCompile>\r
<ClCompile Include="consumer\frame_consumer_device.cpp">\r
<Filter>Source\channel\consumer</Filter>\r
</ClCompile>\r
- <ClCompile Include="producer\frame_producer_device.cpp">\r
- <Filter>Source\channel\producer</Filter>\r
- </ClCompile>\r
<ClCompile Include="server.cpp">\r
<Filter>Source</Filter>\r
</ClCompile>\r
<ClCompile Include="producer\ffmpeg\video\video_decoder.cpp">\r
<Filter>Source\channel\producer\ffmpeg\video</Filter>\r
</ClCompile>\r
+ <ClCompile Include="producer\layer.cpp">\r
+ <Filter>Source\channel</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<Midl Include="consumer\decklink\DeckLinkAPI_v7_3.idl">\r
\r
struct frame_processor_device::implementation : boost::noncopyable\r
{ \r
- typedef boost::shared_future<safe_ptr<const read_frame>> output_type;\r
-\r
implementation(const video_format_desc& format_desc) : fmt_(format_desc), writing_(draw_frame::empty()), image_processor_(format_desc)\r
{ \r
- output_.set_capacity(3);\r
executor_.start();\r
}\r
\r
- void send(safe_ptr<draw_frame>&& frame)\r
+ boost::unique_future<safe_ptr<const read_frame>> process(safe_ptr<draw_frame>&& frame)\r
{ \r
- output_.push(executor_.begin_invoke([=]() -> safe_ptr<const read_frame>\r
+ return executor_.begin_invoke([=]() -> safe_ptr<const read_frame>\r
{ \r
auto result_frame = image_processor_.begin_pass();\r
writing_->process_image(image_processor_);\r
\r
result_frame->audio_data(result_audio);\r
return result_frame;\r
- }));\r
- }\r
-\r
- safe_ptr<const read_frame> receive()\r
- {\r
- output_type future;\r
- output_.pop(future);\r
- return future.get();\r
+ });\r
}\r
- \r
+ \r
safe_ptr<write_frame> create_frame(const pixel_format_desc& desc)\r
{\r
auto pool = &pools_[desc];\r
\r
executor executor_; \r
\r
- tbb::concurrent_bounded_queue<output_type> output_; \r
tbb::concurrent_unordered_map<pixel_format_desc, tbb::concurrent_bounded_queue<std::shared_ptr<write_frame>>, std::hash<pixel_format_desc>> pools_;\r
\r
const video_format_desc fmt_;\r
\r
frame_processor_device::frame_processor_device(frame_processor_device&& other) : impl_(std::move(other.impl_)){}\r
frame_processor_device::frame_processor_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
-void frame_processor_device::send(safe_ptr<draw_frame>&& frame){impl_->send(std::move(frame));}\r
-safe_ptr<const read_frame> frame_processor_device::receive(){return impl_->receive();}\r
+boost::unique_future<safe_ptr<const read_frame>> frame_processor_device::process(safe_ptr<draw_frame>&& frame){return impl_->process(std::move(frame));}\r
const video_format_desc& frame_processor_device::get_video_format_desc() const { return impl_->fmt_; }\r
safe_ptr<write_frame> frame_processor_device::create_frame(const pixel_format_desc& desc){ return impl_->create_frame(desc); } \r
safe_ptr<write_frame> frame_processor_device::create_frame(size_t width, size_t height, pixel_format::type pix_fmt)\r
\r
#include <common/utility/safe_ptr.h>\r
\r
+#include <tbb/concurrent_queue.h>\r
+\r
+#include <boost/thread/future.hpp>\r
+\r
#include <memory>\r
\r
namespace caspar { namespace core {\r
frame_processor_device(frame_processor_device&& other); // nothrow\r
frame_processor_device(const video_format_desc& format_desc);\r
\r
- void send(safe_ptr<draw_frame>&& frame); // nothrow\r
- safe_ptr<const read_frame> receive();\r
+ boost::unique_future<safe_ptr<const read_frame>> process(safe_ptr<draw_frame>&& frame); // nothrow\r
\r
safe_ptr<write_frame> create_frame(const pixel_format_desc& desc); \r
safe_ptr<write_frame> create_frame(size_t width, size_t height, pixel_format::type pix_fmt = pixel_format::bgra); \r
#include "../../format/video_format.h"\r
#include "../../processor/transform_frame.h"\r
#include "../../processor/draw_frame.h"\r
-#include "../../../common/utility/scope_exit.h"\r
#include "../../server.h"\r
\r
#include <tbb/mutex.h>\r
#include "input.h"\r
\r
#include "../../format/video_format.h"\r
-#include "../../../common/concurrency/concurrent_queue.h"\r
+\r
+#include <common/concurrency/executor.h>\r
\r
#include <tbb/concurrent_queue.h>\r
#include <tbb/queuing_mutex.h>\r
#pragma warning (disable : 4244)\r
#endif\r
\r
-#include "../../../common/concurrency/executor.h"\r
\r
extern "C" \r
{\r
\r
executor_.start();\r
executor_.begin_invoke([this]{read_file();});\r
- CASPAR_LOG(info) << print() << " Started";\r
+ CASPAR_LOG(info) << print() << " started.";\r
}\r
\r
~implementation()\r
{\r
- CASPAR_LOG(info) << print() << " Ended";\r
+ CASPAR_LOG(info) << print() << " ended.";\r
}\r
\r
std::shared_ptr<AVCodecContext> open_stream(int codec_type, int& s_index)\r
\r
if (av_read_frame(format_context_.get(), read_packet.get()) >= 0) // NOTE: read_packet is only valid until next call of av_safe_ptr<read_frame> or av_close_input_file\r
{\r
- auto packet = aligned_buffer(read_packet->data, read_packet->data + read_packet->size);\r
+ auto packet = std::make_shared<aligned_buffer>(read_packet->data, read_packet->data + read_packet->size);\r
if(read_packet->stream_index == video_s_index_) \r
{\r
- buffer_size_ += packet.size();\r
+ buffer_size_ += packet->size();\r
video_packet_buffer_.try_push(std::move(packet)); \r
}\r
else if(read_packet->stream_index == audio_s_index_) \r
{\r
- buffer_size_ += packet.size();\r
+ buffer_size_ += packet->size();\r
audio_packet_buffer_.try_push(std::move(packet));\r
}\r
}\r
return get_packet(audio_packet_buffer_);\r
}\r
\r
- aligned_buffer get_packet(concurrent_bounded_queue_r<aligned_buffer>& buffer)\r
+ aligned_buffer get_packet(tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>>& buffer)\r
{\r
- aligned_buffer packet;\r
+ std::shared_ptr<aligned_buffer> packet;\r
if(buffer.try_pop(packet))\r
{\r
- buffer_size_ -= packet.size();\r
+ buffer_size_ -= packet->size();\r
executor_.begin_invoke([this]{read_file();});\r
assert(executor_.size() < 8);\r
+ return std::move(*packet);\r
}\r
- return std::move(packet);\r
+ return aligned_buffer();\r
}\r
\r
bool is_eof() const\r
int video_s_index_;\r
int audio_s_index_;\r
\r
- concurrent_bounded_queue_r<aligned_buffer> video_packet_buffer_;\r
- concurrent_bounded_queue_r<aligned_buffer> audio_packet_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> video_packet_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<aligned_buffer>> audio_packet_buffer_;\r
\r
tbb::atomic<size_t> buffer_size_;\r
\r
#include "../../processor/composite_frame.h"\r
\r
#include <common/concurrency/executor.h>\r
-#include <common/concurrency/concurrent_queue.h>\r
\r
#include <boost/filesystem.hpp>\r
#include <boost/thread.hpp>\r
\r
bool try_pop(safe_ptr<draw_frame>& dest)\r
{\r
- bool result = frame_buffer_.try_pop(last_frame_);\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
}\r
const safe_ptr<bitmap> bmp_frame_; \r
\r
CComPtr<FlashAxContainer> ax_;\r
- concurrent_bounded_queue_r<safe_ptr<draw_frame>> frame_buffer_; \r
+ tbb::concurrent_bounded_queue<std::shared_ptr<draw_frame>> frame_buffer_; \r
safe_ptr<draw_frame> last_frame_;\r
safe_ptr<draw_frame> current_frame_;\r
};\r
+++ /dev/null
-#include "..\StdAfx.h"\r
-\r
-#include "frame_producer_device.h"\r
-\r
-#include "layer.h"\r
-\r
-#include "../processor/composite_frame.h"\r
-#include "../processor/draw_frame.h"\r
-#include "../processor/frame_processor_device.h"\r
-\r
-#include <common/concurrency/executor.h>\r
-\r
-#include <boost/thread.hpp>\r
-#include <boost/range/algorithm_ext/erase.hpp>\r
-\r
-#include <tbb/parallel_for.h>\r
- \r
-namespace caspar { namespace core {\r
- \r
-std::vector<safe_ptr<draw_frame>> receive(std::map<int, layer>& layers)\r
-{ \r
- std::vector<safe_ptr<draw_frame>> frames(layers.size(), draw_frame::empty());\r
- tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size()), \r
- [&](const tbb::blocked_range<size_t>& r)\r
- {\r
- auto it = layers.begin();\r
- std::advance(it, r.begin());\r
- for(size_t i = r.begin(); i != r.end(); ++i, ++it)\r
- frames[i] = it->second.receive();\r
- }); \r
- boost::range::remove_erase(frames, draw_frame::eof());\r
- boost::range::remove_erase(frames, draw_frame::empty());\r
- return frames;\r
-}\r
-\r
-struct frame_producer_device::implementation : boost::noncopyable\r
-{ \r
- implementation(const safe_ptr<frame_processor_device>& frame_processor) : frame_processor_(frame_processor)\r
- {\r
- executor_.start();\r
- executor_.begin_invoke([=]{tick();});\r
- }\r
- \r
- void tick()\r
- { \r
- frame_processor_->send(composite_frame(receive(layers_)));\r
- executor_.begin_invoke([=]{tick();});\r
- }\r
-\r
- void load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay)\r
- {\r
- producer->initialize(frame_processor_);\r
- executor_.begin_invoke([=]\r
- {\r
- auto it = layers_.insert(std::make_pair(render_layer, layer(render_layer))).first;\r
- it->second.load(producer, autoplay);\r
- });\r
- }\r
- \r
- void preview(int render_layer, const safe_ptr<frame_producer>& producer)\r
- {\r
- producer->initialize(frame_processor_);\r
- executor_.begin_invoke([=]\r
- {\r
- auto it = layers_.insert(std::make_pair(render_layer, layer(render_layer))).first;\r
- it->second.preview(producer);\r
- });\r
- }\r
-\r
- void pause(int render_layer)\r
- { \r
- executor_.begin_invoke([=]\r
- { \r
- auto it = layers_.find(render_layer);\r
- if(it != layers_.end())\r
- it->second.pause(); \r
- });\r
- }\r
-\r
- void play(int render_layer)\r
- { \r
- executor_.begin_invoke([=]\r
- {\r
- auto it = layers_.find(render_layer);\r
- if(it != layers_.end())\r
- it->second.play(); \r
- });\r
- }\r
-\r
- void stop(int render_layer)\r
- { \r
- executor_.begin_invoke([=]\r
- {\r
- auto it = layers_.find(render_layer);\r
- if(it != layers_.end()) \r
- {\r
- it->second.stop(); \r
- if(it->second.empty())\r
- layers_.erase(it);\r
- }\r
- });\r
- }\r
-\r
- void clear(int render_layer)\r
- {\r
- executor_.begin_invoke([=]\r
- { \r
- auto it = layers_.find(render_layer);\r
- if(it != layers_.end())\r
- {\r
- it->second.clear(); \r
- layers_.erase(it);\r
- }\r
- });\r
- }\r
- \r
- void clear()\r
- {\r
- executor_.begin_invoke([=]\r
- { \r
- layers_.clear();\r
- });\r
- } \r
-\r
- boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const\r
- {\r
- return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>\r
- { \r
- auto it = layers_.find(render_layer);\r
- return it != layers_.end() ? it->second.foreground() : frame_producer::empty();\r
- });\r
- }\r
- \r
- boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const\r
- {\r
- return executor_.begin_invoke([=]() -> safe_ptr<frame_producer>\r
- {\r
- auto it = layers_.find(render_layer);\r
- return it != layers_.end() ? it->second.background() : frame_producer::empty();\r
- });\r
- }\r
-\r
- mutable executor executor_;\r
- \r
- safe_ptr<frame_processor_device> frame_processor_;\r
- \r
- std::map<int, layer> layers_; \r
-};\r
-\r
-frame_producer_device::frame_producer_device(frame_producer_device&& other) : impl_(std::move(other.impl_)){}\r
-frame_producer_device::frame_producer_device(const safe_ptr<frame_processor_device>& frame_processor) : impl_(new implementation(frame_processor)){}\r
-void frame_producer_device::load(int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay){impl_->load(render_layer, producer, autoplay);}\r
-void frame_producer_device::preview(int render_layer, const safe_ptr<frame_producer>& producer){impl_->preview(render_layer, producer);}\r
-void frame_producer_device::pause(int render_layer){impl_->pause(render_layer);}\r
-void frame_producer_device::play(int render_layer){impl_->play(render_layer);}\r
-void frame_producer_device::stop(int render_layer){impl_->stop(render_layer);}\r
-void frame_producer_device::clear(int render_layer){impl_->clear(render_layer);}\r
-void frame_producer_device::clear(){impl_->clear();}\r
-boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::foreground(int render_layer) const {return impl_->foreground(render_layer);}\r
-boost::unique_future<safe_ptr<frame_producer>> frame_producer_device::background(int render_layer) const {return impl_->background(render_layer);}\r
-}}\r
+++ /dev/null
-#pragma once\r
-\r
-#include "frame_producer.h"\r
-\r
-#include "../format/video_format.h"\r
-\r
-#include <common/utility/safe_ptr.h>\r
-\r
-#include <boost/thread/future.hpp>\r
-\r
-#include <memory>\r
-\r
-namespace caspar { namespace core {\r
-\r
-class frame_producer;\r
-class frame_processor_device;\r
-class layer;\r
- \r
-class frame_producer_device : boost::noncopyable\r
-{ \r
-public:\r
- frame_producer_device(frame_producer_device&& other); // nothrow\r
- frame_producer_device(const safe_ptr<frame_processor_device>& frame_processor); // nothrow\r
- \r
- void load (int render_layer, const safe_ptr<frame_producer>& producer, bool autoplay = false); // throws if producer->initialize throws\r
- void preview(int render_layer, const safe_ptr<frame_producer>& producer); // throws if producer->initialize throws\r
- void pause (int render_layer); // nothrow\r
- void play (int render_layer); // nothrow\r
- void stop (int render_layer); // nothrow\r
- void clear (int render_layer); // nothrow\r
- void clear (); // nothrow\r
- \r
- boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const; // nothrow\r
- boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const; // nothrow\r
-private:\r
- struct implementation;\r
- std::shared_ptr<implementation> impl_;\r
-};\r
-typedef std::shared_ptr<frame_producer_device> frame_producer_device_ptr;\r
-\r
-}}\r
*/\r
\r
#include "../../StdAfx.h"\r
-#include "../../producer/frame_producer_device.h"\r
\r
#include "AMCPProtocolStrategy.h"\r
\r
#include "CIICommand.h"\r
\r
#include "../../consumer/frame_consumer.h"\r
-#include "../../producer/frame_producer_device.h"\r
\r
#include <common/concurrency/executor.h>\r
\r
#include "CLKProtocolStrategy.h"\r
\r
#include "..\..\producer\flash\cg_producer.h"\r
-#include "..\..\producer\frame_producer_device.h"\r
\r
#include <string>\r
#include <sstream>\r
\r
#include "CLKCommand.h"\r
#include "../../../common/io/ProtocolStrategy.h"\r
-#include "../../producer/frame_producer_device.h"\r
#include "../../channel.h"\r
\r
namespace caspar { namespace core { namespace CLK {\r
#include <boost/property_tree/ptree.hpp>\r
#include <boost/property_tree/xml_parser.hpp>\r
\r
-#include "producer/frame_producer_device.h"\r
#include "consumer/frame_consumer_device.h"\r
#include "processor/frame_processor_device.h"\r
\r
}\r
}\r
\r
- auto processor_device = make_safe<frame_processor_device>(format_desc);\r
- auto producer_device = make_safe<frame_producer_device>(processor_device);\r
- auto consumer_device = make_safe<frame_consumer_device>(processor_device, format_desc, consumers);\r
- channels_.push_back(channel(producer_device, processor_device, consumer_device));\r
+ channels_.push_back(channel(format_desc, consumers));\r
}\r
}\r
\r
\r
#include "channel.h"\r
\r
-#include "producer/frame_producer_device.h"\r
-\r
#include <common/exception/exceptions.h>\r
\r
#include <boost/noncopyable.hpp>\r