mpeg4videoparse: Move to the videoparsers plugin
authorThibault Saunier <thibault.saunier@collabora.com>
Mon, 26 Sep 2011 13:39:31 +0000 (10:39 -0300)
committerThibault Saunier <thibault.saunier@collabora.com>
Tue, 29 Nov 2011 00:25:34 +0000 (21:25 -0300)
Rename a few variables to use the same convention as others elements in this
plugin

Conflicts:

gst/videoparsers/gstmpeg4videoparse.c

12 files changed:
configure.ac
gst/mpeg4videoparse/Makefile.am [deleted file]
gst/mpeg4videoparse/mpeg4parse.c [deleted file]
gst/mpeg4videoparse/mpeg4parse.h [deleted file]
gst/mpeg4videoparse/mpeg4videoparse.c [deleted file]
gst/mpeg4videoparse/mpeg4videoparse.h [deleted file]
gst/videoparsers/Makefile.am
gst/videoparsers/gstmpeg4videoparse.c [new file with mode: 0644]
gst/videoparsers/gstmpeg4videoparse.h [new file with mode: 0644]
gst/videoparsers/mpeg4parse.c [new file with mode: 0644]
gst/videoparsers/mpeg4parse.h [new file with mode: 0644]
gst/videoparsers/plugin.c

index 7f9d9715d8f4ea779598e74451a8bd5e79768ae6..fc98fce8fe2ad8022004bd7fb4f721313c42a957 100644 (file)
@@ -337,7 +337,6 @@ AG_GST_CHECK_PLUGIN(mpegdemux)
 AG_GST_CHECK_PLUGIN(mpegtsdemux)
 AG_GST_CHECK_PLUGIN(mpegtsmux)
 AG_GST_CHECK_PLUGIN(mpegpsmux)
-AG_GST_CHECK_PLUGIN(mpeg4videoparse)
 AG_GST_CHECK_PLUGIN(mpegvideoparse)
 AG_GST_CHECK_PLUGIN(mve)
 AG_GST_CHECK_PLUGIN(mxf)
@@ -1948,7 +1947,6 @@ gst/mpegtsdemux/Makefile
 gst/mpegtsmux/Makefile
 gst/mpegtsmux/tsmux/Makefile
 gst/mpegpsmux/Makefile
-gst/mpeg4videoparse/Makefile
 gst/mpegvideoparse/Makefile
 gst/mve/Makefile
 gst/mxf/Makefile
