Implement decoder reset on flush, rather than recreating

Clear decoders out on a flush but keep the same instance,
rather than completely recreating them. That avoids
unecessarily freeing and recreating surface pools
and contexts, which can be quite expensive

https://bugzilla.gnome.org/show_bug.cgi?id=781142
This commit is contained in:
Jan Schmidt 2017-04-05 17:24:20 +10:00
parent bd2e304ea4
commit a7a9b33ad9
8 changed files with 112 additions and 28 deletions

View file

@ -40,6 +40,26 @@
static void drop_frame (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame); static void drop_frame (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame);
static void
parser_state_reset (GstVaapiParserState * ps)
{
if (ps->input_adapter)
gst_adapter_clear (ps->input_adapter);
if (ps->output_adapter)
gst_adapter_clear (ps->output_adapter);
ps->current_adapter = NULL;
if (ps->next_unit_pending) {
gst_vaapi_decoder_unit_clear (&ps->next_unit);
ps->next_unit_pending = FALSE;
}
ps->current_frame_number = 0;
ps->input_offset1 = ps->input_offset2 = 0;
ps->at_eos = FALSE;
}
static void static void
parser_state_finalize (GstVaapiParserState * ps) parser_state_finalize (GstVaapiParserState * ps)
{ {
@ -266,16 +286,6 @@ do_decode (GstVaapiDecoder * decoder, GstVideoCodecFrame * base_frame)
return status; return status;
} }
static inline GstVaapiDecoderStatus
do_flush (GstVaapiDecoder * decoder)
{
GstVaapiDecoderClass *const klass = GST_VAAPI_DECODER_GET_CLASS (decoder);
if (klass->flush)
return klass->flush (decoder);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus static GstVaapiDecoderStatus
decode_step (GstVaapiDecoder * decoder) decode_step (GstVaapiDecoder * decoder)
{ {
@ -1029,13 +1039,69 @@ gst_vaapi_decoder_decode (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame)
return do_decode (decoder, frame); return do_decode (decoder, frame);
} }
/* This function really marks the end of input,
* so that the decoder will drain out any pending
* frames on calls to gst_vaapi_decoder_get_frame_with_timeout() */
GstVaapiDecoderStatus GstVaapiDecoderStatus
gst_vaapi_decoder_flush (GstVaapiDecoder * decoder) gst_vaapi_decoder_flush (GstVaapiDecoder * decoder)
{ {
GstVaapiDecoderClass *klass;
g_return_val_if_fail (decoder != NULL, g_return_val_if_fail (decoder != NULL,
GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER); GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
return do_flush (decoder); klass = GST_VAAPI_DECODER_GET_CLASS (decoder);
if (klass->flush)
return klass->flush (decoder);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
/* Reset the decoder instance to a clean state,
* clearing any pending decode state, without
* reallocating the entire decoder */
GstVaapiDecoderStatus
gst_vaapi_decoder_reset (GstVaapiDecoder * decoder)
{
GstVaapiDecoderClass *klass;
GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
g_return_val_if_fail (decoder != NULL,
GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
klass = GST_VAAPI_DECODER_GET_CLASS (decoder);
GST_DEBUG ("Resetting decoder");
if (klass->reset) {
ret = klass->reset (decoder);
} else {
if (klass->destroy)
klass->destroy (decoder);
if (klass->create)
if (!klass->create (decoder))
ret = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS)
return ret;
/* Clear any buffers and frame in the queues */
{
GstVideoCodecFrame *frame;
GstBuffer *buffer;
while ((frame = g_async_queue_try_pop (decoder->frames)) != NULL)
gst_video_codec_frame_unref (frame);
while ((buffer = g_async_queue_try_pop (decoder->buffers)) != NULL)
gst_buffer_unref (buffer);
}
parser_state_reset (&decoder->parser_state);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
} }
GstVaapiDecoderStatus GstVaapiDecoderStatus

View file

@ -132,6 +132,9 @@ gst_vaapi_decoder_decode (GstVaapiDecoder * decoder,
GstVaapiDecoderStatus GstVaapiDecoderStatus
gst_vaapi_decoder_flush (GstVaapiDecoder * decoder); gst_vaapi_decoder_flush (GstVaapiDecoder * decoder);
GstVaapiDecoderStatus
gst_vaapi_decoder_reset (GstVaapiDecoder * decoder);
GstVaapiDecoderStatus GstVaapiDecoderStatus
gst_vaapi_decoder_check_status (GstVaapiDecoder * decoder); gst_vaapi_decoder_check_status (GstVaapiDecoder * decoder);

View file

@ -1221,10 +1221,11 @@ gst_vaapi_decoder_h264_destroy (GstVaapiDecoder * base_decoder)
guint i; guint i;
gst_vaapi_decoder_h264_close (decoder); gst_vaapi_decoder_h264_close (decoder);
priv->is_opened = FALSE;
g_free (priv->dpb); g_free (priv->dpb);
priv->dpb = NULL; priv->dpb = NULL;
priv->dpb_size = 0; priv->dpb_size_max = priv->dpb_size = 0;
g_free (priv->prev_ref_frames); g_free (priv->prev_ref_frames);
priv->prev_ref_frames = NULL; priv->prev_ref_frames = NULL;

View file

@ -957,6 +957,8 @@ gst_vaapi_decoder_h265_close (GstVaapiDecoderH265 * decoder)
gst_h265_parser_free (priv->parser); gst_h265_parser_free (priv->parser);
priv->parser = NULL; priv->parser = NULL;
} }
priv->is_opened = FALSE;
} }
static gboolean static gboolean
@ -982,7 +984,8 @@ gst_vaapi_decoder_h265_destroy (GstVaapiDecoder * base_decoder)
gst_vaapi_decoder_h265_close (decoder); gst_vaapi_decoder_h265_close (decoder);
g_free (priv->dpb); g_free (priv->dpb);
priv->dpb = NULL; priv->dpb = NULL;
priv->dpb_size = 0; priv->dpb_count = priv->dpb_size_max = priv->dpb_size = 0;
for (i = 0; i < G_N_ELEMENTS (priv->pps); i++) for (i = 0; i < G_N_ELEMENTS (priv->pps); i++)
gst_vaapi_parser_info_h265_replace (&priv->pps[i], NULL); gst_vaapi_parser_info_h265_replace (&priv->pps[i], NULL);
gst_vaapi_parser_info_h265_replace (&priv->active_pps, NULL); gst_vaapi_parser_info_h265_replace (&priv->active_pps, NULL);

View file

@ -317,6 +317,8 @@ gst_vaapi_decoder_mpeg2_close (GstVaapiDecoderMpeg2 * decoder)
priv->state = 0; priv->state = 0;
gst_vaapi_dpb_replace (&priv->dpb, NULL); gst_vaapi_dpb_replace (&priv->dpb, NULL);
priv->is_opened = FALSE;
} }
static gboolean static gboolean

