Skip to content

Commit

Permalink
mppenc: Async encoding
Browse files Browse the repository at this point in the history
Tested on RK3588 with:
gst-launch-1.0 kmssrc sync-fb=0 ! queue ! mpph264enc ! fakesink

Change-Id: I4f5d1714f9b38c483cf30ace31af8da620841ff9
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
  • Loading branch information
JeffyCN committed Dec 1, 2023
1 parent af60316 commit 3e5d951
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 43 deletions.
158 changes: 115 additions & 43 deletions gst/rockchipmpp/gstmppenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
#define parent_class gst_mpp_enc_parent_class
G_DEFINE_ABSTRACT_TYPE (GstMppEnc, gst_mpp_enc, GST_TYPE_VIDEO_ENCODER);

#define MPP_PENDING_MAX 2 /* Max number of MPP pending frame */
#define MPP_PENDING_MAX 16 /* Max number of MPP pending frame */

#define GST_MPP_ENC_TASK_STARTED(encoder) \
(gst_pad_get_task_state ((encoder)->srcpad) == GST_TASK_STARTED)
Expand Down Expand Up @@ -458,6 +458,11 @@ gst_mpp_enc_reset (GstVideoEncoder * encoder, gboolean drain, gboolean final)
self->task_ret = GST_FLOW_OK;
self->pending_frames = 0;

if (self->frames) {
g_list_free (self->frames);
self->frames = NULL;
}

/* Force re-apply prop */
self->prop_dirty = TRUE;

Expand All @@ -468,6 +473,7 @@ static gboolean
gst_mpp_enc_start (GstVideoEncoder * encoder)
{
GstMppEnc *self = GST_MPP_ENC (encoder);
MppPollType timeout = MPP_POLL_NON_BLOCK;

GST_DEBUG_OBJECT (self, "starting");

Expand All @@ -482,6 +488,12 @@ gst_mpp_enc_start (GstVideoEncoder * encoder)
if (mpp_create (&self->mpp_ctx, &self->mpi))
goto err_unref_alloc;

if (self->mpi->control (self->mpp_ctx, MPP_SET_INPUT_TIMEOUT, &timeout))
goto err_destroy_mpp;

if (self->mpi->control (self->mpp_ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout))
goto err_destroy_mpp;

if (mpp_init (self->mpp_ctx, MPP_CTX_ENC, self->mpp_type))
goto err_destroy_mpp;

Expand All @@ -498,6 +510,7 @@ gst_mpp_enc_start (GstVideoEncoder * encoder)
self->input_state = NULL;
self->flushing = FALSE;
self->pending_frames = 0;
self->frames = NULL;

g_mutex_init (&self->mutex);

Expand Down Expand Up @@ -906,57 +919,93 @@ gst_mpp_enc_force_keyframe (GstVideoEncoder * encoder, gboolean keyframe)
return TRUE;
}

static void
gst_mpp_enc_loop (GstVideoEncoder * encoder)
static gboolean
gst_mpp_enc_send_frame_locked (GstVideoEncoder * encoder)
{
GstMppEnc *self = GST_MPP_ENC (encoder);
GstVideoCodecFrame *frame;
GstBuffer *buffer;
GstMemory *mem;
MppFrame mframe;
MppPacket mpkt = NULL;
MppBuffer mbuf;
gboolean keyframe;
gint pkt_size;
guint32 frame_number;

GST_MPP_ENC_WAIT (encoder, self->pending_frames || self->flushing);
if (!self->frames)
return FALSE;

GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
if (!mpp_frame_init (&mframe))
return FALSE;

if (self->flushing && !self->pending_frames)
goto flushing;
mpp_frame_set_fmt (mframe, mpp_frame_get_fmt (self->mpp_frame));
mpp_frame_set_width (mframe, mpp_frame_get_width (self->mpp_frame));
mpp_frame_set_height (mframe, mpp_frame_get_height (self->mpp_frame));
mpp_frame_set_hor_stride (mframe, mpp_frame_get_hor_stride (self->mpp_frame));
mpp_frame_set_ver_stride (mframe, mpp_frame_get_ver_stride (self->mpp_frame));

frame = gst_video_encoder_get_oldest_frame (encoder);
self->pending_frames--;
frame_number = GPOINTER_TO_UINT (g_list_nth_data (self->frames, 0));
frame = gst_video_encoder_get_frame (encoder, frame_number);

GST_MPP_ENC_BROADCAST (encoder);
keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
if (keyframe) {
/* TODO: Find a way to set exact keyframe request */
self->required_keyframe_number = frame_number;
gst_mpp_enc_force_keyframe (encoder, TRUE);
}

/* HACK: get the converted input buffer from frame->output_buffer */
/* HACK: Get the converted input buffer from frame->output_buffer */
mem = gst_buffer_peek_memory (frame->output_buffer, 0);
mbuf = gst_mpp_mpp_buffer_from_gst_memory (mem);

mframe = self->mpp_frame;
mpp_frame_set_buffer (mframe, mbuf);

keyframe = GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame);
if (keyframe)
gst_mpp_enc_force_keyframe (encoder, TRUE);
gst_video_codec_frame_unref (frame);

