<ClInclude Include="io\SocketInfo.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
<ClInclude Include="utility\singleton_pool.h">\r
<Filter>Source\utility</Filter>\r
</ClInclude>\r
+ <ClInclude Include="utility\safe_ptr.h">\r
+ <Filter>Source\utility</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
#include "../exception/win32_exception.h"\r
\r
namespace caspar {\r
-namespace common {\r
\r
Event::Event(bool bManualReset, bool bInitialState) : handle_(0)\r
{\r
}while(bDoRestart);\r
}\r
\r
-} //namespace common\r
} //namespace caspar
\ No newline at end of file
#include <exception>\r
#include <memory>\r
\r
-namespace caspar { namespace common {\r
+namespace caspar {\r
\r
class IRunnable\r
{\r
static bool static_bInstallWin32ExceptionHandler_;\r
};\r
\r
-}}
\ No newline at end of file
+}
\ No newline at end of file
\r
#include <functional>\r
\r
-namespace caspar { namespace common {\r
+namespace caspar {\r
\r
class executor\r
{\r
tbb::concurrent_bounded_queue<std::function<void()>> execution_queue_;\r
};\r
\r
-}}
\ No newline at end of file
+}
\ No newline at end of file
\r
#include <memory>\r
\r
-namespace caspar { namespace common { namespace gl {\r
+namespace caspar { namespace gl {\r
\r
struct frame_buffer_object::implementation\r
{\r
\r
frame_buffer_object::frame_buffer_object(size_t width, size_t height, GLenum mode) : impl_(new implementation(width, height, mode)){}\r
void frame_buffer_object::bind_pixel_source() {impl_->bind_pixel_source();}\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
\r
#include <memory>\r
\r
-namespace caspar { namespace common { namespace gl {\r
+namespace caspar { namespace gl {\r
\r
class frame_buffer_object\r
{\r
};\r
typedef frame_buffer_object fbo;\r
\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
#include "../../common/exception/exceptions.h"\r
#include "../../common/gl/utility.h"\r
\r
-namespace caspar { namespace common { namespace gl {\r
+namespace caspar { namespace gl {\r
\r
struct pixel_buffer_object::implementation : boost::noncopyable\r
{\r
bool pixel_buffer_object::is_reading() const { return impl_->reading_;}\r
bool pixel_buffer_object::is_writing() const { return impl_->writing_;}\r
void pixel_buffer_object::is_smooth(bool smooth){impl_->is_smooth(smooth);}\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
#include <boost/tuple/tuple.hpp>\r
#include <boost/thread/future.hpp>\r
\r
-namespace caspar { namespace common { namespace gl {\r
+namespace caspar { namespace gl {\r
\r
class pixel_buffer_object : boost::noncopyable\r
{\r
\r
typedef pixel_buffer_object pbo;\r
typedef pixel_buffer_object_ptr pbo_ptr;\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
\r
#include <boost/noncopyable.hpp>\r
\r
-namespace caspar { namespace common { namespace gl {\r
+namespace caspar { namespace gl {\r
\r
shader_program& shader_program::operator=(shader_program&& other) \r
{\r
GL(glDeleteObjectARB(vertex_shader));\r
std::stringstream str;\r
str << "Failed to compile vertex shader:" << std::endl << info << std::endl;\r
- BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
+ BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));\r
}\r
\r
const char* fragment_source = fragment_source_str.c_str();\r
GL(glDeleteObjectARB(fragmemt_shader));\r
std::stringstream str;\r
str << "Failed to compile fragment shader:" << std::endl << info << std::endl;\r
- BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
+ BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));\r
}\r
\r
program_ = glCreateProgramObjectARB();\r
GL(glDeleteObjectARB(program_));\r
std::stringstream str;\r
str << "Failed to link shader program:" << std::endl << info << std::endl;\r
- BOOST_THROW_EXCEPTION(common::gl::gl_error() << msg_info(str.str()));\r
+ BOOST_THROW_EXCEPTION(gl::gl_error() << msg_info(str.str()));\r
}\r
GL(glUseProgramObjectARB(program_));\r
glUniform1i(glGetUniformLocation(program_, "plane[0]"), 0);\r
GL(glUseProgramObjectARB(program_)); \r
}\r
\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
\r
#include <memory>\r
\r
-namespace caspar { namespace common { namespace gl {\r
+namespace caspar { namespace gl {\r
\r
class shader_program : boost::noncopyable\r
{\r
};\r
typedef std::shared_ptr<shader_program> shader_program_ptr;\r
\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
\r
#include <boost/lexical_cast.hpp>\r
\r
-namespace caspar { namespace common { namespace gl {\r
+namespace caspar { namespace gl {\r
\r
struct gl_error : virtual caspar_exception{};\r
\r
do \\r
{ \\r
(expr); \\r
- caspar::common::gl::SMFL_GLCheckError(CASPAR_GL_EXPR_STR(expr), __FILE__, __LINE__);\\r
+ caspar::gl::SMFL_GLCheckError(CASPAR_GL_EXPR_STR(expr), __FILE__, __LINE__);\\r
}while(0);\r
#else\r
#define GL(expr) expr\r
#endif\r
\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
#endif\r
\r
namespace caspar { namespace IO {\r
-\r
-using namespace common;\r
-\r
+ \r
#define CASPAR_MAXIMUM_SOCKET_CLIENTS (MAXIMUM_WAIT_OBJECTS-1) \r
\r
long AsyncEventServer::instanceCount_ = 0;\r
\r
typedef std::function<void(caspar::IO::SocketInfoPtr)> ClientDisconnectEvent;\r
\r
-class AsyncEventServer : public common::IRunnable\r
+class AsyncEventServer : public IRunnable\r
{\r
static long instanceCount_;\r
\r
void SetClientDisconnectHandler(ClientDisconnectEvent handler);\r
\r
private:\r
- common::Thread listenThread_;\r
+ Thread listenThread_;\r
void Run(HANDLE stopEvent);\r
bool OnUnhandledException(const std::exception&) throw();\r
\r
* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
*\r
*/\r
- \r
-#ifndef _PROTOCOLSTRATEGY_H__\r
-#define _PROTOCOLSTRATEGY_H__\r
-\r
-#pragma once\r
+ #pragma once\r
\r
#include <string>\r
#include "clientInfo.h"\r
typedef std::tr1::shared_ptr<IProtocolStrategy> ProtocolStrategyPtr;\r
\r
} //namespace IO\r
-} //namespace caspar\r
-\r
-#endif //_PROTOCOLSTRATEGY_H__
\ No newline at end of file
+} //namespace caspar
\ No newline at end of file
\r
#define CASPAR_LOG_CURRENT_EXCEPTION() \\r
try\\r
- {CASPAR_LOG(error) << caspar::common::widen(boost::current_exception_diagnostic_information());}\\r
+ {CASPAR_LOG(error) << caspar::widen(boost::current_exception_diagnostic_information());}\\r
catch(...){}\r
\r
}}\r
--- /dev/null
+#pragma once\r
+\r
+#include "../exception/exceptions.h"\r
+\r
+#include <memory>\r
+#include <vector>\r
+#include <type_traits>\r
+\r
+namespace caspar {\r
+ \r
+template<typename T>\r
+class safe_ptr\r
+{ \r
+ template <typename> friend class safe_ptr;\r
+public:\r
+ typedef T element_type;\r
+ \r
+ safe_ptr() : impl_(std::make_shared<T>()){static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");} \r
+ \r
+ safe_ptr(const safe_ptr<T>& other) : impl_(other.impl_){}\r
+ \r
+ template<typename Y>\r
+ safe_ptr(const safe_ptr<Y>& other, typename std::enable_if<std::is_convertible<Y*, T*>::value, void*>::type = 0) : impl_(other.impl_){}\r
+ \r
+ template<typename Y> \r
+ safe_ptr(const Y& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<Y>::type, typename std::add_pointer<T>::type>::value, void>::type* = 0)\r
+ : impl_(std::make_shared<Y>(impl)) {}\r
+ \r
+ template<typename Y> \r
+ safe_ptr(Y&& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<Y>::type, typename std::add_pointer<T>::type>::value, void>::type* = 0)\r
+ : impl_(std::make_shared<Y>(std::forward<Y>(impl))) {}\r
+\r
+ template<typename Y>\r
+ typename std::enable_if<std::is_convertible<Y*, T*>::value, safe_ptr<T>&>::type\r
+ operator=(const safe_ptr<Y>& other)\r
+ {\r
+ safe_ptr<T> temp(other);\r
+ temp.swap(*this);\r
+ return *this;\r
+ }\r
+\r
+ template <typename Y>\r
+ typename std::enable_if<std::is_convertible<typename std::add_pointer<Y>::type, typename std::add_pointer<T>::type>::value, safe_ptr<T>&>::type\r
+ operator=(Y&& impl)\r
+ {\r
+ safe_ptr<T> temp(std::forward<T>(impl));\r
+ temp.swap(*this);\r
+ return *this;\r
+ }\r
+\r
+ T& operator*() const { return *impl_.get();}\r
+\r
+ T* operator->() const { return impl_.get();}\r
+\r
+ T* get() const { return impl_.get();}\r
+\r
+ bool unique() const { return impl_.unique();}\r
+\r
+ long use_count() const { return impl_.use_count();}\r
+ \r
+ void swap(safe_ptr& other) { impl_.swap(other.impl_); } \r
+ \r
+ std::shared_ptr<T> get_shared() const { return impl_; }\r
+\r
+ static safe_ptr<T> from_shared(const std::shared_ptr<T>& impl) { return safe_ptr<T>(impl); }\r
+\r
+private: \r
+ \r
+ template<typename Y> \r
+ safe_ptr(const std::shared_ptr<Y>& impl, typename std::enable_if<std::is_convertible<Y*, T*>::value, void*>::type = 0) : impl_(impl)\r
+ {\r
+ if(!impl)\r
+ BOOST_THROW_EXCEPTION(null_argument() << msg_info("impl"));\r
+ }\r
+\r
+ std::shared_ptr<T> impl_;\r
+};\r
+\r
+template<class T, class U>\r
+bool operator==(safe_ptr<T> const & a, safe_ptr<U> const & b)\r
+{\r
+ return a.get() == b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator!=(safe_ptr<T> const & a, safe_ptr<U> const & b)\r
+{\r
+ return a.get() != b.get();\r
+}\r
+\r
+template<class T, class U>\r
+bool operator<(safe_ptr<T> const & a, safe_ptr<U> const & b)\r
+{\r
+ return a.get() < b.get();\r
+}\r
+\r
+template<class T> void swap(safe_ptr<T> & a, safe_ptr<T> & b)\r
+{\r
+ a.swap(b);\r
+}\r
+\r
+template<class T> T* get_pointer(safe_ptr<T> const & p)\r
+{\r
+ return p.get();\r
+}\r
+\r
+template<typename T>\r
+safe_ptr<T> make_safe()\r
+{\r
+ static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");\r
+ return safe_ptr<T>();\r
+}\r
+\r
+template<typename T, typename P0>\r
+safe_ptr<T> make_safe(P0&& p0)\r
+{\r
+ static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");\r
+ return safe_ptr<T>(T(std::forward<P0>(p0)));\r
+}\r
+\r
+template<typename T, typename P0, typename P1>\r
+safe_ptr<T> make_safe(P0&& p0, P1&& p1)\r
+{\r
+ static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");\r
+ return safe_ptr<T>(T(std::forward<P0>(p0), std::forward<P1>(p1)));\r
+}\r
+\r
+template<typename T, typename P0, typename P1, typename P2>\r
+safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2)\r
+{\r
+ static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");\r
+ return safe_ptr<T>(T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));\r
+}\r
+\r
+}
\ No newline at end of file
#include <tbb/concurrent_queue.h>\r
#include <tbb/scalable_allocator.h>\r
\r
-namespace caspar { namespace common {\r
+namespace caspar {\r
\r
template <typename T>\r
class singleton_pool\r
}\r
};\r
\r
-}}
\ No newline at end of file
+}
\ No newline at end of file
#include <sstream>\r
#include <boost/lexical_cast.hpp>\r
\r
-namespace caspar { namespace common {\r
+namespace caspar {\r
\r
inline std::wstring widen(const std::string& str, const std::locale& locale = std::locale())\r
{\r
return defaultValue;\r
}\r
\r
-}}
\ No newline at end of file
+}
\ No newline at end of file
producer_device_->clear();\r
}\r
\r
- void load(int render_layer, const frame_producer_ptr& producer, load_option::type option = load_option::none)\r
+ void load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option = load_option::none)\r
{\r
producer_device_->load(render_layer, producer, option);\r
}\r
producer_device_->clear();\r
}\r
\r
- boost::unique_future<frame_producer_ptr> foreground(int render_layer) const\r
+ boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const\r
{\r
return producer_device_->foreground(render_layer);\r
}\r
\r
- boost::unique_future<frame_producer_ptr> background(int render_layer) const\r
+ boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const\r
{\r
return producer_device_->background(render_layer);\r
}\r
\r
channel::channel(const frame_producer_device_ptr& producer_device, const frame_processor_device_ptr& processor_device, const frame_consumer_device_ptr& consumer_device)\r
: impl_(new implementation(producer_device, processor_device, consumer_device)){}\r
-void channel::load(int render_layer, const frame_producer_ptr& producer, load_option::type option){impl_->load(render_layer, producer, option);}\r
+void channel::load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option){impl_->load(render_layer, producer, option);}\r
void channel::pause(int render_layer){impl_->pause(render_layer);}\r
void channel::play(int render_layer){impl_->play(render_layer);}\r
void channel::stop(int render_layer){impl_->stop(render_layer);}\r
void channel::clear(int render_layer){impl_->clear(render_layer);}\r
void channel::clear(){impl_->clear();}\r
-boost::unique_future<frame_producer_ptr> channel::foreground(int render_layer) const{ return impl_->foreground(render_layer);}\r
-boost::unique_future<frame_producer_ptr> channel::background(int render_layer) const{return impl_->background(render_layer);}\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
\r
}}
\ No newline at end of file
public:\r
channel(const frame_producer_device_ptr& producer_device, const frame_processor_device_ptr& processor_device, const frame_consumer_device_ptr& consumer_device);\r
\r
- void load(int render_layer, const frame_producer_ptr& producer, load_option::type option = load_option::none);\r
+ void load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option = load_option::none);\r
void pause(int render_layer);\r
void play(int render_layer);\r
void stop(int render_layer);\r
void clear(int render_layer);\r
void clear(); \r
- boost::unique_future<frame_producer_ptr> foreground(int render_layer) const;\r
- boost::unique_future<frame_producer_ptr> background(int render_layer) const;\r
+ boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const;\r
+ boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const;\r
const video_format_desc& get_video_format_desc() const;\r
private:\r
struct implementation;\r
CASPAR_LOG(error) << "BLUECARD ERROR: Failed to disable video output. (device " << device_index_ << TEXT(")"); \r
}\r
\r
- void send(const read_frame& frame)\r
+ void send(const safe_ptr<read_frame>& frame)\r
{ \r
static size_t audio_samples = 1920;\r
static size_t audio_nchannels = 2;\r
\r
if(embed_audio_)\r
{ \r
- auto& frame_audio_data = frame.audio_data().empty() ? silence : frame.audio_data();\r
+ auto& frame_audio_data = frame->audio_data().empty() ? silence : frame->audio_data();\r
\r
encode_hanc(reinterpret_cast<BLUE_UINT32*>(hanc->data()), const_cast<short*>(frame_audio_data.data()), audio_samples, audio_nchannels);\r
\r
- sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame.pixel_data().begin()), \r
- frame.pixel_data().size(), \r
+ sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame->pixel_data().begin()), \r
+ frame->pixel_data().size(), \r
nullptr, \r
BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
\r
}\r
else\r
{\r
- sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame.pixel_data().begin()),\r
- frame.pixel_data().size(), \r
+ sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame->pixel_data().begin()),\r
+ frame->pixel_data().size(), \r
nullptr, \r
BlueImage_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
\r
}\r
\r
boost::unique_future<void> active_;\r
- common::executor executor_;\r
+ executor executor_;\r
\r
BlueVelvetPtr sdk_;\r
\r
unsigned long res_fmt_; \r
unsigned long engine_mode_;\r
\r
- boost::optional<read_frame> transferring_frame_;\r
+ boost::optional<safe_ptr<read_frame>> transferring_frame_;\r
\r
std::array<page_locked_buffer_ptr, 3> hanc_buffers_;\r
int current_id_;\r
};\r
\r
consumer::consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio) : impl_(new implementation(format_desc, device_index, embed_audio)){} \r
-void consumer::send(const read_frame& frame){impl_->send(frame);}\r
+void consumer::send(const safe_ptr<read_frame>& frame){impl_->send(frame);}\r
frame_consumer::sync_mode consumer::synchronize(){return impl_->synchronize();}\r
size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
}}}\r
public:\r
consumer(const video_format_desc& format_desc, unsigned int deviceIndex, bool embed_audio = false);\r
\r
- virtual void send(const read_frame&);\r
+ virtual void send(const safe_ptr<read_frame>&);\r
virtual sync_mode synchronize();\r
virtual size_t buffer_depth() const;\r
private:\r
CoUninitialize();\r
}\r
\r
- void send(const read_frame& frame)\r
+ void send(const safe_ptr<read_frame>& frame)\r
{\r
active_ = executor_.begin_invoke([=]\r
{ \r
- std::copy(frame.pixel_data().begin(), frame.pixel_data().end(), static_cast<char*>(reserved_frames_.front().first));\r
+ std::copy(frame->pixel_data().begin(), frame->pixel_data().end(), static_cast<char*>(reserved_frames_.front().first));\r
\r
if(FAILED(output_->DisplayVideoFrameSync(reserved_frames_.front().second)))\r
CASPAR_LOG(error) << L"DECKLINK: Failed to display frame.";\r
}\r
\r
boost::unique_future<void> active_;\r
- common::executor executor_;\r
+ executor executor_;\r
\r
std::array<std::pair<void*, CComPtr<IDeckLinkMutableVideoFrame>>, 3> reserved_frames_;\r
\r
};\r
\r
decklink_consumer::decklink_consumer(const video_format_desc& format_desc, bool internalKey) : pImpl_(new Implementation(format_desc, internalKey)){}\r
-void decklink_consumer::send(const read_frame& frame){pImpl_->send(frame);}\r
+void decklink_consumer::send(const safe_ptr<read_frame>& frame){pImpl_->send(frame);}\r
frame_consumer::sync_mode decklink_consumer::synchronize(){return pImpl_->synchronize();}\r
size_t decklink_consumer::buffer_depth() const{return pImpl_->buffer_depth();}\r
\r
public:\r
explicit decklink_consumer(const video_format_desc& format_desc, bool internalKey = false);\r
\r
- virtual void send(const read_frame&);\r
+ virtual void send(const safe_ptr<read_frame>&);\r
virtual sync_mode synchronize();\r
virtual size_t buffer_depth() const;\r
private:\r
\r
virtual ~frame_consumer() {}\r
\r
- virtual void send(const read_frame& frame) = 0;\r
+ virtual void send(const safe_ptr<read_frame>& frame) = 0;\r
virtual sync_mode synchronize() = 0;\r
virtual size_t buffer_depth() const = 0;\r
};\r
executor_.begin_invoke([=]{tick();});\r
}\r
\r
- void process(const read_frame& frame)\r
+ void process(const safe_ptr<read_frame>& frame)\r
{ \r
buffer_.push_back(frame);\r
\r
buffer_.pop_front();\r
}\r
\r
- common::executor executor_; \r
+ executor executor_; \r
\r
size_t max_depth_;\r
- std::deque<read_frame> buffer_; \r
+ std::deque<safe_ptr<read_frame>> buffer_; \r
\r
std::vector<frame_consumer_ptr> consumers_;\r
\r
Stop();\r
}\r
\r
- void send(const read_frame& frame)\r
+ void send(const safe_ptr<read_frame>& frame)\r
{ \r
- input_.push(frame.audio_data()); \r
+ input_.push(frame->audio_data()); \r
\r
if(GetStatus() != Playing && input_.size() > 2) \r
Play(); \r
};\r
\r
consumer::consumer(const video_format_desc&) : impl_(new implementation()){}\r
-void consumer::send(const read_frame& frame){impl_->send(frame);}\r
+void consumer::send(const safe_ptr<read_frame>& frame){impl_->send(frame);}\r
frame_consumer::sync_mode consumer::synchronize(){return impl_->synchronize();}\r
size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
}}}\r
public: \r
explicit consumer(const video_format_desc& format_desc);\r
\r
- virtual void send(const read_frame&);\r
+ virtual void send(const safe_ptr<read_frame>&);\r
virtual sync_mode synchronize();\r
virtual size_t buffer_depth() const;\r
private:\r
return std::make_pair(width, height);\r
}\r
\r
- void render(const read_frame& frame)\r
+ void render(const safe_ptr<read_frame>& frame)\r
{ \r
auto ptr = pbos_.front().end_write();\r
- std::copy_n(frame.pixel_data().begin(), frame.pixel_data().size(), reinterpret_cast<char*>(ptr));\r
+ std::copy_n(frame->pixel_data().begin(), frame->pixel_data().size(), reinterpret_cast<char*>(ptr));\r
\r
GL(glClear(GL_COLOR_BUFFER_BIT)); \r
pbos_.back().bind_texture(); \r
std::rotate(pbos_.begin(), pbos_.begin() + 1, pbos_.end());\r
}\r
\r
- void send(const read_frame& frame)\r
+ void send(const safe_ptr<read_frame>& frame)\r
{\r
active_ = executor_.begin_invoke([=]\r
{\r
}\r
\r
boost::unique_future<void> active_;\r
- common::executor executor_;\r
+ executor executor_;\r
\r
float wratio_;\r
float hratio_;\r
float wSize_;\r
float hSize_;\r
\r
- std::array<common::gl::pixel_buffer_object, 2> pbos_;\r
+ std::array<gl::pixel_buffer_object, 2> pbos_;\r
\r
bool windowed_;\r
unsigned int screen_width_;\r
\r
consumer::consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed)\r
: impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
-void consumer::send(const read_frame& frame){impl_->send(frame);}\r
+void consumer::send(const safe_ptr<read_frame>& frame){impl_->send(frame);}\r
frame_consumer::sync_mode consumer::synchronize(){return impl_->synchronize();}\r
size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
}}}\r
public: \r
explicit consumer(const video_format_desc& format_desc, unsigned int screen_index = 0, stretch stretch = stretch::fill, bool windowed = false);\r
\r
- virtual void send(const read_frame&);\r
+ virtual void send(const safe_ptr<read_frame>&);\r
virtual sync_mode synchronize();\r
virtual size_t buffer_depth() const;\r
private:\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="format\video_format.cpp">\r
+ <ClCompile Include="format\pixel_format.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="processor\composite_frame.cpp">\r
+ <ClCompile Include="format\video_format.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="processor\draw_frame.cpp">\r
+ <ClCompile Include="processor\composite_frame.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../StdAfx.h</PrecompiledHeaderFile>\r
</ClCompile>\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.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\image\image_loader.cpp">\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../StdAfx.h</PrecompiledHeaderFile>\r
<ClCompile Include="producer\ffmpeg\input.cpp">\r
<Filter>Source\channel\producer\ffmpeg\io</Filter>\r
</ClCompile>\r
- <ClCompile Include="processor\draw_frame.cpp">\r
- <Filter>Source\channel\processor\frame</Filter>\r
+ <ClCompile Include="producer\frame_producer.cpp">\r
+ <Filter>Source\channel\producer</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="format\pixel_format.cpp">\r
+ <Filter>Source\channel\format</Filter>\r
</ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
--- /dev/null
+#include "..\StdAfx.h"\r
+\r
+#include "pixel_format.h"\r
+\r
+namespace caspar { namespace core {\r
+ \r
+size_t hash(const pixel_format_desc& desc)\r
+{\r
+ size_t hash = 0;\r
+ switch(desc.pix_fmt)\r
+ {\r
+ case pixel_format::ycbcr:\r
+ case pixel_format::ycbcra:\r
+ // 0-10 (11) width\r
+ // 11-21 (11) height\r
+ // 22-24 (3) x-ratio\r
+ // 25-27 (3) y-ratio\r
+ // 28-29 (2) unused\r
+ // 30 (1) alpha\r
+ // 31 (1) yuv = true => 1\r
+ hash |= ( desc.planes[0].width & 0x7FF ) << 0;\r
+ hash |= ( desc.planes[0].height & 0x7FF ) << 11;\r
+ hash |= ((desc.planes[0].height/desc.planes[1].height) & 0x7 ) << 22;\r
+ hash |= ((desc.planes[0].width/desc.planes[1].width) & 0x7 ) << 25;\r
+ hash |= desc.pix_fmt == pixel_format::ycbcra ? (1 << 30) : 0;\r
+ hash |= 1 << 31;\r
+ return hash;\r
+ case pixel_format::bgra:\r
+ case pixel_format::rgba:\r
+ case pixel_format::argb:\r
+ case pixel_format::abgr:\r
+ \r
+ //0-10 (11) height\r
+ //11-21 (11) width\r
+ //22-29 (8) unused\r
+ //30 (1) alpha\r
+ //31 (1) yuv = false => 0\r
+ hash |= (desc.planes[0].height & 0xFFFF) << 0;\r
+ hash |= (desc.planes[0].width & 0xFFFF) << 15;\r
+ hash |= 1 << 30;\r
+ return hash;\r
+\r
+ default:\r
+ return hash;\r
+ };\r
+}\r
+ \r
+}}\r
pixel_format::type pix_fmt;\r
std::vector<plane> planes;\r
};\r
+\r
+size_t hash(const pixel_format_desc& desc);\r
+ \r
+inline bool operator==(const pixel_format_desc& lhs, const pixel_format_desc& rhs)\r
+{\r
+ return hash(lhs) == hash(rhs);\r
+}\r
+\r
+inline bool operator!=(const pixel_format_desc& lhs, const pixel_format_desc& rhs)\r
+{\r
+ return !(lhs == rhs);\r
+}\r
\r
-}}
\ No newline at end of file
+}}\r
+\r
+namespace std {\r
+\r
+template<> struct hash<caspar::core::pixel_format_desc>\r
+{\r
+ size_t operator()(const caspar::core::pixel_format_desc& desc) const { return caspar::core::hash(desc);}\r
+};\r
+\r
+}
\ No newline at end of file
\r
struct composite_frame::implementation\r
{ \r
- implementation(std::vector<draw_frame>&& frames) : frames_(std::move(frames))\r
+ implementation(std::vector<safe_ptr<draw_frame>>&& frames) : frames_(std::move(frames))\r
{ \r
if(frames_.size() < 2)\r
return;\r
\r
- boost::range::for_each(frames_, [&](const draw_frame& frame)\r
+ boost::range::for_each(frames_, [&](const safe_ptr<draw_frame>& frame)\r
{\r
if(audio_data_.empty())\r
- audio_data_ = frame.audio_data();\r
+ audio_data_ = frame->audio_data();\r
else\r
{\r
tbb::parallel_for\r
(\r
- tbb::blocked_range<size_t>(0, frame.audio_data().size()),\r
+ tbb::blocked_range<size_t>(0, frame->audio_data().size()),\r
[&](const tbb::blocked_range<size_t>& r)\r
{\r
for(size_t n = r.begin(); n < r.end(); ++n) \r
- audio_data_[n] = static_cast<short>((static_cast<int>(audio_data_[n]) + static_cast<int>(frame.audio_data()[n])) & 0xFFFF); \r
+ audio_data_[n] = static_cast<short>((static_cast<int>(audio_data_[n]) + static_cast<int>(frame->audio_data()[n])) & 0xFFFF); \r
}\r
);\r
}\r
\r
void begin_write()\r
{\r
- boost::range::for_each(frames_, std::bind(&detail::draw_frame_access::begin_write, std::placeholders::_1));\r
+ boost::range::for_each(frames_, std::bind(&draw_frame::begin_write, std::placeholders::_1));\r
}\r
\r
void end_write()\r
{\r
- boost::range::for_each(frames_, std::bind(&detail::draw_frame_access::end_write, std::placeholders::_1));\r
+ boost::range::for_each(frames_, std::bind(&draw_frame::end_write, std::placeholders::_1));\r
}\r
\r
void draw(frame_shader& shader)\r
{\r
- boost::range::for_each(frames_, std::bind(&detail::draw_frame_access::draw, std::placeholders::_1, std::ref(shader)));\r
+ boost::range::for_each(frames_, std::bind(&draw_frame::draw, std::placeholders::_1, std::ref(shader)));\r
}\r
\r
const std::vector<short>& audio_data()\r
{\r
static std::vector<short> no_audio;\r
- return !audio_data_.empty() ? audio_data_ : (!frames_.empty() ? frames_.front().audio_data() : no_audio);\r
+ return !audio_data_.empty() ? audio_data_ : (!frames_.empty() ? frames_.front()->audio_data() : no_audio);\r
}\r
\r
std::vector<short> audio_data_;\r
- std::vector<draw_frame> frames_;\r
+ std::vector<safe_ptr<draw_frame>> frames_;\r
};\r
\r
-composite_frame::composite_frame(std::vector<draw_frame>&& frames) : impl_(common::singleton_pool<implementation>::make_shared(std::move(frames))){}\r
+composite_frame::composite_frame(std::vector<safe_ptr<draw_frame>>&& frames) : impl_(singleton_pool<implementation>::make_shared(std::move(frames))){}\r
composite_frame::composite_frame(composite_frame&& other) : impl_(std::move(other.impl_)){}\r
-composite_frame::composite_frame(const composite_frame& other) : impl_(common::singleton_pool<implementation>::make_shared(*other.impl_)){}\r
+composite_frame::composite_frame(const composite_frame& other) : impl_(singleton_pool<implementation>::make_shared(*other.impl_)){}\r
void composite_frame::swap(composite_frame& other){impl_.swap(other.impl_);}\r
composite_frame& composite_frame::operator=(const composite_frame& other)\r
{\r
composite_frame temp(other);\r
- temp.impl_.swap(impl_);\r
+ temp.swap(*this);\r
return *this;\r
}\r
composite_frame& composite_frame::operator=(composite_frame&& other)\r
{\r
- impl_ = std::move(other.impl_);\r
+ composite_frame temp(std::move(other));\r
+ temp.swap(*this);\r
return *this;\r
}\r
\r
-composite_frame::composite_frame(draw_frame&& frame1, draw_frame&& frame2)\r
+composite_frame::composite_frame(safe_ptr<draw_frame>&& frame1, safe_ptr<draw_frame>&& frame2)\r
{\r
- std::vector<draw_frame> frames;\r
+ std::vector<safe_ptr<draw_frame>> frames;\r
frames.push_back(std::move(frame1));\r
frames.push_back(std::move(frame2));\r
impl_.reset(new implementation(std::move(frames)));\r
void composite_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
const std::vector<short>& composite_frame::audio_data() const {return impl_->audio_data();}\r
\r
-composite_frame composite_frame::interlace(draw_frame&& frame1, draw_frame&& frame2, video_mode::type mode)\r
+safe_ptr<composite_frame> composite_frame::interlace(safe_ptr<draw_frame>&& frame1, safe_ptr<draw_frame>&& frame2, video_mode::type mode)\r
{ \r
transform_frame my_frame1 = std::move(frame1);\r
transform_frame my_frame2 = std::move(frame2);\r
my_frame2.video_mode(video_mode::upper);\r
}\r
\r
- std::vector<draw_frame> frames;\r
+ std::vector<safe_ptr<draw_frame>> frames;\r
frames.push_back(std::move(my_frame1));\r
frames.push_back(std::move(my_frame2));\r
- return composite_frame(std::move(frames));\r
+ return make_safe<composite_frame>(std::move(frames));\r
}\r
\r
}}
\ No newline at end of file
\r
namespace caspar { namespace core {\r
\r
-class composite_frame : public detail::draw_frame_impl\r
+class composite_frame : public draw_frame\r
{\r
public:\r
- explicit composite_frame(std::vector<draw_frame>&& frames);\r
- composite_frame(draw_frame&& frame1, draw_frame&& frame2);\r
+ explicit composite_frame(std::vector<safe_ptr<draw_frame>>&& frames);\r
+ composite_frame(safe_ptr<draw_frame>&& frame1, safe_ptr<draw_frame>&& frame2);\r
\r
void swap(composite_frame& other);\r
\r
composite_frame(const composite_frame& other);\r
- composite_frame& operator=(const composite_frame& other);\r
composite_frame(composite_frame&& other);\r
+\r
+ composite_frame& operator=(const composite_frame& other);\r
composite_frame& operator=(composite_frame&& other);\r
\r
- static composite_frame interlace(draw_frame&& frame1, draw_frame&& frame2, video_mode::type mode);\r
+ static safe_ptr<composite_frame> interlace(safe_ptr<draw_frame>&& frame1, safe_ptr<draw_frame>&& frame2, video_mode::type mode);\r
\r
virtual const std::vector<short>& audio_data() const;\r
\r
+++ /dev/null
-#include "../stdafx.h"\r
-\r
-#include "draw_frame.h"\r
-\r
-#include "frame_shader.h"\r
-\r
-namespace caspar { namespace core {\r
- \r
-struct null_frame : public detail::draw_frame_impl\r
-{\r
- virtual const std::vector<short>& audio_data() const\r
- {\r
- static std::vector<short> no_audio;\r
- return no_audio;\r
- }\r
- virtual void begin_write(){}\r
- virtual void end_write(){}\r
- virtual void draw(frame_shader&){}\r
-};\r
-\r
-static const std::shared_ptr<null_frame>& get_empty()\r
-{\r
- static auto empty = std::make_shared<null_frame>();\r
- return empty;\r
-}\r
- \r
-static const std::shared_ptr<null_frame>& get_eof()\r
-{\r
- static auto eof = std::make_shared<null_frame>();\r
- return eof;\r
-}\r
-\r
-draw_frame::draw_frame() : impl_(get_empty()){}\r
-draw_frame::draw_frame(const draw_frame& other) : impl_(other.impl_){}\r
-draw_frame::draw_frame(draw_frame&& other) : impl_(std::move(other.impl_)){other.impl_ = get_empty();}\r
-draw_frame::draw_frame(eof_frame){impl_ = get_eof();}\r
-draw_frame::draw_frame(empty_frame){impl_ = get_empty();}\r
-\r
-void draw_frame::swap(draw_frame& other){impl_.swap(other.impl_);}\r
- \r
-bool draw_frame::operator==(const eof_frame&){return impl_ == get_eof();}\r
-bool draw_frame::operator==(const empty_frame&){return impl_ == get_empty();}\r
-bool draw_frame::operator==(const draw_frame& other){return impl_ == other.impl_;}\r
- \r
-draw_frame& draw_frame::operator=(const draw_frame& other)\r
-{\r
- draw_frame temp(other);\r
- temp.swap(*this);\r
- return *this;\r
-}\r
-\r
-draw_frame& draw_frame::operator=(draw_frame&& other)\r
-{\r
- draw_frame temp(other);\r
- temp.swap(*this);\r
- return *this;\r
-}\r
-\r
-draw_frame& draw_frame::operator=(eof_frame&&)\r
-{\r
- impl_ = get_eof();\r
- return *this;\r
-} \r
-\r
-draw_frame& draw_frame::operator=(empty_frame&&)\r
-{\r
- impl_ = get_empty();\r
- return *this;\r
-} \r
-\r
-eof_frame draw_frame::eof(){return eof_frame();}\r
-empty_frame draw_frame::empty(){return empty_frame();}\r
-\r
-const std::vector<short>& draw_frame::audio_data() const{return impl_->audio_data();} \r
-\r
-void draw_frame::begin_write(){impl_->begin_write();}\r
-void draw_frame::end_write(){impl_->end_write();}\r
-void draw_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
-\r
-}}
\ No newline at end of file
\r
#include <boost/noncopyable.hpp>\r
#include <boost/range/iterator_range.hpp>\r
-#include <boost/variant.hpp>\r
#include <boost/operators.hpp>\r
\r
#include <memory>\r
#include <vector>\r
#include <type_traits>\r
\r
+#include "../../common/utility/safe_ptr.h"\r
+\r
namespace caspar { namespace core {\r
\r
-namespace detail\r
-{\r
-\r
-class draw_frame_impl : boost::noncopyable\r
+class draw_frame : boost::noncopyable\r
{ \r
public:\r
- virtual ~draw_frame_impl(){}\r
+ virtual ~draw_frame(){}\r
\r
virtual const std::vector<short>& audio_data() const = 0; \r
virtual void begin_write() = 0;\r
virtual void end_write() = 0;\r
virtual void draw(frame_shader& shader) = 0;\r
-};\r
-\r
-struct draw_frame_access;\r
-\r
-}\r
-\r
-struct eof_frame{};\r
-struct empty_frame{};\r
-\r
-class draw_frame : boost::equality_comparable<draw_frame>, boost::equality_comparable<eof_frame>, boost::equality_comparable<empty_frame>\r
-{\r
-public:\r
- draw_frame();\r
- draw_frame(const draw_frame& other);\r
- draw_frame(draw_frame&& other);\r
- draw_frame(eof_frame);\r
- draw_frame(empty_frame);\r
\r
- template<typename T>\r
- draw_frame(T&& impl, typename std::enable_if<std::is_base_of<detail::draw_frame_impl, typename std::remove_reference<T>::type>::value, void>::type* dummy = nullptr)\r
- : impl_(std::make_shared<T>(std::forward<T>(impl))) {dummy;}\r
- \r
- void swap(draw_frame& other);\r
- \r
- template <typename T>\r
- typename std::enable_if<std::is_base_of<detail::draw_frame_impl, typename std::remove_reference<T>::type>::value, draw_frame&>::type\r
- operator=(T&& impl)\r
+ static safe_ptr<draw_frame> eof()\r
{\r
- draw_frame temp(std::forward<T>(impl));\r
- temp.swap(*this);\r
- return *this;\r
+ struct eof_frame : public draw_frame\r
+ {\r
+ virtual const std::vector<short>& audio_data() const\r
+ {\r
+ static std::vector<short> audio_data;\r
+ return audio_data;\r
+ }\r
+ virtual void begin_write(){}\r
+ virtual void end_write(){}\r
+ virtual void draw(frame_shader&){}\r
+ };\r
+ static safe_ptr<draw_frame> frame = make_safe<eof_frame>();\r
+ return frame;\r
}\r
- \r
- draw_frame& operator=(const draw_frame& other);\r
- draw_frame& operator=(draw_frame&& other);\r
\r
- draw_frame& operator=(eof_frame&&);\r
- draw_frame& operator=(empty_frame&&);\r
- \r
- bool operator==(const draw_frame& other);\r
- bool operator==(const eof_frame&);\r
- bool operator==(const empty_frame&);\r
-\r
- static eof_frame eof();\r
- static empty_frame empty();\r
- \r
- const std::vector<short>& audio_data() const;\r
-private: \r
- friend struct detail::draw_frame_access;\r
-\r
- void begin_write();\r
- void end_write();\r
- void draw(frame_shader& shader);\r
-\r
- std::shared_ptr<detail::draw_frame_impl> impl_;\r
+ static safe_ptr<draw_frame> empty()\r
+ {\r
+ struct empty_frame : public draw_frame\r
+ {\r
+ virtual const std::vector<short>& audio_data() const\r
+ {\r
+ static std::vector<short> audio_data;\r
+ return audio_data;\r
+ }\r
+ virtual void begin_write(){}\r
+ virtual void end_write(){}\r
+ virtual void draw(frame_shader&){}\r
+ };\r
+ static safe_ptr<draw_frame> frame = make_safe<empty_frame>();\r
+ return frame;\r
+ }\r
};\r
\r
-namespace detail\r
-{\r
- struct draw_frame_access\r
- {\r
- static void begin_write(draw_frame& frame){frame.begin_write();}\r
- static void end_write(draw_frame& frame){frame.end_write();}\r
- static void draw(draw_frame& frame, frame_shader& shader){frame.draw(shader);}\r
- };\r
-}\r
\r
}}
\ No newline at end of file
\r
namespace caspar { namespace core {\r
\r
-using namespace common::gl;\r
-\r
struct frame_processor_device::implementation : boost::noncopyable\r
{ \r
- typedef tbb::concurrent_bounded_queue<pbo_ptr> pbo_pool;\r
-\r
implementation(const video_format_desc& format_desc) : fmt_(format_desc), underrun_count_(0)\r
{ \r
output_.set_capacity(3);\r
});\r
}\r
\r
- void send(const draw_frame& frame)\r
+ void send(const safe_ptr<draw_frame>& frame)\r
{ \r
auto future = executor_.begin_invoke([=]{return renderer_->render(frame);}); \r
output_.push(std::move(future)); // Blocks\r
}\r
\r
- read_frame receive()\r
+ safe_ptr<read_frame> receive()\r
{\r
- boost::shared_future<read_frame> future;\r
+ boost::shared_future<safe_ptr<read_frame>> future;\r
\r
if(!output_.try_pop(future))\r
{\r
return future.get();\r
}\r
\r
- write_frame create_frame(const pixel_format_desc& desc)\r
+ safe_ptr<write_frame> create_frame(const pixel_format_desc& desc)\r
{\r
- std::vector<pbo_pool*> pools(desc.planes.size());\r
- boost::range::transform(desc.planes, pools.begin(), [&](const pixel_format_desc::plane& plane)\r
- {\r
- return &pbo_pools_[((plane.width & 0x7FF)) << 0 | ((plane.height & 0x7FF)) << 11 | plane.channels];\r
- });\r
-\r
- bool filled = true;\r
- std::vector<pbo_ptr> pbos(pools.size());\r
- boost::range::transform(pools, pbos.begin(), [&](pbo_pool* pool) -> pbo_ptr\r
- {\r
- pbo_ptr pbo;\r
- filled &= pool->try_pop(pbo);\r
- return pbo;\r
- });\r
- \r
- if(!filled)\r
- {\r
- executor_.invoke([&]\r
- {\r
- for(size_t n = 0; n < pbos.size(); ++n)\r
- {\r
- if(!pbos[n])\r
- pbos[n] = create_pooled_pbo(desc.planes[n], pools[n]);\r
- }\r
- });\r
- }\r
+ auto pool = &pools_[desc];\r
+ std::shared_ptr<write_frame> frame;\r
+ if(!pool->try_pop(frame))\r
+ frame = executor_.invoke([&]{return std::make_shared<write_frame>(desc);});\r
\r
- return write_frame(std::move(pbos), desc);\r
- }\r
-\r
- pbo_ptr create_pooled_pbo(const pixel_format_desc::plane& plane, pbo_pool* pool)\r
- {\r
- static GLenum mapping[] = {GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGR, GL_BGRA};\r
- auto pooled_pbo = std::make_shared<pbo>(plane.width, plane.height, mapping[plane.channels-1]);\r
- pooled_pbo->end_write();\r
- return pbo_ptr(pooled_pbo.get(), [=](pbo*)\r
+ frame = std::shared_ptr<write_frame>(frame.get(), [=](write_frame*)\r
{\r
executor_.begin_invoke([=]\r
{\r
- pooled_pbo->end_write();\r
- pool->push(pooled_pbo);\r
+ frame->reset();\r
+ pool->push(frame);\r
});\r
});\r
+\r
+ return safe_ptr<write_frame>::from_shared(frame);\r
}\r
\r
- common::executor executor_; \r
+ executor executor_; \r
\r
std::unique_ptr<sf::Context> ogl_context_;\r
std::unique_ptr<frame_renderer> renderer_; \r
\r
- tbb::concurrent_bounded_queue<boost::shared_future<read_frame>> output_; \r
+ tbb::concurrent_bounded_queue<boost::shared_future<safe_ptr<read_frame>>> output_; \r
\r
- tbb::concurrent_unordered_map<int, pbo_pool> pbo_pools_;\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
long underrun_count_;\r
};\r
\r
frame_processor_device::frame_processor_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
-void frame_processor_device::send(const draw_frame& frame){impl_->send(std::move(frame));}\r
-read_frame frame_processor_device::receive(){return impl_->receive();}\r
+void frame_processor_device::send(const safe_ptr<draw_frame>& frame){impl_->send(std::move(frame));}\r
+safe_ptr<read_frame> frame_processor_device::receive(){return impl_->receive();}\r
const video_format_desc& frame_processor_device::get_video_format_desc() const { return impl_->fmt_; }\r
\r
-write_frame frame_processor_device::create_frame(const pixel_format_desc& desc){ return impl_->create_frame(desc); } \r
-write_frame frame_processor_device::create_frame(size_t width, size_t height)\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)\r
{\r
// Create bgra frame\r
pixel_format_desc desc;\r
return create_frame(desc);\r
}\r
\r
-write_frame frame_processor_device::create_frame()\r
+safe_ptr<write_frame> frame_processor_device::create_frame()\r
{\r
// Create bgra frame with output resolution\r
pixel_format_desc desc;\r
public:\r
frame_processor_device(const video_format_desc& format_desc);\r
\r
- void send(const draw_frame& frame);\r
- read_frame receive();\r
+ void send(const safe_ptr<draw_frame>& frame);\r
+ safe_ptr<read_frame> receive();\r
\r
- write_frame create_frame(const pixel_format_desc& desc); \r
- write_frame create_frame(size_t width, size_t height); \r
- write_frame create_frame();\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); \r
+ safe_ptr<write_frame> create_frame();\r
\r
const video_format_desc& get_video_format_desc() const;\r
private:\r
\r
namespace caspar { namespace core {\r
\r
-using namespace common::gl;\r
- \r
struct frame_renderer::implementation : boost::noncopyable\r
-{ \r
- typedef std::pair<pbo_ptr, std::vector<short>> reading_frame;\r
- \r
+{ \r
implementation(const video_format_desc& format_desc) : shader_(format_desc), format_desc_(format_desc),\r
- reading_(create_reading(std::vector<short>())), fbo_(format_desc.width, format_desc.height)\r
+ reading_(create_reading()), fbo_(format_desc.width, format_desc.height), writing_(draw_frame::empty()), drawing_(draw_frame::empty())\r
{ \r
GL(glEnable(GL_POLYGON_STIPPLE));\r
GL(glEnable(GL_TEXTURE_2D));\r
GL(glDisable(GL_DEPTH_TEST));\r
GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); \r
GL(glViewport(0, 0, format_desc.width, format_desc.height));\r
- reading_.first->begin_read();\r
+ reading_->begin_read();\r
}\r
\r
- read_frame render(const draw_frame& frame)\r
+ safe_ptr<read_frame> render(const safe_ptr<draw_frame>& frame)\r
{\r
- reading_frame result;\r
+ safe_ptr<read_frame> result = create_reading();\r
try\r
{\r
drawing_ = writing_;\r
writing_ = frame;\r
\r
- detail::draw_frame_access::begin_write(writing_);\r
+ writing_->begin_write();\r
\r
- reading_.first->end_read();\r
- result = reading_; \r
+ reading_->end_read();\r
\r
GL(glClear(GL_COLOR_BUFFER_BIT));\r
\r
- detail::draw_frame_access::draw(drawing_, shader_);\r
+ drawing_->draw(shader_);\r
\r
- reading_ = create_reading(std::vector<short>(drawing_.audio_data().begin(), drawing_.audio_data().end())); \r
- reading_.first->begin_read();\r
+ result.swap(reading_);\r
+ reading_->begin_read();\r
+ reading_->audio_data(drawing_->audio_data());\r
\r
drawing_ = draw_frame::empty();\r
}\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
}\r
\r
- return read_frame(std::move(result.first), std::move(result.second));\r
+ return result;\r
}\r
\r
- reading_frame create_reading(const std::vector<short>& audio_data)\r
+ safe_ptr<read_frame> create_reading()\r
{\r
- pbo_ptr new_pbo;\r
- if(!pbo_pool_.try_pop(new_pbo)) \r
- new_pbo = std::make_shared<pbo>(format_desc_.width, format_desc_.height, GL_BGRA); \r
- new_pbo = pbo_ptr(new_pbo.get(), [=](pbo*){pbo_pool_.push(new_pbo);});\r
- return reading_frame(std::move(new_pbo), audio_data);\r
+ std::shared_ptr<read_frame> frame;\r
+ if(!pool_.try_pop(frame)) \r
+ frame = std::make_shared<read_frame>(format_desc_.width, format_desc_.height);\r
+ frame = std::shared_ptr<read_frame>(frame.get(), [=](read_frame*){pool_.push(frame);});\r
+ return safe_ptr<read_frame>::from_shared(frame);\r
}\r
\r
const video_format_desc format_desc_;\r
- const fbo fbo_;\r
+ const gl::fbo fbo_;\r
\r
- tbb::concurrent_bounded_queue<pbo_ptr> pbo_pool_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<read_frame>> pool_;\r
\r
- reading_frame reading_; \r
- draw_frame writing_;\r
- draw_frame drawing_;\r
+ safe_ptr<read_frame> reading_; \r
+ safe_ptr<draw_frame> writing_;\r
+ safe_ptr<draw_frame> drawing_;\r
\r
frame_shader shader_;\r
};\r
\r
frame_renderer::frame_renderer(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
-read_frame frame_renderer::render(const draw_frame& frame){return impl_->render(std::move(frame));}\r
+safe_ptr<read_frame> frame_renderer::render(const safe_ptr<draw_frame>& frame){return impl_->render(std::move(frame));}\r
}}
\ No newline at end of file
\r
#include "fwd.h"\r
\r
+#include "../../common/utility/safe_ptr.h"\r
+\r
#include "../format/video_format.h"\r
\r
#include <boost/noncopyable.hpp>\r
public:\r
frame_renderer(const video_format_desc& format_desc_);\r
\r
- read_frame render(const draw_frame& frame);\r
+ safe_ptr<read_frame> render(const safe_ptr<draw_frame>& frame);\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
"} " \r
" ";\r
\r
- shaders_[pixel_format::abgr] = common::gl::shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::abgr] = gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
" gl_FragColor = abgr.argb * gl_Color; "\r
"} ");\r
\r
- shaders_[pixel_format::argb]= common::gl::shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::argb]= gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() " \r
"{ "\r
" gl_FragColor = argb.grab * gl_Color; " \r
"} ");\r
\r
- shaders_[pixel_format::bgra]= common::gl::shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::bgra]= gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
" gl_FragColor = bgra.rgba * gl_Color; "\r
"} ");\r
\r
- shaders_[pixel_format::rgba] = common::gl::shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::rgba] = gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
" gl_FragColor = rgba.bgra * gl_Color; "\r
"} ");\r
\r
- shaders_[pixel_format::ycbcr] = common::gl::shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::ycbcr] = gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
" gl_FragColor = ycbcra_to_bgra(y, cb, cr, a) * gl_Color; "\r
"} ");\r
\r
- shaders_[pixel_format::ycbcra] = common::gl::shader_program(common_vertex, common_fragment +\r
+ shaders_[pixel_format::ycbcra] = gl::shader_program(common_vertex, common_fragment +\r
\r
"void main() "\r
"{ "\r
\r
const video_format_desc format_desc_;\r
pixel_format::type current_;\r
- std::unordered_map<pixel_format::type, common::gl::shader_program> shaders_;\r
+ std::unordered_map<pixel_format::type, gl::shader_program> shaders_;\r
};\r
\r
frame_shader::frame_shader(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
class write_frame;\r
class draw_frame;\r
\r
-class draw_frame_impl;\r
+class draw_frame;\r
+\r
class transform_frame;\r
class composite_frame;\r
\r
\r
struct read_frame::implementation : boost::noncopyable\r
{\r
- implementation(common::gl::pbo_ptr&& pbo, std::vector<short>&& audio_data) : pbo_(std::move(pbo)), audio_data_(std::move(audio_data)){} \r
- common::gl::pbo_ptr pbo_;\r
- std::vector<short> audio_data_;\r
+ implementation(size_t width, size_t height) : pbo_(width, height, GL_BGRA)\r
+ {\r
+ CASPAR_LOG(trace) << "Allocated read_frame.";\r
+ } \r
\r
const boost::iterator_range<const unsigned char*> pixel_data() const\r
{\r
- if(!pbo_ || !pbo_->data())\r
+ if(!pbo_.data())\r
return boost::iterator_range<const unsigned char*>();\r
\r
- auto ptr = static_cast<const unsigned char*>(pbo_->data());\r
- return boost::iterator_range<const unsigned char*>(ptr, ptr+pbo_->size());\r
+ auto ptr = static_cast<const unsigned char*>(pbo_.data());\r
+ return boost::iterator_range<const unsigned char*>(ptr, ptr+pbo_.size());\r
}\r
+\r
+ gl::pbo pbo_;\r
+ std::vector<short> audio_data_;\r
};\r
- \r
-read_frame::read_frame(common::gl::pbo_ptr&& pbo, std::vector<short>&& audio_data) : impl_(common::singleton_pool<implementation>::make_shared(std::move(pbo), std::move(audio_data))){}\r
+\r
+read_frame::read_frame(size_t width, size_t height) : impl_(singleton_pool<implementation>::make_shared(width, height)){}\r
const boost::iterator_range<const unsigned char*> read_frame::pixel_data() const{return impl_->pixel_data();}\r
const std::vector<short>& read_frame::audio_data() const { return impl_->audio_data_; }\r
+void read_frame::audio_data(const std::vector<short>& audio_data) { impl_->audio_data_ = audio_data; }\r
+void read_frame::begin_read(){impl_->pbo_.begin_read();}\r
+void read_frame::end_read(){impl_->pbo_.end_read();}\r
\r
}}
\ No newline at end of file
#include <memory>\r
#include <vector>\r
\r
+#include "../../common/utility/safe_ptr.h"\r
+\r
namespace caspar { namespace core {\r
\r
class read_frame\r
{\r
public:\r
- explicit read_frame(common::gl::pbo_ptr&& frame, std::vector<short>&& audio_data);\r
+ explicit read_frame(size_t width, size_t height);\r
\r
const boost::iterator_range<const unsigned char*> pixel_data() const;\r
const std::vector<short>& audio_data() const;\r
\r
private:\r
+ friend class frame_renderer;\r
+ \r
+ void begin_read();\r
+ void end_read();\r
+ void audio_data(const std::vector<short>& audio_data);\r
+\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
\r
struct transform_frame::implementation\r
{\r
- implementation(const draw_frame& frame) : frame_(frame), audio_volume_(255){}\r
- implementation(const draw_frame& frame, std::vector<short>&& audio_data) : frame_(frame), audio_volume_(255), override_audio_data_(std::move(audio_data)){}\r
- implementation(draw_frame&& frame) : frame_(std::move(frame)), audio_volume_(255){}\r
+ implementation(const safe_ptr<draw_frame>& frame) : frame_(frame), audio_volume_(255){}\r
+ implementation(const safe_ptr<draw_frame>& frame, std::vector<short>&& audio_data) : frame_(frame), audio_volume_(255), override_audio_data_(std::move(audio_data)){}\r
+ implementation(safe_ptr<draw_frame>&& frame) : frame_(std::move(frame)), audio_volume_(255){}\r
\r
- void begin_write(){detail::draw_frame_access::begin_write(frame_);}\r
- void end_write(){detail::draw_frame_access::end_write(frame_);}\r
+ void begin_write(){frame_->begin_write();}\r
+ void end_write(){frame_->end_write();}\r
\r
void draw(frame_shader& shader)\r
{\r
shader.begin(transform_);\r
- detail::draw_frame_access::draw(frame_, shader);\r
+ frame_->draw(shader);\r
shader.end();\r
}\r
\r
- void audio_volume(unsigned char volume)\r
+ void audio_volume(const unsigned char volume)\r
{\r
if(volume == audio_volume_)\r
return;\r
\r
audio_volume_ = volume;\r
+\r
+ auto& source = override_audio_data_;\r
if(override_audio_data_.empty())\r
- audio_data_ = frame_.audio_data();\r
+ source = frame_->audio_data();\r
+\r
+ audio_data_.resize(source.size());\r
tbb::parallel_for\r
(\r
tbb::blocked_range<size_t>(0, audio_data_.size()),\r
[&](const tbb::blocked_range<size_t>& r)\r
{\r
for(size_t n = r.begin(); n < r.end(); ++n) \r
- audio_data_[n] = static_cast<short>((static_cast<int>(audio_data_[n])*audio_volume_)>>8); \r
+ audio_data_[n] = static_cast<short>((static_cast<int>(source[n])*volume)>>8); \r
}\r
);\r
}\r
\r
const std::vector<short>& audio_data() const \r
{\r
- return !audio_data_.empty() ? audio_data_ : (!override_audio_data_.empty() ? override_audio_data_ : frame_.audio_data());\r
+ return !audio_data_.empty() ? audio_data_ : (!override_audio_data_.empty() ? override_audio_data_ : frame_->audio_data());\r
}\r
\r
unsigned char audio_volume_;\r
- draw_frame frame_;\r
+ safe_ptr<draw_frame> frame_;\r
std::vector<short> audio_data_;\r
std::vector<short> override_audio_data_;\r
shader_transform transform_; \r
};\r
\r
-transform_frame::transform_frame(const draw_frame& frame) : impl_(common::singleton_pool<implementation>::make_shared(frame)){}\r
-transform_frame::transform_frame(const draw_frame& frame, std::vector<short>&& audio_data) : impl_(common::singleton_pool<implementation>::make_shared(frame, std::move(audio_data))){}\r
-transform_frame::transform_frame(draw_frame&& frame) : impl_(common::singleton_pool<implementation>::make_shared(std::move(frame))){}\r
-transform_frame::transform_frame(const transform_frame& other) : impl_(common::singleton_pool<implementation>::make_shared(*other.impl_)){}\r
+transform_frame::transform_frame() : impl_(singleton_pool<implementation>::make_shared(draw_frame::empty())){}\r
+transform_frame::transform_frame(const safe_ptr<draw_frame>& frame) : impl_(singleton_pool<implementation>::make_shared(frame)){}\r
+transform_frame::transform_frame(const safe_ptr<draw_frame>& frame, std::vector<short>&& audio_data) : impl_(singleton_pool<implementation>::make_shared(frame, std::move(audio_data))){}\r
+transform_frame::transform_frame(safe_ptr<draw_frame>&& frame) : impl_(singleton_pool<implementation>::make_shared(std::move(frame))){}\r
+transform_frame::transform_frame(const transform_frame& other) : impl_(singleton_pool<implementation>::make_shared(*other.impl_)){}\r
void transform_frame::swap(transform_frame& other){impl_.swap(other.impl_);}\r
transform_frame& transform_frame::operator=(const transform_frame& other)\r
{\r
transform_frame temp(other);\r
- temp.impl_.swap(impl_);\r
+ temp.swap(*this);\r
return *this;\r
}\r
transform_frame::transform_frame(transform_frame&& other) : impl_(std::move(other.impl_)){}\r
transform_frame& transform_frame::operator=(transform_frame&& other)\r
{\r
- impl_ = std::move(other.impl_);\r
+ transform_frame temp(std::move(other));\r
+ temp.swap(*this);\r
return *this;\r
}\r
void transform_frame::begin_write(){impl_->begin_write();}\r
\r
namespace caspar { namespace core {\r
\r
-class transform_frame : public detail::draw_frame_impl\r
+class transform_frame : public draw_frame\r
{\r
public:\r
- transform_frame(const draw_frame& frame);\r
- transform_frame(const draw_frame& frame, std::vector<short>&& audio_data);\r
- transform_frame(draw_frame&& frame);\r
+ transform_frame();\r
+ transform_frame(const safe_ptr<draw_frame>& frame);\r
+ transform_frame(const safe_ptr<draw_frame>& frame, std::vector<short>&& audio_data);\r
+ transform_frame(safe_ptr<draw_frame>&& frame);\r
\r
void swap(transform_frame& other);\r
\r
transform_frame(const transform_frame& other);\r
- transform_frame& operator=(const transform_frame& other);\r
transform_frame(transform_frame&& other);\r
+\r
+ transform_frame& operator=(const transform_frame& other);\r
transform_frame& operator=(transform_frame&& other);\r
\r
virtual const std::vector<short>& audio_data() const;\r
\r
struct write_frame::implementation : boost::noncopyable\r
{\r
- implementation(std::vector<common::gl::pbo_ptr>&& pbos, const pixel_format_desc& desc) : pbos_(std::move(pbos)), desc_(desc){}\r
+ implementation(const pixel_format_desc& desc) : desc_(desc)\r
+ {\r
+ CASPAR_LOG(trace) << "Allocated write_frame.";\r
+\r
+ static GLenum mapping[] = {GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_BGR, GL_BGRA};\r
+ std::transform(desc_.planes.begin(), desc_.planes.end(), std::back_inserter(pbos_), [&](const pixel_format_desc::plane& plane)\r
+ {\r
+ return gl::pbo(plane.width, plane.height, mapping[plane.channels-1]);\r
+ });\r
+ end_write();\r
+ }\r
\r
void begin_write()\r
{\r
- boost::range::for_each(pbos_, std::mem_fn(&common::gl::pbo::begin_write));\r
+ boost::range::for_each(pbos_, std::mem_fn(&gl::pbo::begin_write));\r
}\r
\r
void end_write()\r
{\r
- boost::range::for_each(pbos_, std::mem_fn(&common::gl::pbo::end_write));\r
+ boost::range::for_each(pbos_, std::mem_fn(&gl::pbo::end_write));\r
}\r
\r
void draw(frame_shader& shader)\r
for(size_t n = 0; n < pbos_.size(); ++n)\r
{\r
glActiveTexture(GL_TEXTURE0+n);\r
- pbos_[n]->bind_texture();\r
+ pbos_[n].bind_texture();\r
}\r
shader.render(desc_);\r
}\r
\r
boost::iterator_range<unsigned char*> pixel_data(size_t index)\r
{\r
- auto ptr = static_cast<unsigned char*>(pbos_[index]->data());\r
- return boost::iterator_range<unsigned char*>(ptr, ptr+pbos_[index]->size());\r
+ if(index >= pbos_.size() || !pbos_[index].data())\r
+ return boost::iterator_range<const unsigned char*>();\r
+ auto ptr = static_cast<unsigned char*>(pbos_[index].data());\r
+ return boost::iterator_range<unsigned char*>(ptr, ptr+pbos_[index].size());\r
}\r
const boost::iterator_range<const unsigned char*> pixel_data(size_t index) const\r
{\r
- auto ptr = static_cast<const unsigned char*>(pbos_[index]->data());\r
- return boost::iterator_range<const unsigned char*>(ptr, ptr+pbos_[index]->size());\r
+ if(index >= pbos_.size() || !pbos_[index].data())\r
+ return boost::iterator_range<const unsigned char*>();\r
+ auto ptr = static_cast<const unsigned char*>(pbos_[index].data());\r
+ return boost::iterator_range<const unsigned char*>(ptr, ptr+pbos_[index].size());\r
+ }\r
+\r
+ void reset()\r
+ {\r
+ end_write();\r
+ audio_data_.clear();\r
}\r
\r
- std::vector<common::gl::pbo_ptr> pbos_;\r
+ std::vector<gl::pbo> pbos_;\r
std::vector<short> audio_data_;\r
const pixel_format_desc desc_;\r
};\r
\r
-write_frame::write_frame(std::vector<common::gl::pbo_ptr>&& pbos, const pixel_format_desc& desc) : impl_(common::singleton_pool<implementation>::make_shared(std::move(pbos), desc)){}\r
+write_frame::write_frame(const pixel_format_desc& desc) : impl_(singleton_pool<implementation>::make_shared(desc)){}\r
write_frame::write_frame(write_frame&& other) : impl_(std::move(other.impl_)){}\r
void write_frame::swap(write_frame& other){impl_.swap(other.impl_);}\r
write_frame& write_frame::operator=(write_frame&& other)\r
{\r
- impl_ = std::move(other.impl_);\r
+ write_frame temp(std::move(other));\r
+ temp.swap(*this);\r
return *this;\r
}\r
+void write_frame::reset(){impl_->reset();}\r
void write_frame::begin_write(){impl_->begin_write();}\r
void write_frame::end_write(){impl_->end_write();} \r
void write_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
\r
namespace caspar { namespace core {\r
\r
-class write_frame : public detail::draw_frame_impl\r
+class write_frame : public draw_frame\r
{\r
public: \r
- write_frame(std::vector<common::gl::pbo_ptr>&& pbos, const pixel_format_desc& desc);\r
+ write_frame(const pixel_format_desc& desc);\r
write_frame(write_frame&& other);\r
\r
void swap(write_frame& other);\r
\r
write_frame& operator=(write_frame&& other);\r
\r
+ void reset();\r
+\r
boost::iterator_range<unsigned char*> pixel_data(size_t index = 0);\r
const boost::iterator_range<const unsigned char*> pixel_data(size_t index = 0) const;\r
\r
\r
std::wstring color_code;\r
if(parameter.length() != 9 || parameter[0] != '#')\r
- BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("parameter") << arg_value_info(common::narrow(parameter)) << msg_info("Invalid color code"));\r
+ BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("parameter") << arg_value_info(narrow(parameter)) << msg_info("Invalid color code"));\r
\r
color_code = parameter.substr(1);\r
\r
class color_producer : public frame_producer\r
{\r
public:\r
- explicit color_producer(const std::wstring& color) : color_str_(color), color_value_(get_pixel_color_value(color)){}\r
+ explicit color_producer(const std::wstring& color) : color_str_(color), color_value_(get_pixel_color_value(color)), frame_(draw_frame::empty()){}\r
+ color_producer(color_producer&& other) : frame_(std::move(other.frame_)), color_value_(std::move(other.color_value_)), color_str_(std::move(other.color_str_)){}\r
\r
- draw_frame receive()\r
+ safe_ptr<draw_frame> receive()\r
{ \r
return frame_;\r
}\r
\r
void initialize(const frame_processor_device_ptr& frame_processor)\r
{\r
- write_frame frame = std::move(frame_processor->create_frame());\r
- __stosd(reinterpret_cast<unsigned long*>(frame.pixel_data().begin()), color_value_, frame.pixel_data().size() / sizeof(unsigned long));\r
+ auto frame = std::move(frame_processor->create_frame());\r
+ __stosd(reinterpret_cast<unsigned long*>(frame->pixel_data().begin()), color_value_, frame->pixel_data().size() / sizeof(unsigned long));\r
frame_ = std::move(frame);\r
}\r
\r
return + L"color_producer. color: " + color_str_;\r
}\r
\r
- draw_frame frame_;\r
+ safe_ptr<draw_frame> frame_;\r
unsigned int color_value_;\r
std::wstring color_str_;\r
};\r
\r
-frame_producer_ptr create_color_producer(const std::vector<std::wstring>& params)\r
+safe_ptr<frame_producer> create_color_producer(const std::vector<std::wstring>& params)\r
{\r
if(params.empty() || params[0].at(0) != '#')\r
- return nullptr;\r
- return std::make_shared<color_producer>(params[0]);\r
+ return frame_producer::empty();\r
+ return make_safe<color_producer>(params[0]);\r
}\r
\r
}}
\ No newline at end of file
\r
namespace caspar { namespace core {\r
\r
-frame_producer_ptr create_color_producer(const std::vector<std::wstring>& params);\r
+safe_ptr<frame_producer> create_color_producer(const std::vector<std::wstring>& params);\r
\r
}}\r
#include "video/video_transformer.h"\r
\r
#include "../../format/video_format.h"\r
-#include "../../processor/draw_frame.h"\r
-#include "../../processor/transform_Frame.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
namespace caspar { namespace core { namespace ffmpeg{\r
\r
-struct ffmpeg_producer : public frame_producer\r
+struct ffmpeg_producer_impl\r
{\r
public:\r
- ffmpeg_producer(const std::wstring& filename, const std::vector<std::wstring>& params) : filename_(filename), underrun_count_(0)\r
+ ffmpeg_producer_impl(const std::wstring& filename, const std::vector<std::wstring>& params) : filename_(filename), underrun_count_(0), last_frame_(draw_frame::empty())\r
{\r
if(!boost::filesystem::exists(filename))\r
- BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(common::narrow(filename)));\r
+ BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename)));\r
\r
static boost::once_flag av_register_all_flag = BOOST_ONCE_INIT;\r
boost::call_once(av_register_all, av_register_all_flag); \r
\r
input_.reset(new input());\r
input_->set_loop(std::find(params.begin(), params.end(), L"LOOP") != params.end());\r
- input_->load(common::narrow(filename_));\r
+ input_->load(narrow(filename_));\r
video_decoder_.reset(new video_decoder(input_->get_video_codec_context().get()));\r
video_transformer_.reset(new video_transformer(input_->get_video_codec_context().get()));\r
audio_decoder_.reset(new audio_decoder(input_->get_audio_codec_context().get()));\r
video_transformer_->initialize(frame_processor);\r
}\r
\r
- draw_frame receive()\r
+ safe_ptr<draw_frame> receive()\r
{\r
while(ouput_channel_.empty() && !input_->is_eof())\r
{ \r
if(!video_packet.empty())\r
{\r
auto decoded_frame = video_decoder_->execute(video_packet);\r
- auto frame = video_transformer_->execute(decoded_frame);\r
+ auto frame = make_safe<transform_frame>(video_transformer_->execute(decoded_frame));\r
video_frame_channel_.push_back(std::move(frame)); \r
}\r
}, \r
}\r
}\r
\r
- draw_frame result = last_frame_;\r
+ auto result = last_frame_;\r
if(!ouput_channel_.empty())\r
{\r
result = std::move(ouput_channel_.front());\r
- last_frame_ = transform_frame(result, std::vector<short>()); // last_frame should not have audio, override it!\r
+ last_frame_ = make_safe<transform_frame>(result, std::vector<short>()); // last_frame should not have audio, override it!\r
ouput_channel_.pop();\r
}\r
else if(input_->is_eof())\r
\r
bool has_audio_;\r
\r
- input_uptr input_; \r
+ input_uptr input_; \r
\r
- video_decoder_uptr video_decoder_;\r
- video_transformer_uptr video_transformer_;\r
- std::deque<draw_frame> video_frame_channel_;\r
+ video_decoder_uptr video_decoder_;\r
+ video_transformer_uptr video_transformer_;\r
+ std::deque<safe_ptr<transform_frame>> video_frame_channel_;\r
\r
- audio_decoder_ptr audio_decoder_;\r
- std::deque<std::vector<short>> audio_chunk_channel_;\r
+ audio_decoder_ptr audio_decoder_;\r
+ std::deque<std::vector<short>> audio_chunk_channel_;\r
\r
- std::queue<draw_frame> ouput_channel_;\r
+ std::queue<safe_ptr<transform_frame>> ouput_channel_;\r
\r
- std::wstring filename_;\r
+ std::wstring filename_;\r
+\r
+ long underrun_count_;\r
\r
- long underrun_count_;\r
+ safe_ptr<draw_frame> last_frame_;\r
\r
- draw_frame last_frame_;\r
+ video_format_desc format_desc_;\r
+};\r
\r
- video_format_desc format_desc_;\r
+class ffmpeg_producer : public frame_producer\r
+{\r
+public:\r
+ ffmpeg_producer(const std::wstring& filename, const std::vector<std::wstring>& params) : impl_(new ffmpeg_producer_impl(filename, params)){}\r
+ ffmpeg_producer(ffmpeg_producer&& other) : impl_(std::move(other.impl_)){}\r
+ virtual safe_ptr<draw_frame> receive(){return impl_->receive();}\r
+ virtual void initialize(const frame_processor_device_ptr& frame_processor){impl_->initialize(frame_processor);}\r
+ virtual std::wstring print() const{return impl_->print();}\r
+private:\r
+ std::shared_ptr<ffmpeg_producer_impl> impl_;\r
};\r
\r
-frame_producer_ptr create_ffmpeg_producer(const std::vector<std::wstring>& params)\r
+safe_ptr<frame_producer> create_ffmpeg_producer(const std::vector<std::wstring>& params)\r
{ \r
static const std::vector<std::wstring> extensions = list_of(L"mpg")(L"avi")(L"mov")(L"dv")(L"wav")(L"mp3")(L"mp4")(L"f4v")(L"flv");\r
std::wstring filename = server::media_folder() + L"\\" + params[0];\r
});\r
\r
if(ext == extensions.end())\r
- return nullptr;\r
+ return frame_producer::empty();\r
\r
- return std::make_shared<ffmpeg_producer>(filename + L"." + *ext, params);\r
+ return make_safe<ffmpeg_producer>(filename + L"." + *ext, params);\r
}\r
\r
}}}
\ No newline at end of file
\r
namespace caspar { namespace core { namespace ffmpeg {\r
\r
-frame_producer_ptr create_ffmpeg_producer(const std::vector<std::wstring>& params);\r
+safe_ptr<frame_producer> create_ffmpeg_producer(const std::vector<std::wstring>& params);\r
\r
}}}
\ No newline at end of file
std::shared_ptr<AVPacket> packet(&tmp_packet, av_free_packet); \r
tbb::queuing_mutex::scoped_lock lock(seek_mutex_); \r
\r
- if (av_read_frame(format_context_.get(), packet.get()) >= 0) // NOTE: Packet is only valid until next call of av_read_frame or av_close_input_file\r
+ if (av_read_frame(format_context_.get(), packet.get()) >= 0) // NOTE: Packet is only valid until next call of av_safe_ptr<read_frame> or av_close_input_file\r
{\r
auto buffer = std::make_shared<aligned_buffer>(packet->data, packet->data + packet->size);\r
if(packet->stream_index == video_s_index_) \r
\r
#include "../../../format/video_format.h"\r
#include "../../../processor/draw_frame.h"\r
-#include "../../../processor/draw_frame.h"\r
-#include "../../../processor/draw_frame.h"\r
#include "../../../processor/frame_processor_device.h"\r
\r
#include <tbb/parallel_for.h>\r
}\r
}\r
\r
- draw_frame execute(const std::shared_ptr<AVFrame>& decoded_frame)\r
+ safe_ptr<draw_frame> execute(const std::shared_ptr<AVFrame>& decoded_frame)\r
{ \r
if(decoded_frame == nullptr)\r
return draw_frame::eof();\r
tbb::parallel_for(0, static_cast<int>(desc_.planes.size()), 1, [&](int n)\r
{\r
auto plane = desc_.planes[n];\r
- auto result = write.pixel_data(n).begin();\r
+ auto result = write->pixel_data(n).begin();\r
auto decoded = decoded_frame->data[n];\r
auto decoded_linesize = decoded_frame->linesize[n];\r
\r
\r
AVFrame av_frame; \r
avcodec_get_frame_defaults(&av_frame);\r
- avpicture_fill(reinterpret_cast<AVPicture*>(&av_frame), write.pixel_data().begin(), PIX_FMT_BGRA, width_, height_);\r
+ avpicture_fill(reinterpret_cast<AVPicture*>(&av_frame), write->pixel_data().begin(), PIX_FMT_BGRA, width_, height_);\r
\r
sws_scale(sws_context_.get(), decoded_frame->data, decoded_frame->linesize, 0, height_, av_frame.data, av_frame.linesize); \r
\r
};\r
\r
video_transformer::video_transformer(AVCodecContext* codec_context) : impl_(new implementation(codec_context)){}\r
-draw_frame video_transformer::execute(const std::shared_ptr<AVFrame>& decoded_frame){return impl_->execute(decoded_frame);}\r
+safe_ptr<draw_frame> video_transformer::execute(const std::shared_ptr<AVFrame>& decoded_frame){return impl_->execute(decoded_frame);}\r
void video_transformer::initialize(const frame_processor_device_ptr& frame_processor){impl_->initialize(frame_processor); }\r
}}}
\ No newline at end of file
{\r
public:\r
video_transformer(AVCodecContext* codec_context);\r
- draw_frame execute(const std::shared_ptr<AVFrame>& video_packet); \r
+ safe_ptr<draw_frame> execute(const std::shared_ptr<AVFrame>& video_packet); \r
void initialize(const frame_processor_device_ptr& frame_processor);\r
private:\r
struct implementation;\r
{\r
public:\r
\r
- implementation() : ver_(template_version::invalid)\r
+ implementation() : ver_(template_version::invalid), flash_producer_(create_flash())\r
{\r
+ \r
+ }\r
+\r
+ safe_ptr<flash_producer> create_flash()\r
+ { \r
if(boost::filesystem::exists(server::template_folder()+TEXT("cg.fth.18")))\r
{\r
- flash_producer_ = std::make_shared<flash_producer>(server::template_folder()+TEXT("cg.fth.18"));\r
CASPAR_LOG(info) << L"Running version 1.8 template graphics.";\r
ver_ = template_version::_18;\r
+ return safe_ptr<flash_producer>(flash_producer(server::template_folder()+TEXT("cg.fth.18")));\r
}\r
else if(boost::filesystem::exists(server::template_folder()+TEXT("cg.fth.17")))\r
{\r
- flash_producer_ = std::make_shared<flash_producer>(server::template_folder()+TEXT("cg.fth.17"));\r
CASPAR_LOG(info) << L"Running version 1.7 template graphics.";\r
ver_ = template_version::_17;\r
+ return safe_ptr<flash_producer>(flash_producer(server::template_folder()+TEXT("cg.fth.17")));\r
}\r
else \r
- CASPAR_LOG(info) << L"No templatehost found. Template graphics will be disabled"; \r
+ BOOST_THROW_EXCEPTION(file_not_found() << msg_info("No templatehost found.")); \r
}\r
\r
void clear()\r
{\r
- flash_producer_.reset();\r
+ // TODO\r
}\r
\r
void add(int layer, const std::wstring& template_name, bool play_on_load, const std::wstring& label, const std::wstring& data)\r
{\r
- if(flash_producer_ == nullptr)\r
- return;\r
CASPAR_LOG(info) << "Invoking add-command";\r
\r
std::wstringstream param;\r
\r
void remove(int layer)\r
{\r
- if(flash_producer_ == nullptr)\r
- return;\r
CASPAR_LOG(info) << "Invoking remove-command";\r
\r
std::wstringstream param;\r
\r
void play(int layer)\r
{\r
- if(flash_producer_ == nullptr)\r
- return;\r
CASPAR_LOG(info) << "Invoking play-command";\r
\r
std::wstringstream param;\r
\r
void stop(int layer, unsigned int mix_out_duration)\r
{\r
- if(flash_producer_ == nullptr)\r
- return;\r
CASPAR_LOG(info) << "Invoking stop-command";\r
\r
std::wstringstream param;\r
\r
void next(int layer)\r
{\r
- if(flash_producer_ == nullptr)\r
- return;\r
CASPAR_LOG(info) << "Invoking next-command";\r
\r
std::wstringstream param;\r
\r
void update(int layer, const std::wstring& data)\r
{\r
- if(flash_producer_ == nullptr)\r
- return;\r
CASPAR_LOG(info) << "Invoking update-command";\r
\r
std::wstringstream param;\r
\r
void invoke(int layer, const std::wstring& label)\r
{\r
- if(flash_producer_ == nullptr)\r
- return;\r
CASPAR_LOG(info) << "Invoking invoke-command";\r
\r
std::wstringstream param;\r
flash_producer_->param(param.str());\r
}\r
\r
- draw_frame receive()\r
+ safe_ptr<draw_frame> receive()\r
{\r
- return flash_producer_ ? flash_producer_->receive() : draw_frame::empty();\r
+ return flash_producer_->receive();\r
}\r
\r
void initialize(const frame_processor_device_ptr& frame_processor)\r
{\r
frame_processor_ = frame_processor;\r
- if(flash_producer_ != nullptr)\r
- flash_producer_->initialize(frame_processor_);\r
+ flash_producer_->initialize(frame_processor_);\r
}\r
\r
std::wstring print() const\r
return L"cg_producer. back-end:" + flash_producer_->print();\r
}\r
\r
- flash_producer_ptr flash_producer_;\r
+ safe_ptr<flash_producer> flash_producer_;\r
template_version::type ver_;\r
frame_processor_device_ptr frame_processor_;\r
};\r
\r
-cg_producer_ptr get_default_cg_producer(const channel_ptr& channel, int render_layer)\r
+safe_ptr<cg_producer> get_default_cg_producer(const channel_ptr& channel, int render_layer)\r
{\r
if(!channel)\r
BOOST_THROW_EXCEPTION(null_argument() << msg_info("channel"));\r
\r
- auto producer = std::dynamic_pointer_cast<cg_producer>(channel->foreground(render_layer).get());\r
+ auto producer = std::dynamic_pointer_cast<cg_producer>(channel->foreground(render_layer).get().get_shared());\r
if(producer == nullptr)\r
{\r
producer = std::make_shared<cg_producer>(); \r
- channel->load(render_layer, producer, load_option::auto_play); \r
+ channel->load(render_layer, safe_ptr<frame_producer>::from_shared(producer), load_option::auto_play); \r
}\r
\r
- return producer;\r
+ return safe_ptr<cg_producer>::from_shared(producer);\r
}\r
\r
cg_producer::cg_producer() : impl_(new implementation()){}\r
-draw_frame cg_producer::receive(){return impl_->receive();}\r
+safe_ptr<draw_frame> cg_producer::receive(){return impl_->receive();}\r
void cg_producer::clear(){impl_->clear();}\r
void cg_producer::add(int layer, const std::wstring& template_name, bool play_on_load, const std::wstring& startFromLabel, const std::wstring& data){impl_->add(layer, template_name, play_on_load, startFromLabel, data);}\r
void cg_producer::remove(int layer){impl_->remove(layer);}\r
void cg_producer::update(int layer, const std::wstring& data){impl_->update(layer, data);}\r
void cg_producer::invoke(int layer, const std::wstring& label){impl_->invoke(layer, label);}\r
void cg_producer::initialize(const frame_processor_device_ptr& frame_processor){impl_->initialize(frame_processor);}\r
+std::wstring cg_producer::print() const{return impl_->print();}\r
}}}
\ No newline at end of file
static const unsigned int DEFAULT_LAYER = 5000;\r
\r
cg_producer();\r
+ cg_producer(cg_producer&& other) : impl_(std::move(other.impl_)){}\r
\r
- virtual draw_frame receive();\r
+ virtual safe_ptr<draw_frame> receive();\r
virtual void initialize(const frame_processor_device_ptr& frame_processor);\r
\r
void clear();\r
void next(int layer);\r
void update(int layer, const std::wstring& data);\r
void invoke(int layer, const std::wstring& label);\r
+ \r
+ virtual std::wstring print() const;\r
\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
-typedef std::shared_ptr<cg_producer> cg_producer_ptr;\r
\r
-cg_producer_ptr get_default_cg_producer(const channel_ptr& channel, int layer_index = cg_producer::DEFAULT_LAYER);\r
+safe_ptr<cg_producer> get_default_cg_producer(const channel_ptr& channel, int layer_index = cg_producer::DEFAULT_LAYER);\r
\r
}}}
\ No newline at end of file
\r
struct ct_producer : public cg_producer\r
{\r
+ ct_producer(ct_producer&& other) : initialized_(std::move(other.initialized_)), filename_(std::move(other.filename_)){}\r
ct_producer(const std::wstring& filename) : filename_(filename), initialized_(false){}\r
\r
- draw_frame receive()\r
+ safe_ptr<draw_frame> receive()\r
{\r
if(!initialized_)\r
{\r
std::wstring filename_;\r
};\r
\r
-frame_producer_ptr create_ct_producer(const std::vector<std::wstring>& params) \r
+safe_ptr<frame_producer> create_ct_producer(const std::vector<std::wstring>& params) \r
{\r
std::wstring filename = server::media_folder() + L"\\" + params[0] + L".ct";\r
- return boost::filesystem::exists(filename) ? std::make_shared<ct_producer>(filename) : nullptr;\r
+ return boost::filesystem::exists(filename) ? make_safe<ct_producer>(filename) : frame_producer::empty();\r
}\r
\r
}}}
\ No newline at end of file
\r
namespace caspar { namespace core { namespace flash{\r
\r
-frame_producer_ptr create_ct_producer(const std::vector<std::wstring>& params);\r
+safe_ptr<frame_producer> create_ct_producer(const std::vector<std::wstring>& params);\r
\r
}}}
\ No newline at end of file
: flashax_container_(nullptr), filename_(filename), self_(self), executor_([=]{run();}), invalid_count_(0)\r
{ \r
if(!boost::filesystem::exists(filename))\r
- BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(common::narrow(filename)));\r
+ BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(narrow(filename)));\r
\r
frame_buffer_.set_capacity(3); \r
}\r
{\r
CASPAR_LOG(debug) << "Retrying. Count: " << retries;\r
if(retries > 3)\r
- BOOST_THROW_EXCEPTION(operation_failed() << arg_name_info("param") << arg_value_info(common::narrow(param)));\r
+ BOOST_THROW_EXCEPTION(operation_failed() << arg_name_info("param") << arg_value_info(narrow(param)));\r
}\r
is_empty_ = false; \r
});\r
stop();\r
\r
frame_buffer_.clear();\r
- frame_buffer_.try_push(draw_frame::eof()); // EOF\r
+ frame_buffer_.try_push(draw_frame::eof().get_shared()); // EOF\r
\r
current_frame_ = nullptr;\r
});\r
auto format_desc = frame_processor_->get_video_format_desc();\r
bool is_progressive = format_desc.mode == video_mode::progressive || (flashax_container_->GetFPS() - format_desc.fps/2 == 0);\r
\r
- draw_frame result;\r
-\r
- if(is_progressive) \r
- result = do_receive(); \r
+ std::shared_ptr<draw_frame> frame;\r
+ if(is_progressive)\r
+ frame = do_receive().get_shared();\r
else\r
- result = composite_frame::interlace(do_receive(), do_receive(), format_desc.mode);\r
+ frame = composite_frame::interlace(do_receive(), do_receive(), format_desc.mode).get_shared();\r
\r
- frame_buffer_.push(result);\r
+ frame_buffer_.push(frame);\r
is_empty_ = flashax_container_->IsEmpty();\r
}\r
}\r
\r
- draw_frame do_receive()\r
+ safe_ptr<draw_frame> do_receive()\r
{\r
auto format_desc = frame_processor_->get_video_format_desc();\r
\r
} \r
\r
auto frame = frame_processor_->create_frame(format_desc.width, format_desc.height);\r
- std::copy(current_frame_->data(), current_frame_->data() + current_frame_->size(), frame.pixel_data().begin());\r
- return std::move(frame);\r
+ std::copy(current_frame_->data(), current_frame_->data() + current_frame_->size(), frame->pixel_data().begin());\r
+ return frame;\r
}\r
\r
- draw_frame receive()\r
+ safe_ptr<draw_frame> receive()\r
{ \r
- return (frame_buffer_.try_pop(last_frame_) || !is_empty_) ? last_frame_ : draw_frame::empty();\r
+ return ((frame_buffer_.try_pop(last_frame_) || !is_empty_) && last_frame_) ? safe_ptr<draw_frame>::from_shared(last_frame_) : draw_frame::empty();\r
}\r
\r
void initialize(const frame_processor_device_ptr& frame_processor)\r
\r
CComObject<flash::FlashAxContainer>* flashax_container_;\r
\r
- tbb::concurrent_bounded_queue<draw_frame> frame_buffer_;\r
+ tbb::concurrent_bounded_queue<std::shared_ptr<draw_frame>> frame_buffer_;\r
\r
- draw_frame last_frame_;\r
+ std::shared_ptr<draw_frame> last_frame_;\r
\r
bitmap_ptr current_frame_;\r
bitmap_ptr bmp_frame_;\r
flash_producer* self_;\r
\r
tbb::atomic<bool> is_empty_;\r
- common::executor executor_;\r
+ executor executor_;\r
int invalid_count_;\r
\r
frame_processor_device_ptr frame_processor_;\r
};\r
\r
flash_producer::flash_producer(const std::wstring& filename) : impl_(new implementation(this, filename)){}\r
-draw_frame flash_producer::receive(){return impl_->receive();}\r
+safe_ptr<draw_frame> flash_producer::receive(){return impl_->receive();}\r
void flash_producer::param(const std::wstring& param){impl_->param(param);}\r
void flash_producer::initialize(const frame_processor_device_ptr& frame_processor) { impl_->initialize(frame_processor);}\r
std::wstring flash_producer::print() const {return impl_->print();}\r
return L"";\r
}\r
\r
-flash_producer_ptr create_flash_producer(const std::vector<std::wstring>& params)\r
+safe_ptr<flash_producer> create_flash_producer(const std::vector<std::wstring>& params)\r
{\r
static const std::vector<std::wstring> extensions = list_of(L"swf");\r
std::wstring filename = server::media_folder() + L"\\" + params[0];\r
});\r
\r
if(ext == extensions.end())\r
- return nullptr;\r
+ BOOST_THROW_EXCEPTION(file_not_found() << msg_info(narrow(filename)));\r
\r
- return std::make_shared<flash_producer>(filename + L"." + *ext);\r
+ return make_safe<flash_producer>(filename + L"." + *ext);\r
}\r
\r
}}}
\ No newline at end of file
public:\r
\r
flash_producer(const std::wstring& filename);\r
+ flash_producer(flash_producer&& other) : impl_(std::move(other.impl_)){}\r
\r
- virtual draw_frame receive();\r
+ virtual safe_ptr<draw_frame> receive();\r
virtual void initialize(const frame_processor_device_ptr& frame_processor);\r
virtual std::wstring print() const;\r
\r
\r
};\r
\r
-typedef std::tr1::shared_ptr<flash_producer> flash_producer_ptr;\r
-\r
-flash_producer_ptr create_flash_producer(const std::vector<std::wstring>& params);\r
+safe_ptr<flash_producer> create_flash_producer(const std::vector<std::wstring>& params);\r
\r
}}}
\ No newline at end of file
--- /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
+#include "../stdafx.h"\r
+\r
+#include "frame_producer.h"\r
+\r
+namespace caspar { namespace core {\r
+ \r
+struct empty_frame_producer : public frame_producer\r
+{\r
+ virtual safe_ptr<draw_frame> receive(){return draw_frame::eof();}\r
+ virtual void initialize(const frame_processor_device_ptr&){}\r
+ virtual std::wstring print() const { return L"empty";}\r
+};\r
+\r
+safe_ptr<frame_producer> frame_producer::empty()\r
+{\r
+ static auto empty_producer = std::make_shared<empty_frame_producer>();\r
+ return safe_ptr<frame_producer>::from_shared(empty_producer);\r
+}\r
+\r
+inline std::wostream& operator<<(std::wostream& out, const frame_producer& producer)\r
+{\r
+ out << producer.print().c_str();\r
+ return out;\r
+}\r
+\r
+}}
\ No newline at end of file
\r
#include "../processor/draw_frame.h"\r
#include "../processor/frame_processor_device.h"\r
+#include "../../common/utility/safe_ptr.h"\r
\r
#include <boost/noncopyable.hpp>\r
\r
///\r
/// \return The frame. \r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
- virtual draw_frame receive() = 0;\r
+ virtual safe_ptr<draw_frame> receive() = 0;\r
\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
/// \fn virtual std::shared_ptr<frame_producer> :::get_following_producer() const\r
///\r
/// \return The following producer, or nullptr if there is no following producer. \r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
- virtual std::shared_ptr<frame_producer> get_following_producer() const { return nullptr; }\r
-\r
+ virtual safe_ptr<frame_producer> get_following_producer() const {return frame_producer::empty();}\r
+ \r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
/// \fn virtual void :::set_leading_producer(const std::shared_ptr<frame_producer>& producer)\r
///\r
///\r
/// \param producer The leading producer.\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
- virtual void set_leading_producer(const std::shared_ptr<frame_producer>& /*producer*/) {}\r
+ virtual void set_leading_producer(const safe_ptr<frame_producer>& /*producer*/) {}\r
\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
/// \fn virtual void :::initialize(const frame_processor_device_ptr& frame_processor) = 0;\r
////////////////////////////////////////////////////////////////////////////////////////////////////\r
virtual void initialize(const frame_processor_device_ptr& frame_processor) = 0;\r
\r
- virtual std::wstring print() const { return L"Unknown frame_producer.";}\r
+ static safe_ptr<frame_producer> empty();\r
\r
- static const std::shared_ptr<frame_producer>& empty()\r
- { \r
- struct empty_frame_producer : public frame_producer\r
- {\r
- virtual draw_frame receive(){return draw_frame::empty();}\r
- virtual std::shared_ptr<frame_producer> get_following_producer() const { return nullptr; }\r
- virtual void initialize(const frame_processor_device_ptr&){}\r
- };\r
- static std::shared_ptr<frame_producer> empty_producer = std::make_shared<empty_frame_producer>();\r
- return empty_producer;\r
- }\r
+ virtual std::wstring print() const = 0;\r
};\r
-typedef std::shared_ptr<frame_producer> frame_producer_ptr;\r
\r
-inline std::wostream& operator<<(std::wostream& out, const frame_producer& producer)\r
-{\r
- out << producer.print().c_str();\r
- return out;\r
-}\r
+inline std::wostream& operator<<(std::wostream& out, const frame_producer& producer);\r
\r
-}}
\ No newline at end of file
+}}\r
\r
namespace caspar { namespace core {\r
\r
-std::vector<draw_frame> receive(std::map<int, layer>& layers)\r
+std::vector<safe_ptr<draw_frame>> receive(std::map<int, layer>& layers)\r
{ \r
- std::vector<draw_frame> frames(layers.size(), draw_frame::empty());\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
executor_.begin_invoke([=]{tick();});\r
}\r
\r
- void load(int render_layer, const frame_producer_ptr& producer, load_option::type option)\r
+ void load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option)\r
{\r
producer->initialize(frame_processor_);\r
executor_.begin_invoke([=]\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.background())\r
- layers_.erase(it);\r
- }\r
+ if(it != layers_.end()) \r
+ it->second.stop(); \r
+ if(it->second.empty())\r
+ layers_.erase(it);\r
});\r
}\r
\r
});\r
} \r
\r
- boost::unique_future<frame_producer_ptr> foreground(int render_layer) const\r
+ boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const\r
{\r
- return executor_.begin_invoke([=]() -> frame_producer_ptr\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() : nullptr;\r
+ return it != layers_.end() ? it->second.foreground() : frame_producer::empty();\r
});\r
}\r
\r
- boost::unique_future<frame_producer_ptr> background(int render_layer) const\r
+ boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const\r
{\r
- return executor_.begin_invoke([=]() -> frame_producer_ptr\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() : nullptr;\r
+ return it != layers_.end() ? it->second.background() : frame_producer::empty();\r
});\r
}\r
- mutable common::executor executor_;\r
+ mutable executor executor_;\r
\r
frame_processor_device_ptr frame_processor_;\r
\r
};\r
\r
frame_producer_device::frame_producer_device(const frame_processor_device_ptr& frame_processor) : impl_(new implementation(frame_processor)){}\r
-void frame_producer_device::load(int render_layer, const frame_producer_ptr& producer, load_option::type option){impl_->load(render_layer, producer, option);}\r
+void frame_producer_device::load(int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option){impl_->load(render_layer, producer, option);}\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<frame_producer_ptr> frame_producer_device::foreground(int render_layer) const {return impl_->foreground(render_layer);}\r
-boost::unique_future<frame_producer_ptr> frame_producer_device::background(int render_layer) const {return impl_->background(render_layer);}\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
public:\r
frame_producer_device(const frame_processor_device_ptr& frame_processor);\r
\r
- void load (int render_layer, const frame_producer_ptr& producer, load_option::type option = load_option::none); \r
+ void load (int render_layer, const safe_ptr<frame_producer>& producer, load_option::type option = load_option::none); \r
void pause (int render_layer);\r
void play (int render_layer);\r
void stop (int render_layer);\r
void clear (int render_layer);\r
void clear ();\r
\r
- boost::unique_future<frame_producer_ptr> foreground(int render_layer) const;\r
- boost::unique_future<frame_producer_ptr> background(int render_layer) const;\r
+ boost::unique_future<safe_ptr<frame_producer>> foreground(int render_layer) const;\r
+ boost::unique_future<safe_ptr<frame_producer>> background(int render_layer) const;\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
std::shared_ptr<FIBITMAP> load_image(const std::wstring& filename)\r
{\r
- return load_image(common::narrow(filename));\r
+ return load_image(narrow(filename));\r
}\r
\r
}}}
\ No newline at end of file
\r
struct image_producer : public frame_producer\r
{\r
- image_producer(const std::wstring& filename) : filename_(filename) {}\r
+ image_producer(image_producer&& other) : frame_processor_(std::move(other.frame_processor_)), filename_(std::move(other.filename_)), frame_(draw_frame::empty()){}\r
+ image_producer(const std::wstring& filename) : filename_(filename), frame_(draw_frame::empty()) {}\r
\r
- draw_frame receive(){return frame_;}\r
+ safe_ptr<draw_frame> receive(){return frame_;}\r
\r
void initialize(const frame_processor_device_ptr& frame_processor)\r
{\r
auto bitmap = load_image(filename_);\r
FreeImage_FlipVertical(bitmap.get());\r
auto frame = frame_processor->create_frame(FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()));\r
- std::copy_n(FreeImage_GetBits(bitmap.get()), frame.pixel_data().size(), frame.pixel_data().begin());\r
+ std::copy_n(FreeImage_GetBits(bitmap.get()), frame->pixel_data().size(), frame->pixel_data().begin());\r
frame_ = std::move(frame);\r
}\r
\r
\r
frame_processor_device_ptr frame_processor_;\r
std::wstring filename_;\r
- draw_frame frame_;\r
+ safe_ptr<draw_frame> frame_;\r
};\r
\r
-frame_producer_ptr create_image_producer(const std::vector<std::wstring>& params)\r
+safe_ptr<frame_producer> create_image_producer(const std::vector<std::wstring>& params)\r
{\r
static const std::vector<std::wstring> extensions = list_of(L"png")(L"tga")(L"bmp")(L"jpg")(L"jpeg");\r
std::wstring filename = server::media_folder() + L"\\" + params[0];\r
});\r
\r
if(ext == extensions.end())\r
- return nullptr;\r
+ return frame_producer::empty();\r
\r
- return std::make_shared<image_producer>(filename + L"." + *ext);\r
+ return make_safe<image_producer>(filename + L"." + *ext);\r
}\r
\r
}}}
\ No newline at end of file
\r
namespace caspar { namespace core { namespace image {\r
\r
-frame_producer_ptr create_image_producer(const std::vector<std::wstring>& params);\r
+safe_ptr<frame_producer> create_image_producer(const std::vector<std::wstring>& params);\r
\r
}}}
\ No newline at end of file
// if(pos != std::wstring::npos)\r
// {\r
// speedStr = speedStr.substr(0, pos); \r
-// speed_ = common::lexical_cast_or_default<int>(speedStr, image_scroll_producer::DEFAULT_SCROLL_SPEED);\r
+// speed_ = lexical_cast_or_default<int>(speedStr, image_scroll_producer::DEFAULT_SCROLL_SPEED);\r
// }\r
// }\r
//\r
// return std::move(frame);\r
// }\r
// \r
-// draw_frame receive()\r
+// safe_ptr<draw_frame> receive()\r
// { \r
// if(format_desc_.mode != video_mode::progressive) \r
// {\r
// frame_processor_device_ptr frame_processor_;\r
//};\r
//\r
-//frame_producer_ptr create_image_scroll_producer(const std::vector<std::wstring>& params)\r
+//safe_ptr<frame_producer> create_image_scroll_producer(const std::vector<std::wstring>& params)\r
//{\r
// static const std::vector<std::wstring> extensions = list_of(L"spng")(L"stga")(L"sbmp")(L"sjpg")(L"sjpeg");\r
// std::wstring filename = server::media_folder() + L"\\" + params[0];\r
\r
namespace caspar { namespace core { namespace image {\r
\r
-frame_producer_ptr create_image_scroll_producer(const std::vector<std::wstring>& params);\r
+safe_ptr<frame_producer> create_image_scroll_producer(const std::vector<std::wstring>& params);\r
\r
}}}
\ No newline at end of file
\r
struct layer::implementation\r
{ \r
- implementation() : foreground_(nullptr), background_(nullptr), last_frame_(draw_frame::empty()) {}\r
+ implementation() : foreground_(frame_producer::empty()), background_(frame_producer::empty()), last_frame_(draw_frame::empty()) {}\r
\r
- void load(const frame_producer_ptr& frame_producer, load_option::type option)\r
+ void load(const safe_ptr<frame_producer>& frame_producer, load_option::type option)\r
{ \r
background_ = frame_producer;\r
if(option == load_option::preview) \r
{\r
- foreground_ = nullptr; \r
+ foreground_ = frame_producer::empty(); \r
last_frame_ = frame_producer->receive();\r
}\r
else if(option == load_option::auto_play)\r
\r
void play()\r
{ \r
- if(background_ != nullptr)\r
- {\r
- background_->set_leading_producer(foreground_);\r
- foreground_ = std::move(background_);\r
- }\r
-\r
+ background_->set_leading_producer(foreground_);\r
+ foreground_ = background_;\r
+ background_ = frame_producer::empty();\r
is_paused_ = false;\r
+ CASPAR_LOG(info) << L"Started: " << foreground_->print();\r
}\r
\r
void pause()\r
\r
void stop()\r
{\r
- foreground_ = nullptr;\r
+ foreground_ = frame_producer::empty();\r
last_frame_ = draw_frame::empty();\r
}\r
\r
void clear()\r
{\r
- foreground_ = nullptr;\r
- background_ = nullptr;\r
+ foreground_ = frame_producer::empty();\r
+ background_ = frame_producer::empty();\r
last_frame_ = draw_frame::empty();\r
}\r
\r
- draw_frame receive()\r
+ safe_ptr<draw_frame> receive()\r
{ \r
- if(!foreground_ || is_paused_)\r
+ if(foreground_ == frame_producer::empty() || is_paused_)\r
return last_frame_;\r
\r
try\r
\r
if(last_frame_ == draw_frame::eof())\r
{\r
- CASPAR_LOG(info) << L"EOF: " << foreground_->print();\r
+ CASPAR_LOG(info) << L"Ended: " << foreground_->print();\r
auto following = foreground_->get_following_producer();\r
- if(following)\r
- following->set_leading_producer(foreground_);\r
+ following->set_leading_producer(foreground_);\r
foreground_ = following;\r
last_frame_ = receive();\r
}\r
try\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
- CASPAR_LOG(warning) << L"Removed " << (foreground_ ? foreground_->print() : L"empty") << L" from layer.";\r
- foreground_ = nullptr;\r
+ CASPAR_LOG(warning) << L"Removed " << foreground_->print() << L" from layer.";\r
+ foreground_ = frame_producer::empty();\r
last_frame_ = draw_frame::empty();\r
}\r
catch(...){}\r
return last_frame_;\r
} \r
\r
- tbb::atomic<bool> is_paused_;\r
- draw_frame last_frame_;\r
- frame_producer_ptr foreground_;\r
- frame_producer_ptr background_;\r
+ tbb::atomic<bool> is_paused_;\r
+ safe_ptr<draw_frame> last_frame_;\r
+ safe_ptr<frame_producer> foreground_;\r
+ safe_ptr<frame_producer> background_;\r
};\r
\r
layer::layer() : impl_(new implementation()){}\r
other.impl_ = nullptr;\r
return *this;\r
}\r
-void layer::load(const frame_producer_ptr& frame_producer, load_option::type option){return impl_->load(frame_producer, option);} \r
+void layer::load(const safe_ptr<frame_producer>& frame_producer, load_option::type option){return impl_->load(frame_producer, option);} \r
void layer::play(){impl_->play();}\r
void layer::pause(){impl_->pause();}\r
void layer::stop(){impl_->stop();}\r
void layer::clear(){impl_->clear();}\r
-draw_frame layer::receive() {return impl_->receive();}\r
-frame_producer_ptr layer::foreground() const { return impl_->foreground_;}\r
-frame_producer_ptr layer::background() const { return impl_->background_;}\r
+bool layer::empty() const { return impl_->foreground_ == frame_producer::empty() && impl_->background_ == frame_producer::empty();}\r
+safe_ptr<draw_frame> layer::receive() {return impl_->receive();}\r
+safe_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}\r
+safe_ptr<frame_producer> layer::background() const { return impl_->background_;}\r
}}
\ No newline at end of file
layer(layer&& other);\r
layer& operator=(layer&& other);\r
\r
- void load(const frame_producer_ptr& producer, load_option::type option = load_option::none); \r
+ void load(const safe_ptr<frame_producer>& producer, load_option::type option = load_option::none); \r
void play();\r
void pause();\r
void stop();\r
void clear();\r
+\r
+ bool empty() const;\r
\r
- frame_producer_ptr foreground() const;\r
- frame_producer_ptr background() const;\r
+ safe_ptr<frame_producer> foreground() const;\r
+ safe_ptr<frame_producer> background() const;\r
\r
- draw_frame receive();\r
+ safe_ptr<draw_frame> receive();\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
\r
struct transition_producer::implementation : boost::noncopyable\r
{\r
- implementation(const frame_producer_ptr& dest, const transition_info& info) : current_frame_(0), info_(info), dest_producer_(dest), org_dest_producer_(dest)\r
- {\r
- if(!dest)\r
- BOOST_THROW_EXCEPTION(null_argument() << arg_name_info("dest"));\r
- }\r
+ implementation(const safe_ptr<frame_producer>& dest, const transition_info& info) : current_frame_(0), info_(info), \r
+ dest_producer_(dest), org_dest_producer_(dest), org_source_producer_(frame_producer::empty()), source_producer_(frame_producer::empty())\r
+ {}\r
\r
- frame_producer_ptr get_following_producer() const\r
+ safe_ptr<frame_producer> get_following_producer() const\r
{\r
return dest_producer_;\r
}\r
\r
- void set_leading_producer(const frame_producer_ptr& producer)\r
+ void set_leading_producer(const safe_ptr<frame_producer>& producer)\r
{\r
org_source_producer_ = source_producer_ = producer;\r
}\r
\r
- draw_frame receive()\r
+ safe_ptr<draw_frame> receive()\r
{\r
- if(current_frame_ == 0)\r
- CASPAR_LOG(info) << "Transition started.";\r
-\r
- draw_frame result = [&]() -> draw_frame\r
+ safe_ptr<draw_frame> result = [&]() -> safe_ptr<draw_frame>\r
{\r
if(current_frame_++ >= info_.duration)\r
return draw_frame::eof();\r
\r
- draw_frame source;\r
- draw_frame dest;\r
+ safe_ptr<draw_frame> source(draw_frame::empty());\r
+ safe_ptr<draw_frame> dest(draw_frame::empty());\r
\r
tbb::parallel_invoke\r
(\r
return compose(dest, source);\r
}();\r
\r
- if(result == draw_frame::eof())\r
- CASPAR_LOG(info) << "Transition ended.";\r
-\r
return result;\r
}\r
\r
- draw_frame receive(frame_producer_ptr& producer)\r
+ safe_ptr<draw_frame> receive(safe_ptr<frame_producer>& producer)\r
{\r
- if(!producer)\r
+ if(producer == frame_producer::empty())\r
return draw_frame::eof();\r
\r
- draw_frame frame = draw_frame::eof();\r
+ auto frame = draw_frame::eof();\r
try\r
{\r
frame = producer->receive();\r
catch(...)\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
- producer = nullptr;\r
- CASPAR_LOG(warning) << "Removed producer from transition.";\r
+ producer = frame_producer::empty();\r
+ CASPAR_LOG(warning) << "Failed to receive frame. Removed producer from transition.";\r
}\r
\r
if(frame == draw_frame::eof())\r
{\r
- if(!producer || !producer->get_following_producer())\r
- return draw_frame::eof();\r
-\r
try\r
{\r
auto following = producer->get_following_producer();\r
}\r
catch(...)\r
{\r
- CASPAR_LOG(warning) << "Failed to initialize following producer. Removing it.";\r
- producer = nullptr;\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ producer = frame_producer::empty();\r
+ CASPAR_LOG(warning) << "Failed to initialize following producer. Removed producer from transition.";\r
}\r
\r
return receive(producer);\r
return frame;\r
}\r
\r
- draw_frame compose(draw_frame dest_frame, draw_frame src_frame) \r
+ safe_ptr<draw_frame> compose(safe_ptr<draw_frame> dest_frame, safe_ptr<draw_frame> src_frame) \r
{ \r
if(dest_frame == draw_frame::eof() && src_frame == draw_frame::eof())\r
return draw_frame::eof();\r
\r
std::wstring print() const\r
{\r
- return L"transition_producer. dest: " + (org_dest_producer_ ? org_dest_producer_->print() : L"empty") + L" src: " + (org_source_producer_ ? org_source_producer_->print() : L"empty");\r
+ return L"transition_producer. dest: " + (org_dest_producer_->print()) + L" src: " + (org_source_producer_->print());\r
}\r
\r
- frame_producer_ptr org_source_producer_;\r
- frame_producer_ptr org_dest_producer_;\r
+ safe_ptr<frame_producer> org_source_producer_;\r
+ safe_ptr<frame_producer> org_dest_producer_;\r
\r
- frame_producer_ptr source_producer_;\r
- frame_producer_ptr dest_producer_;\r
+ safe_ptr<frame_producer> source_producer_;\r
+ safe_ptr<frame_producer> dest_producer_;\r
\r
unsigned short current_frame_;\r
\r
frame_processor_device_ptr frame_processor_;\r
};\r
\r
-transition_producer::transition_producer(const frame_producer_ptr& dest, const transition_info& info) : impl_(new implementation(dest, info)){}\r
-draw_frame transition_producer::receive(){return impl_->receive();}\r
-frame_producer_ptr transition_producer::get_following_producer() const{return impl_->get_following_producer();}\r
-void transition_producer::set_leading_producer(const frame_producer_ptr& producer) { impl_->set_leading_producer(producer); }\r
+transition_producer::transition_producer(const safe_ptr<frame_producer>& dest, const transition_info& info) : impl_(new implementation(dest, info)){}\r
+safe_ptr<draw_frame> transition_producer::receive(){return impl_->receive();}\r
+safe_ptr<frame_producer> transition_producer::get_following_producer() const{return impl_->get_following_producer();}\r
+void transition_producer::set_leading_producer(const safe_ptr<frame_producer>& producer) { impl_->set_leading_producer(producer); }\r
void transition_producer::initialize(const frame_processor_device_ptr& frame_processor) { impl_->initialize(frame_processor);}\r
std::wstring transition_producer::print() const { return impl_->print();}\r
\r
class transition_producer : public frame_producer\r
{\r
public:\r
- transition_producer(const frame_producer_ptr& destination, const transition_info& info);\r
+ transition_producer(const safe_ptr<frame_producer>& destination, const transition_info& info);\r
+ transition_producer(transition_producer&& other) : impl_(std::move(other.impl_)){}\r
+ safe_ptr<draw_frame> receive();\r
\r
- draw_frame receive();\r
-\r
- frame_producer_ptr get_following_producer() const;\r
- void set_leading_producer(const frame_producer_ptr& producer);\r
+ safe_ptr<frame_producer> get_following_producer() const;\r
+ void set_leading_producer(const safe_ptr<frame_producer>& producer);\r
virtual void initialize(const frame_processor_device_ptr& frame_processor);\r
virtual std::wstring print() const;\r
private:\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
-typedef std::shared_ptr<transition_producer> transition_producer_ptr;\r
\r
}}
\ No newline at end of file
#include "AMCPCommandQueue.h"\r
\r
namespace caspar { namespace core { namespace amcp {\r
-\r
-using namespace common;\r
-\r
+ \r
AMCPCommandQueue::AMCPCommandQueue() : newCommandEvent_(FALSE, FALSE) \r
{}\r
\r
\r
namespace caspar { namespace core { namespace amcp {\r
\r
-class AMCPCommandQueue : public common::IRunnable\r
+class AMCPCommandQueue : public IRunnable\r
{\r
AMCPCommandQueue(const AMCPCommandQueue&);\r
AMCPCommandQueue& operator=(const AMCPCommandQueue&);\r
void AddCommand(AMCPCommandPtr pCommand);\r
\r
private:\r
- common::Thread commandPump_;\r
+ Thread commandPump_;\r
virtual void Run(HANDLE stopEvent);\r
virtual bool OnUnhandledException(const std::exception& ex) throw();\r
\r
- common::Event newCommandEvent_;\r
+ Event newCommandEvent_;\r
\r
//Needs synro-protection\r
std::list<AMCPCommandPtr> commands_;\r
}\r
\r
namespace amcp {\r
-\r
-using namespace common;\r
-\r
+ \r
AMCPCommand::AMCPCommand() : channelIndex_(0), scheduling_(Default), layerIndex_(-1)\r
{}\r
\r
try\r
{\r
auto pFP = load_media(_parameters);\r
- if(pFP == nullptr)\r
- BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? common::narrow(_parameters[0]) : ""));\r
+ if(pFP == frame_producer::empty())\r
+ BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
\r
- pFP = std::make_shared<transition_producer>(pFP, transitionInfo);\r
+ pFP = safe_ptr<frame_producer>(transition_producer(pFP, transitionInfo));\r
bool autoPlay = std::find(_parameters.begin(), _parameters.end(), TEXT("AUTOPLAY")) != _parameters.end();\r
GetChannel()->load(GetLayerIndex(), pFP, autoPlay ? load_option::auto_play : load_option::none); // TODO: LOOP\r
\r
\r
void GenerateChannelInfo(int index, const channel_ptr& pChannel, std::wstringstream& replyString)\r
{\r
- replyString << index << TEXT(" ") << pChannel->get_video_format_desc().name << TEXT("\r\n") << (pChannel->foreground(0).get() != nullptr ? TEXT(" PLAYING") : TEXT(" STOPPED"));\r
+ replyString << index << TEXT(" ") << pChannel->get_video_format_desc().name << TEXT("\r\n") << (pChannel->foreground(0).get()->print());\r
}\r
\r
bool InfoCommand::DoExecute()\r
\r
namespace caspar { namespace core { namespace amcp {\r
\r
-using namespace common;\r
using IO::ClientInfoPtr;\r
\r
const std::wstring AMCPProtocolStrategy::MessageDelimiter = TEXT("\r\n");\r
#endif\r
\r
namespace caspar { namespace core { namespace cii {\r
-\r
-using namespace common;\r
-\r
+ \r
const std::wstring CIIProtocolStrategy::MessageDelimiter = TEXT("\r\n");\r
const TCHAR CIIProtocolStrategy::TokenDelimiter = TEXT('\\');\r
\r
std::vector<std::wstring> params;\r
params.push_back(server::template_folder()+TEXT("CG.fth"));\r
auto pFP = flash::create_flash_producer(params);\r
- if(pFP != 0)\r
- {\r
- //TODO: Initialize with valid FrameFactory\r
-// pFP->Initialize(0, false);\r
\r
- std::wstringstream flashParam;\r
- flashParam << TEXT("<invoke name=\"Add\" returntype=\"xml\"><arguments><number>1</number><string>") << currentProfile_ << '/' << templateName << TEXT("</string><number>0</number><true/><string> </string><string><![CDATA[ ") << xmlData << TEXT(" ]]></string></arguments></invoke>");\r
- pFP->param(flashParam.str());\r
+ std::wstringstream flashParam;\r
+ flashParam << TEXT("<invoke name=\"Add\" returntype=\"xml\"><arguments><number>1</number><string>") << currentProfile_ << '/' << templateName << TEXT("</string><number>0</number><true/><string> </string><string><![CDATA[ ") << xmlData << TEXT(" ]]></string></arguments></invoke>");\r
+ pFP->param(flashParam.str());\r
\r
- CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;\r
+ CASPAR_LOG(info) << "Saved an instance of " << templateName << TEXT(" as ") << titleName ;\r
\r
- PutPreparedTemplate(titleName, std::static_pointer_cast<frame_producer>(pFP));\r
- }\r
+ PutPreparedTemplate(titleName, safe_ptr<frame_producer>(std::move(*pFP)));\r
+ \r
}\r
\r
void CIIProtocolStrategy::DisplayTemplate(const std::wstring& titleName)\r
transition.duration = 12;\r
\r
auto pFP = load_media(boost::assign::list_of(filename));\r
- auto pTransition = std::make_shared<transition_producer>(pFP, transition);\r
+ auto pTransition = safe_ptr<frame_producer>(transition_producer(pFP, transition));\r
\r
try\r
{\r
CASPAR_LOG(info) << L"Displayed " << filename;\r
}\r
\r
-frame_producer_ptr CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)\r
+safe_ptr<frame_producer> CIIProtocolStrategy::GetPreparedTemplate(const std::wstring& titleName)\r
{\r
- frame_producer_ptr result;\r
+ safe_ptr<frame_producer> result(frame_producer::empty());\r
\r
TitleList::iterator it = std::find(titles_.begin(), titles_.end(), titleName);\r
if(it != titles_.end()) {\r
return result;\r
}\r
\r
-void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, frame_producer_ptr& pFP)\r
+void CIIProtocolStrategy::PutPreparedTemplate(const std::wstring& titleName, safe_ptr<frame_producer>& pFP)\r
{\r
CASPAR_LOG(debug) << L"Saved title with name " << titleName;\r
\r
public:\r
struct TitleHolder\r
{\r
- TitleHolder() : titleName(TEXT("")) {}\r
- TitleHolder(const std::wstring& name, frame_producer_ptr pFP) : titleName(name), pframe_producer(pFP) {}\r
+ TitleHolder() : titleName(TEXT("")), pframe_producer(frame_producer::empty()) {}\r
+ TitleHolder(const std::wstring& name, safe_ptr<frame_producer> pFP) : titleName(name), pframe_producer(pFP) {}\r
TitleHolder(const TitleHolder& th) : titleName(th.titleName), pframe_producer(th.pframe_producer) {}\r
const TitleHolder& operator=(const TitleHolder& th) \r
{\r
}\r
\r
std::wstring titleName;\r
- frame_producer_ptr pframe_producer;\r
+ safe_ptr<frame_producer> pframe_producer;\r
friend CIIProtocolStrategy;\r
};\r
private:\r
\r
typedef std::list<TitleHolder> TitleList;\r
TitleList titles_;\r
- frame_producer_ptr GetPreparedTemplate(const std::wstring& name);\r
- void PutPreparedTemplate(const std::wstring& name, frame_producer_ptr& pframe_producer);\r
+ safe_ptr<frame_producer> GetPreparedTemplate(const std::wstring& name);\r
+ void PutPreparedTemplate(const std::wstring& name, safe_ptr<frame_producer>& pframe_producer);\r
\r
static const TCHAR TokenDelimiter;\r
static const std::wstring MessageDelimiter;\r
int TokenizeMessage(const std::wstring& message, std::vector<std::wstring>* pTokenVector);\r
CIICommandPtr Create(const std::wstring& name);\r
\r
- common::executor executor_;\r
+ executor executor_;\r
std::wstring currentMessage_;\r
\r
std::wstring currentProfile_;\r
#include <algorithm>\r
\r
namespace caspar { namespace core { namespace CLK {\r
-\r
-using namespace common;\r
-\r
+ \r
CLKProtocolStrategy::CLKProtocolStrategy(const std::vector<channel_ptr>& channels) \r
: currentState_(ExpectingNewCommand), bClockLoaded_(false) \r
{ \r
\r
namespace caspar { namespace core { \r
\r
-frame_producer_ptr load_media(const std::vector<std::wstring>& params)\r
+safe_ptr<frame_producer> load_media(const std::vector<std::wstring>& params)\r
{ \r
- typedef std::function<frame_producer_ptr(const std::vector<std::wstring>&)> producer_factory;\r
+ typedef std::function<safe_ptr<frame_producer>(const std::vector<std::wstring>&)> producer_factory;\r
\r
const auto producer_factories = list_of<producer_factory>\r
- (&flash::create_flash_producer)\r
(&flash::create_ct_producer)\r
(&image::create_image_producer)\r
// (&image::create_image_scroll_producer)\r
if(params.empty())\r
BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
\r
- frame_producer_ptr producer;\r
+ safe_ptr<frame_producer> producer(frame_producer::empty());\r
std::any_of(producer_factories.begin(), producer_factories.end(), [&](const producer_factory& factory) -> bool\r
{\r
try\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
}\r
- return producer != nullptr;\r
+ return producer != frame_producer::empty();\r
});\r
\r
return producer;\r
\r
namespace caspar { namespace core { \r
\r
-frame_producer_ptr load_media(const std::vector<std::wstring>& params);\r
+safe_ptr<frame_producer> load_media(const std::vector<std::wstring>& params);\r
\r
}}\r
boost::property_tree::read_xml(initialPath + "\\caspar.config", pt);\r
\r
auto paths = pt.get_child("configuration.paths");\r
- media_folder_ = common::widen(paths.get("media-path", initialPath + "\\media\\"));\r
- log_folder_ = common::widen(paths.get("log-path", initialPath + "\\log\\"));\r
- template_folder_ = common::widen(paths.get("template-path", initialPath + "\\template\\"));\r
- data_folder_ = common::widen(paths.get("data-path", initialPath + "\\data\\"));\r
+ media_folder_ = widen(paths.get("media-path", initialPath + "\\media\\"));\r
+ log_folder_ = widen(paths.get("log-path", initialPath + "\\log\\"));\r
+ template_folder_ = widen(paths.get("template-path", initialPath + "\\template\\"));\r
+ data_folder_ = widen(paths.get("data-path", initialPath + "\\data\\"));\r
}\r
\r
void setup_channels(boost::property_tree::ptree& pt)\r
using boost::property_tree::ptree;\r
BOOST_FOREACH(auto& xml_channel, pt.get_child("configuration.channels"))\r
{ \r
- auto format_desc = video_format_desc::get(common::widen(xml_channel.second.get("videomode", "PAL"))); \r
+ auto format_desc = video_format_desc::get(widen(xml_channel.second.get("videomode", "PAL"))); \r
if(format_desc.format == video_format::invalid)\r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Invalid videomode."));\r
std::vector<frame_consumer_ptr> consumers;\r
\r
using namespace caspar;\r
using namespace caspar::core;\r
-using namespace caspar::common;\r
\r
class win32_handler_tbb_installer : public tbb::task_scheduler_observer\r
{\r