namespace caspar { namespace core {\r
\r
struct channel::implementation : boost::noncopyable\r
-{ \r
- mutable executor executor_;\r
- \r
+{ \r
const safe_ptr<frame_processor_device> processor_device_;\r
frame_consumer_device consumer_device_;\r
\r
\r
const video_format_desc format_desc_;\r
\r
+ mutable executor executor_;\r
+\r
public:\r
- implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) \r
+ implementation(const video_format_desc& format_desc) \r
: format_desc_(format_desc)\r
, processor_device_(frame_processor_device(format_desc))\r
- , consumer_device_(format_desc, consumers)\r
+ , consumer_device_(format_desc)\r
{\r
executor_.start();\r
executor_.begin_invoke([=]{tick();});\r
return draw_frame(frames);\r
}\r
\r
+ void add(int index, const safe_ptr<frame_consumer>& consumer)\r
+ {\r
+ consumer_device_.add(index, consumer);\r
+ }\r
+ \r
+ void remove(int index)\r
+ {\r
+ consumer_device_.remove(index);\r
+ }\r
+\r
void load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load)\r
{\r
+ CASPAR_LOG(trace) << executor_.size();\r
producer->initialize(processor_device_);\r
executor_.begin_invoke([=]\r
{\r
};\r
\r
channel::channel(channel&& other) : impl_(std::move(other.impl_)){}\r
-channel::channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) : impl_(new implementation(format_desc, consumers)){}\r
+channel::channel(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+void channel::add(int index, const safe_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
+void channel::remove(int index){impl_->remove(index);}\r
void channel::load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load){impl_->load(index, producer, play_on_load);}\r
void channel::preview(int index, const safe_ptr<frame_producer>& producer){impl_->preview(index, producer);}\r
void channel::pause(int index){impl_->pause(index);}\r
class channel : boost::noncopyable\r
{\r
public:\r
- explicit channel(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
+ explicit channel(const video_format_desc& format_desc);\r
channel(channel&& other);\r
\r
+ void add(int index, const safe_ptr<frame_consumer>& consumer);\r
+ void remove(int index);\r
+\r
void load(int index, const safe_ptr<frame_producer>& producer, bool play_on_load = false);\r
void preview(int index, const safe_ptr<frame_producer>& producer);\r
void pause(int index);\r
\r
#include <memory>\r
\r
-namespace caspar { namespace core { namespace bluefish {\r
+namespace caspar { namespace core {\r
\r
CBlueVelvet4* (*BlueVelvetFactory4)();\r
BLUE_UINT32 (*encode_hanc_frame)(struct hanc_stream_info_struct * hanc_stream_ptr, void * audio_pcm_ptr,BLUE_UINT32 no_audio_ch,BLUE_UINT32 no_audio_samples,BLUE_UINT32 nTypeOfSample,BLUE_UINT32 emb_audio_flag);\r
blue_hanc_initialize();\r
}\r
\r
-struct consumer::implementation : boost::noncopyable\r
+struct bluefish_consumer::implementation : boost::noncopyable\r
{\r
boost::unique_future<void> active_;\r
executor executor_;\r
}\r
};\r
\r
-consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\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 safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
-}}}
\ No newline at end of file
+bluefish_consumer::bluefish_consumer(bluefish_consumer&& other) : impl_(std::move(other.impl_)){}\r
+bluefish_consumer::bluefish_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 bluefish_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t bluefish_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+ \r
+safe_ptr<frame_consumer> create_bluefish_consumer(const std::vector<std::wstring>& params)\r
+{\r
+ if(params.size() < 2 || params[0] != L"BLUEFISH")\r
+ return frame_consumer::empty();\r
+\r
+ auto format_desc = video_format_desc::get(params[1]);\r
+ if(format_desc.format == video_format::invalid)\r
+ return frame_consumer::empty();\r
+ \r
+ int device_index = 1;\r
+ bool embed_audio = false;\r
+\r
+ try{device_index = boost::lexical_cast<int>(params[2]);}\r
+ catch(boost::bad_lexical_cast&){}\r
+ try{embed_audio = boost::lexical_cast<bool>(params[3]);}\r
+ catch(boost::bad_lexical_cast&){}\r
+\r
+ return make_safe<bluefish_consumer>(format_desc, device_index, embed_audio);\r
+}\r
+\r
+}}
\ No newline at end of file
#include "../../video_format.h"\r
#include "../../consumer/frame_consumer.h"\r
\r
-namespace caspar { namespace core { namespace bluefish {\r
+namespace caspar { namespace core {\r
\r
struct bluefish_exception : public caspar_exception{};\r
\r
-class consumer : public frame_consumer\r
+class bluefish_consumer : public frame_consumer\r
{\r
public:\r
- explicit consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio = false);\r
- consumer(consumer&& other);\r
+ explicit bluefish_consumer(const video_format_desc& format_desc, unsigned int device_index, bool embed_audio = false);\r
+ bluefish_consumer(bluefish_consumer&& other);\r
\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
struct implementation;\r
std::shared_ptr<implementation> impl_;\r
};\r
-typedef std::tr1::shared_ptr<consumer> BlueFishFrameConsumerPtr;\r
+ \r
+safe_ptr<frame_consumer> create_bluefish_consumer(const std::vector<std::wstring>& params);\r
\r
-}}}\r
+}}\r
\r
#include <vector>\r
\r
-namespace caspar { namespace core { namespace bluefish {\r
+namespace caspar { namespace core {\r
\r
static const size_t MAX_HANC_BUFFER_SIZE = 256*1024;\r
static const size_t MAX_VBI_BUFFER_SIZE = 36*1920*4;\r
};\r
typedef std::shared_ptr<blue_dma_buffer> blue_dma_buffer_ptr;\r
\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
#include <BlueVelvet4.h>\r
#include "../../video_format.h"\r
\r
-namespace caspar { namespace core { namespace bluefish {\r
+namespace caspar { namespace core {\r
\r
inline bool is_epoch_card(int card_type)\r
{\r
return set_card_property(pSdk.get(), prop, value);\r
}\r
\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
\r
#pragma warning(push)\r
\r
-namespace caspar { namespace core { namespace decklink{\r
+namespace caspar { namespace core {\r
\r
struct decklink_consumer::implementation : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
{ \r
void decklink_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
size_t decklink_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
\r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_decklink_consumer(const std::vector<std::wstring>& params)\r
+{\r
+ if(params.size() < 2 || params[0] != L"DECKLINK")\r
+ return frame_consumer::empty();\r
+\r
+ auto format_desc = video_format_desc::get(params[1]);\r
+ if(format_desc.format == video_format::invalid)\r
+ return frame_consumer::empty();\r
+\r
+ int device_index = 1;\r
+ bool embed_audio = false;\r
+ bool internal_key = false;\r
+\r
+ try{device_index = boost::lexical_cast<int>(params[2]);}\r
+ catch(boost::bad_lexical_cast&){}\r
+ try{embed_audio = boost::lexical_cast<bool>(params[3]);}\r
+ catch(boost::bad_lexical_cast&){}\r
+ try{internal_key = boost::lexical_cast<bool>(params[4]);}\r
+ catch(boost::bad_lexical_cast&){}\r
+\r
+ return make_safe<decklink_consumer>(format_desc, device_index, embed_audio, internal_key);\r
+}\r
+\r
+}}
\ No newline at end of file
\r
#include "../../video_format.h"\r
\r
-namespace caspar { namespace core { namespace decklink {\r
+namespace caspar { namespace core {\r
\r
class decklink_consumer : public frame_consumer\r
{\r
std::tr1::shared_ptr<implementation> impl_;\r
};\r
\r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_decklink_consumer(const std::vector<std::wstring>& params);\r
+\r
+\r
+}}
\ No newline at end of file
\r
#include "DeckLinkAPI_h.h"\r
\r
-namespace caspar { namespace core { namespace decklink {\r
+namespace caspar { namespace core {\r
\r
static BMDDisplayMode GetDecklinkVideoFormat(video_format::type fmt) \r
{\r
return get_display_mode(output, GetDecklinkVideoFormat(fmt));\r
}\r
\r
-}}}
\ No newline at end of file
+}}
\ No newline at end of file
\r
#include <common/concurrency/executor.h>\r
#include <common/utility/string_convert.h>\r
+#include <common/env.h>\r
\r
#include <boost/thread/once.hpp>\r
\r
#pragma warning (pop)\r
#endif\r
\r
-namespace caspar { namespace core { namespace ffmpeg {\r
+namespace caspar { namespace core {\r
\r
-struct consumer::implementation : boost::noncopyable\r
+struct ffmpeg_consumer::implementation : boost::noncopyable\r
{ \r
executor executor_;\r
const std::string filename_;\r
implementation(const video_format_desc& format_desc, const std::string& filename)\r
: filename_(filename)\r
, format_desc_(format_desc)\r
- , audio_st_(0)\r
- , video_st_(0)\r
- , fmt_(0)\r
- , img_convert_ctx_(0)\r
+ , audio_st_(nullptr)\r
+ , video_st_(nullptr)\r
+ , fmt_(nullptr)\r
+ , img_convert_ctx_(nullptr)\r
, video_outbuf_(format_desc.size)\r
, audio_outbuf_(48000)\r
{\r
if (fmt_->audio_codec != CODEC_ID_NONE) \r
audio_st_ = add_audio_stream(fmt_->audio_codec); \r
\r
- // Set the output parameters (must be done even if no parameters).\r
- \r
+ // Set the output parameters (must be done even if no parameters). \r
int errn = 0;\r
if ((errn = -av_set_parameters(oc_.get(), nullptr)) > 0)\r
BOOST_THROW_EXCEPTION(\r
\r
~implementation()\r
{ \r
+ executor_.stop();\r
+\r
av_write_trailer(oc_.get());\r
\r
// Close each codec.\r
size_t buffer_depth() const { return 1; }\r
};\r
\r
-consumer::consumer(const video_format_desc& format_desc, const std::wstring& filename) : impl_(new implementation(format_desc, narrow(filename))){}\r
-consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
-void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+ffmpeg_consumer::ffmpeg_consumer(const video_format_desc& format_desc, const std::wstring& filename) : impl_(new implementation(format_desc, narrow(filename))){}\r
+ffmpeg_consumer::ffmpeg_consumer(ffmpeg_consumer&& other) : impl_(std::move(other.impl_)){}\r
+void ffmpeg_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t ffmpeg_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+\r
+safe_ptr<frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params)\r
+{\r
+ if(params.size() < 3 || params[0] != L"FILE")\r
+ return frame_consumer::empty();\r
+\r
+ auto format_desc = video_format_desc::get(params[1]);\r
+ if(format_desc.format == video_format::invalid)\r
+ return frame_consumer::empty();\r
+\r
+ return make_safe<ffmpeg_consumer>(format_desc, env::media_folder() + params[2]);\r
+}\r
\r
-}}}\r
+}}\r
#include "../../video_format.h"\r
#include "../../consumer/frame_consumer.h"\r
\r
-namespace caspar { namespace core { namespace ffmpeg {\r
+namespace caspar { namespace core {\r
\r
-class consumer : public frame_consumer\r
+class ffmpeg_consumer : public frame_consumer\r
{\r
public: \r
- explicit consumer(const video_format_desc& format_desc, const std::wstring& filename);\r
- consumer(consumer&& other);\r
+ explicit ffmpeg_consumer(const video_format_desc& format_desc, const std::wstring& filename);\r
+ ffmpeg_consumer(ffmpeg_consumer&& other);\r
\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
std::shared_ptr<implementation> impl_;\r
};\r
\r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_ffmpeg_consumer(const std::vector<std::wstring>& params);\r
+\r
+}}
\ No newline at end of file
struct frame_consumer : boost::noncopyable\r
{\r
virtual ~frame_consumer() {}\r
-\r
+ \r
virtual void send(const safe_ptr<const read_frame>& frame) = 0;\r
virtual size_t buffer_depth() const = 0;\r
+\r
+ static safe_ptr<frame_consumer> empty()\r
+ {\r
+ struct empty_frame_consumer : public frame_consumer\r
+ {\r
+ virtual void send(const safe_ptr<const read_frame>&){}\r
+ virtual size_t buffer_depth() const{return 0;}\r
+ };\r
+ static safe_ptr<frame_consumer> consumer = make_safe<empty_frame_consumer>();\r
+ return consumer;\r
+ }\r
};\r
\r
}}
\ No newline at end of file
\r
struct frame_consumer_device::implementation\r
{\r
+ static int const MAX_DEPTH = 3;\r
+\r
timer clock_;\r
executor executor_; \r
\r
boost::circular_buffer<safe_ptr<const read_frame>> buffer_;\r
\r
- std::list<safe_ptr<frame_consumer>> consumers_; // Valid iterators after erase\r
+ std::map<int, std::shared_ptr<frame_consumer>> consumers_; // Valid iterators after erase\r
\r
const video_format_desc fmt_;\r
\r
public:\r
- implementation(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) \r
- : consumers_(consumers.begin(), consumers.end())\r
- , fmt_(format_desc)\r
+ implementation(const video_format_desc& format_desc) : fmt_(format_desc)\r
{ \r
- if(consumers_.empty())\r
- BOOST_THROW_EXCEPTION(invalid_argument() << msg_info("No consumer."));\r
-\r
- std::vector<size_t> depths;\r
- boost::range::transform(consumers_, std::back_inserter(depths), std::mem_fn(&frame_consumer::buffer_depth));\r
- buffer_.set_capacity(*boost::range::max_element(depths));\r
executor_.set_capacity(3);\r
executor_.start();\r
}\r
+\r
+ void add(int index, const safe_ptr<frame_consumer>& consumer)\r
+ { \r
+ executor_.invoke([&]\r
+ {\r
+ if(buffer_.capacity() < consumer->buffer_depth())\r
+ buffer_.set_capacity(consumer->buffer_depth());\r
+ consumers_[index] = consumer;\r
+ });\r
+ }\r
+\r
+ void remove(int index)\r
+ {\r
+ executor_.invoke([&]\r
+ {\r
+ auto it = consumers_.find(index);\r
+ if(it != consumers_.end())\r
+ consumers_.erase(it);\r
+ });\r
+ }\r
\r
void consume(safe_ptr<const read_frame>&& frame)\r
{ \r
executor_.begin_invoke([=]\r
- {\r
+ { \r
+ clock_.tick(1.0/fmt_.fps);\r
+\r
buffer_.push_back(std::move(frame));\r
\r
if(!buffer_.full())\r
{\r
try\r
{\r
- (*it)->send(buffer_[(*it)->buffer_depth()-1]);\r
+ it->second->send(buffer_[it->second->buffer_depth()-1]);\r
++it;\r
}\r
catch(...)\r
CASPAR_LOG(warning) << "Removed consumer from frame_consumer_device.";\r
}\r
}\r
- \r
- clock_.tick(1.0/fmt_.fps);\r
});\r
}\r
};\r
\r
frame_consumer_device::frame_consumer_device(frame_consumer_device&& other) : impl_(std::move(other.impl_)){}\r
-frame_consumer_device::frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers) : impl_(new implementation(format_desc, consumers)){}\r
+frame_consumer_device::frame_consumer_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
+void frame_consumer_device::add(int index, const safe_ptr<frame_consumer>& consumer){impl_->add(index, consumer);}\r
+void frame_consumer_device::remove(int index){impl_->remove(index);}\r
void frame_consumer_device::consume(safe_ptr<const read_frame>&& future_frame) { impl_->consume(std::move(future_frame)); }\r
}}
\ No newline at end of file
class frame_consumer_device : boost::noncopyable\r
{\r
public:\r
- explicit frame_consumer_device(const video_format_desc& format_desc, const std::vector<safe_ptr<frame_consumer>>& consumers);\r
+ explicit frame_consumer_device(const video_format_desc& format_desc);\r
frame_consumer_device(frame_consumer_device&& other);\r
+\r
+ void add(int index, const safe_ptr<frame_consumer>& consumer);\r
+ void remove(int index);\r
void consume(safe_ptr<const read_frame>&& future_frame); // nothrow\r
private:\r
struct implementation;\r
\r
#include <boost/circular_buffer.hpp>\r
\r
-namespace caspar { namespace core { namespace oal { \r
+namespace caspar { namespace core {\r
\r
-struct consumer::implementation : public sf::SoundStream, boost::noncopyable\r
+struct oal_consumer::implementation : public sf::SoundStream, boost::noncopyable\r
{\r
tbb::concurrent_bounded_queue<std::vector<short>> input_;\r
boost::circular_buffer<std::vector<short>> container_;\r
-\r
+ tbb::atomic<bool> is_running_;\r
public:\r
implementation() \r
: container_(5)\r
{\r
+ is_running_ = true;\r
sf::SoundStream::Initialize(2, 48000);\r
Play(); \r
+ CASPAR_LOG(info) << "Sucessfully started oal_consumer";\r
+ }\r
+\r
+ ~implementation()\r
+ {\r
+ is_running_ = false;\r
+ input_.try_push(std::vector<short>());\r
+ input_.try_push(std::vector<short>());\r
+ CASPAR_LOG(info) << "Sucessfully ended oal_consumer";\r
}\r
\r
virtual void send(const safe_ptr<const read_frame>& frame)\r
data.Samples = container_.back().data();\r
data.NbSamples = container_.back().size(); \r
\r
- return true;\r
+ return is_running_;\r
}\r
};\r
\r
-consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
-consumer::consumer(const video_format_desc&) : impl_(new implementation()){}\r
-void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
-}}}\r
+oal_consumer::oal_consumer(oal_consumer&& other) : impl_(std::move(other.impl_)){}\r
+oal_consumer::oal_consumer(const video_format_desc&) : impl_(new implementation()){}\r
+void oal_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t oal_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+\r
+safe_ptr<frame_consumer> create_oal_consumer(const std::vector<std::wstring>& params)\r
+{\r
+ if(params.size() < 2 || params[0] != L"OAL")\r
+ return frame_consumer::empty();\r
+\r
+ auto format_desc = video_format_desc::get(params[1]);\r
+ if(format_desc.format == video_format::invalid)\r
+ return frame_consumer::empty();\r
+\r
+ return make_safe<oal_consumer>(format_desc);\r
+}\r
+}}\r
#include "../../video_format.h"\r
#include "../../consumer/frame_consumer.h"\r
\r
-namespace caspar { namespace core { namespace oal {\r
+namespace caspar { namespace core {\r
\r
-class consumer : public frame_consumer\r
+class oal_consumer : public frame_consumer\r
{\r
public: \r
- explicit consumer(const video_format_desc& format_desc);\r
- consumer(consumer&& other);\r
+ explicit oal_consumer(const video_format_desc& format_desc);\r
+ oal_consumer(oal_consumer&& other);\r
\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
std::shared_ptr<implementation> impl_;\r
};\r
\r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_oal_consumer(const std::vector<std::wstring>& params);\r
+\r
+}}
\ No newline at end of file
\r
#include <algorithm>\r
\r
-namespace caspar { namespace core { namespace ogl{ \r
+namespace caspar { namespace core {\r
\r
-struct consumer::implementation : boost::noncopyable\r
+struct ogl_consumer::implementation : boost::noncopyable\r
{ \r
boost::unique_future<void> active_;\r
executor executor_;\r
hratio_ = static_cast<float>(format_desc_.height)/static_cast<float>(format_desc_.height);\r
\r
std::pair<float, float> target_ratio = None();\r
- if(stretch_ == ogl::fill)\r
+ if(stretch_ == fill)\r
target_ratio = Fill();\r
- else if(stretch_ == ogl::uniform)\r
+ else if(stretch_ == uniform)\r
target_ratio = Uniform();\r
- else if(stretch_ == ogl::uniform_to_fill)\r
+ else if(stretch_ == uniform_to_fill)\r
target_ratio = UniformToFill();\r
\r
wSize_ = target_ratio.first;\r
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);\r
});\r
active_ = executor_.begin_invoke([]{});\r
+\r
+ CASPAR_LOG(info) << "Sucessfully started ogl_consumer";\r
+ }\r
+\r
+ ~implementation()\r
+ {\r
+ CASPAR_LOG(info) << "Sucessfully ended ogl_consumer";\r
}\r
\r
std::pair<float, float> None()\r
virtual size_t buffer_depth() const{return 2;}\r
};\r
\r
-consumer::consumer(consumer&& other) : impl_(std::move(other.impl_)){}\r
-consumer::consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) : impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
-void consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
-size_t consumer::buffer_depth() const{return impl_->buffer_depth();}\r
-}}}\r
+ogl_consumer::ogl_consumer(ogl_consumer&& other) : impl_(std::move(other.impl_)){}\r
+ogl_consumer::ogl_consumer(const video_format_desc& format_desc, unsigned int screen_index, stretch stretch, bool windowed) : impl_(new implementation(format_desc, screen_index, stretch, windowed)){}\r
+void ogl_consumer::send(const safe_ptr<const read_frame>& frame){impl_->send(frame);}\r
+size_t ogl_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
+\r
+safe_ptr<frame_consumer> create_ogl_consumer(const std::vector<std::wstring>& params)\r
+{\r
+ if(params.size() < 2 || params[0] != L"OGL")\r
+ return frame_consumer::empty();\r
+\r
+ auto format_desc = video_format_desc::get(params[1]);\r
+ if(format_desc.format == video_format::invalid)\r
+ return frame_consumer::empty();\r
+\r
+ unsigned int screen_index = 0;\r
+ stretch stretch = stretch::fill;\r
+ bool windowed = true;\r
+ \r
+ try{screen_index = boost::lexical_cast<int>(params[2]);}\r
+ catch(boost::bad_lexical_cast&){}\r
+ try{windowed = boost::lexical_cast<bool>(params[3]);}\r
+ catch(boost::bad_lexical_cast&){}\r
+\r
+ return make_safe<ogl_consumer>(format_desc, screen_index, stretch, windowed);\r
+}\r
+\r
+}}\r
#include "../../consumer/frame_consumer.h"\r
#include "../../video_format.h"\r
\r
-namespace caspar { namespace core { namespace ogl {\r
+namespace caspar { namespace core {\r
\r
struct ogl_error : virtual caspar_exception{};\r
\r
uniform_to_fill\r
};\r
\r
-class consumer : public frame_consumer\r
+class ogl_consumer : public frame_consumer\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
- consumer(consumer&& other);\r
+ explicit ogl_consumer(const video_format_desc& format_desc, unsigned int screen_index = 0, stretch stretch = stretch::fill, bool windowed = false);\r
+ ogl_consumer(ogl_consumer&& other);\r
\r
virtual void send(const safe_ptr<const read_frame>&);\r
virtual size_t buffer_depth() const;\r
std::shared_ptr<implementation> impl_;\r
};\r
\r
-}}}
\ No newline at end of file
+safe_ptr<frame_consumer> create_ogl_consumer(const std::vector<std::wstring>& params);\r
+\r
+}}
\ No newline at end of file
if(pModelName != nullptr)\r
CASPAR_LOG(info) << "decklink_producer: Modelname: " << pModelName;\r
\r
- unsigned long decklinkVideoFormat = decklink::GetDecklinkVideoFormat(format_desc_.format);\r
+ unsigned long decklinkVideoFormat = GetDecklinkVideoFormat(format_desc_.format);\r
if(decklinkVideoFormat == ULONG_MAX) \r
BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("decklink_producer: Card does not support requested videoformat."));\r
\r
\r
void play()\r
{ \r
- background_->set_leading_producer(foreground_);\r
- foreground_ = background_;\r
- background_ = frame_producer::empty();\r
- is_paused_ = false;\r
- CASPAR_LOG(info) << print() << L" background => foreground";\r
+ if(is_paused_) \r
+ is_paused_ = false;\r
+ else\r
+ {\r
+ background_->set_leading_producer(foreground_);\r
+ foreground_ = background_;\r
+ background_ = frame_producer::empty();\r
+ CASPAR_LOG(info) << print() << L" background => foreground";\r
+ }\r
}\r
\r
void pause()\r
return scheduling_ == Default ? GetDefaultScheduling() : scheduling_;\r
}\r
\r
+ virtual std::wstring print() const = 0;\r
+\r
void SetScheduling(AMCPCommandScheduling s){scheduling_ = s;}\r
\r
protected:\r
\r
if(pCurrentCommand != 0) \r
{\r
- if(pCurrentCommand->Execute()) \r
- CASPAR_LOG(info) << "Executed command";\r
- else \r
- CASPAR_LOG(info) << "Failed to executed command";\r
+ try\r
+ {\r
+ if(pCurrentCommand->Execute()) \r
+ CASPAR_LOG(info) << "Executed command: " << pCurrentCommand->print();\r
+ else \r
+ CASPAR_LOG(info) << "Failed to executed command: " << pCurrentCommand->print();\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ CASPAR_LOG(info) << "Failed to executed command:" << pCurrentCommand->print();\r
+ }\r
\r
pCurrentCommand->SendReply();\r
pCurrentCommand.reset();\r
_parameters.clear();\r
}\r
\r
+bool AddCommand::DoExecute()\r
+{ \r
+ //Perform loading of the clip\r
+ try\r
+ {\r
+ auto consumer = create_consumer(_parameters); \r
+ GetChannel()->add(GetLayerIndex(), consumer);\r
+ \r
+ CASPAR_LOG(info) << "Added " << _parameters[0] << TEXT(" successfully");\r
+\r
+ SetReplyString(TEXT("202 ADD OK\r\n"));\r
+\r
+ return true;\r
+ }\r
+ catch(file_not_found&)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ SetReplyString(TEXT("404 ADD ERROR\r\n"));\r
+ return false;\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ SetReplyString(TEXT("502 ADD FAILED\r\n"));\r
+ return false;\r
+ }\r
+}\r
+\r
+bool RemoveCommand::DoExecute()\r
+{ \r
+ //Perform loading of the clip\r
+ try\r
+ {\r
+ GetChannel()->remove(GetLayerIndex());\r
+ \r
+ CASPAR_LOG(info) << "Removed " << TEXT(" successfully");\r
+\r
+ SetReplyString(TEXT("202 REMOVE OK\r\n"));\r
+\r
+ return true;\r
+ }\r
+ catch(file_not_found&)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ SetReplyString(TEXT("404 REMOVE ERROR\r\n"));\r
+ return false;\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ SetReplyString(TEXT("502 REMOVE FAILED\r\n"));\r
+ return false;\r
+ }\r
+}\r
+\r
bool LoadCommand::DoExecute()\r
{ \r
//Perform loading of the clip\r
try\r
{\r
_parameters[0] = _parameters[0];\r
- auto pFP = load_media(_parameters); \r
+ auto pFP = create_producer(_parameters); \r
GetChannel()->preview(GetLayerIndex(), pFP);\r
\r
CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully");\r
try\r
{\r
_parameters[0] = _parameters[0];\r
- auto pFP = load_media(_parameters);\r
+ auto pFP = create_producer(_parameters);\r
if(pFP == frame_producer::empty())\r
BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
\r
std::wstring ListTemplates();\r
\r
namespace amcp {\r
+ \r
+class AddCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
+{\r
+ std::wstring print() const { return L"AddCommand";}\r
+ bool DoExecute();\r
+};\r
+\r
+class RemoveCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
+{\r
+ std::wstring print() const { return L"RemoveCommand";}\r
+ bool DoExecute();\r
+};\r
\r
-class LoadCommand : public AMCPCommandBase<true, ImmediatelyAndClear, 1>\r
+class LoadCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
{\r
+ std::wstring print() const { return L"LoadCommand";}\r
bool DoExecute();\r
};\r
\r
class LoadbgCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
{\r
+ std::wstring print() const { return L"LoadbgCommand";}\r
bool DoExecute();\r
};\r
\r
class PlayCommand: public AMCPCommandBase<true, AddToQueue, 0>\r
{\r
+ std::wstring print() const { return L"PlayCommand";}\r
bool DoExecute();\r
};\r
\r
class PauseCommand: public AMCPCommandBase<true, AddToQueue, 0>\r
{\r
+ std::wstring print() const { return L"PauseCommand";}\r
bool DoExecute();\r
};\r
\r
-class StopCommand : public AMCPCommandBase<true, ImmediatelyAndClear, 0>\r
+class StopCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
{\r
+ std::wstring print() const { return L"StopCommand";}\r
bool DoExecute();\r
};\r
\r
-class ClearCommand : public AMCPCommandBase<true, ImmediatelyAndClear, 0>\r
+class ClearCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
{\r
+ std::wstring print() const { return L"ClearCommand";}\r
bool DoExecute();\r
};\r
\r
class CGCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
{\r
+ std::wstring print() const { return L"CGCommand";}\r
bool DoExecute();\r
bool ValidateLayer(const std::wstring& layerstring);\r
\r
\r
class DataCommand : public AMCPCommandBase<false, AddToQueue, 1>\r
{\r
+ std::wstring print() const { return L"DataCommand";}\r
bool DoExecute();\r
bool DoExecuteStore();\r
bool DoExecuteRetrieve();\r
\r
class ClsCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
{\r
+ std::wstring print() const { return L"ClsCommand";}\r
bool DoExecute();\r
};\r
\r
class TlsCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
{\r
+ std::wstring print() const { return L"TlsCommand";}\r
bool DoExecute();\r
};\r
\r
class CinfCommand : public AMCPCommandBase<false, AddToQueue, 1>\r
{\r
+ std::wstring print() const { return L"CinfCommand";}\r
bool DoExecute();\r
};\r
\r
class InfoCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
{\r
public:\r
+ std::wstring print() const { return L"InfoCommand";}\r
InfoCommand(const std::vector<safe_ptr<core::channel>>& channels) : channels_(channels){}\r
bool DoExecute();\r
private:\r
\r
class VersionCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
{\r
+ std::wstring print() const { return L"VersionCommand";}\r
bool DoExecute();\r
};\r
\r
class ByeCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
{\r
+ std::wstring print() const { return L"ByeCommand";}\r
bool DoExecute();\r
};\r
\r
class SetCommand : public AMCPCommandBase<true, AddToQueue, 2>\r
{\r
+ std::wstring print() const { return L"SetCommand";}\r
bool DoExecute();\r
};\r
\r
\r
if (s == TEXT("LOAD")) return std::make_shared<LoadCommand>();\r
else if(s == TEXT("LOADBG")) return std::make_shared<LoadbgCommand>();\r
+ else if(s == TEXT("ADD")) return std::make_shared<AddCommand>();\r
+ else if(s == TEXT("REMOVE")) return std::make_shared<RemoveCommand>();\r
else if(s == TEXT("PAUSE")) return std::make_shared<PauseCommand>();\r
else if(s == TEXT("PLAY")) return std::make_shared<PlayCommand>();\r
else if(s == TEXT("STOP")) return std::make_shared<StopCommand>();\r
transition.type = transition::mix;\r
transition.duration = 12;\r
\r
- auto pFP = load_media(boost::assign::list_of(filename));\r
+ auto pFP = create_producer(boost::assign::list_of(filename));\r
auto pTransition = safe_ptr<core::frame_producer>(transition_producer(pFP, transition));\r
\r
try\r
#include <core/producer/flash/cg_producer.h>\r
#include <core/producer/image/image_producer.h>\r
#include <core/producer/decklink/decklink_producer.h>\r
+\r
+#include <core/consumer/bluefish/bluefish_consumer.h>\r
+#include <core/consumer/decklink/decklink_consumer.h>\r
+#include <core/consumer/ogl/ogl_consumer.h>\r
+#include <core/consumer/oal/oal_consumer.h>\r
+#include <core/consumer/ffmpeg/ffmpeg_consumer.h>\r
//#include "../producer/image/image_scroll_producer.h"\r
\r
#include <common/exception/exceptions.h>\r
\r
using namespace core;\r
\r
-safe_ptr<core::frame_producer> load_media(const std::vector<std::wstring>& params)\r
+safe_ptr<core::frame_producer> create_producer(const std::vector<std::wstring>& params)\r
{ \r
- typedef std::function<safe_ptr<core::frame_producer>(const std::vector<std::wstring>&)> producer_factory;\r
+ typedef std::function<safe_ptr<core::frame_producer>(const std::vector<std::wstring>&)> factory_t;\r
\r
- const auto producer_factories = list_of<producer_factory>\r
+ const auto factories = list_of<factory_t>\r
(&core::flash::create_ct_producer)\r
(&core::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
- safe_ptr<core::frame_producer> producer(frame_producer::empty());\r
- std::any_of(producer_factories.begin(), producer_factories.end(), [&](const producer_factory& factory) -> bool\r
+ auto producer = frame_producer::empty();\r
+ std::any_of(factories.begin(), factories.end(), [&](const factory_t& factory) -> bool\r
{\r
try\r
{\r
return producer;\r
}\r
\r
+safe_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params)\r
+{ \r
+ typedef std::function<safe_ptr<core::frame_consumer>(const std::vector<std::wstring>&)> factory_t;\r
+\r
+ const auto factories = list_of<factory_t>\r
+ (&core::create_bluefish_consumer)\r
+ (&core::create_decklink_consumer)\r
+ (&core::create_oal_consumer)\r
+ (&core::create_ogl_consumer)\r
+ (&core::create_ffmpeg_consumer);\r
+\r
+ if(params.empty())\r
+ BOOST_THROW_EXCEPTION(invalid_argument() << arg_name_info("params") << arg_value_info(""));\r
+\r
+ auto consumer = frame_consumer::empty();\r
+ std::any_of(factories.begin(), factories.end(), [&](const factory_t& factory) -> bool\r
+ {\r
+ try\r
+ {\r
+ consumer = factory(params);\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ }\r
+ return consumer != frame_consumer::empty();\r
+ });\r
+\r
+ return consumer;\r
+}\r
+\r
}}\r
#pragma once\r
\r
#include <core/producer/frame_producer.h>\r
+#include <core/consumer/frame_consumer.h>\r
\r
#include <string>\r
#include <vector>\r
\r
namespace caspar { namespace protocol { \r
\r
-safe_ptr<core::frame_producer> load_media(const std::vector<std::wstring>& params);\r
+safe_ptr<core::frame_producer> create_producer(const std::vector<std::wstring>& params);\r
+safe_ptr<core::frame_consumer> create_consumer(const std::vector<std::wstring>& params);\r
\r
}}\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<safe_ptr<frame_consumer>> consumers;\r
-\r
+ \r
+ channels_.push_back(channel(format_desc));\r
+ \r
+ int index = 0;\r
BOOST_FOREACH(auto& xml_consumer, xml_channel.second.get_child("consumers"))\r
{\r
try\r
{ \r
int device = xml_consumer.second.get("device", 0);\r
\r
- ogl::stretch stretch = ogl::stretch::fill;\r
+ stretch stretch = stretch::fill;\r
std::string stretchStr = xml_consumer.second.get("stretch", "");\r
if(stretchStr == "none")\r
- stretch = ogl::stretch::none;\r
+ stretch = stretch::none;\r
else if(stretchStr == "uniform")\r
- stretch = ogl::stretch::uniform;\r
+ stretch = stretch::uniform;\r
else if(stretchStr == "uniformtofill")\r
- stretch = ogl::stretch::uniform_to_fill;\r
+ stretch = stretch::uniform_to_fill;\r
\r
bool windowed = xml_consumer.second.get("windowed", false);\r
- consumers.push_back(ogl::consumer(format_desc, device, stretch, windowed));\r
+ channels_.back()->add(index++, ogl_consumer(format_desc, device, stretch, windowed));\r
}\r
else if(name == "bluefish") \r
- consumers.push_back(bluefish::consumer(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("embedded-audio", false))); \r
+ channels_.back()->add(index++, bluefish_consumer(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("embedded-audio", false))); \r
else if(name == "decklink")\r
- consumers.push_back(make_safe<decklink::decklink_consumer>(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("internalkey", false)));\r
+ channels_.back()->add(index++, decklink_consumer(format_desc, xml_consumer.second.get("device", 0), xml_consumer.second.get("internalkey", false)));\r
else if(name == "audio")\r
- consumers.push_back(oal::consumer(format_desc)); \r
+ channels_.back()->add(index++, oal_consumer(format_desc)); \r
}\r
catch(...)\r
{\r
CASPAR_LOG_CURRENT_EXCEPTION();\r
}\r
- }\r
-\r
- try\r
- {\r
- consumers.push_back(ffmpeg::consumer(format_desc, env::media_folder() + L"test.mpeg")); \r
- }\r
- catch(...)\r
- {\r
- CASPAR_LOG_CURRENT_EXCEPTION();\r
- }\r
- \r
- channels_.push_back(channel(format_desc, consumers));\r
+ } \r
}\r
}\r
\r