]> git.sesse.net Git - casparcg/blob - core/producer/playlist/playlist_producer.cpp
2068e2a57c4969611e4a2e4532ee8ac4dfc66ec3
[casparcg] / core / producer / playlist / playlist_producer.cpp
1 /*\r
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 * This file is part of CasparCG (www.casparcg.com).\r
5 *\r
6 * CasparCG is free software: you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation, either version 3 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * CasparCG is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 * Author: Robert Nagy, ronag89@gmail.com\r
20 */\r
21 \r
22 #include "../../stdafx.h"\r
23 \r
24 #include "playlist_producer.h"\r
25 \r
26 #include <core/producer/frame_producer.h>\r
27 #include <core/producer/frame/basic_frame.h>\r
28 \r
29 #include <boost/regex.hpp>\r
30 #include <boost/property_tree/ptree.hpp>\r
31 \r
32 #include <deque>\r
33 \r
34 namespace caspar { namespace core {     \r
35 \r
36 struct playlist_producer : public frame_producer\r
37 {                               \r
38         safe_ptr<frame_factory>                         factory_;\r
39         safe_ptr<basic_frame>                           last_frame_;\r
40         safe_ptr<frame_producer>                        current_;\r
41         bool                                                            loop_;\r
42 \r
43         std::deque<safe_ptr<frame_producer>> producers_;\r
44 \r
45         playlist_producer(const safe_ptr<frame_factory>& factory, bool loop) \r
46                 : factory_(factory)\r
47                 , last_frame_(basic_frame::empty())\r
48                 , current_(frame_producer::empty())\r
49                 , loop_(loop)\r
50         {\r
51         }\r
52 \r
53         // frame_producer\r
54         \r
55         virtual safe_ptr<basic_frame> receive(int hints) override\r
56         {\r
57                 if(current_ == frame_producer::empty() && !producers_.empty())\r
58                         next();\r
59 \r
60                 auto frame = current_->receive(hints);\r
61                 if(frame == basic_frame::eof())\r
62                 {\r
63                         current_ = frame_producer::empty();\r
64                         return receive(hints);\r
65                 }\r
66 \r
67                 return last_frame_ = frame;\r
68         }\r
69 \r
70         virtual safe_ptr<core::basic_frame> last_frame() const override\r
71         {\r
72                 return disable_audio(last_frame_);\r
73         }\r
74 \r
75         virtual std::wstring print() const override\r
76         {\r
77                 return L"playlist[" + current_->print() + L"]";\r
78         }       \r
79 \r
80         virtual boost::property_tree::wptree info() const override\r
81         {\r
82                 boost::property_tree::wptree info;\r
83                 info.add(L"type", L"playlist-producer");\r
84                 return info;\r
85         }\r
86 \r
87         virtual uint32_t nb_frames() const  override\r
88         {\r
89                 return std::numeric_limits<uint32_t>::max();\r
90         }\r
91         \r
92         virtual boost::unique_future<std::wstring> call(const std::wstring& param) override\r
93         {\r
94                 boost::promise<std::wstring> promise;\r
95                 promise.set_value(do_call(param));\r
96                 return promise.get_future();\r
97         }       \r
98 \r
99         // playlist_producer\r
100 \r
101         std::wstring do_call(const std::wstring& param)\r
102         {               \r
103                 static const boost::wregex push_front_exp       (L"PUSH_FRONT (?<PARAM>.+)");           \r
104                 static const boost::wregex push_back_exp        (L"(PUSH_BACK|PUSH) (?<PARAM>.+)");\r
105                 static const boost::wregex pop_front_exp        (L"POP_FRONT");         \r
106                 static const boost::wregex pop_back_exp         (L"(POP_BACK|POP)");\r
107                 static const boost::wregex clear_exp            (L"CLEAR");\r
108                 static const boost::wregex next_exp                     (L"NEXT");\r
109                 static const boost::wregex insert_exp           (L"INSERT (?<POS>\\d+) (?<PARAM>.+)");  \r
110                 static const boost::wregex remove_exp           (L"REMOVE (?<POS>\\d+) (?<PARAM>.+)");  \r
111                 static const boost::wregex list_exp                     (L"LIST");                      \r
112                 static const boost::wregex loop_exp                     (L"LOOP\\s*(?<VALUE>\\d?)");\r
113                 \r
114                 boost::wsmatch what;\r
115 \r
116                 if(boost::regex_match(param, what, push_front_exp))\r
117                         return push_front(what["PARAM"].str()); \r
118                 else if(boost::regex_match(param, what, push_back_exp))\r
119                         return push_back(what["PARAM"].str()); \r
120                 if(boost::regex_match(param, what, pop_front_exp))\r
121                         return pop_front(); \r
122                 else if(boost::regex_match(param, what, pop_back_exp))\r
123                         return pop_back(); \r
124                 else if(boost::regex_match(param, what, clear_exp))\r
125                         return clear();\r
126                 else if(boost::regex_match(param, what, next_exp))\r
127                         return next(); \r
128                 else if(boost::regex_match(param, what, insert_exp))\r
129                         return insert(boost::lexical_cast<size_t>(what["POS"].str()), what["PARAM"].str());\r
130                 else if(boost::regex_match(param, what, remove_exp))\r
131                         return erase(boost::lexical_cast<size_t>(what["POS"].str()));\r
132                 else if(boost::regex_match(param, what, list_exp))\r
133                         return list();\r
134                 else if(boost::regex_match(param, what, loop_exp))\r
135                 {\r
136                         if(!what["VALUE"].str().empty())\r
137                                 loop_ = boost::lexical_cast<bool>(what["VALUE"].str());\r
138                         return boost::lexical_cast<std::wstring>(loop_);\r
139                 }\r
140 \r
141                 BOOST_THROW_EXCEPTION(invalid_argument());\r
142         }\r
143         \r
144         std::wstring push_front(const std::wstring& str)\r
145         {\r
146                 producers_.push_front(create_producer(factory_, str)); \r
147                 return L"";\r
148         }\r
149 \r
150         std::wstring  push_back(const std::wstring& str)\r
151         {\r
152                 producers_.push_back(create_producer(factory_, str)); \r
153                 return L"";\r
154         }\r
155 \r
156         std::wstring pop_front()\r
157         {\r
158                 producers_.pop_front();\r
159                 return L"";\r
160         }\r
161 \r
162         std::wstring pop_back()\r
163         {\r
164                 producers_.pop_back();\r
165                 return L"";\r
166         }\r
167         \r
168         std::wstring clear()\r
169         {\r
170                 producers_.clear();\r
171                 return L"";\r
172         }\r
173 \r
174         std::wstring next()\r
175         {\r
176                 if(!producers_.empty())\r
177                 {\r
178                         current_ = producers_.front();\r
179                         producers_.pop_front();\r
180                         //if(loop_)\r
181                         //      producers_.push_back(current_);\r
182                 }\r
183                 return L"";\r
184         }\r
185         \r
186         std::wstring  insert(size_t pos, const std::wstring& str)\r
187         {\r
188                 if(pos >= producers_.size())\r
189                         BOOST_THROW_EXCEPTION(out_of_range());\r
190                 producers_.insert(std::begin(producers_) + pos, create_producer(factory_, str));\r
191                 return L"";\r
192         }\r
193 \r
194         std::wstring  erase(size_t pos)\r
195         {\r
196                 if(pos >= producers_.size())\r
197                         BOOST_THROW_EXCEPTION(out_of_range());\r
198                 producers_.erase(std::begin(producers_) + pos);\r
199                 return L"";\r
200         }\r
201 \r
202         std::wstring list() const\r
203         {\r
204                 std::wstring result = L"<playlist>\n";\r
205                 BOOST_FOREACH(auto& producer, producers_)               \r
206                         result += L"\t<producer>" + producer->print() + L"</producer>\n";\r
207                 return result + L"</playlist>";\r
208         }\r
209 };\r
210 \r
211 safe_ptr<frame_producer> create_playlist_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)\r
212 {\r
213         if(boost::range::find(params, L"[PLAYLIST]") == params.end())\r
214                 return core::frame_producer::empty();\r
215 \r
216         bool loop = boost::range::find(params, L"LOOP") != params.end();\r
217 \r
218         return make_safe<playlist_producer>(frame_factory, loop);\r
219 }\r
220 \r
221 }}\r
222 \r