vabaseenc: Enable encoder reconfiguration.
authorVíctor Manuel Jáquez Leal <vjaquez@igalia.com>
Thu, 20 Oct 2022 09:13:19 +0000 (11:13 +0200)
committerVíctor Manuel Jáquez Leal <vjaquez@igalia.com>
Wed, 9 Nov 2022 05:13:26 +0000 (06:13 +0100)
Adds an internal function reset() which drains the internal queues and
calls the reconfig() vmethod.

This reset() method is called inconditionally at set_format() and in
handle_frame() if the instance's reconf flag is enabled.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2466>

subprojects/gst-plugins-bad/sys/va/gstvabaseenc.c
subprojects/gst-plugins-bad/sys/va/gstvabaseenc.h

index 625b965..ba7003d 100644 (file)
@@ -68,6 +68,7 @@ gst_va_base_enc_reset_state_default (GstVaBaseEnc * base)
   base->profile = VAProfileNone;
   base->rt_format = 0;
   base->codedbuf_size = 0;
+  g_atomic_int_set (&base->reconf, FALSE);
 }
 
 static void
@@ -508,6 +509,112 @@ _push_out_one_buffer (GstVaBaseEnc * base)
 }
 
 static GstFlowReturn
+gst_va_base_enc_drain (GstVideoEncoder * venc)
+{
+  GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
+  GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstVideoCodecFrame *frame_enc = NULL;
+  gboolean is_last = FALSE;
+
+  GST_DEBUG_OBJECT (base, "Encoder is draining");
+
+  /* Kickout all cached frames */
+  if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
+    ret = GST_FLOW_ERROR;
+    goto error_and_purge_all;
+  }
+
+  while (frame_enc) {
+    is_last = FALSE;
+
+    if (g_queue_is_empty (&base->reorder_list))
+      is_last = TRUE;
+
+    ret = base_class->encode_frame (base, frame_enc, is_last);
+    if (ret != GST_FLOW_OK)
+      goto error_and_purge_all;
+
+    frame_enc = NULL;
+
+    ret = _push_out_one_buffer (base);
+    if (ret != GST_FLOW_OK)
+      goto error_and_purge_all;
+
+    if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
+      ret = GST_FLOW_ERROR;
+      goto error_and_purge_all;
+    }
+  }
+
+  g_assert (g_queue_is_empty (&base->reorder_list));
+
+  /* Output all frames. */
+  while (!g_queue_is_empty (&base->output_list)) {
+    ret = _push_out_one_buffer (base);
+    if (ret != GST_FLOW_OK)
+      goto error_and_purge_all;
+  }
+
+  /* Also clear the reference list. */
+  g_queue_clear_full (&base->ref_list,
+      (GDestroyNotify) gst_video_codec_frame_unref);
+
+  return GST_FLOW_OK;
+
+error_and_purge_all:
+  if (frame_enc) {
+    gst_clear_buffer (&frame_enc->output_buffer);
+    gst_video_encoder_finish_frame (venc, frame_enc);
+  }
+
+  if (!g_queue_is_empty (&base->output_list)) {
+    GST_WARNING_OBJECT (base, "Still %d frame in the output list"
+        " after drain", g_queue_get_length (&base->output_list));
+    while (!g_queue_is_empty (&base->output_list)) {
+      frame_enc = g_queue_pop_head (&base->output_list);
+      gst_video_codec_frame_unref (frame_enc);
+      gst_clear_buffer (&frame_enc->output_buffer);
+      gst_video_encoder_finish_frame (venc, frame_enc);
+    }
+  }
+
+  if (!g_queue_is_empty (&base->reorder_list)) {
+    GST_WARNING_OBJECT (base, "Still %d frame in the reorder list"
+        " after drain", g_queue_get_length (&base->reorder_list));
+    while (!g_queue_is_empty (&base->reorder_list)) {
+      frame_enc = g_queue_pop_head (&base->reorder_list);
+      gst_video_codec_frame_unref (frame_enc);
+      gst_clear_buffer (&frame_enc->output_buffer);
+      gst_video_encoder_finish_frame (venc, frame_enc);
+    }
+  }
+
+  /* Also clear the reference list. */
+  g_queue_clear_full (&base->ref_list,
+      (GDestroyNotify) gst_video_codec_frame_unref);
+
+  return ret;
+}
+
+static gboolean
+gst_va_base_enc_reset (GstVaBaseEnc * base)
+{
+  GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
+
+  GST_DEBUG_OBJECT (base, "Reconfiguration");
+  if (gst_va_base_enc_drain (GST_VIDEO_ENCODER (base)) != GST_FLOW_OK)
+    return FALSE;
+
+  if (!base_class->reconfig (base)) {
+    GST_ERROR_OBJECT (base, "Error at reconfiguration error");
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
 gst_va_base_enc_handle_frame (GstVideoEncoder * venc,
     GstVideoCodecFrame * frame)
 {
@@ -523,6 +630,11 @@ gst_va_base_enc_handle_frame (GstVideoEncoder * venc,
       GST_TIME_ARGS (GST_BUFFER_DTS (frame->input_buffer)),
       GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer)));
 
+  if (g_atomic_int_compare_and_exchange (&base->reconf, TRUE, FALSE)) {
+    if (!gst_va_base_enc_reset (base))
+      return GST_FLOW_ERROR;
+  }
+
   ret = gst_va_base_enc_import_input_buffer (base,
       frame->input_buffer, &in_buf);
   if (ret != GST_FLOW_OK)
@@ -600,95 +712,6 @@ error_push_buffer:
 }
 
 static GstFlowReturn
