decoder: h264: add support for NALU "alignment" optimization.
authorSreerenj Balachandran <sreerenj.balachandran@intel.com>
Thu, 6 Feb 2014 06:30:10 +0000 (08:30 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Thu, 19 Jun 2014 13:29:12 +0000 (15:29 +0200)
We can avoid scanning for start codes again if the bitstream is fed
in NALU chunks. Currently, we always scan for start codes, and keep
track of remaining bits in a GstAdapter, even if, in practice, we
are likely receiving one GstBuffer per NAL unit. i.e. h264parse with
"nal" alignment.

https://bugzilla.gnome.org/show_bug.cgi?id=723284

[use gst_adapter_available_fast() to determine the top buffer size]
Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
gst-libs/gst/vaapi/gstvaapidecoder_h264.c
gst-libs/gst/vaapi/gstvaapidecoder_h264.h
gst/vaapi/gstvaapidecode.c

index 1e709b5..68c2b81 100644 (file)
@@ -445,6 +445,7 @@ struct _GstVaapiDecoderH264Private {
     GstH264NalParser           *parser;
     guint                       parser_state;
     guint                       decoder_state;
+    GstVaapiStreamAlignH264     stream_alignment;
     GstVaapiPictureH264        *current_picture;
     GstVaapiParserInfoH264     *sps[GST_H264_MAX_SPS_COUNT];
     GstVaapiParserInfoH264     *active_sps;
@@ -3880,7 +3881,14 @@ gst_vaapi_decoder_h264_parse(GstVaapiDecoder *base_decoder,
     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
         return status;
 
-    size = gst_adapter_available(adapter);
+    switch (priv->stream_alignment) {
+    case GST_VAAPI_STREAM_ALIGN_H264_NALU:
+        size = gst_adapter_available_fast(adapter);
+        break;
+    default:
+        size = gst_adapter_available(adapter);
+        break;
+    }
 
     if (priv->is_avcC) {
         if (size < priv->nal_length_size)
@@ -3902,30 +3910,34 @@ gst_vaapi_decoder_h264_parse(GstVaapiDecoder *base_decoder,
         if (size < 4)
             return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
 
-        ofs = scan_for_start_code(adapter, 0, size, NULL);
-        if (ofs < 0)
-            return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
-
-        if (ofs > 0) {
-            gst_adapter_flush(adapter, ofs);
-            size -= ofs;
-        }
+        if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H264_NALU)
+            buf_size = size;
+        else {
+            ofs = scan_for_start_code(adapter, 0, size, NULL);
+            if (ofs < 0)
+                return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
 
-        ofs2 = ps->input_offset2 - ofs - 4;
-        if (ofs2 < 4)
-            ofs2 = 4;
+            if (ofs > 0) {
+                gst_adapter_flush(adapter, ofs);
+                size -= ofs;
+            }
 
-        ofs = G_UNLIKELY(size < ofs2 + 4) ? -1 :
-            scan_for_start_code(adapter, ofs2, size - ofs2, NULL);
-        if (ofs < 0) {
-            // Assume the whole NAL unit is present if end-of-stream
-            if (!at_eos) {
-                ps->input_offset2 = size;
-                return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+            ofs2 = ps->input_offset2 - ofs - 4;
+            if (ofs2 < 4)
+                ofs2 = 4;
+
+            ofs = G_UNLIKELY(size < ofs2 + 4) ? -1 :
+                scan_for_start_code(adapter, ofs2, size - ofs2, NULL);
+            if (ofs < 0) {
+                // Assume the whole NAL unit is present if end-of-stream
+                if (!at_eos) {
+                    ps->input_offset2 = size;
+                    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+                }
+                ofs = size;
             }
-            ofs = size;
+            buf_size = ofs;
         }
-        buf_size = ofs;
     }
     ps->input_offset2 = 0;
 
@@ -4128,6 +4140,24 @@ gst_vaapi_decoder_h264_class(void)
 }
 
 /**
+ * gst_vaapi_decoder_h264_set_alignment:
+ * @decoder: a #GstVaapiDecoderH264
+ * @alignment: the #GstVaapiStreamAlignH264
+ *
+ * Specifies how stream buffers are aligned / fed, i.e. the boundaries
+ * of each buffer that is supplied to the decoder. This could be no
+ * specific alignment, NAL unit boundaries, or access unit boundaries.
+ */
+void
+gst_vaapi_decoder_h264_set_alignment(GstVaapiDecoderH264 *decoder,
+    GstVaapiStreamAlignH264 alignment)
+{
+    g_return_if_fail(decoder != NULL);
+
+    decoder->priv.stream_alignment = alignment;
+}
+
+/**
  * gst_vaapi_decoder_h264_new:
  * @display: a #GstVaapiDisplay
  * @caps: a #GstCaps holding codec information
index 05c010b..f9949dd 100644 (file)
 
 G_BEGIN_DECLS
 
+#define GST_VAAPI_DECODER_H264(decoder) \
+    ((GstVaapiDecoderH264 *)(decoder))
+
 typedef struct _GstVaapiDecoderH264             GstVaapiDecoderH264;
 
+/**
+ * GstVaapiStreamAlignH264:
+ * @GST_VAAPI_STREAM_ALIGN_H264_NONE: Generic H.264 stream buffers
+ * @GST_VAAPI_STREAM_ALIGN_H264_NALU: H.264 stream buffers aligned NAL
+ *   unit boundaries
+ * @GST_VAAPI_STREAM_ALIGN_H264_AU: H.264 stream buffers aligned on
+ *   access unit boundaries
+ *
+ * Set of possible buffer alignments for H.264 streams.
+ */
+typedef enum {
+    GST_VAAPI_STREAM_ALIGN_H264_NONE,
+    GST_VAAPI_STREAM_ALIGN_H264_NALU,
+    GST_VAAPI_STREAM_ALIGN_H264_AU
+} GstVaapiStreamAlignH264;
+
 GstVaapiDecoder *
 gst_vaapi_decoder_h264_new(GstVaapiDisplay *display, GstCaps *caps);
 
+void
+gst_vaapi_decoder_h264_set_alignment(GstVaapiDecoderH264 *decoder,
+    GstVaapiStreamAlignH264 alignment);
+
 G_END_DECLS
 
 #endif /* GST_VAAPI_DECODER_H264_H */
index 8ccc169..49df984 100644 (file)
@@ -644,6 +644,24 @@ gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
         break;
     case GST_VAAPI_CODEC_H264:
         decode->decoder = gst_vaapi_decoder_h264_new(dpy, caps);
+
+        /* Set the stream buffer alignment for better optimizations */
+        if (decode->decoder && caps) {
+            GstStructure * const structure = gst_caps_get_structure(caps, 0);
+            const gchar *str = NULL;
+
+            if ((str = gst_structure_get_string(structure, "alignment"))) {
+                GstVaapiStreamAlignH264 alignment;
+                if (g_strcmp0(str, "au") == 0)
+                    alignment = GST_VAAPI_STREAM_ALIGN_H264_AU;
+                else if (g_strcmp0(str, "nal") == 0)
+                    alignment = GST_VAAPI_STREAM_ALIGN_H264_NALU;
+                else
+                    alignment = GST_VAAPI_STREAM_ALIGN_H264_NONE;
+                gst_vaapi_decoder_h264_set_alignment(
+                    GST_VAAPI_DECODER_H264(decode->decoder), alignment);
+            }
+        }
         break;
     case GST_VAAPI_CODEC_WMV3:
     case GST_VAAPI_CODEC_VC1: