mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-08 18:39:54 +00:00
d3d11decoder: Refactor decoding process
* Move decoding process to handle_frame * Remove GstVideoDecoder::parse implementation * Clarify flush/drain/finish usage In forward playback case, have_frame() call will be followed by handle_frame() but reverse playback is not the case. To ensure GstVideoCodecFrame, the decoding process should be placed inside of handle_frame(), instead of parse(). Since we don't support alignment=nal, the parse() implementation is not worth. In order to fix broken reverse playback, let's remove the parse() implementation and revisit it when adding alignment=nal support.
This commit is contained in:
parent
3e78afbe0a
commit
a39a5bf131
2 changed files with 144 additions and 322 deletions
|
@ -95,6 +95,7 @@ struct _GstH264DecoderPrivate
|
|||
|
||||
/* Picture currently being processed/decoded */
|
||||
GstH264Picture *current_picture;
|
||||
GstVideoCodecFrame *current_frame;
|
||||
|
||||
/* Slice (slice header + nalu) currently being processed/decodec */
|
||||
GstH264Slice current_slice;
|
||||
|
@ -127,8 +128,6 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstH264Decoder, gst_h264_decoder,
|
|||
|
||||
static gboolean gst_h264_decoder_start (GstVideoDecoder * decoder);
|
||||
static gboolean gst_h264_decoder_stop (GstVideoDecoder * decoder);
|
||||
static GstFlowReturn gst_h264_decoder_parse (GstVideoDecoder * decoder,
|
||||
GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
|
||||
static gboolean gst_h264_decoder_set_format (GstVideoDecoder * decoder,
|
||||
GstVideoCodecState * state);
|
||||
static GstFlowReturn gst_h264_decoder_finish (GstVideoDecoder * decoder);
|
||||
|
@ -141,6 +140,8 @@ static GstFlowReturn gst_h264_decoder_handle_frame (GstVideoDecoder * decoder,
|
|||
static gboolean gst_h264_decoder_process_sps (GstH264Decoder * self,
|
||||
GstH264SPS * sps);
|
||||
static gboolean gst_h264_decoder_decode_slice (GstH264Decoder * self);
|
||||
static gboolean gst_h264_decoder_decode_nal (GstH264Decoder * self,
|
||||
GstH264NalUnit * nalu, GstClockTime pts);
|
||||
static gboolean gst_h264_decoder_fill_picture_from_slice (GstH264Decoder * self,
|
||||
const GstH264Slice * slice, GstH264Picture * picture);
|
||||
static gboolean gst_h264_decoder_calculate_poc (GstH264Decoder * self,
|
||||
|
@ -160,7 +161,6 @@ gst_h264_decoder_class_init (GstH264DecoderClass * klass)
|
|||
|
||||
decoder_class->start = GST_DEBUG_FUNCPTR (gst_h264_decoder_start);
|
||||
decoder_class->stop = GST_DEBUG_FUNCPTR (gst_h264_decoder_stop);
|
||||
decoder_class->parse = GST_DEBUG_FUNCPTR (gst_h264_decoder_parse);
|
||||
decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_h264_decoder_set_format);
|
||||
decoder_class->finish = GST_DEBUG_FUNCPTR (gst_h264_decoder_finish);
|
||||
decoder_class->flush = GST_DEBUG_FUNCPTR (gst_h264_decoder_flush);
|
||||
|
@ -172,7 +172,7 @@ gst_h264_decoder_class_init (GstH264DecoderClass * klass)
|
|||
static void
|
||||
gst_h264_decoder_init (GstH264Decoder * self)
|
||||
{
|
||||
gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), FALSE);
|
||||
gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
|
||||
|
||||
self->priv = gst_h264_decoder_get_instance_private (self);
|
||||
}
|
||||
|
@ -228,16 +228,10 @@ static gboolean
|
|||
gst_h264_decoder_flush (GstVideoDecoder * decoder)
|
||||
{
|
||||
GstH264Decoder *self = GST_H264_DECODER (decoder);
|
||||
gboolean ret = TRUE;
|
||||
|
||||
gst_h264_decoder_finish_current_picture (self);
|
||||
|
||||
if (!gst_h264_decoder_output_all_remaining_pics (self))
|
||||
ret = FALSE;
|
||||
|
||||
gst_h264_decoder_clear_dpb (self);
|
||||
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -246,7 +240,9 @@ gst_h264_decoder_drain (GstVideoDecoder * decoder)
|
|||
GstH264Decoder *self = GST_H264_DECODER (decoder);
|
||||
GstH264DecoderPrivate *priv = self->priv;
|
||||
|
||||
gst_h264_decoder_flush (decoder);
|
||||
priv->last_ret = GST_FLOW_OK;
|
||||
gst_h264_decoder_output_all_remaining_pics (self);
|
||||
gst_h264_decoder_clear_dpb (self);
|
||||
|
||||
return priv->last_ret;
|
||||
}
|
||||
|
@ -264,26 +260,68 @@ gst_h264_decoder_handle_frame (GstVideoDecoder * decoder,
|
|||
GstH264Decoder *self = GST_H264_DECODER (decoder);
|
||||
GstH264DecoderPrivate *priv = self->priv;
|
||||
GstBuffer *in_buf = frame->input_buffer;
|
||||
GstH264NalUnit nalu;
|
||||
GstH264ParserResult pres;
|
||||
GstMapInfo map;
|
||||
gboolean decode_ret = TRUE;
|
||||
|
||||
GST_LOG_OBJECT (self,
|
||||
"handle frame, PTS: %" GST_TIME_FORMAT ", DTS: %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (in_buf)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DTS (in_buf)));
|
||||
|
||||
if (!priv->current_picture) {
|
||||
GST_ERROR_OBJECT (self, "No current picture");
|
||||
gst_video_decoder_drop_frame (decoder, frame);
|
||||
priv->current_frame = frame;
|
||||
priv->last_ret = GST_FLOW_OK;
|
||||
|
||||
return GST_FLOW_ERROR;
|
||||
gst_buffer_map (in_buf, &map, GST_MAP_READ);
|
||||
if (priv->in_format == GST_H264_DECODER_FORMAT_AVC) {
|
||||
pres = gst_h264_parser_identify_nalu_avc (priv->parser,
|
||||
map.data, 0, map.size, priv->nal_length_size, &nalu);
|
||||
|
||||
while (pres == GST_H264_PARSER_OK && decode_ret) {
|
||||
decode_ret = gst_h264_decoder_decode_nal (self,
|
||||
&nalu, GST_BUFFER_PTS (in_buf));
|
||||
|
||||
pres = gst_h264_parser_identify_nalu_avc (priv->parser,
|
||||
map.data, nalu.offset + nalu.size, map.size, priv->nal_length_size,
|
||||
&nalu);
|
||||
}
|
||||
} else {
|
||||
pres = gst_h264_parser_identify_nalu (priv->parser,
|
||||
map.data, 0, map.size, &nalu);
|
||||
|
||||
if (pres == GST_H264_PARSER_NO_NAL_END)
|
||||
pres = GST_H264_PARSER_OK;
|
||||
|
||||
while (pres == GST_H264_PARSER_OK && decode_ret) {
|
||||
decode_ret = gst_h264_decoder_decode_nal (self,
|
||||
&nalu, GST_BUFFER_PTS (in_buf));
|
||||
|
||||
pres = gst_h264_parser_identify_nalu (priv->parser,
|
||||
map.data, nalu.offset + nalu.size, map.size, &nalu);
|
||||
|
||||
if (pres == GST_H264_PARSER_NO_NAL_END)
|
||||
pres = GST_H264_PARSER_OK;
|
||||
}
|
||||
}
|
||||
|
||||
gst_video_codec_frame_set_user_data (frame,
|
||||
gst_h264_picture_ref (priv->current_picture),
|
||||
(GDestroyNotify) gst_h264_picture_unref);
|
||||
gst_buffer_unmap (in_buf, &map);
|
||||
priv->current_frame = NULL;
|
||||
|
||||
if (!decode_ret) {
|
||||
GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
|
||||
("Failed to decode data"), (NULL), priv->last_ret);
|
||||
gst_video_decoder_drop_frame (decoder, frame);
|
||||
|
||||
gst_h264_picture_clear (&priv->current_picture);
|
||||
|
||||
return priv->last_ret;
|
||||
}
|
||||
|
||||
gst_h264_decoder_finish_current_picture (self);
|
||||
gst_video_codec_frame_unref (frame);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
return priv->last_ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -294,8 +332,6 @@ gst_h264_decoder_parse_sps (GstH264Decoder * self, GstH264NalUnit * nalu)
|
|||
GstH264ParserResult pres;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
gst_h264_decoder_finish_current_picture (self);
|
||||
|
||||
pres = gst_h264_parser_parse_sps (priv->parser, nalu, &sps);
|
||||
if (pres != GST_H264_PARSER_OK) {
|
||||
GST_WARNING_OBJECT (self, "Failed to parse SPS, result %d", pres);
|
||||
|
@ -319,8 +355,6 @@ gst_h264_decoder_parse_pps (GstH264Decoder * self, GstH264NalUnit * nalu)
|
|||
GstH264PPS pps;
|
||||
GstH264ParserResult pres;
|
||||
|
||||
gst_h264_decoder_finish_current_picture (self);
|
||||
|
||||
pres = gst_h264_parser_parse_pps (priv->parser, nalu, &pps);
|
||||
if (pres != GST_H264_PARSER_OK) {
|
||||
GST_WARNING_OBJECT (self, "Failed to parse PPS, result %d", pres);
|
||||
|
@ -407,62 +441,12 @@ gst_h264_decoder_parse_codec_data (GstH264Decoder * self, const guint8 * data,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_h264_decoder_is_new_au (GstH264Decoder * self, GstH264Slice * slice)
|
||||
{
|
||||
GstH264DecoderPrivate *priv = self->priv;
|
||||
GstH264SliceHdr *slice_hdr;
|
||||
GstH264NalUnit *nalu;
|
||||
GstH264Picture *current_picture;
|
||||
const GstH264SPS *sps;
|
||||
|
||||
current_picture = priv->current_picture;
|
||||
if (!current_picture)
|
||||
return TRUE;
|
||||
|
||||
slice_hdr = &slice->header;
|
||||
nalu = &slice->nalu;
|
||||
if (slice_hdr->frame_num != current_picture->frame_num ||
|
||||
slice_hdr->pps->id != priv->active_pps->id ||
|
||||
nalu->ref_idc != current_picture->nal_ref_idc ||
|
||||
(! !nalu->idr_pic_flag) != (! !current_picture->idr_pic_id) ||
|
||||
(nalu->idr_pic_flag &&
|
||||
(slice_hdr->idr_pic_id != current_picture->idr_pic_id ||
|
||||
!slice_hdr->first_mb_in_slice)))
|
||||
return TRUE;
|
||||
|
||||
sps = priv->active_sps;
|
||||
if (!sps)
|
||||
return FALSE;
|
||||
|
||||
if (sps->pic_order_cnt_type == current_picture->pic_order_cnt_type) {
|
||||
if (current_picture->pic_order_cnt_type == 0) {
|
||||
if (slice_hdr->pic_order_cnt_lsb != current_picture->pic_order_cnt_lsb ||
|
||||
slice_hdr->delta_pic_order_cnt_bottom !=
|
||||
current_picture->delta_pic_order_cnt_bottom)
|
||||
return TRUE;
|
||||
} else if (current_picture->pic_order_cnt_type == 1) {
|
||||
if (slice_hdr->delta_pic_order_cnt[0] !=
|
||||
current_picture->delta_pic_order_cnt0
|
||||
|| slice_hdr->delta_pic_order_cnt[1] !=
|
||||
current_picture->delta_pic_order_cnt1)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_h264_decoder_preprocess_slice (GstH264Decoder * self, GstH264Slice * slice)
|
||||
{
|
||||
GstH264DecoderPrivate *priv = self->priv;
|
||||
|
||||
if (gst_h264_decoder_is_new_au (self, slice)) {
|
||||
/* finish previous frame if any */
|
||||
if (!gst_h264_decoder_finish_current_picture (self))
|
||||
return FALSE;
|
||||
|
||||
if (!priv->current_picture) {
|
||||
if (slice->header.first_mb_in_slice != 0) {
|
||||
GST_ERROR_OBJECT (self, "Invalid stream, first_mb_in_slice %d",
|
||||
slice->header.first_mb_in_slice);
|
||||
|
@ -474,7 +458,7 @@ gst_h264_decoder_preprocess_slice (GstH264Decoder * self, GstH264Slice * slice)
|
|||
/* Output all remaining pictures, unless we are explicitly instructed
|
||||
* not to do so */
|
||||
if (!slice->header.dec_ref_pic_marking.no_output_of_prior_pics_flag)
|
||||
gst_h264_decoder_flush (GST_VIDEO_DECODER (self));
|
||||
gst_h264_decoder_drain (GST_VIDEO_DECODER (self));
|
||||
|
||||
gst_h264_dpb_clear (priv->dpb);
|
||||
}
|
||||
|
@ -675,6 +659,9 @@ gst_h264_decoder_parse_slice (GstH264Decoder * self, GstH264NalUnit * nalu,
|
|||
}
|
||||
|
||||
priv->current_picture = picture;
|
||||
gst_video_codec_frame_set_user_data (priv->current_frame,
|
||||
gst_h264_picture_ref (priv->current_picture),
|
||||
(GDestroyNotify) gst_h264_picture_unref);
|
||||
|
||||
if (!gst_h264_decoder_start_current_picture (self)) {
|
||||
GST_ERROR_OBJECT (self, "start picture failed");
|
||||
|
@ -685,62 +672,21 @@ gst_h264_decoder_parse_slice (GstH264Decoder * self, GstH264NalUnit * nalu,
|
|||
return gst_h264_decoder_decode_slice (self);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_h264_decoder_parse_nal (GstH264Decoder * self, const guint8 * data,
|
||||
gsize size, GstClockTime pts, gboolean at_eos, gsize * consumed_size)
|
||||
static gboolean
|
||||
gst_h264_decoder_decode_nal (GstH264Decoder * self, GstH264NalUnit * nalu,
|
||||
GstClockTime pts)
|
||||
{
|
||||
GstH264DecoderPrivate *priv = self->priv;
|
||||
GstH264ParserResult pres;
|
||||
GstH264NalUnit nalu;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
*consumed_size = 0;
|
||||
|
||||
if (priv->in_format == GST_H264_DECODER_FORMAT_AVC) {
|
||||
if (priv->nal_length_size < 1 || priv->nal_length_size > 4) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"invalid nal length size %d", priv->nal_length_size);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
pres = gst_h264_parser_identify_nalu_avc (priv->parser,
|
||||
data, 0, size, priv->nal_length_size, &nalu);
|
||||
|
||||
if (pres != GST_H264_PARSER_OK) {
|
||||
GST_WARNING_OBJECT (self, "parsing avc nal ret %d", pres);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (size < 5) {
|
||||
GST_DEBUG_OBJECT (self, "Too small data");
|
||||
return GST_VIDEO_DECODER_FLOW_NEED_DATA;
|
||||
}
|
||||
|
||||
pres = gst_h264_parser_identify_nalu (priv->parser, data, 0, size, &nalu);
|
||||
|
||||
if (pres != GST_H264_PARSER_OK) {
|
||||
if (pres == GST_H264_PARSER_NO_NAL_END) {
|
||||
if (at_eos || priv->align == GST_H264_DECODER_ALIGN_AU) {
|
||||
/* assume au boundary */
|
||||
} else {
|
||||
return GST_VIDEO_DECODER_FLOW_NEED_DATA;
|
||||
}
|
||||
} else {
|
||||
GST_WARNING_OBJECT (self, "parser ret %d", pres);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (self, "Parsed nal type: %d, offset %d, size %d",
|
||||
nalu.type, nalu.offset, nalu.size);
|
||||
nalu->type, nalu->offset, nalu->size);
|
||||
|
||||
switch (nalu.type) {
|
||||
switch (nalu->type) {
|
||||
case GST_H264_NAL_SPS:
|
||||
ret = gst_h264_decoder_parse_sps (self, &nalu);
|
||||
ret = gst_h264_decoder_parse_sps (self, nalu);
|
||||
break;
|
||||
case GST_H264_NAL_PPS:
|
||||
ret = gst_h264_decoder_parse_pps (self, &nalu);
|
||||
ret = gst_h264_decoder_parse_pps (self, nalu);
|
||||
break;
|
||||
case GST_H264_NAL_SLICE:
|
||||
case GST_H264_NAL_SLICE_DPA:
|
||||
|
@ -748,67 +694,12 @@ gst_h264_decoder_parse_nal (GstH264Decoder * self, const guint8 * data,
|
|||
case GST_H264_NAL_SLICE_DPC:
|
||||
case GST_H264_NAL_SLICE_IDR:
|
||||
case GST_H264_NAL_SLICE_EXT:
|
||||
ret = gst_h264_decoder_parse_slice (self, &nalu, pts);
|
||||
ret = gst_h264_decoder_parse_slice (self, nalu, pts);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (consumed_size)
|
||||
*consumed_size = nalu.offset + nalu.size;
|
||||
|
||||
if (!ret)
|
||||
return GST_FLOW_ERROR;
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_h264_decoder_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame,
|
||||
GstAdapter * adapter, gboolean at_eos)
|
||||
{
|
||||
GstH264Decoder *self = GST_H264_DECODER (decoder);
|
||||
GstH264DecoderPrivate *priv = self->priv;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint size;
|
||||
const guint8 *data;
|
||||
gsize consumed = 0;
|
||||
|
||||
/* The return from have_frame() or output_picture() */
|
||||
priv->last_ret = GST_FLOW_OK;
|
||||
|
||||
size = gst_adapter_available (adapter);
|
||||
|
||||
data = (const guint8 *) gst_adapter_map (adapter, size);
|
||||
ret = gst_h264_decoder_parse_nal (self, data, size,
|
||||
gst_adapter_prev_pts (adapter, NULL), at_eos, &consumed);
|
||||
gst_adapter_unmap (adapter);
|
||||
|
||||
if (consumed) {
|
||||
GST_TRACE_OBJECT (self, "consumed size %" G_GSIZE_FORMAT, consumed);
|
||||
gst_video_decoder_add_to_frame (decoder, consumed);
|
||||
}
|
||||
|
||||
if (ret == GST_FLOW_ERROR)
|
||||
goto error;
|
||||
|
||||
/* When AU alginment and has no available input data more,
|
||||
* finish current picture if any */
|
||||
if (priv->align == GST_H264_DECODER_ALIGN_AU &&
|
||||
!gst_adapter_available (adapter)) {
|
||||
gst_h264_decoder_finish_current_picture (self);
|
||||
}
|
||||
|
||||
/* check last flow return again */
|
||||
if (ret == GST_FLOW_ERROR)
|
||||
goto error;
|
||||
|
||||
return priv->last_ret;
|
||||
|
||||
error:
|
||||
GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
|
||||
("Failed to decode data"), (NULL), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1240,8 +1131,6 @@ gst_h264_decoder_finish_current_picture (GstH264Decoder * self)
|
|||
if (klass->end_picture)
|
||||
ret = klass->end_picture (self, priv->current_picture);
|
||||
|
||||
gst_video_decoder_have_frame (GST_VIDEO_DECODER (self));
|
||||
|
||||
/* finish picture takes ownership of the picture */
|
||||
ret = gst_h264_decoder_finish_picture (self, priv->current_picture);
|
||||
priv->current_picture = NULL;
|
||||
|
@ -1801,7 +1690,7 @@ gst_h264_decoder_process_sps (GstH264Decoder * self, GstH264SPS * sps)
|
|||
priv->width, priv->height, sps->width, sps->height,
|
||||
prev_max_dpb_size, max_dpb_size);
|
||||
|
||||
if (!gst_h264_decoder_flush (GST_VIDEO_DECODER (self)))
|
||||
if (gst_h264_decoder_drain (GST_VIDEO_DECODER (self)) != GST_FLOW_OK)
|
||||
return FALSE;
|
||||
|
||||
g_assert (klass->new_sequence);
|
||||
|
|
|
@ -68,6 +68,7 @@ struct _GstH265DecoderPrivate
|
|||
|
||||
/* Picture currently being processed/decoded */
|
||||
GstH265Picture *current_picture;
|
||||
GstVideoCodecFrame *current_frame;
|
||||
|
||||
/* Slice (slice header + nalu) currently being processed/decodec */
|
||||
GstH265Slice current_slice;
|
||||
|
@ -101,8 +102,6 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstH265Decoder, gst_h265_decoder,
|
|||
|
||||
static gboolean gst_h265_decoder_start (GstVideoDecoder * decoder);
|
||||
static gboolean gst_h265_decoder_stop (GstVideoDecoder * decoder);
|
||||
static GstFlowReturn gst_h265_decoder_parse (GstVideoDecoder * decoder,
|
||||
GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
|
||||
static gboolean gst_h265_decoder_set_format (GstVideoDecoder * decoder,
|
||||
GstVideoCodecState * state);
|
||||
static GstFlowReturn gst_h265_decoder_finish (GstVideoDecoder * decoder);
|
||||
|
@ -124,7 +123,6 @@ gst_h265_decoder_class_init (GstH265DecoderClass * klass)
|
|||
|
||||
decoder_class->start = GST_DEBUG_FUNCPTR (gst_h265_decoder_start);
|
||||
decoder_class->stop = GST_DEBUG_FUNCPTR (gst_h265_decoder_stop);
|
||||
decoder_class->parse = GST_DEBUG_FUNCPTR (gst_h265_decoder_parse);
|
||||
decoder_class->set_format = GST_DEBUG_FUNCPTR (gst_h265_decoder_set_format);
|
||||
decoder_class->finish = GST_DEBUG_FUNCPTR (gst_h265_decoder_finish);
|
||||
decoder_class->flush = GST_DEBUG_FUNCPTR (gst_h265_decoder_flush);
|
||||
|
@ -136,7 +134,7 @@ gst_h265_decoder_class_init (GstH265DecoderClass * klass)
|
|||
static void
|
||||
gst_h265_decoder_init (GstH265Decoder * self)
|
||||
{
|
||||
gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), FALSE);
|
||||
gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
|
||||
|
||||
self->priv = gst_h265_decoder_get_instance_private (self);
|
||||
}
|
||||
|
@ -189,8 +187,6 @@ gst_h265_decoder_parse_vps (GstH265Decoder * self, GstH265NalUnit * nalu)
|
|||
GstH265ParserResult pres;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
gst_h265_decoder_finish_current_picture (self);
|
||||
|
||||
pres = gst_h265_parser_parse_vps (priv->parser, nalu, &vps);
|
||||
if (pres != GST_H265_PARSER_OK) {
|
||||
GST_WARNING_OBJECT (self, "Failed to parse VPS, result %d", pres);
|
||||
|
@ -277,8 +273,6 @@ gst_h265_decoder_parse_sps (GstH265Decoder * self, GstH265NalUnit * nalu)
|
|||
GstH265ParserResult pres;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
gst_h265_decoder_finish_current_picture (self);
|
||||
|
||||
pres = gst_h265_parser_parse_sps (priv->parser, nalu, &sps, TRUE);
|
||||
if (pres != GST_H265_PARSER_OK) {
|
||||
GST_WARNING_OBJECT (self, "Failed to parse SPS, result %d", pres);
|
||||
|
@ -300,8 +294,6 @@ gst_h265_decoder_parse_pps (GstH265Decoder * self, GstH265NalUnit * nalu)
|
|||
GstH265PPS pps;
|
||||
GstH265ParserResult pres;
|
||||
|
||||
gst_h265_decoder_finish_current_picture (self);
|
||||
|
||||
pres = gst_h265_parser_parse_pps (priv->parser, nalu, &pps);
|
||||
if (pres != GST_H265_PARSER_OK) {
|
||||
GST_WARNING_OBJECT (self, "Failed to parse PPS, result %d", pres);
|
||||
|
@ -347,7 +339,7 @@ gst_h265_decoder_preprocess_slice (GstH265Decoder * self, GstH265Slice * slice)
|
|||
|
||||
if (IS_IDR (nalu->type)) {
|
||||
GST_DEBUG_OBJECT (self, "IDR nalu, clear dpb");
|
||||
gst_h265_decoder_flush (GST_VIDEO_DECODER (self));
|
||||
gst_h265_decoder_drain (GST_VIDEO_DECODER (self));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -398,6 +390,9 @@ gst_h265_decoder_parse_slice (GstH265Decoder * self, GstH265NalUnit * nalu,
|
|||
}
|
||||
|
||||
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");
|
||||
|
@ -413,65 +408,24 @@ gst_h265_decoder_parse_slice (GstH265Decoder * self, GstH265NalUnit * nalu,
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_h265_decoder_parse_nal (GstH265Decoder * self, const guint8 * data,
|
||||
gsize size, GstClockTime pts, gboolean at_eos, gsize * consumed_size)
|
||||
gst_h265_decoder_decode_nal (GstH265Decoder * self, GstH265NalUnit * nalu,
|
||||
GstClockTime pts)
|
||||
{
|
||||
GstH265DecoderPrivate *priv = self->priv;
|
||||
GstH265ParserResult pres;
|
||||
GstH265NalUnit nalu;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
*consumed_size = 0;
|
||||
|
||||
if (priv->in_format == GST_H265_DECODER_FORMAT_HVC1 ||
|
||||
priv->in_format == GST_H265_DECODER_FORMAT_HEV1) {
|
||||
if (priv->nal_length_size < 1 || priv->nal_length_size > 4) {
|
||||
GST_ERROR_OBJECT (self,
|
||||
"invalid nal length size %d", priv->nal_length_size);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
pres = gst_h265_parser_identify_nalu_hevc (priv->parser,
|
||||
data, 0, size, priv->nal_length_size, &nalu);
|
||||
|
||||
if (pres != GST_H265_PARSER_OK) {
|
||||
GST_WARNING_OBJECT (self, "parsing hevc nal ret %d", pres);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (size < 5) {
|
||||
GST_DEBUG_OBJECT (self, "Too small data");
|
||||
return GST_VIDEO_DECODER_FLOW_NEED_DATA;
|
||||
}
|
||||
|
||||
pres = gst_h265_parser_identify_nalu (priv->parser, data, 0, size, &nalu);
|
||||
|
||||
if (pres != GST_H265_PARSER_OK) {
|
||||
if (pres == GST_H265_PARSER_NO_NAL_END) {
|
||||
if (at_eos || priv->align == GST_H265_DECODER_ALIGN_AU) {
|
||||
/* assume au boundary */
|
||||
} else {
|
||||
return GST_VIDEO_DECODER_FLOW_NEED_DATA;
|
||||
}
|
||||
} else {
|
||||
GST_WARNING_OBJECT (self, "parser ret %d", pres);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (self, "Parsed nal type: %d, offset %d, size %d",
|
||||
nalu.type, nalu.offset, nalu.size);
|
||||
nalu->type, nalu->offset, nalu->size);
|
||||
|
||||
switch (nalu.type) {
|
||||
switch (nalu->type) {
|
||||
case GST_H265_NAL_VPS:
|
||||
ret = gst_h265_decoder_parse_vps (self, &nalu);
|
||||
ret = gst_h265_decoder_parse_vps (self, nalu);
|
||||
break;
|
||||
case GST_H265_NAL_SPS:
|
||||
ret = gst_h265_decoder_parse_sps (self, &nalu);
|
||||
ret = gst_h265_decoder_parse_sps (self, nalu);
|
||||
break;
|
||||
case GST_H265_NAL_PPS:
|
||||
ret = gst_h265_decoder_parse_pps (self, &nalu);
|
||||
ret = gst_h265_decoder_parse_pps (self, nalu);
|
||||
break;
|
||||
case GST_H265_NAL_SLICE_TRAIL_N:
|
||||
case GST_H265_NAL_SLICE_TRAIL_R:
|
||||
|
@ -489,77 +443,22 @@ gst_h265_decoder_parse_nal (GstH265Decoder * self, const guint8 * data,
|
|||
case GST_H265_NAL_SLICE_IDR_W_RADL:
|
||||
case GST_H265_NAL_SLICE_IDR_N_LP:
|
||||
case GST_H265_NAL_SLICE_CRA_NUT:
|
||||
ret = gst_h265_decoder_parse_slice (self, &nalu, pts);
|
||||
ret = gst_h265_decoder_parse_slice (self, nalu, pts);
|
||||
priv->new_bitstream = FALSE;
|
||||
priv->prev_nal_is_eos = FALSE;
|
||||
break;
|
||||
case GST_H265_NAL_EOB:
|
||||
ret = gst_h265_decoder_flush (GST_VIDEO_DECODER (self));
|
||||
gst_h265_decoder_drain (GST_VIDEO_DECODER (self));
|
||||
priv->new_bitstream = TRUE;
|
||||
break;
|
||||
case GST_H265_NAL_EOS:
|
||||
ret = gst_h265_decoder_flush (GST_VIDEO_DECODER (self));
|
||||
gst_h265_decoder_drain (GST_VIDEO_DECODER (self));
|
||||
priv->prev_nal_is_eos = TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (consumed_size)
|
||||
*consumed_size = nalu.offset + nalu.size;
|
||||
|
||||
if (!ret)
|
||||
return GST_FLOW_ERROR;
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_h265_decoder_parse (GstVideoDecoder * decoder,
|
||||
GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
|
||||
{
|
||||
GstH265Decoder *self = GST_H265_DECODER (decoder);
|
||||
GstH265DecoderPrivate *priv = self->priv;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint size;
|
||||
const guint8 *data;
|
||||
gsize consumed = 0;
|
||||
|
||||
/* The return from have_frame() or output_picture() */
|
||||
priv->last_ret = GST_FLOW_OK;
|
||||
|
||||
size = gst_adapter_available (adapter);
|
||||
|
||||
data = (const guint8 *) gst_adapter_map (adapter, size);
|
||||
ret = gst_h265_decoder_parse_nal (self, data, size,
|
||||
gst_adapter_prev_pts (adapter, NULL), at_eos, &consumed);
|
||||
gst_adapter_unmap (adapter);
|
||||
|
||||
if (consumed) {
|
||||
GST_TRACE_OBJECT (self, "consumed size %" G_GSIZE_FORMAT, consumed);
|
||||
gst_video_decoder_add_to_frame (decoder, consumed);
|
||||
}
|
||||
|
||||
if (ret == GST_FLOW_ERROR)
|
||||
goto error;
|
||||
|
||||
/* When AU alginment and has no available input data more,
|
||||
* finish current picture if any */
|
||||
if (priv->align == GST_H265_DECODER_ALIGN_AU &&
|
||||
!gst_adapter_available (adapter)) {
|
||||
gst_h265_decoder_finish_current_picture (self);
|
||||
}
|
||||
|
||||
/* check last flow return again */
|
||||
if (ret == GST_FLOW_ERROR)
|
||||
goto error;
|
||||
|
||||
return priv->last_ret;
|
||||
|
||||
error:
|
||||
GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
|
||||
("Failed to decode data"), (NULL), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -757,14 +656,10 @@ static gboolean
|
|||
gst_h265_decoder_flush (GstVideoDecoder * decoder)
|
||||
{
|
||||
GstH265Decoder *self = GST_H265_DECODER (decoder);
|
||||
gboolean ret = TRUE;
|
||||
|
||||
if (!gst_h265_decoder_output_all_remaining_pics (self))
|
||||
ret = FALSE;
|
||||
|
||||
gst_h265_decoder_clear_dpb (self);
|
||||
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -773,7 +668,9 @@ gst_h265_decoder_drain (GstVideoDecoder * decoder)
|
|||
GstH265Decoder *self = GST_H265_DECODER (decoder);
|
||||
GstH265DecoderPrivate *priv = self->priv;
|
||||
|
||||
gst_h265_decoder_flush (decoder);
|
||||
priv->last_ret = GST_FLOW_OK;
|
||||
gst_h265_decoder_output_all_remaining_pics (self);
|
||||
gst_h265_decoder_clear_dpb (self);
|
||||
|
||||
return priv->last_ret;
|
||||
}
|
||||
|
@ -1257,7 +1154,7 @@ gst_h265_decoder_dpb_init (GstH265Decoder * self, const GstH265Slice * slice,
|
|||
|
||||
if (picture->NoOutputOfPriorPicsFlag) {
|
||||
GST_DEBUG_OBJECT (self, "Clear dpb");
|
||||
gst_h265_decoder_flush (GST_VIDEO_DECODER (self));
|
||||
gst_h265_decoder_drain (GST_VIDEO_DECODER (self));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1456,13 +1353,6 @@ gst_h265_decoder_finish_current_picture (GstH265Decoder * self)
|
|||
if (klass->end_picture)
|
||||
ret = klass->end_picture (self, priv->current_picture);
|
||||
|
||||
if (priv->current_picture->output_flag) {
|
||||
gst_video_decoder_have_frame (GST_VIDEO_DECODER (self));
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (self, "Skip have_frame for picture %p",
|
||||
priv->current_picture);
|
||||
}
|
||||
|
||||
/* finish picture takes ownership of the picture */
|
||||
ret = gst_h265_decoder_finish_picture (self, priv->current_picture);
|
||||
priv->current_picture = NULL;
|
||||
|
@ -1482,24 +1372,67 @@ gst_h265_decoder_handle_frame (GstVideoDecoder * decoder,
|
|||
GstH265Decoder *self = GST_H265_DECODER (decoder);
|
||||
GstH265DecoderPrivate *priv = self->priv;
|
||||
GstBuffer *in_buf = frame->input_buffer;
|
||||
GstH265NalUnit nalu;
|
||||
GstH265ParserResult pres;
|
||||
GstMapInfo map;
|
||||
gboolean decode_ret = TRUE;
|
||||
|
||||
GST_LOG_OBJECT (self,
|
||||
"handle frame, PTS: %" GST_TIME_FORMAT ", DTS: %"
|
||||
GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (in_buf)),
|
||||
GST_TIME_ARGS (GST_BUFFER_DTS (in_buf)));
|
||||
|
||||
if (!priv->current_picture) {
|
||||
GST_ERROR_OBJECT (self, "No current picture");
|
||||
gst_video_decoder_drop_frame (decoder, frame);
|
||||
priv->current_frame = frame;
|
||||
priv->last_ret = GST_FLOW_OK;
|
||||
|
||||
return GST_FLOW_ERROR;
|
||||
gst_buffer_map (in_buf, &map, GST_MAP_READ);
|
||||
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,
|
||||
map.data, 0, map.size, priv->nal_length_size, &nalu);
|
||||
|
||||
while (pres == GST_H265_PARSER_OK && decode_ret) {
|
||||
decode_ret = gst_h265_decoder_decode_nal (self,
|
||||
&nalu, GST_BUFFER_PTS (in_buf));
|
||||
|
||||
pres = gst_h265_parser_identify_nalu_hevc (priv->parser,
|
||||
map.data, nalu.offset + nalu.size, map.size, priv->nal_length_size,
|
||||
&nalu);
|
||||
}
|
||||
} else {
|
||||
pres = gst_h265_parser_identify_nalu (priv->parser,
|
||||
map.data, 0, map.size, &nalu);
|
||||
|
||||
if (pres == GST_H265_PARSER_NO_NAL_END)
|
||||
pres = GST_H265_PARSER_OK;
|
||||
|
||||
while (pres == GST_H265_PARSER_OK && decode_ret) {
|
||||
decode_ret = gst_h265_decoder_decode_nal (self,
|
||||
&nalu, GST_BUFFER_PTS (in_buf));
|
||||
|
||||
pres = gst_h265_parser_identify_nalu (priv->parser,
|
||||
map.data, nalu.offset + nalu.size, map.size, &nalu);
|
||||
|
||||
if (pres == GST_H265_PARSER_NO_NAL_END)
|
||||
pres = GST_H265_PARSER_OK;
|
||||
}
|
||||
}
|
||||
|
||||
gst_video_codec_frame_set_user_data (frame,
|
||||
gst_h265_picture_ref (priv->current_picture),
|
||||
(GDestroyNotify) gst_h265_picture_unref);
|
||||
gst_buffer_unmap (in_buf, &map);
|
||||
priv->current_frame = NULL;
|
||||
|
||||
if (!decode_ret) {
|
||||
GST_VIDEO_DECODER_ERROR (self, 1, STREAM, DECODE,
|
||||
("Failed to decode data"), (NULL), priv->last_ret);
|
||||
gst_video_decoder_drop_frame (decoder, frame);
|
||||
|
||||
gst_h265_picture_clear (&priv->current_picture);
|
||||
|
||||
return priv->last_ret;
|
||||
}
|
||||
|
||||
gst_h265_decoder_finish_current_picture (self);
|
||||
gst_video_codec_frame_unref (frame);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
return priv->last_ret;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue