}\r
}\r
\r
+ layer_status status() const\r
+ {\r
+ layer_status status;\r
+ status.foreground = foreground_->print();\r
+ status.background = background_->print();\r
+ status.is_paused = is_paused_;\r
+ status.total_frames = foreground_->nb_frames();\r
+ status.current_frame = frame_number_;\r
+\r
+ return status;\r
+ }\r
+\r
bool empty() const\r
{\r
return background_ == core::frame_producer::empty() && foreground_ == core::frame_producer::empty();\r
void layer::play(){impl_->play();}\r
void layer::pause(){impl_->pause();}\r
void layer::stop(){impl_->stop();}\r
+bool layer::is_paused() const{return impl_->is_paused_;}\r
+int64_t layer::frame_number() const{return impl_->frame_number_;}\r
+layer_status layer::status() const {return impl_->status();}\r
safe_ptr<basic_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
struct frame_producer;\r
class basic_frame;\r
\r
+struct layer_status\r
+{\r
+ std::wstring foreground;\r
+ std::wstring background;\r
+ bool is_paused;\r
+ int64_t total_frames;\r
+ int64_t current_frame;\r
+};\r
+\r
class layer : boost::noncopyable\r
{\r
public:\r
void stop(); // nothrow\r
void param(const std::wstring& param);\r
\r
+ bool is_paused() const;\r
+ int64_t frame_number() const;\r
+\r
+ layer_status status() const;\r
+\r
bool empty() const;\r
\r
safe_ptr<frame_producer> foreground() const; // nothrow\r
#include <set>\r
\r
namespace caspar { namespace core {\r
- \r
+ \r
void destroy_producer(safe_ptr<frame_producer>& producer)\r
{\r
if(!producer.unique())\r
\r
channel_.execution().invoke([&]{other.impl_->channel_.execution().invoke(func, high_priority);});\r
}\r
+\r
+ layer_status get_status(int index)\r
+ { \r
+ return channel_.execution().invoke([&]\r
+ {\r
+ return layers_[index].status();\r
+ }, high_priority );\r
+ }\r
\r
boost::unique_future<safe_ptr<frame_producer>> foreground(int index)\r
{\r
void stage::clear(){impl_->clear();}\r
void stage::swap_layer(int index, size_t other_index){impl_->swap_layer(index, other_index);}\r
void stage::swap_layer(int index, size_t other_index, stage& other){impl_->swap_layer(index, other_index, other);}\r
+layer_status stage::get_status(int index){return impl_->get_status(index);}\r
boost::unique_future<safe_ptr<frame_producer>> stage::foreground(size_t index) {return impl_->foreground(index);}\r
boost::unique_future<safe_ptr<frame_producer>> stage::background(size_t index) {return impl_->background(index);}\r
std::map<int, safe_ptr<basic_frame>> stage::execute(){return impl_->execute();}\r
namespace caspar { namespace core {\r
\r
struct video_format_desc;\r
-class video_channel_context;;\r
+class video_channel_context;\r
+struct layer_status;\r
\r
class stage : boost::noncopyable\r
{\r
void clear(); \r
void swap_layer(int index, size_t other_index);\r
void swap_layer(int index, size_t other_index, stage& other);\r
+\r
+ layer_status get_status(int index);\r
boost::unique_future<safe_ptr<frame_producer>> foreground(size_t index);\r
boost::unique_future<safe_ptr<frame_producer>> background(size_t index);\r
\r
#include <core/producer/transition/transition_producer.h>\r
#include <core/producer/frame/image_transform.h>\r
#include <core/producer/frame/audio_transform.h>\r
+#include <core/producer/stage.h>\r
+#include <core/producer/layer.h>\r
#include <core/mixer/mixer.h>\r
#include <core/consumer/output.h>\r
\r
return true;\r
}\r
\r
+bool StatusCommand::DoExecute()\r
+{ \r
+ if (GetLayerIndex() > -1)\r
+ {\r
+ auto status = GetChannel()->stage()->get_status(GetLayerIndex());\r
+ std::wstringstream status_text;\r
+ status_text\r
+ << L"202 STATUS OK\r\n"\r
+ << L"FOREGROUND:" << status.foreground << L"\r\n"\r
+ << L"BACKGROUND:" << status.background << L"\r\n"\r
+ << L"STATUS:" << (status.is_paused ? L"PAUSED" : L"PLAYING") << L"\r\n"\r
+ << L"TOTAL FRAMES:" << (status.total_frames == std::numeric_limits<int64_t>::max() ? 0 : status.total_frames) << L"\r\n"\r
+ << L"CURRENT FRAME:" << status.current_frame << L"\r\n";\r
+\r
+ SetReplyString(status_text.str());\r
+ return true;\r
+ }\r
+ else\r
+ {\r
+ //NOTE: Possible to extend soo that "channel" status is returned when no layer is specified.\r
+\r
+ SetReplyString(TEXT("403 LAYER MUST BE SPECIFIED\r\n"));\r
+ return false;\r
+ }\r
+}\r
+\r
bool LogCommand::DoExecute()\r
{\r
if(_parameters.at(0) == L"LEVEL")\r
bool DoExecute();\r
};\r
\r
+class StatusCommand : public AMCPCommandBase<true, AddToQueue, 0>\r
+{\r
+ std::wstring print() const { return L"StatusCommand";}\r
+ bool DoExecute();\r
+};\r
+\r
class LogCommand : public AMCPCommandBase<false, AddToQueue, 0>\r
{\r
std::wstring print() const { return L"LogCommand";}\r
else if(s == TEXT("STOP")) return std::make_shared<StopCommand>();\r
else if(s == TEXT("CLEAR")) return std::make_shared<ClearCommand>();\r
else if(s == TEXT("PRINT")) return std::make_shared<PrintCommand>();\r
+ else if(s == TEXT("STATUS")) return std::make_shared<StatusCommand>();\r
else if(s == TEXT("LOG")) return std::make_shared<LogCommand>();\r
else if(s == TEXT("CG")) return std::make_shared<CGCommand>();\r
else if(s == TEXT("DATA")) return std::make_shared<DataCommand>();\r