diff options
Diffstat (limited to 'gst-libs/gst/codecparsers')
-rw-r--r-- | gst-libs/gst/codecparsers/Makefile.am | 4 | ||||
-rw-r--r-- | gst-libs/gst/codecparsers/gsth264parser.c | 343 | ||||
-rw-r--r-- | gst-libs/gst/codecparsers/gsth265parser.c | 268 | ||||
-rw-r--r-- | gst-libs/gst/codecparsers/nalutils.c | 296 | ||||
-rw-r--r-- | gst-libs/gst/codecparsers/nalutils.h | 147 |
5 files changed, 451 insertions, 607 deletions
diff --git a/gst-libs/gst/codecparsers/Makefile.am b/gst-libs/gst/codecparsers/Makefile.am index e29024a5a..be45840d0 100644 --- a/gst-libs/gst/codecparsers/Makefile.am +++ b/gst-libs/gst/codecparsers/Makefile.am @@ -2,13 +2,13 @@ lib_LTLIBRARIES = libgstcodecparsers-@GST_API_VERSION@.la libgstcodecparsers_@GST_API_VERSION@_la_SOURCES = \ gstmpegvideoparser.c gsth264parser.c gstvc1parser.c gstmpeg4parser.c gsth265parser.c \ - parserutils.c \ + parserutils.c nalutils.c \ gstmpegvideometa.c libgstcodecparsers_@GST_API_VERSION@includedir = \ $(includedir)/gstreamer-@GST_API_VERSION@/gst/codecparsers -noinst_HEADERS = parserutils.h +noinst_HEADERS = parserutils.h nalutils.h libgstcodecparsers_@GST_API_VERSION@include_HEADERS = \ gstmpegvideoparser.h gsth264parser.h gstvc1parser.h gstmpeg4parser.h gsth265parser.h \ diff --git a/gst-libs/gst/codecparsers/gsth264parser.c b/gst-libs/gst/codecparsers/gsth264parser.c index 52f2bf739..506946d24 100644 --- a/gst-libs/gst/codecparsers/gsth264parser.c +++ b/gst-libs/gst/codecparsers/gsth264parser.c @@ -84,6 +84,7 @@ # include "config.h" #endif +#include "nalutils.h" #include "gsth264parser.h" #include <gst/base/gstbytereader.h> @@ -170,289 +171,6 @@ static PAR aspect_ratios[17] = { {2, 1} }; -/* Compute Ceil(Log2(v)) */ -/* Derived from branchless code for integer log2(v) from: - <http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog> */ -static guint -ceil_log2 (guint32 v) -{ - guint r, shift; - - v--; - r = (v > 0xFFFF) << 4; - v >>= r; - shift = (v > 0xFF) << 3; - v >>= shift; - r |= shift; - shift = (v > 0xF) << 2; - v >>= shift; - r |= shift; - shift = (v > 0x3) << 1; - v >>= shift; - r |= shift; - r |= (v >> 1); - return r + 1; -} - -/****** Nal parser ******/ - -typedef struct -{ - const guint8 *data; - guint size; - - guint n_epb; /* Number of emulation prevention bytes */ - guint byte; /* Byte position */ - guint bits_in_cache; /* bitpos in the cache of next bit */ - guint8 first_byte; - guint64 cache; /* cached bytes */ -} NalReader; - -static void -nal_reader_init (NalReader * nr, const guint8 * data, guint size) -{ - nr->data = data; - nr->size = size; - nr->n_epb = 0; - - nr->byte = 0; - nr->bits_in_cache = 0; - /* fill with something other than 0 to detect emulation prevention bytes */ - nr->first_byte = 0xff; - nr->cache = 0xff; -} - -static inline gboolean -nal_reader_read (NalReader * nr, guint nbits) -{ - if (G_UNLIKELY (nr->byte * 8 + (nbits - nr->bits_in_cache) > nr->size * 8)) { - GST_DEBUG ("Can not read %u bits, bits in cache %u, Byte * 8 %u, size in " - "bits %u", nbits, nr->bits_in_cache, nr->byte * 8, nr->size * 8); - return FALSE; - } - - while (nr->bits_in_cache < nbits) { - guint8 byte; - gboolean check_three_byte; - - check_three_byte = TRUE; - next_byte: - if (G_UNLIKELY (nr->byte >= nr->size)) - return FALSE; - - byte = nr->data[nr->byte++]; - - /* check if the byte is a emulation_prevention_three_byte */ - if (check_three_byte && byte == 0x03 && nr->first_byte == 0x00 && - ((nr->cache & 0xff) == 0)) { - /* next byte goes unconditionally to the cache, even if it's 0x03 */ - check_three_byte = FALSE; - nr->n_epb++; - goto next_byte; - } - nr->cache = (nr->cache << 8) | nr->first_byte; - nr->first_byte = byte; - nr->bits_in_cache += 8; - } - - return TRUE; -} - -static inline gboolean -nal_reader_skip (NalReader * nr, guint nbits) -{ - if (G_UNLIKELY (!nal_reader_read (nr, nbits))) - return FALSE; - - nr->bits_in_cache -= nbits; - - return TRUE; -} - -static inline gboolean -nal_reader_skip_to_next_byte (NalReader * nr) -{ - if (nr->bits_in_cache == 0) { - if (G_LIKELY ((nr->size - nr->byte) > 0)) - nr->byte++; - else - return FALSE; - } - - nr->bits_in_cache = 0; - - return TRUE; -} - -static inline guint -nal_reader_get_pos (const NalReader * nr) -{ - return nr->byte * 8 - nr->bits_in_cache; -} - -static inline guint -nal_reader_get_remaining (const NalReader * nr) -{ - return (nr->size - nr->byte) * 8 + nr->bits_in_cache; -} - -static inline guint -nal_reader_get_epb_count (const NalReader * nr) -{ - return nr->n_epb; -} - -#define GST_NAL_READER_READ_BITS(bits) \ -static gboolean \ -nal_reader_get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits) \ -{ \ - guint shift; \ - \ - if (!nal_reader_read (nr, nbits)) \ - return FALSE; \ - \ - /* bring the required bits down and truncate */ \ - shift = nr->bits_in_cache - nbits; \ - *val = nr->first_byte >> shift; \ - \ - *val |= nr->cache << (8 - shift); \ - /* mask out required bits */ \ - if (nbits < bits) \ - *val &= ((guint##bits)1 << nbits) - 1; \ - \ - nr->bits_in_cache = shift; \ - \ - return TRUE; \ -} \ - -GST_NAL_READER_READ_BITS (8); -GST_NAL_READER_READ_BITS (16); -GST_NAL_READER_READ_BITS (32); - -#define GST_NAL_READER_PEAK_BITS(bits) \ -static gboolean \ -nal_reader_peek_bits_uint##bits (const NalReader *nr, guint##bits *val, guint nbits) \ -{ \ - NalReader tmp; \ - \ - tmp = *nr; \ - return nal_reader_get_bits_uint##bits (&tmp, val, nbits); \ -} - -GST_NAL_READER_PEAK_BITS (8); - -static gboolean -nal_reader_get_ue (NalReader * nr, guint32 * val) -{ - guint i = 0; - guint8 bit; - guint32 value; - - if (G_UNLIKELY (!nal_reader_get_bits_uint8 (nr, &bit, 1))) { - - return FALSE; - } - - while (bit == 0) { - i++; - if G_UNLIKELY - ((!nal_reader_get_bits_uint8 (nr, &bit, 1))) - return FALSE; - } - - if (G_UNLIKELY (i > 32)) - return FALSE; - - if (G_UNLIKELY (!nal_reader_get_bits_uint32 (nr, &value, i))) - return FALSE; - - *val = (1 << i) - 1 + value; - - return TRUE; -} - -static inline gboolean -nal_reader_get_se (NalReader * nr, gint32 * val) -{ - guint32 value; - - if (G_UNLIKELY (!nal_reader_get_ue (nr, &value))) - return FALSE; - - if (value % 2) - *val = (value / 2) + 1; - else - *val = -(value / 2); - - return TRUE; -} - -#define CHECK_ALLOWED(val, min, max) { \ - if (val < min || val > max) { \ - GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \ - val, min, max); \ - goto error; \ - } \ -} - -#define READ_UINT8(nr, val, nbits) { \ - if (!nal_reader_get_bits_uint8 (nr, &val, nbits)) { \ - GST_WARNING ("failed to read uint8, nbits: %d", nbits); \ - goto error; \ - } \ -} - -#define READ_UINT16(nr, val, nbits) { \ - if (!nal_reader_get_bits_uint16 (nr, &val, nbits)) { \ - GST_WARNING ("failed to read uint16, nbits: %d", nbits); \ - goto error; \ - } \ -} - -#define READ_UINT32(nr, val, nbits) { \ - if (!nal_reader_get_bits_uint32 (nr, &val, nbits)) { \ - GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ - goto error; \ - } \ -} - -#define READ_UINT64(nr, val, nbits) { \ - if (!nal_reader_get_bits_uint64 (nr, &val, nbits)) { \ - GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ - goto error; \ - } \ -} - -#define READ_UE(nr, val) { \ - if (!nal_reader_get_ue (nr, &val)) { \ - GST_WARNING ("failed to read UE"); \ - goto error; \ - } \ -} - -#define READ_UE_ALLOWED(nr, val, min, max) { \ - guint32 tmp; \ - READ_UE (nr, tmp); \ - CHECK_ALLOWED (tmp, min, max); \ - val = tmp; \ -} - -#define READ_SE(nr, val) { \ - if (!nal_reader_get_se (nr, &val)) { \ - GST_WARNING ("failed to read SE"); \ - goto error; \ - } \ -} - -#define READ_SE_ALLOWED(nr, val, min, max) { \ - gint32 tmp; \ - READ_SE (nr, tmp); \ - CHECK_ALLOWED (tmp, min, max); \ - val = tmp; \ -} - -/*********** end of nal parser ***************/ - /***** Utils ****/ #define EXTENDED_SAR 255 @@ -494,57 +212,6 @@ set_nalu_datas (GstH264NalUnit * nalu) GST_DEBUG ("Nal type %u, ref_idc %u", nalu->type, nalu->ref_idc); } -static inline gint -scan_for_start_codes (const guint8 * data, guint size) -{ - GstByteReader br; - gst_byte_reader_init (&br, data, size); - - /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */ - return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, - 0, size); -} - -static gboolean -gst_h264_parser_byte_aligned (NalReader * nr) -{ - if (nr->bits_in_cache != 0) - return FALSE; - return TRUE; -} - -static gboolean -gst_h264_parser_more_data (NalReader * nr) -{ - guint remaining; - - remaining = nal_reader_get_remaining (nr); - if (remaining == 0) - return FALSE; - - if (remaining <= 8) { - guint8 rbsp_stop_one_bit; - - if (!nal_reader_peek_bits_uint8 (nr, &rbsp_stop_one_bit, 1)) - return FALSE; - - if (rbsp_stop_one_bit == 1) { - guint8 zero_bits; - - if (remaining == 1) - return FALSE; - - if (!nal_reader_peek_bits_uint8 (nr, &zero_bits, remaining)) - return FALSE; - - if ((zero_bits - (1 << (remaining - 1))) == 0) - return FALSE; - } - } - - return TRUE; -} - /****** Parsing functions *****/ static gboolean @@ -1221,13 +888,13 @@ gst_h264_parser_parse_sei_message (GstH264NalParser * nalparser, /* When SEI message doesn't end at byte boundary, * check remaining bits fit the specification. */ - if (!gst_h264_parser_byte_aligned (nr)) { + if (!gst_nal_reader_is_byte_aligned (nr)) { guint8 bit_equal_to_one; READ_UINT8 (nr, bit_equal_to_one, 1); if (!bit_equal_to_one) GST_WARNING ("Bit non equal to one."); - while (!gst_h264_parser_byte_aligned (nr)) { + while (!gst_nal_reader_is_byte_aligned (nr)) { guint8 bit_equal_to_zero; READ_UINT8 (nr, bit_equal_to_zero, 1); if (bit_equal_to_zero) @@ -1791,7 +1458,7 @@ gst_h264_parse_pps (GstH264NalParser * nalparser, GstH264NalUnit * nalu, READ_UINT8 (&nr, pps->constrained_intra_pred_flag, 1); READ_UINT8 (&nr, pps->redundant_pic_cnt_present_flag, 1); - if (!gst_h264_parser_more_data (&nr)) + if (!gst_nal_reader_has_more_data (&nr)) goto done; READ_UINT8 (&nr, pps->transform_8x8_mode_flag, 1); @@ -2063,7 +1730,7 @@ gst_h264_parser_parse_sei (GstH264NalParser * nalparser, GstH264NalUnit * nalu, g_array_append_val (*messages, sei); else break; - } while (gst_h264_parser_more_data (&nr)); + } while (gst_nal_reader_has_more_data (&nr)); return res; } diff --git a/gst-libs/gst/codecparsers/gsth265parser.c b/gst-libs/gst/codecparsers/gsth265parser.c index f489947d1..ee2be3a1b 100644 --- a/gst-libs/gst/codecparsers/gsth265parser.c +++ b/gst-libs/gst/codecparsers/gsth265parser.c @@ -78,6 +78,7 @@ # include "config.h" #endif +#include "nalutils.h" #include "gsth265parser.h" #include <gst/base/gstbytereader.h> @@ -156,262 +157,6 @@ static PAR aspect_ratios[17] = { {2, 1} }; -/* Compute Ceil(Log2(v)) */ -/* Derived from branchless code for integer log2(v) from: - <http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog> */ -static guint -ceil_log2 (guint32 v) -{ - guint r, shift; - - v--; - r = (v > 0xFFFF) << 4; - v >>= r; - shift = (v > 0xFF) << 3; - v >>= shift; - r |= shift; - shift = (v > 0xF) << 2; - v >>= shift; - r |= shift; - shift = (v > 0x3) << 1; - v >>= shift; - r |= shift; - r |= (v >> 1); - return r + 1; -} - -/****** Nal parser ******/ - -typedef struct -{ - const guint8 *data; - guint size; - - guint n_epb; /* Number of emulation prevention bytes */ - guint byte; /* Byte position */ - guint bits_in_cache; /* bitpos in the cache of next bit */ - guint8 first_byte; - guint64 cache; /* cached bytes */ -} NalReader; - -static void -nal_reader_init (NalReader * nr, const guint8 * data, guint size) -{ - nr->data = data; - nr->size = size; - nr->n_epb = 0; - - nr->byte = 0; - nr->bits_in_cache = 0; - /* fill with something other than 0 to detect emulation prevention bytes */ - nr->first_byte = 0xff; - nr->cache = 0xff; -} - -static inline gboolean -nal_reader_read (NalReader * nr, guint nbits) -{ - if (G_UNLIKELY (nr->byte * 8 + (nbits - nr->bits_in_cache) > nr->size * 8)) { - GST_DEBUG ("Can not read %u bits, bits in cache %u, Byte * 8 %u, size in " - "bits %u", nbits, nr->bits_in_cache, nr->byte * 8, nr->size * 8); - return FALSE; - } - - while (nr->bits_in_cache < nbits) { - guint8 byte; - gboolean check_three_byte; - - check_three_byte = TRUE; - next_byte: - if (G_UNLIKELY (nr->byte >= nr->size)) - return FALSE; - - byte = nr->data[nr->byte++]; - - /* check if the byte is a emulation_prevention_three_byte */ - if (check_three_byte && byte == 0x03 && nr->first_byte == 0x00 && - ((nr->cache & 0xff) == 0)) { - /* next byte goes unconditionally to the cache, even if it's 0x03 */ - check_three_byte = FALSE; - nr->n_epb++; - goto next_byte; - } - nr->cache = (nr->cache << 8) | nr->first_byte; - nr->first_byte = byte; - nr->bits_in_cache += 8; - } - - return TRUE; -} - -static inline gboolean -nal_reader_skip (NalReader * nr, guint nbits) -{ - if (G_UNLIKELY (!nal_reader_read (nr, nbits))) - return FALSE; - - nr->bits_in_cache -= nbits; - - return TRUE; -} - -static inline guint -nal_reader_get_pos (const NalReader * nr) -{ - return nr->byte * 8 - nr->bits_in_cache; -} - -static inline guint -nal_reader_get_remaining (const NalReader * nr) -{ - return (nr->size - nr->byte) * 8 + nr->bits_in_cache; -} - -static inline guint -nal_reader_get_epb_count (const NalReader * nr) -{ - return nr->n_epb; -} - -#define GST_NAL_READER_READ_BITS(bits) \ -static gboolean \ -nal_reader_get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits) \ -{ \ - guint shift; \ - \ - if (!nal_reader_read (nr, nbits)) \ - return FALSE; \ - \ - /* bring the required bits down and truncate */ \ - shift = nr->bits_in_cache - nbits; \ - *val = nr->first_byte >> shift; \ - \ - *val |= nr->cache << (8 - shift); \ - /* mask out required bits */ \ - if (nbits < bits) \ - *val &= ((guint##bits)1 << nbits) - 1; \ - \ - nr->bits_in_cache = shift; \ - \ - return TRUE; \ -} \ - -GST_NAL_READER_READ_BITS (8); -GST_NAL_READER_READ_BITS (16); -GST_NAL_READER_READ_BITS (32); - -static gboolean -nal_reader_get_ue (NalReader * nr, guint32 * val) -{ - guint i = 0; - guint8 bit; - guint32 value; - - if (G_UNLIKELY (!nal_reader_get_bits_uint8 (nr, &bit, 1))) { - - return FALSE; - } - - while (bit == 0) { - i++; - if G_UNLIKELY - ((!nal_reader_get_bits_uint8 (nr, &bit, 1))) - return FALSE; - } - - if (G_UNLIKELY (i > 32)) - return FALSE; - - if (G_UNLIKELY (!nal_reader_get_bits_uint32 (nr, &value, i))) - return FALSE; - - *val = (1 << i) - 1 + value; - - return TRUE; -} - -static inline gboolean -nal_reader_get_se (NalReader * nr, gint32 * val) -{ - guint32 value; - - if (G_UNLIKELY (!nal_reader_get_ue (nr, &value))) - return FALSE; - - if (value % 2) - *val = (value / 2) + 1; - else - *val = -(value / 2); - - return TRUE; -} - -#define CHECK_ALLOWED(val, min, max) { \ - if (val < min || val > max) { \ - GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \ - val, min, max); \ - goto error; \ - } \ -} - -#define READ_UINT8(nr, val, nbits) { \ - if (!nal_reader_get_bits_uint8 (nr, &val, nbits)) { \ - GST_WARNING ("failed to read uint8, nbits: %d", nbits); \ - goto error; \ - } \ -} - -#define READ_UINT16(nr, val, nbits) { \ - if (!nal_reader_get_bits_uint16 (nr, &val, nbits)) { \ - GST_WARNING ("failed to read uint16, nbits: %d", nbits); \ - goto error; \ - } \ -} - -#define READ_UINT32(nr, val, nbits) { \ - if (!nal_reader_get_bits_uint32 (nr, &val, nbits)) { \ - GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ - goto error; \ - } \ -} - -#define READ_UINT64(nr, val, nbits) { \ - if (!nal_reader_get_bits_uint64 (nr, &val, nbits)) { \ - GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ - goto error; \ - } \ -} - -#define READ_UE(nr, val) { \ - if (!nal_reader_get_ue (nr, &val)) { \ - GST_WARNING ("failed to read UE"); \ - goto error; \ - } \ -} - -#define READ_UE_ALLOWED(nr, val, min, max) { \ - guint32 tmp; \ - READ_UE (nr, tmp); \ - CHECK_ALLOWED (tmp, min, max); \ - val = tmp; \ -} - -#define READ_SE(nr, val) { \ - if (!nal_reader_get_se (nr, &val)) { \ - GST_WARNING ("failed to read SE"); \ - goto error; \ - } \ -} - -#define READ_SE_ALLOWED(nr, val, min, max) { \ - gint32 tmp; \ - READ_SE (nr, tmp); \ - CHECK_ALLOWED (tmp, min, max); \ - val = tmp; \ -} - -/*********** end of nal parser ***************/ - /***** Utils ****/ #define EXTENDED_SAR 255 @@ -476,17 +221,6 @@ gst_h265_parse_nalu_header (GstH265NalUnit * nalu) return TRUE; } -static inline gint -scan_for_start_codes (const guint8 * data, guint size) -{ - GstByteReader br; - gst_byte_reader_init (&br, data, size); - - /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */ - return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, - 0, size); -} - /****** Parsing functions *****/ static gboolean diff --git a/gst-libs/gst/codecparsers/nalutils.c b/gst-libs/gst/codecparsers/nalutils.c new file mode 100644 index 000000000..c3dd1ca29 --- /dev/null +++ b/gst-libs/gst/codecparsers/nalutils.c @@ -0,0 +1,296 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com> + * + * Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c: + * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * (C) 2005 Michal Benes <michal.benes@itonis.tv> + * (C) 2008 Wim Taymans <wim.taymans@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * Common code for NAL parsing from h264 and h265 parsers. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "nalutils.h" + +/* Compute Ceil(Log2(v)) */ +/* Derived from branchless code for integer log2(v) from: + <http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog> */ +guint +ceil_log2 (guint32 v) +{ + guint r, shift; + + v--; + r = (v > 0xFFFF) << 4; + v >>= r; + shift = (v > 0xFF) << 3; + v >>= shift; + r |= shift; + shift = (v > 0xF) << 2; + v >>= shift; + r |= shift; + shift = (v > 0x3) << 1; + v >>= shift; + r |= shift; + r |= (v >> 1); + return r + 1; +} + +/****** Nal parser ******/ + +void +nal_reader_init (NalReader * nr, const guint8 * data, guint size) +{ + nr->data = data; + nr->size = size; + nr->n_epb = 0; + + nr->byte = 0; + nr->bits_in_cache = 0; + /* fill with something other than 0 to detect emulation prevention bytes */ + nr->first_byte = 0xff; + nr->cache = 0xff; +} + +inline gboolean +nal_reader_read (NalReader * nr, guint nbits) +{ + if (G_UNLIKELY (nr->byte * 8 + (nbits - nr->bits_in_cache) > nr->size * 8)) { + GST_DEBUG ("Can not read %u bits, bits in cache %u, Byte * 8 %u, size in " + "bits %u", nbits, nr->bits_in_cache, nr->byte * 8, nr->size * 8); + return FALSE; + } + + while (nr->bits_in_cache < nbits) { + guint8 byte; + gboolean check_three_byte; + + check_three_byte = TRUE; + next_byte: + if (G_UNLIKELY (nr->byte >= nr->size)) + return FALSE; + + byte = nr->data[nr->byte++]; + + /* check if the byte is a emulation_prevention_three_byte */ + if (check_three_byte && byte == 0x03 && nr->first_byte == 0x00 && + ((nr->cache & 0xff) == 0)) { + /* next byte goes unconditionally to the cache, even if it's 0x03 */ + check_three_byte = FALSE; + nr->n_epb++; + goto next_byte; + } + nr->cache = (nr->cache << 8) | nr->first_byte; + nr->first_byte = byte; + nr->bits_in_cache += 8; + } + + return TRUE; +} + +inline gboolean +nal_reader_skip (NalReader * nr, guint nbits) +{ + if (G_UNLIKELY (!nal_reader_read (nr, nbits))) + return FALSE; + + nr->bits_in_cache -= nbits; + + return TRUE; +} + +inline gboolean +nal_reader_skip_to_next_byte (NalReader * nr) +{ + if (nr->bits_in_cache == 0) { + if (G_LIKELY ((nr->size - nr->byte) > 0)) + nr->byte++; + else + return FALSE; + } + + nr->bits_in_cache = 0; + + return TRUE; +} + +inline guint +nal_reader_get_pos (const NalReader * nr) +{ + return nr->byte * 8 - nr->bits_in_cache; +} + +inline guint +nal_reader_get_remaining (const NalReader * nr) +{ + return (nr->size - nr->byte) * 8 + nr->bits_in_cache; +} + +inline guint +nal_reader_get_epb_count (const NalReader * nr) +{ + return nr->n_epb; +} + +#define GST_NAL_READER_READ_BITS(bits) \ +gboolean \ +nal_reader_get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits) \ +{ \ + guint shift; \ + \ + if (!nal_reader_read (nr, nbits)) \ + return FALSE; \ + \ + /* bring the required bits down and truncate */ \ + shift = nr->bits_in_cache - nbits; \ + *val = nr->first_byte >> shift; \ + \ + *val |= nr->cache << (8 - shift); \ + /* mask out required bits */ \ + if (nbits < bits) \ + *val &= ((guint##bits)1 << nbits) - 1; \ + \ + nr->bits_in_cache = shift; \ + \ + return TRUE; \ +} \ + +GST_NAL_READER_READ_BITS (8); +GST_NAL_READER_READ_BITS (16); +GST_NAL_READER_READ_BITS (32); + +#define GST_NAL_READER_PEEK_BITS(bits) \ +gboolean \ +nal_reader_peek_bits_uint##bits (const NalReader *nr, guint##bits *val, guint nbits) \ +{ \ + NalReader tmp; \ + \ + tmp = *nr; \ + return nal_reader_get_bits_uint##bits (&tmp, val, nbits); \ +} + +GST_NAL_READER_PEEK_BITS (8); + +gboolean +nal_reader_get_ue (NalReader * nr, guint32 * val) +{ + guint i = 0; + guint8 bit; + guint32 value; + + if (G_UNLIKELY (!nal_reader_get_bits_uint8 (nr, &bit, 1))) { + + return FALSE; + } + + while (bit == 0) { + i++; + if G_UNLIKELY + ((!nal_reader_get_bits_uint8 (nr, &bit, 1))) + return FALSE; + } + + if (G_UNLIKELY (i > 32)) + return FALSE; + + if (G_UNLIKELY (!nal_reader_get_bits_uint32 (nr, &value, i))) + return FALSE; + + *val = (1 << i) - 1 + value; + + return TRUE; +} + +inline gboolean +nal_reader_get_se (NalReader * nr, gint32 * val) +{ + guint32 value; + + if (G_UNLIKELY (!nal_reader_get_ue (nr, &value))) + return FALSE; + + if (value % 2) + *val = (value / 2) + 1; + else + *val = -(value / 2); + + return TRUE; +} + +gboolean +gst_nal_reader_is_byte_aligned (NalReader * nr) +{ + if (nr->bits_in_cache != 0) + return FALSE; + return TRUE; +} + +gboolean +gst_nal_reader_has_more_data (NalReader * nr) +{ + guint remaining; + + remaining = nal_reader_get_remaining (nr); + if (remaining == 0) + return FALSE; + + if (remaining <= 8) { + guint8 rbsp_stop_one_bit; + + if (!nal_reader_peek_bits_uint8 (nr, &rbsp_stop_one_bit, 1)) + return FALSE; + + if (rbsp_stop_one_bit == 1) { + guint8 zero_bits; + + if (remaining == 1) + return FALSE; + + if (!nal_reader_peek_bits_uint8 (nr, &zero_bits, remaining)) + return FALSE; + + if ((zero_bits - (1 << (remaining - 1))) == 0) + return FALSE; + } + } + + return TRUE; +} + +/*********** end of nal parser ***************/ + +inline gint +scan_for_start_codes (const guint8 * data, guint size) +{ + GstByteReader br; + gst_byte_reader_init (&br, data, size); + + /* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */ + return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, + 0, size); +} diff --git a/gst-libs/gst/codecparsers/nalutils.h b/gst-libs/gst/codecparsers/nalutils.h new file mode 100644 index 000000000..aa99242ca --- /dev/null +++ b/gst-libs/gst/codecparsers/nalutils.h @@ -0,0 +1,147 @@ +/* Gstreamer + * Copyright (C) <2011> Intel Corporation + * Copyright (C) <2011> Collabora Ltd. + * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com> + * + * Some bits C-c,C-v'ed and s/4/3 from h264parse and videoparsers/h264parse.c: + * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + * Copyright (C) <2010> Collabora Multimedia + * Copyright (C) <2010> Nokia Corporation + * + * (C) 2005 Michal Benes <michal.benes@itonis.tv> + * (C) 2008 Wim Taymans <wim.taymans@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * Common code for NAL parsing from h264 and h265 parsers. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gst/base/gstbytereader.h> +#include <gst/base/gstbitreader.h> +#include <string.h> + +guint ceil_log2 (guint32 v); + +typedef struct +{ + const guint8 *data; + guint size; + + guint n_epb; /* Number of emulation prevention bytes */ + guint byte; /* Byte position */ + guint bits_in_cache; /* bitpos in the cache of next bit */ + guint8 first_byte; + guint64 cache; /* cached bytes */ +} NalReader; + +void nal_reader_init (NalReader * nr, const guint8 * data, guint size); + +gboolean nal_reader_read (NalReader * nr, guint nbits); +gboolean nal_reader_skip (NalReader * nr, guint nbits); +gboolean nal_reader_skip_to_next_byte (NalReader * nr); +guint nal_reader_get_pos (const NalReader * nr); +guint nal_reader_get_remaining (const NalReader * nr); +guint nal_reader_get_epb_count (const NalReader * nr); + +gboolean gst_nal_reader_is_byte_aligned (NalReader * nr); +gboolean gst_nal_reader_has_more_data (NalReader * nr); + +#define GST_NAL_READER_READ_BITS_H(bits) \ +gboolean nal_reader_get_bits_uint##bits (NalReader *nr, guint##bits *val, guint nbits) + +GST_NAL_READER_READ_BITS_H (8); +GST_NAL_READER_READ_BITS_H (16); +GST_NAL_READER_READ_BITS_H (32); + +#define GST_NAL_READER_PEEK_BITS_H(bits) \ +gboolean nal_reader_peek_bits_uint##bits (const NalReader *nr, guint##bits *val, guint nbits) + +GST_NAL_READER_PEEK_BITS_H (8); + +gboolean nal_reader_get_ue (NalReader * nr, guint32 * val); +gboolean nal_reader_get_se (NalReader * nr, gint32 * val); + +#define CHECK_ALLOWED(val, min, max) { \ + if (val < min || val > max) { \ + GST_WARNING ("value not in allowed range. value: %d, range %d-%d", \ + val, min, max); \ + goto error; \ + } \ +} + +#define READ_UINT8(nr, val, nbits) { \ + if (!nal_reader_get_bits_uint8 (nr, &val, nbits)) { \ + GST_WARNING ("failed to read uint8, nbits: %d", nbits); \ + goto error; \ + } \ +} + +#define READ_UINT16(nr, val, nbits) { \ + if (!nal_reader_get_bits_uint16 (nr, &val, nbits)) { \ + GST_WARNING ("failed to read uint16, nbits: %d", nbits); \ + goto error; \ + } \ +} + +#define READ_UINT32(nr, val, nbits) { \ + if (!nal_reader_get_bits_uint32 (nr, &val, nbits)) { \ + GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ + goto error; \ + } \ +} + +#define READ_UINT64(nr, val, nbits) { \ + if (!nal_reader_get_bits_uint64 (nr, &val, nbits)) { \ + GST_WARNING ("failed to read uint32, nbits: %d", nbits); \ + goto error; \ + } \ +} + +#define READ_UE(nr, val) { \ + if (!nal_reader_get_ue (nr, &val)) { \ + GST_WARNING ("failed to read UE"); \ + goto error; \ + } \ +} + +#define READ_UE_ALLOWED(nr, val, min, max) { \ + guint32 tmp; \ + READ_UE (nr, tmp); \ + CHECK_ALLOWED (tmp, min, max); \ + val = tmp; \ +} + +#define READ_SE(nr, val) { \ + if (!nal_reader_get_se (nr, &val)) { \ + GST_WARNING ("failed to read SE"); \ + goto error; \ + } \ +} + +#define READ_SE_ALLOWED(nr, val, min, max) { \ + gint32 tmp; \ + READ_SE (nr, tmp); \ + CHECK_ALLOWED (tmp, min, max); \ + val = tmp; \ +} + +gint scan_for_start_codes (const guint8 * data, guint size); |