nvenc: Ensure drain all frames on finish
authorSeungha Yang <seungha.yang@navercorp.com>
Thu, 13 Dec 2018 13:03:36 +0000 (22:03 +0900)
committerSeungha Yang <seungha.yang@navercorp.com>
Sun, 10 Mar 2019 04:58:42 +0000 (13:58 +0900)
To drain all queued encoding items, encoder should gracefully
wait the encoding thread without stealing queued items.
Otherwise, some input frames can be dropped.

sys/nvenc/gstnvbaseenc.c

index 51e75eb..3d991ba 100644 (file)
@@ -210,7 +210,8 @@ static void gst_nv_base_enc_get_property (GObject * object, guint prop_id,
 static void gst_nv_base_enc_finalize (GObject * obj);
 static GstCaps *gst_nv_base_enc_getcaps (GstVideoEncoder * enc,
     GstCaps * filter);
-static gboolean gst_nv_base_enc_stop_bitstream_thread (GstNvBaseEnc * nvenc);
+static gboolean gst_nv_base_enc_stop_bitstream_thread (GstNvBaseEnc * nvenc,
+    gboolean force);
 
 static void
 gst_nv_base_enc_class_init (GstNvBaseEncClass * klass)
@@ -508,7 +509,7 @@ gst_nv_base_enc_stop (GstVideoEncoder * enc)
 {
   GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
 
-  gst_nv_base_enc_stop_bitstream_thread (nvenc);
+  gst_nv_base_enc_stop_bitstream_thread (nvenc, TRUE);
 
   gst_nv_base_enc_free_buffers (nvenc);
 
@@ -883,24 +884,27 @@ gst_nv_base_enc_start_bitstream_thread (GstNvBaseEnc * nvenc)
 }
 
 static gboolean
-gst_nv_base_enc_stop_bitstream_thread (GstNvBaseEnc * nvenc)
+gst_nv_base_enc_stop_bitstream_thread (GstNvBaseEnc * nvenc, gboolean force)
 {
   gpointer out_buf;
 
   if (nvenc->bitstream_thread == NULL)
     return TRUE;
 
-  /* FIXME */
-  GST_FIXME_OBJECT (nvenc, "stop bitstream reading thread properly");
-  g_async_queue_lock (nvenc->bitstream_queue);
-  g_async_queue_lock (nvenc->bitstream_pool);
-  while ((out_buf = g_async_queue_try_pop_unlocked (nvenc->bitstream_queue))) {
-    GST_INFO_OBJECT (nvenc, "stole bitstream buffer %p from queue", out_buf);
-    g_async_queue_push_unlocked (nvenc->bitstream_pool, out_buf);
+  if (force) {
+    g_async_queue_lock (nvenc->bitstream_queue);
+    g_async_queue_lock (nvenc->bitstream_pool);
+    while ((out_buf = g_async_queue_try_pop_unlocked (nvenc->bitstream_queue))) {
+      GST_INFO_OBJECT (nvenc, "stole bitstream buffer %p from queue", out_buf);
+      g_async_queue_push_unlocked (nvenc->bitstream_pool, out_buf);
+    }
+    g_async_queue_push_unlocked (nvenc->bitstream_queue, SHUTDOWN_COOKIE);
+    g_async_queue_unlock (nvenc->bitstream_pool);
+    g_async_queue_unlock (nvenc->bitstream_queue);
+  } else {
+    /* wait for encoder to drain the remaining buffers */
+    g_async_queue_push (nvenc->bitstream_queue, SHUTDOWN_COOKIE);
   }
-  g_async_queue_push_unlocked (nvenc->bitstream_queue, SHUTDOWN_COOKIE);
-  g_async_queue_unlock (nvenc->bitstream_pool);
-  g_async_queue_unlock (nvenc->bitstream_queue);
 
   /* temporary unlock, so other thread can find and push frame */
   GST_VIDEO_ENCODER_STREAM_UNLOCK (nvenc);
@@ -1902,12 +1906,10 @@ gst_nv_base_enc_finish (GstVideoEncoder * enc)
 {
   GstNvBaseEnc *nvenc = GST_NV_BASE_ENC (enc);
 
-  GST_FIXME_OBJECT (enc, "implement finish");
-
-  gst_nv_base_enc_drain_encoder (nvenc);
+  if (!gst_nv_base_enc_drain_encoder (nvenc))
+    return GST_FLOW_ERROR;
 
-  /* wait for encoder to output the remaining buffers */
-  gst_nv_base_enc_stop_bitstream_thread (nvenc);
+  gst_nv_base_enc_stop_bitstream_thread (nvenc, FALSE);
 
   return GST_FLOW_OK;
 }