From a9e35a4c5f335d25535adc3330ca8a64730e763e Mon Sep 17 00:00:00 2001 From: ronag Date: Fri, 25 Nov 2011 19:08:18 +0000 Subject: [PATCH] 2.0.2: - stage: PARAM command is now synchronized with rendering thread. - ffmpeg_producer: PARAM LOOP and PARAM SEEK implemented. - playlist_producer: Added some more small features.hpp NOTE: PARAM is a horrible name for this command, should be replaced with INVOKE or something similar in the future. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.2@1659 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- core/producer/layer.cpp | 6 ++ core/producer/layer.h | 1 + core/producer/playlist/playlist_producer.cpp | 94 ++++++++++++++++---- core/producer/stage.cpp | 9 ++ core/producer/stage.h | 1 + modules/ffmpeg/producer/ffmpeg_producer.cpp | 22 +++++ modules/ffmpeg/producer/input/input.cpp | 57 ++++++------ modules/ffmpeg/producer/input/input.h | 6 ++ protocol/amcp/AMCPCommandsImpl.cpp | 6 +- 9 files changed, 158 insertions(+), 44 deletions(-) diff --git a/core/producer/layer.cpp b/core/producer/layer.cpp index f940d2a9e..deed583ed 100644 --- a/core/producer/layer.cpp +++ b/core/producer/layer.cpp @@ -133,6 +133,11 @@ public: return status; } + std::wstring param(bool foreground, const std::wstring& param) + { + return (foreground ? foreground_ : background_)->param(param); + } + bool empty() const { return background_ == core::frame_producer::empty() && foreground_ == core::frame_producer::empty(); @@ -168,4 +173,5 @@ safe_ptr layer::receive() {return impl_->receive();} safe_ptr layer::foreground() const { return impl_->foreground_;} safe_ptr layer::background() const { return impl_->background_;} bool layer::empty() const {return impl_->empty();} +std::wstring layer::param(bool foreground, const std::wstring& param){return impl_->param(foreground, param);} }} \ No newline at end of file diff --git a/core/producer/layer.h b/core/producer/layer.h index 430f34513..d04def0c5 100644 --- a/core/producer/layer.h +++ b/core/producer/layer.h @@ -55,6 +55,7 @@ public: void play(); // nothrow void pause(); // nothrow void stop(); // nothrow + std::wstring param(bool foreground, const std::wstring& param); bool is_paused() const; int64_t frame_number() const; diff --git a/core/producer/playlist/playlist_producer.cpp b/core/producer/playlist/playlist_producer.cpp index 885f2b52b..1565d68de 100644 --- a/core/producer/playlist/playlist_producer.cpp +++ b/core/producer/playlist/playlist_producer.cpp @@ -24,6 +24,10 @@ #include #include +#include + +#include + namespace caspar { namespace core { struct playlist_producer : public frame_producer @@ -33,7 +37,7 @@ struct playlist_producer : public frame_producer safe_ptr current_; bool loop_; - std::list> producers_; + std::deque> producers_; playlist_producer(const safe_ptr& factory, bool loop) : factory_(factory) @@ -79,31 +83,89 @@ struct playlist_producer : public frame_producer } virtual std::wstring param(const std::wstring& param) + { + static const boost::wregex push_front_exp (L"PUSH_FRONT (?.+)"); + static const boost::wregex push_back_exp (L"PUSH_BACK (?.+)"); + static const boost::wregex pop_front_exp (L"POP_FRONT"); + static const boost::wregex pop_back_exp (L"POP_BACK"); + static const boost::wregex insert_exp (L"INSERT (?\\d+) (?.+)"); + static const boost::wregex remove_exp (L"REMOVE (?\\d+) (?.+)"); + static const boost::wregex list_exp (L"LIST"); + static const boost::wregex loop_exp (L"LOOP\\s*(?\\d?)"); + + boost::wsmatch what; + + if(boost::regex_match(param, what, push_front_exp)) + return push_front(what["PARAM"].str()); + else if(boost::regex_match(param, what, push_back_exp)) + return push_back(what["PARAM"].str()); + if(boost::regex_match(param, what, pop_front_exp)) + return pop_front(); + else if(boost::regex_match(param, what, pop_back_exp)) + return pop_back(); + else if(boost::regex_match(param, what, insert_exp)) + return insert(boost::lexical_cast(what["POS"].str()), what["PARAM"].str()); + else if(boost::regex_match(param, what, remove_exp)) + return erase(boost::lexical_cast(what["POS"].str())); + else if(boost::regex_match(param, what, list_exp)) + return list(); + else if(boost::regex_match(param, what, loop_exp)) + { + if(!what["VALUE"].str().empty()) + loop_ = boost::lexical_cast(what["VALUE"].str()); + return boost::lexical_cast(loop_); + } + + BOOST_THROW_EXCEPTION(invalid_argument()); + } + + std::wstring push_front(const std::wstring& str) + { + producers_.push_front(create_producer(factory_, str)); + return L""; + } + + std::wstring push_back(const std::wstring& str) + { + producers_.push_back(create_producer(factory_, str)); + return L""; + } + + std::wstring pop_front() { - const static std::wstring push_front_str = L"PUSH_FRONT "; - const static std::wstring push_back_str = L"PUSH_BACK "; + producers_.pop_front(); + return L""; + } - auto pos = param.find(push_front_str); + std::wstring pop_back() + { + producers_.pop_back(); + return L""; + } - if(pos != std::wstring::npos) - push_front(param.substr(pos+push_front_str.size())); - - pos = param.find(push_back_str); - - if(pos != std::wstring::npos) - push_back(param.substr(pos+push_back_str.size())); + std::wstring insert(size_t pos, const std::wstring& str) + { + if(pos >= producers_.size()) + BOOST_THROW_EXCEPTION(out_of_range()); + producers_.insert(std::begin(producers_) + pos, create_producer(factory_, str)); return L""; } - - void push_back(const std::wstring& param) + + std::wstring erase(size_t pos) { - producers_.push_back(create_producer(factory_, param)); + if(pos >= producers_.size()) + BOOST_THROW_EXCEPTION(out_of_range()); + producers_.erase(std::begin(producers_) + pos); + return L""; } - void push_front(const std::wstring& param) + std::wstring list() const { - producers_.push_front(create_producer(factory_, param)); + std::wstring result = L""; + BOOST_FOREACH(auto& producer, producers_) + result += L"" + producer->print() + L"\n"; + return result + L""; } }; diff --git a/core/producer/stage.cpp b/core/producer/stage.cpp index ea3b91c4f..ef09a1550 100644 --- a/core/producer/stage.cpp +++ b/core/producer/stage.cpp @@ -154,6 +154,14 @@ public: }, high_priority); } + std::wstring param(int index, bool foreground, const std::wstring& param) + { + return executor_.invoke([&] + { + return layers_[index].param(foreground, param); + }, high_priority); + } + void swap_layer(int index, size_t other_index) { executor_.invoke([&] @@ -229,4 +237,5 @@ layer_status stage::get_status(int index){return impl_->get_status(index);} safe_ptr stage::foreground(size_t index) {return impl_->foreground(index);} safe_ptr stage::background(size_t index) {return impl_->background(index);} void stage::set_video_format_desc(const video_format_desc& format_desc){impl_->set_video_format_desc(format_desc);} +std::wstring stage::param(int index, bool foreground, const std::wstring& param){return impl_->param(index, foreground, param);} }} \ No newline at end of file diff --git a/core/producer/stage.h b/core/producer/stage.h index 90b32cf67..68ccfef42 100644 --- a/core/producer/stage.h +++ b/core/producer/stage.h @@ -49,6 +49,7 @@ public: void stop(int index); void clear(int index); void clear(); + std::wstring param(int index, bool foreground, const std::wstring& param); void swap_layer(int index, size_t other_index); void swap_layer(int index, size_t other_index, stage& other); diff --git a/modules/ffmpeg/producer/ffmpeg_producer.cpp b/modules/ffmpeg/producer/ffmpeg_producer.cpp index 10a30c341..da665d854 100644 --- a/modules/ffmpeg/producer/ffmpeg_producer.cpp +++ b/modules/ffmpeg/producer/ffmpeg_producer.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include @@ -230,6 +231,27 @@ public: return nb_frames - start_; } + + virtual std::wstring param(const std::wstring& param) + { + static const boost::wregex loop_exp(L"LOOP\\s*(?\\d?)"); + static const boost::wregex seek_exp(L"SEEK\\s+(?\\d+)"); + + boost::wsmatch what; + if(boost::regex_match(param, what, loop_exp)) + { + if(!what["VALUE"].str().empty()) + input_.loop(boost::lexical_cast(what["VALUE"].str())); + return boost::lexical_cast(input_.loop()); + } + if(boost::regex_match(param, what, seek_exp)) + { + input_.seek(boost::lexical_cast(what["VALUE"].str())); + return L""; + } + + BOOST_THROW_EXCEPTION(invalid_argument()); + } virtual std::wstring print() const { diff --git a/modules/ffmpeg/producer/input/input.cpp b/modules/ffmpeg/producer/input/input.cpp index 95842235a..213bc52fb 100644 --- a/modules/ffmpeg/producer/input/input.cpp +++ b/modules/ffmpeg/producer/input/input.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -70,7 +71,7 @@ struct input::implementation : boost::noncopyable const int default_stream_index_; const std::wstring filename_; - const bool loop_; + tbb::atomic loop_; const size_t start_; const size_t length_; size_t frame_number_; @@ -86,17 +87,18 @@ struct input::implementation : boost::noncopyable boost::thread thread_; tbb::atomic is_running_; -public: + tbb::recursive_mutex mutex_; + explicit implementation(const safe_ptr& graph, const std::wstring& filename, bool loop, size_t start, size_t length) : graph_(graph) , format_context_(open_input(filename)) , default_stream_index_(av_find_default_stream_index(format_context_.get())) - , loop_(loop) , filename_(filename) , start_(start) , length_(length) , frame_number_(0) - { + { + loop_ = loop; buffer_size_ = 0; nb_frames_ = 0; nb_loops_ = 0; @@ -106,7 +108,7 @@ public: nb_loops_ = 0; if(start_ > 0) - seek_frame(start_); + do_seek(start_); graph_->set_color("seek", diagnostics::color(1.0f, 0.5f, 0.0f)); graph_->set_color("buffer-count", diagnostics::color(0.7f, 0.4f, 0.4f)); @@ -141,19 +143,7 @@ public: return result; } - - size_t nb_frames() const - { - return nb_frames_; - } - - size_t nb_loops() const - { - return nb_loops_; - } - -private: - + void run() { caspar::win32_exception::install_handler(); @@ -185,6 +175,8 @@ private: void read_next_packet() { + tbb::recursive_mutex::scoped_lock lock(mutex_); + auto packet = create_packet(); 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. @@ -195,7 +187,7 @@ private: if(loop_) { - seek_frame(start_); + do_seek(start_); graph_->add_tag("seek"); CASPAR_LOG(debug) << print() << " Looping."; } @@ -240,9 +232,9 @@ private: { return is_running_ && (buffer_size_ > MAX_BUFFER_SIZE || buffer_.size() > MAX_BUFFER_COUNT) && buffer_.size() > MIN_BUFFER_COUNT; } - - void seek_frame(int64_t target) - { + + void do_seek(int64_t target) + { CASPAR_LOG(debug) << print() << " Seeking: " << target; int flags = AVSEEK_FLAG_FRAME; @@ -266,7 +258,19 @@ private: THROW_ON_ERROR2(avformat_seek_file(format_context_.get(), default_stream_index_, std::numeric_limits::min(), target, std::numeric_limits::max(), 0), print()); buffer_.push(flush_packet()); - } + } + + void seek(int64_t target) + { + tbb::recursive_mutex::scoped_lock lock(mutex_); + + std::shared_ptr packet; + while(try_pop(packet)) + { + } + + do_seek(target); + } bool is_eof(int ret) { @@ -289,6 +293,9 @@ input::input(const safe_ptr& graph, const std::wstring& file bool input::eof() const {return !impl_->is_running_;} bool input::try_pop(std::shared_ptr& packet){return impl_->try_pop(packet);} safe_ptr input::context(){return impl_->format_context_;} -size_t input::nb_frames() const {return impl_->nb_frames();} -size_t input::nb_loops() const {return impl_->nb_loops();} +size_t input::nb_frames() const {return impl_->nb_frames_;} +size_t input::nb_loops() const {return impl_->nb_loops_;} +void input::loop(bool value){impl_->loop_ = value;} +bool input::loop() const{return impl_->loop_;} +void input::seek(int64_t target){impl_->seek(target);} }} diff --git a/modules/ffmpeg/producer/input/input.h b/modules/ffmpeg/producer/input/input.h index 6b391581f..b434b2089 100644 --- a/modules/ffmpeg/producer/input/input.h +++ b/modules/ffmpeg/producer/input/input.h @@ -23,6 +23,7 @@ #include #include +#include #include @@ -50,6 +51,11 @@ public: size_t nb_frames() const; size_t nb_loops() const; + void loop(bool value); + bool loop() const; + + void seek(int64_t target); + safe_ptr context(); private: struct implementation; diff --git a/protocol/amcp/AMCPCommandsImpl.cpp b/protocol/amcp/AMCPCommandsImpl.cpp index b8770fd48..0cb915cfe 100644 --- a/protocol/amcp/AMCPCommandsImpl.cpp +++ b/protocol/amcp/AMCPCommandsImpl.cpp @@ -227,9 +227,9 @@ bool ParamCommand::DoExecute() std::wstring result; if(what == L"B") - result = GetChannel()->stage()->background(GetLayerIndex()).get()->param(param); - else if(what == L"F") - result = GetChannel()->stage()->foreground(GetLayerIndex()).get()->param(param); + result = GetChannel()->stage()->param(GetLayerIndex(), false, param); + else + result = GetChannel()->stage()->param(GetLayerIndex(), true, param); CASPAR_LOG(info) << "Executed param: " << _parameters[0] << TEXT(" successfully"); -- 2.39.2