return status;\r
}\r
\r
+ std::wstring param(bool foreground, const std::wstring& param)\r
+ {\r
+ return (foreground ? foreground_ : background_)->param(param);\r
+ }\r
+\r
bool empty() const\r
{\r
return background_ == core::frame_producer::empty() && foreground_ == core::frame_producer::empty();\r
safe_ptr<frame_producer> layer::foreground() const { return impl_->foreground_;}\r
safe_ptr<frame_producer> layer::background() const { return impl_->background_;}\r
bool layer::empty() const {return impl_->empty();}\r
+std::wstring layer::param(bool foreground, const std::wstring& param){return impl_->param(foreground, param);}\r
}}
\ No newline at end of file
void play(); // nothrow\r
void pause(); // nothrow\r
void stop(); // nothrow\r
+ std::wstring param(bool foreground, const std::wstring& param);\r
\r
bool is_paused() const;\r
int64_t frame_number() const;\r
#include <core/producer/frame_producer.h>\r
#include <core/producer/frame/basic_frame.h>\r
\r
+#include <boost/regex.hpp>\r
+\r
+#include <deque>\r
+\r
namespace caspar { namespace core { \r
\r
struct playlist_producer : public frame_producer\r
safe_ptr<frame_producer> current_;\r
bool loop_;\r
\r
- std::list<safe_ptr<frame_producer>> producers_;\r
+ std::deque<safe_ptr<frame_producer>> producers_;\r
\r
playlist_producer(const safe_ptr<frame_factory>& factory, bool loop) \r
: factory_(factory)\r
}\r
\r
virtual std::wstring param(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 (?<PARAM>.+)");\r
+ static const boost::wregex pop_front_exp (L"POP_FRONT"); \r
+ static const boost::wregex pop_back_exp (L"POP_BACK"); \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, 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
- const static std::wstring push_front_str = L"PUSH_FRONT ";\r
- const static std::wstring push_back_str = L"PUSH_BACK ";\r
+ producers_.pop_front();\r
+ return L"";\r
+ }\r
\r
- auto pos = param.find(push_front_str);\r
+ std::wstring pop_back()\r
+ {\r
+ producers_.pop_back();\r
+ return L"";\r
+ }\r
\r
- if(pos != std::wstring::npos)\r
- push_front(param.substr(pos+push_front_str.size()));\r
- \r
- pos = param.find(push_back_str);\r
- \r
- if(pos != std::wstring::npos)\r
- push_back(param.substr(pos+push_back_str.size()));\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
- void push_back(const std::wstring& param)\r
+\r
+ std::wstring erase(size_t pos)\r
{\r
- producers_.push_back(create_producer(factory_, param)); \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
- void push_front(const std::wstring& param)\r
+ std::wstring list() const\r
{\r
- producers_.push_front(create_producer(factory_, param)); \r
+ std::wstring result = L"<array>";\r
+ BOOST_FOREACH(auto& producer, producers_) \r
+ result += L"<string>" + producer->print() + L"</string>\n";\r
+ return result + L"</array>";\r
}\r
};\r
\r
}, high_priority);\r
} \r
\r
+ std::wstring param(int index, bool foreground, const std::wstring& param)\r
+ {\r
+ return executor_.invoke([&]\r
+ {\r
+ return layers_[index].param(foreground, param);\r
+ }, high_priority);\r
+ }\r
+\r
void swap_layer(int index, size_t other_index)\r
{\r
executor_.invoke([&]\r
safe_ptr<frame_producer> stage::foreground(size_t index) {return impl_->foreground(index);}\r
safe_ptr<frame_producer> stage::background(size_t index) {return impl_->background(index);}\r
void stage::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);}\r
+std::wstring stage::param(int index, bool foreground, const std::wstring& param){return impl_->param(index, foreground, param);}\r
}}
\ No newline at end of file
void stop(int index);\r
void clear(int index);\r
void clear(); \r
+ std::wstring param(int index, bool foreground, const std::wstring& param);\r
void swap_layer(int index, size_t other_index);\r
void swap_layer(int index, size_t other_index, stage& other);\r
\r
#include <boost/filesystem.hpp>\r
#include <boost/range/algorithm/find_if.hpp>\r
#include <boost/range/algorithm/find.hpp>\r
+#include <boost/regex.hpp>\r
\r
#include <tbb/parallel_invoke.h>\r
\r
\r
return nb_frames - start_;\r
}\r
+\r
+ virtual std::wstring param(const std::wstring& param)\r
+ {\r
+ static const boost::wregex loop_exp(L"LOOP\\s*(?<VALUE>\\d?)");\r
+ static const boost::wregex seek_exp(L"SEEK\\s+(?<VALUE>\\d+)");\r
+ \r
+ boost::wsmatch what;\r
+ if(boost::regex_match(param, what, loop_exp))\r
+ {\r
+ if(!what["VALUE"].str().empty())\r
+ input_.loop(boost::lexical_cast<bool>(what["VALUE"].str()));\r
+ return boost::lexical_cast<std::wstring>(input_.loop());\r
+ }\r
+ if(boost::regex_match(param, what, seek_exp))\r
+ {\r
+ input_.seek(boost::lexical_cast<int64_t>(what["VALUE"].str()));\r
+ return L"";\r
+ }\r
+\r
+ BOOST_THROW_EXCEPTION(invalid_argument());\r
+ }\r
\r
virtual std::wstring print() const\r
{\r
\r
#include <tbb/concurrent_queue.h>\r
#include <tbb/atomic.h>\r
+#include <tbb/recursive_mutex.h>\r
\r
#include <boost/range/algorithm.hpp>\r
#include <boost/thread/condition_variable.hpp>\r
const int default_stream_index_;\r
\r
const std::wstring filename_;\r
- const bool loop_;\r
+ tbb::atomic<bool> loop_;\r
const size_t start_; \r
const size_t length_;\r
size_t frame_number_;\r
boost::thread thread_;\r
tbb::atomic<bool> is_running_;\r
\r
-public:\r
+ tbb::recursive_mutex mutex_;\r
+\r
explicit implementation(const safe_ptr<diagnostics::graph>& graph, const std::wstring& filename, bool loop, size_t start, size_t length) \r
: graph_(graph)\r
, format_context_(open_input(filename)) \r
, default_stream_index_(av_find_default_stream_index(format_context_.get()))\r
- , loop_(loop)\r
, filename_(filename)\r
, start_(start)\r
, length_(length)\r
, frame_number_(0)\r
- { \r
+ { \r
+ loop_ = loop;\r
buffer_size_ = 0;\r
nb_frames_ = 0;\r
nb_loops_ = 0;\r
nb_loops_ = 0;\r
\r
if(start_ > 0) \r
- seek_frame(start_);\r
+ do_seek(start_);\r
\r
graph_->set_color("seek", diagnostics::color(1.0f, 0.5f, 0.0f)); \r
graph_->set_color("buffer-count", diagnostics::color(0.7f, 0.4f, 0.4f));\r
\r
return result;\r
}\r
-\r
- size_t nb_frames() const\r
- {\r
- return nb_frames_;\r
- }\r
-\r
- size_t nb_loops() const\r
- {\r
- return nb_loops_;\r
- }\r
-\r
-private:\r
- \r
+ \r
void run()\r
{ \r
caspar::win32_exception::install_handler();\r
\r
void read_next_packet()\r
{ \r
+ tbb::recursive_mutex::scoped_lock lock(mutex_);\r
+\r
auto packet = create_packet();\r
auto ret = av_read_frame(format_context_.get(), packet.get()); // packet is only valid until next call of av_read_frame. Use av_dup_packet to extend its life. \r
\r
\r
if(loop_)\r
{\r
- seek_frame(start_);\r
+ do_seek(start_);\r
graph_->add_tag("seek"); \r
CASPAR_LOG(debug) << print() << " Looping."; \r
} \r
{\r
return is_running_ && (buffer_size_ > MAX_BUFFER_SIZE || buffer_.size() > MAX_BUFFER_COUNT) && buffer_.size() > MIN_BUFFER_COUNT;\r
}\r
-\r
- void seek_frame(int64_t target)\r
- { \r
+ \r
+ void do_seek(int64_t target)\r
+ { \r
CASPAR_LOG(debug) << print() << " Seeking: " << target;\r
\r
int flags = AVSEEK_FLAG_FRAME;\r
THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits<int64_t>::min(), target, std::numeric_limits<int64_t>::max(), 0), print()); \r
\r
buffer_.push(flush_packet());\r
- } \r
+ } \r
+\r
+ void seek(int64_t target)\r
+ {\r
+ tbb::recursive_mutex::scoped_lock lock(mutex_);\r
+\r
+ std::shared_ptr<AVPacket> packet;\r
+ while(try_pop(packet))\r
+ {\r
+ }\r
+\r
+ do_seek(target);\r
+ }\r
\r
bool is_eof(int ret)\r
{\r
bool input::eof() const {return !impl_->is_running_;}\r
bool input::try_pop(std::shared_ptr<AVPacket>& packet){return impl_->try_pop(packet);}\r
safe_ptr<AVFormatContext> input::context(){return impl_->format_context_;}\r
-size_t input::nb_frames() const {return impl_->nb_frames();}\r
-size_t input::nb_loops() const {return impl_->nb_loops();}\r
+size_t input::nb_frames() const {return impl_->nb_frames_;}\r
+size_t input::nb_loops() const {return impl_->nb_loops_;}\r
+void input::loop(bool value){impl_->loop_ = value;}\r
+bool input::loop() const{return impl_->loop_;}\r
+void input::seek(int64_t target){impl_->seek(target);}\r
}}\r
\r
#include <memory>\r
#include <string>\r
+#include <cstdint>\r
\r
#include <boost/noncopyable.hpp>\r
\r
size_t nb_frames() const;\r
size_t nb_loops() const;\r
\r
+ void loop(bool value);\r
+ bool loop() const;\r
+\r
+ void seek(int64_t target);\r
+\r
safe_ptr<AVFormatContext> context();\r
private:\r
struct implementation;\r
\r
std::wstring result;\r
if(what == L"B")\r
- result = GetChannel()->stage()->background(GetLayerIndex()).get()->param(param);\r
- else if(what == L"F")\r
- result = GetChannel()->stage()->foreground(GetLayerIndex()).get()->param(param);\r
+ result = GetChannel()->stage()->param(GetLayerIndex(), false, param);\r
+ else\r
+ result = GetChannel()->stage()->param(GetLayerIndex(), true, param);\r
\r
CASPAR_LOG(info) << "Executed param: " << _parameters[0] << TEXT(" successfully");\r
\r