@@ -21,6 +21,7 @@ public unsafe class VideoStreamDecoder : Disposable
2121 protected readonly AVFormatContext * FormatContext ;
2222 protected readonly Frame Frame ;
2323 protected readonly AVPacket * Packet ;
24+ protected readonly AVStream * Stream ;
2425 protected readonly int StreamIndex ;
2526
2627 public readonly string CodecName ;
@@ -43,9 +44,10 @@ public VideoStreamDecoder(string url, AVInputFormat* inputFormat = null)
4344 StreamIndex = ffmpeg
4445 . av_find_best_stream ( formatContext , AVMediaType . AVMEDIA_TYPE_VIDEO , - 1 , - 1 , & codec , 0 )
4546 . ThrowExceptionIfError ( ) ;
47+ Stream = formatContext ->streams [ StreamIndex ] ;
4648 CodecContext = ffmpeg . avcodec_alloc_context3 ( codec ) ;
4749
48- ffmpeg . avcodec_parameters_to_context ( CodecContext , formatContext -> streams [ StreamIndex ] ->codecpar )
50+ ffmpeg . avcodec_parameters_to_context ( CodecContext , Stream ->codecpar )
4951 . ThrowExceptionIfError ( ) ;
5052 ffmpeg . avcodec_open2 ( CodecContext , codec , null ) . ThrowExceptionIfError ( ) ;
5153
@@ -58,6 +60,13 @@ public VideoStreamDecoder(string url, AVInputFormat* inputFormat = null)
5860 Frame = new Frame ( ) ;
5961 }
6062
63+ /// <summary>
64+ /// Trigger field, used to decide whether we wait longer during a Thread.Sleep()
65+ /// when there are no frames available.
66+ /// </summary>
67+ /// <remarks>
68+ /// Waiting longer would mean a full frame interval (for example ~16ms when 60 fps), 1ms otherwise.
69+ private bool waitLonger = false ;
6170 public DecodeStatus TryDecodeNextFrame ( out Frame nextFrame )
6271 {
6372 int eagain = ffmpeg . AVERROR ( ffmpeg . EAGAIN ) ;
@@ -74,8 +83,13 @@ public DecodeStatus TryDecodeNextFrame(out Frame nextFrame)
7483 {
7584 nextFrame = Frame ;
7685 GC . Collect ( ) ;
77- Thread . Sleep ( 1 ) ;
7886
87+ // Big brain move to avoid overloading the CPU \o/
88+ AVRational fps = Stream ->r_frame_rate ;
89+ Thread . Sleep ( waitLonger ? 1000 * fps . den / ( fps . num + 5 ) : 1 ) ;
90+
91+ // We only wait longer once to make sure we catch the frame on time.
92+ waitLonger = false ;
7993 return error == eagain
8094 ? DecodeStatus . NoFrameAvailable
8195 : DecodeStatus . EndOfStream ;
@@ -98,6 +112,8 @@ public DecodeStatus TryDecodeNextFrame(out Frame nextFrame)
98112 error . ThrowExceptionIfError ( ) ;
99113
100114 nextFrame = Frame ;
115+ // Always wait longer just after receiving a new frame.
116+ waitLonger = true ;
101117 GC . Collect ( ) ;
102118 return DecodeStatus . NewFrame ;
103119 }
0 commit comments