codecparsers: mpeg: Add an mpeg video bitstream parsing library
authorThibault Saunier <thibault.saunier@collabora.com>
Tue, 19 Jul 2011 11:52:01 +0000 (13:52 +0200)
committerEdward Hervey <edward.hervey@collabora.co.uk>
Fri, 2 Sep 2011 13:46:02 +0000 (15:46 +0200)
Create a new codecparsers library

12 files changed:
configure.ac
docs/libs/gst-plugins-bad-libs-docs.sgml
docs/libs/gst-plugins-bad-libs-sections.txt
docs/libs/gst-plugins-bad-libs.types
gst-libs/gst/Makefile.am
gst-libs/gst/codecparsers/Makefile.am [new file with mode: 0644]
gst-libs/gst/codecparsers/gstmpegvideoparser.c [new file with mode: 0644]
gst-libs/gst/codecparsers/gstmpegvideoparser.h [new file with mode: 0644]
gst-plugins-bad.spec.in
pkgconfig/gstreamer-plugins-bad.pc.in
tests/check/Makefile.am
tests/check/libs/mpegvideoparser.c [new file with mode: 0644]

index 5d90452..17ea3b9 100644 (file)
@@ -1946,6 +1946,7 @@ gst-libs/gst/Makefile
 gst-libs/gst/basecamerabinsrc/Makefile
 gst-libs/gst/interfaces/Makefile
 gst-libs/gst/signalprocessor/Makefile
+gst-libs/gst/codecparsers/Makefile
 gst-libs/gst/video/Makefile
 sys/Makefile
 sys/dshowdecwrapper/Makefile
index 49f0402..d1113bc 100644 (file)
       package.
     </para>
     <xi:include href="compiling.sgml" />
+
+    <chapter id="codecparsers">
+      <title>Bitstream parsing Library</title>
+      <para>
+        This library should be linked to by getting cflags and libs from
+        <filename>gstreamer-plugins-bad-&GST_MAJORMINOR;.pc</filename> and adding
+        <filename>-lgscodeparsers-&GST_MAJORMINOR;</filename> to the library flags.
+      </para>
+      <xi:include href="xml/gstmpegvideoparser.xml" />
+    </chapter>
   </part>
 
   <part id="gstreamer-libs-hierarchy">
index e69de29..a09929c 100644 (file)
@@ -0,0 +1,28 @@
+# codecparsers
+<SECTION>
+<FILE>gstmpegvideoparser</FILE>
+<TITLE>mpegvideoparser</TITLE>
+<INCLUDE>gst/codecparsers/gstmpegvideoparser.h</INCLUDE>
+GstMpegVideoPacketTypeCode
+GstMpegVideoPacketExtensionCode
+GstMpegVideoLevel
+GstMpegVideoProfile
+GstMpegVideoPictureType
+GstMpegVideoPictureStructure
+GstMpegVideoSequenceHdr
+GstMpegVideoSequenceExt
+GstMpegVideoPictureHdr
+GstMpegVideoGop
+GstMpegVideoPictureExt
+GstMpegVideoQuantMatrixExt
+GstMpegVideoTypeOffsetSize
+gst_mpeg_video_parse
+gst_mpeg_video_parse_sequence_header
+gst_mpeg_video_parse_picture_header
+gst_mpeg_video_parse_picture_extension
+gst_mpeg_video_parse_gop
+gst_mpeg_video_parse_sequence_extension
+gst_mpeg_video_parse_quant_matrix_extension
+<SUBSECTION Standard>
+<SUBSECTION Private>
+</SECTION>
index 9f4950e..4ca1a2b 100644 (file)
@@ -1 +1,3 @@
 #include <gst/gst.h>
+
+#include <gst/codecparsers/gstmpegvideoparser.h>
index ac83c68..130956e 100644 (file)
@@ -1,6 +1,6 @@
 
-SUBDIRS = interfaces signalprocessor video basecamerabinsrc
+SUBDIRS = interfaces signalprocessor video basecamerabinsrc codecparsers
 
 noinst_HEADERS = gst-i18n-plugin.h gettext.h
-DIST_SUBDIRS = interfaces signalprocessor video basecamerabinsrc
+DIST_SUBDIRS = interfaces signalprocessor video basecamerabinsrc codecparsers
 
diff --git a/gst-libs/gst/codecparsers/Makefile.am b/gst-libs/gst/codecparsers/Makefile.am
new file mode 100644 (file)
index 0000000..86a7b16
--- /dev/null
@@ -0,0 +1,29 @@
+lib_LTLIBRARIES = libgstcodecparsers-@GST_MAJORMINOR@.la
+
+libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES = gstmpegvideoparser.c
+
+libgstcodecparsers_@GST_MAJORMINOR@includedir = \
+       $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/codecparsers
+
+libgstcodecparsers_@GST_MAJORMINOR@include_HEADERS = \
+       gstmpegvideoparser.h
+
+libgstcodecparsers_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_CFLAGS)
+libgstcodecparsers_@GST_MAJORMINOR@_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
+libgstcodecparsers_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
+
+Android.mk:  $(BUILT_SOURCES) Makefile.am
+       androgenizer -:PROJECT libgstcodecparsers -:STATIC libgstcodecparsers-@GST_MAJORMINOR@ \
+        -:TAGS eng debug \
+         -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
+        -:SOURCES $(libgstcodecparsers_@GST_MAJORMINOR@_la_SOURCES) \
+         $(built_sources) \
+        -:CFLAGS $(DEFS) $(libgstcodecparsers_@GST_MAJORMINOR@_la_CFLAGS) \
+        -:LDFLAGS $(libgstcodecparsers_@GST_MAJORMINOR@_la_LDFLAGS) \
+                  $(libgstcodecparsers@GST_MAJORMINOR@_la_LIBADD) \
+                  -ldl \
+        -:HEADER_TARGET gstreamer-@GST_MAJORMINOR@/gst/codecparsers \
+        -:HEADERS $(libgstcodecparsersinclude_HEADERS) \
+         $(built_headers) \
+        -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
+       > $@
diff --git a/gst-libs/gst/codecparsers/gstmpegvideoparser.c b/gst-libs/gst/codecparsers/gstmpegvideoparser.c
new file mode 100644 (file)
index 0000000..be34e5f
--- /dev/null
@@ -0,0 +1,749 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ * From bad/sys/vdpau/mpeg/mpegutil.c:
+ *   Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
+ *   Copyright (C) <2009> Carl-Anton Ingmarsson <ca.ingmarsson@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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:gstmpegvideoparser
+ * @short_description: Convenience library for mpeg1 and 2 video
+ * bitstream parsing.
+ *
+ * <refsect2>
+ * <para>
+ * Provides useful functions for mpeg videos bitstream parsing.
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "gstmpegvideoparser.h"
+
+#include <string.h>
+#include <gst/base/gstbitreader.h>
+#include <gst/base/gstbytereader.h>
+
+#define MARKER_BIT 0x1
+
+#define GET_BITS(b, num, bits) G_STMT_START {        \
+  if (!gst_bit_reader_get_bits_uint32(b, bits, num)) \
+    goto failed;                                     \
+  GST_TRACE ("parsed %d bits: %d", num, *(bits));    \
+} G_STMT_END
+
+#define READ_UINT8(br, val, nbits) G_STMT_START {  \
+  if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \
+    GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
+    goto failed; \
+  } \
+} G_STMT_END
+
+#define READ_UINT16(br, val, nbits) G_STMT_START { \
+  if (!gst_bit_reader_get_bits_uint16 (br, &val, nbits)) { \
+    GST_WARNING ("failed to read uint16, nbits: %d", nbits); \
+    goto failed; \
+  } \
+} G_STMT_END
+
+#define READ_UINT32(br, val, nbits) G_STMT_START { \
+  if (!gst_bit_reader_get_bits_uint32 (br, &val, nbits)) { \
+    GST_WARNING ("failed to read uint32, nbits: %d", nbits); \
+    goto failed; \
+  } \
+} G_STMT_END
+
+/* default intra quant matrix, in zig-zag order */
+const guint8 default_intra_quantizer_matrix[64] = {
+  8,
+  16, 16,
+  19, 16, 19,
+  22, 22, 22, 22,
+  22, 22, 26, 24, 26,
+  27, 27, 27, 26, 26, 26,
+  26, 27, 27, 27, 29, 29, 29,
+  34, 34, 34, 29, 29, 29, 27, 27,
+  29, 29, 32, 32, 34, 34, 37,
+  38, 37, 35, 35, 34, 35,
+  38, 38, 40, 40, 40,
+  48, 48, 46, 46,
+  56, 56, 58,
+  69, 69,
+  83
+};
+
+const guint8 mpeg_zigzag_8x8[64] = {
+  0, 1, 8, 16, 9, 2, 3, 10,
+  17, 24, 32, 25, 18, 11, 4, 5,
+  12, 19, 26, 33, 40, 48, 41, 34,
+  27, 20, 13, 6, 7, 14, 21, 28,
+  35, 42, 49, 56, 57, 50, 43, 36,
+  29, 22, 15, 23, 30, 37, 44, 51,
+  58, 59, 52, 45, 38, 31, 39, 46,
+  53, 60, 61, 54, 47, 55, 62, 63
+};
+
+GST_DEBUG_CATEGORY (mpegvideo_parser_debug);
+#define GST_CAT_DEFAULT mpegvideo_parser_debug
+
+static gboolean initialized = FALSE;
+
+static inline gboolean
+find_start_code (GstBitReader * b)
+{
+  guint32 bits;
+
+  /* 0 bits until byte aligned */
+  while (b->bit != 0) {
+    GET_BITS (b, 1, &bits);
+  }
+
+  /* 0 bytes until startcode */
+  while (gst_bit_reader_peek_bits_uint32 (b, &bits, 32)) {
+    if (bits >> 8 == 0x1) {
+      return TRUE;
+    } else {
+      gst_bit_reader_skip (b, 8);
+    }
+  }
+
+  return FALSE;
+
+failed:
+  return FALSE;
+}
+
+/* Set the Pixel Aspect Ratio in our hdr from a DAR code in the data */
+static void
+set_par_from_dar (GstMpegVideoSequenceHdr * seqhdr, guint8 asr_code)
+{
+  /* Pixel_width = DAR_width * display_vertical_size */
+  /* Pixel_height = DAR_height * display_horizontal_size */
+  switch (asr_code) {
+    case 0x02:                 /* 3:4 DAR = 4:3 pixels */
+      seqhdr->par_w = 4 * seqhdr->height;
+      seqhdr->par_h = 3 * seqhdr->width;
+      break;
+    case 0x03:                 /* 9:16 DAR */
+      seqhdr->par_w = 16 * seqhdr->height;
+      seqhdr->par_h = 9 * seqhdr->width;
+      break;
+    case 0x04:                 /* 1:2.21 DAR */
+      seqhdr->par_w = 221 * seqhdr->height;
+      seqhdr->par_h = 100 * seqhdr->width;
+      break;
+    case 0x01:                 /* Square pixels */
+      seqhdr->par_w = seqhdr->par_h = 1;
+      break;
+    default:
+      GST_DEBUG ("unknown/invalid aspect_ratio_information %d", asr_code);
+      break;
+  }
+}
+
+static void
+set_fps_from_code (GstMpegVideoSequenceHdr * seqhdr, guint8 fps_code)
+{
+  const gint framerates[][2] = {
+    {30, 1}, {24000, 1001}, {24, 1}, {25, 1},
+    {30000, 1001}, {30, 1}, {50, 1}, {60000, 1001},
+    {60, 1}, {30, 1}
+  };
+
+  if (fps_code && fps_code < 10) {
+    seqhdr->fps_n = framerates[fps_code][0];
+    seqhdr->fps_d = framerates[fps_code][1];
+  } else {
+    GST_DEBUG ("unknown/invalid frame_rate_code %d", fps_code);
+    /* Force a valid framerate */
+    /* FIXME or should this be kept unknown ?? */
+    seqhdr->fps_n = 30000;
+    seqhdr->fps_d = 1001;
+  }
+}
+
+static gboolean
+gst_mpeg_video_parse_sequence (GstMpegVideoSequenceHdr * seqhdr,
+    GstBitReader * br)
+{
+  guint8 bits;
+  guint8 load_intra_flag, load_non_intra_flag;
+
+  /* Setting the height/width codes */
+  READ_UINT16 (br, seqhdr->width, 12);
+  READ_UINT16 (br, seqhdr->height, 12);
+
+  READ_UINT8 (br, seqhdr->aspect_ratio_info, 4);
+  set_par_from_dar (seqhdr, seqhdr->aspect_ratio_info);
+
+  READ_UINT8 (br, seqhdr->frame_rate_code, 4);
+  set_fps_from_code (seqhdr, seqhdr->frame_rate_code);
+
+  READ_UINT32 (br, seqhdr->bitrate_value, 18);
+  if (seqhdr->bitrate_value == 0x3ffff) {
+    /* VBR stream */
+    seqhdr->bitrate = 0;
+  } else {
+    /* Value in header is in units of 400 bps */
+    seqhdr->bitrate *= 400;
+  }
+
+  READ_UINT8 (br, bits, 1);
+  if (bits != MARKER_BIT)
+    goto failed;
+
+  /* VBV buffer size */
+  READ_UINT16 (br, seqhdr->vbv_buffer_size_value, 10);
+
+  /* constrained_parameters_flag */
+  READ_UINT8 (br, seqhdr->constrained_parameters_flag, 1);
+
+  /* load_intra_quantiser_matrix */
+  READ_UINT8 (br, load_intra_flag, 1);
+  if (load_intra_flag) {
+    gint i;
+    for (i = 0; i < 64; i++)
+      READ_UINT8 (br, seqhdr->intra_quantizer_matrix[mpeg_zigzag_8x8[i]], 8);
+  } else
+    memcpy (seqhdr->intra_quantizer_matrix, default_intra_quantizer_matrix, 64);
+
+  /* non intra quantizer matrix */
+  READ_UINT8 (br, load_non_intra_flag, 1);
+  if (load_non_intra_flag) {
+    gint i;
+    for (i = 0; i < 64; i++)
+      READ_UINT8 (br, seqhdr->non_intra_quantizer_matrix[mpeg_zigzag_8x8[i]],
+          8);
+  } else
+    memset (seqhdr->non_intra_quantizer_matrix, 16, 64);
+
+  /* dump some info */
+  GST_LOG ("width x height: %d x %d", seqhdr->width, seqhdr->height);
+  GST_LOG ("fps: %d/%d", seqhdr->fps_n, seqhdr->fps_d);
+  GST_LOG ("par: %d/%d", seqhdr->par_w, seqhdr->par_h);
+  GST_LOG ("bitrate: %d", seqhdr->bitrate);
+
+  return TRUE;
+
+  /* ERRORS */
+failed:
+  {
+    GST_WARNING ("Failed to parse sequence header");
+    /* clear out stuff */
+    memset (seqhdr, 0, sizeof (*seqhdr));
+    return FALSE;
+  }
+}
+
+static inline guint
+scan_for_start_codes (const GstByteReader * reader, guint offset, guint size)
+{
+  const guint8 *data;
+  guint32 state;
+  guint i;
+
+  g_return_val_if_fail (size > 0, -1);
+  g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte,
+      -1);
+
+  /* we can't find the pattern with less than 4 bytes */
+  if (G_UNLIKELY (size < 4))
+    return -1;
+
+  data = reader->data + reader->byte + offset;
+
+  /* set the state to something that does not match */
+  state = 0xffffffff;
+
+  /* now find data */
+  for (i = 0; i < size; i++) {
+    /* throw away one byte and move in the next byte */
+    state = ((state << 8) | data[i]);
+    if (G_UNLIKELY ((state & 0xffffff00) == 0x00000100)) {
+      /* we have a match but we need to have skipped at
+       * least 4 bytes to fill the state. */
+      if (G_LIKELY (i >= 3))
+        return offset + i - 3;
+    }
+
+    /* TODO: reimplement making 010001 not detected as a sc
+     * Accelerate search for start code
+     * if (data[i] > 1) {
+     * while (i < (size - 4) && data[i] > 1) {
+     *   if (data[i + 3] > 1)
+     *     i += 4;
+     *   else
+     *     i += 1;
+     * }
+     * state = 0x00000100;
+     *}
+     */
+  }
+
+  /* nothing found */
+  return -1;
+}
+
+/****** API *******/
+
+/**
+ * gst_mpeg_video_parse:
+ * @data: The datas from which to parse
+ * @size: The size of @data
+ * @offset: The offset from which to start the parsing
+ *
+ * Parses @data, and detects the different packets types, offset,
+ * and size, starting from @offset
+ *
+ * Returns: a #GList of #GstMpegVideoTypeOffsetSize
+ */
+GList *
+gst_mpeg_video_parse (guint8 * data, gsize size, guint offset)
+{
+  gint off, rsize;
+  GstByteReader br;
+  GList *ret = NULL;
+  size = size - offset;
+
+  if (!initialized) {
+    GST_DEBUG_CATEGORY_INIT (mpegvideo_parser_debug, "codecparsers_mpegvideo",
+        0, "Mpegvideo parser library");
+    initialized = TRUE;
+  }
+
+  if (size <= 0) {
+    GST_DEBUG ("Can't parse from offset %d, buffer is to small", offset);
+    return NULL;
+  }
+
+  gst_byte_reader_init (&br, &data[offset], size);
+
+  off = scan_for_start_codes (&br, 0, size);
+
+  if (off < 0) {
+    GST_DEBUG ("No start code prefix in this buffer");
+    return NULL;
+  }
+
+  while (off >= 0 && off + 3 < size) {
+    GstMpegVideoTypeOffsetSize *codoffsize;
+
+    gst_byte_reader_skip (&br, off + 3);
+
+    codoffsize = g_malloc (sizeof (GstMpegVideoTypeOffsetSize));
+    gst_byte_reader_get_uint8 (&br, &codoffsize->type);
+
+    codoffsize->offset = gst_byte_reader_get_pos (&br) + offset;
+
+    rsize = gst_byte_reader_get_remaining (&br);
+    if (rsize <= 0)
+      break;
+
+    off = scan_for_start_codes (&br, 0, rsize);
+
+    codoffsize->size = off;
+
+    ret = g_list_prepend (ret, codoffsize);
+    codoffsize = ret->data;
+  }
+
+  return g_list_reverse (ret);
+}
+
+/**
+ * gst_mpeg_video_parse_sequence_header:
+ * @seqhdr: The #GstMpegVideoSequenceHdr to set
+ * @data: The datas from which to parse the seqhdr
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start parsing @data
+ *
+ * Sets the @seqhdr Mpeg Video Sequence Header structure members from @data
+ *
+ * Returns: %TRUE if the seqhdr could be parsed correctly, %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_sequence_header (GstMpegVideoSequenceHdr * seqhdr,
+    guint8 * data, gsize size, guint offset)
+{
+  GstBitReader br;
+
+  size = size - offset;
+
+  if (size - offset < 4)
+    return FALSE;
+
+  gst_bit_reader_init (&br, &data[offset], size);
+
+  return gst_mpeg_video_parse_sequence (seqhdr, &br);
+}
+
+/**
+ * gst_mpeg_video_parse_sequence_extension:
+ * @seqhdr: The #GstMpegVideoSequenceExt to set
+ * @data: The datas from which to parse the seqext
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start parsing @data
+ *
+ * Sets the @seqext Mpeg Video Sequence Extension structure members from @data
+ *
+ * Returns: %TRUE if the seqext could be parsed correctly, %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_sequence_extension (GstMpegVideoSequenceExt * seqext,
+    guint8 * data, gsize size, guint offset)
+{
+  GstBitReader br;
+
+  size = size - offset;
+
+  if (size < 6) {
+    GST_DEBUG ("not enough bytes to parse the extension");
+    return FALSE;
+  }
+
+  gst_bit_reader_init (&br, &data[offset], size);
+
+  if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) !=
+      GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE) {
+    GST_DEBUG ("Not parsing a sequence extension");
+    return FALSE;
+  }
+
+  /* skip profile and level escape bit */
+  gst_bit_reader_skip_unchecked (&br, 1);
+
+  seqext->profile = gst_bit_reader_get_bits_uint8_unchecked (&br, 3);
+  seqext->level = gst_bit_reader_get_bits_uint8_unchecked (&br, 4);
+
+  /* progressive */
+  seqext->progressive = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
+
+  /* chroma format */
+  seqext->chroma_format = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+
+  /* resolution extension */
+  seqext->horiz_size_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+  seqext->vert_size_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+
+  seqext->bitrate_ext = gst_bit_reader_get_bits_uint16_unchecked (&br, 12);
+
+  /* skip marker bits */
+  gst_bit_reader_skip_unchecked (&br, 1);
+
+  seqext->vbv_buffer_size_extension =
+      gst_bit_reader_get_bits_uint8_unchecked (&br, 8);
+  seqext->low_delay = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
+
+  /* framerate extension */
+  seqext->fps_n_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+  seqext->fps_d_ext = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
+
+  return TRUE;
+}
+
+/**
+ * gst_mpeg_video_parse_quant_matrix_extension:
+ * @ext: The #GstMpegVideoQuantMatrixExt to set
+ * @data: The datas from which to parse @quant
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start the parsing
+ *
+ * Sets the @quant Mpeg Video Quant Matrix Extension structure members from
+ * @data
+ *
+ * Returns: %TRUE if the quant matrix extension could be parsed correctly,
+ * %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_quant_matrix_extension (GstMpegVideoQuantMatrixExt * quant,
+    guint8 * data, gsize size, guint offset)
+{
+  guint8 i;
+  GstBitReader br;
+
+  size = size - offset;
+
+  if (size < 1) {
+    GST_DEBUG ("not enough bytes to parse the extension");
+    return FALSE;
+  }
+
+  gst_bit_reader_init (&br, &data[offset], size);
+
+  if (gst_bit_reader_get_bits_uint8_unchecked (&br, 4) !=
+      GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX) {
+    GST_DEBUG ("Not parsing a quant matrix extension");
+    return FALSE;
+  }
+
+  READ_UINT8 (&br, quant->load_intra_quantiser_matrix, 1);
+  if (quant->load_intra_quantiser_matrix) {
+    for (i = 0; i < 64; i++) {
+      READ_UINT8 (&br, quant->intra_quantiser_matrix[mpeg_zigzag_8x8[i]], 8);
+    }
+  }
+
+  READ_UINT8 (&br, quant->load_non_intra_quantiser_matrix, 1);
+  if (quant->load_non_intra_quantiser_matrix) {
+    for (i = 0; i < 64; i++) {
+      READ_UINT8 (&br, quant->non_intra_quantiser_matrix[mpeg_zigzag_8x8[i]],
+          8);
+    }
+  }
+
+  READ_UINT8 (&br, quant->load_chroma_intra_quantiser_matrix, 1);
+  if (quant->load_non_intra_quantiser_matrix) {
+    for (i = 0; i < 64; i++) {
+      READ_UINT8 (&br, quant->chroma_intra_quantiser_matrix[mpeg_zigzag_8x8[i]],
+          8);
+    }
+  }
+
+  READ_UINT8 (&br, quant->load_chroma_non_intra_quantiser_matrix, 1);
+  if (quant->load_chroma_non_intra_quantiser_matrix) {
+    for (i = 0; i < 64; i++) {
+      READ_UINT8 (&br,
+          quant->chroma_non_intra_quantiser_matrix[mpeg_zigzag_8x8[i]], 8);
+    }
+  }
+
+  return TRUE;
+
+failed:
+  GST_WARNING ("error parsing \"Quant Matrix Extension\"");
+  return FALSE;
+}
+
+/**
+ * gst_mpeg_video_parse_picture_extension:
+ * @ext: The #GstMpegVideoPictureExt to set
+ * @data: The datas from which to parse the ext
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start the parsing
+ *
+ * Sets the @ext Mpeg Video Picture Extension structure members from @data
+ *
+ * Returns: %TRUE if the picture extension could be parsed correctly,
+ * %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_picture_extension (GstMpegVideoPictureExt * ext,
+    guint8 * data, gsize size, guint offset)
+{
+  GstBitReader br;
+
+  size = size - offset;
+
+  if (size < 4)
+    return FALSE;
+
+  gst_bit_reader_init (&br, &data[offset], size);
+
+  /* f_code */
+  READ_UINT8 (&br, ext->f_code[0][0], 4);
+  READ_UINT8 (&br, ext->f_code[0][1], 4);
+  READ_UINT8 (&br, ext->f_code[1][0], 4);
+  READ_UINT8 (&br, ext->f_code[1][1], 4);
+
+  /* intra DC precision */
+  READ_UINT8 (&br, ext->intra_dc_precision, 2);
+
+  /* picture structure */
+  READ_UINT8 (&br, ext->picture_structure, 2);
+
+  /* top field first */
+  READ_UINT8 (&br, ext->top_field_first, 1);
+
+  /* frame pred frame dct */
+  READ_UINT8 (&br, ext->frame_pred_frame_dct, 1);
+
+  /* concealment motion vectors */
+  READ_UINT8 (&br, ext->concealment_motion_vectors, 1);
+
+  /* q scale type */
+  READ_UINT8 (&br, ext->q_scale_type, 1);
+
+  /* intra vlc format */
+  READ_UINT8 (&br, ext->intra_vlc_format, 1);
+
+  /* alternate scan */
+  READ_UINT8 (&br, ext->alternate_scan, 1);
+
+  /* repeat first field */
+  READ_UINT8 (&br, ext->repeat_first_field, 1);
+
+  /* chroma_420_type */
+  READ_UINT8 (&br, ext->chroma_420_type, 1);
+
+  /* progressive_frame */
+  READ_UINT8 (&br, ext->progressive_frame, 1);
+
+  /* composite display */
+  READ_UINT8 (&br, ext->composite_display, 1);
+
+  if (ext->composite_display) {
+
+    /* v axis */
+    READ_UINT8 (&br, ext->v_axis, 1);
+
+    /* field sequence */
+    READ_UINT8 (&br, ext->field_sequence, 3);
+
+    /* sub carrier */
+    READ_UINT8 (&br, ext->sub_carrier, 1);
+
+    /* burst amplitude */
+    READ_UINT8 (&br, ext->burst_amplitude, 7);
+
+    /* sub_carrier phase */
+    READ_UINT8 (&br, ext->sub_carrier_phase, 8);
+  }
+
+  return TRUE;
+
+failed:
+  GST_WARNING ("error parsing \"Picture Coding Extension\"");
+  return FALSE;
+
+}
+
+/**
+ * gst_mpeg_video_parse_picture_header:
+ * @hdr: The #GstMpegVideoPictureHdr to set
+ * @data: The datas from which to parse the hdr
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start the parsing
+ *
+ * Sets the @hdr Mpeg Video Picture Header structure members from @data
+ *
+ * Returns: %TRUE if the picture sequence could be parsed correctly, %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_picture_header (GstMpegVideoPictureHdr * hdr,
+    guint8 * data, gsize size, guint offset)
+{
+  GstBitReader br;
+
+  size = size - offset;
+
+  if (size < 4)
+    return FALSE;
+
+  gst_bit_reader_init (&br, &data[offset], size);
+
+  /* temperal sequence number */
+  if (!gst_bit_reader_get_bits_uint16 (&br, &hdr->tsn, 10))
+    return FALSE;
+
+  /* frame type */
+  if (!gst_bit_reader_get_bits_uint8 (&br, (guint8 *) & hdr->pic_type, 3))
+    return FALSE;
+
+  if (hdr->pic_type == 0 || hdr->pic_type > 4)
+    return FALSE;               /* Corrupted picture packet */
+
+  /* skype VBV delay */
+  if (!gst_bit_reader_skip (&br, 8))
+    return FALSE;
+
+  if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_P
+      || hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) {
+
+    READ_UINT8 (&br, hdr->full_pel_forward_vector, 1);
+
+    READ_UINT8 (&br, hdr->f_code[0][0], 3);
+    hdr->f_code[0][1] = hdr->f_code[0][0];
+  } else {
+    hdr->full_pel_forward_vector = 0;
+    hdr->f_code[0][0] = hdr->f_code[0][1] = 0;
+  }
+
+  if (hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_B) {
+    READ_UINT8 (&br, hdr->full_pel_backward_vector, 1);
+
+    READ_UINT8 (&br, hdr->f_code[1][0], 3);
+    hdr->f_code[1][1] = hdr->f_code[1][0];
+  } else {
+    hdr->full_pel_backward_vector = 0;
+    hdr->f_code[1][0] = hdr->f_code[1][1] = 0;
+  }
+
+  return TRUE;
+
+failed:
+  {
+    GST_WARNING ("Failed to parse sequence extension");
+    return FALSE;
+  }
+}
+
+/**
+ * gst_mpeg_video_parse_gop:
+ * @gop: The #GstMpegVideoGop to set
+ * @data: The datas from which to parse the gop
+ * @size: The size of @data
+ * @offset: The offset in byte from which to start the parsing
+ *
+ *
+ * Sets the @gop Mpeg Video Group of Picture structure members from @data
+ *
+ * Returns: %TRUE if the gop could be parsed correctly, %FALSE otherwize.
+ */
+gboolean
+gst_mpeg_video_parse_gop (GstMpegVideoGop * gop, guint8 * data,
+    gsize size, guint offset)
+{
+  GstBitReader br;
+
+  size = size - offset;
+
+  if (size < 4)
+    return FALSE;
+
+  gst_bit_reader_init (&br, &data[offset], size);
+
+  READ_UINT8 (&br, gop->drop_frame_flag, 1);
+
+  READ_UINT8 (&br, gop->hour, 5);
+
+  READ_UINT8 (&br, gop->minute, 6);
+
+  /* skip unused bit */
+  if (!gst_bit_reader_skip (&br, 1))
+    return FALSE;
+
+  READ_UINT8 (&br, gop->second, 6);
+
+  READ_UINT8 (&br, gop->frame, 6);
+
+  READ_UINT8 (&br, gop->closed_gop, 1);
+
+  READ_UINT8 (&br, gop->broken_gop, 1);
+
+  return TRUE;
+
+failed:
+  GST_WARNING ("error parsing \"GOP\"");
+  return FALSE;
+}
diff --git a/gst-libs/gst/codecparsers/gstmpegvideoparser.h b/gst-libs/gst/codecparsers/gstmpegvideoparser.h
new file mode 100644 (file)
index 0000000..8d034af
--- /dev/null
@@ -0,0 +1,365 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ * From bad/sys/vdpau/mpeg/mpegutil.c:
+ *   Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
+ *   Copyright (C) <2009> Carl-Anton Ingmarsson <ca.ingmarsson@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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_MPEG_VIDEO_UTILS_H__
+#define __GST_MPEG_VIDEO_UTILS_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstMpegVideoPacketTypeCode:
+ * @GST_MPEG_VIDEO_PACKET_PICTURE: Picture packet starting code
+ * @GST_MPEG_VIDEO_PACKET_SLICE_MIN: Picture packet starting code
+ * @GST_MPEG_VIDEO_PACKET_SLICE_MAX: Slice max packet starting code
+ * @GST_MPEG_VIDEO_PACKET_SEQUENCE : Sequence packet starting code
+ * @GST_MPEG_VIDEO_PACKET_EXTENSION: Extension packet starting code
+ * @GST_MPEG_VIDEO_PACKET_SEQUENCE_END: Sequence end packet code
+ * @GST_MPEG_VIDEO_PACKET_GOP: Group of Picture packet starting code
+ * @GST_MPEG_VIDEO_PACKET_NONE: None packet code
+ *
+ * Indicates the type of MPEG packet
+ */
+typedef enum {
+  GST_MPEG_VIDEO_PACKET_PICTURE      = 0x00,
+  GST_MPEG_VIDEO_PACKET_SLICE_MIN    = 0x01,
+  GST_MPEG_VIDEO_PACKET_SLICE_MAX    = 0xaf,
+  GST_MPEG_VIDEO_PACKET_SEQUENCE     = 0xb3,
+  GST_MPEG_VIDEO_PACKET_EXTENSION    = 0xb5,
+  GST_MPEG_VIDEO_PACKET_SEQUENCE_END = 0xb7,
+  GST_MPEG_VIDEO_PACKET_GOP          = 0xb8,
+  GST_MPEG_VIDEO_PACKET_NONE         = 0xff
+} GstMpegVideoPacketTypeCode;
+
+/**
+ * GstMpegVideoPacketExtensionCode:
+ * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE: Sequence extension code
+ * @GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY: Display extension code
+ * @GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX: Quantizer extension code
+ * @GST_MPEG_VIDEO_PACKET_EXT_GOP: Group Of Picture extension code
+ *
+ * Indicates what type of packets are in this
+ * block, some are mutually * exclusive though - ie, sequence packs are
+ * accumulated separately. GOP & Picture may occur together or separately
+ */
+typedef enum {
+  GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE         = 0x01,
+  GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY = 0x02,
+  GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX     = 0x03,
+  GST_MPEG_VIDEO_PACKET_EXT_GOP              = 0x04
+} GstMpegVideoPacketExtensionCode;
+
+/**
+ * GstMpegVideoLevel:
+ * @GST_MPEG_VIDEO_LEVEL_LOW
+ * @GST_MPEG_VIDEO_LEVEL_MAIN
+ * @GST_MPEG_VIDEO_LEVEL_HIGH_1440
+ * @GST_MPEG_VIDEO_LEVEL_HIGH
+ *
+ * Indicates the level in use
+ **/
+typedef enum {
+ GST_MPEG_VIDEO_LEVEL_HIGH      = 0x04,
+ GST_MPEG_VIDEO_LEVEL_HIGH_1440 = 0x06,
+ GST_MPEG_VIDEO_LEVEL_MAIN      = 0x08,
+ GST_MPEG_VIDEO_LEVEL_LOW       = 0x0a
+} GstMpegVideoLevel;
+
+/**
+ * GstMpegVideoProfile:
+ * @GST_MPEG_VIDEO_PROFILE_422,
+ * @GST_MPEG_VIDEO_PROFILE_HIGH,
+ * @GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE,
+ * @GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE,
+ * @GST_MPEG_VIDEO_PROFILE_MAIN,
+ * @GST_MPEG_VIDEO_PROFILE_SIMPLE,
+ *
+ * Indicates the profile type in use
+ **/
+typedef enum {
+  GST_MPEG_VIDEO_PROFILE_422                 = 0x00,
+  GST_MPEG_VIDEO_PROFILE_HIGH                = 0x01,
+  GST_MPEG_VIDEO_PROFILE_SPATIALLY_SCALABLE  = 0x02,
+  GST_MPEG_VIDEO_PROFILE_SNR_SCALABLE        = 0x03,
+  GST_MPEG_VIDEO_PROFILE_MAIN                = 0x04,
+  GST_MPEG_VIDEO_PROFILE_SIMPLE              = 0x05
+} GstMpegVideoProfile;
+
+/**
+ * GstMpegVideoPictureType:
+ * @GST_MPEG_VIDEO_PICTURE_TYPE_I: Type I
+ * @GST_MPEG_VIDEO_PICTURE_TYPE_P: Type P
+ * @GST_MPEG_VIDEO_PICTURE_TYPE_B: Type B
+ * @GST_MPEG_VIDEO_PICTURE_TYPE_D: Type D
+ *
+ * Indicates the type of picture
+ */
+typedef enum {
+  GST_MPEG_VIDEO_PICTURE_TYPE_I = 0x01,
+  GST_MPEG_VIDEO_PICTURE_TYPE_P = 0x02,
+  GST_MPEG_VIDEO_PICTURE_TYPE_B = 0x03,
+  GST_MPEG_VIDEO_PICTURE_TYPE_D = 0x04
+} GstMpegVideoPictureType;
+
+/**
+ * GstMpegVideoPictureStructure:
+ * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD: Top field
+ * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD: Bottom field
+ * @GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME: Frame
+ *
+ * Indicates the structure of picture
+ */
+typedef enum {
+    GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD    = 0x01,
+    GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD = 0x02,
+    GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME        = 0x03
+} GstMpegVideoPictureStructure;
+
+typedef struct _GstMpegVideoSequenceHdr     GstMpegVideoSequenceHdr;
+typedef struct _GstMpegVideoSequenceExt     GstMpegVideoSequenceExt;
+typedef struct _GstMpegVideoPictureHdr      GstMpegVideoPictureHdr;
+typedef struct _GstMpegVideoGop             GstMpegVideoGop;
+typedef struct _GstMpegVideoPictureExt      GstMpegVideoPictureExt;
+typedef struct _GstMpegVideoQuantMatrixExt  GstMpegVideoQuantMatrixExt;
+typedef struct _GstMpegVideoTypeOffsetSize  GstMpegVideoTypeOffsetSize;
+
+/**
+ * GstMpegVideoSequenceHdr:
+ * @width: Width of each frame
+ * @height: Height of each frame
+ * @par_w: Calculated Pixel Aspect Ratio width
+ * @par_h: Pixel Aspect Ratio height
+ * @fps_n: Calculated Framrate nominator
+ * @fps_d: Calculated Framerate denominator
+ * @bitrate_value: Value of the bitrate as is in the stream (400bps unit)
+ * @bitrate: the real bitrate of the Mpeg video stream in bits per second, 0 if VBR stream
+ * @constrained_parameters_flag: %TRUE if this stream uses contrained parameters.
+ * @intra_quantizer_matrix: intra-quantization table
+ * @non_intra_quantizer_matrix: non-intra quantization table
+ *
+ * The Mpeg2 Video Sequence Header structure.
+ */
+struct _GstMpegVideoSequenceHdr
+{
+  guint16 width, height;
+  guint8 aspect_ratio_info;
+  guint8 frame_rate_code;
+  guint32 bitrate_value;
+  guint16 vbv_buffer_size_value;
+
+  guint8 constrained_parameters_flag;
+
+  guint8 intra_quantizer_matrix[64];
+  guint8 non_intra_quantizer_matrix[64];
+
+  /* Calculated values */
+  guint par_w, par_h;
+  guint fps_n, fps_d;
+  guint bitrate;
+};
+
+/**
+ * GstMpegVideoSequenceExt:
+ * @profile: mpeg2 decoder profil
+ * @level: mpeg2 decoder level
+ * @progressive: %TRUE if the frames are progressive %FALSE otherwize
+ * @chroma_format: indicates the chrominance format
+ * @horiz_size_ext: Horizontal size
+ * @vert_size_ext: Vertical size
+ * @bitrate_ext: The bitrate
+ * @vbv_buffer_size_extension: Vbv vuffer size
+ * @low_delay: %TRUE if the sequence doesn't contain any B-pitcture, %FALSE
+ * otherwize
+ * @fps_n_ext: Framerate nominator code
+ * @fps_d_ext: Framerate denominator code
+ *
+ * The Mpeg2 Video Sequence Extension structure.
+ **/
+struct _GstMpegVideoSequenceExt
+{
+  /* mpeg2 decoder profile */
+  guint8 profile;
+  /* mpeg2 decoder level */
+  guint8 level;
+
+  guint8 progressive;
+  guint8 chroma_format;
+
+  guint8 horiz_size_ext, vert_size_ext;
+
+  guint16 bitrate_ext;
+  guint8 vbv_buffer_size_extension;
+  guint8 low_delay;
+  guint8 fps_n_ext, fps_d_ext;
+
+};
+
+/**
+ * GstMpegVideoQuantMatrixExt:
+ * @load_intra_quantiser_matrix
+ * @intra_quantiser_matrix
+ * @load_non_intra_quantiser_matrix
+ * @non_intra_quantiser_matrix:
+ * @load_chroma_intra_quantiser_matrix
+ * @chroma_intra_quantiser_matrix
+ * @load_chroma_non_intra_quantiser_matrix
+ * @chroma_non_intra_quantiser_matrix
+ *
+ * The Quant Matrix Extension structure
+ */
+struct _GstMpegVideoQuantMatrixExt
+{
+ guint8 load_intra_quantiser_matrix;
+ guint8 intra_quantiser_matrix[64];
+ guint8 load_non_intra_quantiser_matrix;
+ guint8 non_intra_quantiser_matrix[64];
+ guint8 load_chroma_intra_quantiser_matrix;
+ guint8 chroma_intra_quantiser_matrix[64];
+ guint8 load_chroma_non_intra_quantiser_matrix;
+ guint8 chroma_non_intra_quantiser_matrix[64];
+};
+
+/**
+ * GstMpegVideoPictureHdr:
+ * @tsn: Temporal Sequence Number
+ * @pic_type: Type of the frame
+ * @full_pel_forward_vector: the full pel forward flag of
+ *  the frame: 0 or 1.
+ * @full_pel_backward_vector: the full pel backward flag
+ *  of the frame: 0 or 1.
+ * @f_code: F code
+ *
+ * The Mpeg2 Video Picture Header structure.
+ */
+struct _GstMpegVideoPictureHdr
+{
+  guint16 tsn;
+  guint8 pic_type;
+
+  guint8 full_pel_forward_vector, full_pel_backward_vector;
+
+  guint8 f_code[2][2];
+};
+
+/**
+ * GstMpegVideoPictureExt:
+ * @intra_dc_precision: Intra DC precision
+ * @picture_structure: Structure of the picture
+ * @top_field_first: Top field first
+ * @frame_pred_frame_dct: Frame
+ * @concealment_motion_vectors: Concealment Motion Vectors
+ * @q_scale_type: Q Scale Type
+ * @intra_vlc_format: Intra Vlc Format
+ * @alternate_scan: Alternate Scan
+ * @repeat_first_field: Repeat First Field
+ * @chroma_420_type: Chroma 420 Type
+ * @progressive_frame: %TRUE if the frame is progressive %FALSE otherwize
+ *
+ * The Mpeg2 Video Picture Extension structure.
+ */
+struct _GstMpegVideoPictureExt
+{
+  guint8 f_code[2][2];
+
+  guint8 intra_dc_precision;
+  guint8 picture_structure;
+  guint8 top_field_first;
+  guint8 frame_pred_frame_dct;
+  guint8 concealment_motion_vectors;
+  guint8 q_scale_type;
+  guint8 intra_vlc_format;
+  guint8 alternate_scan;
+  guint8 repeat_first_field;
+  guint8 chroma_420_type;
+  guint8 progressive_frame;
+  guint8 composite_display;
+  guint8 v_axis;
+  guint8 field_sequence;
+  guint8 sub_carrier;
+  guint8 burst_amplitude;
+  guint8 sub_carrier_phase;
+};
+
+/**
+ * GstMpegVideoGop:
+ * @drop_frame_flag: Drop Frame Flag
+ * @hour: Hour (0-23)
+ * @minute: Minute (O-59)
+ * @second: Second (0-59)
+ * @frame: Frame (0-59)
+ * @closed_gop: Closed Gop
+ * @broken_gop: Broken Gop
+ *
+ * The Mpeg Video Group of Picture structure.
+ */
+struct _GstMpegVideoGop
+{
+  guint8 drop_frame_flag;
+
+  guint8 hour, minute, second, frame;
+
+  guint8 closed_gop;
+  guint8 broken_gop;
+};
+
+/**
+ * GstMpegVideoTypeOffsetSize:
+ * @type: the type of the packet that start at @offset
+ * @offset: the offset of the packet start in bytes, it is the exact, start of the packet, no sync code included
+ * @size: The size in bytes of the packet or -1 if the end wasn't found. It is the exact size of the packet, no sync code included
+ *
+ * A structure that contains the type of a packet, its offset and its size
+ */
+struct _GstMpegVideoTypeOffsetSize
+{
+  guint8 type;
+  guint offset;
+  gint size;
+};
+
+GList * gst_mpeg_video_parse                          (guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_sequence_header         (GstMpegVideoSequenceHdr * params,
+                                                       guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_picture_header          (GstMpegVideoPictureHdr* hdr,
+                                                       guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_picture_extension       (GstMpegVideoPictureExt *ext,
+                                                       guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_gop                     (GstMpegVideoGop * gop,
+                                                       guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_sequence_extension      (GstMpegVideoSequenceExt * seqext,
+                                                       guint8 * data, gsize size, guint offset);
+
+gboolean gst_mpeg_video_parse_quant_matrix_extension  (GstMpegVideoQuantMatrixExt * quant,
+                                                       guint8 * data, gsize size, guint offset);
+
+G_END_DECLS
+
+#endif
index c1c81f1..adbd33d 100644 (file)
@@ -204,6 +204,7 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS=''
 %{_libdir}/libgstbasevideo-%{majorminor}.so.*
 %{_libdir}/libgstphotography-%{majorminor}.so.*
 %{_libdir}/libgstsignalprocessor-%{majorminor}.so.*
+%{_libdir}/libgstcodecparsers-%{majorminor}.so.*
 # Plugins without external dependencies
 %{_libdir}/gstreamer-%{majorminor}/libgstadpcmdec.so
 %{_libdir}/gstreamer-%{majorminor}/libgstadpcmenc.so
@@ -329,8 +330,10 @@ make ERROR_CFLAGS='' ERROR_CXXFLAGS=''
 %{_libdir}/libgstbasevideo-%{majorminor}.so
 %{_libdir}/libgstphotography-%{majorminor}.so
 %{_libdir}/libgstsignalprocessor-%{majorminor}.so
+%{_libdir}/libgstcodecparsers-%{majorminor}.so
 %{_libdir}/libgstbasecamerabinsrc-%{majorminor}.so
 %{_includedir}/gstreamer-%{majorminor}/gst/interfaces/photography*
+%{_includedir}/gstreamer-%{majorminor}/gst/codecparsers
 %{_includedir}/gstreamer-%{majorminor}/gst/signalprocessor
 %{_includedir}/gstreamer-%{majorminor}/gst/video
 %{_includedir}/gstreamer-%{majorminor}/gst/basecamerabinsrc/gstbasecamerasrc.h
index c75ff59..1fad717 100644 (file)
@@ -7,6 +7,7 @@ Name: GStreamer Bad Plugin libraries
 Description: Currently includes the photography interface library
 Requires: gstreamer-@GST_MAJORMINOR@ gstreamer-base-@GST_MAJORMINOR@
 Version: @VERSION@
-Libs: -L${libdir} -lgstphotography-@GST_MAJORMINOR@
+Libs: -L${libdir} -lgstphotography-@GST_MAJORMINOR@\
+    -L${libdir} -lgstcodecparsers-@GST_MAJORMINOR@\
 Cflags: -I${includedir}
 
index 174c730..8528eb2 100644 (file)
@@ -183,6 +183,7 @@ check_PROGRAMS = \
        pipelines/colorspace \
        $(check_mimic) \
        elements/rtpmux \
+       libs/mpegvideoparser \
        $(check_schro) \
        $(check_vp8) \
         elements/viewfinderbin \
@@ -214,6 +215,15 @@ elements_h263parse_LDADD = libparser.la $(LDADD)
 
 elements_h264parse_LDADD = libparser.la $(LDADD)
 
+libs_mpegvideoparser_CFLAGS = \
+       $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
+       $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
+
+libs_mpegvideoparser_LDADD = \
+       $(top_builddir)/gst-libs/gst/codecparsers/libgstcodecparsers-@GST_MAJORMINOR@.la \
+       $(GST_PLUGINS_BAD_LIBS) -lgstcodecparsers-@GST_MAJORMINOR@ \
+       $(GST_BASE_LIBS) $(GST_LIBS) $(LDADD)
+
 elements_voaacenc_CFLAGS = \
        $(GST_PLUGINS_BASE_CFLAGS) \
        $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(AM_CFLAGS)
diff --git a/tests/check/libs/mpegvideoparser.c b/tests/check/libs/mpegvideoparser.c
new file mode 100644 (file)
index 0000000..414a45e
--- /dev/null
@@ -0,0 +1,208 @@
+/* Gstreamer
+ * Copyright (C) <2011> Intel Corporation
+ * Copyright (C) <2011> Collabora Ltd.
+ * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gst/check/gstcheck.h>
+#include <gst/codecparsers/gstmpegvideoparser.h>
+
+/* actually seq + gop */
+static guint8 mpeg2_seq[] = {
+  0x00, 0x00, 0x01, 0xb3, 0x02, 0x00, 0x18, 0x15, 0xff, 0xff, 0xe0, 0x28,
+  0x00, 0x00, 0x01, 0xb3, 0x78, 0x04, 0x38, 0x37, 0xff, 0xff, 0xf0, 0x00,
+  0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x11, 0x03, 0x71,
+  0x00, 0x00, 0x01, 0xb8, 0x00, 0x08, 0x00, 0x00,
+  0x00, 0x00, 0x01, 0x03, 0x00, 0x08, 0x00, 0x00
+};
+
+static guint8 mis_identified_datas[] = {
+  0x00, 0x00, 0x01, 0x1f, 0x4a, 0xf4, 0xd4, 0xd8, 0x08, 0x23, 0xdd,
+  0x7c, 0xd3, 0x75, 0x21, 0x43, 0x85, 0x31, 0x43, 0x04, 0x24, 0x30,
+  0x18, 0x43, 0xba, 0x1a, 0x50, 0x60, 0xbb, 0x53, 0x56, 0x80, 0x41,
+  0xb9, 0xd4, 0x25, 0x42, 0xea, 0x71, 0xb7, 0x49, 0x84, 0x0b, 0x14,
+  0x24, 0xc2, 0xaa, 0xba, 0xf9, 0xf7, 0x5b, 0x78, 0xa2, 0xba, 0xd3,
+  0xc7, 0x12, 0xee, 0xbe, 0xba, 0xfa, 0xeb, 0xeb, 0xaf, 0xbe, 0x6f,
+  0xce, 0x92, 0x05, 0x15, 0x22, 0x44, 0xf4, 0xc9, 0x1b, 0xcd, 0x84,
+  0x80, 0x87, 0x35, 0x6c, 0x07, 0x82, 0xaf, 0x3c, 0x3a, 0x89, 0x48,
+  0x3a, 0x26, 0x00, 0x64, 0x03, 0x12, 0x60, 0x03, 0xf4, 0x8c, 0x21,
+  0x16, 0xbe, 0x3c, 0x7c, 0x18, 0x03, 0x10, 0x0c, 0x80, 0xa0, 0x05,
+  0xe1, 0x85, 0x94, 0x90, 0xc4, 0x74, 0x05, 0x72, 0x80, 0x7a, 0x8e,
+  0x3e, 0x00, 0x30,
+  /* The accelerated version of scan_for_start_codes()
+   * mis-identifies the following as a start code */
+  0x01, 0x00, 0x01, 0x80, 0x68, 0x14,
+  0x26, 0xe4, 0x80, 0x98, 0x0a, 0xba, 0x77, 0x01, 0xc2, 0x42, 0x12,
+  0xc4, 0x59, 0x2a, 0xbb, 0x49, 0xf2, 0xc5, 0xa8, 0xd9, 0x30, 0x33,
+  0x16, 0x50, 0x60, 0x61, 0x41, 0xaa, 0x0d, 0x41, 0x5b, 0x17, 0x77,
+  0x76, 0x1a, 0x14, 0x3a, 0x08, 0x19, 0x3d, 0x6c, 0x94, 0x55, 0xd0,
+  0x94, 0x5a, 0xeb, 0x61, 0x22, 0xa7, 0xa6, 0x83, 0x47, 0x6d, 0x4d,
+  0x84, 0xc4, 0x6f, 0x78, 0xd8, 0x3a, 0xb4, 0x02, 0x0c, 0x36, 0xa6,
+  0x0b, 0x18, 0x49, 0xf7, 0xad, 0x00, 0x82, 0x09, 0xba, 0x12, 0xba,
+  0x1d, 0x44, 0x94, 0x0a, 0x1b, 0x03, 0xbb, 0xa2, 0x53, 0x02, 0xc0,
+  0x41, 0xac, 0x22,
+  /* the real start code is here */
+  0x00, 0x00, 0x01, 0x20, 0x4a, 0xfd, 0xf5, 0x50
+};
+
+static GstMpegVideoPacketTypeCode ordercode[] = {
+  GST_MPEG_VIDEO_PACKET_SEQUENCE,
+  GST_MPEG_VIDEO_PACKET_EXTENSION,
+  GST_MPEG_VIDEO_PACKET_GOP,
+};
+
+GST_START_TEST (test_mpeg_parse)
+{
+  gint i;
+  GList *list, *tmp;
+  GstMpegVideoTypeOffsetSize *typeoffsz;
+
+  list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12);
+
+  assert_equals_int (g_list_length (list), 4);
+  for (tmp = list, i = 0; tmp; tmp = g_list_next (tmp), i++) {
+    typeoffsz = tmp->data;
+    if (i == 3) {
+      fail_unless (GST_MPEG_VIDEO_PACKET_SLICE_MIN <= typeoffsz->type &&
+          typeoffsz->type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX);
+      fail_unless (typeoffsz->size < 0);
+    } else
+      assert_equals_int (ordercode[i], typeoffsz->type);
+  }
+
+  g_list_free_full (list, (GDestroyNotify) g_free);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mpeg_parse_sequence_header)
+{
+  GList *list;
+  GstMpegVideoTypeOffsetSize *typeoffsz;
+  GstMpegVideoSequenceHdr seqhdr;
+
+  list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12);
+
+  typeoffsz = list->data;
+  fail_unless (typeoffsz->type == GST_MPEG_VIDEO_PACKET_SEQUENCE);
+  fail_unless (gst_mpeg_video_parse_sequence_header (&seqhdr, mpeg2_seq,
+          sizeof (mpeg2_seq), typeoffsz->offset));
+  assert_equals_int (seqhdr.width, 1920);
+  assert_equals_int (seqhdr.height, 1080);
+  assert_equals_int (seqhdr.aspect_ratio_info, 3);
+  assert_equals_int (seqhdr.par_w, 17280);
+  assert_equals_int (seqhdr.par_h, 17280);
+  assert_equals_int (seqhdr.frame_rate_code, 7);
+  assert_equals_int (seqhdr.fps_n, 60000);
+  assert_equals_int (seqhdr.fps_d, 1001);
+  assert_equals_int (seqhdr.bitrate_value, 262143);
+  assert_equals_int (seqhdr.bitrate, 0);
+  assert_equals_int (seqhdr.vbv_buffer_size_value, 512);
+  fail_unless (seqhdr.constrained_parameters_flag == FALSE);
+
+  g_list_free_full (list, (GDestroyNotify) g_free);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mpeg_parse_sequence_extension)
+{
+  GList *list;
+  GstMpegVideoTypeOffsetSize *typeoffsz;
+  GstMpegVideoSequenceExt seqext;
+
+  list = gst_mpeg_video_parse (mpeg2_seq, sizeof (mpeg2_seq), 12);
+
+  typeoffsz = list->next->data;
+  fail_unless (typeoffsz->type == GST_MPEG_VIDEO_PACKET_EXTENSION);
+  fail_unless (gst_mpeg_video_parse_sequence_extension (&seqext,
+          mpeg2_seq, sizeof (mpeg2_seq), typeoffsz->offset));
+  assert_equals_int (seqext.profile, 4);
+  assert_equals_int (seqext.level, 8);
+  assert_equals_int (seqext.progressive, 1);
+  assert_equals_int (seqext.chroma_format, 1);
+  assert_equals_int (seqext.horiz_size_ext, 0);
+  assert_equals_int (seqext.vert_size_ext, 0);
+  assert_equals_int (seqext.vert_size_ext, 0);
+  assert_equals_int (seqext.bitrate_ext, 8);
+  assert_equals_int (seqext.vbv_buffer_size_extension, 3);
+  assert_equals_int (seqext.low_delay, 0);
+  assert_equals_int (seqext.fps_n_ext, 3);
+  assert_equals_int (seqext.fps_d_ext, 2);
+
+  g_list_free_full (list, (GDestroyNotify) g_free);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_mis_identified_datas)
+{
+  GList *list, *tmp;
+  GstMpegVideoTypeOffsetSize *typeoffsz;
+  guint8 *data = mis_identified_datas;
+
+  list = gst_mpeg_video_parse (mis_identified_datas,
+      sizeof (mis_identified_datas), 0);
+
+  assert_equals_int (g_list_length (list), 2);
+  for (tmp = list; tmp; tmp = g_list_next (tmp)) {
+    typeoffsz = tmp->data;
+
+    assert_equals_int (data[typeoffsz->offset - 4], 0);
+    assert_equals_int (data[typeoffsz->offset - 3], 0);
+    assert_equals_int (data[typeoffsz->offset - 2], 1);
+  }
+
+  g_list_free_full (list, (GDestroyNotify) g_free);
+}
+
+GST_END_TEST;
+
+static Suite *
+videoparsers_suite (void)
+{
+  Suite *s = suite_create ("Video Parsers library");
+
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_mpeg_parse);
+  tcase_add_test (tc_chain, test_mpeg_parse_sequence_header);
+  tcase_add_test (tc_chain, test_mpeg_parse_sequence_extension);
+  tcase_add_test (tc_chain, test_mis_identified_datas);
+
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = videoparsers_suite ();
+
+  SRunner *sr = srunner_create (s);
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}