msdk: enc: fix missing some frames to be encoded

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
This commit is contained in:
Hyunjun Ko 2018-03-08 11:39:25 -09:00 committed by Sreerenj Balachandran
parent 8a3630ffd7
commit 4918430858
2 changed files with 37 additions and 32 deletions

View file

@ -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;
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;
}
}
if (!task->sync_point) {
if (!task->sync_point)
return GST_FLOW_OK;
frame = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (thiz));
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;

View file

@ -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);