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 <gwenole.beauchesne@intel.com>
This commit is contained in:
Sreerenj Balachandran 2014-02-06 08:30:10 +02:00 committed by Gwenole Beauchesne
parent 95c781c34f
commit cb9f98f0d5
3 changed files with 93 additions and 22 deletions

View 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;
}
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

View file

@ -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 */

View 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: