libs: decoder: h265: skip all pictures prior the first I-frame
authorVíctor Manuel Jáquez Leal <vjaquez@igalia.com>
Sun, 3 Nov 2019 16:59:01 +0000 (17:59 +0100)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 29 Nov 2019 15:34:05 +0000 (15:34 +0000)
Don't try to decode until the first I-frame is received within the
currently active sequence. i965 H265 decoder don't show any artifact
but it crashes.

Fixes: #98
gst-libs/gst/vaapi/gstvaapidecoder_h265.c

index a04c74b8eed01c403ddbc8847160988937541f3d..5d554fce466892d3fc7c2493f09389654a163c5d 100644 (file)
@@ -334,6 +334,8 @@ typedef enum
   GST_H265_VIDEO_STATE_GOT_SPS = 1 << 1,
   GST_H265_VIDEO_STATE_GOT_PPS = 1 << 2,
   GST_H265_VIDEO_STATE_GOT_SLICE = 1 << 3,
+  GST_H265_VIDEO_STATE_GOT_I_FRAME = 1 << 4,    /* persistent across SPS */
+  GST_H265_VIDEO_STATE_GOT_P_SLICE = 1 << 5,    /* predictive (all non-intra) */
 
   GST_H265_VIDEO_STATE_VALID_PICTURE_HEADERS =
       (GST_H265_VIDEO_STATE_GOT_SPS | GST_H265_VIDEO_STATE_GOT_PPS),
@@ -583,6 +585,11 @@ ensure_sps (GstVaapiDecoderH265 * decoder, GstH265SPS * sps)
   GstVaapiDecoderH265Private *const priv = &decoder->priv;
   GstVaapiParserInfoH265 *const pi = priv->sps[sps->id];
 
+  /* Propagate "got I-frame" state to the next SPS unit if the current
+   * sequence was not ended */
+  if (pi && priv->active_sps)
+    pi->state |= (priv->active_sps->state & GST_H265_VIDEO_STATE_GOT_I_FRAME);
+
   gst_vaapi_parser_info_h265_replace (&priv->active_sps, pi);
   return pi ? &pi->data.sps : NULL;
 }
@@ -1317,12 +1324,20 @@ static GstVaapiDecoderStatus
 decode_current_picture (GstVaapiDecoderH265 * decoder)
 {
   GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const sps_pi = decoder->priv.active_sps;
   GstVaapiPictureH265 *const picture = priv->current_picture;
 
   if (!is_valid_state (priv->decoder_state, GST_H265_VIDEO_STATE_VALID_PICTURE)) {
     goto drop_frame;
   }
 
+  priv->decoder_state |= sps_pi->state;
+  if (!(priv->decoder_state & GST_H265_VIDEO_STATE_GOT_I_FRAME)) {
+    if (priv->decoder_state & GST_H265_VIDEO_STATE_GOT_P_SLICE)
+      goto drop_frame;
+    sps_pi->state |= GST_H265_VIDEO_STATE_GOT_I_FRAME;
+  }
+
   priv->decoder_state = 0;
   /* FIXME: Use SEI header values */
   priv->pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
@@ -1459,6 +1474,8 @@ parse_slice (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
     return get_status (result);
 
   priv->parser_state |= GST_H265_VIDEO_STATE_GOT_SLICE;
+  if (!GST_H265_IS_I_SLICE (slice_hdr))
+    priv->parser_state |= GST_H265_VIDEO_STATE_GOT_P_SLICE;
   return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
@@ -1548,9 +1565,15 @@ static GstVaapiDecoderStatus
 decode_sequence_end (GstVaapiDecoderH265 * decoder)
 {
   GstVaapiDecoderStatus status;
+  GstVaapiParserInfoH265 *const sps_pi = decoder->priv.active_sps;
 
   GST_DEBUG ("decode sequence-end");
 
+  /* Sequence ended, don't try to propagate "got I-frame" state beyond
+   * this point */
+  if (sps_pi)
+    sps_pi->state &= ~GST_H265_VIDEO_STATE_GOT_I_FRAME;
+
   status = decode_current_picture (decoder);
   if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
     return status;
@@ -2718,7 +2741,6 @@ decode_slice (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
 
   gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
   picture->last_slice_hdr = slice_hdr;
-  priv->decoder_state |= GST_H265_VIDEO_STATE_GOT_SLICE;
   return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }