h265decoder: Fix broken SPS/PPS link
Because of 2 pass nalu handling in decoder, link between slice header and SPS/PPS can be broken at the second pass if SPS/PPS got updated after slice header in the same AU Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/4323 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8673>
This commit is contained in:
parent
4898020c28
commit
a014556713
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <gst/base/base.h>
|
#include <gst/base/base.h>
|
||||||
#include "gsth265decoder.h"
|
#include "gsth265decoder.h"
|
||||||
|
#include <gst/codecparsers/gsth265parser-private.h>
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY (gst_h265_decoder_debug);
|
GST_DEBUG_CATEGORY (gst_h265_decoder_debug);
|
||||||
#define GST_CAT_DEFAULT gst_h265_decoder_debug
|
#define GST_CAT_DEFAULT gst_h265_decoder_debug
|
||||||
@ -67,6 +68,7 @@ struct _GstH265DecoderPrivate
|
|||||||
GstH265DecoderFormat in_format;
|
GstH265DecoderFormat in_format;
|
||||||
GstH265DecoderAlign align;
|
GstH265DecoderAlign align;
|
||||||
GstH265Parser *parser;
|
GstH265Parser *parser;
|
||||||
|
GstH265Parser *preproc_parser;
|
||||||
GstH265Dpb *dpb;
|
GstH265Dpb *dpb;
|
||||||
|
|
||||||
/* 0: frame or field-pair interlaced stream
|
/* 0: frame or field-pair interlaced stream
|
||||||
@ -144,10 +146,13 @@ typedef struct
|
|||||||
{
|
{
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
GstH265VPS vps;
|
||||||
GstH265SPS sps;
|
GstH265SPS sps;
|
||||||
|
GstH265PPS pps;
|
||||||
GstH265Slice slice;
|
GstH265Slice slice;
|
||||||
} unit;
|
} unit;
|
||||||
gboolean is_slice;
|
GstH265NalUnitType nalu_type;
|
||||||
|
guint pps_id;
|
||||||
} GstH265DecoderNalUnit;
|
} GstH265DecoderNalUnit;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -266,6 +271,7 @@ gst_h265_decoder_start (GstVideoDecoder * decoder)
|
|||||||
GstH265DecoderPrivate *priv = self->priv;
|
GstH265DecoderPrivate *priv = self->priv;
|
||||||
|
|
||||||
priv->parser = gst_h265_parser_new ();
|
priv->parser = gst_h265_parser_new ();
|
||||||
|
priv->preproc_parser = gst_h265_parser_new ();
|
||||||
priv->dpb = gst_h265_dpb_new ();
|
priv->dpb = gst_h265_dpb_new ();
|
||||||
priv->new_bitstream = TRUE;
|
priv->new_bitstream = TRUE;
|
||||||
priv->prev_nal_is_eos = FALSE;
|
priv->prev_nal_is_eos = FALSE;
|
||||||
@ -290,6 +296,11 @@ gst_h265_decoder_stop (GstVideoDecoder * decoder)
|
|||||||
priv->parser = NULL;
|
priv->parser = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->preproc_parser) {
|
||||||
|
gst_h265_parser_free (priv->preproc_parser);
|
||||||
|
priv->preproc_parser = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->dpb) {
|
if (priv->dpb) {
|
||||||
gst_h265_dpb_free (priv->dpb);
|
gst_h265_dpb_free (priv->dpb);
|
||||||
priv->dpb = NULL;
|
priv->dpb = NULL;
|
||||||
@ -626,7 +637,7 @@ gst_h265_decoder_parse_sei (GstH265Decoder * self, GstH265NalUnit * nalu)
|
|||||||
GArray *messages = NULL;
|
GArray *messages = NULL;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
pres = gst_h265_parser_parse_sei (priv->parser, nalu, &messages);
|
pres = gst_h265_parser_parse_sei (priv->preproc_parser, nalu, &messages);
|
||||||
if (pres != GST_H265_PARSER_OK) {
|
if (pres != GST_H265_PARSER_OK) {
|
||||||
GST_WARNING_OBJECT (self, "Failed to parse SEI, result %d", pres);
|
GST_WARNING_OBJECT (self, "Failed to parse SEI, result %d", pres);
|
||||||
|
|
||||||
@ -904,7 +915,8 @@ gst_h265_decoder_parse_slice (GstH265Decoder * self, GstH265NalUnit * nalu)
|
|||||||
|
|
||||||
memset (&slice, 0, sizeof (GstH265Slice));
|
memset (&slice, 0, sizeof (GstH265Slice));
|
||||||
|
|
||||||
pres = gst_h265_parser_parse_slice_hdr (priv->parser, nalu, &slice.header);
|
pres = gst_h265_parser_parse_slice_hdr (priv->preproc_parser,
|
||||||
|
nalu, &slice.header);
|
||||||
if (pres != GST_H265_PARSER_OK)
|
if (pres != GST_H265_PARSER_OK)
|
||||||
return pres;
|
return pres;
|
||||||
|
|
||||||
@ -948,7 +960,9 @@ gst_h265_decoder_parse_slice (GstH265Decoder * self, GstH265NalUnit * nalu)
|
|||||||
priv->no_output_of_prior_pics_flag = TRUE;
|
priv->no_output_of_prior_pics_flag = TRUE;
|
||||||
|
|
||||||
decoder_nalu.unit.slice = slice;
|
decoder_nalu.unit.slice = slice;
|
||||||
decoder_nalu.is_slice = TRUE;
|
decoder_nalu.nalu_type = nalu->type;
|
||||||
|
decoder_nalu.pps_id = slice.header.pps->id;
|
||||||
|
|
||||||
g_array_append_val (priv->nalu, decoder_nalu);
|
g_array_append_val (priv->nalu, decoder_nalu);
|
||||||
|
|
||||||
return GST_H265_PARSER_OK;
|
return GST_H265_PARSER_OK;
|
||||||
@ -967,21 +981,33 @@ gst_h265_decoder_parse_nalu (GstH265Decoder * self, GstH265NalUnit * nalu)
|
|||||||
GST_LOG_OBJECT (self, "Parsed nal type: %d, offset %d, size %d",
|
GST_LOG_OBJECT (self, "Parsed nal type: %d, offset %d, size %d",
|
||||||
nalu->type, nalu->offset, nalu->size);
|
nalu->type, nalu->offset, nalu->size);
|
||||||
|
|
||||||
|
memset (&decoder_nalu, 0, sizeof (GstH265DecoderNalUnit));
|
||||||
|
decoder_nalu.nalu_type = nalu->type;
|
||||||
|
|
||||||
switch (nalu->type) {
|
switch (nalu->type) {
|
||||||
case GST_H265_NAL_VPS:
|
case GST_H265_NAL_VPS:
|
||||||
ret = gst_h265_parser_parse_vps (priv->parser, nalu, &vps);
|
ret = gst_h265_parser_parse_vps (priv->preproc_parser, nalu, &vps);
|
||||||
break;
|
if (ret != GST_H265_PARSER_OK)
|
||||||
case GST_H265_NAL_SPS:
|
break;
|
||||||
ret = gst_h265_parser_parse_sps (priv->parser, nalu, &sps, TRUE);
|
|
||||||
|
decoder_nalu.unit.vps = vps;
|
||||||
|
g_array_append_val (priv->nalu, decoder_nalu);
|
||||||
|
break;
|
||||||
|
case GST_H265_NAL_SPS:
|
||||||
|
ret = gst_h265_parser_parse_sps (priv->preproc_parser, nalu, &sps, TRUE);
|
||||||
if (ret != GST_H265_PARSER_OK)
|
if (ret != GST_H265_PARSER_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
memset (&decoder_nalu, 0, sizeof (GstH265DecoderNalUnit));
|
|
||||||
decoder_nalu.unit.sps = sps;
|
decoder_nalu.unit.sps = sps;
|
||||||
g_array_append_val (priv->nalu, decoder_nalu);
|
g_array_append_val (priv->nalu, decoder_nalu);
|
||||||
break;
|
break;
|
||||||
case GST_H265_NAL_PPS:
|
case GST_H265_NAL_PPS:
|
||||||
ret = gst_h265_parser_parse_pps (priv->parser, nalu, &pps);
|
ret = gst_h265_parser_parse_pps (priv->preproc_parser, nalu, &pps);
|
||||||
|
if (ret != GST_H265_PARSER_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
decoder_nalu.unit.pps = pps;
|
||||||
|
g_array_append_val (priv->nalu, decoder_nalu);
|
||||||
break;
|
break;
|
||||||
case GST_H265_NAL_PREFIX_SEI:
|
case GST_H265_NAL_PREFIX_SEI:
|
||||||
case GST_H265_NAL_SUFFIX_SEI:
|
case GST_H265_NAL_SUFFIX_SEI:
|
||||||
@ -1020,14 +1046,53 @@ gst_h265_decoder_parse_nalu (GstH265Decoder * self, GstH265NalUnit * nalu)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
is_slice_nalu (GstH265NalUnitType type)
|
||||||
|
{
|
||||||
|
if ((type >= GST_H265_NAL_SLICE_TRAIL_N &&
|
||||||
|
type <= GST_H265_NAL_SLICE_RASL_R) ||
|
||||||
|
(type >= GST_H265_NAL_SLICE_BLA_W_LP &&
|
||||||
|
type <= GST_H265_NAL_SLICE_CRA_NUT)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_h265_decoder_decode_nalu (GstH265Decoder * self,
|
gst_h265_decoder_decode_nalu (GstH265Decoder * self,
|
||||||
GstH265DecoderNalUnit * nalu)
|
GstH265DecoderNalUnit * nalu)
|
||||||
{
|
{
|
||||||
if (nalu->is_slice)
|
GstH265DecoderPrivate *priv = self->priv;
|
||||||
return gst_h265_decoder_process_slice (self, &nalu->unit.slice);
|
GstH265ParserResult rst;
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
switch (nalu->nalu_type) {
|
||||||
|
case GST_H265_NAL_VPS:
|
||||||
|
gst_h265_parser_update_vps (priv->parser, &nalu->unit.vps);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
case GST_H265_NAL_SPS:
|
||||||
|
gst_h265_parser_update_sps (priv->parser, &nalu->unit.sps);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
case GST_H265_NAL_PPS:
|
||||||
|
gst_h265_parser_update_pps (priv->parser, &nalu->unit.pps);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
default:
|
||||||
|
if (!is_slice_nalu (nalu->nalu_type)) {
|
||||||
|
GST_WARNING_OBJECT (self, "Unexpected nal type %d", nalu->nalu_type);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rst = gst_h265_parser_link_slice_hdr (priv->parser,
|
||||||
|
&nalu->unit.slice.header, nalu->pps_id);
|
||||||
|
|
||||||
|
if (rst != GST_H265_PARSER_OK) {
|
||||||
|
GST_ERROR_OBJECT (self, "Couldn't update slice header");
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gst_h265_decoder_process_slice (self, &nalu->unit.slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1112,6 +1177,7 @@ gst_h265_decoder_parse_codec_data (GstH265Decoder * self, const guint8 * data,
|
|||||||
GST_WARNING_OBJECT (self, "Failed to parse VPS");
|
GST_WARNING_OBJECT (self, "Failed to parse VPS");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
gst_h265_parser_update_vps (priv->preproc_parser, &vps);
|
||||||
break;
|
break;
|
||||||
case GST_H265_NAL_SPS:
|
case GST_H265_NAL_SPS:
|
||||||
pres = gst_h265_parser_parse_sps (parser, nalu, &sps, TRUE);
|
pres = gst_h265_parser_parse_sps (parser, nalu, &sps, TRUE);
|
||||||
@ -1119,6 +1185,7 @@ gst_h265_decoder_parse_codec_data (GstH265Decoder * self, const guint8 * data,
|
|||||||
GST_WARNING_OBJECT (self, "Failed to parse SPS");
|
GST_WARNING_OBJECT (self, "Failed to parse SPS");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
gst_h265_parser_update_sps (priv->preproc_parser, &sps);
|
||||||
break;
|
break;
|
||||||
case GST_H265_NAL_PPS:
|
case GST_H265_NAL_PPS:
|
||||||
pres = gst_h265_parser_parse_pps (parser, nalu, &pps);
|
pres = gst_h265_parser_parse_pps (parser, nalu, &pps);
|
||||||
@ -1126,6 +1193,7 @@ gst_h265_decoder_parse_codec_data (GstH265Decoder * self, const guint8 * data,
|
|||||||
GST_WARNING_OBJECT (self, "Failed to parse PPS");
|
GST_WARNING_OBJECT (self, "Failed to parse PPS");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
gst_h265_parser_update_pps (priv->preproc_parser, &pps);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -2055,7 +2123,7 @@ gst_h265_decoder_handle_frame (GstVideoDecoder * decoder,
|
|||||||
gsize consumed;
|
gsize consumed;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
pres = gst_h265_parser_identify_and_split_nalu_hevc (priv->parser,
|
pres = gst_h265_parser_identify_and_split_nalu_hevc (priv->preproc_parser,
|
||||||
map.data, offset, map.size, priv->nal_length_size, priv->split_nalu,
|
map.data, offset, map.size, priv->nal_length_size, priv->split_nalu,
|
||||||
&consumed);
|
&consumed);
|
||||||
if (pres != GST_H265_PARSER_OK)
|
if (pres != GST_H265_PARSER_OK)
|
||||||
@ -2075,7 +2143,7 @@ gst_h265_decoder_handle_frame (GstVideoDecoder * decoder,
|
|||||||
offset += consumed;
|
offset += consumed;
|
||||||
} while (pres == GST_H265_PARSER_OK);
|
} while (pres == GST_H265_PARSER_OK);
|
||||||
} else {
|
} else {
|
||||||
pres = gst_h265_parser_identify_nalu (priv->parser,
|
pres = gst_h265_parser_identify_nalu (priv->preproc_parser,
|
||||||
map.data, 0, map.size, &nalu);
|
map.data, 0, map.size, &nalu);
|
||||||
|
|
||||||
if (pres == GST_H265_PARSER_NO_NAL_END)
|
if (pres == GST_H265_PARSER_NO_NAL_END)
|
||||||
@ -2086,7 +2154,7 @@ gst_h265_decoder_handle_frame (GstVideoDecoder * decoder,
|
|||||||
if (pres != GST_H265_PARSER_OK)
|
if (pres != GST_H265_PARSER_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
pres = gst_h265_parser_identify_nalu (priv->parser,
|
pres = gst_h265_parser_identify_nalu (priv->preproc_parser,
|
||||||
map.data, nalu.offset + nalu.size, map.size, &nalu);
|
map.data, nalu.offset + nalu.size, map.size, &nalu);
|
||||||
if (pres == GST_H265_PARSER_NO_NAL_END)
|
if (pres == GST_H265_PARSER_NO_NAL_END)
|
||||||
pres = GST_H265_PARSER_OK;
|
pres = GST_H265_PARSER_OK;
|
||||||
@ -2142,7 +2210,7 @@ gst_h265_decoder_clear_nalu (GstH265DecoderNalUnit * nalu)
|
|||||||
if (!nalu)
|
if (!nalu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (nalu->is_slice)
|
if (is_slice_nalu (nalu->nalu_type))
|
||||||
gst_h265_slice_hdr_free (&nalu->unit.slice.header);
|
gst_h265_slice_hdr_free (&nalu->unit.slice.header);
|
||||||
|
|
||||||
memset (nalu, 0, sizeof (GstH265DecoderNalUnit));
|
memset (nalu, 0, sizeof (GstH265DecoderNalUnit));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user