From f330b5ae6274d8008d0934a1811f44528e3bc807 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 28 Jul 2020 18:37:38 -0400 Subject: [PATCH] h265decoder: Sync with the H264 implementation This ensures that we get the last reference to picture being outputed, avoiding GstBuffer structure copies and simplifying the buffer management. Part-of: --- gst-libs/gst/codecs/gsth265decoder.c | 230 ++++++++++++++++++--------- gst-libs/gst/codecs/gsth265decoder.h | 24 ++- gst-libs/gst/codecs/gsth265picture.c | 71 ++++++++- gst-libs/gst/codecs/gsth265picture.h | 9 +- sys/d3d11/gstd3d11h265dec.c | 36 ++--- sys/nvcodec/gstnvh265dec.c | 41 +++-- 6 files changed, 286 insertions(+), 125 deletions(-) diff --git a/gst-libs/gst/codecs/gsth265decoder.c b/gst-libs/gst/codecs/gsth265decoder.c index 033d9f26b3..4b1c9b239a 100644 --- a/gst-libs/gst/codecs/gsth265decoder.c +++ b/gst-libs/gst/codecs/gsth265decoder.c @@ -77,7 +77,7 @@ struct _GstH265DecoderPrivate GstH265Picture *current_picture; GstVideoCodecFrame *current_frame; - /* Slice (slice header + nalu) currently being processed/decodec */ + /* Slice (slice header + nalu) currently being processed/decoded */ GstH265Slice current_slice; GstH265Slice prev_slice; GstH265Slice prev_independent_slice; @@ -101,6 +101,9 @@ struct _GstH265DecoderPrivate gboolean associated_irap_NoRaslOutputFlag; gboolean new_bitstream; gboolean prev_nal_is_eos; + + /* Cached array to handle pictures to be outputted */ + GArray *to_output; }; #define parent_class gst_h265_decoder_parent_class @@ -110,6 +113,8 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstH265Decoder, gst_h265_decoder, GST_DEBUG_CATEGORY_INIT (gst_h265_decoder_debug, "h265decoder", 0, "H.265 Video Decoder")); +static void gst_h265_decoder_finalize (GObject * object); + static gboolean gst_h265_decoder_start (GstVideoDecoder * decoder); static gboolean gst_h265_decoder_stop (GstVideoDecoder * decoder); static gboolean gst_h265_decoder_set_format (GstVideoDecoder * decoder, @@ -122,14 +127,16 @@ static GstFlowReturn gst_h265_decoder_handle_frame (GstVideoDecoder * decoder, static gboolean gst_h265_decoder_finish_current_picture (GstH265Decoder * self); static void gst_h265_decoder_clear_dpb (GstH265Decoder * self); -static gboolean -gst_h265_decoder_output_all_remaining_pics (GstH265Decoder * self); +static gboolean gst_h265_decoder_drain_internal (GstH265Decoder * self); static gboolean gst_h265_decoder_start_current_picture (GstH265Decoder * self); static void gst_h265_decoder_class_init (GstH265DecoderClass * klass) { GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = GST_DEBUG_FUNCPTR (gst_h265_decoder_finalize); decoder_class->start = GST_DEBUG_FUNCPTR (gst_h265_decoder_start); decoder_class->stop = GST_DEBUG_FUNCPTR (gst_h265_decoder_stop); @@ -144,9 +151,27 @@ gst_h265_decoder_class_init (GstH265DecoderClass * klass) static void gst_h265_decoder_init (GstH265Decoder * self) { + GstH265DecoderPrivate *priv; + gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE); - self->priv = gst_h265_decoder_get_instance_private (self); + self->priv = priv = gst_h265_decoder_get_instance_private (self); + + priv->to_output = g_array_sized_new (FALSE, TRUE, + sizeof (GstH265Picture *), 16); + g_array_set_clear_func (priv->to_output, + (GDestroyNotify) gst_h265_picture_clear); +} + +static void +gst_h265_decoder_finalize (GObject * object) +{ + GstH265Decoder *self = GST_H265_DECODER (object); + GstH265DecoderPrivate *priv = self->priv; + + g_array_unref (priv->to_output); + + G_OBJECT_CLASS (parent_class)->finalize (object); } static gboolean @@ -336,6 +361,7 @@ gst_h265_decoder_decode_slice (GstH265Decoder * self) g_assert (klass->decode_slice); + /* FIXME ref_pic_list0, ref_pic_list1 */ return klass->decode_slice (self, picture, slice); } @@ -398,20 +424,19 @@ gst_h265_decoder_parse_slice (GstH265Decoder * self, GstH265NalUnit * nalu, /* This allows accessing the frame from the picture. */ picture->system_frame_number = priv->current_frame->system_frame_number; + priv->current_picture = picture; + g_assert (priv->current_frame); + if (klass->new_picture) - ret = klass->new_picture (self, picture); + ret = klass->new_picture (self, priv->current_frame, picture); if (!ret) { GST_ERROR_OBJECT (self, "subclass does not want accept new picture"); + priv->current_picture = NULL; gst_h265_picture_unref (picture); return FALSE; } - priv->current_picture = picture; - gst_video_codec_frame_set_user_data (priv->current_frame, - gst_h265_picture_ref (priv->current_picture), - (GDestroyNotify) gst_h265_picture_unref); - if (!gst_h265_decoder_start_current_picture (self)) { GST_ERROR_OBJECT (self, "start picture failed"); return FALSE; @@ -700,8 +725,8 @@ gst_h265_decoder_drain (GstVideoDecoder * decoder) GstH265DecoderPrivate *priv = self->priv; priv->last_ret = GST_FLOW_OK; - gst_h265_decoder_output_all_remaining_pics (self); - gst_h265_decoder_clear_dpb (self); + /* dpb will be cleared by this method */ + gst_h265_decoder_drain_internal (self); return priv->last_ret; } @@ -1121,13 +1146,17 @@ gst_h265_decoder_clear_dpb (GstH265Decoder * self) static void gst_h265_decoder_do_output_picture (GstH265Decoder * self, - GstH265Picture * picture) + GstH265Picture * picture, gboolean clear_dpb) { GstH265DecoderPrivate *priv = self->priv; GstH265DecoderClass *klass; + GstVideoCodecFrame *frame = NULL; picture->outputted = TRUE; + if (clear_dpb && !picture->ref) + gst_h265_dpb_delete_by_poc (priv->dpb, picture->pic_order_cnt); + if (picture->pic_order_cnt < priv->last_output_poc) { GST_WARNING_OBJECT (self, "Outputting out of order %d -> %d, likely a broken stream", @@ -1136,50 +1165,69 @@ gst_h265_decoder_do_output_picture (GstH265Decoder * self, priv->last_output_poc = picture->pic_order_cnt; + frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self), + picture->system_frame_number); + + if (!frame) { + GST_ERROR_OBJECT (self, + "No available codec frame with frame number %d", + picture->system_frame_number); + priv->last_ret = GST_FLOW_ERROR; + gst_h265_picture_unref (picture); + + return; + } + klass = GST_H265_DECODER_GET_CLASS (self); g_assert (klass->output_picture); - priv->last_ret = klass->output_picture (self, picture); + priv->last_ret = klass->output_picture (self, frame, picture); } static gint -poc_asc_compare (const GstH265Picture * a, const GstH265Picture * b) +poc_asc_compare (const GstH265Picture ** a, const GstH265Picture ** b) { - return a->pic_order_cnt > b->pic_order_cnt; + return (*a)->pic_order_cnt > (*b)->pic_order_cnt; } static gboolean -gst_h265_decoder_output_all_remaining_pics (GstH265Decoder * self) +gst_h265_decoder_drain_internal (GstH265Decoder * self) { GstH265DecoderPrivate *priv = self->priv; - GList *to_output = NULL; - GList *iter; + GArray *to_output = priv->to_output; - gst_h265_dpb_get_pictures_not_outputted (priv->dpb, &to_output); + gst_h265_dpb_delete_outputted (priv->dpb); + gst_h265_dpb_get_pictures_not_outputted (priv->dpb, to_output); + g_array_sort (to_output, (GCompareFunc) poc_asc_compare); - to_output = g_list_sort (to_output, (GCompareFunc) poc_asc_compare); + while (to_output->len) { + GstH265Picture *picture = g_array_index (to_output, GstH265Picture *, 0); - for (iter = to_output; iter; iter = g_list_next (iter)) { - GstH265Picture *picture = (GstH265Picture *) iter->data; + /* We want the last reference when outputing so take a ref and then remove + * from both arrays. */ + gst_h265_picture_ref (picture); + g_array_remove_index (to_output, 0); + gst_h265_dpb_delete_by_poc (priv->dpb, picture->pic_order_cnt); GST_LOG_OBJECT (self, "Output picture %p (poc %d)", picture, picture->pic_order_cnt); - gst_h265_decoder_do_output_picture (self, picture); + gst_h265_decoder_do_output_picture (self, picture, FALSE); + picture = NULL; } - if (to_output) - g_list_free_full (to_output, (GDestroyNotify) gst_h265_picture_unref); - + g_array_set_size (to_output, 0); + gst_h265_dpb_clear (priv->dpb); + priv->last_output_poc = 0; return TRUE; } static gboolean -gst_h265_decoder_check_latency_count (GList * list, guint32 max_latency) +gst_h265_decoder_check_latency_count (GArray * array, guint32 max_latency) { - GList *iter; + gint i; - for (iter = list; iter; iter = g_list_next (iter)) { - GstH265Picture *pic = (GstH265Picture *) iter->data; + for (i = 0; i < array->len; i++) { + GstH265Picture *pic = g_array_index (array, GstH265Picture *, i); if (!pic->outputted && pic->pic_latency_cnt >= max_latency) return TRUE; } @@ -1263,24 +1311,22 @@ gst_h265_decoder_finish_picture (GstH265Decoder * self, { GstH265DecoderPrivate *priv = self->priv; const GstH265SPS *sps = priv->active_sps; - GList *not_outputted = NULL; + GArray *not_outputted = priv->to_output; guint num_remaining; - GList *iter; -#ifndef GST_DISABLE_GST_DEBUG gint i; -#endif GST_LOG_OBJECT (self, "Finishing picture %p (poc %d), entries in DPB %d", picture, picture->pic_order_cnt, gst_h265_dpb_get_size (priv->dpb)); /* Get all pictures that haven't been outputted yet */ - gst_h265_dpb_get_pictures_not_outputted (priv->dpb, ¬_outputted); + gst_h265_dpb_get_pictures_not_outputted (priv->dpb, not_outputted); /* C.5.2.3 */ if (picture->output_flag) { - for (iter = not_outputted; iter; iter = g_list_next (iter)) { - GstH265Picture *other = GST_H265_PICTURE (iter->data); + for (i = 0; i < not_outputted->len; i++) { + GstH265Picture *other = + g_array_index (not_outputted, GstH265Picture *, i); if (!other->outputted) other->pic_latency_cnt++; @@ -1297,40 +1343,29 @@ gst_h265_decoder_finish_picture (GstH265Decoder * self, picture->long_term = FALSE; /* Include the one we've just decoded */ - if (picture->output_flag) { - not_outputted = - g_list_append (not_outputted, gst_h265_picture_ref (picture)); - } - - /* Add to dpb and transfer ownership */ - gst_h265_dpb_add (priv->dpb, picture); + if (picture->output_flag) + g_array_append_val (not_outputted, picture); /* for debugging */ #ifndef GST_DISABLE_GST_DEBUG GST_TRACE_OBJECT (self, "Before sorting not outputted list"); - i = 0; - for (iter = not_outputted; iter; iter = g_list_next (iter)) { - GstH265Picture *tmp = (GstH265Picture *) iter->data; - + for (i = 0; i < not_outputted->len; i++) { + GstH265Picture *tmp = g_array_index (not_outputted, GstH265Picture *, i); GST_TRACE_OBJECT (self, "\t%dth picture %p (poc %d)", i, tmp, tmp->pic_order_cnt); - i++; } #endif /* Sort in output order */ - not_outputted = g_list_sort (not_outputted, (GCompareFunc) poc_asc_compare); + g_array_sort (not_outputted, (GCompareFunc) poc_asc_compare); #ifndef GST_DISABLE_GST_DEBUG GST_TRACE_OBJECT (self, "After sorting not outputted list in poc ascending order"); - i = 0; - for (iter = not_outputted; iter; iter = g_list_next (iter)) { - GstH265Picture *tmp = (GstH265Picture *) iter->data; - + for (i = 0; i < not_outputted->len; i++) { + GstH265Picture *tmp = g_array_index (not_outputted, GstH265Picture *, i); GST_TRACE_OBJECT (self, "\t%dth picture %p (poc %d)", i, tmp, tmp->pic_order_cnt); - i++; } #endif @@ -1339,36 +1374,61 @@ gst_h265_decoder_finish_picture (GstH265Decoder * self, * in DPB afterwards would at least be equal to max_num_reorder_frames. * If the outputted picture is not a reference picture, it doesn't have * to remain in the DPB and can be removed */ - iter = not_outputted; - num_remaining = g_list_length (not_outputted); + num_remaining = not_outputted->len; while (num_remaining > sps->max_num_reorder_pics[sps->max_sub_layers_minus1] || (num_remaining && sps->max_latency_increase_plus1[sps->max_sub_layers_minus1] && - gst_h265_decoder_check_latency_count (iter, + gst_h265_decoder_check_latency_count (not_outputted, priv->SpsMaxLatencyPictures))) { - GstH265Picture *to_output = GST_H265_PICTURE (iter->data); + gboolean clear_dpb = TRUE; + GstH265Picture *to_output = + g_array_index (not_outputted, GstH265Picture *, 0); + + gst_h265_picture_ref (to_output); + g_array_remove_index (not_outputted, 0); GST_LOG_OBJECT (self, "Output picture %p (poc %d)", to_output, to_output->pic_order_cnt); - gst_h265_decoder_do_output_picture (self, to_output); - if (!to_output->ref) { - /* Current picture hasn't been inserted into DPB yet, so don't remove it - * if we managed to output it immediately */ - gint outputted_poc = to_output->pic_order_cnt; - if (outputted_poc != picture->pic_order_cnt) { - GST_LOG_OBJECT (self, "Delete picture %p (poc %d) from DPB", - to_output, to_output->pic_order_cnt); - gst_h265_dpb_delete_by_poc (priv->dpb, outputted_poc); + + /* Current picture hasn't been inserted into DPB yet, so don't remove it + * if we managed to output it immediately */ + if (picture && to_output == picture) { + clear_dpb = FALSE; + + if (picture->ref) { + GST_TRACE_OBJECT (self, + "Put current picture %p (poc %d) to dpb", + picture, picture->pic_order_cnt); + gst_h265_dpb_add (priv->dpb, gst_h265_picture_ref (picture)); } + + /* and mark current picture as handled */ + picture = NULL; } - iter = g_list_next (iter); + gst_h265_decoder_do_output_picture (self, to_output, clear_dpb); + num_remaining--; } - if (not_outputted) - g_list_free_full (not_outputted, (GDestroyNotify) gst_h265_picture_unref); + /* If we haven't managed to output the picture that we just decoded, or if + * it's a reference picture, we have to store it in DPB */ + if (picture && (!picture->outputted || picture->ref)) { + if (gst_h265_dpb_is_full (priv->dpb)) { + /* If we haven't managed to output anything to free up space in DPB + * to store this picture, it's an error in the stream */ + GST_WARNING_OBJECT (self, "Could not free up space in DPB"); + return FALSE; + } + + GST_TRACE_OBJECT (self, + "Put picture %p (outputted %d, ref %d, poc %d) to dpb", + picture, picture->outputted, picture->ref, picture->pic_order_cnt); + gst_h265_dpb_add (priv->dpb, gst_h265_picture_ref (picture)); + } + + g_array_set_size (not_outputted, 0); return TRUE; } @@ -1420,7 +1480,12 @@ gst_h265_decoder_handle_frame (GstVideoDecoder * decoder, priv->current_frame = frame; priv->last_ret = GST_FLOW_OK; - gst_buffer_map (in_buf, &map, GST_MAP_READ); + if (!gst_buffer_map (in_buf, &map, GST_MAP_READ)) { + GST_ELEMENT_ERROR (self, RESOURCE, READ, + ("Failed to map memory for reading"), (NULL)); + return GST_FLOW_ERROR; + } + if (priv->in_format == GST_H265_DECODER_FORMAT_HVC1 || priv->in_format == GST_H265_DECODER_FORMAT_HEV1) { pres = gst_h265_parser_identify_nalu_hevc (priv->parser, @@ -1471,3 +1536,22 @@ gst_h265_decoder_handle_frame (GstVideoDecoder * decoder, return priv->last_ret; } + +/** + * gst_h265_decoder_get_picture: + * @decoder: a #GstH265Decoder + * @system_frame_number: a target system frame number of #GstH265Picture + * + * Retrive DPB and return a #GstH265Picture corresponding to + * the @system_frame_number + * + * Returns: (transfer full): a #GstH265Picture if successful, or %NULL otherwise + * + * Since: 1.20 + */ +GstH265Picture * +gst_h265_decoder_get_picture (GstH265Decoder * decoder, + guint32 system_frame_number) +{ + return gst_h265_dpb_get_picture (decoder->priv->dpb, system_frame_number); +} diff --git a/gst-libs/gst/codecs/gsth265decoder.h b/gst-libs/gst/codecs/gsth265decoder.h index b688e278d6..6e9e3397d8 100644 --- a/gst-libs/gst/codecs/gsth265decoder.h +++ b/gst-libs/gst/codecs/gsth265decoder.h @@ -87,9 +87,7 @@ struct _GstH265Decoder * Called per one #GstH265Picture to notify subclass to finish * decoding process for the #GstH265Picture * @output_picture: Called with a #GstH265Picture which is required to be outputted. - * Subclass can retrieve parent #GstVideoCodecFrame by using - * gst_video_decoder_get_frame() with system_frame_number - * and the #GstVideoCodecFrame must be consumed by subclass via + * The #GstVideoCodecFrame must be consumed by subclass via * gst_video_decoder_{finish,drop,release}_frame(). */ struct _GstH265DecoderClass @@ -99,8 +97,14 @@ struct _GstH265DecoderClass gboolean (*new_sequence) (GstH265Decoder * decoder, const GstH265SPS * sps, gint max_dpb_size); - + /** + * GstH265Decoder:new_picture: + * @decoder: a #GstH265Decoder + * @frame: (transfer none): a #GstVideoCodecFrame + * @picture: (transfer none): a #GstH265Picture + */ gboolean (*new_picture) (GstH265Decoder * decoder, + GstVideoCodecFrame * frame, GstH265Picture * picture); gboolean (*start_picture) (GstH265Decoder * decoder, @@ -114,8 +118,14 @@ struct _GstH265DecoderClass gboolean (*end_picture) (GstH265Decoder * decoder, GstH265Picture * picture); - + /** + * GstH265Decoder:output_picture: + * @decoder: a #GstH265Decoder + * @frame: (transfer full): a #GstVideoCodecFrame + * @picture: (transfer full): a #GstH265Picture + */ GstFlowReturn (*output_picture) (GstH265Decoder * decoder, + GstVideoCodecFrame * frame, GstH265Picture * picture); /*< private >*/ @@ -127,6 +137,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstH265Decoder, gst_object_unref) GST_CODECS_API GType gst_h265_decoder_get_type (void); +GST_CODECS_API +GstH265Picture * gst_h265_decoder_get_picture (GstH265Decoder * decoder, + guint32 system_frame_number); + G_END_DECLS #endif /* __GST_H265_DECODER_H__ */ diff --git a/gst-libs/gst/codecs/gsth265picture.c b/gst-libs/gst/codecs/gsth265picture.c index 0c7fb87140..69cd3556c8 100644 --- a/gst-libs/gst/codecs/gsth265picture.c +++ b/gst-libs/gst/codecs/gsth265picture.c @@ -231,6 +231,34 @@ gst_h265_dpb_delete_unused (GstH265Dpb * dpb) } } +/** + * gst_h265_dpb_delete_outputted: + * @dpb: a #GstH265Dpb + * + * Delete already outputted picture, even if they are referenced. + * + * Since: 1.20 + */ +void +gst_h265_dpb_delete_outputted (GstH265Dpb * dpb) +{ + gint i; + + g_return_if_fail (dpb != NULL); + + for (i = 0; i < dpb->pic_list->len; i++) { + GstH265Picture *picture = + g_array_index (dpb->pic_list, GstH265Picture *, i); + + if (picture->outputted) { + GST_TRACE ("remove picture %p (poc %d) from dpb", + picture, picture->pic_order_cnt); + g_array_remove_index_fast (dpb->pic_list, i); + i--; + } + } +} + /** * gst_h265_dpb_delete_by_poc: * @dpb: a #GstH265Dpb @@ -423,13 +451,13 @@ gst_h265_dpb_get_long_ref_by_poc (GstH265Dpb * dpb, gint poc) /** * gst_h265_dpb_get_pictures_not_outputted: * @dpb: a #GstH265Dpb - * @out: (out) (element-type GstH265Picture) (transfer full): a list - * of #GstH265Dpb + * @out: (out) (element-type GstH265Picture) (transfer full): an array + * of #GstH265Picture pointer * * Retrieve all not-outputted pictures from @dpb */ void -gst_h265_dpb_get_pictures_not_outputted (GstH265Dpb * dpb, GList ** out) +gst_h265_dpb_get_pictures_not_outputted (GstH265Dpb * dpb, GArray * out) { gint i; @@ -440,8 +468,10 @@ gst_h265_dpb_get_pictures_not_outputted (GstH265Dpb * dpb, GList ** out) GstH265Picture *picture = g_array_index (dpb->pic_list, GstH265Picture *, i); - if (!picture->outputted) - *out = g_list_append (*out, gst_h265_picture_ref (picture)); + if (!picture->outputted) { + gst_h265_picture_ref (picture); + g_array_append_val (out, picture); + } } } @@ -487,3 +517,34 @@ gst_h265_dpb_is_full (GstH265Dpb * dpb) return dpb->pic_list->len >= dpb->max_num_pics; } + +/** + * gst_h265_dpb_get_picture: + * @dpb: a #GstH265Dpb + * @system_frame_number The system frame number + * + * Returns: (transfer full): the picture identified with the specified + * @system_frame_number, or %NULL if DPB does not contain a #GstH265Picture + * corresponding to the @system_frame_number + * + * Since: 1.20 + */ +GstH265Picture * +gst_h265_dpb_get_picture (GstH265Dpb * dpb, guint32 system_frame_number) +{ + gint i; + + g_return_val_if_fail (dpb != NULL, NULL); + + for (i = 0; i < dpb->pic_list->len; i++) { + GstH265Picture *picture = + g_array_index (dpb->pic_list, GstH265Picture *, i); + + if (picture->system_frame_number == system_frame_number) { + gst_h265_picture_ref (picture); + return picture; + } + } + + return NULL; +} diff --git a/gst-libs/gst/codecs/gsth265picture.h b/gst-libs/gst/codecs/gsth265picture.h index 38dd5b3628..b1155ceeb8 100644 --- a/gst-libs/gst/codecs/gsth265picture.h +++ b/gst-libs/gst/codecs/gsth265picture.h @@ -160,6 +160,9 @@ void gst_h265_dpb_add (GstH265Dpb * dpb, GST_CODECS_API void gst_h265_dpb_delete_unused (GstH265Dpb * dpb); +GST_CODECS_API +void gst_h265_dpb_delete_outputted (GstH265Dpb * dpb); + GST_CODECS_API void gst_h265_dpb_delete_by_poc (GstH265Dpb * dpb, gint poc); @@ -188,11 +191,15 @@ GstH265Picture * gst_h265_dpb_get_long_ref_by_poc (GstH265Dpb * dpb, GST_CODECS_API void gst_h265_dpb_get_pictures_not_outputted (GstH265Dpb * dpb, - GList ** out); + GArray * out); GST_CODECS_API GArray * gst_h265_dpb_get_pictures_all (GstH265Dpb * dpb); +GST_CODECS_API +GstH265Picture * gst_h265_dpb_get_picture (GstH265Dpb * dpb, + guint32 system_frame_number); + GST_CODECS_API gint gst_h265_dpb_get_size (GstH265Dpb * dpb); diff --git a/sys/d3d11/gstd3d11h265dec.c b/sys/d3d11/gstd3d11h265dec.c index 375ce8bad0..b395c1bc84 100644 --- a/sys/d3d11/gstd3d11h265dec.c +++ b/sys/d3d11/gstd3d11h265dec.c @@ -120,9 +120,9 @@ static gboolean gst_d3d11_h265_dec_src_query (GstVideoDecoder * decoder, static gboolean gst_d3d11_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps, gint max_dpb_size); static gboolean gst_d3d11_h265_dec_new_picture (GstH265Decoder * decoder, - GstH265Picture * picture); + GstVideoCodecFrame * cframe, GstH265Picture * picture); static GstFlowReturn gst_d3d11_h265_dec_output_picture (GstH265Decoder * - decoder, GstH265Picture * picture); + decoder, GstVideoCodecFrame * frame, GstH265Picture * picture); static gboolean gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder, GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb); static gboolean gst_d3d11_h265_dec_decode_slice (GstH265Decoder * decoder, @@ -624,7 +624,7 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder, static gboolean gst_d3d11_h265_dec_new_picture (GstH265Decoder * decoder, - GstH265Picture * picture) + GstVideoCodecFrame * cframe, GstH265Picture * picture) { GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder); GstBuffer *view_buffer; @@ -651,10 +651,10 @@ gst_d3d11_h265_dec_new_picture (GstH265Decoder * decoder, static GstFlowReturn gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder, - GstH265Picture * picture) + GstVideoCodecFrame * frame, GstH265Picture * picture) { GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder); - GstVideoCodecFrame *frame = NULL; + GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder); GstBuffer *output_buffer = NULL; GstBuffer *view_buffer; @@ -665,16 +665,7 @@ gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder, if (!view_buffer) { GST_ERROR_OBJECT (self, "Could not get output view"); - return GST_FLOW_ERROR; - } - - frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self), - picture->system_frame_number); - - /* FIXME: Sync with other codec implementation */ - if (!frame) { - GST_ERROR_OBJECT (self, "Couldn't get codec frame"); - return GST_FLOW_ERROR; + goto error; } /* if downstream is d3d11 element and forward playback case, @@ -696,9 +687,7 @@ gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder, if (!output_buffer) { GST_ERROR_OBJECT (self, "Couldn't allocate output buffer"); - gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); - - return GST_FLOW_ERROR; + goto error; } frame->output_buffer = output_buffer; @@ -710,11 +699,18 @@ gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder, view_buffer, output_buffer)) { GST_ERROR_OBJECT (self, "Failed to copy buffer"); gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); - - return GST_FLOW_ERROR; + goto error; } + gst_h265_picture_unref (picture); + return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); + +error: + gst_video_decoder_drop_frame (vdec, frame); + gst_h265_picture_unref (picture); + + return GST_FLOW_ERROR; } static gboolean diff --git a/sys/nvcodec/gstnvh265dec.c b/sys/nvcodec/gstnvh265dec.c index 36b7818cfe..b15fb1166e 100644 --- a/sys/nvcodec/gstnvh265dec.c +++ b/sys/nvcodec/gstnvh265dec.c @@ -146,9 +146,9 @@ static gboolean gst_nv_h265_dec_src_query (GstVideoDecoder * decoder, static gboolean gst_nv_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps, gint max_dpb_size); static gboolean gst_nv_h265_dec_new_picture (GstH265Decoder * decoder, - GstH265Picture * picture); + GstVideoCodecFrame * frame, GstH265Picture * picture); static GstFlowReturn gst_nv_h265_dec_output_picture (GstH265Decoder * - decoder, GstH265Picture * picture); + decoder, GstVideoCodecFrame * frame, GstH265Picture * picture); static gboolean gst_nv_h265_dec_start_picture (GstH265Decoder * decoder, GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb); static gboolean gst_nv_h265_dec_decode_slice (GstH265Decoder * decoder, @@ -414,7 +414,8 @@ gst_nv_h265_dec_new_sequence (GstH265Decoder * decoder, const GstH265SPS * sps, } static gboolean -gst_nv_h265_dec_new_picture (GstH265Decoder * decoder, GstH265Picture * picture) +gst_nv_h265_dec_new_picture (GstH265Decoder * decoder, + GstVideoCodecFrame * cframe, GstH265Picture * picture) { GstNvH265Dec *self = GST_NV_H265_DEC (decoder); GstNvDecoderFrame *frame; @@ -435,11 +436,10 @@ gst_nv_h265_dec_new_picture (GstH265Decoder * decoder, GstH265Picture * picture) static GstFlowReturn gst_nv_h265_dec_output_picture (GstH265Decoder * decoder, - GstH265Picture * picture) + GstVideoCodecFrame * frame, GstH265Picture * picture) { GstNvH265Dec *self = GST_NV_H265_DEC (decoder); - GstVideoCodecFrame *frame = NULL; - GstBuffer *output_buffer = NULL; + GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder); GstNvDecoderFrame *decoder_frame; gboolean ret G_GNUC_UNUSED = FALSE; @@ -450,24 +450,16 @@ gst_nv_h265_dec_output_picture (GstH265Decoder * decoder, (GstNvDecoderFrame *) gst_h265_picture_get_user_data (picture); if (!decoder_frame) { GST_ERROR_OBJECT (self, "No decoder frame in picture %p", picture); - return GST_FLOW_ERROR; + goto error; } - frame = gst_video_decoder_get_frame (GST_VIDEO_DECODER (self), - picture->system_frame_number); - if (!frame) { - GST_ERROR_OBJECT (self, "Failed to retrieve codec frame"); - return GST_FLOW_ERROR; - } - - output_buffer = - gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self)); - frame->output_buffer = output_buffer; + frame->output_buffer = + gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self));; if (self->output_type == GST_NV_DECOCER_OUTPUT_TYPE_GL) { ret = gst_nv_decoder_finish_frame (self->decoder, GST_NV_DECOCER_OUTPUT_TYPE_GL, self->gl_context, - decoder_frame, output_buffer); + decoder_frame, frame->output_buffer); /* FIXME: This is the case where OpenGL context of downstream glbufferpool * belongs to non-nvidia (or different device). @@ -483,14 +475,21 @@ gst_nv_h265_dec_output_picture (GstH265Decoder * decoder, if (!ret) { if (!gst_nv_decoder_finish_frame (self->decoder, GST_NV_DECOCER_OUTPUT_TYPE_SYSTEM, NULL, decoder_frame, - output_buffer)) { + frame->output_buffer)) { GST_ERROR_OBJECT (self, "Failed to finish frame"); - gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); - return GST_FLOW_ERROR; + goto error; } } + gst_h265_picture_unref (picture); + return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); + +error: + gst_video_decoder_drop_frame (vdec, frame); + gst_h265_picture_unref (picture); + + return GST_FLOW_ERROR; } static GstNvDecoderFrame *