vp{8,9}enc: Tell the encoder about actual timestamps and durations of frames
authorSebastian Dröge <sebastian@centricular.com>
Mon, 2 Mar 2015 14:02:20 +0000 (15:02 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Mon, 2 Mar 2015 14:03:49 +0000 (15:03 +0100)
... 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
ext/vpx/gstvp8enc.h
ext/vpx/gstvp9enc.c
ext/vpx/gstvp9enc.h

index 083c590..7513943 100644 (file)
@@ -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);
 
index 206ac02..d70f383 100644 (file)
@@ -102,7 +102,7 @@ struct _GstVP8Enc
 
   vpx_image_t image;
 
-  int n_frames;
+  GstClockTime last_pts;
   int keyframe_distance;
 
   GstVideoCodecState *input_state;
index 7a18e61..2f88984 100644 (file)
@@ -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);
 
index b991905..7851f1a 100644 (file)
@@ -102,8 +102,7 @@ struct _GstVP9Enc
 
   vpx_image_t image;
 
-  int n_frames;
-
+  GstClockTime last_pts;
   GstVideoCodecState *input_state;
 };