/* Encode one frame */
GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
if (!self->mpi->encode_put_frame (self->mpp_ctx, mframe))
self->mpi->encode_get_packet (self->mpp_ctx, &mpkt);
GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
if (!self->mpi->encode_put_frame (self->mpp_ctx, mframe)) {
GST_DEBUG_OBJECT (self, "encoding frame %d", frame_number);
self->frames = g_list_delete_link (self->frames, self->frames);
return TRUE;
}

if (keyframe)
gst_mpp_enc_force_keyframe (encoder, FALSE);
mpp_frame_deinit (mframe);
return FALSE;
}

static gboolean
gst_mpp_enc_poll_packet_locked (GstVideoEncoder * encoder)
{
GstMppEnc *self = GST_MPP_ENC (encoder);
GstVideoCodecFrame *frame;
GstBuffer *buffer;
GstMemory *mem;
MppFrame mframe;
MppPacket mpkt;
MppMeta meta;
MppBuffer mbuf;
gint pkt_size;

self->mpi->encode_get_packet (self->mpp_ctx, &mpkt);
if (!mpkt)
goto error;
return FALSE;

pkt_size = mpp_packet_get_length (mpkt);
/* Deinit input frame */
meta = mpp_packet_get_meta (mpkt);
if (!mpp_meta_get_frame (meta, KEY_INPUT_FRAME, &mframe))
mpp_frame_deinit (mframe);

/* Wake up the frame producer */
self->pending_frames--;
GST_MPP_ENC_BROADCAST (encoder);

/* This encoded frame must be the oldest one */
frame = gst_video_encoder_get_oldest_frame (encoder);

/* TODO: Remove it when using exact keyframe request */
if (frame->system_frame_number == self->required_keyframe_number)
gst_mpp_enc_force_keyframe (encoder, FALSE);

pkt_size = mpp_packet_get_length (mpkt);
mbuf = mpp_packet_get_buffer (mpkt);
if (!mbuf)
goto error;

if (self->zero_copy_pkt) {
buffer = gst_buffer_new ();
Expand Down Expand Up @@ -994,9 +1043,39 @@ gst_mpp_enc_loop (GstVideoEncoder * encoder)
gst_video_encoder_finish_frame (encoder, frame);

out:
if (mpkt)
mpp_packet_deinit (&mpkt);
mpp_packet_deinit (&mpkt);
return TRUE;
error:
GST_WARNING_OBJECT (self, "can't process this frame");
drop:
GST_DEBUG_OBJECT (self, "drop frame");
gst_buffer_replace (&frame->output_buffer, NULL);
gst_video_encoder_finish_frame (encoder, frame);
goto out;
}

static void
gst_mpp_enc_loop (GstVideoEncoder * encoder)
{
GstMppEnc *self = GST_MPP_ENC (encoder);

GST_MPP_ENC_WAIT (encoder, self->pending_frames || self->flushing);

GST_VIDEO_ENCODER_STREAM_LOCK (encoder);

if (self->flushing && !self->pending_frames) {
GST_INFO_OBJECT (self, "flushing");
self->task_ret = GST_FLOW_FLUSHING;
goto out;
}

/* Try sending ready frames to MPP (non-block) */
while (gst_mpp_enc_send_frame_locked (encoder));

/* Try polling encoded packets from MPP (non-block) */
while (gst_mpp_enc_poll_packet_locked (encoder));

out:
if (self->task_ret != GST_FLOW_OK) {
GST_DEBUG_OBJECT (self, "leaving output thread: %s",
gst_flow_get_name (self->task_ret));
Expand All @@ -1005,19 +1084,6 @@ gst_mpp_enc_loop (GstVideoEncoder * encoder)
}

GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
return;
flushing:
GST_INFO_OBJECT (self, "flushing");
self->task_ret = GST_FLOW_FLUSHING;
goto out;
error:
GST_WARNING_OBJECT (self, "can't process this frame");
goto drop;
drop:
GST_DEBUG_OBJECT (self, "drop frame");
gst_buffer_replace (&frame->output_buffer, NULL);
gst_video_encoder_finish_frame (encoder, frame);
goto out;
}

static GstFlowReturn
Expand Down Expand Up @@ -1056,7 +1122,13 @@ gst_mpp_enc_handle_frame (GstVideoEncoder * encoder, GstVideoCodecFrame * frame)
|| self->flushing);
GST_VIDEO_ENCODER_STREAM_LOCK (encoder);

if (G_UNLIKELY (self->flushing))
goto flushing;

self->pending_frames++;
self->frames =
g_list_append (self->frames,
GUINT_TO_POINTER (frame->system_frame_number));

GST_MPP_ENC_BROADCAST (encoder);

Expand Down
5 changes: 5 additions & 0 deletions gst/rockchipmpp/gstmppenc.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ struct _GstMppEnc
/* drop frames when flushing but not draining */
gboolean draining;

/* frame system numbers that are ready for sending to MPP */
GList *frames;

guint32 required_keyframe_number;

guint pending_frames;
GMutex event_mutex;
GCond event_cond;
Expand Down

0 comments on commit 3e5d951

Please sign in to comment.