@@ -285,6 +285,8 @@ bool Decoder::init(
285
285
return false ;
286
286
}
287
287
288
+ avioCtx_->max_packet_size = params.maxEncodedBufferSize ;
289
+
288
290
inputCtx_->pb = avioCtx_;
289
291
inputCtx_->flags |= AVFMT_FLAG_CUSTOM_IO;
290
292
}
@@ -382,7 +384,30 @@ bool Decoder::init(
382
384
av_seek_frame (inputCtx_, -1 , offset, AVSEEK_FLAG_BACKWARD);
383
385
}
384
386
387
+ for (unsigned int i = 0 ; i < inputCtx_->nb_streams ; i++) {
388
+ if (
389
+ #if LIBAVUTIL_VERSION_MAJOR < 56 // Before FFMPEG 4.0
390
+ inputCtx_->streams [i]->codec ->codec_type == AVMEDIA_TYPE_VIDEO
391
+ #else // FFMPEG 4.0+
392
+ inputCtx_->streams [i]->codecpar ->codec_type == AVMEDIA_TYPE_VIDEO
393
+ #endif
394
+ && inputCtx_->streams [i]->duration > 0 ) {
395
+ // There is at least two 1/r_frame_rates from the frame before the last
396
+ // one until the video duration, let's prefer to set duration after the
397
+ // frame before the last one, but as early as possible
398
+ double correction = 2 * inputCtx_->streams [i]->r_frame_rate .den /
399
+ (double )inputCtx_->streams [i]->r_frame_rate .num -
400
+ 1 / (double )AV_TIME_BASE;
401
+ videoDurationMs_ = 1000 * inputCtx_->streams [i]->duration *
402
+ inputCtx_->streams [i]->time_base .num /
403
+ (double )inputCtx_->streams [i]->time_base .den -
404
+ 1000 * correction;
405
+ break ;
406
+ }
407
+ }
408
+
385
409
VLOG (1 ) << " Decoder initialized, log level: " << params_.logLevel ;
410
+ VLOG (1 ) << " Video duration: " << videoDurationMs_;
386
411
return true ;
387
412
}
388
413
@@ -590,13 +615,30 @@ int Decoder::getFrame(size_t workingTimeInMs) {
590
615
result = 0 ;
591
616
592
617
av_packet_unref (avPacket);
618
+
619
+ if (params_.uniformSampling > 1 ) {
620
+ if (doSeek_) {
621
+ double duration =
622
+ videoDurationMs_ > 0 ? videoDurationMs_ : params_.expectedDuration ;
623
+ double step =
624
+ (duration * AV_TIME_BASE) / (1000 * (params_.uniformSampling - 1 ));
625
+ avformat_seek_file (
626
+ inputCtx_,
627
+ -1 ,
628
+ static_cast <int64_t >(step * kFramesDecoded_ ) + 1 ,
629
+ static_cast <int64_t >(step * (kFramesDecoded_ + 1 )),
630
+ static_cast <int64_t >(step * (kFramesDecoded_ + 1 )),
631
+ 0 );
632
+ ++kFramesDecoded_ ;
633
+ doSeek_ = false ;
634
+ }
635
+ }
593
636
}
594
637
595
638
av_packet_free (&avPacket);
596
- VLOG (2 ) << " Interrupted loop"
597
- << " , interrupted_ " << interrupted_ << " , inRange_.any() "
598
- << inRange_.any () << " , decodedFrame " << decodedFrame << " , result "
599
- << result;
639
+ VLOG (2 ) << " Interrupted loop" << " , interrupted_ " << interrupted_
640
+ << " , inRange_.any() " << inRange_.any () << " , decodedFrame "
641
+ << decodedFrame << " , result " << result;
600
642
601
643
// loop can be terminated, either by:
602
644
// 1. explicitly interrupted
@@ -660,13 +702,35 @@ int Decoder::processPacket(
660
702
startCondition = msg.header .pts >= params_.startOffset ;
661
703
}
662
704
if (endInRange && startCondition) {
663
- *hasMsg = true ;
664
- push (std::move (msg));
705
+ *hasMsg = pushMsg (std::move (msg));
665
706
}
666
707
}
667
708
return result;
668
709
}
669
710
711
+ bool Decoder::pushMsg (DecoderOutputMessage&& msg) {
712
+ pastDecodedPTS_ = currentDecodedPTS_;
713
+ currentDecodedPTS_ = msg.header .pts ;
714
+
715
+ if (params_.uniformSampling <= 1 ) {
716
+ push (std::move (msg));
717
+ return true ;
718
+ }
719
+
720
+ double duration =
721
+ videoDurationMs_ > 0 ? videoDurationMs_ : params_.expectedDuration ;
722
+ double step =
723
+ (duration * AV_TIME_BASE) / (1000 * (params_.uniformSampling - 1 ));
724
+ if (pastDecodedPTS_ < step * kFramesDecoded_ &&
725
+ step * kFramesDecoded_ <= currentDecodedPTS_) {
726
+ push (std::move (msg));
727
+ doSeek_ = true ;
728
+ return true ;
729
+ }
730
+
731
+ return false ;
732
+ }
733
+
670
734
void Decoder::flushStreams () {
671
735
VLOG (1 ) << " Flushing streams..." ;
672
736
for (auto & stream : streams_) {
@@ -678,7 +742,7 @@ void Decoder::flushStreams() {
678
742
params_.endOffset <= 0 || msg.header .pts <= params_.endOffset ;
679
743
inRange_.set (stream.second ->getIndex (), endInRange);
680
744
if (endInRange && msg.header .pts >= params_.startOffset ) {
681
- push (std::move (msg));
745
+ pushMsg (std::move (msg));
682
746
} else {
683
747
msg.payload .reset ();
684
748
}
0 commit comments