From 9ed6ac1f763589dd3f77fdccfe6b3487c3a836ba Mon Sep 17 00:00:00 2001 From: Hyunjun Ko Date: Fri, 17 Mar 2017 17:14:01 +0900 Subject: [PATCH] libs: h26x: adds gst_vaapi_utils_h26x_write_nal_unit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements gst_vaapi_utils_h26x_write_nal_unit(), which writes NAL unit length and data to a bitwriter. Note that this helper function applies EPB (Emulation Prevention Bytes), since otherwise produced codec_data might be broken when decoder/parser considering EPB, starts parsing. See sections 7.3 and 7.4 of the H264 and H264 specifications, which describes the emulation_prevention_three_byte. https://bugzilla.gnome.org/show_bug.cgi?id=778750 Signed-off-by: Víctor Manuel Jáquez Leal --- gst-libs/gst/vaapi/gstvaapiencoder_h264.c | 18 +++- gst-libs/gst/vaapi/gstvaapiencoder_h265.c | 24 ++++-- gst-libs/gst/vaapi/gstvaapiutils_h26x.c | 89 ++++++++++++++++++++ gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h | 6 ++ 4 files changed, 127 insertions(+), 10 deletions(-) diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c index 801a721f7c..bd5e791216 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h264.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h264.c @@ -2532,13 +2532,15 @@ gst_vaapi_encoder_h264_get_codec_data (GstVaapiEncoder * base_encoder, /* Write SPS */ WRITE_UINT32 (&bs, 1, 5); /* SPS count = 1 */ g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); - WRITE_UINT32 (&bs, sps_info.size, 16); - gst_bit_writer_put_bytes (&bs, sps_info.data, sps_info.size); + /* Write Nal unit length and data of SPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, sps_info.data, sps_info.size)) + goto nal_to_byte_stream_error; /* Write PPS */ WRITE_UINT32 (&bs, 1, 8); /* PPS count = 1 */ - WRITE_UINT32 (&bs, pps_info.size, 16); - gst_bit_writer_put_bytes (&bs, pps_info.data, pps_info.size); + /* Write Nal unit length and data of PPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, pps_info.data, pps_info.size)) + goto nal_to_byte_stream_error; gst_buffer_unmap (encoder->pps_data, &pps_info); gst_buffer_unmap (encoder->sps_data, &sps_info); @@ -2561,6 +2563,14 @@ bs_error: gst_bit_writer_clear (&bs, TRUE); return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; } +nal_to_byte_stream_error: + { + GST_ERROR ("failed to write nal unit"); + gst_buffer_unmap (encoder->sps_data, &sps_info); + gst_buffer_unmap (encoder->pps_data, &pps_info); + gst_bit_writer_clear (&bs, TRUE); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } error_map_sps_buffer: { GST_ERROR ("failed to map SPS packed header"); diff --git a/gst-libs/gst/vaapi/gstvaapiencoder_h265.c b/gst-libs/gst/vaapi/gstvaapiencoder_h265.c index e156fdbb49..8d30287ec0 100644 --- a/gst-libs/gst/vaapi/gstvaapiencoder_h265.c +++ b/gst-libs/gst/vaapi/gstvaapiencoder_h265.c @@ -2116,8 +2116,9 @@ gst_vaapi_encoder_h265_get_codec_data (GstVaapiEncoder * base_encoder, WRITE_UINT32 (&bs, GST_H265_NAL_VPS, 6); /* Nal_unit_type */ WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, VPS count = 1 */ g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); - WRITE_UINT32 (&bs, vps_info.size, 16); /* VPS nalUnitLength */ - gst_bit_writer_put_bytes (&bs, vps_info.data, vps_info.size); + /* Write Nal unit length and data of VPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, vps_info.data, vps_info.size)) + goto nal_to_byte_stream_error; /* Write SPS */ WRITE_UINT32 (&bs, 0x00, 1); /* array_completeness */ @@ -2125,16 +2126,18 @@ gst_vaapi_encoder_h265_get_codec_data (GstVaapiEncoder * base_encoder, WRITE_UINT32 (&bs, GST_H265_NAL_SPS, 6); /* Nal_unit_type */ WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, SPS count = 1 */ g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0); - WRITE_UINT32 (&bs, sps_info.size, 16); /* SPS nalUnitLength */ - gst_bit_writer_put_bytes (&bs, sps_info.data, sps_info.size); + /* Write Nal unit length and data of SPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, sps_info.data, sps_info.size)) + goto nal_to_byte_stream_error; /* Write PPS */ WRITE_UINT32 (&bs, 0x00, 1); /* array_completeness */ WRITE_UINT32 (&bs, 0x00, 1); /* reserved zero */ WRITE_UINT32 (&bs, GST_H265_NAL_PPS, 6); /* Nal_unit_type */ WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, PPS count = 1 */ - WRITE_UINT32 (&bs, pps_info.size, 16); /* PPS nalUnitLength */ - gst_bit_writer_put_bytes (&bs, pps_info.data, pps_info.size); + /* Write Nal unit length and data of PPS */ + if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, pps_info.data, pps_info.size)) + goto nal_to_byte_stream_error; gst_buffer_unmap (encoder->pps_data, &pps_info); gst_buffer_unmap (encoder->sps_data, &sps_info); @@ -2159,6 +2162,15 @@ bs_error: gst_bit_writer_clear (&bs, TRUE); return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; } +nal_to_byte_stream_error: + { + GST_ERROR ("failed to write nal unit"); + gst_buffer_unmap (encoder->vps_data, &vps_info); + gst_buffer_unmap (encoder->sps_data, &sps_info); + gst_buffer_unmap (encoder->pps_data, &pps_info); + gst_bit_writer_clear (&bs, TRUE); + return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED; + } error_map_vps_buffer: { GST_ERROR ("failed to map VPS packed header"); diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h26x.c b/gst-libs/gst/vaapi/gstvaapiutils_h26x.c index 717be39339..4a679aaa74 100644 --- a/gst-libs/gst/vaapi/gstvaapiutils_h26x.c +++ b/gst-libs/gst/vaapi/gstvaapiutils_h26x.c @@ -3,6 +3,9 @@ * * Copyright (C) 2011-2014 Intel Corporation * Author: Gwenole Beauchesne + * Copyright (C) 2017 Intel Corporation + * Author: Hyunjun Ko + * Author: Mark Thompson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -56,3 +59,89 @@ bs_write_se (GstBitWriter * bs, gint32 value) return FALSE; return TRUE; } + +/* Copy from src to dst, applying emulation prevention bytes. + * + * This is copied from libavcodec written by Mark Thompson + * from + * http://git.videolan.org/?p=ffmpeg.git;a=commit;h=2c62fcdf5d617791a653d7957d449f75569eede0 + */ +static gboolean +gst_vaapi_utils_h26x_nal_unit_to_byte_stream (guint8 * dst, guint * dst_len, + guint8 * src, guint src_len) +{ + guint dp = 0, sp; + guint zero_run = 0; + + for (sp = 0; sp < src_len; sp++) { + if (dp >= *dst_len) + goto fail; + if (zero_run < 2) { + if (src[sp] == 0) + ++zero_run; + else + zero_run = 0; + } else { + if ((src[sp] & ~3) == 0) { + /* emulation_prevention_byte: 0x03 */ + dst[dp++] = 3; + if (dp >= *dst_len) + goto fail; + } + zero_run = src[sp] == 0; + } + dst[dp++] = src[sp]; + } + + *dst_len = dp; + return TRUE; + +fail: + *dst_len = 0; + return FALSE; +} + +/** + * gst_vaapi_utils_h26x_write_nal_unit: + * @bs: a #GstBitWriter instance + * @nal: the NAL (Network Abstraction Layer) unit to write + * @nal_size: the size, in bytes, of @nal + * + * Writes in the @bs the @nal rewritten with the "emulation prevention + * bytes" if required. + * + * Returns: TRUE if the NAL unit could be coded applying the + * "emulation prevention bytes"; otherwise FALSE. + **/ +gboolean +gst_vaapi_utils_h26x_write_nal_unit (GstBitWriter * bs, guint8 * nal, + guint nal_size) +{ + guint8 *byte_stream = NULL; + guint byte_stream_len; + + byte_stream_len = nal_size + 10; + byte_stream = g_malloc (byte_stream_len); + + if (!byte_stream) + return FALSE; + + if (!gst_vaapi_utils_h26x_nal_unit_to_byte_stream (byte_stream, + &byte_stream_len, nal, nal_size)) { + g_free (byte_stream); + return FALSE; + } + + WRITE_UINT32 (bs, byte_stream_len, 16); + gst_bit_writer_put_bytes (bs, byte_stream, byte_stream_len); + g_free (byte_stream); + + return TRUE; + +bs_error: + { + GST_ERROR ("failed to write codec-data"); + g_free (byte_stream); + return FALSE; + } +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h b/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h index a1ede90520..4122904d21 100644 --- a/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h +++ b/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h @@ -3,6 +3,8 @@ * * Copyright (C) 2011-2014 Intel Corporation * Author: Gwenole Beauchesne + * Copyright (C) 2017 Intel Corporation + * Author: Hyunjun Ko * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -77,6 +79,10 @@ bs_write_ue (GstBitWriter * bs, guint32 value); gboolean bs_write_se (GstBitWriter * bs, gint32 value); +/* Write nal unit, applying emulation prevention bytes */ +gboolean +gst_vaapi_utils_h26x_write_nal_unit (GstBitWriter * bs, guint8 * nal, guint nal_size); + G_END_DECLS #endif /* GST_VAAPI_UTILS_H26X_PRIV_H */