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)
gst/mpegtsmux/Makefile
gst/mpegtsmux/tsmux/Makefile
gst/mpegpsmux/Makefile
-gst/mpeg4videoparse/Makefile
gst/mpegvideoparse/Makefile
gst/mve/Makefile
gst/mxf/Makefile
+++ /dev/null
-
-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' \
- > $@
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-/* 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
+++ /dev/null
-/* 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)
+++ /dev/null
-/* 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__ */
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) \
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 \
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
#include "gsth264parse.h"
#include "gstdiracparse.h"
#include "gstmpegvideoparse.h"
+#include "gstmpeg4videoparse.h"
static gboolean
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;
}