diff --git a/gst/mpeg4videoparse/Makefile.am b/gst/mpeg4videoparse/Makefile.am
deleted file mode 100644 (file)
index 8259ed5..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-
-plugin_LTLIBRARIES = libgstmpeg4videoparse.la
-
-libgstmpeg4videoparse_la_SOURCES = mpeg4videoparse.c mpeg4parse.c
-libgstmpeg4videoparse_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
-libgstmpeg4videoparse_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
-libgstmpeg4videoparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstmpeg4videoparse_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = mpeg4videoparse.h mpeg4parse.h
-
-Android.mk: Makefile.am $(BUILT_SOURCES)
-       androgenizer \
-       -:PROJECT libgstmpeg4videoparse -:SHARED libgstmpeg4videoparse \
-        -:TAGS eng debug \
-         -:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-        -:SOURCES $(libgstmpeg4videoparse_la_SOURCES) \
-        -:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstmpeg4videoparse_la_CFLAGS) \
-        -:LDFLAGS $(libgstmpeg4videoparse_la_LDFLAGS) \
-                  $(libgstmpeg4videoparse_la_LIBADD) \
-                  -ldl \
-        -:PASSTHROUGH LOCAL_ARM_MODE:=arm \
-                      LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
-       > $@
diff --git a/gst/mpeg4videoparse/mpeg4parse.c b/gst/mpeg4videoparse/mpeg4parse.c
deleted file mode 100644 (file)
index 5c8ce95..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/* GStreamer MPEG4-2 video Parser
- * Copyright (C) <2008> Mindfruit B.V.
- *   @author Sjoerd Simons <sjoerd@luon.net>
- * Copyright (C) <2007> Julien Moutte <julien@fluendo.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.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include "mpeg4parse.h"
-
-#include <gst/base/gstbitreader.h>
-
-GST_DEBUG_CATEGORY_EXTERN (mpeg4v_parse_debug);
-#define GST_CAT_DEFAULT mpeg4v_parse_debug
-
-
-#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 MARKER_BIT(b) G_STMT_START {  \
-  guint32 i;                          \
-  GET_BITS(b, 1, &i);                 \
-  if (i != 0x1)                       \
-    goto failed;                      \
-} G_STMT_END
-
-static inline gboolean
-next_start_code (GstBitReader * b)
-{
-  guint32 bits = 0;
-
-  GET_BITS (b, 1, &bits);
-  if (bits != 0)
-    goto failed;
-
-  while (b->bit != 0) {
-    GET_BITS (b, 1, &bits);
-    if (bits != 0x1)
-      goto failed;
-  }
-
-  return TRUE;
-
-failed:
-  return FALSE;
-}
-
-static inline gboolean
-skip_user_data (GstBitReader * bs, guint32 * bits)
-{
-  while (*bits == MPEG4_USER_DATA_STARTCODE_MARKER) {
-    guint32 b = 0;
-
-    do {
-      GET_BITS (bs, 8, &b);
-      *bits = (*bits << 8) | b;
-    } while ((*bits >> 8) != MPEG4_START_MARKER);
-  }
-
-  return TRUE;
-
-failed:
-  return FALSE;
-}
-
-
-static gint aspect_ratio_table[6][2] = {
-  {-1, -1}, {1, 1}, {12, 11}, {10, 11}, {16, 11}, {40, 33}
-};
-
-static gboolean
-gst_mpeg4_params_parse_vo (MPEG4Params * params, GstBitReader * br)
-{
-  guint32 bits;
-  guint16 time_increment_resolution = 0;
-  guint16 fixed_time_increment = 0;
-  gint aspect_ratio_width = -1, aspect_ratio_height = -1;
-  gint height = -1, width = -1;
-
-  /* expecting a video object startcode */
-  GET_BITS (br, 32, &bits);
-  if (bits > 0x11F)
-    goto failed;
-
-  /* expecting a video object layer startcode */
-  GET_BITS (br, 32, &bits);
-  if (bits < 0x120 || bits > 0x12F)
-    goto failed;
-
-  /* ignore random accessible vol  and video object type indication */
-  GET_BITS (br, 9, &bits);
-
-  GET_BITS (br, 1, &bits);
-  if (bits) {
-    /* skip video object layer verid and priority */
-    GET_BITS (br, 7, &bits);
-  }
-
-  /* aspect ratio info */
-  GET_BITS (br, 4, &bits);
-  if (bits == 0)
-    goto failed;
-
-  /* check if aspect ratio info  is extended par */
-  if (bits == 0xf) {
-    GET_BITS (br, 8, &bits);
-    aspect_ratio_width = bits;
-    GET_BITS (br, 8, &bits);
-    aspect_ratio_height = bits;
-  } else if (bits < 0x6) {
-    aspect_ratio_width = aspect_ratio_table[bits][0];
-    aspect_ratio_height = aspect_ratio_table[bits][1];
-  }
-  GST_DEBUG ("aspect ratio %d/%d", aspect_ratio_width, aspect_ratio_height);
-
-  GET_BITS (br, 1, &bits);
-  if (bits) {
-    /* vol control parameters, skip chroma and low delay */
-    GET_BITS (br, 3, &bits);
-    GET_BITS (br, 1, &bits);
-    if (bits) {
-      /* skip vbv_parameters */
-      if (!gst_bit_reader_skip (br, 79))
-        goto failed;
-    }
-  }
-
-  /* layer shape */
-  GET_BITS (br, 2, &bits);
-  /* only support rectangular */
-  if (bits != 0)
-    goto failed;
-
-  MARKER_BIT (br);
-  GET_BITS (br, 16, &bits);
-  time_increment_resolution = bits;
-  MARKER_BIT (br);
-
-  GST_DEBUG ("time increment resolution %d", time_increment_resolution);
-
-  GET_BITS (br, 1, &bits);
-  if (bits) {
-    /* fixed time increment */
-    int n;
-
-    /* Length of the time increment is the minimal number of bits needed to
-     * represent time_increment_resolution-1 */
-    for (n = 0; ((time_increment_resolution - 1) >> n) != 0; n++);
-    GET_BITS (br, n, &bits);
-
-    fixed_time_increment = bits;
-  } else {
-    /* When fixed_vop_rate is not set we can't guess any framerate */
-    fixed_time_increment = 0;
-  }
-  GST_DEBUG ("fixed time increment %d", fixed_time_increment);
-
-  /* assuming rectangular shape */
-  MARKER_BIT (br);
-  GET_BITS (br, 13, &bits);
-  width = bits;
-  MARKER_BIT (br);
-  GET_BITS (br, 13, &bits);
-  height = bits;
-  MARKER_BIT (br);
-  GST_DEBUG ("width x height: %d x %d", width, height);
-
-  /* so we got it all, report back */
-  params->width = width;
-  params->height = height;
-  params->time_increment_resolution = time_increment_resolution;
-  params->fixed_time_increment = fixed_time_increment;
-  params->aspect_ratio_width = aspect_ratio_width;
-  params->aspect_ratio_height = aspect_ratio_height;
-
-  return TRUE;
-
-  /* ERRORS */
-failed:
-  {
-    GST_WARNING ("Failed to parse config data");
-    return FALSE;
-  }
-}
-
-static gboolean
-gst_mpeg4_params_parse_vos (MPEG4Params * params, GstBitReader * br)
-{
-  guint32 bits = 0;
-
-  GET_BITS (br, 32, &bits);
-  if (bits != MPEG4_VOS_STARTCODE_MARKER)
-    goto failed;
-
-  GET_BITS (br, 8, &bits);
-  params->profile = bits;
-
-  /* invalid profile, warn but carry on */
-  if (params->profile == 0) {
-    GST_WARNING ("Invalid profile in VOS");
-  }
-
-  /* Expect Visual Object startcode */
-  GET_BITS (br, 32, &bits);
-
-  /* but skip optional user data */
-  if (!skip_user_data (br, &bits))
-    goto failed;
-
-  if (bits != MPEG4_VISUAL_OBJECT_STARTCODE_MARKER)
-    goto failed;
-
-  GET_BITS (br, 1, &bits);
-  if (bits == 0x1) {
-    /* Skip visual_object_verid and priority */
-    GET_BITS (br, 7, &bits);
-  }
-
-  GET_BITS (br, 4, &bits);
-  /* Only support video ID */
-  if (bits != 0x1)
-    goto failed;
-
-  /* video signal type */
-  GET_BITS (br, 1, &bits);
-
-  if (bits == 0x1) {
-    /* video signal type, ignore format and range */
-    GET_BITS (br, 4, &bits);
-
-    GET_BITS (br, 1, &bits);
-    if (bits == 0x1) {
-      /* ignore color description */
-      GET_BITS (br, 24, &bits);
-    }
-  }
-
-  if (!next_start_code (br))
-    goto failed;
-
-  /* skip optional user data */
-  GET_BITS (br, 32, &bits);
-  if (!skip_user_data (br, &bits))
-    goto failed;
-
-  /* rewind to start code */
-  gst_bit_reader_set_pos (br, gst_bit_reader_get_pos (br) - 32);
-
-  return gst_mpeg4_params_parse_vo (params, br);
-
-  /* ERRORS */
-failed:
-  {
-    GST_WARNING ("Failed to parse config data");
-    return FALSE;
-  }
-}
-
-gboolean
-gst_mpeg4_params_parse_config (MPEG4Params * params, const guint8 * data,
-    guint size)
-{
-  GstBitReader br;
-
-  if (size < 4)
-    return FALSE;
-
-  gst_bit_reader_init (&br, data, size);
-
-  if (data[3] == MPEG4_VOS_STARTCODE)
-    return gst_mpeg4_params_parse_vos (params, &br);
-  else
-    return gst_mpeg4_params_parse_vo (params, &br);
-}
diff --git a/gst/mpeg4videoparse/mpeg4parse.h b/gst/mpeg4videoparse/mpeg4parse.h
deleted file mode 100644 (file)
index cf79e88..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* GStreamer MPEG4-2 video Parser
- * Copyright (C) <2008> Mindfruit B.V.
- *   @author Sjoerd Simons <sjoerd@luon.net>
- * Copyright (C) <2007> Julien Moutte <julien@fluendo.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_MPEG4_PARAMS_H__
-#define __GST_MPEG4_PARAMS_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define MPEG4_VIDEO_OBJECT_STARTCODE_MIN      0x00
-#define MPEG4_VIDEO_OBJECT_STARTCODE_MAX      0x1F
-#define MPEG4_VOS_STARTCODE                   0xB0
-#define MPEG4_VOS_ENDCODE                     0xB1
-#define MPEG4_USER_DATA_STARTCODE             0xB2
-#define MPEG4_GOP_STARTCODE                   0xB3
-#define MPEG4_VISUAL_OBJECT_STARTCODE         0xB5
-#define MPEG4_VOP_STARTCODE                   0xB6
-
-#define MPEG4_START_MARKER                    0x000001
-#define MPEG4_VISUAL_OBJECT_STARTCODE_MARKER  \
-  ((MPEG4_START_MARKER << 8) + MPEG4_VISUAL_OBJECT_STARTCODE)
-#define MPEG4_VOS_STARTCODE_MARKER            \
-  ((MPEG4_START_MARKER << 8) + MPEG4_VOS_STARTCODE)
-#define MPEG4_USER_DATA_STARTCODE_MARKER      \
-  ((MPEG4_START_MARKER << 8) + MPEG4_USER_DATA_STARTCODE)
-
-
-typedef struct _MPEG4Params MPEG4Params;
-
-struct _MPEG4Params
-{
-  gint  profile;
-
-  gint  width, height;
-  gint  aspect_ratio_width, aspect_ratio_height;
-  gint  time_increment_resolution;
-  gint  fixed_time_increment;
-};
-
-GstFlowReturn gst_mpeg4_params_parse_config (MPEG4Params * params,
-                                            const guint8 * data, guint size);
-
-G_END_DECLS
-#endif
diff --git a/gst/mpeg4videoparse/mpeg4videoparse.c b/gst/mpeg4videoparse/mpeg4videoparse.c
deleted file mode 100644 (file)
index 83c3db4..0000000
+++ /dev/null
@@ -1,658 +0,0 @@
-/* GStreamer
- * Copyright (C) <2008> Mindfruit B.V.
- *   @author Sjoerd Simons <sjoerd@luon.net>
- * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
- * Copyright (C) <2011> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
- * Copyright (C) <2011> Collabora Multimedia
- * Copyright (C) <2011> Nokia Corporation
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include <gst/base/gstbytereader.h>
-#include "mpeg4videoparse.h"
-
-GST_DEBUG_CATEGORY (mpeg4v_parse_debug);
-#define GST_CAT_DEFAULT mpeg4v_parse_debug
-
-static GstStaticPadTemplate src_template =
-GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("video/mpeg, "
-        "mpegversion = (int) 4, "
-        "parsed = (boolean) true, " "systemstream = (boolean) false")
-    );
-
-static GstStaticPadTemplate sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
-    GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("video/mpeg, "
-        "mpegversion = (int) 4, " "systemstream = (boolean) false")
-    );
-
-/* Properties */
-#define DEFAULT_PROP_DROP      TRUE
-#define DEFAULT_CONFIG_INTERVAL (0)
-
-enum
-{
-  PROP_0,
-  PROP_DROP,
-  PROP_CONFIG_INTERVAL,
-  PROP_LAST
-};
-
-GST_BOILERPLATE (GstMpeg4VParse, gst_mpeg4vparse, GstBaseParse,
-    GST_TYPE_BASE_PARSE);
-
-static gboolean gst_mpeg4vparse_start (GstBaseParse * parse);
-static gboolean gst_mpeg4vparse_stop (GstBaseParse * parse);
-static gboolean gst_mpeg4vparse_check_valid_frame (GstBaseParse * parse,
-    GstBaseParseFrame * frame, guint * framesize, gint * skipsize);
-static GstFlowReturn gst_mpeg4vparse_parse_frame (GstBaseParse * parse,
-    GstBaseParseFrame * frame);
-static GstFlowReturn gst_mpeg4vparse_pre_push_frame (GstBaseParse * parse,
-    GstBaseParseFrame * frame);
-static gboolean gst_mpeg4vparse_set_caps (GstBaseParse * parse, GstCaps * caps);
-static GstCaps *gst_mpeg4vparse_get_caps (GstBaseParse * parse);
-
-static void gst_mpeg4vparse_set_property (GObject * object, guint prop_id,
-    const GValue * value, GParamSpec * pspec);
-static void gst_mpeg4vparse_get_property (GObject * object, guint prop_id,
-    GValue * value, GParamSpec * pspec);
-
-static void
-gst_mpeg4vparse_base_init (gpointer klass)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
-  gst_element_class_add_static_pad_template (element_class, &src_template);
-  gst_element_class_add_static_pad_template (element_class,
-      &sink_template);
-
-  gst_element_class_set_details_simple (element_class,
-      "MPEG 4 video elementary stream parser", "Codec/Parser/Video",
-      "Parses MPEG-4 Part 2 elementary video streams",
-      "Julien Moutte <julien@fluendo.com>");
-}
-
-static void
-gst_mpeg4vparse_set_property (GObject * object, guint property_id,
-    const GValue * value, GParamSpec * pspec)
-{
-  GstMpeg4VParse *parse = GST_MPEG4VIDEOPARSE (object);
-
-  switch (property_id) {
-    case PROP_DROP:
-      parse->drop = g_value_get_boolean (value);
-      break;
-    case PROP_CONFIG_INTERVAL:
-      parse->interval = g_value_get_uint (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-  }
-}
-
-static void
-gst_mpeg4vparse_get_property (GObject * object, guint property_id,
-    GValue * value, GParamSpec * pspec)
-{
-  GstMpeg4VParse *parse = GST_MPEG4VIDEOPARSE (object);
-
-  switch (property_id) {
-    case PROP_DROP:
-      g_value_set_boolean (value, parse->drop);
-      break;
-    case PROP_CONFIG_INTERVAL:
-      g_value_set_uint (value, parse->interval);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-  }
-}
-
-static void
-gst_mpeg4vparse_class_init (GstMpeg4VParseClass * klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_class->set_property = gst_mpeg4vparse_set_property;
-  gobject_class->get_property = gst_mpeg4vparse_get_property;
-
-  g_object_class_install_property (gobject_class, PROP_DROP,
-      g_param_spec_boolean ("drop", "drop",
-          "Drop data untill valid configuration data is received either "
-          "in the stream or through caps", DEFAULT_PROP_DROP,
-          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  g_object_class_install_property (gobject_class, PROP_CONFIG_INTERVAL,
-      g_param_spec_uint ("config-interval",
-          "Configuration Send Interval",
-          "Send Configuration Insertion Interval in seconds (configuration headers "
-          "will be multiplexed in the data stream when detected.) (0 = disabled)",
-          0, 3600, DEFAULT_CONFIG_INTERVAL,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-  /* Override BaseParse vfuncs */
-  parse_class->start = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_start);
-  parse_class->stop = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_stop);
-  parse_class->check_valid_frame =
-      GST_DEBUG_FUNCPTR (gst_mpeg4vparse_check_valid_frame);
-  parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_parse_frame);
-  parse_class->pre_push_frame =
-      GST_DEBUG_FUNCPTR (gst_mpeg4vparse_pre_push_frame);
-  parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_set_caps);
-  parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_get_caps);
-}
-
-static void
-gst_mpeg4vparse_init (GstMpeg4VParse * parse, GstMpeg4VParseClass * g_class)
-{
-  parse->interval = DEFAULT_CONFIG_INTERVAL;
-  parse->last_report = GST_CLOCK_TIME_NONE;
-}
-
-static void
-gst_mpeg4vparse_reset_frame (GstMpeg4VParse * mp4vparse)
-{
-  /* done parsing; reset state */
-  mp4vparse->last_sc = -1;
-  mp4vparse->vop_offset = -1;
-  mp4vparse->vos_offset = -1;
-  mp4vparse->vo_offset = -1;
-}
-
-static void
-gst_mpeg4vparse_reset (GstMpeg4VParse * mp4vparse)
-{
-  gst_mpeg4vparse_reset_frame (mp4vparse);
-  mp4vparse->profile = 0;
-  mp4vparse->update_caps = TRUE;
-
-  gst_buffer_replace (&mp4vparse->config, NULL);
-  memset (&mp4vparse->params, 0, sizeof (mp4vparse->params));
-}
-
-static gboolean
-gst_mpeg4vparse_start (GstBaseParse * parse)
-{
-  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEOPARSE (parse);
-
-  GST_DEBUG_OBJECT (parse, "start");
-
-  gst_mpeg4vparse_reset (mp4vparse);
-  /* at least this much for a valid frame */
-  gst_base_parse_set_min_frame_size (parse, 6);
-
-  return TRUE;
-}
-
-static gboolean
-gst_mpeg4vparse_stop (GstBaseParse * parse)
-{
-  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEOPARSE (parse);
-
-  GST_DEBUG_OBJECT (parse, "stop");
-
-  gst_mpeg4vparse_reset (mp4vparse);
-
-  return TRUE;
-}
-
-static gboolean
-gst_mpeg4vparse_process_config (GstMpeg4VParse * mp4vparse, const guint8 * data,
-    gsize size)
-{
-  /* only do stuff if something new */
-  if (mp4vparse->config && size == GST_BUFFER_SIZE (mp4vparse->config) &&
-      memcmp (GST_BUFFER_DATA (mp4vparse->config), data, size) == 0)
-    return TRUE;
-
-  if (!gst_mpeg4_params_parse_config (&mp4vparse->params, data, size)) {
-    GST_DEBUG_OBJECT (mp4vparse, "failed to parse config data (size %"
-        G_GSSIZE_FORMAT ")", size);
-    return FALSE;
-  }
-
-  GST_LOG_OBJECT (mp4vparse, "accepting parsed config size %" G_GSSIZE_FORMAT,
-      size);
-
-  /* parsing ok, so accept it as new config */
-  if (mp4vparse->config != NULL)
-    gst_buffer_unref (mp4vparse->config);
-
-  mp4vparse->config = gst_buffer_new_and_alloc (size);
-  memcpy (GST_BUFFER_DATA (mp4vparse->config), data, size);
-
-  /* trigger src caps update */
-  mp4vparse->update_caps = TRUE;
-
-  return TRUE;
-}
-
-/* caller guarantees at least start code in @buf at @off */
-static gboolean
-gst_mpeg4vparse_process_sc (GstMpeg4VParse * mp4vparse, GstBuffer * buf,
-    gint off)
-{
-  guint8 *data;
-  guint code;
-
-  g_return_val_if_fail (buf && GST_BUFFER_SIZE (buf) >= off + 4, FALSE);
-
-  data = GST_BUFFER_DATA (buf);
-  code = data[off + 3];
-
-  GST_LOG_OBJECT (mp4vparse, "process startcode %x", code);
-
-  /* if we found a VOP, next start code ends it,
-   * except for final VOS end sequence code included in last VOP-frame */
-  if (mp4vparse->vop_offset >= 0 && code != MPEG4_VOS_ENDCODE) {
-    if (G_LIKELY (GST_BUFFER_SIZE (buf) > mp4vparse->vop_offset + 4)) {
-      mp4vparse->intra_frame =
-          ((data[mp4vparse->vop_offset + 4] >> 6 & 0x3) == 0);
-    } else {
-      GST_WARNING_OBJECT (mp4vparse, "no data following VOP startcode");
-      mp4vparse->intra_frame = FALSE;
-    }
-    GST_LOG_OBJECT (mp4vparse, "ending frame of size %d, is intra %d", off,
-        mp4vparse->intra_frame);
-    return TRUE;
-  }
-
-  switch (code) {
-    case MPEG4_VOP_STARTCODE:
-    case MPEG4_GOP_STARTCODE:
-    {
-      gint offset;
-
-      if (code == MPEG4_VOP_STARTCODE) {
-        GST_LOG_OBJECT (mp4vparse, "startcode is VOP");
-        mp4vparse->vop_offset = off;
-      } else {
-        GST_LOG_OBJECT (mp4vparse, "startcode is GOP");
-      }
-      /* parse config data ending here if proper startcodes found earlier;
-       * preferably start at VOS (visual object sequence),
-       * otherwise at VO (video object) */
-      offset = mp4vparse->vos_offset >= 0 ?
-          mp4vparse->vos_offset : mp4vparse->vo_offset;
-      if (offset >= 0) {
-        gst_mpeg4vparse_process_config (mp4vparse, GST_BUFFER_DATA (buf), off);
-        /* avoid accepting again for a VOP sc following a GOP sc */
-        mp4vparse->vos_offset = -1;
-        mp4vparse->vo_offset = -1;
-      }
-      break;
-    }
-    case MPEG4_VOS_STARTCODE:
-      GST_LOG_OBJECT (mp4vparse, "startcode is VOS");
-      mp4vparse->vos_offset = off;
-      break;
-    default:
-      /* VO (video object) cases */
-      if (code <= 0x1f) {
-        GST_LOG_OBJECT (mp4vparse, "startcode is VO");
-        mp4vparse->vo_offset = off;
-      }
-      break;
-  }
-
-  /* at least need to have a VOP in a frame */
-  return FALSE;
-}
-
-/* FIXME move into baseparse, or anything equivalent;
- * see https://bugzilla.gnome.org/show_bug.cgi?id=650093 */
-#define GST_BASE_PARSE_FRAME_FLAG_PARSING   0x10000
-
-static gboolean
-gst_mpeg4vparse_check_valid_frame (GstBaseParse * parse,
-    GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
-{
-  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEOPARSE (parse);
-  GstBuffer *buf = frame->buffer;
-  GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
-  gint off = 0;
-  gboolean ret;
-  guint code;
-
-retry:
-  /* at least start code and subsequent byte */
-  if (G_UNLIKELY (GST_BUFFER_SIZE (buf) - off < 5))
-    return FALSE;
-
-  /* avoid stale cached parsing state */
-  if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_PARSING)) {
-    GST_LOG_OBJECT (mp4vparse, "parsing new frame");
-    gst_mpeg4vparse_reset_frame (mp4vparse);
-    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_PARSING;
-  } else {
-    GST_LOG_OBJECT (mp4vparse, "resuming frame parsing");
-  }
-
-  /* if already found a previous start code, e.g. start of frame, go for next */
-  if (mp4vparse->last_sc >= 0) {
-    off = mp4vparse->last_sc;
-    goto next;
-  }
-
-  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffff00, 0x00000100,
-      off, GST_BUFFER_SIZE (buf) - off);
-
-  GST_LOG_OBJECT (mp4vparse, "possible sync at buffer offset %d", off);
-
-  /* didn't find anything that looks like a sync word, skip */
-  if (G_UNLIKELY (off < 0)) {
-    *skipsize = GST_BUFFER_SIZE (buf) - 3;
-    return FALSE;
-  }
-
-  /* possible frame header, but not at offset 0? skip bytes before sync */
-  if (G_UNLIKELY (off > 0)) {
-    *skipsize = off;
-    return FALSE;
-  }
-
-  /* ensure start code looks like a real starting start code */
-  code = GST_BUFFER_DATA (buf)[3];
-  switch (code) {
-    case MPEG4_VOP_STARTCODE:
-    case MPEG4_VOS_STARTCODE:
-    case MPEG4_GOP_STARTCODE:
-      break;
-    default:
-      if (code <= 0x1f)
-        break;
-      /* undesirable sc */
-      GST_LOG_OBJECT (mp4vparse, "start code is no VOS, VO, VOP or GOP");
-      off++;
-      goto retry;
-  }
-
-  /* found sc */
-  mp4vparse->last_sc = 0;
-
-  /* examine start code, which should not end frame at present */
-  gst_mpeg4vparse_process_sc (mp4vparse, buf, 0);
-
-next:
-  /* start is fine as of now */
-  *skipsize = 0;
-  /* position a bit further than last sc */
-  off++;
-  /* so now we have start code at start of data; locate next start code */
-  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffff00, 0x00000100,
-      off, GST_BUFFER_SIZE (buf) - off);
-
-  GST_LOG_OBJECT (mp4vparse, "next start code at %d", off);
-  if (off < 0) {
-    /* if draining, take all */
-    if (GST_BASE_PARSE_DRAINING (parse)) {
-      off = GST_BUFFER_SIZE (buf);
-      ret = TRUE;
-    } else {
-      /* resume scan where we left it */
-      mp4vparse->last_sc = GST_BUFFER_SIZE (buf) - 4;
-      /* request best next available */
-      *framesize = G_MAXUINT;
-      return FALSE;
-    }
-  } else {
-    /* decide whether this startcode ends a frame */
-    ret = gst_mpeg4vparse_process_sc (mp4vparse, buf, off);
-  }
-
-  if (ret) {
-    *framesize = off;
-  } else {
-    goto next;
-  }
-
-  return ret;
-}
-
-static void
-gst_mpeg4vparse_update_src_caps (GstMpeg4VParse * mp4vparse)
-{
-  GstCaps *caps = NULL;
-
-  /* only update if no src caps yet or explicitly triggered */
-  if (G_LIKELY (GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (mp4vparse)) &&
-          !mp4vparse->update_caps))
-    return;
-
-  /* carry over input caps as much as possible; override with our own stuff */
-  caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (mp4vparse));
-  if (caps) {
-    caps = gst_caps_copy (caps);
-  } else {
-    caps = gst_caps_new_simple ("video/mpeg",
-        "mpegversion", G_TYPE_INT, 4, NULL);
-  }
-
-  gst_caps_set_simple (caps, "systemstream", G_TYPE_BOOLEAN, FALSE,
-      "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
-
-  if (mp4vparse->profile != 0) {
-    gchar *profile = NULL;
-
-    /* FIXME does it make sense to expose the profile in the caps ? */
-    profile = g_strdup_printf ("%d", mp4vparse->profile);
-    gst_caps_set_simple (caps, "profile-level-id",
-        G_TYPE_STRING, profile, NULL);
-    g_free (profile);
-  }
-
-  if (mp4vparse->config != NULL) {
-    gst_caps_set_simple (caps, "codec_data",
-        GST_TYPE_BUFFER, mp4vparse->config, NULL);
-  }
-
-  if (mp4vparse->params.width > 0 && mp4vparse->params.height > 0) {
-    gst_caps_set_simple (caps, "width", G_TYPE_INT, mp4vparse->params.width,
-        "height", G_TYPE_INT, mp4vparse->params.height, NULL);
-  }
-
-  /* perhaps we have  a framerate */
-  if (mp4vparse->params.fixed_time_increment != 0) {
-    gint fps_num = mp4vparse->params.time_increment_resolution;
-    gint fps_den = mp4vparse->params.fixed_time_increment;
-    GstClockTime latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
-
-    gst_caps_set_simple (caps, "framerate",
-        GST_TYPE_FRACTION, fps_num, fps_den, NULL);
-    gst_base_parse_set_frame_rate (GST_BASE_PARSE (mp4vparse),
-        fps_num, fps_den, 0, 0);
-    gst_base_parse_set_latency (GST_BASE_PARSE (mp4vparse), latency, latency);
-  }
-
-  /* or pixel-aspect-ratio */
-  if (mp4vparse->params.aspect_ratio_width > 0 &&
-      mp4vparse->params.aspect_ratio_height > 0) {
-    gst_caps_set_simple (caps, "pixel-aspect-ratio",
-        GST_TYPE_FRACTION, mp4vparse->params.aspect_ratio_width,
-        mp4vparse->params.aspect_ratio_height, NULL);
-  }
-
-  gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (mp4vparse), caps);
-  gst_caps_unref (caps);
-}
-
-static GstFlowReturn
-gst_mpeg4vparse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
-{
-  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEOPARSE (parse);
-  GstBuffer *buffer = frame->buffer;
-
-  gst_mpeg4vparse_update_src_caps (mp4vparse);
-
-  if (mp4vparse->intra_frame)
-    GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
-  else
-    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
-
-  if (G_UNLIKELY (mp4vparse->drop && !mp4vparse->config)) {
-    GST_DEBUG_OBJECT (mp4vparse, "dropping frame as no config yet");
-    return GST_BASE_PARSE_FLOW_DROPPED;
-  } else
-    return GST_FLOW_OK;
-}
-
-static GstFlowReturn
-gst_mpeg4vparse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
-{
-  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEOPARSE (parse);
-  GstBuffer *buffer = frame->buffer;
-
-  /* periodic SPS/PPS sending */
-  if (mp4vparse->interval > 0) {
-    GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
-    guint64 diff;
-
-    /* init */
-    if (!GST_CLOCK_TIME_IS_VALID (mp4vparse->last_report)) {
-      mp4vparse->last_report = timestamp;
-    }
-
-    if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
-      if (timestamp > mp4vparse->last_report)
-        diff = timestamp - mp4vparse->last_report;
-      else
-        diff = 0;
-
-      GST_LOG_OBJECT (mp4vparse,
-          "now %" GST_TIME_FORMAT ", last config %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (timestamp), GST_TIME_ARGS (mp4vparse->last_report));
-
-      GST_LOG_OBJECT (mp4vparse,
-          "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
-
-      if (GST_TIME_AS_SECONDS (diff) >= mp4vparse->interval) {
-        /* we need to send config now first */
-        GST_LOG_OBJECT (parse, "inserting config in stream");
-
-        /* avoid inserting duplicate config */
-        if ((GST_BUFFER_SIZE (buffer) < GST_BUFFER_SIZE (mp4vparse->config)) ||
-            memcmp (GST_BUFFER_DATA (buffer),
-                GST_BUFFER_DATA (mp4vparse->config),
-                GST_BUFFER_SIZE (mp4vparse->config))) {
-          GstBuffer *superbuf;
-
-          /* insert header */
-          superbuf = gst_buffer_merge (mp4vparse->config, buffer);
-          gst_buffer_copy_metadata (superbuf, buffer, GST_BUFFER_COPY_ALL);
-          gst_buffer_replace (&frame->buffer, superbuf);
-          gst_buffer_unref (superbuf);
-        } else {
-          GST_LOG_OBJECT (parse, "... but avoiding duplication");
-        }
-
-        if (G_UNLIKELY (timestamp != -1)) {
-          mp4vparse->last_report = timestamp;
-        }
-      }
-    }
-  }
-
-  return GST_FLOW_OK;
-}
-
-static gboolean
-gst_mpeg4vparse_set_caps (GstBaseParse * parse, GstCaps * caps)
-{
-  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEOPARSE (parse);
-  GstStructure *s;
-  const GValue *value;
-  GstBuffer *buf;
-
-  GST_DEBUG_OBJECT (parse, "setcaps called with %" GST_PTR_FORMAT, caps);
-
-  s = gst_caps_get_structure (caps, 0);
-
-  if ((value = gst_structure_get_value (s, "codec_data")) != NULL
-      && (buf = gst_value_get_buffer (value))) {
-    /* best possible parse attempt,
-     * src caps are based on sink caps so it will end up in there
-     * whether sucessful or not */
-    gst_mpeg4vparse_process_config (mp4vparse, GST_BUFFER_DATA (buf),
-        GST_BUFFER_SIZE (buf));
-  }
-
-  /* let's not interfere and accept regardless of config parsing success */
-  return TRUE;
-}
-
-static GstCaps *
-gst_mpeg4vparse_get_caps (GstBaseParse * parse)
-{
-  GstCaps *peercaps;
-  GstCaps *res;
-
-  peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse));
-  if (peercaps) {
-    guint i, n;
-
-    /* Remove the parsed field */
-    peercaps = gst_caps_make_writable (peercaps);
-    n = gst_caps_get_size (peercaps);
-    for (i = 0; i < n; i++) {
-      GstStructure *s = gst_caps_get_structure (peercaps, i);
-
-      gst_structure_remove_field (s, "parsed");
-    }
-
-    res =
-        gst_caps_intersect_full (peercaps,
-        gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD (parse)),
-        GST_CAPS_INTERSECT_FIRST);
-    gst_caps_unref (peercaps);
-  } else {
-    res =
-        gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD
-            (parse)));
-  }
-
-  return res;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
-  GST_DEBUG_CATEGORY_INIT (mpeg4v_parse_debug, "mpeg4videoparse", 0,
-      "MPEG-4 video parser");
-
-  if (!gst_element_register (plugin, "mpeg4videoparse", GST_RANK_PRIMARY + 1,
-          gst_mpeg4vparse_get_type ()))
-    return FALSE;
-
-  return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
-    GST_VERSION_MINOR,
-    "mpeg4videoparse",
-    "MPEG-4 video parser",
-    plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/mpeg4videoparse/mpeg4videoparse.h b/gst/mpeg4videoparse/mpeg4videoparse.h
deleted file mode 100644 (file)
index 05d81e8..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* GStreamer
- * Copyright (C) <2007> Julien Moutte <julien@fluendo.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 __MPEG4VIDEOPARSE_H__
-#define __MPEG4VIDEOPARSE_H__
-
-#include <gst/gst.h>
-#include <gst/base/gstbaseparse.h>
-
-#include "mpeg4parse.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_MPEG4VIDEOPARSE            (gst_mpeg4vparse_get_type())
-#define GST_MPEG4VIDEOPARSE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),\
-                                GST_TYPE_MPEG4VIDEOPARSE, GstMpeg4VParse))
-#define GST_MPEG4VIDEOPARSE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),\
-                                GST_TYPE_MPEG4VIDEOPARSE, GstMpeg4VParseClass))
-#define GST_MPEG4VIDEOPARSE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),\
-                                GST_TYPE_MPEG4VIDEOPARSE, GstMpeg4VParseClass))
-#define GST_IS_MPEG4VIDEOPARSE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
-                                GST_TYPE_MPEG4VIDEOPARSE))
-#define GST_IS_MPEG4VIDEOPARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
-                                GST_TYPE_MPEG4VIDEOPARSE))
-
-typedef struct _GstMpeg4VParse GstMpeg4VParse;
-typedef struct _GstMpeg4VParseClass GstMpeg4VParseClass;
-
-struct _GstMpeg4VParse {
-  GstBaseParse element;
-
-  GstClockTime last_report;
-
-  /* parse state */
-  gint last_sc;
-  gint vop_offset;
-  gint vos_offset;
-  gint vo_offset;
-  gboolean intra_frame;
-  gboolean update_caps;
-
-  GstBuffer *config;
-  guint8 profile;
-  MPEG4Params params;
-
-  /* properties */
-  gboolean drop;
-  guint interval;
-};
-
-struct _GstMpeg4VParseClass {
-  GstBaseParseClass parent_class;
-};
-
-GType gst_mpeg4vparse_get_type (void);
-
-G_END_DECLS
-
-#endif /* __MPEG4VIDEOPARSE_H__ */
index ac2a51711980c5332afc5e2056445b083134ef42..e2d3976f0cd3a7080370e1dce914d0629da13ae2 100644 (file)
@@ -3,7 +3,8 @@ plugin_LTLIBRARIES = libgstvideoparsersbad.la
 libgstvideoparsersbad_la_SOURCES = plugin.c \
        h263parse.c gsth263parse.c \
        gstdiracparse.c dirac_parse.c \
-       gsth264parse.c gstmpegvideoparse.c
+       gsth264parse.c gstmpegvideoparse.c \
+       gstmpeg4videoparse.c mpeg4parse.c
 
 libgstvideoparsersbad_la_CFLAGS = \
        $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
@@ -17,7 +18,8 @@ libgstvideoparsersbad_la_LIBTOOLFLAGS = --tag=disable-static
 
 noinst_HEADERS = gsth263parse.h h263parse.h \
        gstdiracparse.h dirac_parse.h \
-       gsth264parse.h gstmpegvideoparse.h
+       gsth264parse.h gstmpegvideoparse.h \
+       gstmpeg4videoparse.h mpeg4parse.h
 
 Android.mk: Makefile.am $(BUILT_SOURCES)
        androgenizer \
diff --git a/gst/videoparsers/gstmpeg4videoparse.c b/gst/videoparsers/gstmpeg4videoparse.c
new file mode 100644 (file)
index 0000000..1612626
--- /dev/null
@@ -0,0 +1,643 @@
+/* GStreamer
+ * Copyright (C) <2008> Mindfruit B.V.
+ *   @author Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
+ * Copyright (C) <2011> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
+ * Copyright (C) <2011> Collabora Multimedia
+ * Copyright (C) <2011> Nokia Corporation
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <gst/base/gstbytereader.h>
+#include "gstmpeg4videoparse.h"
+
+GST_DEBUG_CATEGORY (mpeg4v_parse_debug);
+#define GST_CAT_DEFAULT mpeg4v_parse_debug
+
+static GstStaticPadTemplate src_template =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg, "
+        "mpegversion = (int) 4, "
+        "parsed = (boolean) true, " "systemstream = (boolean) false")
+    );
+
+static GstStaticPadTemplate sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("video/mpeg, "
+        "mpegversion = (int) 4, " "systemstream = (boolean) false")
+    );
+
+/* Properties */
+#define DEFAULT_PROP_DROP      TRUE
+#define DEFAULT_CONFIG_INTERVAL (0)
+
+enum
+{
+  PROP_0,
+  PROP_DROP,
+  PROP_CONFIG_INTERVAL,
+  PROP_LAST
+};
+
+GST_BOILERPLATE (GstMpeg4VParse, gst_mpeg4vparse, GstBaseParse,
+    GST_TYPE_BASE_PARSE);
+
+static gboolean gst_mpeg4vparse_start (GstBaseParse * parse);
+static gboolean gst_mpeg4vparse_stop (GstBaseParse * parse);
+static gboolean gst_mpeg4vparse_check_valid_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, guint * framesize, gint * skipsize);
+static GstFlowReturn gst_mpeg4vparse_parse_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+static GstFlowReturn gst_mpeg4vparse_pre_push_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame);
+static gboolean gst_mpeg4vparse_set_caps (GstBaseParse * parse, GstCaps * caps);
+static GstCaps *gst_mpeg4vparse_get_caps (GstBaseParse * parse);
+
+static void gst_mpeg4vparse_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_mpeg4vparse_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+static void
+gst_mpeg4vparse_base_init (gpointer klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+  gst_element_class_add_static_pad_template (element_class,
+      &sink_template);
+
+  gst_element_class_set_details_simple (element_class,
+      "MPEG 4 video elementary stream parser", "Codec/Parser/Video",
+      "Parses MPEG-4 Part 2 elementary video streams",
+      "Julien Moutte <julien@fluendo.com>");
+
+  GST_DEBUG_CATEGORY_INIT (mpeg4v_parse_debug, "mpeg4videoparse", 0,
+      "MPEG-4 video parser");
+}
+
+static void
+gst_mpeg4vparse_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMpeg4VParse *parse = GST_MPEG4VIDEO_PARSE (object);
+
+  switch (property_id) {
+    case PROP_DROP:
+      parse->drop = g_value_get_boolean (value);
+      break;
+    case PROP_CONFIG_INTERVAL:
+      parse->interval = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+gst_mpeg4vparse_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstMpeg4VParse *parse = GST_MPEG4VIDEO_PARSE (object);
+
+  switch (property_id) {
+    case PROP_DROP:
+      g_value_set_boolean (value, parse->drop);
+      break;
+    case PROP_CONFIG_INTERVAL:
+      g_value_set_uint (value, parse->interval);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+gst_mpeg4vparse_class_init (GstMpeg4VParseClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->set_property = gst_mpeg4vparse_set_property;
+  gobject_class->get_property = gst_mpeg4vparse_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_DROP,
+      g_param_spec_boolean ("drop", "drop",
+          "Drop data untill valid configuration data is received either "
+          "in the stream or through caps", DEFAULT_PROP_DROP,
+          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CONFIG_INTERVAL,
+      g_param_spec_uint ("config-interval",
+          "Configuration Send Interval",
+          "Send Configuration Insertion Interval in seconds (configuration headers "
+          "will be multiplexed in the data stream when detected.) (0 = disabled)",
+          0, 3600, DEFAULT_CONFIG_INTERVAL,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /* Override BaseParse vfuncs */
+  parse_class->start = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_start);
+  parse_class->stop = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_stop);
+  parse_class->check_valid_frame =
+      GST_DEBUG_FUNCPTR (gst_mpeg4vparse_check_valid_frame);
+  parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_parse_frame);
+  parse_class->pre_push_frame =
+      GST_DEBUG_FUNCPTR (gst_mpeg4vparse_pre_push_frame);
+  parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_set_caps);
+  parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_get_caps);
+}
+
+static void
+gst_mpeg4vparse_init (GstMpeg4VParse * parse, GstMpeg4VParseClass * g_class)
+{
+  parse->interval = DEFAULT_CONFIG_INTERVAL;
+  parse->last_report = GST_CLOCK_TIME_NONE;
+}
+
+static void
+gst_mpeg4vparse_reset_frame (GstMpeg4VParse * mp4vparse)
+{
+  /* done parsing; reset state */
+  mp4vparse->last_sc = -1;
+  mp4vparse->vop_offset = -1;
+  mp4vparse->vos_offset = -1;
+  mp4vparse->vo_offset = -1;
+}
+
+static void
+gst_mpeg4vparse_reset (GstMpeg4VParse * mp4vparse)
+{
+  gst_mpeg4vparse_reset_frame (mp4vparse);
+  mp4vparse->profile = 0;
+  mp4vparse->update_caps = TRUE;
+
+  gst_buffer_replace (&mp4vparse->config, NULL);
+  memset (&mp4vparse->params, 0, sizeof (mp4vparse->params));
+}
+
+static gboolean
+gst_mpeg4vparse_start (GstBaseParse * parse)
+{
+  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEO_PARSE (parse);
+
+  GST_DEBUG_OBJECT (parse, "start");
+
+  gst_mpeg4vparse_reset (mp4vparse);
+  /* at least this much for a valid frame */
+  gst_base_parse_set_min_frame_size (parse, 6);
+
+  return TRUE;
+}
+
+static gboolean
+gst_mpeg4vparse_stop (GstBaseParse * parse)
+{
+  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEO_PARSE (parse);
+
+  GST_DEBUG_OBJECT (parse, "stop");
+
+  gst_mpeg4vparse_reset (mp4vparse);
+
+  return TRUE;
+}
+
+static gboolean
+gst_mpeg4vparse_process_config (GstMpeg4VParse * mp4vparse, const guint8 * data,
+    gsize size)
+{
+  /* only do stuff if something new */
+  if (mp4vparse->config && size == GST_BUFFER_SIZE (mp4vparse->config) &&
+      memcmp (GST_BUFFER_DATA (mp4vparse->config), data, size) == 0)
+    return TRUE;
+
+  if (!gst_mpeg4_params_parse_config (&mp4vparse->params, data, size)) {
+    GST_DEBUG_OBJECT (mp4vparse, "failed to parse config data (size %"
+        G_GSSIZE_FORMAT ")", size);
+    return FALSE;
+  }
+
+  GST_LOG_OBJECT (mp4vparse, "accepting parsed config size %" G_GSSIZE_FORMAT,
+      size);
+
+  /* parsing ok, so accept it as new config */
+  if (mp4vparse->config != NULL)
+    gst_buffer_unref (mp4vparse->config);
+
+  mp4vparse->config = gst_buffer_new_and_alloc (size);
+  memcpy (GST_BUFFER_DATA (mp4vparse->config), data, size);
+
+  /* trigger src caps update */
+  mp4vparse->update_caps = TRUE;
+
+  return TRUE;
+}
+
+/* caller guarantees at least start code in @buf at @off */
+static gboolean
+gst_mpeg4vparse_process_sc (GstMpeg4VParse * mp4vparse, GstBuffer * buf,
+    gint off)
+{
+  guint8 *data;
+  guint code;
+
+  g_return_val_if_fail (buf && GST_BUFFER_SIZE (buf) >= off + 4, FALSE);
+
+  data = GST_BUFFER_DATA (buf);
+  code = data[off + 3];
+
+  GST_LOG_OBJECT (mp4vparse, "process startcode %x", code);
+
+  /* if we found a VOP, next start code ends it,
+   * except for final VOS end sequence code included in last VOP-frame */
+  if (mp4vparse->vop_offset >= 0 && code != MPEG4_VOS_ENDCODE) {
+    if (G_LIKELY (GST_BUFFER_SIZE (buf) > mp4vparse->vop_offset + 4)) {
+      mp4vparse->intra_frame =
+          ((data[mp4vparse->vop_offset + 4] >> 6 & 0x3) == 0);
+    } else {
+      GST_WARNING_OBJECT (mp4vparse, "no data following VOP startcode");
+      mp4vparse->intra_frame = FALSE;
+    }
+    GST_LOG_OBJECT (mp4vparse, "ending frame of size %d, is intra %d", off,
+        mp4vparse->intra_frame);
+    return TRUE;
+  }
+
+  switch (code) {
+    case MPEG4_VOP_STARTCODE:
+    case MPEG4_GOP_STARTCODE:
+    {
+      gint offset;
+
+      if (code == MPEG4_VOP_STARTCODE) {
+        GST_LOG_OBJECT (mp4vparse, "startcode is VOP");
+        mp4vparse->vop_offset = off;
+      } else {
+        GST_LOG_OBJECT (mp4vparse, "startcode is GOP");
+      }
+      /* parse config data ending here if proper startcodes found earlier;
+       * preferably start at VOS (visual object sequence),
+       * otherwise at VO (video object) */
+      offset = mp4vparse->vos_offset >= 0 ?
+          mp4vparse->vos_offset : mp4vparse->vo_offset;
+      if (offset >= 0) {
+        gst_mpeg4vparse_process_config (mp4vparse, GST_BUFFER_DATA (buf), off);
+        /* avoid accepting again for a VOP sc following a GOP sc */
+        mp4vparse->vos_offset = -1;
+        mp4vparse->vo_offset = -1;
+      }
+      break;
+    }
+    case MPEG4_VOS_STARTCODE:
+      GST_LOG_OBJECT (mp4vparse, "startcode is VOS");
+      mp4vparse->vos_offset = off;
+      break;
+    default:
+      /* VO (video object) cases */
+      if (code <= 0x1f) {
+        GST_LOG_OBJECT (mp4vparse, "startcode is VO");
+        mp4vparse->vo_offset = off;
+      }
+      break;
+  }
+
+  /* at least need to have a VOP in a frame */
+  return FALSE;
+}
+
+/* FIXME move into baseparse, or anything equivalent;
+ * see https://bugzilla.gnome.org/show_bug.cgi?id=650093 */
+#define GST_BASE_PARSE_FRAME_FLAG_PARSING   0x10000
+
+static gboolean
+gst_mpeg4vparse_check_valid_frame (GstBaseParse * parse,
+    GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
+{
+  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEO_PARSE (parse);
+  GstBuffer *buf = frame->buffer;
+  GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buf);
+  gint off = 0;
+  gboolean ret;
+  guint code;
+
+retry:
+  /* at least start code and subsequent byte */
+  if (G_UNLIKELY (GST_BUFFER_SIZE (buf) - off < 5))
+    return FALSE;
+
+  /* avoid stale cached parsing state */
+  if (!(frame->flags & GST_BASE_PARSE_FRAME_FLAG_PARSING)) {
+    GST_LOG_OBJECT (mp4vparse, "parsing new frame");
+    gst_mpeg4vparse_reset_frame (mp4vparse);
+    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_PARSING;
+  } else {
+    GST_LOG_OBJECT (mp4vparse, "resuming frame parsing");
+  }
+
+  /* if already found a previous start code, e.g. start of frame, go for next */
+  if (mp4vparse->last_sc >= 0) {
+    off = mp4vparse->last_sc;
+    goto next;
+  }
+
+  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffff00, 0x00000100,
+      off, GST_BUFFER_SIZE (buf) - off);
+
+  GST_LOG_OBJECT (mp4vparse, "possible sync at buffer offset %d", off);
+
+  /* didn't find anything that looks like a sync word, skip */
+  if (G_UNLIKELY (off < 0)) {
+    *skipsize = GST_BUFFER_SIZE (buf) - 3;
+    return FALSE;
+  }
+
+  /* possible frame header, but not at offset 0? skip bytes before sync */
+  if (G_UNLIKELY (off > 0)) {
+    *skipsize = off;
+    return FALSE;
+  }
+
+  /* ensure start code looks like a real starting start code */
+  code = GST_BUFFER_DATA (buf)[3];
+  switch (code) {
+    case MPEG4_VOP_STARTCODE:
+    case MPEG4_VOS_STARTCODE:
+    case MPEG4_GOP_STARTCODE:
+      break;
+    default:
+      if (code <= 0x1f)
+        break;
+      /* undesirable sc */
+      GST_LOG_OBJECT (mp4vparse, "start code is no VOS, VO, VOP or GOP");
+      off++;
+      goto retry;
+  }
+
+  /* found sc */
+  mp4vparse->last_sc = 0;
+
+  /* examine start code, which should not end frame at present */
+  gst_mpeg4vparse_process_sc (mp4vparse, buf, 0);
+
+next:
+  /* start is fine as of now */
+  *skipsize = 0;
+  /* position a bit further than last sc */
+  off++;
+  /* so now we have start code at start of data; locate next start code */
+  off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffff00, 0x00000100,
+      off, GST_BUFFER_SIZE (buf) - off);
+
+  GST_LOG_OBJECT (mp4vparse, "next start code at %d", off);
+  if (off < 0) {
+    /* if draining, take all */
+    if (GST_BASE_PARSE_DRAINING (parse)) {
+      off = GST_BUFFER_SIZE (buf);
+      ret = TRUE;
+    } else {
+      /* resume scan where we left it */
+      mp4vparse->last_sc = GST_BUFFER_SIZE (buf) - 4;
+      /* request best next available */
+      *framesize = G_MAXUINT;
+      return FALSE;
+    }
+  } else {
+    /* decide whether this startcode ends a frame */
+    ret = gst_mpeg4vparse_process_sc (mp4vparse, buf, off);
+  }
+
+  if (ret) {
+    *framesize = off;
+  } else {
+    goto next;
+  }
+
+  return ret;
+}
+
+static void
+gst_mpeg4vparse_update_src_caps (GstMpeg4VParse * mp4vparse)
+{
+  GstCaps *caps = NULL;
+
+  /* only update if no src caps yet or explicitly triggered */
+  if (G_LIKELY (GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (mp4vparse)) &&
+          !mp4vparse->update_caps))
+    return;
+
+  /* carry over input caps as much as possible; override with our own stuff */
+  caps = GST_PAD_CAPS (GST_BASE_PARSE_SINK_PAD (mp4vparse));
+  if (caps) {
+    caps = gst_caps_copy (caps);
+  } else {
+    caps = gst_caps_new_simple ("video/mpeg",
+        "mpegversion", G_TYPE_INT, 4, NULL);
+  }
+
+  gst_caps_set_simple (caps, "systemstream", G_TYPE_BOOLEAN, FALSE,
+      "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+  if (mp4vparse->profile != 0) {
+    gchar *profile = NULL;
+
+    /* FIXME does it make sense to expose the profile in the caps ? */
+    profile = g_strdup_printf ("%d", mp4vparse->profile);
+    gst_caps_set_simple (caps, "profile-level-id",
+        G_TYPE_STRING, profile, NULL);
+    g_free (profile);
+  }
+
+  if (mp4vparse->config != NULL) {
+    gst_caps_set_simple (caps, "codec_data",
+        GST_TYPE_BUFFER, mp4vparse->config, NULL);
+  }
+
+  if (mp4vparse->params.width > 0 && mp4vparse->params.height > 0) {
+    gst_caps_set_simple (caps, "width", G_TYPE_INT, mp4vparse->params.width,
+        "height", G_TYPE_INT, mp4vparse->params.height, NULL);
+  }
+
+  /* perhaps we have  a framerate */
+  if (mp4vparse->params.fixed_time_increment != 0) {
+    gint fps_num = mp4vparse->params.time_increment_resolution;
+    gint fps_den = mp4vparse->params.fixed_time_increment;
+    GstClockTime latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
+
+    gst_caps_set_simple (caps, "framerate",
+        GST_TYPE_FRACTION, fps_num, fps_den, NULL);
+    gst_base_parse_set_frame_rate (GST_BASE_PARSE (mp4vparse),
+        fps_num, fps_den, 0, 0);
+    gst_base_parse_set_latency (GST_BASE_PARSE (mp4vparse), latency, latency);
+  }
+
+  /* or pixel-aspect-ratio */
+  if (mp4vparse->params.aspect_ratio_width > 0 &&
+      mp4vparse->params.aspect_ratio_height > 0) {
+    gst_caps_set_simple (caps, "pixel-aspect-ratio",
+        GST_TYPE_FRACTION, mp4vparse->params.aspect_ratio_width,
+        mp4vparse->params.aspect_ratio_height, NULL);
+  }
+
+  gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (mp4vparse), caps);
+  gst_caps_unref (caps);
+}
+
+static GstFlowReturn
+gst_mpeg4vparse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEO_PARSE (parse);
+  GstBuffer *buffer = frame->buffer;
+
+  gst_mpeg4vparse_update_src_caps (mp4vparse);
+
+  if (mp4vparse->intra_frame)
+    GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+  else
+    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
+
+  if (G_UNLIKELY (mp4vparse->drop && !mp4vparse->config)) {
+    GST_DEBUG_OBJECT (mp4vparse, "dropping frame as no config yet");
+    return GST_BASE_PARSE_FLOW_DROPPED;
+  } else
+    return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_mpeg4vparse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
+{
+  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEO_PARSE (parse);
+  GstBuffer *buffer = frame->buffer;
+
+  /* periodic SPS/PPS sending */
+  if (mp4vparse->interval > 0) {
+    GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
+    guint64 diff;
+
+    /* init */
+    if (!GST_CLOCK_TIME_IS_VALID (mp4vparse->last_report)) {
+      mp4vparse->last_report = timestamp;
+    }
+
+    if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
+      if (timestamp > mp4vparse->last_report)
+        diff = timestamp - mp4vparse->last_report;
+      else
+        diff = 0;
+
+      GST_LOG_OBJECT (mp4vparse,
+          "now %" GST_TIME_FORMAT ", last config %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (timestamp), GST_TIME_ARGS (mp4vparse->last_report));
+
+      GST_LOG_OBJECT (mp4vparse,
+          "interval since last config %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
+
+      if (GST_TIME_AS_SECONDS (diff) >= mp4vparse->interval) {
+        /* we need to send config now first */
+        GST_LOG_OBJECT (parse, "inserting config in stream");
+
+        /* avoid inserting duplicate config */
+        if ((GST_BUFFER_SIZE (buffer) < GST_BUFFER_SIZE (mp4vparse->config)) ||
+            memcmp (GST_BUFFER_DATA (buffer),
+                GST_BUFFER_DATA (mp4vparse->config),
+                GST_BUFFER_SIZE (mp4vparse->config))) {
+          GstBuffer *superbuf;
+
+          /* insert header */
+          superbuf = gst_buffer_merge (mp4vparse->config, buffer);
+          gst_buffer_copy_metadata (superbuf, buffer, GST_BUFFER_COPY_ALL);
+          gst_buffer_replace (&frame->buffer, superbuf);
+          gst_buffer_unref (superbuf);
+        } else {
+          GST_LOG_OBJECT (parse, "... but avoiding duplication");
+        }
+
+        if (G_UNLIKELY (timestamp != -1)) {
+          mp4vparse->last_report = timestamp;
+        }
+      }
+    }
+  }
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_mpeg4vparse_set_caps (GstBaseParse * parse, GstCaps * caps)
+{
+  GstMpeg4VParse *mp4vparse = GST_MPEG4VIDEO_PARSE (parse);
+  GstStructure *s;
+  const GValue *value;
+  GstBuffer *buf;
+
+  GST_DEBUG_OBJECT (parse, "setcaps called with %" GST_PTR_FORMAT, caps);
+
+  s = gst_caps_get_structure (caps, 0);
+
+  if ((value = gst_structure_get_value (s, "codec_data")) != NULL
+      && (buf = gst_value_get_buffer (value))) {
+    /* best possible parse attempt,
+     * src caps are based on sink caps so it will end up in there
+     * whether sucessful or not */
+    gst_mpeg4vparse_process_config (mp4vparse, GST_BUFFER_DATA (buf),
+        GST_BUFFER_SIZE (buf));
+  }
+
+  /* let's not interfere and accept regardless of config parsing success */
+  return TRUE;
+}
+
+
+static GstCaps *
+gst_mpeg4vparse_get_caps (GstBaseParse * parse)
+{
+  GstCaps *peercaps;
+  GstCaps *res;
+
+  peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse));
+  if (peercaps) {
+    guint i, n;
+
+    /* Remove the parsed field */
+    peercaps = gst_caps_make_writable (peercaps);
+    n = gst_caps_get_size (peercaps);
+    for (i = 0; i < n; i++) {
+      GstStructure *s = gst_caps_get_structure (peercaps, i);
+
+      gst_structure_remove_field (s, "parsed");
+    }
+
+    res =
+        gst_caps_intersect_full (peercaps,
+        gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD (parse)),
+        GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (peercaps);
+  } else {
+    res =
+        gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD
+            (parse)));
+  }
+
+  return res;
+}
diff --git a/gst/videoparsers/gstmpeg4videoparse.h b/gst/videoparsers/gstmpeg4videoparse.h
new file mode 100644 (file)
index 0000000..3171182
--- /dev/null
@@ -0,0 +1,75 @@
+/* GStreamer
+ * Copyright (C) <2007> Julien Moutte <julien@fluendo.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 __MPEG4VIDEO_PARSE_H__
+#define __MPEG4VIDEO_PARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbaseparse.h>
+
+#include "mpeg4parse.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_MPEG4VIDEO_PARSE            (gst_mpeg4vparse_get_type())
+#define GST_MPEG4VIDEO_PARSE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),\
+                                GST_TYPE_MPEG4VIDEO_PARSE, GstMpeg4VParse))
+#define GST_MPEG4VIDEO_PARSE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),\
+                                GST_TYPE_MPEG4VIDEO_PARSE, GstMpeg4VParseClass))
+#define GST_MPEG4VIDEO_PARSE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+                                GST_TYPE_MPEG4VIDEO_PARSE, GstMpeg4VParseClass))
+#define GST_IS_MPEG4VIDEO_PARSE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
+                                GST_TYPE_MPEG4VIDEO_PARSE))
+#define GST_IS_MPEG4VIDEO_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
+                                GST_TYPE_MPEG4VIDEO_PARSE))
+
+typedef struct _GstMpeg4VParse GstMpeg4VParse;
+typedef struct _GstMpeg4VParseClass GstMpeg4VParseClass;
+
+struct _GstMpeg4VParse {
+  GstBaseParse element;
+
+  GstClockTime last_report;
+
+  /* parse state */
+  gint last_sc;
+  gint vop_offset;
+  gint vos_offset;
+  gint vo_offset;
+  gboolean intra_frame;
+  gboolean update_caps;
+
+  GstBuffer *config;
+  guint8 profile;
+  MPEG4Params params;
+
+  /* properties */
+  gboolean drop;
+  guint interval;
+};
+
+struct _GstMpeg4VParseClass {
+  GstBaseParseClass parent_class;
+};
+
+GType gst_mpeg4vparse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __MPEG4VIDEO_PARSE_H__ */
diff --git a/gst/videoparsers/mpeg4parse.c b/gst/videoparsers/mpeg4parse.c
new file mode 100644 (file)
index 0000000..5c8ce95
--- /dev/null
@@ -0,0 +1,294 @@
+/* GStreamer MPEG4-2 video Parser
+ * Copyright (C) <2008> Mindfruit B.V.
+ *   @author Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) <2007> Julien Moutte <julien@fluendo.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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "mpeg4parse.h"
+
+#include <gst/base/gstbitreader.h>
+
+GST_DEBUG_CATEGORY_EXTERN (mpeg4v_parse_debug);
+#define GST_CAT_DEFAULT mpeg4v_parse_debug
+
+
+#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 MARKER_BIT(b) G_STMT_START {  \
+  guint32 i;                          \
+  GET_BITS(b, 1, &i);                 \
+  if (i != 0x1)                       \
+    goto failed;                      \
+} G_STMT_END
+
+static inline gboolean
+next_start_code (GstBitReader * b)
+{
+  guint32 bits = 0;
+
+  GET_BITS (b, 1, &bits);
+  if (bits != 0)
+    goto failed;
+
+  while (b->bit != 0) {
+    GET_BITS (b, 1, &bits);
+    if (bits != 0x1)
+      goto failed;
+  }
+
+  return TRUE;
+
+failed:
+  return FALSE;
+}
+
+static inline gboolean
+skip_user_data (GstBitReader * bs, guint32 * bits)
+{
+  while (*bits == MPEG4_USER_DATA_STARTCODE_MARKER) {
+    guint32 b = 0;
+
+    do {
+      GET_BITS (bs, 8, &b);
+      *bits = (*bits << 8) | b;
+    } while ((*bits >> 8) != MPEG4_START_MARKER);
+  }
+
+  return TRUE;
+
+failed:
+  return FALSE;
+}
+
+
+static gint aspect_ratio_table[6][2] = {
+  {-1, -1}, {1, 1}, {12, 11}, {10, 11}, {16, 11}, {40, 33}
+};
+
+static gboolean
+gst_mpeg4_params_parse_vo (MPEG4Params * params, GstBitReader * br)
+{
+  guint32 bits;
+  guint16 time_increment_resolution = 0;
+  guint16 fixed_time_increment = 0;
+  gint aspect_ratio_width = -1, aspect_ratio_height = -1;
+  gint height = -1, width = -1;
+
+  /* expecting a video object startcode */
+  GET_BITS (br, 32, &bits);
+  if (bits > 0x11F)
+    goto failed;
+
+  /* expecting a video object layer startcode */
+  GET_BITS (br, 32, &bits);
+  if (bits < 0x120 || bits > 0x12F)
+    goto failed;
+
+  /* ignore random accessible vol  and video object type indication */
+  GET_BITS (br, 9, &bits);
+
+  GET_BITS (br, 1, &bits);
+  if (bits) {
+    /* skip video object layer verid and priority */
+    GET_BITS (br, 7, &bits);
+  }
+
+  /* aspect ratio info */
+  GET_BITS (br, 4, &bits);
+  if (bits == 0)
+    goto failed;
+
+  /* check if aspect ratio info  is extended par */
+  if (bits == 0xf) {
+    GET_BITS (br, 8, &bits);
+    aspect_ratio_width = bits;
+    GET_BITS (br, 8, &bits);
+    aspect_ratio_height = bits;
+  } else if (bits < 0x6) {
+    aspect_ratio_width = aspect_ratio_table[bits][0];
+    aspect_ratio_height = aspect_ratio_table[bits][1];
+  }
+  GST_DEBUG ("aspect ratio %d/%d", aspect_ratio_width, aspect_ratio_height);
+
+  GET_BITS (br, 1, &bits);
+  if (bits) {
+    /* vol control parameters, skip chroma and low delay */
+    GET_BITS (br, 3, &bits);
+    GET_BITS (br, 1, &bits);
+    if (bits) {
+      /* skip vbv_parameters */
+      if (!gst_bit_reader_skip (br, 79))
+        goto failed;
+    }
+  }
+
+  /* layer shape */
+  GET_BITS (br, 2, &bits);
+  /* only support rectangular */
+  if (bits != 0)
+    goto failed;
+
+  MARKER_BIT (br);
+  GET_BITS (br, 16, &bits);
+  time_increment_resolution = bits;
+  MARKER_BIT (br);
+
+  GST_DEBUG ("time increment resolution %d", time_increment_resolution);
+
+  GET_BITS (br, 1, &bits);
+  if (bits) {
+    /* fixed time increment */
+    int n;
+
+    /* Length of the time increment is the minimal number of bits needed to
+     * represent time_increment_resolution-1 */
+    for (n = 0; ((time_increment_resolution - 1) >> n) != 0; n++);
+    GET_BITS (br, n, &bits);
+
+    fixed_time_increment = bits;
+  } else {
+    /* When fixed_vop_rate is not set we can't guess any framerate */
+    fixed_time_increment = 0;
+  }
+  GST_DEBUG ("fixed time increment %d", fixed_time_increment);
+
+  /* assuming rectangular shape */
+  MARKER_BIT (br);
+  GET_BITS (br, 13, &bits);
+  width = bits;
+  MARKER_BIT (br);
+  GET_BITS (br, 13, &bits);
+  height = bits;
+  MARKER_BIT (br);
+  GST_DEBUG ("width x height: %d x %d", width, height);
+
+  /* so we got it all, report back */
+  params->width = width;
+  params->height = height;
+  params->time_increment_resolution = time_increment_resolution;
+  params->fixed_time_increment = fixed_time_increment;
+  params->aspect_ratio_width = aspect_ratio_width;
+  params->aspect_ratio_height = aspect_ratio_height;
+
+  return TRUE;
+
+  /* ERRORS */
+failed:
+  {
+    GST_WARNING ("Failed to parse config data");
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_mpeg4_params_parse_vos (MPEG4Params * params, GstBitReader * br)
+{
+  guint32 bits = 0;
+
+  GET_BITS (br, 32, &bits);
+  if (bits != MPEG4_VOS_STARTCODE_MARKER)
+    goto failed;
+
+  GET_BITS (br, 8, &bits);
+  params->profile = bits;
+
+  /* invalid profile, warn but carry on */
+  if (params->profile == 0) {
+    GST_WARNING ("Invalid profile in VOS");
+  }
+
+  /* Expect Visual Object startcode */
+  GET_BITS (br, 32, &bits);
+
+  /* but skip optional user data */
+  if (!skip_user_data (br, &bits))
+    goto failed;
+
+  if (bits != MPEG4_VISUAL_OBJECT_STARTCODE_MARKER)
+    goto failed;
+
+  GET_BITS (br, 1, &bits);
+  if (bits == 0x1) {
+    /* Skip visual_object_verid and priority */
+    GET_BITS (br, 7, &bits);
+  }
+
+  GET_BITS (br, 4, &bits);
+  /* Only support video ID */
+  if (bits != 0x1)
+    goto failed;
+
+  /* video signal type */
+  GET_BITS (br, 1, &bits);
+
+  if (bits == 0x1) {
+    /* video signal type, ignore format and range */
+    GET_BITS (br, 4, &bits);
+
+    GET_BITS (br, 1, &bits);
+    if (bits == 0x1) {
+      /* ignore color description */
+      GET_BITS (br, 24, &bits);
+    }
+  }
+
+  if (!next_start_code (br))
+    goto failed;
+
+  /* skip optional user data */
+  GET_BITS (br, 32, &bits);
+  if (!skip_user_data (br, &bits))
+    goto failed;
+
+  /* rewind to start code */
+  gst_bit_reader_set_pos (br, gst_bit_reader_get_pos (br) - 32);
+
+  return gst_mpeg4_params_parse_vo (params, br);
+
+  /* ERRORS */
+failed:
+  {
+    GST_WARNING ("Failed to parse config data");
+    return FALSE;
+  }
+}
+
+gboolean
+gst_mpeg4_params_parse_config (MPEG4Params * params, const guint8 * data,
+    guint size)
+{
+  GstBitReader br;
+
+  if (size < 4)
+    return FALSE;
+
+  gst_bit_reader_init (&br, data, size);
+
+  if (data[3] == MPEG4_VOS_STARTCODE)
+    return gst_mpeg4_params_parse_vos (params, &br);
+  else
+    return gst_mpeg4_params_parse_vo (params, &br);
+}
diff --git a/gst/videoparsers/mpeg4parse.h b/gst/videoparsers/mpeg4parse.h
new file mode 100644 (file)
index 0000000..cf79e88
--- /dev/null
@@ -0,0 +1,63 @@
+/* GStreamer MPEG4-2 video Parser
+ * Copyright (C) <2008> Mindfruit B.V.
+ *   @author Sjoerd Simons <sjoerd@luon.net>
+ * Copyright (C) <2007> Julien Moutte <julien@fluendo.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_MPEG4_PARAMS_H__
+#define __GST_MPEG4_PARAMS_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define MPEG4_VIDEO_OBJECT_STARTCODE_MIN      0x00
+#define MPEG4_VIDEO_OBJECT_STARTCODE_MAX      0x1F
+#define MPEG4_VOS_STARTCODE                   0xB0
+#define MPEG4_VOS_ENDCODE                     0xB1
+#define MPEG4_USER_DATA_STARTCODE             0xB2
+#define MPEG4_GOP_STARTCODE                   0xB3
+#define MPEG4_VISUAL_OBJECT_STARTCODE         0xB5
+#define MPEG4_VOP_STARTCODE                   0xB6
+
+#define MPEG4_START_MARKER                    0x000001
+#define MPEG4_VISUAL_OBJECT_STARTCODE_MARKER  \
+  ((MPEG4_START_MARKER << 8) + MPEG4_VISUAL_OBJECT_STARTCODE)
+#define MPEG4_VOS_STARTCODE_MARKER            \
+  ((MPEG4_START_MARKER << 8) + MPEG4_VOS_STARTCODE)
+#define MPEG4_USER_DATA_STARTCODE_MARKER      \
+  ((MPEG4_START_MARKER << 8) + MPEG4_USER_DATA_STARTCODE)
+
+
+typedef struct _MPEG4Params MPEG4Params;
+
+struct _MPEG4Params
+{
+  gint  profile;
+
+  gint  width, height;
+  gint  aspect_ratio_width, aspect_ratio_height;
+  gint  time_increment_resolution;
+  gint  fixed_time_increment;
+};
+
+GstFlowReturn gst_mpeg4_params_parse_config (MPEG4Params * params,
+                                            const guint8 * data, guint size);
+
+G_END_DECLS
+#endif
index 3f2f73a2fffb564ccb23c7e6ac50b2741470eb77..111bb1a87c91f7c6403cb1d37f4239007c9ce380 100644 (file)
@@ -26,6 +26,7 @@
 #include "gsth264parse.h"
 #include "gstdiracparse.h"
 #include "gstmpegvideoparse.h"
+#include "gstmpeg4videoparse.h"
 
 static gboolean
 plugin_init (GstPlugin * plugin)
@@ -40,6 +41,8 @@ plugin_init (GstPlugin * plugin)
       GST_RANK_NONE, GST_TYPE_DIRAC_PARSE);
   ret |= gst_element_register (plugin, "mpegvideoparse",
       GST_RANK_PRIMARY + 1, GST_TYPE_MPEGVIDEO_PARSE);
+  ret |= gst_element_register (plugin, "mpeg4videoparse",
+      GST_RANK_PRIMARY + 1, GST_TYPE_MPEG4VIDEO_PARSE);
 
   return ret;
 }