Commit 73ce8c5b authored by Michael Smith's avatar Michael Smith
Browse files

Add Annodex elements from Alessendro Decina: skeleton and CMML.

Original commit message from CVS:
* configure.ac:
* docs/plugins/gst-plugins-good-plugins-sections.txt:
* ext/Makefile.am:
* ext/annodex/Makefile.am:
* ext/annodex/gstannodex.c:
* ext/annodex/gstannodex.h:
* ext/annodex/gstcmmldec.c:
* ext/annodex/gstcmmldec.h:
* ext/annodex/gstcmmlenc.c:
* ext/annodex/gstcmmlenc.h:
* ext/annodex/gstcmmlparser.c:
* ext/annodex/gstcmmlparser.h:
* ext/annodex/gstcmmltag.c:
* ext/annodex/gstcmmltag.h:
* ext/annodex/gstcmmlutils.c:
* ext/annodex/gstcmmlutils.h:
* ext/annodex/gstskeldec.c:
* ext/annodex/gstskeldec.h:
* ext/annodex/gstskeltag.c:
* ext/annodex/gstskeltag.h:
* tests/check/Makefile.am:
* tests/check/elements/cmmldec.c:
* tests/check/elements/cmmlenc.c:
* tests/check/elements/skeldec.c:
Add Annodex elements from Alessendro Decina: skeleton and CMML.
Includes tests & docs, oh my! Passes Thomas's -good checklist
entirely. Wow.
parent dd8f37fa
2006-02-24 Michael Smith <msmith@fluendo.com>
* configure.ac:
* docs/plugins/gst-plugins-good-plugins-sections.txt:
* ext/Makefile.am:
* ext/annodex/Makefile.am:
* ext/annodex/gstannodex.c:
* ext/annodex/gstannodex.h:
* ext/annodex/gstcmmldec.c:
* ext/annodex/gstcmmldec.h:
* ext/annodex/gstcmmlenc.c:
* ext/annodex/gstcmmlenc.h:
* ext/annodex/gstcmmlparser.c:
* ext/annodex/gstcmmlparser.h:
* ext/annodex/gstcmmltag.c:
* ext/annodex/gstcmmltag.h:
* ext/annodex/gstcmmlutils.c:
* ext/annodex/gstcmmlutils.h:
* ext/annodex/gstskeldec.c:
* ext/annodex/gstskeldec.h:
* ext/annodex/gstskeltag.c:
* ext/annodex/gstskeltag.h:
* tests/check/Makefile.am:
* tests/check/elements/cmmldec.c:
* tests/check/elements/cmmlenc.c:
* tests/check/elements/skeldec.c:
Add Annodex elements from Alessendro Decina: skeleton and CMML.
Includes tests & docs, oh my! Passes Thomas's -good checklist
entirely. Wow.
2006-02-24 Michael Smith <msmith@fluendo.com>
* autogen.sh:
......
......@@ -133,6 +133,8 @@ dnl common/m4/gst-arch.m4
dnl check CPU type
GST_ARCH
AC_SUBST(GST_CTRL_LIBS)
dnl Determine endianness
AC_C_BIGENDIAN
......@@ -326,6 +328,18 @@ GST_CHECK_FEATURE(AALIB, [aasink plug-in], aasink, [
AS_SCRUB_INCLUDE(AALIB_CFLAGS)
])
dnl *** annodex ***
translit(dnm, m, l) AM_CONDITIONAL(USE_ANNODEX, true)
GST_CHECK_FEATURE(ANNODEX, [annodex plug-in], skeldec cmmlenc cmmldec, [
PKG_CHECK_MODULES(XML, libxml-2.0 >= 2.4.9, [
HAVE_ANNODEX=yes
AC_SUBST(XML_CFLAGS)
AC_SUBST(XML_LIBS)
], [
HAVE_ANNODEX=no
])
])
dnl *** cairo ***
translit(dnm, m, l) AM_CONDITIONAL(USE_CAIRO, true)
GST_CHECK_FEATURE(CAIRO, [cairo plug-in], cairo, [
......@@ -618,6 +632,7 @@ gst/flx/Makefile
ext/jpeg/Makefile
ext/Makefile
ext/aalib/Makefile
ext/annodex/Makefile
ext/cairo/Makefile
ext/cdio/Makefile
ext/dv/Makefile
......
......@@ -30,6 +30,14 @@ GstCairoTimeOverlay
GstCairoTimeOverlayClass
</SECTION>
<SECTION>
<FILE>element-cmmldec</FILE>
GstCmmlDec
<TITLE>cmmldec</TITLE>
<SUBSECTION Standard>
GstCmmlDecClass
</SECTION>
<SECTION>
<FILE>element-cdiocddasrc</FILE>
GstCdioCddaSrc
......
......@@ -4,6 +4,12 @@ else
AALIB_DIR =
endif
if USE_ANNODEX
ANNODEX_DIR = annodex
else
ANNODEX_DIR =
endif
if USE_CAIRO
CAIRO_DIR = cairo
else
......@@ -108,6 +114,7 @@ endif
SUBDIRS = \
$(AALIB_DIR) \
$(ANNODEX_DIR) \
$(CAIRO_DIR) \
$(CDIO_DIR) \
$(DV1394_DIR) \
......
# plugindir is set in configure
# change libgstplugin.la to something more suitable
plugin_LTLIBRARIES = libgstannodex.la
# for the next set of variables, rename the prefix if you renamed the .la
# sources used to compile this plug-in
libgstannodex_la_SOURCES = \
gstannodex.c \
gstcmmlutils.c \
gstcmmldec.c \
gstcmmlenc.c \
gstcmmltag.c \
gstcmmlparser.c \
gstskeldec.c \
gstskeltag.c
# flags used to compile this plugin
# we use the GST_LIBS flags because we might be using plug-in libs
libgstannodex_la_CFLAGS = $(GST_CFLAGS) $(XML_CFLAGS)
libgstannodex_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(XML_LIBS)
libgstannodex_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
# headers we need but don't want installed
noinst_HEADERS = gstannodex.h gstcmmlutils.h gstcmmltag.h gstcmmlparser.h \
gstcmmldec.h gstskeldec.h gstcmmlenc.h
/*
* gstannodex.c - GStreamer annodex plugin
* Copyright (C) 2005 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
*
* 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 "gstcmmlenc.h"
#include "gstcmmldec.h"
#include "gstskeldec.h"
GstClockTime
gst_annodex_granule_to_time (gint64 granulepos, gint64 granulerate_n,
gint64 granulerate_d, guint8 granuleshift)
{
gint64 keyindex, keyoffset;
gint64 granulerate;
GstClockTime res;
if (granulepos == -1)
return GST_CLOCK_TIME_NONE;
if (granulepos == 0 || granulerate_n == 0 || granulerate_d == 0)
return 0;
if (granuleshift != 0) {
keyindex = granulepos >> granuleshift;
keyoffset = granulepos - (keyindex << granuleshift);
granulepos = keyindex + keyoffset;
}
/* GST_SECOND / granulerate_n / granulerate_d */
granulerate = gst_util_uint64_scale (GST_SECOND,
granulerate_n, granulerate_d);
/* granulepos * granulerate */
res = gst_util_uint64_scale (granulepos, granulerate, 1);
return res;
}
GValueArray *
gst_annodex_parse_headers (const gchar * headers)
{
GValueArray *array;
GValue val = { 0 };
gchar *header_name = NULL;
gchar *header_value = NULL;
gchar *line, *column, *space, *tmp;
gchar **lines;
gint i = 0;
array = g_value_array_new (0);
g_value_init (&val, G_TYPE_STRING);
lines = g_strsplit (headers, "\r\n", 0);
line = lines[i];
while (line != NULL && *line != '\0') {
if (line[0] == '\t' || line[0] == ' ') {
/* WSP: continuation line */
if (header_value == NULL)
/* continuation line without a previous value */
goto fail;
tmp = g_strjoin (" ", header_value, g_strstrip (line), NULL);
g_free (header_value);
header_value = tmp;
} else {
if (header_name) {
g_value_take_string (&val, header_name);
g_value_array_append (array, &val);
g_value_take_string (&val, header_value);
g_value_array_append (array, &val);
}
/* search the column starting from line[1] as an header name can't be
* empty */
column = g_strstr_len (line + 1, strlen (line) - 1, ":");
if (column == NULL)
/* bad syntax */
goto fail;
if (*(space = column + 1) != ' ')
/* bad syntax */
goto fail;
header_name = g_strndup (line, column - line);
header_value = g_strdup (space + 1);
}
line = lines[++i];
}
if (header_name) {
g_value_take_string (&val, header_name);
g_value_array_append (array, &val);
g_value_take_string (&val, header_value);
g_value_array_append (array, &val);
}
g_value_unset (&val);
g_strfreev (lines);
return array;
fail:
GST_WARNING ("could not parse annodex headers");
g_free (header_name);
g_free (header_value);
g_strfreev (lines);
g_value_array_free (array);
g_value_unset (&val);
return NULL;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
gst_tag_register (GST_TAG_CMML_STREAM, GST_TAG_FLAG_META,
GST_TYPE_CMML_TAG_STREAM, "cmml-stream", "annodex CMML stream tag", NULL);
gst_tag_register (GST_TAG_CMML_HEAD, GST_TAG_FLAG_META,
GST_TYPE_CMML_TAG_HEAD, "cmml-head", "annodex CMML head tag", NULL);
gst_tag_register (GST_TAG_CMML_CLIP, GST_TAG_FLAG_META,
GST_TYPE_CMML_TAG_CLIP, "cmml-clip", "annodex CMML clip tag", NULL);
if (!gst_cmml_enc_plugin_init (plugin))
return FALSE;
if (!gst_cmml_dec_plugin_init (plugin))
return FALSE;
if (!gst_skel_dec_plugin_init (plugin))
return FALSE;
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"annodex",
"annodex stream manipulation (info about annodex: http://www.annodex.net)",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
/*
* gstannodex.h - GStreamer annodex utility functions
* Copyright (C) 2005 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
*
* 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_ANNODEX_H__
#define __GST_ANNODEX_H__
#include <gst/gst.h>
GstClockTime gst_annodex_granule_to_time (gint64 granulepos,
gint64 granulerate_n, gint64 granulerate_d, guint8 granuleshift);
gchar *gst_annodex_time_to_npt (GstClockTime time);
GValueArray *gst_annodex_parse_headers (const gchar * headers);
#endif /* __GST_ANNODEX_H__ */
This diff is collapsed.
/*
* gstcmmldec.h - GStreamer annodex CMML decoder
* Copyright (C) 2005 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
*
* 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_CMML_DEC_H__
#define __GST_CMML_DEC_H__
#include <gst/gst.h>
#include <gst/gstformat.h>
#include <gst/controller/gstcontroller.h>
#include "gstcmmlparser.h"
/* GstCmmlDec */
#define GST_TYPE_CMML_DEC (gst_cmml_dec_get_type())
#define GST_CMML_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_CMML_DEC, GstCmmlDec))
#define GST_CMML_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_CMML_DEC, GstCmmlDec))
#define GST_IS_CMML_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_CMML_DEC))
#define GST_IS_CMML_DEC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_CMML_DEC))
#define GST_CMML_DEC_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_CMML_DEC, GstCmmlDecClass))
typedef struct _GstCmmlDec GstCmmlDec;
typedef struct _GstCmmlDecClass GstCmmlDecClass;
typedef enum _GstCmmlPacketType GstCmmlPacketType;
enum _GstCmmlPacketType
{
GST_CMML_PACKET_UNKNOWN,
GST_CMML_PACKET_IDENT_HEADER,
GST_CMML_PACKET_FIRST_HEADER,
GST_CMML_PACKET_SECOND_HEADER,
GST_CMML_PACKET_CLIP
};
struct _GstCmmlDec
{
GstElement element;
/* element part */
GstPad *sinkpad;
GstPad *srcpad;
/* bitstream part */
gint16 major; /* bitstream version major */
gint16 minor; /* bitstream version minor */
gint64 granulerate_n; /* bitrstream granulerate numerator */
gint64 granulerate_d; /* bitstream granulerate denominator */
gint8 granuleshift; /* bitstreamgranuleshift */
gint64 granulepos; /* bitstream granule position */
GstClockTime timestamp; /* timestamp of the last buffer */
/* decoder part */
GstCmmlParser *parser; /* cmml parser */
gboolean sent_root;
GstFlowReturn flow_return; /* _chain return value */
gboolean wait_clip_end; /* when TRUE, the GST_TAG_MESSAGE for a
* clip is sent when the next clip (or EOS)
* is found, so that the clip end-time is
* known. This is useful for pre-extracting
* the clips.
*/
GHashTable *tracks;
};
struct _GstCmmlDecClass
{
GstElementClass parent_class;
};
gboolean gst_cmml_dec_plugin_init (GstPlugin * plugin);
#endif /* __GST_CMML_DEC_H__ */
/*
* gstcmmlenc.c - GStreamer CMML encoder
* Copyright (C) 2005 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:element-cmmlenc
* @see_also: cmmldec, oggmux
*
* <refsect2>
* <para> Cmmlenc encodes a CMML document into a CMML stream. <ulink
* url="http://www.annodex.net/TR/draft-pfeiffer-cmml-02.html">CMML</ulink> is
* an XML markup language for time-continuous data maintained by the <ulink
* url="http:/www.annodex.org/">Annodex Foundation</ulink>.
* </para>
* <title>Example pipeline</title>
* <programlisting>
* gst-launch -v filesrc location=annotations.cmml ! cmmlenc ! oggmux name=mux ! filesink location=annotated.ogg
* </programlisting>
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "gstcmmlenc.h"
#include "gstannodex.h"
GST_DEBUG_CATEGORY (cmmlenc);
#define GST_CAT_DEFAULT cmmlenc
#define CMML_IDENT_HEADER_SIZE 29
enum
{
ARG_0,
GST_CMML_ENC_GRANULERATE_N,
GST_CMML_ENC_GRANULERATE_D,
GST_CMML_ENC_GRANULESHIFT
};
enum
{
LAST_SIGNAL
};
static GstElementDetails gst_cmml_enc_details = {
"cmmlenc: Encodes CMML streams", "Codec/Encoder",
"Encodes CMML streams",
"Alessandro Decina <alessandro@nnva.org>",
};
static GstStaticPadTemplate gst_cmml_enc_src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("text/x-cmml")
);
static GstStaticPadTemplate gst_cmml_enc_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("text/xml")
);
GST_BOILERPLATE (GstCmmlEnc, gst_cmml_enc, GstElement, GST_TYPE_ELEMENT);
static void gst_cmml_enc_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec);
static void gst_cmml_enc_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec);
static gboolean gst_cmml_enc_sink_event (GstPad * pad, GstEvent * event);
static GstStateChangeReturn gst_cmml_enc_change_state (GstElement * element,
GstStateChange transition);
static GstFlowReturn gst_cmml_enc_chain (GstPad * pad, GstBuffer * buffer);
static void gst_cmml_enc_parse_preamble (GstCmmlEnc * enc,
guchar * preamble, guchar * processing_instruction);
static void gst_cmml_enc_parse_end_tag (GstCmmlEnc * enc);
static void gst_cmml_enc_parse_tag_head (GstCmmlEnc * enc,
GstCmmlTagHead * head);
static void gst_cmml_enc_parse_tag_clip (GstCmmlEnc * enc,
GstCmmlTagClip * tag);
static GstFlowReturn gst_cmml_enc_new_buffer (GstCmmlEnc * enc,
guchar * data, gint size, GstBuffer ** buffer);
#if 0
static void gst_cmml_enc_flush_clips (GstCmmlEnc * enc);
#endif
static GstFlowReturn gst_cmml_enc_push_clip (GstCmmlEnc * enc,
GstCmmlTagClip * clip, GstClockTime prev_clip_time);
static GstFlowReturn gst_cmml_enc_push (GstCmmlEnc * enc, GstBuffer * buffer);
static void
gst_cmml_enc_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_cmml_enc_sink_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_cmml_enc_src_factory));
gst_element_class_set_details (element_class, &gst_cmml_enc_details);
}
static void
gst_cmml_enc_class_init (GstCmmlEncClass * enc_class)
{
GObjectClass *klass = G_OBJECT_CLASS (enc_class);
klass->get_property = gst_cmml_enc_get_property;
klass->set_property = gst_cmml_enc_set_property;
g_object_class_install_property (klass, GST_CMML_ENC_GRANULERATE_N,
g_param_spec_int64 ("granule-rate-numerator",
"Granulerate numerator",
"Granulerate numerator",
0, G_MAXINT64, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (klass, GST_CMML_ENC_GRANULERATE_D,
g_param_spec_int64 ("granule-rate-denominator",
"Granulerate denominator",
"Granulerate denominator",
0, G_MAXINT64, 1000, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (klass, GST_CMML_ENC_GRANULESHIFT,
g_param_spec_uchar ("granule-shift",
"Granuleshift",
"The number of lower bits to use for partitioning a granule position",
0, G_MAXUINT8, 32, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
GST_ELEMENT_CLASS (klass)->change_state = gst_cmml_enc_change_state;
}
static void
gst_cmml_enc_init (GstCmmlEnc * enc, GstCmmlEncClass * klass)
{
enc->sinkpad =
gst_pad_new_from_static_template (&gst_cmml_enc_sink_factory, "sink");
gst_pad_set_chain_function (enc->sinkpad, gst_cmml_enc_chain);
gst_pad_set_event_function (enc->sinkpad, gst_cmml_enc_sink_event);
gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
enc->srcpad =
gst_pad_new_from_static_template (&gst_cmml_enc_src_factory, "src");
gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
enc->major = 3;
enc->minor = 0;
}
static void
gst_cmml_enc_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
GstCmmlEnc *enc = GST_CMML_ENC (object);
switch (property_id) {
case GST_CMML_ENC_GRANULERATE_N:
/* XXX: may need to flush clips */
enc->granulerate_n = g_value_get_int64 (value);
break;
case GST_CMML_ENC_GRANULERATE_D:
enc->granulerate_d = g_value_get_int64 (value);
break;
case GST_CMML_ENC_GRANULESHIFT:
enc->granuleshift = g_value_get_uchar (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
gst_cmml_enc_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
GstCmmlEnc *enc = GST_CMML_ENC (object);