<ClInclude Include="memory\safe_ptr.h" />\r
<ClInclude Include="env.h" />\r
<ClInclude Include="stdafx.h" />\r
+ <ClInclude Include="utility\assert.h" />\r
<ClInclude Include="utility\string_convert.h" />\r
<ClInclude Include="utility\timer.h" />\r
</ItemGroup>\r
<ClInclude Include="env.h">\r
<Filter>Source</Filter>\r
</ClInclude>\r
+ <ClInclude Include="utility\assert.h">\r
+ <Filter>Source\utility</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
</Project>
\ No newline at end of file
int device_index = 1;\r
bool embed_audio = false;\r
\r
- try{device_index = boost::lexical_cast<int>(params[2]);}\r
+ try{if(params.size() > 2) 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
+ try{if(params.size() > 3) 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
bool embed_audio = false;\r
bool internal_key = false;\r
\r
- try{device_index = boost::lexical_cast<int>(params[2]);}\r
+ try{if(params.size() > 2) 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
+ try{if(params.size() > 3) 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
+ try{if(params.size() > 4) 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
#include <common/concurrency/executor.h>\r
#include <common/utility/timer.h>\r
+#include <common/utility/assert.h>\r
\r
#include <boost/range/algorithm_ext/erase.hpp>\r
#include <boost/range/algorithm.hpp>\r
consumers_.erase(it);\r
});\r
}\r
+\r
+ safe_ptr<frame_consumer> get(int index)\r
+ {\r
+ return executor_.invoke([&]() -> safe_ptr<frame_consumer>\r
+ {\r
+ auto it = consumers_.find(index);\r
+ return it != consumers_.end() && it->second ? safe_ptr<frame_consumer>(it->second) : frame_consumer::empty();\r
+ });\r
+ }\r
\r
void send(const safe_ptr<const read_frame>& frame)\r
{ \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
+safe_ptr<frame_consumer> frame_consumer_device::get(int index) { return impl_->get(index); }\r
void frame_consumer_device::send(const safe_ptr<const read_frame>& future_frame) { impl_->send(future_frame); }\r
}}
\ No newline at end of file
\r
void add(int index, const safe_ptr<frame_consumer>& consumer);\r
void remove(int index);\r
+ safe_ptr<frame_consumer> get(int index);\r
+\r
void send(const safe_ptr<const read_frame>& future_frame); // nothrow\r
private:\r
struct implementation;\r
stretch stretch = stretch::fill;\r
bool windowed = true;\r
\r
- try{screen_index = boost::lexical_cast<int>(params[2]);}\r
+ try{if(params.size() > 2) screen_index = boost::lexical_cast<int>(params[2]);}\r
catch(boost::bad_lexical_cast&){}\r
- try{windowed = boost::lexical_cast<bool>(params[3]);}\r
+ try{if(params.size() > 3) 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
#include "../video_format.h"\r
\r
+#include <common/utility/assert.h>\r
+\r
namespace caspar { namespace core {\r
\r
struct layer::implementation : boost::noncopyable\r
last_frame_ = foreground_->receive(); \r
if(last_frame_ == draw_frame::eof())\r
{\r
- assert(foreground_ != frame_producer::empty());\r
+ CASPAR_ASSERT(foreground_ != frame_producer::empty());\r
\r
auto following = foreground_->get_following_producer();\r
following->set_leading_producer(foreground_);\r
}\r
else\r
{\r
+ last_frame_ = draw_frame(last_frame_);\r
last_frame_->get_image_transform().gain *= video_gain_;\r
last_frame_->get_image_transform().alpha *= video_opacity_;\r
last_frame_->get_audio_transform().gain *= audio_gain_;\r
void SetChannel(const std::shared_ptr<core::channel>& pChannel){pChannel_ = pChannel;}\r
std::shared_ptr<core::channel> GetChannel(){return pChannel_;}\r
\r
+ void SetChannels(const std::vector<safe_ptr<core::channel>>& channels){channels_ = channels;}\r
+ const std::vector<safe_ptr<core::channel>>& GetChannels() { return channels_; }\r
+\r
void SetChannelIndex(unsigned int channelIndex){channelIndex_ = channelIndex;}\r
unsigned int GetChannelIndex(){return channelIndex_;}\r
\r
int layerIndex_;\r
IO::ClientInfoPtr pClientInfo_;\r
std::shared_ptr<core::channel> pChannel_;\r
+ std::vector<safe_ptr<core::channel>> channels_;\r
AMCPCommandScheduling scheduling_;\r
std::wstring replyString_;\r
};\r
}\r
}\r
\r
+bool SwapCommand::DoExecute()\r
+{ \r
+ //Perform loading of the clip\r
+ try\r
+ {\r
+ std::vector<std::string> strs;\r
+ boost::split(strs, _parameters[0], boost::is_any_of("-"));\r
+ \r
+ auto ch1 = GetChannel();\r
+ auto ch2 = GetChannels().at(boost::lexical_cast<int>(strs.at(0))-1);\r
+\r
+ int l1 = GetLayerIndex();\r
+ int l2 = boost::lexical_cast<int>(strs.at(1));\r
+ \r
+ auto c1 = ch1->consumer().get(l1);\r
+ auto c2 = ch2->consumer().get(l2);\r
+\r
+ ch2->consumer().add(l1, c1);\r
+ ch1->consumer().add(l2, c2);\r
+ CASPAR_LOG(info) << "Swapped successfully";\r
+\r
+ SetReplyString(TEXT("202 SWAP OK\r\n"));\r
+\r
+ return true;\r
+ }\r
+ catch(file_not_found&)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ SetReplyString(TEXT("404 SWAP ERROR\r\n"));\r
+ return false;\r
+ }\r
+ catch(...)\r
+ {\r
+ CASPAR_LOG_CURRENT_EXCEPTION();\r
+ SetReplyString(TEXT("502 SWAP FAILED\r\n"));\r
+ return false;\r
+ }\r
+}\r
+\r
bool AddCommand::DoExecute()\r
{ \r
//Perform loading of the clip\r
bool DoExecute();\r
};\r
\r
+class SwapCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
+{\r
+ std::wstring print() const { return L"SwapCommand";}\r
+ bool DoExecute();\r
+};\r
+\r
class LoadCommand : public AMCPCommandBase<true, AddToQueue, 1>\r
{\r
std::wstring print() const { return L"LoadCommand";}\r
}\r
\r
pCommand->SetChannel(pChannel);\r
+ pCommand->SetChannels(channels_);\r
pCommand->SetChannelIndex(channelIndex);\r
pCommand->SetLayerIntex(layerIndex);\r
\r
transform(s.begin(), s.end(), s.begin(), toupper);\r
\r
if (s == TEXT("MIXER")) return std::make_shared<MixerCommand>();\r
+ else if(s == TEXT("SWAP")) return std::make_shared<SwapCommand>();\r
else 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
</bluefish-->\r
</consumers>\r
</channel>\r
+ <channel>\r
+ <videomode>PAL</videomode>\r
+ <consumers>\r
+ <ogl>\r
+ <device>1</device>\r
+ <stretch>uniform</stretch>\r
+ <windowed>true</windowed>\r
+ </ogl>\r
+ <audio/>\r
+ <!--decklink>\r
+ <device>1</device>\r
+ <embedded-audio>true</embedded-audio>\r
+ </decklink-->\r
+ <!--bluefish>\r
+ <device>1</device> \r
+ <embedded-audio>true</embedded-audio>\r
+ </bluefish-->\r
+ </consumers>\r
+ </channel>\r
</channels>\r
<controllers>\r
<tcpcontroller>\r
#include <common/exception/exceptions.h>\r
#include <common/log/log.h>\r
#include <common/env.h>\r
+#include <common/utility/assert.h>\r
#include <protocol/amcp/AMCPProtocolStrategy.h>\r
\r
using namespace caspar;\r