From cb9f98f0d5501f7f700e33bbc969d0ce420c2601 Mon Sep 17 00:00:00 2001 From: Sreerenj Balachandran Date: Thu, 6 Feb 2014 08:30:10 +0200 Subject: [PATCH] decoder: h264: add support for NALU "alignment" optimization. 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 --- gst-libs/gst/vaapi/gstvaapidecoder_h264.c | 74 ++++++++++++++++------- gst-libs/gst/vaapi/gstvaapidecoder_h264.h | 23 +++++++ gst/vaapi/gstvaapidecode.c | 18 ++++++ 3 files changed, 93 insertions(+), 22 deletions(-) diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c index 1e709b5952..68c2b8192a 100644 --- a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c @@ -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; - } - - 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; + 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; + + if (ofs > 0) { + gst_adapter_flush(adapter, ofs); + size -= ofs; } - ofs = size; + + 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; + } + buf_size = ofs; } - buf_size = ofs; } ps->input_offset2 = 0; @@ -4127,6 +4139,24 @@ gst_vaapi_decoder_h264_class(void) return GST_VAAPI_DECODER_CLASS(&g_class); } +/** + * 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 diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.h b/gst-libs/gst/vaapi/gstvaapidecoder_h264.h index 05c010b685..f9949dd126 100644 --- a/gst-libs/gst/vaapi/gstvaapidecoder_h264.h +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h264.h @@ -27,11 +27,34 @@ 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 */ diff --git a/gst/vaapi/gstvaapidecode.c b/gst/vaapi/gstvaapidecode.c index 8ccc169d21..49df98422d 100644 --- a/gst/vaapi/gstvaapidecode.c +++ b/gst/vaapi/gstvaapidecode.c @@ -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: