From ac23e04236b0f1d71f66e3d3fa20695525972450 Mon Sep 17 00:00:00 2001 From: He Junyan Date: Thu, 14 Mar 2024 23:17:32 +0800 Subject: [PATCH] va: av1enc: Improve the LAST reference assignment The last frame which has the smallest diff should be consider as the first choice rather than the golden frame. Especially when only one reference available, this way can improve the BD rate about 5 percentage. Part-of: --- .../gst-plugins-bad/sys/va/gstvaav1enc.c | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/va/gstvaav1enc.c b/subprojects/gst-plugins-bad/sys/va/gstvaav1enc.c index a0a0b91333..a8207041fd 100644 --- a/subprojects/gst-plugins-bad/sys/va/gstvaav1enc.c +++ b/subprojects/gst-plugins-bad/sys/va/gstvaav1enc.c @@ -1419,6 +1419,7 @@ _av1_assign_ref_index (GstVaAV1Enc * self, GstVideoCodecFrame * frame) gint forward_ref_num, backward_ref_num;; GstVaAV1EncFrame *va_frame = _enc_frame (frame); gint i, num; + gboolean gf_assigned; memset (va_frame->ref_frame_idx, -1, sizeof (va_frame->ref_frame_idx)); @@ -1482,36 +1483,53 @@ _av1_assign_ref_index (GstVaAV1Enc * self, GstVideoCodecFrame * frame) g_qsort_with_data (all_refs, ref_num, sizeof (GstVaAV1Ref), _av1_sort_by_frame_num, NULL); - /* Setting the forward refs. GOLDEN is always set first. - LAST is set to the nearest frame in the past if forward_ref_num - is enough. LAST2 and LAST3 are set to next nearest frames in the - past if forward_ref_num is enough. - If forward_ref_num is not enough, they are just set to GOLDEN. */ + /* Assign the forward references in order of: + * 1. The last frame which has the smallest diff. + * 2. The golden frame which can be a key frame with better quality. + * 3. The other frames by inverse frame number order. + */ va_frame->bidir_ref = FALSE; + gf_assigned = FALSE; num = forward_num - 1; - if (backward_num > 0) { - forward_ref_num = self->gop.forward_ref_num - 1 /* already assign gf */ ; - } else { - /* if forward only, should use forward_only_ref_num */ - forward_ref_num = - self->gop.forward_only_ref_num - 1 /* already assign gf */ ; - } + g_assert (num >= 0); + /* if forward only, should use forward_only_ref_num */ + forward_ref_num = backward_num > 0 ? + self->gop.forward_ref_num : self->gop.forward_only_ref_num; + g_assert (forward_ref_num > 0); - if (num >= 0 && all_refs[num].index_in_dpb == - va_frame->ref_frame_idx[GST_AV1_REF_GOLDEN_FRAME]) + /* The golden frame happens to be the last frame. */ + if (all_refs[num].index_in_dpb == + va_frame->ref_frame_idx[GST_AV1_REF_GOLDEN_FRAME]) { num--; + forward_ref_num--; + gf_assigned = TRUE; + } if (num >= 0 && forward_ref_num > 0) { va_frame->ref_frame_idx[GST_AV1_REF_LAST_FRAME] = all_refs[num].index_in_dpb; } else { + /* At least one forward reference. + Just let the last frame be the same as the golden frame. */ + g_assert (gf_assigned); va_frame->ref_frame_idx[GST_AV1_REF_LAST_FRAME] = va_frame->ref_frame_idx[GST_AV1_REF_GOLDEN_FRAME]; } num--; forward_ref_num--; + + if (!gf_assigned) { + if (forward_ref_num <= 0) { + va_frame->ref_frame_idx[GST_AV1_REF_GOLDEN_FRAME] = + va_frame->ref_frame_idx[GST_AV1_REF_LAST_FRAME]; + } else { + /* The golden frame index is already found. */ + forward_ref_num--; + } + } + if (num >= 0 && all_refs[num].index_in_dpb == va_frame->ref_frame_idx[GST_AV1_REF_GOLDEN_FRAME]) num--; @@ -1521,7 +1539,7 @@ _av1_assign_ref_index (GstVaAV1Enc * self, GstVideoCodecFrame * frame) all_refs[num].index_in_dpb; } else { va_frame->ref_frame_idx[GST_AV1_REF_LAST2_FRAME] = - va_frame->ref_frame_idx[GST_AV1_REF_GOLDEN_FRAME]; + va_frame->ref_frame_idx[GST_AV1_REF_LAST_FRAME]; } num--; @@ -1535,7 +1553,7 @@ _av1_assign_ref_index (GstVaAV1Enc * self, GstVideoCodecFrame * frame) all_refs[num].index_in_dpb; } else { va_frame->ref_frame_idx[GST_AV1_REF_LAST3_FRAME] = - va_frame->ref_frame_idx[GST_AV1_REF_GOLDEN_FRAME]; + va_frame->ref_frame_idx[GST_AV1_REF_LAST_FRAME]; } /* Setting the backward refs */