From 491843085817ba9c5bc98f8d4087a1cc7ab4fad6 Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Thu, 8 Mar 2018 11:39:25 -0900 Subject: msdk: enc: fix missing some frames to be encoded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was not handling the end of encoding sequence in encoder. This patch does drain any remaining internal streams while decoder already does this. Document says: "To mark the end of the encoding sequence, call this function with a NULL surface pointer. Repeat the call to drain any remaining internally cached bitstreams—one frame at a time—until MFX_ERR_MORE_DATA is returned." https://bugzilla.gnome.org/show_bug.cgi?id=793236 --- sys/msdk/gstmsdkenc.c | 64 +++++++++++++++++++++++++++++---------------------- sys/msdk/gstmsdkenc.h | 3 --- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/sys/msdk/gstmsdkenc.c b/sys/msdk/gstmsdkenc.c index 4ccaf56c9..e23c1532e 100644 --- a/sys/msdk/gstmsdkenc.c +++ b/sys/msdk/gstmsdkenc.c @@ -643,39 +643,24 @@ gst_msdkenc_get_free_task (GstMsdkEnc * thiz) static void gst_msdkenc_reset_task (MsdkEncTask * task) { - task->input_frame = NULL; task->output_bitstream.DataLength = 0; task->sync_point = NULL; - task->more_data = FALSE; } static GstFlowReturn gst_msdkenc_finish_frame (GstMsdkEnc * thiz, MsdkEncTask * task, gboolean discard) { - GstVideoCodecFrame *frame = task->input_frame; + GstVideoCodecFrame *frame; - if (task->more_data) { - GstVideoCodecFrame *frame; + if (!task->sync_point) + return GST_FLOW_OK; - frame = - gst_video_encoder_get_frame (GST_VIDEO_ENCODER_CAST (thiz), - task->pending_frame_number); - if (frame) { - gst_msdkenc_dequeue_frame (thiz, frame); - gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame); - gst_msdkenc_reset_task (task); - return GST_FLOW_OK; - } else { - GST_ERROR_OBJECT (thiz, - "Couldn't find the pending frame %d to be finished", - task->pending_frame_number); - return GST_FLOW_ERROR; - } - } + frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz)); - if (!task->sync_point) { - return GST_FLOW_OK; + if (!frame) { + GST_ERROR_OBJECT (thiz, "failed to get a frame"); + return GST_FLOW_ERROR; } /* Wait for encoding operation to complete */ @@ -705,7 +690,9 @@ gst_msdkenc_finish_frame (GstMsdkEnc * thiz, MsdkEncTask * task, gst_msdkenc_reset_task (task); } + gst_video_codec_frame_unref (frame); gst_msdkenc_dequeue_frame (thiz, frame); + return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (thiz), frame); } @@ -752,13 +739,9 @@ gst_msdkenc_encode_frame (GstMsdkEnc * thiz, mfxFrameSurface1 * surface, } if (task->sync_point) { - task->input_frame = input_frame; thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks; } else if (status == MFX_ERR_MORE_DATA) { - task->more_data = TRUE; - task->pending_frame_number = input_frame->system_frame_number; - gst_video_codec_frame_unref (input_frame); - thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks; + gst_msdkenc_dequeue_frame (thiz, input_frame); } /* Ensure that next task is available */ @@ -802,11 +785,36 @@ gst_msdkenc_set_latency (GstMsdkEnc * thiz) static void gst_msdkenc_flush_frames (GstMsdkEnc * thiz, gboolean discard) { - guint i, t = thiz->next_task; + mfxStatus status; + mfxSession session; + MsdkEncTask *task; + guint i, t; if (!thiz->tasks) return; + session = gst_msdk_context_get_session (thiz->context); + + for (;;) { + task = thiz->tasks + thiz->next_task; + gst_msdkenc_finish_frame (thiz, task, FALSE); + + status = MFXVideoENCODE_EncodeFrameAsync (session, NULL, NULL, + &task->output_bitstream, &task->sync_point); + + if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) { + GST_ELEMENT_ERROR (thiz, STREAM, ENCODE, ("Encode frame failed."), + ("MSDK encode error (%s)", msdk_status_to_string (status))); + } + + if (task->sync_point) { + thiz->next_task = ((task - thiz->tasks) + 1) % thiz->num_tasks; + } else if (status == MFX_ERR_MORE_DATA) { + break; + } + }; + + t = thiz->next_task; for (i = 0; i < thiz->num_tasks; i++) { gst_msdkenc_finish_frame (thiz, &thiz->tasks[t], discard); t = (t + 1) % thiz->num_tasks; diff --git a/sys/msdk/gstmsdkenc.h b/sys/msdk/gstmsdkenc.h index db333bd0d..634a54139 100644 --- a/sys/msdk/gstmsdkenc.h +++ b/sys/msdk/gstmsdkenc.h @@ -167,11 +167,8 @@ struct _GstMsdkEncClass struct _MsdkEncTask { - GstVideoCodecFrame *input_frame; mfxSyncPoint sync_point; mfxBitstream output_bitstream; - gboolean more_data; - guint pending_frame_number; }; GType gst_msdkenc_get_type (void); -- cgit v1.2.1