-/*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
-*\r
-* This file is part of CasparCG (www.casparcg.com).\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
-* Author: Robert Nagy, ronag89@gmail.com\r
-*/\r
-\r
-#include "../../stdafx.h"\r
-\r
-#include "playlist_producer.h"\r
-\r
-#include <core/producer/frame_producer.h>\r
-#include <core/producer/frame/basic_frame.h>\r
-\r
-#include <boost/regex.hpp>\r
-#include <boost/property_tree/ptree.hpp>\r
-\r
-#include <deque>\r
-\r
-namespace caspar { namespace core { \r
-\r
-struct playlist_producer : public frame_producer\r
-{ \r
- safe_ptr<frame_factory> factory_;\r
- safe_ptr<basic_frame> last_frame_;\r
- safe_ptr<frame_producer> current_;\r
- bool loop_;\r
-\r
- std::deque<safe_ptr<frame_producer>> producers_;\r
-\r
- playlist_producer(const safe_ptr<frame_factory>& factory, bool loop) \r
- : factory_(factory)\r
- , last_frame_(basic_frame::empty())\r
- , current_(frame_producer::empty())\r
- , loop_(loop)\r
- {\r
- }\r
-\r
- // frame_producer\r
- \r
- virtual safe_ptr<basic_frame> receive(int hints) override\r
- {\r
- if(current_ == frame_producer::empty() && !producers_.empty())\r
- next();\r
-\r
- auto frame = current_->receive(hints);\r
- if(frame == basic_frame::eof())\r
- {\r
- current_ = frame_producer::empty();\r
- return receive(hints);\r
- }\r
-\r
- return last_frame_ = frame;\r
- }\r
-\r
- virtual safe_ptr<core::basic_frame> last_frame() const override\r
- {\r
- return disable_audio(last_frame_);\r
- }\r
-\r
- virtual std::wstring print() const override\r
- {\r
- return L"playlist[" + current_->print() + L"]";\r
- } \r
-\r
- virtual boost::property_tree::wptree info() const override\r
- {\r
- boost::property_tree::wptree info;\r
- info.add(L"type", L"playlist-producer");\r
- return info;\r
- }\r
-\r
- virtual uint32_t nb_frames() const override\r
- {\r
- return std::numeric_limits<uint32_t>::max();\r
- }\r
- \r
- virtual boost::unique_future<std::wstring> call(const std::wstring& param) override\r
- {\r
- boost::promise<std::wstring> promise;\r
- promise.set_value(do_call(param));\r
- return promise.get_future();\r
- } \r
-\r
- // playlist_producer\r
-\r
- std::wstring do_call(const std::wstring& param)\r
- { \r
- static const boost::wregex push_front_exp (L"PUSH_FRONT (?<PARAM>.+)"); \r
- static const boost::wregex push_back_exp (L"(PUSH_BACK|PUSH) (?<PARAM>.+)");\r
- static const boost::wregex pop_front_exp (L"POP_FRONT"); \r
- static const boost::wregex pop_back_exp (L"(POP_BACK|POP)");\r
- static const boost::wregex clear_exp (L"CLEAR");\r
- static const boost::wregex next_exp (L"NEXT");\r
- static const boost::wregex insert_exp (L"INSERT (?<POS>\\d+) (?<PARAM>.+)"); \r
- static const boost::wregex remove_exp (L"REMOVE (?<POS>\\d+) (?<PARAM>.+)"); \r
- static const boost::wregex list_exp (L"LIST"); \r
- static const boost::wregex loop_exp (L"LOOP\\s*(?<VALUE>\\d?)");\r
- \r
- boost::wsmatch what;\r
-\r
- if(boost::regex_match(param, what, push_front_exp))\r
- return push_front(what["PARAM"].str()); \r
- else if(boost::regex_match(param, what, push_back_exp))\r
- return push_back(what["PARAM"].str()); \r
- if(boost::regex_match(param, what, pop_front_exp))\r
- return pop_front(); \r
- else if(boost::regex_match(param, what, pop_back_exp))\r
- return pop_back(); \r
- else if(boost::regex_match(param, what, clear_exp))\r
- return clear();\r
- else if(boost::regex_match(param, what, next_exp))\r
- return next(); \r
- else if(boost::regex_match(param, what, insert_exp))\r
- return insert(boost::lexical_cast<size_t>(what["POS"].str()), what["PARAM"].str());\r
- else if(boost::regex_match(param, what, remove_exp))\r
- return erase(boost::lexical_cast<size_t>(what["POS"].str()));\r
- else if(boost::regex_match(param, what, list_exp))\r
- return list();\r
- else if(boost::regex_match(param, what, loop_exp))\r
- {\r
- if(!what["VALUE"].str().empty())\r
- loop_ = boost::lexical_cast<bool>(what["VALUE"].str());\r
- return boost::lexical_cast<std::wstring>(loop_);\r
- }\r
-\r
- BOOST_THROW_EXCEPTION(invalid_argument());\r
- }\r
- \r
- std::wstring push_front(const std::wstring& str)\r
- {\r
- producers_.push_front(create_producer(factory_, str)); \r
- return L"";\r
- }\r
-\r
- std::wstring push_back(const std::wstring& str)\r
- {\r
- producers_.push_back(create_producer(factory_, str)); \r
- return L"";\r
- }\r
-\r
- std::wstring pop_front()\r
- {\r
- producers_.pop_front();\r
- return L"";\r
- }\r
-\r
- std::wstring pop_back()\r
- {\r
- producers_.pop_back();\r
- return L"";\r
- }\r
- \r
- std::wstring clear()\r
- {\r
- producers_.clear();\r
- return L"";\r
- }\r
-\r
- std::wstring next()\r
- {\r
- if(!producers_.empty())\r
- {\r
- current_ = producers_.front();\r
- producers_.pop_front();\r
- //if(loop_)\r
- // producers_.push_back(current_);\r
- }\r
- return L"";\r
- }\r
- \r
- std::wstring insert(size_t pos, const std::wstring& str)\r
- {\r
- if(pos >= producers_.size())\r
- BOOST_THROW_EXCEPTION(out_of_range());\r
- producers_.insert(std::begin(producers_) + pos, create_producer(factory_, str));\r
- return L"";\r
- }\r
-\r
- std::wstring erase(size_t pos)\r
- {\r
- if(pos >= producers_.size())\r
- BOOST_THROW_EXCEPTION(out_of_range());\r
- producers_.erase(std::begin(producers_) + pos);\r
- return L"";\r
- }\r
-\r
- std::wstring list() const\r
- {\r
- std::wstring result = L"<playlist>\n";\r
- BOOST_FOREACH(auto& producer, producers_) \r
- result += L"\t<producer>" + producer->print() + L"</producer>\n";\r
- return result + L"</playlist>";\r
- }\r
-};\r
-\r
-safe_ptr<frame_producer> create_playlist_producer(\r
- const safe_ptr<core::frame_factory>& frame_factory,\r
- const std::vector<std::wstring>& params,\r
- const std::vector<std::wstring>& original_case_params)\r
-{\r
- if(boost::range::find(params, L"[PLAYLIST]") == params.end())\r
- return core::frame_producer::empty();\r
-\r
- bool loop = boost::range::find(params, L"LOOP") != params.end();\r
-\r
- return make_safe<playlist_producer>(frame_factory, loop);\r
-}\r
-\r
-}}\r
-\r