diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index b30ca9f..1b51cac 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -709,7 +709,6 @@ void ImGuiVisitor::visit (NetworkSource& s) s.setConnection(s.connection()); } - } @@ -718,33 +717,43 @@ void ImGuiVisitor::visit (MultiFileSource& s) ImGuiToolkit::Icon(s.icon().x, s.icon().y); ImGui::SameLine(0, 10); ImGui::Text("Images sequence"); + static int64_t id = s.id(); // information text std::ostringstream msg; - msg << "Sequence of " << s.sequence().max - s.sequence().min << " "; + msg << "Sequence of " << s.sequence().max - s.sequence().min + 1 << " "; msg << s.sequence().codec << " images"; -// msg << "named " << SystemToolkit::base_filename( s.sequence().location ); -// msg << " in range [" << s.sequence().min << " - " << s.sequence().max << "]"; ImGui::Text("%s", msg.str().c_str()); // change range - glm::ivec2 range = s.range(); + static int _begin = -1; + if (_begin < 0 || id != s.id()) + _begin = s.begin(); + static int _end = -1; + if (_end < 0 || id != s.id()) + _end = s.end(); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - if ( ImGui::DragIntRange2("Range", &range.x, &range.y, 1, s.sequence().min, s.sequence().max) ){ - s.setRange( range ); + ImGui::DragIntRange2("Range", &_begin, &_end, 1, s.sequence().min, s.sequence().max); + if (ImGui::IsItemDeactivatedAfterEdit()){ + s.setRange( _begin, _end ); + std::ostringstream oss; + oss << s.name() << ": Range " << _begin << "-" << _end; + Action::manager().store(oss.str()); + _begin = _end = -1; } // change framerate - int _fps = s.framerate(); - static int _fps_changed = -1; + static int _fps = -1; + if (_fps < 0 || id != s.id()) + _fps = s.framerate(); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - if ( ImGui::SliderInt("Framerate", &_fps, 1, 30, "%d fps") ) { - _fps_changed = _fps; - } - // only call for setFramerate after mouse release to avoid repeating call to re-open the stream - else if (_fps_changed > 0 && ImGui::IsMouseReleased(ImGuiMouseButton_Left)){ - s.setFramerate(_fps_changed); - _fps_changed = -1; + ImGui::SliderInt("Framerate", &_fps, 1, 30, "%d fps"); + if (ImGui::IsItemDeactivatedAfterEdit()){ + s.setFramerate(_fps); + std::ostringstream oss; + oss << s.name() << ": Framerate " << _fps << " fps"; + Action::manager().store(oss.str()); + _fps = -1; } // offer to open file browser at location @@ -755,4 +764,5 @@ void ImGuiVisitor::visit (MultiFileSource& s) ImGui::SameLine(); ImGui::Text("Folder"); + id = s.id(); } diff --git a/MultiFileSource.cpp b/MultiFileSource.cpp index f441e1d..43ca8ce 100644 --- a/MultiFileSource.cpp +++ b/MultiFileSource.cpp @@ -83,7 +83,7 @@ MultiFile::MultiFile() : Stream(), src_(nullptr) } -void MultiFile::open(const MultiFileSequence &sequence, uint framerate ) +void MultiFile::open (const MultiFileSequence &sequence, uint framerate ) { if (sequence.location.empty()) return; @@ -95,8 +95,7 @@ void MultiFile::open(const MultiFileSequence &sequence, uint framerate ) gstreamer_pipeline << sequence.codec; gstreamer_pipeline << ",framerate=(fraction)"; gstreamer_pipeline << framerate; - gstreamer_pipeline << "/1\" loop="; - gstreamer_pipeline << sequence.loop; + gstreamer_pipeline << "/1\" loop=1"; gstreamer_pipeline << " start-index="; gstreamer_pipeline << sequence.min; gstreamer_pipeline << " stop-index="; @@ -106,28 +105,23 @@ void MultiFile::open(const MultiFileSequence &sequence, uint framerate ) // (private) open stream Stream::open(gstreamer_pipeline.str(), sequence.width, sequence.height); + // keep multifile source for dynamic properties change src_ = gst_bin_get_by_name (GST_BIN (pipeline_), "src"); - } -void MultiFile::setLoop (int on) -{ - if (src_) { - g_object_set (src_, "loop", on, NULL); - } -} -void MultiFile::setRange (int begin, int end) +void MultiFile::setProperties (int begin, int end, int loop) { if (src_) { g_object_set (src_, "start-index", MAX(begin, 0), NULL); g_object_set (src_, "stop-index", MAX(end, 0), NULL); + g_object_set (src_, "loop", MIN(loop, 1), NULL); } } -MultiFileSource::MultiFileSource(uint64_t id) : StreamSource(id), framerate_(0), range_(glm::ivec2(0)) +MultiFileSource::MultiFileSource (uint64_t id) : StreamSource(id), framerate_(0), begin_(-1), end_(INT_MAX), loop_(1) { // create stream stream_ = static_cast( new MultiFile ); @@ -154,8 +148,8 @@ void MultiFileSource::setSequence (const MultiFileSequence &sequence, uint frame multifile()->open( sequence_, framerate_ ); stream_->play(true); - // init range - range_ = glm::ivec2(sequence_.min, sequence_.max); + // validate range and apply loop_ + setRange(begin_, end_); // will be ready after init and one frame rendered ready_ = false; @@ -172,30 +166,30 @@ void MultiFileSource::setFramerate (uint framerate) void MultiFileSource::setLoop (bool on) { if (multifile()) { - sequence_.loop = on ? 1 : 0; - multifile()->setLoop( sequence_.loop ); + loop_ = on ? 1 : 0; + multifile()->setProperties (begin_, end_, loop_); } } -void MultiFileSource::setRange (glm::ivec2 range) +void MultiFileSource::setRange (int begin, int end) { - range_.x = glm::clamp( range.x, sequence_.min, sequence_.max ); - range_.y = glm::clamp( range.y, sequence_.min, sequence_.max ); - range_.x = glm::min( range_.x, range_.y ); - range_.y = glm::max( range_.x, range_.y ); + begin_ = glm::clamp( begin, sequence_.min, sequence_.max ); + end_ = glm::clamp( end , sequence_.min, sequence_.max ); + begin_ = glm::min( begin_, end_ ); + end_ = glm::max( begin_, end_ ); if (multifile()) - multifile()->setRange( range_.x, range_.y ); + multifile()->setProperties (begin_, end_, loop_); } -void MultiFileSource::accept(Visitor& v) +void MultiFileSource::accept (Visitor& v) { Source::accept(v); if (!failed()) v.visit(*this); } -MultiFile *MultiFileSource::multifile() const +MultiFile *MultiFileSource::multifile () const { return dynamic_cast(stream_); } diff --git a/MultiFileSource.h b/MultiFileSource.h index 52d27c0..676e822 100644 --- a/MultiFileSource.h +++ b/MultiFileSource.h @@ -13,6 +13,8 @@ struct MultiFileSequence { uint height; int min; int max; + int begin; + int end; int loop; MultiFileSequence (); @@ -28,8 +30,8 @@ public: MultiFile (); void open (const MultiFileSequence &sequence, uint framerate = 30); - void setRange(int begin, int end); - void setLoop (int on); + // dynamic change of gstreamer multifile source properties + void setProperties(int begin, int end, int loop); protected: GstElement *src_ ; @@ -57,17 +59,19 @@ public: inline uint framerate () const { return framerate_; } void setLoop (bool on); - inline bool loop () const { return sequence_.loop; } + inline bool loop () const { return loop_ > 0 ? true : false; } - void setRange (glm::ivec2 range); - glm::ivec2 range () const { return range_; } + void setRange (int begin, int end); + inline int begin() const { return begin_; } + inline int end () const { return end_; } MultiFile *multifile () const; private: MultiFileSequence sequence_; uint framerate_; - glm::ivec2 range_; + int begin_, end_, loop_; + }; diff --git a/SessionCreator.cpp b/SessionCreator.cpp index 083c5a6..513f1ee 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -897,12 +897,12 @@ void SessionLoader::visit (MultiFileSource& s) sequence.location = std::string ( seq->GetText() ); seq->QueryIntAttribute("min", &sequence.min); seq->QueryIntAttribute("max", &sequence.max); - seq->QueryIntAttribute("loop", &sequence.loop); seq->QueryUnsignedAttribute("width", &sequence.width); seq->QueryUnsignedAttribute("height", &sequence.height); const char *codec = seq->Attribute("codec"); if (codec) sequence.codec = std::string(codec); + uint fps = 0; seq->QueryUnsignedAttribute("fps", &fps); @@ -911,11 +911,21 @@ void SessionLoader::visit (MultiFileSource& s) s.setSequence( sequence, fps); } // same sequence, different framerate - else if ( fps != s.framerate() ) { + else if ( fps != s.framerate() ) { s.setFramerate( fps ); } + int begin = -1; + seq->QueryIntAttribute("begin", &begin); + int end = INT_MAX; + seq->QueryIntAttribute("end", &end); + if ( begin != s.begin() || end != s.end() ) + s.setRange(begin, end); + bool loop = true; + seq->QueryBoolAttribute("loop", &loop); + if ( loop != s.loop() ) + s.setLoop(loop); } } diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index 2361595..f593c5b 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -599,10 +599,14 @@ void SessionVisitor::visit (MultiFileSource& s) xmlCurrent_->SetAttribute("type", "MultiFileSource"); XMLElement *sequence = xmlDoc_->NewElement("Sequence"); + // play properties sequence->SetAttribute("fps", s.framerate()); + sequence->SetAttribute("begin", s.begin()); + sequence->SetAttribute("end", s.end()); + sequence->SetAttribute("loop", s.loop()); + // file sequence description sequence->SetAttribute("min", s.sequence().min); sequence->SetAttribute("max", s.sequence().max); - sequence->SetAttribute("loop", s.sequence().loop); sequence->SetAttribute("width", s.sequence().width); sequence->SetAttribute("height", s.sequence().height); sequence->SetAttribute("codec", s.sequence().codec.c_str()); @@ -610,18 +614,6 @@ void SessionVisitor::visit (MultiFileSource& s) sequence->InsertEndChild( location ); xmlCurrent_->InsertEndChild(sequence); - -// XMLElement *sequence = xmlDoc_->NewElement("Sequence"); -// sequence->SetAttribute("fps", s.fps()); - -// std::list list = s.sequence (); -// for (auto it = list.cbegin(); it != list.cend(); ++it) { -// XMLElement *f = xmlDoc_->NewElement("file"); -// XMLText *filename = xmlDoc_->NewText( it->c_str() ); -// f->InsertEndChild( filename ); -// sequence->InsertEndChild(f); -// } -// xmlCurrent_->InsertEndChild(sequence); } std::string SessionVisitor::getClipboard(const SourceList &list)