-gst_va_base_enc_drain (GstVideoEncoder * venc)
-{
-  GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
-  GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
-  GstFlowReturn ret = GST_FLOW_OK;
-  GstVideoCodecFrame *frame_enc = NULL;
-  gboolean is_last = FALSE;
-
-  GST_DEBUG_OBJECT (base, "Encoder is draining");
-
-  /* Kickout all cached frames */
-  if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
-    ret = GST_FLOW_ERROR;
-    goto error_and_purge_all;
-  }
-
-  while (frame_enc) {
-    is_last = FALSE;
-
-    if (g_queue_is_empty (&base->reorder_list))
-      is_last = TRUE;
-
-    ret = base_class->encode_frame (base, frame_enc, is_last);
-    if (ret != GST_FLOW_OK)
-      goto error_and_purge_all;
-
-    frame_enc = NULL;
-
-    ret = _push_out_one_buffer (base);
-    if (ret != GST_FLOW_OK)
-      goto error_and_purge_all;
-
-    if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
-      ret = GST_FLOW_ERROR;
-      goto error_and_purge_all;
-    }
-  }
-
-  g_assert (g_queue_is_empty (&base->reorder_list));
-
-  /* Output all frames. */
-  while (!g_queue_is_empty (&base->output_list)) {
-    ret = _push_out_one_buffer (base);
-    if (ret != GST_FLOW_OK)
-      goto error_and_purge_all;
-  }
-
-  /* Also clear the reference list. */
-  g_queue_clear_full (&base->ref_list,
-      (GDestroyNotify) gst_video_codec_frame_unref);
-
-  return GST_FLOW_OK;
-
-error_and_purge_all:
-  if (frame_enc) {
-    gst_clear_buffer (&frame_enc->output_buffer);
-    gst_video_encoder_finish_frame (venc, frame_enc);
-  }
-
-  if (!g_queue_is_empty (&base->output_list)) {
-    GST_WARNING_OBJECT (base, "Still %d frame in the output list"
-        " after drain", g_queue_get_length (&base->output_list));
-    while (!g_queue_is_empty (&base->output_list)) {
-      frame_enc = g_queue_pop_head (&base->output_list);
-      gst_video_codec_frame_unref (frame_enc);
-      gst_clear_buffer (&frame_enc->output_buffer);
-      gst_video_encoder_finish_frame (venc, frame_enc);
-    }
-  }
-
-  if (!g_queue_is_empty (&base->reorder_list)) {
-    GST_WARNING_OBJECT (base, "Still %d frame in the reorder list"
-        " after drain", g_queue_get_length (&base->reorder_list));
-    while (!g_queue_is_empty (&base->reorder_list)) {
-      frame_enc = g_queue_pop_head (&base->reorder_list);
-      gst_video_codec_frame_unref (frame_enc);
-      gst_clear_buffer (&frame_enc->output_buffer);
-      gst_video_encoder_finish_frame (venc, frame_enc);
-    }
-  }
-
-  /* Also clear the reference list. */
-  g_queue_clear_full (&base->ref_list,
-      (GDestroyNotify) gst_video_codec_frame_unref);
-
-  return ret;
-}
-
-static GstFlowReturn
 gst_va_base_enc_finish (GstVideoEncoder * venc)
 {
   return gst_va_base_enc_drain (venc);
@@ -698,7 +721,6 @@ static gboolean
 gst_va_base_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
 {
   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
-  GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
 
   g_return_val_if_fail (state->caps != NULL, FALSE);
 
@@ -706,18 +728,8 @@ gst_va_base_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
     gst_video_codec_state_unref (base->input_state);
   base->input_state = gst_video_codec_state_ref (state);
 
-  if (gst_va_base_enc_drain (venc) != GST_FLOW_OK)
-    return FALSE;
-
-  if (!gst_va_encoder_close (base->encoder)) {
-    GST_ERROR_OBJECT (base, "Failed to close the VA encoder");
-    return FALSE;
-  }
-
-  if (!base_class->reconfig (base)) {
-    GST_ERROR_OBJECT (base, "Reconfig the encoder error");
+  if (!gst_va_base_enc_reset (base))
     return FALSE;
-  }
 
   /* Sub class should open the encoder if reconfig succeeds. */
   return gst_va_encoder_is_open (base->encoder);
index 20b858d..2db7c76 100644 (file)
@@ -46,6 +46,8 @@ struct _GstVaBaseEnc
   GstVaDisplay *display;
   GstVaEncoder *encoder;
 
+  gboolean reconf;
+
   VAProfile profile;
   gint width;
   gint height;