View file

@ -225,6 +225,7 @@ struct _GstVaapiDecoderClass
struct _GstVaapiDecoderUnit * unit); struct _GstVaapiDecoderUnit * unit);
GstVaapiDecoderStatus (*end_frame) (GstVaapiDecoder * decoder); GstVaapiDecoderStatus (*end_frame) (GstVaapiDecoder * decoder);
GstVaapiDecoderStatus (*flush) (GstVaapiDecoder * decoder); GstVaapiDecoderStatus (*flush) (GstVaapiDecoder * decoder);
GstVaapiDecoderStatus (*reset) (GstVaapiDecoder * decoder);
GstVaapiDecoderStatus (*decode_codec_data) (GstVaapiDecoder * decoder, GstVaapiDecoderStatus (*decode_codec_data) (GstVaapiDecoder * decoder,
const guchar * buf, guint buf_size); const guchar * buf, guint buf_size);
}; };

View file

@ -67,7 +67,6 @@ struct _GstVaapiDecoderVC1Private
guint8 rndctrl; guint8 rndctrl;
guint rbdu_buffer_size; guint rbdu_buffer_size;
guint is_opened:1; guint is_opened:1;
guint is_first_field:1;
guint has_codec_data:1; guint has_codec_data:1;
guint has_entrypoint:1; guint has_entrypoint:1;
guint size_changed:1; guint size_changed:1;
@ -134,6 +133,7 @@ gst_vaapi_decoder_vc1_close (GstVaapiDecoderVC1 * decoder)
gst_vc1_bitplanes_free (priv->bitplanes); gst_vc1_bitplanes_free (priv->bitplanes);
priv->bitplanes = NULL; priv->bitplanes = NULL;
} }
priv->is_opened = FALSE;
} }
static gboolean static gboolean
@ -150,6 +150,11 @@ gst_vaapi_decoder_vc1_open (GstVaapiDecoderVC1 * decoder)
priv->bitplanes = gst_vc1_bitplanes_new (); priv->bitplanes = gst_vc1_bitplanes_new ();
if (!priv->bitplanes) if (!priv->bitplanes)
return FALSE; return FALSE;
memset (&priv->seq_hdr, 0, sizeof (GstVC1SeqHdr));
memset (&priv->entrypoint_hdr, 0, sizeof (GstVC1EntryPointHdr));
memset (&priv->frame_hdr, 0, sizeof (GstVC1FrameHdr));
return TRUE; return TRUE;
} }
@ -174,8 +179,13 @@ gst_vaapi_decoder_vc1_create (GstVaapiDecoder * base_decoder)
GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder); GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
GstVaapiDecoderVC1Private *const priv = &decoder->priv; GstVaapiDecoderVC1Private *const priv = &decoder->priv;
priv->has_codec_data = priv->has_entrypoint =
priv->size_changed = priv->profile_changed =
priv->closed_entry = priv->broken_link = FALSE;
priv->profile = (GstVaapiProfile) 0; priv->profile = (GstVaapiProfile) 0;
priv->rndctrl = 0; priv->rndctrl = 0;
priv->width = priv->height = 0;
return TRUE; return TRUE;
} }
@ -1357,6 +1367,9 @@ gst_vaapi_decoder_vc1_start_frame (GstVaapiDecoder * base_decoder,
GST_ERROR ("failed to reset context"); GST_ERROR ("failed to reset context");
return status; return status;
} }
status = ensure_decoder (decoder);
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
return status;
picture = GST_VAAPI_PICTURE_NEW (VC1, decoder); picture = GST_VAAPI_PICTURE_NEW (VC1, decoder);
if (!picture) { if (!picture) {

View file

@ -953,20 +953,21 @@ gst_vaapidecode_destroy (GstVaapiDecode * decode)
} }
static gboolean static gboolean
gst_vaapidecode_reset_full (GstVaapiDecode * decode, GstCaps * caps, gst_vaapidecode_reset (GstVaapiDecode * decode, GstCaps * caps,
gboolean hard) gboolean force_reset)
{ {
/* Reset tracked frame size */ /* Reset tracked frame size */
decode->current_frame_size = 0; decode->current_frame_size = 0;
if (!hard && decode->decoder) { if (decode->decoder) {
if (gst_vaapi_decoder_update_caps (decode->decoder, caps)) { if (gst_vaapi_decoder_update_caps (decode->decoder, caps)) {
g_atomic_int_set (&decode->do_renego, TRUE); g_atomic_int_set (&decode->do_renego, TRUE);
return TRUE; if (!force_reset)
return TRUE;
} }
return gst_vaapi_decoder_reset (decode->decoder);
} }
gst_vaapidecode_destroy (decode);
return gst_vaapidecode_create (decode, caps); return gst_vaapidecode_create (decode, caps);
} }
@ -1047,8 +1048,6 @@ static gboolean
gst_vaapidecode_flush (GstVideoDecoder * vdec) gst_vaapidecode_flush (GstVideoDecoder * vdec)
{ {
GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec); GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
gboolean reverse;
if (!decode->decoder) if (!decode->decoder)
return FALSE; return FALSE;
@ -1056,13 +1055,9 @@ gst_vaapidecode_flush (GstVideoDecoder * vdec)
gst_vaapidecode_purge (decode); gst_vaapidecode_purge (decode);
/* in reverse playback we cannot destroy the decoder at flush, since /* There could be issues if we avoid the reset() while doing
* it will lost the parsing state */
reverse = decode->in_segment.rate < 0;
/* There could be issues if we avoid the reset_full() while doing
* seeking: we have to reset the internal state */ * seeking: we have to reset the internal state */
return gst_vaapidecode_reset_full (decode, decode->sinkpad_caps, !reverse); return gst_vaapidecode_reset (decode, decode->sinkpad_caps, TRUE);
} }
static gboolean static gboolean
@ -1077,7 +1072,7 @@ gst_vaapidecode_set_format (GstVideoDecoder * vdec, GstVideoCodecState * state)
return FALSE; return FALSE;
if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL)) if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL))
return FALSE; return FALSE;
if (!gst_vaapidecode_reset_full (decode, decode->sinkpad_caps, FALSE)) if (!gst_vaapidecode_reset (decode, decode->sinkpad_caps, FALSE))
return FALSE; return FALSE;
return TRUE; return TRUE;