From 63e29adbf57bdc2b6f72eddd9690c2dc4c6e0b52 Mon Sep 17 00:00:00 2001 From: Gwenole Beauchesne Date: Fri, 2 Mar 2012 13:41:16 +0100 Subject: [PATCH] h264: fix slice_data_bit_offset calculation. Unlike what VA-API documentation defines, the slice_data_bit_offset represents the offset to the first macroblock in the slice data, minus any emulation prevention bytes in the slice_header(). This fix copes with binary-only VA drivers that won't be fixed any time soon. Besides, this aligns with the current FFmpeg behaviour that was based on those proprietary drivers implementing the API incorrectly. --- configure.ac | 24 +++++++++++++++++ gst-libs/gst/vaapi/gstvaapidecoder_h264.c | 44 ++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index f0184df..81583c5 100644 --- a/configure.ac +++ b/configure.ac @@ -247,6 +247,30 @@ AC_DEFINE_UNQUOTED(USE_CODEC_PARSERS, $USE_CODEC_PARSERS, [Defined to 1 if GStreamer codec parsers are used]) AM_CONDITIONAL(USE_CODEC_PARSERS, test $USE_CODEC_PARSERS -eq 1) +if test "$enable_codecparsers" = "yes"; then +AC_CACHE_CHECK([for GstH264SliceHdr::n_emulation_prevention_bytes], + ac_cv_have_gst_h264_slice_hdr_epb_count, [ + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $GST_CFLAGS $GST_CODEC_PARSERS_CFLAGS" + saved_LIBS="$LIBS" + LIBS="$LIBS $GST_LIBS $GST_CODEC_PARSERS_LIBS" + AC_TRY_COMPILE( + [#include ], + [GstH264SliceHdr slice_hdr; + slice_hdr.n_emulation_prevention_bytes = 0;], + [ac_cv_have_gst_h264_slice_hdr_epb_count="yes"], + [ac_cv_have_gst_h264_slice_hdr_epb_count="no"] + ) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" +]) +fi + +if test "$ac_cv_have_gst_h264_slice_hdr_epb_count" = "yes"; then + AC_DEFINE_UNQUOTED(HAVE_GST_H264_SLICE_HDR_EPB_COUNT, 1, + [Defined to 1 if GstH264SliceHdr::n_emulation_prevention_bytes exists.]) +fi + dnl Check for GStreamer interfaces PKG_CHECK_MODULES([GST_INTERFACES], [gstreamer-interfaces-$GST_MAJORMINOR >= $GST_PLUGINS_BASE_VERSION_REQUIRED] diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c index e19fa42..9ee3809 100644 --- a/gst-libs/gst/vaapi/gstvaapidecoder_h264.c +++ b/gst-libs/gst/vaapi/gstvaapidecoder_h264.c @@ -1965,6 +1965,40 @@ decode_picture_end(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture) return TRUE; } +#ifndef HAVE_GST_H264_SLICE_HDR_EPB_COUNT +static guint +get_epb_count(const guint8 *buf, guint buf_size, guint header_size) +{ + guint i, n = 0; + + if (buf_size > header_size) + buf_size = header_size; + + for (i = 2; i < buf_size; i++) { + if (!buf[i - 2] && !buf[i - 1] && buf[i] == 0x03) + i += 2, n++; + } + return n; +} +#endif + +static inline guint +get_slice_data_bit_offset(GstH264SliceHdr *slice_hdr, GstH264NalUnit *nalu) +{ + guint epb_count; + +#ifdef HAVE_GST_H264_SLICE_HDR_EPB_COUNT + epb_count = slice_hdr->n_emulation_prevention_bytes; +#else + epb_count = get_epb_count( + nalu->data + nalu->offset, + nalu->size, + slice_hdr->header_size / 8 + ); +#endif + return 8 /* nal_unit_type */ + slice_hdr->header_size - epb_count * 8; +} + static gboolean fill_pred_weight_table(GstVaapiDecoderH264 *decoder, GstVaapiSliceH264 *slice) { @@ -2074,13 +2108,17 @@ fill_RefPicList(GstVaapiDecoderH264 *decoder, GstVaapiSliceH264 *slice) } static gboolean -fill_slice(GstVaapiDecoderH264 *decoder, GstVaapiSliceH264 *slice) +fill_slice( + GstVaapiDecoderH264 *decoder, + GstVaapiSliceH264 *slice, + GstH264NalUnit *nalu +) { GstH264SliceHdr * const slice_hdr = &slice->slice_hdr; VASliceParameterBufferH264 * const slice_param = slice->base.param; /* Fill in VASliceParameterBufferH264 */ - slice_param->slice_data_bit_offset = 8 /* nal_unit_type */ + slice_hdr->header_size; + slice_param->slice_data_bit_offset = get_slice_data_bit_offset(slice_hdr, nalu); slice_param->first_mb_in_slice = slice_hdr->first_mb_in_slice; slice_param->slice_type = slice_hdr->type % 5; slice_param->direct_spatial_mv_pred_flag = slice_hdr->direct_spatial_mv_pred_flag; @@ -2137,7 +2175,7 @@ decode_slice(GstVaapiDecoderH264 *decoder, GstH264NalUnit *nalu) priv->mb_x = slice_hdr->first_mb_in_slice % priv->mb_width; priv->mb_y = slice_hdr->first_mb_in_slice / priv->mb_width; // FIXME: MBAFF or field - if (!fill_slice(decoder, slice)) { + if (!fill_slice(decoder, slice, nalu)) { status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; goto error; } -- 2.7.4