summaryrefslogtreecommitdiff
path: root/gst-libs/gst/codecparsers
diff options
context:
space:
mode:
authorThiago Santos <ts.santos@sisa.samsung.com>2014-01-24 01:07:45 -0300
committerThiago Santos <ts.santos@sisa.samsung.com>2014-01-24 09:30:35 -0300
commit61192a1619a2f1042a2c701de7864fcdf54cdf2c (patch)
tree3c40dee436f9da7173a4055be4460ab3d423aafe /gst-libs/gst/codecparsers
parentaf78b45979564035ce4f2535d7257201112f776b (diff)
downloadgstreamer-plugins-bad-61192a1619a2f1042a2c701de7864fcdf54cdf2c.tar.gz
codecparsers: refactor common nal parsing to nalutils
Moves common code from h264 and h265 to a separate file
Diffstat (limited to 'gst-libs/gst/codecparsers')
-rw-r--r--gst-libs/gst/codecparsers/Makefile.am4
-rw-r--r--gst-libs/gst/codecparsers/gsth264parser.c343
-rw-r--r--gst-libs/gst/codecparsers/gsth265parser.c268
-rw-r--r--gst-libs/gst/codecparsers/nalutils.c296
-rw-r--r--gst-libs/gst/codecparsers/nalutils.h147
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);