mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-27 01:28:34 +00:00
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/3727>
This commit is contained in:
parent
af97e98315
commit
2c503a8d7d
2 changed files with 30 additions and 8 deletions
|
@ -398,6 +398,7 @@ gst_ffmpegvidenc_set_format (GstVideoEncoder * encoder,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* success! */
|
/* success! */
|
||||||
|
ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
|
||||||
ffmpegenc->opened = TRUE;
|
ffmpegenc->opened = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -617,9 +618,20 @@ gst_ffmpegvidenc_send_frame (GstFFMpegVidEnc * ffmpegenc,
|
||||||
picture->width = GST_VIDEO_FRAME_WIDTH (&buffer_info->vframe);
|
picture->width = GST_VIDEO_FRAME_WIDTH (&buffer_info->vframe);
|
||||||
picture->height = GST_VIDEO_FRAME_HEIGHT (&buffer_info->vframe);
|
picture->height = GST_VIDEO_FRAME_HEIGHT (&buffer_info->vframe);
|
||||||
|
|
||||||
picture->pts =
|
if (ffmpegenc->pts_offset == GST_CLOCK_TIME_NONE) {
|
||||||
gst_ffmpeg_time_gst_to_ff (frame->pts /
|
ffmpegenc->pts_offset = frame->pts;
|
||||||
ffmpegenc->context->ticks_per_frame, ffmpegenc->context->time_base);
|
}
|
||||||
|
|
||||||
|
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:
|
send_frame:
|
||||||
if (!picture) {
|
if (!picture) {
|
||||||
|
@ -701,14 +713,20 @@ gst_ffmpegvidenc_receive_packet (GstFFMpegVidEnc * ffmpegenc,
|
||||||
GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
|
GST_VIDEO_CODEC_FRAME_UNSET_SYNC_POINT (frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->dts =
|
if (pkt->dts != AV_NOPTS_VALUE) {
|
||||||
gst_ffmpeg_time_ff_to_gst (pkt->dts, ffmpegenc->context->time_base);
|
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
|
/* 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
|
* buffer directly, but that way we're sure PTS and DTS are consistent, in
|
||||||
* particular DTS should always be <= PTS
|
* particular DTS should always be <= PTS
|
||||||
*/
|
*/
|
||||||
frame->pts =
|
if (pkt->pts != AV_NOPTS_VALUE) {
|
||||||
gst_ffmpeg_time_ff_to_gst (pkt->pts, ffmpegenc->context->time_base);
|
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);
|
ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (ffmpegenc), frame);
|
||||||
|
|
||||||
|
@ -802,6 +820,7 @@ gst_ffmpegvidenc_flush_buffers (GstFFMpegVidEnc * ffmpegenc, gboolean send)
|
||||||
break;
|
break;
|
||||||
} while (got_packet);
|
} while (got_packet);
|
||||||
avcodec_flush_buffers (ffmpegenc->context);
|
avcodec_flush_buffers (ffmpegenc->context);
|
||||||
|
ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* FFMpeg will return AVERROR_EOF if it's internal was fully drained
|
/* FFMpeg will return AVERROR_EOF if it's internal was fully drained
|
||||||
|
@ -877,8 +896,10 @@ gst_ffmpegvidenc_flush (GstVideoEncoder * encoder)
|
||||||
{
|
{
|
||||||
GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
|
GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) encoder;
|
||||||
|
|
||||||
if (ffmpegenc->opened)
|
if (ffmpegenc->opened) {
|
||||||
avcodec_flush_buffers (ffmpegenc->context);
|
avcodec_flush_buffers (ffmpegenc->context);
|
||||||
|
ffmpegenc->pts_offset = GST_CLOCK_TIME_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ struct _GstFFMpegVidEnc
|
||||||
|
|
||||||
AVCodecContext *context;
|
AVCodecContext *context;
|
||||||
AVFrame *picture;
|
AVFrame *picture;
|
||||||
|
GstClockTime pts_offset;
|
||||||
gboolean opened;
|
gboolean opened;
|
||||||
gboolean need_reopen;
|
gboolean need_reopen;
|
||||||
gboolean discont;
|
gboolean discont;
|
||||||
|
|
Loading…
Reference in a new issue