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_;