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: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1713>
This commit is contained in:
Nicolas Dufresne 2020-07-28 18:37:38 -04:00
parent f615677051
commit f330b5ae62
6 changed files with 286 additions and 125 deletions

View file

@ -77,7 +77,7 @@ struct _GstH265DecoderPrivate
GstH265Picture *current_picture; GstH265Picture *current_picture;
GstVideoCodecFrame *current_frame; GstVideoCodecFrame *current_frame;
/* Slice (slice header + nalu) currently being processed/decodec */ /* Slice (slice header + nalu) currently being processed/decoded */
GstH265Slice current_slice; GstH265Slice current_slice;
GstH265Slice prev_slice; GstH265Slice prev_slice;
GstH265Slice prev_independent_slice; GstH265Slice prev_independent_slice;
@ -101,6 +101,9 @@ struct _GstH265DecoderPrivate
gboolean associated_irap_NoRaslOutputFlag; gboolean associated_irap_NoRaslOutputFlag;
gboolean new_bitstream; gboolean new_bitstream;
gboolean prev_nal_is_eos; gboolean prev_nal_is_eos;
/* Cached array to handle pictures to be outputted */
GArray *to_output;
}; };
#define parent_class gst_h265_decoder_parent_class #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, GST_DEBUG_CATEGORY_INIT (gst_h265_decoder_debug, "h265decoder", 0,
"H.265 Video Decoder")); "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_start (GstVideoDecoder * decoder);
static gboolean gst_h265_decoder_stop (GstVideoDecoder * decoder); static gboolean gst_h265_decoder_stop (GstVideoDecoder * decoder);
static gboolean gst_h265_decoder_set_format (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 gboolean gst_h265_decoder_finish_current_picture (GstH265Decoder * self);
static void gst_h265_decoder_clear_dpb (GstH265Decoder * self); static void gst_h265_decoder_clear_dpb (GstH265Decoder * self);
static gboolean static gboolean gst_h265_decoder_drain_internal (GstH265Decoder * self);
gst_h265_decoder_output_all_remaining_pics (GstH265Decoder * self);
static gboolean gst_h265_decoder_start_current_picture (GstH265Decoder * self); static gboolean gst_h265_decoder_start_current_picture (GstH265Decoder * self);
static void static void
gst_h265_decoder_class_init (GstH265DecoderClass * klass) gst_h265_decoder_class_init (GstH265DecoderClass * klass)
{ {
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (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->start = GST_DEBUG_FUNCPTR (gst_h265_decoder_start);
decoder_class->stop = GST_DEBUG_FUNCPTR (gst_h265_decoder_stop); decoder_class->stop = GST_DEBUG_FUNCPTR (gst_h265_decoder_stop);
@ -144,9 +151,27 @@ gst_h265_decoder_class_init (GstH265DecoderClass * klass)
static void static void
gst_h265_decoder_init (GstH265Decoder * self) gst_h265_decoder_init (GstH265Decoder * self)
{ {
GstH265DecoderPrivate *priv;
gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE); 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 static gboolean
@ -336,6 +361,7 @@ gst_h265_decoder_decode_slice (GstH265Decoder * self)
g_assert (klass->decode_slice); g_assert (klass->decode_slice);
/* FIXME ref_pic_list0, ref_pic_list1 */
return klass->decode_slice (self, picture, slice); 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. */ /* This allows accessing the frame from the picture. */
picture->system_frame_number = priv->current_frame->system_frame_number; picture->system_frame_number = priv->current_frame->system_frame_number;
priv->current_picture = picture;
g_assert (priv->current_frame);
if (klass->new_picture) if (klass->new_picture)
ret = klass->new_picture (self, picture); ret = klass->new_picture (self, priv->current_frame, picture);
if (!ret) { if (!ret) {
GST_ERROR_OBJECT (self, "subclass does not want accept new picture"); GST_ERROR_OBJECT (self, "subclass does not want accept new picture");
priv->current_picture = NULL;
gst_h265_picture_unref (picture); gst_h265_picture_unref (picture);
return FALSE; 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)) { if (!gst_h265_decoder_start_current_picture (self)) {
GST_ERROR_OBJECT (self, "start picture failed"); GST_ERROR_OBJECT (self, "start picture failed");
return FALSE; return FALSE;
@ -700,8 +725,8 @@ gst_h265_decoder_drain (GstVideoDecoder * decoder)
GstH265DecoderPrivate *priv = self->priv; GstH265DecoderPrivate *priv = self->priv;
priv->last_ret = GST_FLOW_OK; priv->last_ret = GST_FLOW_OK;
gst_h265_decoder_output_all_remaining_pics (self); /* dpb will be cleared by this method */
gst_h265_decoder_clear_dpb (self); gst_h265_decoder_drain_internal (self);
return priv->last_ret; return priv->last_ret;
} }
@ -1121,13 +1146,17 @@ gst_h265_decoder_clear_dpb (GstH265Decoder * self)
static void static void
gst_h265_decoder_do_output_picture (GstH265Decoder * self, gst_h265_decoder_do_output_picture (GstH265Decoder * self,
GstH265Picture * picture) GstH265Picture * picture, gboolean clear_dpb)
{ {
GstH265DecoderPrivate *priv = self->priv; GstH265DecoderPrivate *priv = self->priv;
GstH265DecoderClass *klass; GstH265DecoderClass *klass;
GstVideoCodecFrame *frame = NULL;
picture->outputted = TRUE; 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) { if (picture->pic_order_cnt < priv->last_output_poc) {
GST_WARNING_OBJECT (self, GST_WARNING_OBJECT (self,
"Outputting out of order %d -> %d, likely a broken stream", "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; 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); klass = GST_H265_DECODER_GET_CLASS (self);
g_assert (klass->output_picture); g_assert (klass->output_picture);
priv->last_ret = klass->output_picture (self, picture); priv->last_ret = klass->output_picture (self, frame, picture);
} }
static gint 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 static gboolean
gst_h265_decoder_output_all_remaining_pics (GstH265Decoder * self) gst_h265_decoder_drain_internal (GstH265Decoder * self)
{ {
GstH265DecoderPrivate *priv = self->priv; GstH265DecoderPrivate *priv = self->priv;
GList *to_output = NULL; GArray *to_output = priv->to_output;
GList *iter;
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)) { /* We want the last reference when outputing so take a ref and then remove
GstH265Picture *picture = (GstH265Picture *) iter->data; * 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, GST_LOG_OBJECT (self, "Output picture %p (poc %d)", picture,
picture->pic_order_cnt); 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_array_set_size (to_output, 0);
g_list_free_full (to_output, (GDestroyNotify) gst_h265_picture_unref); gst_h265_dpb_clear (priv->dpb);
priv->last_output_poc = 0;
return TRUE; return TRUE;
} }
static gboolean 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)) { for (i = 0; i < array->len; i++) {
GstH265Picture *pic = (GstH265Picture *) iter->data; GstH265Picture *pic = g_array_index (array, GstH265Picture *, i);
if (!pic->outputted && pic->pic_latency_cnt >= max_latency) if (!pic->outputted && pic->pic_latency_cnt >= max_latency)
return TRUE; return TRUE;
} }
@ -1263,24 +1311,22 @@ gst_h265_decoder_finish_picture (GstH265Decoder * self,
{ {
GstH265DecoderPrivate *priv = self->priv; GstH265DecoderPrivate *priv = self->priv;
const GstH265SPS *sps = priv->active_sps; const GstH265SPS *sps = priv->active_sps;
GList *not_outputted = NULL; GArray *not_outputted = priv->to_output;
guint num_remaining; guint num_remaining;
GList *iter;
#ifndef GST_DISABLE_GST_DEBUG
gint i; gint i;
#endif
GST_LOG_OBJECT (self, GST_LOG_OBJECT (self,
"Finishing picture %p (poc %d), entries in DPB %d", "Finishing picture %p (poc %d), entries in DPB %d",
picture, picture->pic_order_cnt, gst_h265_dpb_get_size (priv->dpb)); picture, picture->pic_order_cnt, gst_h265_dpb_get_size (priv->dpb));
/* Get all pictures that haven't been outputted yet */ /* Get all pictures that haven't been outputted yet */
gst_h265_dpb_get_pictures_not_outputted (priv->dpb, &not_outputted); gst_h265_dpb_get_pictures_not_outputted (priv->dpb, not_outputted);
/* C.5.2.3 */ /* C.5.2.3 */
if (picture->output_flag) { if (picture->output_flag) {
for (iter = not_outputted; iter; iter = g_list_next (iter)) { for (i = 0; i < not_outputted->len; i++) {
GstH265Picture *other = GST_H265_PICTURE (iter->data); GstH265Picture *other =
g_array_index (not_outputted, GstH265Picture *, i);
if (!other->outputted) if (!other->outputted)
other->pic_latency_cnt++; other->pic_latency_cnt++;
@ -1297,40 +1343,29 @@ gst_h265_decoder_finish_picture (GstH265Decoder * self,
picture->long_term = FALSE; picture->long_term = FALSE;
/* Include the one we've just decoded */ /* Include the one we've just decoded */
if (picture->output_flag) { if (picture->output_flag)
not_outputted = g_array_append_val (not_outputted, picture);
g_list_append (not_outputted, gst_h265_picture_ref (picture));
}
/* Add to dpb and transfer ownership */
gst_h265_dpb_add (priv->dpb, picture);
/* for debugging */ /* for debugging */
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
GST_TRACE_OBJECT (self, "Before sorting not outputted list"); GST_TRACE_OBJECT (self, "Before sorting not outputted list");
i = 0; for (i = 0; i < not_outputted->len; i++) {
for (iter = not_outputted; iter; iter = g_list_next (iter)) { GstH265Picture *tmp = g_array_index (not_outputted, GstH265Picture *, i);
GstH265Picture *tmp = (GstH265Picture *) iter->data;
GST_TRACE_OBJECT (self, GST_TRACE_OBJECT (self,
"\t%dth picture %p (poc %d)", i, tmp, tmp->pic_order_cnt); "\t%dth picture %p (poc %d)", i, tmp, tmp->pic_order_cnt);
i++;
} }
#endif #endif
/* Sort in output order */ /* 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 #ifndef GST_DISABLE_GST_DEBUG
GST_TRACE_OBJECT (self, GST_TRACE_OBJECT (self,
"After sorting not outputted list in poc ascending order"); "After sorting not outputted list in poc ascending order");
i = 0; for (i = 0; i < not_outputted->len; i++) {
for (iter = not_outputted; iter; iter = g_list_next (iter)) { GstH265Picture *tmp = g_array_index (not_outputted, GstH265Picture *, i);
GstH265Picture *tmp = (GstH265Picture *) iter->data;
GST_TRACE_OBJECT (self, GST_TRACE_OBJECT (self,
"\t%dth picture %p (poc %d)", i, tmp, tmp->pic_order_cnt); "\t%dth picture %p (poc %d)", i, tmp, tmp->pic_order_cnt);
i++;
} }
#endif #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. * 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 * If the outputted picture is not a reference picture, it doesn't have
* to remain in the DPB and can be removed */ * to remain in the DPB and can be removed */
iter = not_outputted; num_remaining = not_outputted->len;
num_remaining = g_list_length (not_outputted);
while (num_remaining > sps->max_num_reorder_pics[sps->max_sub_layers_minus1] while (num_remaining > sps->max_num_reorder_pics[sps->max_sub_layers_minus1]
|| (num_remaining && || (num_remaining &&
sps->max_latency_increase_plus1[sps->max_sub_layers_minus1] && 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))) { 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, GST_LOG_OBJECT (self,
"Output picture %p (poc %d)", to_output, to_output->pic_order_cnt); "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
/* Current picture hasn't been inserted into DPB yet, so don't remove it * if we managed to output it immediately */
* if we managed to output it immediately */ if (picture && to_output == picture) {
gint outputted_poc = to_output->pic_order_cnt; clear_dpb = FALSE;
if (outputted_poc != picture->pic_order_cnt) {
GST_LOG_OBJECT (self, "Delete picture %p (poc %d) from DPB", if (picture->ref) {
to_output, to_output->pic_order_cnt); GST_TRACE_OBJECT (self,
gst_h265_dpb_delete_by_poc (priv->dpb, outputted_poc); "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--; num_remaining--;
} }
if (not_outputted) /* If we haven't managed to output the picture that we just decoded, or if
g_list_free_full (not_outputted, (GDestroyNotify) gst_h265_picture_unref); * 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; return TRUE;
} }
@ -1420,7 +1480,12 @@ gst_h265_decoder_handle_frame (GstVideoDecoder * decoder,
priv->current_frame = frame; priv->current_frame = frame;
priv->last_ret = GST_FLOW_OK; 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 || if (priv->in_format == GST_H265_DECODER_FORMAT_HVC1 ||
priv->in_format == GST_H265_DECODER_FORMAT_HEV1) { priv->in_format == GST_H265_DECODER_FORMAT_HEV1) {
pres = gst_h265_parser_identify_nalu_hevc (priv->parser, pres = gst_h265_parser_identify_nalu_hevc (priv->parser,
@ -1471,3 +1536,22 @@ gst_h265_decoder_handle_frame (GstVideoDecoder * decoder,
return priv->last_ret; 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);
}

View file

@ -87,9 +87,7 @@ struct _GstH265Decoder
* Called per one #GstH265Picture to notify subclass to finish * Called per one #GstH265Picture to notify subclass to finish
* decoding process for the #GstH265Picture * decoding process for the #GstH265Picture
* @output_picture: Called with a #GstH265Picture which is required to be outputted. * @output_picture: Called with a #GstH265Picture which is required to be outputted.
* Subclass can retrieve parent #GstVideoCodecFrame by using * The #GstVideoCodecFrame must be consumed by subclass via
* gst_video_decoder_get_frame() with system_frame_number
* and the #GstVideoCodecFrame must be consumed by subclass via
* gst_video_decoder_{finish,drop,release}_frame(). * gst_video_decoder_{finish,drop,release}_frame().
*/ */
struct _GstH265DecoderClass struct _GstH265DecoderClass
@ -99,8 +97,14 @@ struct _GstH265DecoderClass
gboolean (*new_sequence) (GstH265Decoder * decoder, gboolean (*new_sequence) (GstH265Decoder * decoder,
const GstH265SPS * sps, const GstH265SPS * sps,
gint max_dpb_size); 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, gboolean (*new_picture) (GstH265Decoder * decoder,
GstVideoCodecFrame * frame,
GstH265Picture * picture); GstH265Picture * picture);
gboolean (*start_picture) (GstH265Decoder * decoder, gboolean (*start_picture) (GstH265Decoder * decoder,
@ -114,8 +118,14 @@ struct _GstH265DecoderClass
gboolean (*end_picture) (GstH265Decoder * decoder, gboolean (*end_picture) (GstH265Decoder * decoder,
GstH265Picture * picture); GstH265Picture * picture);
/**
* GstH265Decoder:output_picture:
* @decoder: a #GstH265Decoder
* @frame: (transfer full): a #GstVideoCodecFrame
* @picture: (transfer full): a #GstH265Picture
*/
GstFlowReturn (*output_picture) (GstH265Decoder * decoder, GstFlowReturn (*output_picture) (GstH265Decoder * decoder,
GstVideoCodecFrame * frame,
GstH265Picture * picture); GstH265Picture * picture);
/*< private >*/ /*< private >*/
@ -127,6 +137,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstH265Decoder, gst_object_unref)
GST_CODECS_API GST_CODECS_API
GType gst_h265_decoder_get_type (void); 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 G_END_DECLS
#endif /* __GST_H265_DECODER_H__ */ #endif /* __GST_H265_DECODER_H__ */

View file

@ -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: * gst_h265_dpb_delete_by_poc:
* @dpb: a #GstH265Dpb * @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: * gst_h265_dpb_get_pictures_not_outputted:
* @dpb: a #GstH265Dpb * @dpb: a #GstH265Dpb
* @out: (out) (element-type GstH265Picture) (transfer full): a list * @out: (out) (element-type GstH265Picture) (transfer full): an array
* of #GstH265Dpb * of #GstH265Picture pointer
* *
* Retrieve all not-outputted pictures from @dpb * Retrieve all not-outputted pictures from @dpb
*/ */
void 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; gint i;
@ -440,8 +468,10 @@ gst_h265_dpb_get_pictures_not_outputted (GstH265Dpb * dpb, GList ** out)
GstH265Picture *picture = GstH265Picture *picture =
g_array_index (dpb->pic_list, GstH265Picture *, i); g_array_index (dpb->pic_list, GstH265Picture *, i);
if (!picture->outputted) if (!picture->outputted) {
*out = g_list_append (*out, gst_h265_picture_ref (picture)); 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; 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;
}

View file

@ -160,6 +160,9 @@ void gst_h265_dpb_add (GstH265Dpb * dpb,
GST_CODECS_API GST_CODECS_API
void gst_h265_dpb_delete_unused (GstH265Dpb * dpb); void gst_h265_dpb_delete_unused (GstH265Dpb * dpb);
GST_CODECS_API
void gst_h265_dpb_delete_outputted (GstH265Dpb * dpb);
GST_CODECS_API GST_CODECS_API
void gst_h265_dpb_delete_by_poc (GstH265Dpb * dpb, void gst_h265_dpb_delete_by_poc (GstH265Dpb * dpb,
gint poc); gint poc);
@ -188,11 +191,15 @@ GstH265Picture * gst_h265_dpb_get_long_ref_by_poc (GstH265Dpb * dpb,
GST_CODECS_API GST_CODECS_API
void gst_h265_dpb_get_pictures_not_outputted (GstH265Dpb * dpb, void gst_h265_dpb_get_pictures_not_outputted (GstH265Dpb * dpb,
GList ** out); GArray * out);
GST_CODECS_API GST_CODECS_API
GArray * gst_h265_dpb_get_pictures_all (GstH265Dpb * dpb); 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 GST_CODECS_API
gint gst_h265_dpb_get_size (GstH265Dpb * dpb); gint gst_h265_dpb_get_size (GstH265Dpb * dpb);

View file

@ -120,9 +120,9 @@ static gboolean gst_d3d11_h265_dec_src_query (GstVideoDecoder * decoder,
static gboolean gst_d3d11_h265_dec_new_sequence (GstH265Decoder * decoder, static gboolean gst_d3d11_h265_dec_new_sequence (GstH265Decoder * decoder,
const GstH265SPS * sps, gint max_dpb_size); const GstH265SPS * sps, gint max_dpb_size);
static gboolean gst_d3d11_h265_dec_new_picture (GstH265Decoder * decoder, 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 * 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, static gboolean gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb); GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb);
static gboolean gst_d3d11_h265_dec_decode_slice (GstH265Decoder * decoder, static gboolean gst_d3d11_h265_dec_decode_slice (GstH265Decoder * decoder,
@ -624,7 +624,7 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
static gboolean static gboolean
gst_d3d11_h265_dec_new_picture (GstH265Decoder * decoder, gst_d3d11_h265_dec_new_picture (GstH265Decoder * decoder,
GstH265Picture * picture) GstVideoCodecFrame * cframe, GstH265Picture * picture)
{ {
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder); GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder);
GstBuffer *view_buffer; GstBuffer *view_buffer;
@ -651,10 +651,10 @@ gst_d3d11_h265_dec_new_picture (GstH265Decoder * decoder,
static GstFlowReturn static GstFlowReturn
gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder, gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder,
GstH265Picture * picture) GstVideoCodecFrame * frame, GstH265Picture * picture)
{ {
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder); GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder);
GstVideoCodecFrame *frame = NULL; GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
GstBuffer *output_buffer = NULL; GstBuffer *output_buffer = NULL;
GstBuffer *view_buffer; GstBuffer *view_buffer;
@ -665,16 +665,7 @@ gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder,
if (!view_buffer) { if (!view_buffer) {
GST_ERROR_OBJECT (self, "Could not get output view"); GST_ERROR_OBJECT (self, "Could not get output view");
return GST_FLOW_ERROR; goto 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;
} }
/* if downstream is d3d11 element and forward playback case, /* if downstream is d3d11 element and forward playback case,
@ -696,9 +687,7 @@ gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder,
if (!output_buffer) { if (!output_buffer) {
GST_ERROR_OBJECT (self, "Couldn't allocate output buffer"); GST_ERROR_OBJECT (self, "Couldn't allocate output buffer");
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); goto error;
return GST_FLOW_ERROR;
} }
frame->output_buffer = output_buffer; frame->output_buffer = output_buffer;
@ -710,11 +699,18 @@ gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder,
view_buffer, output_buffer)) { view_buffer, output_buffer)) {
GST_ERROR_OBJECT (self, "Failed to copy buffer"); GST_ERROR_OBJECT (self, "Failed to copy buffer");
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
goto error;
return GST_FLOW_ERROR;
} }
gst_h265_picture_unref (picture);
return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); 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 static gboolean

View file

@ -146,9 +146,9 @@ static gboolean gst_nv_h265_dec_src_query (GstVideoDecoder * decoder,
static gboolean gst_nv_h265_dec_new_sequence (GstH265Decoder * decoder, static gboolean gst_nv_h265_dec_new_sequence (GstH265Decoder * decoder,
const GstH265SPS * sps, gint max_dpb_size); const GstH265SPS * sps, gint max_dpb_size);
static gboolean gst_nv_h265_dec_new_picture (GstH265Decoder * decoder, 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 * 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, static gboolean gst_nv_h265_dec_start_picture (GstH265Decoder * decoder,
GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb); GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb);
static gboolean gst_nv_h265_dec_decode_slice (GstH265Decoder * decoder, 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 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); GstNvH265Dec *self = GST_NV_H265_DEC (decoder);
GstNvDecoderFrame *frame; GstNvDecoderFrame *frame;
@ -435,11 +436,10 @@ gst_nv_h265_dec_new_picture (GstH265Decoder * decoder, GstH265Picture * picture)
static GstFlowReturn static GstFlowReturn
gst_nv_h265_dec_output_picture (GstH265Decoder * decoder, gst_nv_h265_dec_output_picture (GstH265Decoder * decoder,
GstH265Picture * picture) GstVideoCodecFrame * frame, GstH265Picture * picture)
{ {
GstNvH265Dec *self = GST_NV_H265_DEC (decoder); GstNvH265Dec *self = GST_NV_H265_DEC (decoder);
GstVideoCodecFrame *frame = NULL; GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
GstBuffer *output_buffer = NULL;
GstNvDecoderFrame *decoder_frame; GstNvDecoderFrame *decoder_frame;
gboolean ret G_GNUC_UNUSED = FALSE; 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); (GstNvDecoderFrame *) gst_h265_picture_get_user_data (picture);
if (!decoder_frame) { if (!decoder_frame) {
GST_ERROR_OBJECT (self, "No decoder frame in picture %p", picture); 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), frame->output_buffer =
picture->system_frame_number); gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self));;
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;
if (self->output_type == GST_NV_DECOCER_OUTPUT_TYPE_GL) { if (self->output_type == GST_NV_DECOCER_OUTPUT_TYPE_GL) {
ret = gst_nv_decoder_finish_frame (self->decoder, ret = gst_nv_decoder_finish_frame (self->decoder,
GST_NV_DECOCER_OUTPUT_TYPE_GL, self->gl_context, 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 /* FIXME: This is the case where OpenGL context of downstream glbufferpool
* belongs to non-nvidia (or different device). * belongs to non-nvidia (or different device).
@ -483,14 +475,21 @@ gst_nv_h265_dec_output_picture (GstH265Decoder * decoder,
if (!ret) { if (!ret) {
if (!gst_nv_decoder_finish_frame (self->decoder, if (!gst_nv_decoder_finish_frame (self->decoder,
GST_NV_DECOCER_OUTPUT_TYPE_SYSTEM, NULL, decoder_frame, GST_NV_DECOCER_OUTPUT_TYPE_SYSTEM, NULL, decoder_frame,
output_buffer)) { frame->output_buffer)) {
GST_ERROR_OBJECT (self, "Failed to finish frame"); GST_ERROR_OBJECT (self, "Failed to finish frame");
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); goto error;
return GST_FLOW_ERROR;
} }
} }
gst_h265_picture_unref (picture);
return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); 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 * static GstNvDecoderFrame *