va: encoder: extend prepare_output() virtual function

The output of VP9 and AV1 encoder is a little different from the H264
and H265 encoder, it may contain repeat frames and so the output frame
number may be more than the input. We need to call finish_subframe()
when some frame will be repeated later. So we need to extend the
current prepare_output() virtual function.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3015>
This commit is contained in:
He Junyan 2022-11-10 17:00:28 +08:00 committed by GStreamer Marge Bot
parent a278137f7e
commit 39144f612e
4 changed files with 60 additions and 28 deletions

View file

@ -269,7 +269,7 @@ gst_va_base_enc_import_input_buffer (GstVaBaseEnc * base,
return gst_va_buffer_importer_import (&importer, inbuf, buf); return gst_va_buffer_importer_import (&importer, inbuf, buf);
} }
static GstBuffer * GstBuffer *
gst_va_base_enc_create_output_buffer (GstVaBaseEnc * base, gst_va_base_enc_create_output_buffer (GstVaBaseEnc * base,
GstVaEncodePicture * picture) GstVaEncodePicture * picture)
{ {
@ -404,37 +404,38 @@ config_failed:
static GstFlowReturn static GstFlowReturn
_push_buffer_to_downstream (GstVaBaseEnc * base, GstVideoCodecFrame * frame) _push_buffer_to_downstream (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
{ {
GstVaEncodePicture *enc_picture;
GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base); GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
GstBuffer *buf; GstFlowReturn ret;
gboolean complete = TRUE;
if (base_class->prepare_output) if (!base_class->prepare_output (base, frame, &complete)) {
base_class->prepare_output (base, frame); GST_ERROR_OBJECT (base, "Failed to prepare output");
enc_picture =
*((GstVaEncodePicture **) gst_video_codec_frame_get_user_data (frame));
buf = gst_va_base_enc_create_output_buffer (base, enc_picture);
if (!buf) {
GST_ERROR_OBJECT (base, "Failed to create output buffer");
goto error; goto error;
} }
gst_buffer_replace (&frame->output_buffer, buf); if (frame->output_buffer)
gst_clear_buffer (&buf); GST_LOG_OBJECT (base, "Push to downstream: frame system_frame_number: %d,"
" pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT
" duration: %" GST_TIME_FORMAT ", buffer size: %" G_GSIZE_FORMAT,
frame->system_frame_number, GST_TIME_ARGS (frame->pts),
GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->duration),
gst_buffer_get_size (frame->output_buffer));
GST_LOG_OBJECT (base, "Push to downstream: frame system_frame_number: %d," if (complete) {
" pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
" duration: %" GST_TIME_FORMAT ", buffer size: %" G_GSIZE_FORMAT, } else {
frame->system_frame_number, GST_TIME_ARGS (frame->pts), if (frame->output_buffer) {
GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->duration), ret = gst_video_encoder_finish_subframe (GST_VIDEO_ENCODER (base), frame);
gst_buffer_get_size (frame->output_buffer)); } else {
/* Allow to output later and no data here. */
ret = GST_FLOW_OK;
}
}
return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame); return ret;
error: error:
gst_clear_buffer (&frame->output_buffer); gst_clear_buffer (&frame->output_buffer);
gst_clear_buffer (&buf);
gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame); gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;

View file

@ -91,8 +91,9 @@ struct _GstVaBaseEncClass
GstFlowReturn (*encode_frame) (GstVaBaseEnc * encoder, GstFlowReturn (*encode_frame) (GstVaBaseEnc * encoder,
GstVideoCodecFrame * frame, GstVideoCodecFrame * frame,
gboolean is_last); gboolean is_last);
void (*prepare_output) (GstVaBaseEnc * encoder, gboolean (*prepare_output) (GstVaBaseEnc * encoder,
GstVideoCodecFrame * frame); GstVideoCodecFrame * frame,
gboolean * complete);
GstVaCodecs codec; GstVaCodecs codec;
VAEntrypoint entrypoint; VAEntrypoint entrypoint;
@ -136,6 +137,8 @@ gboolean gst_va_base_enc_add_trellis_parameter (GstVaBaseEnc * base
void gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base, void gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base,
const gchar * codec_name); const gchar * codec_name);
void gst_va_base_enc_reset_state (GstVaBaseEnc * base); void gst_va_base_enc_reset_state (GstVaBaseEnc * base);
GstBuffer * gst_va_base_enc_create_output_buffer (GstVaBaseEnc * base,
GstVaEncodePicture * picture);
void gst_va_base_enc_update_property_uint (GstVaBaseEnc * base, void gst_va_base_enc_update_property_uint (GstVaBaseEnc * base,
guint32 * old_val, guint32 * old_val,

View file

@ -3038,11 +3038,13 @@ gst_va_h264_enc_flush (GstVideoEncoder * venc)
return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (venc); return GST_VIDEO_ENCODER_CLASS (parent_class)->flush (venc);
} }
static void static gboolean
gst_va_h264_enc_prepare_output (GstVaBaseEnc * base, GstVideoCodecFrame * frame) gst_va_h264_enc_prepare_output (GstVaBaseEnc * base,
GstVideoCodecFrame * frame, gboolean * complete)
{ {
GstVaH264Enc *self = GST_VA_H264_ENC (base); GstVaH264Enc *self = GST_VA_H264_ENC (base);
GstVaH264EncFrame *frame_enc; GstVaH264EncFrame *frame_enc;
GstBuffer *buf;
frame_enc = _enc_frame (frame); frame_enc = _enc_frame (frame);
@ -3054,6 +3056,18 @@ gst_va_h264_enc_prepare_output (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
(gint64) self->gop.num_reorder_frames); (gint64) self->gop.num_reorder_frames);
base->output_frame_count++; base->output_frame_count++;
frame->duration = base->frame_duration; frame->duration = base->frame_duration;
buf = gst_va_base_enc_create_output_buffer (base, frame_enc->picture);
if (!buf) {
GST_ERROR_OBJECT (base, "Failed to create output buffer");
return FALSE;
}
gst_buffer_replace (&frame->output_buffer, buf);
gst_clear_buffer (&buf);
*complete = TRUE;
return TRUE;
} }
static gint static gint

View file

@ -4611,11 +4611,13 @@ gst_va_h265_enc_new_frame (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
return TRUE; return TRUE;
} }
static void static gboolean
gst_va_h265_enc_prepare_output (GstVaBaseEnc * base, GstVideoCodecFrame * frame) gst_va_h265_enc_prepare_output (GstVaBaseEnc * base,
GstVideoCodecFrame * frame, gboolean * complete)
{ {
GstVaH265Enc *self = GST_VA_H265_ENC (base); GstVaH265Enc *self = GST_VA_H265_ENC (base);
GstVaH265EncFrame *frame_enc; GstVaH265EncFrame *frame_enc;
GstBuffer *buf;
frame_enc = _enc_frame (frame); frame_enc = _enc_frame (frame);
@ -4627,6 +4629,18 @@ gst_va_h265_enc_prepare_output (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
(gint64) self->gop.num_reorder_frames); (gint64) self->gop.num_reorder_frames);
base->output_frame_count++; base->output_frame_count++;
frame->duration = base->frame_duration; frame->duration = base->frame_duration;
buf = gst_va_base_enc_create_output_buffer (base, frame_enc->picture);
if (!buf) {
GST_ERROR_OBJECT (base, "Failed to create output buffer");
return FALSE;
}
gst_buffer_replace (&frame->output_buffer, buf);
gst_clear_buffer (&buf);
*complete = TRUE;
return TRUE;
} }
/* *INDENT-OFF* */ /* *INDENT-OFF* */