diff --git a/MediaPlayer.cpp b/MediaPlayer.cpp index cae6c96..2806553 100644 --- a/MediaPlayer.cpp +++ b/MediaPlayer.cpp @@ -520,7 +520,7 @@ void MediaPlayer::rewind() else { // end is the start of a gab which includes the last PTS (if exists) // normal case, end is last frame - execute_seek_command( media_.timeline.previous(media_.timeline.last())); + execute_seek_command( media_.timeline.previous(media_.timeline.last()) ); } } @@ -673,8 +673,12 @@ void MediaPlayer::update() // try to get info from discoverer if (discoverer_.wait_for( std::chrono::milliseconds(4) ) == std::future_status::ready ) { - // ok, discovering thread is finished ! Get the info + // remember loaded gaps + TimeIntervalSet gaps = media_.timeline.gaps(); + // ok, discovering thread is finished ! Get the media info media_ = discoverer_.get(); + // restore loaded gaps (overwriten above) + media_.timeline.setGaps( gaps ); // if its ok, open the media if (media_.valid) execute_open(); @@ -687,6 +691,13 @@ void MediaPlayer::update() if (!enabled_ || (media_.isimage && textureindex_>0 ) ) return; +// if (seeking_) { +// GstState state; +// gst_element_get_state (pipeline_, &state, NULL, GST_CLOCK_TIME_NONE); +// seeking_ = false; +// return; +// } + // local variables before trying to update guint read_index = 0; bool need_loop = false; @@ -744,35 +755,39 @@ void MediaPlayer::update() // unkock frame after reading it frame_[read_index].access.unlock(); + // if already seeking (asynch) if (seeking_) { + // request status update to pipeline (re-sync gst thread) GstState state; gst_element_get_state (pipeline_, &state, NULL, GST_CLOCK_TIME_NONE); + // seek should be resolved next frame seeking_ = false; + // do NOT do another seek yet } + // otherwise check for need to seek (pipeline management) + else { + // manage timeline: test if position falls into a gap + TimeInterval gap; + if (position_ != GST_CLOCK_TIME_NONE && media_.timeline.gapAt(position_, gap)) { + // if in a gap, seek to next section + if (gap.is_valid()) { + // jump in one or the other direction + GstClockTime jumpPts = (rate_>0.f) ? gap.end : gap.begin; + // seek to next valid time (if not beginnig or end of timeline) + if (jumpPts > media_.timeline.first() && jumpPts < media_.timeline.last()) + seek( jumpPts ); + // otherwise, we should loop + else + need_loop = true; + } - // manage timeline: test if position falls into a gap - TimeInterval gap; - if (position_ != GST_CLOCK_TIME_NONE && media_.timeline.gapAt(position_, gap)) { - // if in a gap, seek to next section - if (gap.is_valid()) { - // jump in one or the other direction - GstClockTime jumpPts = (rate_>0.f) ? gap.end : gap.begin; - // seek to next valid time (if not beginnig or end of timeline) - if (jumpPts > media_.timeline.first() && jumpPts < media_.timeline.last()) - seek( jumpPts); - // otherwise, we should loop - else - need_loop = true; } - + // manage loop mode + if (need_loop) { + execute_loop_command(); + } } - // manage loop mode - if (need_loop) { - execute_loop_command(); - } - - } void MediaPlayer::execute_loop_command() @@ -791,7 +806,7 @@ void MediaPlayer::execute_loop_command() void MediaPlayer::execute_seek_command(GstClockTime target) { - if ( pipeline_ == nullptr || !media_.seekable) + if ( pipeline_ == nullptr || !media_.seekable ) return; // seek position : default to target @@ -943,7 +958,8 @@ bool MediaPlayer::fill_frame(GstBuffer *buf, FrameStatus status) // set the start position (i.e. pts of first frame we got) if (media_.timeline.start() == GST_CLOCK_TIME_NONE) { media_.timeline.setFirst(buf->pts); - Log::Info("Timeline %ld [%ld %ld]", media_.timeline.numFrames(), media_.timeline.first(), media_.timeline.end()); + Log::Info("Timeline %ld [%ld %ld] %d gaps", media_.timeline.numFrames(), + media_.timeline.first(), media_.timeline.end(), media_.timeline.numGaps()); } } // full but invalid frame : will be deleted next iteration diff --git a/SessionCreator.cpp b/SessionCreator.cpp index 54d329f..22034bc 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -186,6 +186,7 @@ void SessionCreator::visit(MediaPlayer &n) // timeline XMLElement *gapselement = mediaplayerNode->FirstChildElement("Gaps"); if (gapselement) { + Timeline tl; XMLElement* gap = gapselement->FirstChildElement("Interval"); for( ; gap ; gap = gap->NextSiblingElement()) { @@ -193,8 +194,9 @@ void SessionCreator::visit(MediaPlayer &n) GstClockTime b = GST_CLOCK_TIME_NONE; gap->QueryUnsigned64Attribute("begin", &a); gap->QueryUnsigned64Attribute("end", &b); - n.timeline().addGap( a, b ); + tl.addGap( a, b ); } + n.setTimeline(tl); } // playing properties double speed = 1.0; diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index c1e2d19..1474dfa 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -149,11 +149,11 @@ void SessionVisitor::visit(MediaPlayer &n) // gaps in timeline XMLElement *gapselement = xmlDoc_->NewElement("Gaps"); - std::list< std::pair > gaps = n.timeline().gaps(); + TimeIntervalSet gaps = n.timeline().gaps(); for( auto it = gaps.begin(); it!= gaps.end(); it++) { XMLElement *g = xmlDoc_->NewElement("Interval"); - g->SetAttribute("begin", (*it).first); - g->SetAttribute("end", (*it).second); + g->SetAttribute("begin", (*it).begin); + g->SetAttribute("end", (*it).end); gapselement->InsertEndChild(g); } newelement->InsertEndChild(gapselement); diff --git a/Timeline.cpp b/Timeline.cpp index e1d9d16..b722be4 100644 --- a/Timeline.cpp +++ b/Timeline.cpp @@ -142,11 +142,6 @@ void Timeline::fillArrayFromGaps(float *array_, size_t array_size_) } } -size_t Timeline::numGaps() -{ - return gaps_.size(); -} - bool Timeline::gapAt(const GstClockTime t, TimeInterval &gap) const { TimeIntervalSet::const_iterator g = std::find_if(gaps_.begin(), gaps_.end(), includesTime(t)); @@ -172,6 +167,11 @@ bool Timeline::addGap(TimeInterval s) return false; } +void Timeline::setGaps(TimeIntervalSet g) +{ + gaps_ = g; +} + //void Timeline::toggleGaps(GstClockTime from, GstClockTime to) //{ // TimeInterval interval(from, to); @@ -221,12 +221,4 @@ void Timeline::clearGaps() gaps_.clear(); } -std::list< std::pair > Timeline::gaps() const -{ - std::list< std::pair > ret; - for (TimeIntervalSet::iterator it = gaps_.begin(); it != gaps_.end(); it++) - ret.push_back( std::make_pair( it->begin, it->end ) ); - - return ret; -} diff --git a/Timeline.h b/Timeline.h index 3d35a0c..45884fc 100644 --- a/Timeline.h +++ b/Timeline.h @@ -98,21 +98,19 @@ public: inline GstClockTime step() const { return step_; } inline GstClockTime duration() const { return timing_.duration(); } inline size_t numFrames() const { return duration() / step_; } + inline TimeIntervalSet gaps() const { return gaps_; } + inline size_t numGaps() const { return gaps_.size(); } GstClockTime next(GstClockTime time) const; GstClockTime previous(GstClockTime time) const; - // Add / remove gaps in the timeline + // Add / remove / get gaps in the timeline + void clearGaps(); bool addGap(TimeInterval s); bool addGap(GstClockTime begin, GstClockTime end); bool removeGaptAt(GstClockTime t); - void clearGaps(); -// void toggleGaps(GstClockTime from, GstClockTime to); - - // get gaps - size_t numGaps(); bool gapAt(const GstClockTime t, TimeInterval &gap) const; - std::list< std::pair > gaps() const; + void setGaps(TimeIntervalSet g); // synchronize data structures void updateGapsFromArray(float *array_, size_t array_size_);