From 51ebca3c0363210da2d51e350bfcadf858fa855a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 2 Mar 2015 15:02:20 +0100 Subject: [PATCH] vp{8,9}enc: Tell the encoder about actual timestamps and durations of frames ... instead of just counting frames. The values are supposed to be in timebase units, not frame units. This fixes various quality problems with VP8/VP9 encoding and in general makes the encoder behave better. Thanks to Nirbheek Chauhan for noticing this bug. --- ext/vpx/gstvp8enc.c | 43 +++++++++++++++++++++++++++++++++++-------- ext/vpx/gstvp8enc.h | 2 +- ext/vpx/gstvp9enc.c | 43 +++++++++++++++++++++++++++++++++++-------- ext/vpx/gstvp9enc.h | 3 +-- 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/ext/vpx/gstvp8enc.c b/ext/vpx/gstvp8enc.c index 083c5902f1..7513943a66 100644 --- a/ext/vpx/gstvp8enc.c +++ b/ext/vpx/gstvp8enc.c @@ -805,7 +805,6 @@ gst_vp8_enc_finalize (GObject * object) g_mutex_clear (&gst_vp8_enc->encoder_lock); G_OBJECT_CLASS (parent_class)->finalize (object); - } static void @@ -1877,15 +1876,19 @@ gst_vp8_enc_drain (GstVideoEncoder * video_encoder) int flags = 0; vpx_codec_err_t status; gint64 deadline; + vpx_codec_pts_t pts; encoder = GST_VP8_ENC (video_encoder); g_mutex_lock (&encoder->encoder_lock); deadline = encoder->deadline; - status = - vpx_codec_encode (&encoder->encoder, NULL, encoder->n_frames, 1, flags, - deadline); + pts = + gst_util_uint64_scale (encoder->last_pts, + encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND, + encoder->cfg.g_timebase.den); + + status = vpx_codec_encode (&encoder->encoder, NULL, pts, 1, flags, deadline); g_mutex_unlock (&encoder->encoder_lock); if (status != 0) { @@ -1917,11 +1920,18 @@ gst_vp8_enc_drain (GstVideoEncoder * video_encoder) static GstFlowReturn gst_vp8_enc_finish (GstVideoEncoder * video_encoder) { + GstVP8Enc *encoder; GstFlowReturn ret; GST_DEBUG_OBJECT (video_encoder, "finish"); - ret = gst_vp8_enc_drain (video_encoder); + encoder = GST_VP8_ENC (video_encoder); + + if (encoder->inited) { + ret = gst_vp8_enc_drain (video_encoder); + } else { + ret = GST_FLOW_OK; + } return ret; } @@ -1954,13 +1964,13 @@ gst_vp8_enc_handle_frame (GstVideoEncoder * video_encoder, vpx_image_t *image; GstVP8EncUserData *user_data; GstVideoFrame vframe; + vpx_codec_pts_t pts; + unsigned long duration; GST_DEBUG_OBJECT (video_encoder, "handle_frame"); encoder = GST_VP8_ENC (video_encoder); - encoder->n_frames++; - GST_DEBUG_OBJECT (video_encoder, "size %d %d", GST_VIDEO_INFO_WIDTH (&encoder->input_state->info), GST_VIDEO_INFO_HEIGHT (&encoder->input_state->info)); @@ -1979,8 +1989,25 @@ gst_vp8_enc_handle_frame (GstVideoEncoder * video_encoder, } g_mutex_lock (&encoder->encoder_lock); + pts = + gst_util_uint64_scale (frame->pts, + encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND, + encoder->cfg.g_timebase.den); + encoder->last_pts = frame->pts; + + if (frame->duration != GST_CLOCK_TIME_NONE) { + duration = + gst_util_uint64_scale (frame->duration, + encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND, + encoder->cfg.g_timebase.den); + encoder->last_pts += frame->duration; + } else { + duration = 1; + } + status = vpx_codec_encode (&encoder->encoder, image, - encoder->n_frames, 1, flags, encoder->deadline); + pts, duration, flags, encoder->deadline); + g_mutex_unlock (&encoder->encoder_lock); gst_video_frame_unmap (&vframe); diff --git a/ext/vpx/gstvp8enc.h b/ext/vpx/gstvp8enc.h index 206ac02a47..d70f383a38 100644 --- a/ext/vpx/gstvp8enc.h +++ b/ext/vpx/gstvp8enc.h @@ -102,7 +102,7 @@ struct _GstVP8Enc vpx_image_t image; - int n_frames; + GstClockTime last_pts; int keyframe_distance; GstVideoCodecState *input_state; diff --git a/ext/vpx/gstvp9enc.c b/ext/vpx/gstvp9enc.c index 7a18e6102e..2f88984a97 100644 --- a/ext/vpx/gstvp9enc.c +++ b/ext/vpx/gstvp9enc.c @@ -780,7 +780,6 @@ gst_vp9_enc_finalize (GObject * object) g_mutex_clear (&gst_vp9_enc->encoder_lock); G_OBJECT_CLASS (parent_class)->finalize (object); - } static void @@ -1816,15 +1815,19 @@ gst_vp9_enc_drain (GstVideoEncoder * video_encoder) int flags = 0; vpx_codec_err_t status; gint64 deadline; + vpx_codec_pts_t pts; encoder = GST_VP9_ENC (video_encoder); g_mutex_lock (&encoder->encoder_lock); deadline = encoder->deadline; - status = - vpx_codec_encode (&encoder->encoder, NULL, encoder->n_frames, 1, flags, - deadline); + pts = + gst_util_uint64_scale (encoder->last_pts, + encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND, + encoder->cfg.g_timebase.den); + + status = vpx_codec_encode (&encoder->encoder, NULL, pts, 0, flags, deadline); g_mutex_unlock (&encoder->encoder_lock); if (status != 0) { @@ -1856,11 +1859,18 @@ gst_vp9_enc_drain (GstVideoEncoder * video_encoder) static GstFlowReturn gst_vp9_enc_finish (GstVideoEncoder * video_encoder) { + GstVP9Enc *encoder; GstFlowReturn ret; GST_DEBUG_OBJECT (video_encoder, "finish"); - ret = gst_vp9_enc_drain (video_encoder); + encoder = GST_VP9_ENC (video_encoder); + + if (encoder->inited) { + ret = gst_vp9_enc_drain (video_encoder); + } else { + ret = GST_FLOW_OK; + } return ret; } @@ -1892,13 +1902,13 @@ gst_vp9_enc_handle_frame (GstVideoEncoder * video_encoder, int flags = 0; vpx_image_t *image; GstVideoFrame vframe; + vpx_codec_pts_t pts; + unsigned long duration; GST_DEBUG_OBJECT (video_encoder, "handle_frame"); encoder = GST_VP9_ENC (video_encoder); - encoder->n_frames++; - GST_DEBUG_OBJECT (video_encoder, "size %d %d", GST_VIDEO_INFO_WIDTH (&encoder->input_state->info), GST_VIDEO_INFO_HEIGHT (&encoder->input_state->info)); @@ -1912,8 +1922,25 @@ gst_vp9_enc_handle_frame (GstVideoEncoder * video_encoder, } g_mutex_lock (&encoder->encoder_lock); + pts = + gst_util_uint64_scale (frame->pts, + encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND, + encoder->cfg.g_timebase.den); + encoder->last_pts = frame->pts; + + if (frame->duration != GST_CLOCK_TIME_NONE) { + duration = + gst_util_uint64_scale (frame->duration, + encoder->cfg.g_timebase.num * (GstClockTime) GST_SECOND, + encoder->cfg.g_timebase.den); + encoder->last_pts += frame->duration; + } else { + duration = 1; + } + status = vpx_codec_encode (&encoder->encoder, image, - encoder->n_frames, 1, flags, encoder->deadline); + pts, duration, flags, encoder->deadline); + g_mutex_unlock (&encoder->encoder_lock); gst_video_frame_unmap (&vframe); diff --git a/ext/vpx/gstvp9enc.h b/ext/vpx/gstvp9enc.h index b991905796..7851f1a32e 100644 --- a/ext/vpx/gstvp9enc.h +++ b/ext/vpx/gstvp9enc.h @@ -102,8 +102,7 @@ struct _GstVP9Enc vpx_image_t image; - int n_frames; - + GstClockTime last_pts; GstVideoCodecState *input_state; };