diff --git a/video/ffmpeg_encode.cpp b/video/ffmpeg_encode.cpp index c7444e0a..1d2db726 100644 --- a/video/ffmpeg_encode.cpp +++ b/video/ffmpeg_encode.cpp @@ -489,6 +489,8 @@ bool VideoEncoder::Impl::encode_frame(const uint8_t *buffer, const PlaneLayout * memcpy(dst_chroma, src_chroma, chroma_width); } + video.av_frame->pict_type = AV_PICTURE_TYPE_NONE; + if (options.realtime) { int64_t target_pts = av_rescale_q_rnd(pts, {1, AV_TIME_BASE}, video.av_ctx->time_base, AV_ROUND_ZERO); @@ -527,6 +529,12 @@ bool VideoEncoder::Impl::encode_frame(const uint8_t *buffer, const PlaneLayout * else video.av_frame->pts = encode_video_pts++; + // When new stream clients come in we need to force IDR frames. + // This is not necessary for x264 apparently, but NVENC does ... + // Callback is responsible for controlling how often an IDR should be sent. + if (mux_stream_callback && mux_stream_callback->should_force_idr()) + video.av_frame->pict_type = AV_PICTURE_TYPE_I; + AVFrame *hw_frame = nullptr; if (hw.get_hw_device_type() != AV_HWDEVICE_TYPE_NONE) { @@ -544,6 +552,7 @@ bool VideoEncoder::Impl::encode_frame(const uint8_t *buffer, const PlaneLayout * } hw_frame->pts = video.av_frame->pts; + hw_frame->pict_type = video.av_frame->pict_type; } ret = avcodec_send_frame(video.av_ctx, hw_frame ? hw_frame : video.av_frame); @@ -631,7 +640,6 @@ bool VideoEncoder::Impl::drain_packets(CodecStream &stream) { if (&stream == &video) { - // Avoid negative values in the beginning by biasing. mux_stream_callback->write_video_packet( stream.av_pkt->pts, stream.av_pkt->dts, @@ -962,6 +970,12 @@ bool VideoEncoder::Impl::init_video_codec() if (options.low_latency) av_dict_set_int(&opts, "zerolatency", 1, 0); } + + if ((is_x264 || is_nvenc) && options.low_latency) + { + av_dict_set_int(&opts, "intra-refresh", 1, 0); + av_dict_set_int(&opts, "forced-idr", 1, 0); + } } else { diff --git a/video/ffmpeg_encode.hpp b/video/ffmpeg_encode.hpp index a86fd453..1139616b 100644 --- a/video/ffmpeg_encode.hpp +++ b/video/ffmpeg_encode.hpp @@ -42,6 +42,7 @@ class MuxStreamCallback virtual void set_codec_parameters(const pyro_codec_parameters &codec) = 0; virtual void write_video_packet(int64_t pts, int64_t dts, const void *data, size_t size, bool is_key_frame) = 0; virtual void write_audio_packet(int64_t pts, int64_t dts, const void *data, size_t size) = 0; + virtual bool should_force_idr() = 0; }; class VideoEncoder diff --git a/video/pyro_protocol.h b/video/pyro_protocol.h index 7085feac..edb1e385 100644 --- a/video/pyro_protocol.h +++ b/video/pyro_protocol.h @@ -48,6 +48,7 @@ struct pyro_progress_report { uint64_t total_received_packets; uint64_t total_dropped_packets; + uint64_t total_received_key_frames; }; #define PYRO_MAX_UDP_DATAGRAM_SIZE (PYRO_MAX_PAYLOAD_SIZE + sizeof(struct pyro_codec_parameters))