diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp index 18f287e97a809061296a2b03efd02ac2af657cd1..894f4bde6d3c19c34f58ec53fc3130a6d8ed506b 100644 --- a/src/media/media_decoder.cpp +++ b/src/media/media_decoder.cpp @@ -325,6 +325,19 @@ MediaDemuxer::decode() int ret = av_read_frame(inputCtx_, packet.get()); if (ret == AVERROR(EAGAIN)) { + /*no data available. Calculate time until next frame. + We do not use the emulated frame mechanism from the decoder because it will affect all platforms. + With the current implementation, the demuxer will be waiting just in case when av_read_frame + returns EAGAIN. For some platforms, av_read_frame is blocking and it will never happen. + */ + if (inputParams_.framerate.numerator() == 0) + return Status::Success; + rational<double> frameTime = 1e6/inputParams_.framerate; + int64_t timeToSleep = lastReadPacketTime_ - av_gettime_relative() + frameTime.real<int64_t>(); + if (timeToSleep <= 0) { + return Status::Success; + } + std::this_thread::sleep_for(std::chrono::microseconds(timeToSleep)); return Status::Success; } else if (ret == AVERROR_EOF) { return Status::EndOfFile; @@ -338,6 +351,8 @@ MediaDemuxer::decode() return Status::Success; } + lastReadPacketTime_ = av_gettime_relative(); + auto& cb = streams_[streamIndex]; if (cb) { DecodeStatus ret = cb(*packet.get()); diff --git a/src/media/media_decoder.h b/src/media/media_decoder.h index 917e54ab7a5678f9f5e91ebc235ab2a097ea7e21..826a9ab10bc7981b84fa64116c6fca957227ff45 100644 --- a/src/media/media_decoder.h +++ b/src/media/media_decoder.h @@ -131,6 +131,7 @@ private: AVFormatContext* inputCtx_ = nullptr; std::vector<StreamCallback> streams_; int64_t startTime_; + int64_t lastReadPacketTime_ {}; DeviceParams inputParams_; AVDictionary* options_ = nullptr; MediaDemuxer::CurrentState currentState_;