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.
This commit is contained in:
Gwenole Beauchesne 2012-03-02 13:41:16 +01:00
parent c979d51da6
commit 63e29adbf5
2 changed files with 65 additions and 3 deletions

View file

@ -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 <gst/codecparsers/gsth264parser.h>],
[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]

View file

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