2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
\r
4 * This file is part of CasparCG (www.casparcg.com).
\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
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
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
19 * Author: Robert Nagy, ronag89@gmail.com
\r
22 #include "../../stdafx.h"
\r
24 #include "playlist_producer.h"
\r
26 #include <core/producer/frame_producer.h>
\r
27 #include <core/producer/frame/basic_frame.h>
\r
29 #include <boost/regex.hpp>
\r
30 #include <boost/property_tree/ptree.hpp>
\r
34 namespace caspar { namespace core {
\r
36 struct playlist_producer : public frame_producer
\r
38 safe_ptr<frame_factory> factory_;
\r
39 safe_ptr<basic_frame> last_frame_;
\r
40 safe_ptr<frame_producer> current_;
\r
43 std::deque<safe_ptr<frame_producer>> producers_;
\r
45 playlist_producer(const safe_ptr<frame_factory>& factory, bool loop)
\r
47 , last_frame_(basic_frame::empty())
\r
48 , current_(frame_producer::empty())
\r
55 virtual safe_ptr<basic_frame> receive(int hints) override
\r
57 if(current_ == frame_producer::empty() && !producers_.empty())
\r
60 auto frame = current_->receive(hints);
\r
61 if(frame == basic_frame::eof())
\r
63 current_ = frame_producer::empty();
\r
64 return receive(hints);
\r
67 return last_frame_ = frame;
\r
70 virtual safe_ptr<core::basic_frame> last_frame() const override
\r
72 return disable_audio(last_frame_);
\r
75 virtual std::wstring print() const override
\r
77 return L"playlist[" + current_->print() + L"]";
\r
80 virtual boost::property_tree::wptree info() const override
\r
82 boost::property_tree::wptree info;
\r
83 info.add(L"type", L"playlist-producer");
\r
87 virtual uint32_t nb_frames() const override
\r
89 return std::numeric_limits<uint32_t>::max();
\r
92 virtual boost::unique_future<std::wstring> call(const std::wstring& param) override
\r
94 boost::promise<std::wstring> promise;
\r
95 promise.set_value(do_call(param));
\r
96 return promise.get_future();
\r
99 // playlist_producer
\r
101 std::wstring do_call(const std::wstring& param)
\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
114 boost::wsmatch what;
\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
126 else if(boost::regex_match(param, what, next_exp))
\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
134 else if(boost::regex_match(param, what, loop_exp))
\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
141 BOOST_THROW_EXCEPTION(invalid_argument());
\r
144 std::wstring push_front(const std::wstring& str)
\r
146 producers_.push_front(create_producer(factory_, str));
\r
150 std::wstring push_back(const std::wstring& str)
\r
152 producers_.push_back(create_producer(factory_, str));
\r
156 std::wstring pop_front()
\r
158 producers_.pop_front();
\r
162 std::wstring pop_back()
\r
164 producers_.pop_back();
\r
168 std::wstring clear()
\r
170 producers_.clear();
\r
174 std::wstring next()
\r
176 if(!producers_.empty())
\r
178 current_ = producers_.front();
\r
179 producers_.pop_front();
\r
181 // producers_.push_back(current_);
\r
186 std::wstring insert(size_t pos, const std::wstring& str)
\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
194 std::wstring erase(size_t pos)
\r
196 if(pos >= producers_.size())
\r
197 BOOST_THROW_EXCEPTION(out_of_range());
\r
198 producers_.erase(std::begin(producers_) + pos);
\r
202 std::wstring list() const
\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
211 safe_ptr<frame_producer> create_playlist_producer(const safe_ptr<core::frame_factory>& frame_factory, const std::vector<std::wstring>& params)
\r
213 if(boost::range::find(params, L"[PLAYLIST]") == params.end())
\r
214 return core::frame_producer::empty();
\r
216 bool loop = boost::range::find(params, L"LOOP") != params.end();
\r
218 return make_safe<playlist_producer>(frame_factory, loop);
\r