summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2023-01-13 12:43:30 +0200
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>2023-01-13 17:18:38 +0000
commit79e8d2c03e70488b9ae2c72739df6da819c6bd1d (patch)
treef547751fe166a96c10dfc7f9a702837c638d25ec
parent13ad8c8e4e2101c5a50c9e9232187b3ebf29f04d (diff)
downloadgstreamer-79e8d2c03e70488b9ae2c72739df6da819c6bd1d.tar.gz
avvidenc: Offset PTS to zero to fix bitrate control
Otherwise ffmpeg's rate control algorithm will not work correctly as it is based on the absolute PTS values. Fixes https://gitlab.freedesktop.org/gstreamer/gst-libav/-/issues/91 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3718>
-rw-r--r--subprojects/gst-libav/ext/libav/gstavvidenc.c37
-rw-r--r--subprojects/gst-libav/ext/libav/gstavvidenc.h1
2 files changed, 30 insertions, 8 deletions
diff --git a/subprojects/gst-libav/ext/libav/gstavvidenc.c b/subprojects/gst-libav/ext/libav/gstavvidenc.c
index d08e39644d..9659d694d4 100644
--- a/subprojects/gst-libav/ext/libav/gstavvidenc.c
+++ b/subprojects/gst-libav/ext/libav/gstavvidenc.c
@@ -399,6 +399,7 @@ gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
}
/* success! */
+ ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
ffmpegenc->opened = TRUE;
return TRUE;
@@ -618,9 +619,20 @@ gst_ffmpegvidenc_send_frame (GstFFMpegVidEnc * ffmpegenc,
picture->width = GST_VIDEO_FRAME_WIDTH (&buffer_info->vframe);
picture->height = GST_VIDEO_FRAME_HEIGHT (&buffer_info->vframe);
- picture->pts =
- gst_ffmpeg_time_gst_to_ff (frame->pts /
- ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base);
+ if (ffmpegenc->pts_offset == GST_CLOCK_TIME_NONE) {
+ ffmpegenc->pts_offset = frame->pts;
+ }
+
+ if (frame->pts == GST_CLOCK_TIME_NONE) {
+ picture->pts = AV_NOPTS_VALUE;
+ } else if (frame->pts < ffmpegenc->pts_offset) {
+ GST_ERROR_OBJECT (ffmpegenc, "PTS is going backwards");
+ picture->pts = AV_NOPTS_VALUE;
+ } else {
+ picture->pts =
+ gst_ffmpeg_time_gst_to_ff ((frame->pts - ffmpegenc->pts_offset) /
+ ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base);
+ }
send_frame:
if (!picture) {
@@ -703,14 +715,20 @@ gst_ffmpegvidenc_receive_packet (GstFFMpegVidEnc * ffmpegenc,
GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
}
- frame->dts =
- gst_ffmpeg_time_ff_to_gst (pkt->dts, ffmpegenc->context->time_base);
+ if (pkt->dts != AV_NOPTS_VALUE) {
+ frame->dts =
+ gst_ffmpeg_time_ff_to_gst (pkt->dts + ffmpegenc->pts_offset,
+ ffmpegenc->context->time_base);
+ }
/* This will lose some precision compared to setting the PTS from the input
* buffer directly, but that way we're sure PTS and DTS are consistent, in
* particular DTS should always be <= PTS
*/
- frame->pts =
- gst_ffmpeg_time_ff_to_gst (pkt->pts, ffmpegenc->context->time_base);
+ if (pkt->pts != AV_NOPTS_VALUE) {
+ frame->pts =
+ gst_ffmpeg_time_ff_to_gst (pkt->pts + ffmpegenc->pts_offset,
+ ffmpegenc->context->time_base);
+ }
ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
@@ -804,6 +822,7 @@ gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
break;
} while (got_packet);
avcodec_flush_buffers (ffmpegenc->context);
+ ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
done:
/* FFMpeg will return AVERROR_EOF if it's internal was fully drained
@@ -879,8 +898,10 @@ gst_ffmpegvidenc_flush (GstVideoEncoder * encoder)
{
GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
- if (ffmpegenc->opened)
+ if (ffmpegenc->opened) {
avcodec_flush_buffers (ffmpegenc->context);
+ ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
+ }
return TRUE;
}
diff --git a/subprojects/gst-libav/ext/libav/gstavvidenc.h b/subprojects/gst-libav/ext/libav/gstavvidenc.h
index 2d0b7c8b6b..340fb25204 100644
--- a/subprojects/gst-libav/ext/libav/gstavvidenc.h
+++ b/subprojects/gst-libav/ext/libav/gstavvidenc.h
@@ -40,6 +40,7 @@ struct _GstFFMpegVidEnc
AVCodecContext *context;
AVFrame *picture;
+ GstClockTime pts_offset;
gboolean opened;
gboolean need_reopen;
gboolean discont;