vah264enc: Invert video codec frame dependency.

Instead of using GstMiniObject to hold H264 frame, now it uses a plain
structure. Besides, instead of holding a reference to
GstVideoCodecFrame, the H264 frame structure is set as a
GstVideoCodecFrame user data.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1856>
This commit is contained in:
Víctor Manuel Jáquez Leal 2022-03-04 13:19:17 +01:00 committed by GStreamer Marge Bot
parent f39174fbc4
commit 838fe24e78

View file

@ -83,11 +83,6 @@ typedef struct _GstVaH264LevelLimits GstVaH264LevelLimits;
#define GST_VA_H264_ENC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), G_TYPE_FROM_INSTANCE (obj), GstVaH264EncClass))
#define GST_VA_H264_ENC_CLASS(klass) ((GstVaH264EncClass *) klass)
static GType gst_va_h264_enc_frame_get_type (void);
#define GST_TYPE_VA_H264_ENC_FRAME (gst_va_h264_enc_frame_get_type())
#define GST_IS_VA_H264_ENC_FRAME(obj) (GST_IS_MINI_OBJECT_TYPE((obj), GST_TYPE_VA_H264_ENC_FRAME))
#define GST_VA_H264_ENC_FRAME(obj) ((GstVaH264EncFrame *)(obj))
enum
{
PROP_KEY_INT_MAX = 1,
@ -141,12 +136,12 @@ struct _GstVaH264EncClass
gboolean (*reconfig) (GstVaH264Enc * encoder);
gboolean (*push_frame) (GstVaH264Enc * encoder,
GstVaH264EncFrame * frame,
GstVideoCodecFrame * frame,
gboolean last);
gboolean (*pop_frame) (GstVaH264Enc * encoder,
GstVaH264EncFrame ** out_frame);
GstVideoCodecFrame ** out_frame);
gboolean (*encode_frame) (GstVaH264Enc * encoder,
GstVaH264EncFrame * frame);
GstVideoCodecFrame * frame);
};
/* *INDENT-ON* */
@ -300,9 +295,6 @@ struct _GstVaH264Enc
struct _GstVaH264EncFrame
{
GstMiniObject parent;
GstVideoCodecFrame *frame;
GstVaEncodePicture *picture;
GstH264SliceType type;
gboolean is_ref;
@ -323,8 +315,6 @@ struct _GstVaH264EncFrame
guint total_frame_count;
};
GST_DEFINE_MINI_OBJECT_TYPE (GstVaH264EncFrame, gst_va_h264_enc_frame);
/**
* GstVaH264LevelLimits:
* @name: the level name
@ -469,13 +459,35 @@ gst_va_h264_enc_mbbrc_get_type (void)
return type;
}
static void
gst_va_enc_frame_free (GstVaH264EncFrame * frame)
static GstVaH264EncFrame *
gst_va_enc_frame_new (void)
{
g_clear_pointer (&frame->picture, gst_va_encode_picture_free);
g_clear_pointer (&frame->frame, gst_video_codec_frame_unref);
GstVaH264EncFrame *frame;
g_free (frame);
frame = g_slice_new (GstVaH264EncFrame);
frame->last_frame = FALSE;
frame->frame_num = 0;
frame->unused_for_reference_pic_num = -1;
frame->picture = NULL;
frame->total_frame_count = 0;
return frame;
}
static void
gst_va_enc_frame_free (gpointer pframe)
{
GstVaH264EncFrame *frame = pframe;
g_clear_pointer (&frame->picture, gst_va_encode_picture_free);
g_slice_free (GstVaH264EncFrame, frame);
}
static inline GstVaH264EncFrame *
_enc_frame (GstVideoCodecFrame * frame)
{
GstVaH264EncFrame *enc_frame = gst_video_codec_frame_get_user_data (frame);
g_assert (enc_frame);
return enc_frame;
}
/* Normalizes bitrate (and CPB size) for HRD conformance */
@ -1649,13 +1661,15 @@ gst_va_h264_enc_reconfig (GstVaH264Enc * self)
}
static gboolean
gst_va_h264_enc_push_frame (GstVaH264Enc * self,
GstVaH264EncFrame * frame, gboolean last)
gst_va_h264_enc_push_frame (GstVaH264Enc * self, GstVideoCodecFrame * gst_frame,
gboolean last)
{
GstVaH264EncFrame *frame;
g_return_val_if_fail (self->gop.cur_frame_index <= self->gop.idr_period,
FALSE);
if (frame) {
if (gst_frame) {
/* Begin a new GOP, should have a empty reorder_list. */
if (self->gop.cur_frame_index == self->gop.idr_period) {
g_assert (g_queue_is_empty (&self->reorder_list));
@ -1663,16 +1677,17 @@ gst_va_h264_enc_push_frame (GstVaH264Enc * self,
self->gop.cur_frame_num = 0;
}
frame = _enc_frame (gst_frame);
frame->poc =
((self->gop.cur_frame_index * 2) % self->gop.max_pic_order_cnt);
if (self->gop.cur_frame_index == 0) {
g_assert (frame->poc == 0);
GST_LOG_OBJECT (self, "system_frame_number: %d, an IDR frame, starts"
" a new GOP", frame->frame->system_frame_number);
" a new GOP", gst_frame->system_frame_number);
g_queue_clear_full (&self->ref_list,
(GDestroyNotify) gst_mini_object_unref);
(GDestroyNotify) gst_video_codec_frame_unref);
}
frame->type = self->gop.frame_types[self->gop.cur_frame_index].slice_type;
@ -1684,34 +1699,36 @@ gst_va_h264_enc_push_frame (GstVaH264Enc * self,
frame->right_ref_poc_diff =
self->gop.frame_types[self->gop.cur_frame_index].right_ref_poc_diff;
if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame->frame)) {
if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (gst_frame)) {
GST_DEBUG_OBJECT (self, "system_frame_number: %d, a force key frame,"
" promote its type from %s to %s", frame->frame->system_frame_number,
" promote its type from %s to %s", gst_frame->system_frame_number,
_slice_type_name (frame->type), _slice_type_name (GST_H264_I_SLICE));
frame->type = GST_H264_I_SLICE;
frame->is_ref = TRUE;
}
GST_LOG_OBJECT (self, "Push frame, system_frame_number: %d, poc %d, "
"frame type %s", frame->frame->system_frame_number, frame->poc,
"frame type %s", gst_frame->system_frame_number, frame->poc,
_slice_type_name (frame->type));
self->gop.cur_frame_index++;
g_queue_push_tail (&self->reorder_list, frame);
g_queue_push_tail (&self->reorder_list,
gst_video_codec_frame_ref (gst_frame));
}
/* ensure the last one a non-B and end the GOP. */
if (last && self->gop.cur_frame_index < self->gop.idr_period) {
GstVaH264EncFrame *last_frame;
GstVideoCodecFrame *last_frame;
/* Ensure next push will start a new GOP. */
self->gop.cur_frame_index = self->gop.idr_period;
if (!g_queue_is_empty (&self->reorder_list)) {
last_frame = g_queue_peek_tail (&self->reorder_list);
if (last_frame->type == GST_H264_B_SLICE) {
last_frame->type = GST_H264_P_SLICE;
last_frame->is_ref = TRUE;
frame = _enc_frame (last_frame);
if (frame->type == GST_H264_B_SLICE) {
frame->type = GST_H264_P_SLICE;
frame->is_ref = TRUE;
}
}
}
@ -1728,7 +1745,7 @@ struct RefFramesCount
static void
_count_backward_ref_num (gpointer data, gpointer user_data)
{
GstVaH264EncFrame *frame = (GstVaH264EncFrame *) data;
GstVaH264EncFrame *frame = _enc_frame (data);
struct RefFramesCount *count = (struct RefFramesCount *) user_data;
g_assert (frame->poc != count->poc);
@ -1736,20 +1753,24 @@ _count_backward_ref_num (gpointer data, gpointer user_data)
count->num++;
}
static GstVaH264EncFrame *
static GstVideoCodecFrame *
_pop_pyramid_b_frame (GstVaH264Enc * self)
{
guint i;
GstVaH264EncFrame *b_frame;
gint index = -1;
GstVaH264EncFrame *b_vaframe;
GstVideoCodecFrame *b_frame;
struct RefFramesCount count;
g_assert (self->gop.ref_num_list1 == 1);
/* Find the lowest level with smallest poc. */
b_frame = NULL;
b_vaframe = NULL;
/* Find the lowest level with smallest poc. */
for (i = 0; i < g_queue_get_length (&self->reorder_list); i++) {
GstVaH264EncFrame *f;
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
f = g_queue_peek_nth (&self->reorder_list, i);
@ -1759,13 +1780,14 @@ _pop_pyramid_b_frame (GstVaH264Enc * self)
continue;
}
if (b_frame->pyramid_level > f->pyramid_level) {
vaf = _enc_frame (f);
if (b_vaframe->pyramid_level > vaf->pyramid_level) {
b_frame = f;
index = i;
continue;
}
if (b_frame->poc > f->poc) {
if (b_vaframe->poc > vaf->poc) {
b_frame = f;
index = i;
}
@ -1773,18 +1795,20 @@ _pop_pyramid_b_frame (GstVaH264Enc * self)
again:
/* Check whether its refs are already poped. */
g_assert (b_frame->left_ref_poc_diff != 0);
g_assert (b_frame->right_ref_poc_diff != 0);
g_assert (b_vaframe->left_ref_poc_diff != 0);
g_assert (b_vaframe->right_ref_poc_diff != 0);
for (i = 0; i < g_queue_get_length (&self->reorder_list); i++) {
GstVaH264EncFrame *f;
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
f = g_queue_peek_nth (&self->reorder_list, i);
if (f == b_frame)
continue;
if (f->poc == b_frame->poc + b_frame->left_ref_poc_diff ||
f->poc == b_frame->poc + b_frame->right_ref_poc_diff) {
vaf = _enc_frame (f);
if (vaf->poc == b_vaframe->poc + b_vaframe->left_ref_poc_diff
|| vaf->poc == b_vaframe->poc + b_vaframe->right_ref_poc_diff) {
b_frame = f;
index = i;
goto again;
@ -1793,11 +1817,12 @@ again:
/* Ensure we already have enough backward refs */
count.num = 0;
count.poc = b_frame->poc;
count.poc = b_vaframe->poc;
g_queue_foreach (&self->ref_list, (GFunc) _count_backward_ref_num, &count);
if (count.num >= self->gop.ref_num_list1) {
GstVaH264EncFrame *f;
GstVideoCodecFrame *f;
/* it will unref at pop_frame */
f = g_queue_pop_nth (&self->reorder_list, index);
g_assert (f == b_frame);
} else {
@ -1808,23 +1833,23 @@ again:
}
static gboolean
gst_va_h264_enc_pop_frame (GstVaH264Enc * self, GstVaH264EncFrame ** out_frame)
gst_va_h264_enc_pop_frame (GstVaH264Enc * self, GstVideoCodecFrame ** out_frame)
{
GstVaH264EncFrame *frame;
GstVaH264EncFrame *vaframe;
GstVideoCodecFrame *frame;
struct RefFramesCount count;
g_return_val_if_fail (self->gop.cur_frame_index <= self->gop.idr_period,
FALSE);
*out_frame = NULL;
if (g_queue_is_empty (&self->reorder_list))
return TRUE;
/* Return the last pushed non-B immediately. */
frame = g_queue_peek_tail (&self->reorder_list);
if (frame->type != GST_H264_B_SLICE) {
*out_frame = g_queue_pop_tail (&self->reorder_list);
vaframe = _enc_frame (frame);
if (vaframe->type != GST_H264_B_SLICE) {
frame = g_queue_pop_tail (&self->reorder_list);
goto get_one;
}
@ -1832,8 +1857,6 @@ gst_va_h264_enc_pop_frame (GstVaH264Enc * self, GstVaH264EncFrame ** out_frame)
frame = _pop_pyramid_b_frame (self);
if (frame == NULL)
return TRUE;
*out_frame = frame;
goto get_one;
}
@ -1841,17 +1864,18 @@ gst_va_h264_enc_pop_frame (GstVaH264Enc * self, GstVaH264EncFrame ** out_frame)
/* If GOP end, pop anyway. */
if (self->gop.cur_frame_index == self->gop.idr_period) {
*out_frame = g_queue_pop_head (&self->reorder_list);
frame = g_queue_pop_head (&self->reorder_list);
goto get_one;
}
/* Ensure we already have enough backward refs */
frame = g_queue_peek_head (&self->reorder_list);
vaframe = _enc_frame (frame);
count.num = 0;
count.poc = frame->poc;
g_queue_foreach (&self->ref_list, (GFunc) _count_backward_ref_num, &count);
count.poc = vaframe->poc;
g_queue_foreach (&self->ref_list, _count_backward_ref_num, &count);
if (count.num >= self->gop.ref_num_list1) {
*out_frame = g_queue_pop_head (&self->reorder_list);
frame = g_queue_pop_head (&self->reorder_list);
goto get_one;
}
@ -1860,29 +1884,31 @@ gst_va_h264_enc_pop_frame (GstVaH264Enc * self, GstVaH264EncFrame ** out_frame)
get_one:
g_assert (self->gop.cur_frame_num < self->gop.max_frame_num);
(*out_frame)->frame_num = self->gop.cur_frame_num;
vaframe = _enc_frame (frame);
vaframe->frame_num = self->gop.cur_frame_num;
/* Add the frame number for ref frames. */
if ((*out_frame)->is_ref)
if (vaframe->is_ref)
self->gop.cur_frame_num++;
if ((*out_frame)->frame_num == 0)
if (vaframe->frame_num == 0)
self->gop.total_idr_count++;
if (self->gop.b_pyramid && (*out_frame)->type == GST_H264_B_SLICE) {
if (self->gop.b_pyramid && vaframe->type == GST_H264_B_SLICE) {
GST_LOG_OBJECT (self, "pop a pyramid B frame with system_frame_number:"
" %d, poc: %d, frame num: %d, is_ref: %s, level %d",
(*out_frame)->frame->system_frame_number, (*out_frame)->poc,
(*out_frame)->frame_num, (*out_frame)->is_ref ? "true" : "false",
(*out_frame)->pyramid_level);
frame->system_frame_number, vaframe->poc, vaframe->frame_num,
vaframe->is_ref ? "true" : "false", vaframe->pyramid_level);
} else {
GST_LOG_OBJECT (self, "pop a frame with system_frame_number: %d,"
" frame type: %s, poc: %d, frame num: %d, is_ref: %s",
(*out_frame)->frame->system_frame_number,
_slice_type_name ((*out_frame)->type),
(*out_frame)->poc, (*out_frame)->frame_num,
(*out_frame)->is_ref ? "true" : "false");
frame->system_frame_number, _slice_type_name (vaframe->type),
vaframe->poc, vaframe->frame_num, vaframe->is_ref ? "true" : "false");
}
/* unref frame popped from queue or pyramid b_frame */
gst_video_codec_frame_unref (frame);
*out_frame = frame;
return TRUE;
}
@ -2353,7 +2379,7 @@ _fill_picture_parameter (GstVaH264Enc * self, GstVaH264EncFrame * frame,
/* ref frames in queue are already sorted by frame_num. */
for (; i < g_queue_get_length (&self->ref_list); i++) {
f = g_queue_peek_nth (&self->ref_list, i);
f = _enc_frame (g_queue_peek_nth (&self->ref_list, i));
pic_param->ReferenceFrames[i].picture_id =
gst_va_encode_picture_get_reconstruct_surface (f->picture);
@ -2816,7 +2842,8 @@ _add_aud (GstVaH264Enc * self, GstVaH264EncFrame * frame)
}
static gboolean
gst_va_h264_enc_encode_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
gst_va_h264_enc_encode_frame (GstVaH264Enc * self,
GstVideoCodecFrame * gst_frame)
{
VAEncPictureParameterBufferH264 pic_param;
GstH264PPS pps;
@ -2826,6 +2853,11 @@ gst_va_h264_enc_encode_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
guint list1_num = 0;
guint slice_of_mbs, slice_mod_mbs, slice_start_mb, slice_mbs;
gint i;
GstVaH264EncFrame *frame;
g_return_val_if_fail (gst_frame, FALSE);
frame = _enc_frame (gst_frame);
/* Repeat the SPS for IDR. */
if (frame->poc == 0) {
@ -2866,14 +2898,16 @@ gst_va_h264_enc_encode_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
/* Non I frame, construct reference list. */
if (frame->type != GST_H264_I_SLICE) {
GstVaH264EncFrame *f;
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
for (i = g_queue_get_length (&self->ref_list) - 1; i >= 0; i--) {
f = g_queue_peek_nth (&self->ref_list, i);
if (f->poc > frame->poc)
vaf = _enc_frame (f);
if (vaf->poc > frame->poc)
continue;
list0[list0_num] = f;
list0[list0_num] = vaf;
list0_num++;
}
@ -2886,14 +2920,16 @@ gst_va_h264_enc_encode_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
}
if (frame->type == GST_H264_B_SLICE) {
GstVaH264EncFrame *f;
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
for (i = 0; i < g_queue_get_length (&self->ref_list); i++) {
f = g_queue_peek_nth (&self->ref_list, i);
if (f->poc < frame->poc)
vaf = _enc_frame (f);
if (vaf->poc < frame->poc)
continue;
list1[list1_num] = f;
list1[list1_num] = vaf;
list1_num++;
}
@ -3036,10 +3072,11 @@ _flush_all_frames (GstVideoEncoder * venc)
GstVaH264Enc *self = GST_VA_H264_ENC (venc);
g_queue_clear_full (&self->reorder_list,
(GDestroyNotify) gst_mini_object_unref);
(GDestroyNotify) gst_video_codec_frame_unref);
g_queue_clear_full (&self->output_list,
(GDestroyNotify) gst_mini_object_unref);
g_queue_clear_full (&self->ref_list, (GDestroyNotify) gst_mini_object_unref);
(GDestroyNotify) gst_video_codec_frame_unref);
g_queue_clear_full (&self->ref_list,
(GDestroyNotify) gst_video_codec_frame_unref);
}
static gboolean
@ -3203,9 +3240,9 @@ invalid_buffer:
}
static GstFlowReturn
_push_buffer_to_downstream (GstVaH264Enc * self, GstVaH264EncFrame * frame_enc)
_push_buffer_to_downstream (GstVaH264Enc * self, GstVideoCodecFrame * frame)
{
GstVideoCodecFrame *frame;
GstVaH264EncFrame *frame_enc;
GstFlowReturn ret;
guint coded_size;
goffset offset;
@ -3215,10 +3252,10 @@ _push_buffer_to_downstream (GstVaH264Enc * self, GstVaH264EncFrame * frame_enc)
VAStatus status;
VACodedBufferSegment *seg, *seg_list;
frame = frame_enc->frame;
dpy = gst_va_display_get_va_dpy (self->display);
frame_enc = _enc_frame (frame);
/* Wait for encoding to finish */
surface = gst_va_encode_picture_get_raw_surface (frame_enc->picture);
status = vaSyncSurface (dpy, surface);
@ -3278,7 +3315,6 @@ _push_buffer_to_downstream (GstVaH264Enc * self, GstVaH264EncFrame * frame_enc)
self->output_frame_count++;
frame->duration = self->frame_duration;
gst_clear_mini_object ((GstMiniObject **) & frame_enc);
gst_buffer_replace (&frame->output_buffer, buf);
gst_clear_buffer (&buf);
@ -3293,39 +3329,37 @@ _push_buffer_to_downstream (GstVaH264Enc * self, GstVaH264EncFrame * frame_enc)
return ret;
error:
gst_clear_mini_object ((GstMiniObject **) & frame_enc);
gst_clear_buffer (&buf);
gst_clear_buffer (&frame->output_buffer);
gst_clear_buffer (&buf);
gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
return GST_FLOW_ERROR;
}
static gboolean
_reorder_frame (GstVideoEncoder * venc, GstVaH264EncFrame * in_frame,
gboolean bump_all, GstVaH264EncFrame ** out_frame)
_reorder_frame (GstVideoEncoder * venc, GstVideoCodecFrame * frame,
gboolean bump_all, GstVideoCodecFrame ** out_frame)
{
GstVaH264Enc *self = GST_VA_H264_ENC (venc);
GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
GstVaH264EncFrame *frame_out = NULL;
g_assert (klass->push_frame);
if (!klass->push_frame (self, in_frame, bump_all)) {
if (!klass->push_frame (self, frame, bump_all)) {
GST_ERROR_OBJECT (self, "Failed to push the input frame"
" system_frame_number: %d into the reorder list",
in_frame->frame->system_frame_number);
frame->system_frame_number);
*out_frame = NULL;
return FALSE;
}
g_assert (klass->pop_frame);
if (!klass->pop_frame (self, &frame_out)) {
if (!klass->pop_frame (self, out_frame)) {
GST_ERROR_OBJECT (self, "Failed to pop the frame from the reorder list");
*out_frame = NULL;
return FALSE;
}
*out_frame = frame_out;
return TRUE;
}
@ -3340,11 +3374,12 @@ _sort_by_frame_num (gconstpointer a, gconstpointer b, gpointer user_data)
return frame1->frame_num - frame2->frame_num;
}
static GstVaH264EncFrame *
static GstVideoCodecFrame *
_find_unused_reference_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
{
GstVaH264EncFrame *b_vaframe;
GstVideoCodecFrame *b_frame;
guint i;
GstVaH264EncFrame *b_frame;
/* We still have more space. */
if (g_queue_get_length (&self->ref_list) < self->gop.num_ref_frames)
@ -3361,11 +3396,12 @@ _find_unused_reference_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
/* Choose the B frame with lowest POC. */
b_frame = NULL;
for (i = 0; i < g_queue_get_length (&self->ref_list); i++) {
GstVaH264EncFrame *f;
GstVaH264EncFrame *vaf;
GstVideoCodecFrame *f;
f = g_queue_peek_nth (&self->ref_list, i);
if (f->type != GST_H264_B_SLICE)
vaf = _enc_frame (f);
if (vaf->type != GST_H264_B_SLICE)
continue;
if (!b_frame) {
@ -3373,8 +3409,9 @@ _find_unused_reference_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
continue;
}
g_assert (f->poc != b_frame->poc);
if (f->poc < b_frame->poc)
b_vaframe = _enc_frame (b_frame);
g_assert (vaf->poc != b_vaframe->poc);
if (vaf->poc < b_vaframe->poc)
b_frame = f;
}
@ -3383,26 +3420,29 @@ _find_unused_reference_frame (GstVaH264Enc * self, GstVaH264EncFrame * frame)
return g_queue_peek_head (&self->ref_list);
if (b_frame != g_queue_peek_head (&self->ref_list)) {
frame->unused_for_reference_pic_num = b_frame->frame_num;
b_vaframe = _enc_frame (b_frame);
frame->unused_for_reference_pic_num = b_vaframe->frame_num;
GST_LOG_OBJECT (self, "The frame with POC: %d, pic_num %d will be"
" replaced by the frame with POC: %d, pic_num %d explicitly by"
" using memory_management_control_operation=1",
b_frame->poc, b_frame->frame_num, frame->poc, frame->frame_num);
b_vaframe->poc, b_vaframe->frame_num, frame->poc, frame->frame_num);
}
return b_frame;
}
static GstFlowReturn
_encode_frame (GstVideoEncoder * venc, GstVaH264EncFrame * frame)
_encode_frame (GstVideoEncoder * venc, GstVideoCodecFrame * gst_frame)
{
GstVaH264Enc *self = GST_VA_H264_ENC (venc);
GstVaH264EncClass *klass = GST_VA_H264_ENC_GET_CLASS (self);
GstVaH264EncFrame *unused_ref = NULL;
GstVaH264EncFrame *frame;
GstVideoCodecFrame *unused_ref = NULL;
frame = _enc_frame (gst_frame);
g_assert (frame->picture == NULL);
frame->picture = gst_va_encode_picture_new (self->encoder,
frame->frame->input_buffer);
gst_frame->input_buffer);
if (!frame->picture) {
GST_ERROR_OBJECT (venc, "Failed to create the encode picture");
@ -3412,24 +3452,23 @@ _encode_frame (GstVideoEncoder * venc, GstVaH264EncFrame * frame)
if (frame->is_ref)
unused_ref = _find_unused_reference_frame (self, frame);
if (!klass->encode_frame (self, frame)) {
if (!klass->encode_frame (self, gst_frame)) {
GST_ERROR_OBJECT (venc, "Failed to encode the frame");
return GST_FLOW_ERROR;
}
g_queue_push_tail (&self->output_list, frame);
g_queue_push_tail (&self->output_list, gst_video_codec_frame_ref (gst_frame));
if (frame->is_ref) {
if (unused_ref) {
if (!g_queue_remove (&self->ref_list, unused_ref))
g_assert_not_reached ();
gst_mini_object_unref ((GstMiniObject *) unused_ref);
gst_video_codec_frame_unref (unused_ref);
}
/* Add it into the reference list. */
gst_mini_object_ref ((GstMiniObject *) frame);
g_queue_push_tail (&self->ref_list, frame);
g_queue_push_tail (&self->ref_list, gst_video_codec_frame_ref (gst_frame));
g_queue_sort (&self->ref_list, _sort_by_frame_num, NULL);
g_assert (g_queue_get_length (&self->ref_list) <= self->gop.num_ref_frames);
@ -3446,8 +3485,7 @@ gst_va_h264_enc_handle_frame (GstVideoEncoder * venc,
GstFlowReturn ret;
GstBuffer *in_buf = NULL;
GstVaH264EncFrame *frame_in = NULL;
GstVaH264EncFrame *frame_encode = NULL;
GstVaH264EncFrame *frame_out = NULL;
GstVideoCodecFrame *frame_out, *frame_encode = NULL;
GST_LOG_OBJECT (venc,
"handle frame id %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
@ -3462,24 +3500,15 @@ gst_va_h264_enc_handle_frame (GstVideoEncoder * venc,
gst_buffer_replace (&frame->input_buffer, in_buf);
gst_clear_buffer (&in_buf);
frame_in = g_new (GstVaH264EncFrame, 1);
gst_mini_object_init (GST_MINI_OBJECT_CAST (frame_in), 0,
GST_TYPE_VA_H264_ENC_FRAME, NULL, NULL,
(GstMiniObjectFreeFunction) gst_va_enc_frame_free);
frame_in->last_frame = FALSE;
frame_in->frame_num = 0;
frame_in->unused_for_reference_pic_num = -1;
frame_in->frame = gst_video_codec_frame_ref (frame);
frame_in->picture = NULL;
frame_in->total_frame_count = self->input_frame_count;
self->input_frame_count++;
frame_in = gst_va_enc_frame_new ();
frame_in->total_frame_count = self->input_frame_count++;
gst_video_codec_frame_set_user_data (frame, frame_in, gst_va_enc_frame_free);
if (!_reorder_frame (venc, frame_in, FALSE, &frame_encode))
if (!_reorder_frame (venc, frame, FALSE, &frame_encode))
goto error_reorder;
/* pass it to reorder list and we should not use it again. */
frame = NULL;
frame_in = NULL;
while (frame_encode) {
ret = _encode_frame (venc, frame_encode);
@ -3488,6 +3517,7 @@ gst_va_h264_enc_handle_frame (GstVideoEncoder * venc,
while (g_queue_get_length (&self->output_list) > 0) {
frame_out = g_queue_pop_head (&self->output_list);
gst_video_codec_frame_unref (frame_out);
ret = _push_buffer_to_downstream (self, frame_out);
if (ret != GST_FLOW_OK)
goto error_push_buffer;
@ -3513,20 +3543,18 @@ error_reorder:
{
GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
("Failed to reorder the input frame."), (NULL));
if (frame_in) {
gst_clear_buffer (&frame_in->frame->output_buffer);
gst_video_encoder_finish_frame (venc, frame_in->frame);
if (frame) {
gst_clear_buffer (&frame->output_buffer);
gst_video_encoder_finish_frame (venc, frame);
}
gst_clear_mini_object ((GstMiniObject **) & frame_in);
return GST_FLOW_ERROR;
}
error_encode:
{
GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
("Failed to encode the frame."), (NULL));
gst_clear_buffer (&frame_encode->frame->output_buffer);
gst_video_encoder_finish_frame (venc, frame_encode->frame);
gst_clear_mini_object ((GstMiniObject **) & frame_encode);
gst_clear_buffer (&frame_encode->output_buffer);
gst_video_encoder_finish_frame (venc, frame_encode);
return ret;
}
error_push_buffer:
@ -3539,7 +3567,7 @@ gst_va_h264_enc_drain (GstVideoEncoder * venc)
{
GstVaH264Enc *self = GST_VA_H264_ENC (venc);
GstFlowReturn ret = GST_FLOW_OK;
GstVaH264EncFrame *frame_enc = NULL;
GstVideoCodecFrame *frame_enc = NULL;
GST_DEBUG_OBJECT (self, "Encoder is draining");
@ -3551,13 +3579,14 @@ gst_va_h264_enc_drain (GstVideoEncoder * venc)
while (frame_enc) {
if (g_queue_is_empty (&self->reorder_list))
frame_enc->last_frame = TRUE;
_enc_frame (frame_enc)->last_frame = TRUE;
ret = _encode_frame (venc, frame_enc);
if (ret != GST_FLOW_OK)
goto error_and_purge_all;
frame_enc = g_queue_pop_head (&self->output_list);
gst_video_codec_frame_unref (frame_enc);
ret = _push_buffer_to_downstream (self, frame_enc);
frame_enc = NULL;
if (ret != GST_FLOW_OK)
@ -3575,6 +3604,7 @@ gst_va_h264_enc_drain (GstVideoEncoder * venc)
/* Output all frames. */
while (!g_queue_is_empty (&self->output_list)) {
frame_enc = g_queue_pop_head (&self->output_list);
gst_video_codec_frame_unref (frame_enc);
ret = _push_buffer_to_downstream (self, frame_enc);
frame_enc = NULL;
if (ret != GST_FLOW_OK)
@ -3582,15 +3612,15 @@ gst_va_h264_enc_drain (GstVideoEncoder * venc)
}
/* Also clear the reference list. */
g_queue_clear_full (&self->ref_list, (GDestroyNotify) gst_mini_object_unref);
g_queue_clear_full (&self->ref_list,
(GDestroyNotify) gst_video_codec_frame_unref);
return GST_FLOW_OK;
error_and_purge_all:
if (frame_enc) {
gst_clear_buffer (&frame_enc->frame->output_buffer);
gst_video_encoder_finish_frame (venc, frame_enc->frame);
gst_clear_mini_object ((GstMiniObject **) & frame_enc);
gst_clear_buffer (&frame_enc->output_buffer);
gst_video_encoder_finish_frame (venc, frame_enc);
}
if (!g_queue_is_empty (&self->output_list)) {
@ -3598,9 +3628,9 @@ error_and_purge_all:
" after drain", g_queue_get_length (&self->output_list));
while (!g_queue_is_empty (&self->output_list)) {
frame_enc = g_queue_pop_head (&self->output_list);
gst_clear_buffer (&frame_enc->frame->output_buffer);
gst_video_encoder_finish_frame (venc, frame_enc->frame);
gst_clear_mini_object ((GstMiniObject **) & frame_enc);
gst_video_codec_frame_unref (frame_enc);
gst_clear_buffer (&frame_enc->output_buffer);
gst_video_encoder_finish_frame (venc, frame_enc);
}
}
@ -3609,14 +3639,15 @@ error_and_purge_all:
" after drain", g_queue_get_length (&self->reorder_list));
while (!g_queue_is_empty (&self->reorder_list)) {
frame_enc = g_queue_pop_head (&self->reorder_list);
gst_clear_buffer (&frame_enc->frame->output_buffer);
gst_video_encoder_finish_frame (venc, frame_enc->frame);
gst_clear_mini_object ((GstMiniObject **) & frame_enc);
gst_video_codec_frame_unref (frame_enc);
gst_clear_buffer (&frame_enc->output_buffer);
gst_video_encoder_finish_frame (venc, frame_enc);
}
}
/* Also clear the reference list. */
g_queue_clear_full (&self->ref_list, (GDestroyNotify) gst_mini_object_unref);
g_queue_clear_full (&self->ref_list,
(GDestroyNotify) gst_video_codec_frame_unref);
return ret;
}