mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-04 21:42:25 +00:00
tagging stuff and build fixes. In detail:
Original commit message from CVS: tagging stuff and build fixes. In detail: - make gdk-pixbuf loader work when distchecking - fix invalid syntax in ffmpeg Makefile. wildcards for EXTRA_DIST are not allowed. This broke builds where distdir != srcdir - fix ffmpeg cvs grabbing when srcdir != distdir - new id3tag plugin for id3 tag reading/writing (uses mad's libid3tag) - mad and libid3tag require mad/libid3tag v0.15. Fixed configure to require that - added ogg demuxer in ext/ogg. The demuxer does not handle events yet. Especially getting seeking right will require some effort or code copying from libvorbis. - added raw vorbis detection to typefinding. oggdemux requires a typefind function to detect its contents. - tags plugin in gst/tags. Provides API in <gst/tags/gsttagediting.h>. API includes tag matching GStreamer <=> ID3 and GStreamer <=> vorbis and writing/reading vorbiscomments or ID3v1 tags. Also included is a simple vorbiscomment reader/writer. Writing will not really work though until someone writes oggmux. - various build fixes. Mostly missing (DIST)CLEANFILES. - vorbisenc handles tag writing. Now it's YOUR turn to fix and write more plugins that handle writing/reading of tags. :)
This commit is contained in:
parent
695f8923b3
commit
788acc4917
21 changed files with 2048 additions and 131 deletions
24
configure.ac
24
configure.ac
|
@ -12,7 +12,7 @@ AM_MAINTAINER_MODE
|
||||||
|
|
||||||
dnl when going to/from release please set the nano (fourth number) right !
|
dnl when going to/from release please set the nano (fourth number) right !
|
||||||
dnl releases only do Wall, cvs and prerelease does Werror too
|
dnl releases only do Wall, cvs and prerelease does Werror too
|
||||||
AS_VERSION(gst-plugins, GST_PLUGINS_VERSION, 0, 7, 1, 1, GST_CVS="no", GST_CVS="yes")
|
AS_VERSION(gst-plugins, GST_PLUGINS_VERSION, 0, 7, 2, 1, GST_CVS="no", GST_CVS="yes")
|
||||||
|
|
||||||
dnl add a suffix to apps
|
dnl add a suffix to apps
|
||||||
if test x$program_suffix = xNONE ; then
|
if test x$program_suffix = xNONE ; then
|
||||||
|
@ -189,7 +189,6 @@ fi
|
||||||
|
|
||||||
AC_SUBST(GST_CONTROL_LIBS)
|
AC_SUBST(GST_CONTROL_LIBS)
|
||||||
|
|
||||||
|
|
||||||
dnl Set up conditionals for (target) architecture:
|
dnl Set up conditionals for (target) architecture:
|
||||||
dnl ==============================================
|
dnl ==============================================
|
||||||
|
|
||||||
|
@ -241,6 +240,8 @@ if test "x$HAVE_GTK_22" = "xyes"; then
|
||||||
AC_SUBST(GTK_VERSION)
|
AC_SUBST(GTK_VERSION)
|
||||||
GTK_PREFIX=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`
|
GTK_PREFIX=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`
|
||||||
GTK_SYSCONFDIR=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`
|
GTK_SYSCONFDIR=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`
|
||||||
|
GDK_PIXBUF_LIBDIR=`$PKG_CONFIG --variable=libdir gdk-pixbuf-2.0`
|
||||||
|
GDK_PIXBUF_PREFIXDIR=`$PKG_CONFIG --variable=prefix gdk-pixbuf-2.0`
|
||||||
AC_SUBST(GTK_BASE_DIR)
|
AC_SUBST(GTK_BASE_DIR)
|
||||||
else
|
else
|
||||||
PKG_CHECK_MODULES(GTK2, gtk+-2.0, HAVE_GTK_20=yes, HAVE_GTK_20=no)
|
PKG_CHECK_MODULES(GTK2, gtk+-2.0, HAVE_GTK_20=yes, HAVE_GTK_20=no)
|
||||||
|
@ -255,7 +256,7 @@ AC_SUBST(GTK_CFLAGS)
|
||||||
AC_SUBST(HAVE_GTK)
|
AC_SUBST(HAVE_GTK)
|
||||||
AM_CONDITIONAL(HAVE_GDK_LOADERS, test "x$HAVE_GTK_22" = "xyes")
|
AM_CONDITIONAL(HAVE_GDK_LOADERS, test "x$HAVE_GTK_22" = "xyes")
|
||||||
|
|
||||||
GDK_PIXBUF_LOADER_DIR="\$(libdir)/gtk-2.0/\$(GTK_VERSION)/\loaders"
|
GDK_PIXBUF_LOADER_DIR="$GDK_PIXBUF_LIBDIR/gtk-2.0/\$(GTK_VERSION)/loaders"
|
||||||
AC_ARG_WITH(gdk-pixbuf-loader-dir,
|
AC_ARG_WITH(gdk-pixbuf-loader-dir,
|
||||||
AC_HELP_STRING([--with-gdk-pixbuf-loader-dir],
|
AC_HELP_STRING([--with-gdk-pixbuf-loader-dir],
|
||||||
[directory to install the gdk_pixbuf loader]),
|
[directory to install the gdk_pixbuf loader]),
|
||||||
|
@ -265,7 +266,7 @@ AC_ARG_WITH(gdk-pixbuf-loader-dir,
|
||||||
])
|
])
|
||||||
AC_SUBST(GDK_PIXBUF_LOADER_DIR)
|
AC_SUBST(GDK_PIXBUF_LOADER_DIR)
|
||||||
|
|
||||||
GDK_PIXBUF_CONFFILE="\$(sysconfdir)/gtk-2.0/gdk-pixbuf.loaders"
|
GDK_PIXBUF_CONFFILE="$GDK_PIXBUF_PREFIXDIR/gtk-2.0/gdk-pixbuf.loaders"
|
||||||
AC_ARG_WITH(gdk-pixbuf-conffile,
|
AC_ARG_WITH(gdk-pixbuf-conffile,
|
||||||
AC_HELP_STRING([--with-gdk-pixbuf-conffile],
|
AC_HELP_STRING([--with-gdk-pixbuf-conffile],
|
||||||
[path to the gdk_pixbuf config file]),
|
[path to the gdk_pixbuf config file]),
|
||||||
|
@ -334,6 +335,7 @@ GST_PLUGINS_ALL="\
|
||||||
speed \
|
speed \
|
||||||
stereo \
|
stereo \
|
||||||
synaesthesia \
|
synaesthesia \
|
||||||
|
tags \
|
||||||
tcp \
|
tcp \
|
||||||
typefind \
|
typefind \
|
||||||
udp \
|
udp \
|
||||||
|
@ -970,16 +972,15 @@ dnl FIXME: we could use header checks here as well IMO
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_MAD, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_MAD, true)
|
||||||
GST_CHECK_FEATURE(MAD, [mad mp3 decoder], mad, [
|
GST_CHECK_FEATURE(MAD, [mad mp3 decoder], mad, [
|
||||||
dnl check with pkg-config first
|
dnl check with pkg-config first
|
||||||
PKG_CHECK_MODULES(MAD, mad id3tag, HAVE_MAD="yes", HAVE_MAD="no")
|
PKG_CHECK_MODULES(MAD, mad >= 0.15 id3tag >= 0.15, HAVE_MAD="yes", HAVE_MAD="no")
|
||||||
if test "x$HAVE_MAD" = "xno"; then
|
if test "x$HAVE_MAD" = "xno"; then
|
||||||
dnl fall back to oldskool detection
|
dnl fall back to oldskool detection
|
||||||
AC_CHECK_LIB(mad, mad_decoder_finish, HAVE_MAD="yes" MAD_LIBS="-lmad")
|
AC_CHECK_LIB(mad, mad_decoder_finish, HAVE_MAD="yes" MAD_LIBS="-lmad")
|
||||||
if test "x$HAVE_MAD" = "xyes"; then
|
if test "x$HAVE_MAD" = "xyes"; then
|
||||||
# installed with mad >= 0.14
|
|
||||||
HAVE_MAD="no"
|
HAVE_MAD="no"
|
||||||
save_libs=$LIBS
|
save_libs=$LIBS
|
||||||
LIBS="-lz"
|
LIBS="-lz"
|
||||||
AC_CHECK_LIB(id3tag, id3_tag_query, HAVE_MAD="yes" MAD_LIBS="$MAD_LIBS -lid3tag")
|
AC_CHECK_LIB(id3tag, id3_tag_options, HAVE_MAD="yes" MAD_LIBS="-lmad -lid3tag -lz")
|
||||||
LIBS=$save_LIBS
|
LIBS=$save_LIBS
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -1096,6 +1097,13 @@ GST_CHECK_FEATURE(TARKIN, [tarkinenc tarkindec], tarkin, [
|
||||||
HAVE_TARKIN="yes"
|
HAVE_TARKIN="yes"
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl *** ogg ***
|
||||||
|
translit(dnm, m, l) AM_CONDITIONAL(USE_OGG, true)
|
||||||
|
GST_CHECK_FEATURE(OGG, [ogg de/encoder], oggdemux oggmux, [
|
||||||
|
XIPH_PATH_OGG(HAVE_OGG=yes, HAVE_OGG=no)
|
||||||
|
AS_SCRUB_INCLUDE(OGG_CFLAGS)
|
||||||
|
])
|
||||||
|
|
||||||
dnl *** vorbis ***
|
dnl *** vorbis ***
|
||||||
dnl AM_PATH_VORBIS only takes two options
|
dnl AM_PATH_VORBIS only takes two options
|
||||||
translit(dnm, m, l) AM_CONDITIONAL(USE_VORBIS, true)
|
translit(dnm, m, l) AM_CONDITIONAL(USE_VORBIS, true)
|
||||||
|
@ -1365,6 +1373,7 @@ gst/spectrum/Makefile
|
||||||
gst/speed/Makefile
|
gst/speed/Makefile
|
||||||
gst/stereo/Makefile
|
gst/stereo/Makefile
|
||||||
gst/synaesthesia/Makefile
|
gst/synaesthesia/Makefile
|
||||||
|
gst/tags/Makefile
|
||||||
gst/tcp/Makefile
|
gst/tcp/Makefile
|
||||||
gst/typefind/Makefile
|
gst/typefind/Makefile
|
||||||
gst/udp/Makefile
|
gst/udp/Makefile
|
||||||
|
@ -1427,6 +1436,7 @@ ext/mas/Makefile
|
||||||
ext/mikmod/Makefile
|
ext/mikmod/Makefile
|
||||||
ext/mpeg2dec/Makefile
|
ext/mpeg2dec/Makefile
|
||||||
ext/mplex/Makefile
|
ext/mplex/Makefile
|
||||||
|
ext/ogg/Makefile
|
||||||
ext/pango/Makefile
|
ext/pango/Makefile
|
||||||
ext/raw1394/Makefile
|
ext/raw1394/Makefile
|
||||||
ext/sdl/Makefile
|
ext/sdl/Makefile
|
||||||
|
|
|
@ -196,6 +196,12 @@ else
|
||||||
MPLEX_DIR=
|
MPLEX_DIR=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if USE_OGG
|
||||||
|
OGG_DIR=ogg
|
||||||
|
else
|
||||||
|
OGG_DIR=
|
||||||
|
endif
|
||||||
|
|
||||||
if USE_PANGO
|
if USE_PANGO
|
||||||
PANGO_DIR=pango
|
PANGO_DIR=pango
|
||||||
else
|
else
|
||||||
|
@ -313,6 +319,7 @@ SUBDIRS=\
|
||||||
$(MIKMOD_DIR) \
|
$(MIKMOD_DIR) \
|
||||||
$(MPEG2DEC_DIR) \
|
$(MPEG2DEC_DIR) \
|
||||||
$(MPLEX_DIR) \
|
$(MPLEX_DIR) \
|
||||||
|
$(OGG_DIR) \
|
||||||
$(PANGO_DIR) \
|
$(PANGO_DIR) \
|
||||||
$(RAW1394_DIR) \
|
$(RAW1394_DIR) \
|
||||||
$(SDL_DIR) \
|
$(SDL_DIR) \
|
||||||
|
@ -361,6 +368,7 @@ DIST_SUBDIRS=\
|
||||||
mikmod \
|
mikmod \
|
||||||
mpeg2dec \
|
mpeg2dec \
|
||||||
mplex \
|
mplex \
|
||||||
|
ogg \
|
||||||
pango \
|
pango \
|
||||||
raw1394 \
|
raw1394 \
|
||||||
sdl \
|
sdl \
|
||||||
|
|
9
ext/ogg/Makefile.am
Normal file
9
ext/ogg/Makefile.am
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
||||||
|
|
||||||
|
plugin_LTLIBRARIES = libgstogg.la
|
||||||
|
|
||||||
|
libgstogg_la_SOURCES = gstoggdemux.c
|
||||||
|
libgstogg_la_CFLAGS = $(GST_CFLAGS) $(OGG_CFLAGS)
|
||||||
|
libgstogg_la_LIBADD = $(OGG_LIBS)
|
||||||
|
libgstogg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
587
ext/ogg/gstoggdemux.c
Normal file
587
ext/ogg/gstoggdemux.c
Normal file
|
@ -0,0 +1,587 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gstid3tagsetter.c: plugin for reading / modifying id3 tags
|
||||||
|
*
|
||||||
|
* 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 <gst/gst.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
/* memcpy - if someone knows a way to get rid of it, please speak up */
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (gst_ogg_demux_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_ogg_demux_debug
|
||||||
|
|
||||||
|
#define GST_TYPE_OGG_DEMUX (gst_ogg_demux_get_type())
|
||||||
|
#define GST_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_DEMUX, GstOggDemux))
|
||||||
|
#define GST_OGG_DEMUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_DEMUX, GstOggDemux))
|
||||||
|
#define GST_IS_OGG_DEMUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_DEMUX))
|
||||||
|
#define GST_IS_OGG_DEMUX_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_DEMUX))
|
||||||
|
|
||||||
|
typedef struct _GstOggDemux GstOggDemux;
|
||||||
|
typedef struct _GstOggDemuxClass GstOggDemuxClass;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GstPad * pad; /* reference for this pad is held by element we belong to */
|
||||||
|
|
||||||
|
int serial;
|
||||||
|
ogg_stream_state stream;
|
||||||
|
guint64 offset; /* end offset of last buffer */
|
||||||
|
} GstOggPad;
|
||||||
|
|
||||||
|
struct _GstOggDemux {
|
||||||
|
GstElement element;
|
||||||
|
|
||||||
|
/* pads */
|
||||||
|
GstPad * sinkpad;
|
||||||
|
GSList * srcpads; /* list of GstOggPad */
|
||||||
|
|
||||||
|
/* ogg stuff */
|
||||||
|
ogg_sync_state sync;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstOggDemuxClass {
|
||||||
|
GstElementClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* elementfactory information */
|
||||||
|
static GstElementDetails gst_ogg_demux_details = GST_ELEMENT_DETAILS (
|
||||||
|
"ogg demuxer",
|
||||||
|
"Codec/Demuxer",
|
||||||
|
"demux ogg streams (info about ogg: http://xiph.org)",
|
||||||
|
"Benjamin Otte <in7y118@public.uni-hamburg.de>"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/* signals and args */
|
||||||
|
enum {
|
||||||
|
/* FILL ME */
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ARG_0,
|
||||||
|
/* FILL ME */
|
||||||
|
};
|
||||||
|
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (ogg_demux_src_template_factory,
|
||||||
|
"src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_SOMETIMES,
|
||||||
|
NULL
|
||||||
|
)
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (ogg_demux_sink_template_factory,
|
||||||
|
"sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_NEW (
|
||||||
|
"ogg_demux_sink",
|
||||||
|
"application/ogg",
|
||||||
|
NULL
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_ogg_demux_base_init (gpointer g_class);
|
||||||
|
static void gst_ogg_demux_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_ogg_demux_init (GTypeInstance * instance,
|
||||||
|
gpointer g_class);
|
||||||
|
static void gst_ogg_demux_dispose (GObject * object);
|
||||||
|
|
||||||
|
static gboolean gst_ogg_demux_src_event (GstPad * pad,
|
||||||
|
GstEvent * event);
|
||||||
|
static const GstEventMask* gst_ogg_demux_get_event_masks (GstPad * pad);
|
||||||
|
static const GstQueryType* gst_ogg_demux_get_query_types (GstPad * pad);
|
||||||
|
|
||||||
|
static gboolean gst_ogg_demux_src_query (GstPad * pad,
|
||||||
|
GstQueryType type,
|
||||||
|
GstFormat * format,
|
||||||
|
gint64 * value);
|
||||||
|
|
||||||
|
static void gst_ogg_demux_chain (GstPad * pad,
|
||||||
|
GstData * buffer);
|
||||||
|
|
||||||
|
static GstElementStateReturn gst_ogg_demux_change_state (GstElement * element);
|
||||||
|
|
||||||
|
static GstOggPad * gst_ogg_pad_new (GstOggDemux * ogg,
|
||||||
|
int serial_no);
|
||||||
|
static void gst_ogg_pad_remove (GstOggDemux * ogg,
|
||||||
|
GstOggPad * ogg_pad);
|
||||||
|
static void gst_ogg_pad_reset (GstOggDemux * ogg,
|
||||||
|
GstOggPad * pad);
|
||||||
|
static void gst_ogg_demux_push (GstOggDemux * ogg,
|
||||||
|
ogg_page * page);
|
||||||
|
static void gst_ogg_pad_push (GstOggDemux * ogg,
|
||||||
|
GstOggPad * ogg_pad);
|
||||||
|
|
||||||
|
static GstCaps * gst_ogg_type_find (ogg_packet * packet);
|
||||||
|
|
||||||
|
|
||||||
|
static GstElementClass *parent_class = NULL;
|
||||||
|
/* static guint gst_ogg_demux_signals[LAST_SIGNAL] = { 0 }; */
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_ogg_demux_get_type (void)
|
||||||
|
{
|
||||||
|
static GType ogg_demux_type = 0;
|
||||||
|
|
||||||
|
if (!ogg_demux_type) {
|
||||||
|
static const GTypeInfo ogg_demux_info = {
|
||||||
|
sizeof (GstOggDemuxClass),
|
||||||
|
gst_ogg_demux_base_init,
|
||||||
|
NULL,
|
||||||
|
gst_ogg_demux_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstOggDemux),
|
||||||
|
0,
|
||||||
|
gst_ogg_demux_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
ogg_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstOggDemux", &ogg_demux_info, 0);
|
||||||
|
}
|
||||||
|
return ogg_demux_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_ogg_demux_base_init (gpointer g_class)
|
||||||
|
{
|
||||||
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
|
gst_element_class_set_details (element_class, &gst_ogg_demux_details);
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
GST_PAD_TEMPLATE_GET (ogg_demux_sink_template_factory));
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
GST_PAD_TEMPLATE_GET (ogg_demux_src_template_factory));
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_demux_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
|
gstelement_class->change_state = gst_ogg_demux_change_state;
|
||||||
|
|
||||||
|
gobject_class->dispose = gst_ogg_demux_dispose;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_demux_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstOggDemux *ogg = GST_OGG_DEMUX (instance);
|
||||||
|
|
||||||
|
/* create the sink pad */
|
||||||
|
ogg->sinkpad = gst_pad_new_from_template(
|
||||||
|
GST_PAD_TEMPLATE_GET (ogg_demux_sink_template_factory), "sink");
|
||||||
|
gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
|
||||||
|
gst_pad_set_chain_function (ogg->sinkpad, GST_DEBUG_FUNCPTR (gst_ogg_demux_chain));
|
||||||
|
|
||||||
|
/* initalize variables */
|
||||||
|
ogg->srcpads = NULL;
|
||||||
|
|
||||||
|
GST_FLAG_SET (ogg, GST_ELEMENT_EVENT_AWARE);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_demux_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GstOggDemux *ogg;
|
||||||
|
|
||||||
|
ogg = GST_OGG_DEMUX (object);
|
||||||
|
|
||||||
|
/* srcpads are removed when going to READY */
|
||||||
|
g_assert (ogg->srcpads == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GstEventMask*
|
||||||
|
gst_ogg_demux_get_event_masks (GstPad *pad)
|
||||||
|
{
|
||||||
|
static const GstEventMask gst_ogg_demux_src_event_masks[] = {
|
||||||
|
{ GST_EVENT_SEEK, GST_SEEK_METHOD_SET |
|
||||||
|
GST_SEEK_FLAG_FLUSH },
|
||||||
|
{ 0, }
|
||||||
|
};
|
||||||
|
return gst_ogg_demux_src_event_masks;
|
||||||
|
}
|
||||||
|
static const GstQueryType*
|
||||||
|
gst_ogg_demux_get_query_types (GstPad *pad)
|
||||||
|
{
|
||||||
|
static const GstQueryType gst_ogg_demux_src_query_types[] = {
|
||||||
|
GST_QUERY_TOTAL,
|
||||||
|
GST_QUERY_POSITION,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
return gst_ogg_demux_src_query_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_ogg_demux_src_query (GstPad *pad, GstQueryType type,
|
||||||
|
GstFormat *format, gint64 *value)
|
||||||
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
GstOggDemux *ogg;
|
||||||
|
|
||||||
|
ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GST_QUERY_TOTAL: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GST_QUERY_POSITION:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_ogg_demux_src_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
GstOggDemux *ogg;
|
||||||
|
|
||||||
|
ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_SEEK:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_event_unref (event);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_demux_handle_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
GstOggDemux *ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
ogg=ogg;
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_DISCONTINUOUS:
|
||||||
|
break;
|
||||||
|
case GST_EVENT_EOS:
|
||||||
|
if (ogg->srcpads)
|
||||||
|
GST_WARNING_OBJECT (ogg, "got EOS in unfinished ogg stream");
|
||||||
|
while (ogg->srcpads) {
|
||||||
|
gst_ogg_pad_remove (ogg, (GstOggPad *) ogg->srcpads->data);
|
||||||
|
}
|
||||||
|
gst_element_set_eos (GST_ELEMENT (ogg));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_demux_chain (GstPad *pad, GstData *buffer)
|
||||||
|
{
|
||||||
|
GstOggDemux *ogg;
|
||||||
|
guint8 *data;
|
||||||
|
int pageout_ret = 1;
|
||||||
|
|
||||||
|
/* handle events */
|
||||||
|
if (GST_IS_EVENT (buffer)) {
|
||||||
|
gst_ogg_demux_handle_event (pad, GST_EVENT (buffer));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
data = (guint8 *) ogg_sync_buffer(&ogg->sync, GST_BUFFER_SIZE (buffer));
|
||||||
|
memcpy (data, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
|
||||||
|
if (ogg_sync_wrote (&ogg->sync, GST_BUFFER_SIZE (buffer)) != 0) {
|
||||||
|
gst_data_unref (buffer);
|
||||||
|
gst_element_error (GST_ELEMENT (ogg), "ogg_sync_wrote failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gst_data_unref (buffer);
|
||||||
|
while (pageout_ret != 0) {
|
||||||
|
ogg_page page;
|
||||||
|
|
||||||
|
pageout_ret = ogg_sync_pageout (&ogg->sync, &page);
|
||||||
|
switch (pageout_ret) {
|
||||||
|
case -1:
|
||||||
|
/* FIXME: need some kind of discont here, we don't know any values */
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
gst_ogg_demux_push (ogg, &page);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_WARNING_OBJECT (ogg, "unknown return value %d from ogg_sync_pageout", pageout_ret);
|
||||||
|
pageout_ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static GstOggPad *
|
||||||
|
gst_ogg_pad_new (GstOggDemux *ogg, int serial)
|
||||||
|
{
|
||||||
|
GstOggPad *ret = g_new (GstOggPad, 1);
|
||||||
|
|
||||||
|
ret->serial = serial;
|
||||||
|
if (ogg_stream_init (&ret->stream, serial) != 0) {
|
||||||
|
GST_ERROR_OBJECT (ogg, "Could not initialize ogg_stream struct for serial %d.", serial);
|
||||||
|
g_free (ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ret->pad = NULL;
|
||||||
|
ret->offset = 0;
|
||||||
|
GST_LOG_OBJECT (ogg, "created new ogg src %p for stream with serial %d", ret, serial);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_pad_remove (GstOggDemux *ogg, GstOggPad *pad)
|
||||||
|
{
|
||||||
|
ogg->srcpads = g_slist_remove (ogg->srcpads, pad);
|
||||||
|
if (pad->pad) {
|
||||||
|
gst_pad_push (pad->pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
|
||||||
|
gst_element_remove_pad (GST_ELEMENT (ogg), pad->pad);
|
||||||
|
}
|
||||||
|
if (ogg_stream_clear (&pad->stream) != 0)
|
||||||
|
GST_ERROR_OBJECT (ogg, "ogg_stream_clear (serial %d) did not return 0, ignoring this error", pad->serial);
|
||||||
|
GST_LOG_OBJECT (ogg, "free ogg src %p for stream with serial %d", pad, pad->serial);
|
||||||
|
g_free (pad);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_demux_push (GstOggDemux *ogg, ogg_page* page)
|
||||||
|
{
|
||||||
|
GSList *walk;;
|
||||||
|
GstOggPad *cur;
|
||||||
|
|
||||||
|
/* find the stream */
|
||||||
|
walk = ogg->srcpads;
|
||||||
|
while (walk) {
|
||||||
|
cur = (GstOggPad *) walk->data;
|
||||||
|
if (cur->serial == ogg_page_serialno (page)) {
|
||||||
|
goto br;
|
||||||
|
}
|
||||||
|
walk = g_slist_next (walk);
|
||||||
|
}
|
||||||
|
cur = NULL;
|
||||||
|
br:
|
||||||
|
/* now we either have a stream (cur) or not */
|
||||||
|
if (ogg_page_bos (page)) {
|
||||||
|
if (cur) {
|
||||||
|
/* huh? */
|
||||||
|
GST_WARNING_OBJECT (ogg, "Ignoring error: ogg page declared as BOS while stream already existed.");
|
||||||
|
} else {
|
||||||
|
/* FIXME: monitor if we are still in creation stage? */
|
||||||
|
cur = gst_ogg_pad_new (ogg, ogg_page_serialno (page));
|
||||||
|
if (!cur) {
|
||||||
|
gst_element_error (GST_ELEMENT (ogg), "Creating ogg_stream struct failed.");
|
||||||
|
}
|
||||||
|
ogg->srcpads = g_slist_prepend (ogg->srcpads, cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cur == NULL) {
|
||||||
|
gst_element_error (GST_ELEMENT (ogg), "invalid ogg stream serial no");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ogg_stream_pagein (&cur->stream, page) != 0) {
|
||||||
|
GST_WARNING_OBJECT (ogg, "ogg stream choked on page (serial %d), resetting stream", cur->serial);
|
||||||
|
gst_ogg_pad_reset (ogg, cur);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gst_ogg_pad_push (ogg, cur);
|
||||||
|
#if 0
|
||||||
|
/* Removing pads while PLAYING doesn't work with current schedulers */
|
||||||
|
/* remove from list, as this will never be called again */
|
||||||
|
if (ogg_page_eos (page)) {
|
||||||
|
gst_ogg_pad_remove (ogg, cur);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_pad_push (GstOggDemux *ogg, GstOggPad *pad)
|
||||||
|
{
|
||||||
|
ogg_packet packet;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
ret = ogg_stream_packetout (&pad->stream, &packet);
|
||||||
|
switch (ret) {
|
||||||
|
case 0:
|
||||||
|
return;
|
||||||
|
case -1:
|
||||||
|
gst_ogg_pad_reset (ogg, pad);
|
||||||
|
break;
|
||||||
|
case 1: {
|
||||||
|
if (!pad->pad) {
|
||||||
|
GstCaps *caps = gst_ogg_type_find (&packet);
|
||||||
|
gchar *name = g_strdup_printf ("serial %d", pad->serial);
|
||||||
|
|
||||||
|
pad->pad = gst_pad_new_from_template (ogg_demux_src_template_factory(), name);
|
||||||
|
g_free (name);
|
||||||
|
gst_pad_set_event_function (pad->pad, GST_DEBUG_FUNCPTR (gst_ogg_demux_src_event));
|
||||||
|
gst_pad_set_event_mask_function (pad->pad, GST_DEBUG_FUNCPTR (gst_ogg_demux_get_event_masks));
|
||||||
|
gst_pad_set_query_function (pad->pad, GST_DEBUG_FUNCPTR (gst_ogg_demux_src_query));
|
||||||
|
gst_pad_set_query_type_function (pad->pad, GST_DEBUG_FUNCPTR (gst_ogg_demux_get_query_types));
|
||||||
|
if (caps)
|
||||||
|
g_assert (gst_pad_try_set_caps (pad->pad, caps) >= GST_PAD_LINK_OK);
|
||||||
|
gst_pad_set_active (pad->pad, TRUE);
|
||||||
|
gst_element_add_pad (GST_ELEMENT (ogg), pad->pad);
|
||||||
|
}
|
||||||
|
/* optimization: use a bufferpool containing the ogg packet */
|
||||||
|
GstBuffer *buf = gst_buffer_new_and_alloc (packet.bytes);
|
||||||
|
memcpy (buf->data, packet.packet, packet.bytes);
|
||||||
|
GST_BUFFER_OFFSET (buf) = pad->offset;
|
||||||
|
pad->offset = GST_BUFFER_OFFSET_END (buf) = packet.granulepos;
|
||||||
|
gst_pad_push (pad->pad, GST_DATA (buf));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
GST_ERROR_OBJECT (ogg, "invalid return value %d for ogg_stream_packetout, resetting stream", ret);
|
||||||
|
gst_ogg_pad_reset (ogg, pad);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_ogg_pad_reset (GstOggDemux *ogg, GstOggPad *pad)
|
||||||
|
{
|
||||||
|
ogg_stream_reset (&pad->stream);
|
||||||
|
pad->offset = GST_BUFFER_OFFSET_NONE;
|
||||||
|
/* FIXME: need a discont here */
|
||||||
|
}
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_ogg_demux_change_state (GstElement *element)
|
||||||
|
{
|
||||||
|
GstOggDemux *ogg;
|
||||||
|
|
||||||
|
ogg = GST_OGG_DEMUX (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
case GST_STATE_NULL_TO_READY:
|
||||||
|
ogg_sync_init (&ogg->sync);
|
||||||
|
break;
|
||||||
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
ogg_sync_reset (&ogg->sync);
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
break;
|
||||||
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
while (ogg->srcpads) {
|
||||||
|
gst_ogg_pad_remove (ogg, (GstOggPad *) ogg->srcpads->data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_STATE_READY_TO_NULL:
|
||||||
|
ogg_sync_clear (&ogg->sync);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent_class->change_state (element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** typefinding **************************************************************/
|
||||||
|
/* ogg supports its own typefinding because the ogg spec defines that the first
|
||||||
|
* packet of an ogg stream must identify the stream. Therefore ogg can use a
|
||||||
|
* simplified approach at typefinding.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
ogg_packet * packet;
|
||||||
|
guint best_probability;
|
||||||
|
GstCaps * caps;
|
||||||
|
} OggTypeFind;
|
||||||
|
static guint8 *
|
||||||
|
ogg_find_peek (gpointer data, gint64 offset, guint size)
|
||||||
|
{
|
||||||
|
OggTypeFind *find = (OggTypeFind *) data;
|
||||||
|
|
||||||
|
if (offset + size <= find->packet->bytes) {
|
||||||
|
return ((guint8 *) find->packet->packet) + offset;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
ogg_find_suggest (gpointer data, guint probability, GstCaps *caps)
|
||||||
|
{
|
||||||
|
OggTypeFind *find = (OggTypeFind *) data;
|
||||||
|
|
||||||
|
if (probability > find->best_probability) {
|
||||||
|
gst_caps_replace_sink (&find->caps, caps);
|
||||||
|
find->best_probability = probability;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static GstCaps *
|
||||||
|
gst_ogg_type_find (ogg_packet *packet)
|
||||||
|
{
|
||||||
|
GstTypeFind gst_find;
|
||||||
|
OggTypeFind find;
|
||||||
|
GList *walk, *type_list = NULL;
|
||||||
|
|
||||||
|
walk = type_list = gst_type_find_factory_get_list ();
|
||||||
|
|
||||||
|
find.packet = packet;
|
||||||
|
find.best_probability = 0;
|
||||||
|
find.caps = NULL;
|
||||||
|
gst_find.data = &find;
|
||||||
|
gst_find.peek = ogg_find_peek;
|
||||||
|
gst_find.suggest = ogg_find_suggest;
|
||||||
|
|
||||||
|
while (walk) {
|
||||||
|
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
|
||||||
|
|
||||||
|
gst_type_find_factory_call_function (factory, &gst_find);
|
||||||
|
if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
|
||||||
|
break;
|
||||||
|
walk = g_list_next (walk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find.best_probability > 0)
|
||||||
|
return find.caps;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
plugin_init (GstPlugin *plugin)
|
||||||
|
{
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_debug, "oggdemux", 0, "ogg demuxer");
|
||||||
|
|
||||||
|
return gst_element_register (plugin, "oggdemux", GST_RANK_PRIMARY, GST_TYPE_OGG_DEMUX);
|
||||||
|
}
|
||||||
|
GST_PLUGIN_DEFINE (
|
||||||
|
GST_VERSION_MAJOR,
|
||||||
|
GST_VERSION_MINOR,
|
||||||
|
"ogg",
|
||||||
|
"ogg stream manipulation (info about ogg: http://xiph.org)",
|
||||||
|
plugin_init,
|
||||||
|
VERSION,
|
||||||
|
GST_LICENSE,
|
||||||
|
GST_COPYRIGHT,
|
||||||
|
GST_PACKAGE,
|
||||||
|
GST_ORIGIN
|
||||||
|
)
|
|
@ -2,9 +2,9 @@
|
||||||
plugin_LTLIBRARIES = libgstvorbis.la
|
plugin_LTLIBRARIES = libgstvorbis.la
|
||||||
|
|
||||||
libgstvorbis_la_SOURCES = vorbis.c vorbisenc.c vorbisfile.c
|
libgstvorbis_la_SOURCES = vorbis.c vorbisenc.c vorbisfile.c
|
||||||
libgstvorbis_la_CFLAGS = $(GST_CFLAGS) $(VORBIS_CFLAGS)
|
libgstvorbis_la_CFLAGS = $(GST_CFLAGS) $(VORBIS_CFLAGS)
|
||||||
## AM_PATH_VORBIS also sets VORBISENC_LIBS
|
## AM_PATH_VORBIS also sets VORBISENC_LIBS
|
||||||
libgstvorbis_la_LIBADD = $(VORBIS_LIBS) $(VORBISENC_LIBS) $(VORBISFILE_LIBS)
|
libgstvorbis_la_LIBADD = $(VORBIS_LIBS) $(VORBISENC_LIBS) $(VORBISFILE_LIBS)
|
||||||
libgstvorbis_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstvorbis_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = vorbisenc.h
|
noinst_HEADERS = vorbisenc.h
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <vorbis/vorbisenc.h>
|
#include <vorbis/vorbisenc.h>
|
||||||
|
|
||||||
|
#include <gst/gsttaginterface.h>
|
||||||
#include "vorbisenc.h"
|
#include "vorbisenc.h"
|
||||||
|
|
||||||
static GstPadTemplate *gst_vorbisenc_src_template, *gst_vorbisenc_sink_template;
|
static GstPadTemplate *gst_vorbisenc_src_template, *gst_vorbisenc_sink_template;
|
||||||
|
@ -116,8 +117,15 @@ vorbisenc_get_type (void)
|
||||||
0,
|
0,
|
||||||
(GInstanceInitFunc) gst_vorbisenc_init,
|
(GInstanceInitFunc) gst_vorbisenc_init,
|
||||||
};
|
};
|
||||||
|
static const GInterfaceInfo tag_setter_info = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
vorbisenc_type = g_type_register_static (GST_TYPE_ELEMENT, "VorbisEnc", &vorbisenc_info, 0);
|
vorbisenc_type = g_type_register_static (GST_TYPE_ELEMENT, "VorbisEnc", &vorbisenc_info, 0);
|
||||||
|
|
||||||
|
g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER, &tag_setter_info);
|
||||||
}
|
}
|
||||||
return vorbisenc_type;
|
return vorbisenc_type;
|
||||||
}
|
}
|
||||||
|
@ -197,9 +205,6 @@ gst_vorbisenc_class_init (VorbisEncClass * klass)
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SERIAL,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SERIAL,
|
||||||
g_param_spec_int ("serial", "Serial", "Specify a serial number for the stream. (-1 is random)",
|
g_param_spec_int ("serial", "Serial", "Specify a serial number for the stream. (-1 is random)",
|
||||||
-1, G_MAXINT, -1, G_PARAM_READWRITE));
|
-1, G_MAXINT, -1, G_PARAM_READWRITE));
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METADATA,
|
|
||||||
g_param_spec_boxed ("metadata", "Metadata", "Metadata to add to the stream,",
|
|
||||||
GST_TYPE_CAPS, G_PARAM_READWRITE));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED,
|
||||||
g_param_spec_boolean ("managed", "Managed", "Enable bitrate management engine",
|
g_param_spec_boolean ("managed", "Managed", "Enable bitrate management engine",
|
||||||
FALSE, G_PARAM_READWRITE));
|
FALSE, G_PARAM_READWRITE));
|
||||||
|
@ -458,52 +463,106 @@ gst_vorbisenc_init (VorbisEnc * vorbisenc)
|
||||||
|
|
||||||
vorbisenc->setup = FALSE;
|
vorbisenc->setup = FALSE;
|
||||||
vorbisenc->eos = FALSE;
|
vorbisenc->eos = FALSE;
|
||||||
|
vorbisenc->header_sent = FALSE;
|
||||||
|
|
||||||
vorbisenc->metadata = GST_CAPS_NEW (
|
vorbisenc->tags = gst_tag_list_new ();
|
||||||
"vorbisenc_metadata",
|
|
||||||
"application/x-gst-metadata",
|
|
||||||
"DESCRIPTION", GST_PROPS_STRING ("Track encoded with GStreamer"),
|
|
||||||
"DATE", GST_PROPS_STRING (""),
|
|
||||||
"TRACKNUMBER", GST_PROPS_STRING (""),
|
|
||||||
"TITLE", GST_PROPS_STRING (""),
|
|
||||||
"ARTIST", GST_PROPS_STRING (""),
|
|
||||||
"ALBUM", GST_PROPS_STRING (""),
|
|
||||||
"GENRE", GST_PROPS_STRING ("")
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/* we're chained and we can deal with events */
|
/* we're chained and we can deal with events */
|
||||||
GST_FLAG_SET (vorbisenc, GST_ELEMENT_EVENT_AWARE);
|
GST_FLAG_SET (vorbisenc, GST_ELEMENT_EVENT_AWARE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_vorbisenc_add_metadata (VorbisEnc *vorbisenc, GstCaps *caps)
|
gst_vorbisenc_metadata_set1 (const GstTagList *list, const gchar *tag, gpointer vorbisenc)
|
||||||
{
|
{
|
||||||
GList *props;
|
gchar *vorbistag, *vorbisvalue;
|
||||||
GstPropsEntry *prop;
|
guint i, count;
|
||||||
|
VorbisEnc *enc = GST_VORBISENC (vorbisenc);
|
||||||
|
|
||||||
if (caps == NULL)
|
count = gst_tag_list_get_tag_size (list, tag);
|
||||||
return;
|
for (i = 0; i < count; i++) {
|
||||||
|
/* get tag name right */
|
||||||
vorbis_comment_init (&vorbisenc->vc);
|
if (strcmp (tag, GST_TAG_TITLE) == 0) {
|
||||||
|
vorbistag = g_strdup ("TITLE");
|
||||||
props = gst_caps_get_props (caps)->properties;
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
while (props) {
|
} else if (strcmp (tag, GST_TAG_VERSION) == 0) {
|
||||||
prop = (GstPropsEntry*)(props->data);
|
vorbistag = g_strdup ("VERSION");
|
||||||
props = g_list_next(props);
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_ALBUM) == 0) {
|
||||||
if (gst_props_entry_get_props_type (prop) == GST_PROPS_STRING_TYPE) {
|
vorbistag = g_strdup ("ALBUM");
|
||||||
const gchar *name = gst_props_entry_get_name (prop);
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
const gchar *value;
|
} else if (strcmp (tag, GST_TAG_TRACK_NUMBER) == 0) {
|
||||||
|
vorbistag = g_strdup ("TRACKNUMBER");
|
||||||
gst_props_entry_get_string (prop, &value);
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_ARTIST) == 0) {
|
||||||
if (!value || strlen (value) == 0)
|
vorbistag = g_strdup ("ARTIST");
|
||||||
continue;
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_PERFORMER) == 0) {
|
||||||
vorbis_comment_add_tag (&vorbisenc->vc, g_strdup (name), g_strdup (value));
|
vorbistag = g_strdup ("PERFORMER");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_COPYRIGHT) == 0) {
|
||||||
|
vorbistag = g_strdup ("COPYRIGHT");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_LICENSE) == 0) {
|
||||||
|
vorbistag = g_strdup ("LICENSE");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_ORGANIZATION) == 0) {
|
||||||
|
vorbistag = g_strdup ("ORGANIZATION");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_DESCRIPTION) == 0) {
|
||||||
|
vorbistag = g_strdup ("DESCRIPTION");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_GENRE) == 0) {
|
||||||
|
vorbistag = g_strdup ("GENRE");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_DATE) == 0) {
|
||||||
|
/* FIXME: how are dates represented in vorbis files? */
|
||||||
|
GDate *date;
|
||||||
|
guint u;
|
||||||
|
|
||||||
|
vorbistag = g_strdup ("DATE");
|
||||||
|
g_assert (gst_tag_list_get_uint_index (list, tag, i, &u));
|
||||||
|
date = g_date_new_julian (u);
|
||||||
|
vorbisvalue = g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
|
||||||
|
(gint) g_date_get_month (date), (gint) g_date_get_day (date));
|
||||||
|
g_date_free (date);
|
||||||
|
/* NOTE: GST_TAG_LOCATION != vorbis' location
|
||||||
|
} else if (strcmp (tag, PLACE) == 0) {
|
||||||
|
vorbistag = g_strdup ("LOCATION");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
*/
|
||||||
|
} else if (strcmp (tag, GST_TAG_CONTACT) == 0) {
|
||||||
|
vorbistag = g_strdup ("CONTACT");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else if (strcmp (tag, GST_TAG_ISRC) == 0) {
|
||||||
|
vorbistag = g_strdup ("ISRC");
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else {
|
||||||
|
vorbistag = g_ascii_strup (tag, -1);
|
||||||
|
if (gst_tag_get_type (tag) == G_TYPE_STRING) {
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
|
||||||
|
} else {
|
||||||
|
const GValue *value = gst_tag_list_get_value_index (list, tag, i);
|
||||||
|
vorbisvalue = g_strdup_value_contents (value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vorbis_comment_add_tag (&enc->vc, vorbistag, vorbisvalue);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_vorbisenc_set_metadata (VorbisEnc *vorbisenc)
|
||||||
|
{
|
||||||
|
GstTagList *copy;
|
||||||
|
const GstTagList *user_tags;
|
||||||
|
|
||||||
|
user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (vorbisenc));
|
||||||
|
if (!(vorbisenc->tags || user_tags))
|
||||||
|
return;
|
||||||
|
|
||||||
|
copy = gst_tag_list_merge (user_tags, vorbisenc->tags, gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc)));
|
||||||
|
vorbis_comment_init (&vorbisenc->vc);
|
||||||
|
gst_tag_list_foreach (copy, gst_vorbisenc_metadata_set1, vorbisenc);
|
||||||
|
gst_tag_list_free (copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gchar*
|
static gchar*
|
||||||
|
@ -635,8 +694,6 @@ gst_vorbisenc_setup (VorbisEnc *vorbisenc)
|
||||||
}
|
}
|
||||||
vorbis_encode_setup_init(&vorbisenc->vi);
|
vorbis_encode_setup_init(&vorbisenc->vi);
|
||||||
|
|
||||||
gst_vorbisenc_add_metadata (vorbisenc, vorbisenc->metadata);
|
|
||||||
|
|
||||||
/* set up the analysis state and auxiliary encoding storage */
|
/* set up the analysis state and auxiliary encoding storage */
|
||||||
vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
|
vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
|
||||||
vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
|
vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
|
||||||
|
@ -654,28 +711,6 @@ gst_vorbisenc_setup (VorbisEnc *vorbisenc)
|
||||||
|
|
||||||
ogg_stream_init (&vorbisenc->os, serial);
|
ogg_stream_init (&vorbisenc->os, serial);
|
||||||
|
|
||||||
/* Vorbis streams begin with three headers; the initial header (with
|
|
||||||
most of the codec setup parameters) which is mandated by the Ogg
|
|
||||||
bitstream spec. The second header holds any comment fields. The
|
|
||||||
third header holds the bitstream codebook. We merely need to
|
|
||||||
make the headers, then pass them to libvorbis one at a time;
|
|
||||||
libvorbis handles the additional Ogg bitstream constraints */
|
|
||||||
|
|
||||||
{
|
|
||||||
ogg_packet header;
|
|
||||||
ogg_packet header_comm;
|
|
||||||
ogg_packet header_code;
|
|
||||||
|
|
||||||
vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header, &header_comm, &header_code);
|
|
||||||
ogg_stream_packetin (&vorbisenc->os, &header); /* automatically placed in its own
|
|
||||||
page */
|
|
||||||
ogg_stream_packetin (&vorbisenc->os, &header_comm);
|
|
||||||
ogg_stream_packetin (&vorbisenc->os, &header_code);
|
|
||||||
|
|
||||||
/* no need to write out here. We'll get to that in the main loop */
|
|
||||||
vorbisenc->flush_header = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
vorbisenc->setup = TRUE;
|
vorbisenc->setup = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -732,6 +767,15 @@ gst_vorbisenc_chain (GstPad * pad, GstData *_data)
|
||||||
vorbis_analysis_wrote (&vorbisenc->vd, 0);
|
vorbis_analysis_wrote (&vorbisenc->vd, 0);
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
break;
|
break;
|
||||||
|
case GST_EVENT_TAG:
|
||||||
|
if (vorbisenc->tags) {
|
||||||
|
gst_tag_list_merge (vorbisenc->tags, gst_event_tag_get_list (event),
|
||||||
|
gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc)));
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
gst_pad_event_default (pad, event);
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
gst_pad_event_default (pad, event);
|
gst_pad_event_default (pad, event);
|
||||||
return;
|
return;
|
||||||
|
@ -749,16 +793,28 @@ gst_vorbisenc_chain (GstPad * pad, GstData *_data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vorbisenc->flush_header) {
|
if (!vorbisenc->header_sent) {
|
||||||
gint result;
|
gint result;
|
||||||
|
/* Vorbis streams begin with three headers; the initial header (with
|
||||||
|
most of the codec setup parameters) which is mandated by the Ogg
|
||||||
|
bitstream spec. The second header holds any comment fields. The
|
||||||
|
third header holds the bitstream codebook. We merely need to
|
||||||
|
make the headers, then pass them to libvorbis one at a time;
|
||||||
|
libvorbis handles the additional Ogg bitstream constraints */
|
||||||
|
ogg_packet header;
|
||||||
|
ogg_packet header_comm;
|
||||||
|
ogg_packet header_code;
|
||||||
|
|
||||||
|
gst_vorbisenc_set_metadata (vorbisenc);
|
||||||
|
vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header, &header_comm, &header_code);
|
||||||
|
ogg_stream_packetin (&vorbisenc->os, &header); /* automatically placed in its own page */
|
||||||
|
ogg_stream_packetin (&vorbisenc->os, &header_comm);
|
||||||
|
ogg_stream_packetin (&vorbisenc->os, &header_code);
|
||||||
|
|
||||||
while ((result = ogg_stream_flush(&vorbisenc->os, &vorbisenc->og))) {
|
while ((result = ogg_stream_flush(&vorbisenc->os, &vorbisenc->og))) {
|
||||||
if (!result)
|
|
||||||
break;
|
|
||||||
|
|
||||||
gst_vorbisenc_write_page (vorbisenc, &vorbisenc->og);
|
gst_vorbisenc_write_page (vorbisenc, &vorbisenc->og);
|
||||||
}
|
}
|
||||||
vorbisenc->flush_header = FALSE;
|
vorbisenc->header_sent = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* data to encode */
|
/* data to encode */
|
||||||
|
@ -852,9 +908,6 @@ gst_vorbisenc_get_property (GObject * object, guint prop_id, GValue * value, GPa
|
||||||
case ARG_SERIAL:
|
case ARG_SERIAL:
|
||||||
g_value_set_int (value, vorbisenc->serial);
|
g_value_set_int (value, vorbisenc->serial);
|
||||||
break;
|
break;
|
||||||
case ARG_METADATA:
|
|
||||||
g_value_set_static_boxed (value, vorbisenc->metadata);
|
|
||||||
break;
|
|
||||||
case ARG_MANAGED:
|
case ARG_MANAGED:
|
||||||
g_value_set_boolean (value, vorbisenc->managed);
|
g_value_set_boolean (value, vorbisenc->managed);
|
||||||
break;
|
break;
|
||||||
|
@ -920,9 +973,6 @@ gst_vorbisenc_set_property (GObject * object, guint prop_id, const GValue * valu
|
||||||
case ARG_SERIAL:
|
case ARG_SERIAL:
|
||||||
vorbisenc->serial = g_value_get_int (value);
|
vorbisenc->serial = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
case ARG_METADATA:
|
|
||||||
vorbisenc->metadata = g_value_get_boxed (value);
|
|
||||||
break;
|
|
||||||
case ARG_MANAGED:
|
case ARG_MANAGED:
|
||||||
vorbisenc->managed = g_value_get_boolean (value);
|
vorbisenc->managed = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
@ -947,6 +997,9 @@ gst_vorbisenc_change_state (GstElement *element)
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_READY:
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
vorbisenc->setup = FALSE;
|
vorbisenc->setup = FALSE;
|
||||||
|
vorbisenc->header_sent = FALSE;
|
||||||
|
gst_tag_list_free (vorbisenc->tags);
|
||||||
|
vorbisenc->tags = gst_tag_list_new ();
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -78,10 +78,10 @@ struct _VorbisEnc {
|
||||||
guint64 samples_in;
|
guint64 samples_in;
|
||||||
guint64 bytes_out;
|
guint64 bytes_out;
|
||||||
|
|
||||||
GstCaps *metadata;
|
GstTagList * tags;
|
||||||
|
|
||||||
gboolean setup;
|
gboolean setup;
|
||||||
gboolean flush_header;
|
gboolean header_sent;
|
||||||
gchar *last_message;
|
gchar *last_message;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,43 +25,6 @@ patches:
|
||||||
|
|
||||||
SUBDIRS =
|
SUBDIRS =
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
$(PATCHES) \
|
|
||||||
Tag \
|
|
||||||
ffmpeg/CREDITS \
|
|
||||||
ffmpeg/INSTALL \
|
|
||||||
ffmpeg/README \
|
|
||||||
ffmpeg/config.mak \
|
|
||||||
ffmpeg/configure \
|
|
||||||
ffmpeg/cygwin_inttypes.h \
|
|
||||||
ffmpeg/ffserver.h \
|
|
||||||
ffmpeg/ffmpeg.c \
|
|
||||||
ffmpeg/ffserver.c \
|
|
||||||
ffmpeg/berrno.h \
|
|
||||||
ffmpeg/config.h \
|
|
||||||
ffmpeg/libavcodec/alpha/*.c \
|
|
||||||
ffmpeg/libavcodec/alpha/*.h \
|
|
||||||
ffmpeg/libavcodec/alpha/*.S \
|
|
||||||
ffmpeg/libavcodec/armv4l/*.c \
|
|
||||||
ffmpeg/libavcodec/armv4l/*.S \
|
|
||||||
ffmpeg/libavcodec/i386/*.c \
|
|
||||||
ffmpeg/libavcodec/i386/*.h \
|
|
||||||
ffmpeg/libavcodec/liba52/*.c \
|
|
||||||
ffmpeg/libavcodec/liba52/*.h \
|
|
||||||
ffmpeg/libavcodec/ppc/*.c \
|
|
||||||
ffmpeg/libavcodec/ppc/*.h \
|
|
||||||
ffmpeg/libavcodec/ps2/*.c \
|
|
||||||
ffmpeg/libavcodec/ps2/*.h \
|
|
||||||
ffmpeg/libavcodec/*.c \
|
|
||||||
ffmpeg/libavcodec/*.h \
|
|
||||||
ffmpeg/libavformat/*.c \
|
|
||||||
ffmpeg/libavformat/*.h \
|
|
||||||
ffmpeg/tests/*.c \
|
|
||||||
ffmpeg/tests/*.ref \
|
|
||||||
ffmpeg/tests/*.sh \
|
|
||||||
ffmpeg/tests/test.conf \
|
|
||||||
ffmpeg/vhook/*.c
|
|
||||||
|
|
||||||
|
|
||||||
checkout:
|
checkout:
|
||||||
cvs -d:pserver:anonymous@mplayerhq.hu:/cvsroot/ffmpeg co ffmpeg
|
cvs -d:pserver:anonymous@mplayerhq.hu:/cvsroot/ffmpeg co ffmpeg
|
||||||
|
@ -164,9 +127,7 @@ libavformat_la_CFLAGS = $(defs) -Wall -I$(srcdir) -I$(srcdir)/ffmpeg \
|
||||||
-I$(top_srcdir)/gst-libs/ext/linux/ -DHAVE_AV_CONFIG_H \
|
-I$(top_srcdir)/gst-libs/ext/linux/ -DHAVE_AV_CONFIG_H \
|
||||||
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE
|
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE
|
||||||
|
|
||||||
|
files_i386 = \
|
||||||
if HAVE_CPU_I386
|
|
||||||
sources_i386 = \
|
|
||||||
ffmpeg/libavcodec/i386/cputest.c \
|
ffmpeg/libavcodec/i386/cputest.c \
|
||||||
ffmpeg/libavcodec/i386/dsputil_mmx.c \
|
ffmpeg/libavcodec/i386/dsputil_mmx.c \
|
||||||
ffmpeg/libavcodec/i386/fdct_mmx.c \
|
ffmpeg/libavcodec/i386/fdct_mmx.c \
|
||||||
|
@ -175,12 +136,13 @@ sources_i386 = \
|
||||||
ffmpeg/libavcodec/i386/motion_est_mmx.c \
|
ffmpeg/libavcodec/i386/motion_est_mmx.c \
|
||||||
ffmpeg/libavcodec/i386/mpegvideo_mmx.c \
|
ffmpeg/libavcodec/i386/mpegvideo_mmx.c \
|
||||||
ffmpeg/libavcodec/i386/simple_idct_mmx.c
|
ffmpeg/libavcodec/i386/simple_idct_mmx.c
|
||||||
|
if HAVE_CPU_I386
|
||||||
|
sources_i386 = $(files_i386)
|
||||||
else
|
else
|
||||||
sources_i386 =
|
sources_i386 =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if HAVE_CPU_PPC
|
files_powerpc = \
|
||||||
sources_powerpc = \
|
|
||||||
ffmpeg/libavcodec/ppc/dsputil_ppc.c \
|
ffmpeg/libavcodec/ppc/dsputil_ppc.c \
|
||||||
ffmpeg/libavcodec/ppc/mpegvideo_ppc.c
|
ffmpeg/libavcodec/ppc/mpegvideo_ppc.c
|
||||||
# disabled Altivec support for now until someone shows up that make them compile conditionally
|
# disabled Altivec support for now until someone shows up that make them compile conditionally
|
||||||
|
@ -189,6 +151,8 @@ sources_powerpc = \
|
||||||
# ffmpeg/libavcodec/ppc/gmc_altivec.c \
|
# ffmpeg/libavcodec/ppc/gmc_altivec.c \
|
||||||
# ffmpeg/libavcodec/ppc/idct_altivec.c \
|
# ffmpeg/libavcodec/ppc/idct_altivec.c \
|
||||||
# ffmpeg/libavcodec/ppc/mpegvideo_altivec.c
|
# ffmpeg/libavcodec/ppc/mpegvideo_altivec.c
|
||||||
|
if HAVE_CPU_PPC
|
||||||
|
sources_powerpc = $(files_powerpc)
|
||||||
else
|
else
|
||||||
sources_powerpc =
|
sources_powerpc =
|
||||||
endif
|
endif
|
||||||
|
@ -270,3 +234,86 @@ libavcodec_la_SOURCES = \
|
||||||
$(sources_i386) \
|
$(sources_i386) \
|
||||||
$(sources_powerpc)
|
$(sources_powerpc)
|
||||||
|
|
||||||
|
more_libavcodec_files = \
|
||||||
|
ffmpeg/libavcodec/mdec.c \
|
||||||
|
ffmpeg/libavcodec/motion_est_template.c \
|
||||||
|
ffmpeg/libavcodec/svq3.c \
|
||||||
|
ffmpeg/libavcodec/wmv2.c
|
||||||
|
|
||||||
|
|
||||||
|
all_headers = \
|
||||||
|
ffmpeg/berrno.h \
|
||||||
|
ffmpeg/cmdutils.h \
|
||||||
|
ffmpeg/cygwin_inttypes.h \
|
||||||
|
ffmpeg/ffserver.h \
|
||||||
|
ffmpeg/xvmc_render.h \
|
||||||
|
ffmpeg/libavcodec/ac3.h \
|
||||||
|
ffmpeg/libavcodec/ac3tab.h \
|
||||||
|
ffmpeg/libavcodec/avcodec.h \
|
||||||
|
ffmpeg/libavcodec/bswap.h \
|
||||||
|
ffmpeg/libavcodec/cabac.h \
|
||||||
|
ffmpeg/libavcodec/common.h \
|
||||||
|
ffmpeg/libavcodec/dsputil.h \
|
||||||
|
ffmpeg/libavcodec/dvdata.h \
|
||||||
|
ffmpeg/libavcodec/faandct.h \
|
||||||
|
ffmpeg/libavcodec/fastmemcpy.h \
|
||||||
|
ffmpeg/libavcodec/golomb.h \
|
||||||
|
ffmpeg/libavcodec/h263data.h \
|
||||||
|
ffmpeg/libavcodec/h264data.h \
|
||||||
|
ffmpeg/libavcodec/imgconvert_template.h \
|
||||||
|
ffmpeg/libavcodec/indeo3data.h \
|
||||||
|
ffmpeg/libavcodec/mpeg12data.h \
|
||||||
|
ffmpeg/libavcodec/mpeg4data.h \
|
||||||
|
ffmpeg/libavcodec/mpegaudio.h \
|
||||||
|
ffmpeg/libavcodec/mpegaudiodectab.h \
|
||||||
|
ffmpeg/libavcodec/mpegaudiotab.h \
|
||||||
|
ffmpeg/libavcodec/mpegvideo.h \
|
||||||
|
ffmpeg/libavcodec/msmpeg4data.h \
|
||||||
|
ffmpeg/libavcodec/oggvorbis.h \
|
||||||
|
ffmpeg/libavcodec/ra144.h \
|
||||||
|
ffmpeg/libavcodec/ra288.h \
|
||||||
|
ffmpeg/libavcodec/rational.h \
|
||||||
|
ffmpeg/libavcodec/simple_idct.h \
|
||||||
|
ffmpeg/libavcodec/sp5x.h \
|
||||||
|
ffmpeg/libavcodec/svq1_cb.h \
|
||||||
|
ffmpeg/libavcodec/svq1_vlc.h \
|
||||||
|
ffmpeg/libavcodec/vp3data.h \
|
||||||
|
ffmpeg/libavcodec/wmadata.h \
|
||||||
|
ffmpeg/libavcodec/i386/dsputil_mmx_avg.h \
|
||||||
|
ffmpeg/libavcodec/i386/dsputil_mmx_rnd.h \
|
||||||
|
ffmpeg/libavcodec/i386/mmx.h \
|
||||||
|
ffmpeg/libavcodec/ppc/dsputil_altivec.h \
|
||||||
|
ffmpeg/libavcodec/ppc/dsputil_ppc.h \
|
||||||
|
ffmpeg/libavcodec/ppc/gcc_fixes.h \
|
||||||
|
ffmpeg/libavformat/avformat.h \
|
||||||
|
ffmpeg/libavformat/avi.h \
|
||||||
|
ffmpeg/libavformat/avio.h \
|
||||||
|
ffmpeg/libavformat/barpainet.h \
|
||||||
|
ffmpeg/libavformat/dv.h \
|
||||||
|
ffmpeg/libavformat/dv1394.h \
|
||||||
|
ffmpeg/libavformat/framehook.h \
|
||||||
|
ffmpeg/libavformat/mpegts.h \
|
||||||
|
ffmpeg/libavformat/os_support.h \
|
||||||
|
ffmpeg/libavformat/rtp.h \
|
||||||
|
ffmpeg/libavformat/rtsp.h \
|
||||||
|
ffmpeg/libavformat/rtspcodes.h
|
||||||
|
|
||||||
|
DISTCLEANFILES = \
|
||||||
|
ffmpeg/config.h \
|
||||||
|
ffmpeg/config.mak
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
$(PATCHES) \
|
||||||
|
Tag \
|
||||||
|
ffmpeg/CREDITS \
|
||||||
|
ffmpeg/INSTALL \
|
||||||
|
ffmpeg/README \
|
||||||
|
ffmpeg/configure \
|
||||||
|
ffmpeg/ffmpeg.c \
|
||||||
|
ffmpeg/ffserver.c \
|
||||||
|
$(libavcodec_la_SOURCES) \
|
||||||
|
$(more_libavcodec_files) \
|
||||||
|
$(libavformat_la_SOURCES) \
|
||||||
|
$(files_i386) \
|
||||||
|
$(files_powerpc) \
|
||||||
|
$(all_headers)
|
||||||
|
|
13
gst/tags/Makefile.am
Normal file
13
gst/tags/Makefile.am
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
plugin_LTLIBRARIES = libgsttagediting.la
|
||||||
|
|
||||||
|
libgsttagediting_la_SOURCES = gstvorbistag.c gsttagediting.c gstmp3tag.c
|
||||||
|
libgsttagediting_la_CFLAGS = $(GST_CFLAGS)
|
||||||
|
libgsttagediting_la_LIBADD = $(GST_LIBS)
|
||||||
|
libgsttagediting_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
|
|
||||||
|
libgsttageditingincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/tags
|
||||||
|
libgsttageditinginclude_HEADERS = gsttagediting.h
|
||||||
|
|
||||||
|
noinst_HEADERS = gsttageditingprivate.h
|
||||||
|
|
331
gst/tags/gstmp3tag.c
Normal file
331
gst/tags/gstmp3tag.c
Normal file
|
@ -0,0 +1,331 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gstvorbistagsetter.c: plugin for reading / modifying vorbis tags
|
||||||
|
*
|
||||||
|
* 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 "gsttageditingprivate.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static const gchar *genres[] = {
|
||||||
|
"Blues",
|
||||||
|
"Classic Rock",
|
||||||
|
"Country",
|
||||||
|
"Dance",
|
||||||
|
"Disco",
|
||||||
|
"Funk",
|
||||||
|
"Grunge",
|
||||||
|
"Hip-Hop",
|
||||||
|
"Jazz",
|
||||||
|
"Metal",
|
||||||
|
"New Age",
|
||||||
|
"Oldies",
|
||||||
|
"Other",
|
||||||
|
"Pop",
|
||||||
|
"R&B",
|
||||||
|
"Rap",
|
||||||
|
"Reggae",
|
||||||
|
"Rock",
|
||||||
|
"Techno",
|
||||||
|
"Industrial",
|
||||||
|
"Alternative",
|
||||||
|
"Ska",
|
||||||
|
"Death Metal",
|
||||||
|
"Pranks",
|
||||||
|
"Soundtrack",
|
||||||
|
"Euro-Techno",
|
||||||
|
"Ambient",
|
||||||
|
"Trip-Hop",
|
||||||
|
"Vocal",
|
||||||
|
"Jazz+Funk",
|
||||||
|
"Fusion",
|
||||||
|
"Trance",
|
||||||
|
"Classical",
|
||||||
|
"Instrumental",
|
||||||
|
"Acid",
|
||||||
|
"House",
|
||||||
|
"Game",
|
||||||
|
"Sound Clip",
|
||||||
|
"Gospel",
|
||||||
|
"Noise",
|
||||||
|
"Alternative Rock",
|
||||||
|
"Bass",
|
||||||
|
"Soul",
|
||||||
|
"Punk",
|
||||||
|
"Space",
|
||||||
|
"Meditative",
|
||||||
|
"Instrumental Pop",
|
||||||
|
"Instrumental Rock",
|
||||||
|
"Ethnic",
|
||||||
|
"Gothic",
|
||||||
|
"Darkwave",
|
||||||
|
"Techno-Industrial",
|
||||||
|
"Electronic",
|
||||||
|
"Pop-Folk",
|
||||||
|
"Eurodance",
|
||||||
|
"Dream",
|
||||||
|
"Southern Rock",
|
||||||
|
"Comedy",
|
||||||
|
"Cult",
|
||||||
|
"Gangsta",
|
||||||
|
"Top 40",
|
||||||
|
"Christian Rap",
|
||||||
|
"Pop/Funk",
|
||||||
|
"Jungle",
|
||||||
|
"Native American",
|
||||||
|
"Cabaret",
|
||||||
|
"New Wave",
|
||||||
|
"Psychadelic",
|
||||||
|
"Rave",
|
||||||
|
"Showtunes",
|
||||||
|
"Trailer",
|
||||||
|
"Lo-Fi",
|
||||||
|
"Tribal",
|
||||||
|
"Acid Punk",
|
||||||
|
"Acid Jazz",
|
||||||
|
"Polka",
|
||||||
|
"Retro",
|
||||||
|
"Musical",
|
||||||
|
"Rock & Roll",
|
||||||
|
"Hard Rock",
|
||||||
|
"Folk",
|
||||||
|
"Folk/Rock",
|
||||||
|
"National Folk",
|
||||||
|
"Swing",
|
||||||
|
"Fusion",
|
||||||
|
"Bebob",
|
||||||
|
"Latin",
|
||||||
|
"Revival",
|
||||||
|
"Celtic",
|
||||||
|
"Bluegrass",
|
||||||
|
"Avantgarde",
|
||||||
|
"Gothic Rock",
|
||||||
|
"Progressive Rock",
|
||||||
|
"Psychadelic Rock",
|
||||||
|
"Symphonic Rock",
|
||||||
|
"Slow Rock",
|
||||||
|
"Big Band",
|
||||||
|
"Chorus",
|
||||||
|
"Easy Listening",
|
||||||
|
"Acoustic",
|
||||||
|
"Humour",
|
||||||
|
"Speech",
|
||||||
|
"Chanson",
|
||||||
|
"Opera",
|
||||||
|
"Chamber Music",
|
||||||
|
"Sonata",
|
||||||
|
"Symphony",
|
||||||
|
"Booty Bass",
|
||||||
|
"Primus",
|
||||||
|
"Porn Groove",
|
||||||
|
"Satire",
|
||||||
|
"Slow Jam",
|
||||||
|
"Club",
|
||||||
|
"Tango",
|
||||||
|
"Samba",
|
||||||
|
"Folklore",
|
||||||
|
"Ballad",
|
||||||
|
"Power Ballad",
|
||||||
|
"Rhythmic Soul",
|
||||||
|
"Freestyle",
|
||||||
|
"Duet",
|
||||||
|
"Punk Rock",
|
||||||
|
"Drum Solo",
|
||||||
|
"A Capella",
|
||||||
|
"Euro-House",
|
||||||
|
"Dance Hall",
|
||||||
|
"Goa",
|
||||||
|
"Drum & Bass",
|
||||||
|
"Club-House",
|
||||||
|
"Hardcore",
|
||||||
|
"Terror",
|
||||||
|
"Indie",
|
||||||
|
"BritPop",
|
||||||
|
"Negerpunk",
|
||||||
|
"Polsk Punk",
|
||||||
|
"Beat",
|
||||||
|
"Christian Gangsta Rap",
|
||||||
|
"Heavy Metal",
|
||||||
|
"Black Metal",
|
||||||
|
"Crossover",
|
||||||
|
"Contemporary Christian",
|
||||||
|
"Christian Rock",
|
||||||
|
"Merengue",
|
||||||
|
"Salsa",
|
||||||
|
"Thrash Metal",
|
||||||
|
"Anime",
|
||||||
|
"Jpop",
|
||||||
|
"Synthpop"
|
||||||
|
};
|
||||||
|
|
||||||
|
static GstTagEntryMatch tag_matches[] = {
|
||||||
|
{ GST_TAG_TITLE, "TIT2" },
|
||||||
|
{ GST_TAG_ALBUM, "TALB" },
|
||||||
|
{ GST_TAG_TRACK_NUMBER, "TRCK" },
|
||||||
|
{ GST_TAG_ARTIST, "TPE1" },
|
||||||
|
{ GST_TAG_COPYRIGHT, "TCOP" },
|
||||||
|
{ GST_TAG_GENRE, "TCON" },
|
||||||
|
{ GST_TAG_DATE, "TDRC" },
|
||||||
|
{ GST_TAG_COMMENT, "COMM" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* gst_tag_from_id3_tag:
|
||||||
|
* @id3_tag: ID3v2 tag to convert to GStreamer tag
|
||||||
|
*
|
||||||
|
* Looks up the GStreamer tag for a ID3v2 tag.
|
||||||
|
*
|
||||||
|
* Returns: The corresponding GStreamer tag or NULL if none exists.
|
||||||
|
*/
|
||||||
|
G_CONST_RETURN gchar *
|
||||||
|
gst_tag_from_id3_tag (const gchar *id3_tag)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
g_return_val_if_fail (id3_tag != NULL, NULL);
|
||||||
|
|
||||||
|
while (tag_matches[i].gstreamer_tag != NULL) {
|
||||||
|
if (strcmp (id3_tag, tag_matches[i].original_tag) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return tag_matches[i].gstreamer_tag;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_tag_to_id3_tag:
|
||||||
|
* @gst_tag: GStreamer tag to convert to vorbiscomment tag
|
||||||
|
*
|
||||||
|
* Looks up the ID3v2 tag for a GStreamer tag.
|
||||||
|
*
|
||||||
|
* Returns: The corresponding ID3v2 tag or NULL if none exists.
|
||||||
|
*/
|
||||||
|
G_CONST_RETURN gchar *
|
||||||
|
gst_tag_to_id3_tag (const gchar *gst_tag)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
g_return_val_if_fail (gst_tag != NULL, NULL);
|
||||||
|
|
||||||
|
while (tag_matches[i].gstreamer_tag != NULL) {
|
||||||
|
if (strcmp (gst_tag, tag_matches[i].gstreamer_tag) == 0) {
|
||||||
|
return tag_matches[i].original_tag;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_tag_extract (GstTagList *list, const gchar *tag, const gchar *start, const guint size)
|
||||||
|
{
|
||||||
|
gsize bytes_read;
|
||||||
|
gchar *conv;
|
||||||
|
|
||||||
|
/* FIXME: better charset detection? */
|
||||||
|
if (g_utf8_validate (start, size, NULL)) {
|
||||||
|
conv = g_strchomp (g_strndup (start, size));
|
||||||
|
} else {
|
||||||
|
conv = g_locale_to_utf8 (start, size, &bytes_read, NULL, NULL);
|
||||||
|
if (bytes_read != size) {
|
||||||
|
g_free (conv);
|
||||||
|
conv = g_convert (start, size, "UTF-8", "ISO-8859-1", &bytes_read, NULL, NULL);
|
||||||
|
if (bytes_read != size) {
|
||||||
|
g_free (conv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, tag, conv, NULL);
|
||||||
|
g_free (conv);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_tag_list_new_from_id3v1:
|
||||||
|
* @data: 128 bytes of data containing the ID3v1 tag
|
||||||
|
*
|
||||||
|
* Parses the data containing an ID3v1 tag and returns a #GstTagList from the
|
||||||
|
* parsed data.
|
||||||
|
*
|
||||||
|
* Returns: A new tag list or NULL if the data was not an ID3v1 tag.
|
||||||
|
*/
|
||||||
|
GstTagList *
|
||||||
|
gst_tag_list_new_from_id3v1 (const guint8 *data)
|
||||||
|
{
|
||||||
|
guint year;
|
||||||
|
gchar *ystr;
|
||||||
|
GstTagList *list;
|
||||||
|
|
||||||
|
g_return_val_if_fail (data != NULL, NULL);
|
||||||
|
|
||||||
|
if (data[0] == 'T' && data[1] == 'A' && data[2] == 'G') return NULL;
|
||||||
|
list = gst_tag_list_new ();
|
||||||
|
gst_tag_extract (list, GST_TAG_TITLE, &data[3], 30);
|
||||||
|
gst_tag_extract (list, GST_TAG_ARTIST, &data[33], 30);
|
||||||
|
gst_tag_extract (list, GST_TAG_ALBUM, &data[63], 30);
|
||||||
|
ystr = g_strndup (&data[93], 4);
|
||||||
|
year = strtoul (ystr, NULL, 10);
|
||||||
|
g_free (ystr);
|
||||||
|
if (year > 0) {
|
||||||
|
GDate *date = g_date_new_dmy (1, 1, year);
|
||||||
|
year = g_date_get_julian (date);
|
||||||
|
g_date_free (date);
|
||||||
|
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_DATE, year, NULL);
|
||||||
|
}
|
||||||
|
if (data[125] == 0) {
|
||||||
|
gst_tag_extract (list, GST_TAG_ALBUM, &data[97], 28);
|
||||||
|
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_NUMBER, (guint) data[126], NULL);
|
||||||
|
} else {
|
||||||
|
gst_tag_extract (list, GST_TAG_ALBUM, &data[97], 30);
|
||||||
|
}
|
||||||
|
if (data[127] < gst_tag_id3_genre_count ()) {
|
||||||
|
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_TRACK_NUMBER, gst_tag_id3_genre_get (data[126]), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_tag_id3_genre_count:
|
||||||
|
*
|
||||||
|
* Gets the number of ID3v1 genres that can be identified. Winamp genres are
|
||||||
|
* included.
|
||||||
|
*
|
||||||
|
* Returns: the number of ID3v1 genres that can be identified
|
||||||
|
*/
|
||||||
|
guint
|
||||||
|
gst_tag_id3_genre_count (void)
|
||||||
|
{
|
||||||
|
return G_N_ELEMENTS (genres);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_tag_id3_genre_get:
|
||||||
|
* @id: ID of genre to query
|
||||||
|
*
|
||||||
|
* Gets the ID3v1 genre name for a given ID.
|
||||||
|
*
|
||||||
|
* Returns: the genre or NULL if no genre is associated with that ID.
|
||||||
|
*/
|
||||||
|
G_CONST_RETURN gchar *
|
||||||
|
gst_tag_id3_genre_get (const guint id)
|
||||||
|
{
|
||||||
|
if (id >= G_N_ELEMENTS (genres)) return NULL;
|
||||||
|
return genres[id];
|
||||||
|
}
|
||||||
|
|
52
gst/tags/gsttagediting.c
Normal file
52
gst/tags/gsttagediting.c
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gstoggplugins.c: register ogg plugins
|
||||||
|
*
|
||||||
|
* 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 "gsttageditingprivate.h"
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
plugin_init(GstPlugin *plugin)
|
||||||
|
{
|
||||||
|
if (!gst_element_register (plugin, "vorbistag",
|
||||||
|
GST_RANK_PRIMARY, gst_vorbis_tag_get_type())) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_PLUGIN_DEFINE (
|
||||||
|
GST_VERSION_MAJOR,
|
||||||
|
GST_VERSION_MINOR,
|
||||||
|
"gsttags",
|
||||||
|
"elements for manipulating data from ogg streams",
|
||||||
|
plugin_init,
|
||||||
|
VERSION,
|
||||||
|
GST_LICENSE,
|
||||||
|
GST_COPYRIGHT,
|
||||||
|
GST_PACKAGE,
|
||||||
|
GST_ORIGIN
|
||||||
|
)
|
||||||
|
|
55
gst/tags/gsttagediting.h
Normal file
55
gst/tags/gsttagediting.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* 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_TAG_EDITING_H__
|
||||||
|
#define __GST_TAG_EDITING_H__
|
||||||
|
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
|
||||||
|
/* functions for vorbis comment manipulation */
|
||||||
|
|
||||||
|
G_CONST_RETURN gchar * gst_tag_from_vorbis_tag (const gchar * vorbis_tag);
|
||||||
|
G_CONST_RETURN gchar * gst_tag_to_vorbis_tag (const gchar * gst_tag);
|
||||||
|
/* functions to convert GstBuffers with vorbiscomment contents to GstTagLists and back */
|
||||||
|
GstTagList * gst_tag_list_from_vorbiscomment_buffer (const GstBuffer * buffer,
|
||||||
|
const guint8 * id_data,
|
||||||
|
const guint id_data_length,
|
||||||
|
gchar ** vendor_string);
|
||||||
|
GstBuffer * gst_tag_list_to_vorbiscomment_buffer (const GstTagList * list,
|
||||||
|
const guint8 * id_data,
|
||||||
|
const guint id_data_length,
|
||||||
|
const gchar * vendor_string);
|
||||||
|
|
||||||
|
/* functions for ID3 tag manipulation */
|
||||||
|
|
||||||
|
guint gst_tag_id3_genre_count (void);
|
||||||
|
G_CONST_RETURN gchar * gst_tag_id3_genre_get (const guint id);
|
||||||
|
GstTagList * gst_tag_list_new_from_id3v1 (const guint8 * data);
|
||||||
|
|
||||||
|
G_CONST_RETURN gchar * gst_tag_from_id3_tag (const gchar * vorbis_tag);
|
||||||
|
G_CONST_RETURN gchar * gst_tag_to_id3_tag (const gchar * gst_tag);
|
||||||
|
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_TAG_EDITING_H__ */
|
41
gst/tags/gsttageditingprivate.h
Normal file
41
gst/tags/gsttageditingprivate.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* 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_OGG_PLUGINS_H__
|
||||||
|
#define __GST_OGG_PLUGINS_H__
|
||||||
|
|
||||||
|
#include <gst/tags/gsttagediting.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _GstTagEntryMatch GstTagEntryMatch;
|
||||||
|
struct _GstTagEntryMatch {
|
||||||
|
gchar * gstreamer_tag;
|
||||||
|
gchar * original_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GType gst_vorbis_tag_get_type (void);
|
||||||
|
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GST_OGG_PLUGINS_H__ */
|
563
gst/tags/gstvorbistag.c
Normal file
563
gst/tags/gstvorbistag.c
Normal file
|
@ -0,0 +1,563 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
||||||
|
*
|
||||||
|
* gstvorbistagsetter.c: plugin for reading / modifying vorbis tags
|
||||||
|
*
|
||||||
|
* 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 <gst/gsttaginterface.h>
|
||||||
|
#include "gsttageditingprivate.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_STATIC (gst_vorbis_tag_debug);
|
||||||
|
#define GST_CAT_DEFAULT gst_vorbis_tag_debug
|
||||||
|
|
||||||
|
#define GST_TYPE_VORBIS_TAG (gst_vorbis_tag_get_type())
|
||||||
|
#define GST_VORBIS_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBIS_TAG, GstVorbisTag))
|
||||||
|
#define GST_VORBIS_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBIS_TAG, GstVorbisTag))
|
||||||
|
#define GST_IS_VORBIS_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBIS_TAG))
|
||||||
|
#define GST_IS_VORBIS_TAG_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBIS_TAG))
|
||||||
|
|
||||||
|
typedef struct _GstVorbisTag GstVorbisTag;
|
||||||
|
typedef struct _GstVorbisTagClass GstVorbisTagClass;
|
||||||
|
|
||||||
|
struct _GstVorbisTag {
|
||||||
|
GstElement element;
|
||||||
|
|
||||||
|
/* pads */
|
||||||
|
GstPad * sinkpad;
|
||||||
|
GstPad * srcpad;
|
||||||
|
|
||||||
|
/* output mode */
|
||||||
|
guint output;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstVorbisTagClass {
|
||||||
|
GstElementClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* elementfactory information */
|
||||||
|
static GstElementDetails gst_vorbis_tag_details = GST_ELEMENT_DETAILS (
|
||||||
|
"vorbis tag extractor",
|
||||||
|
"Tag",
|
||||||
|
"Extract tagging information from vorbis streams",
|
||||||
|
"Benjamin Otte <in7y118@public.uni-hamburg.de>"
|
||||||
|
);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OUTPUT_UNKNOWN,
|
||||||
|
OUTPUT_TAGS,
|
||||||
|
OUTPUT_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
/* signals and args */
|
||||||
|
enum {
|
||||||
|
/* FILL ME */
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (vorbis_tag_src_template_factory,
|
||||||
|
"src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_NEW (
|
||||||
|
"vorbis_tag_data_src",
|
||||||
|
"application/x-vorbis",
|
||||||
|
NULL
|
||||||
|
),
|
||||||
|
GST_CAPS_NEW (
|
||||||
|
"vorbis_tag_tag_src",
|
||||||
|
"application/x-gst-tags",
|
||||||
|
NULL
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
GST_PAD_TEMPLATE_FACTORY (vorbis_tag_sink_template_factory,
|
||||||
|
"sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_CAPS_NEW (
|
||||||
|
"vorbis_tag_data_sink",
|
||||||
|
"application/x-vorbis",
|
||||||
|
NULL
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
static void gst_vorbis_tag_base_init (gpointer g_class);
|
||||||
|
static void gst_vorbis_tag_class_init (gpointer g_class,
|
||||||
|
gpointer class_data);
|
||||||
|
static void gst_vorbis_tag_init (GTypeInstance * instance,
|
||||||
|
gpointer g_class);
|
||||||
|
|
||||||
|
static void gst_vorbis_tag_chain (GstPad * pad,
|
||||||
|
GstData * data);
|
||||||
|
|
||||||
|
static GstElementStateReturn gst_vorbis_tag_change_state (GstElement * element);
|
||||||
|
|
||||||
|
static GstElementClass *parent_class = NULL;
|
||||||
|
/* static guint gst_vorbis_tag_signals[LAST_SIGNAL] = { 0 }; */
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_vorbis_tag_get_type (void)
|
||||||
|
{
|
||||||
|
static GType vorbis_tag_type = 0;
|
||||||
|
|
||||||
|
if (!vorbis_tag_type) {
|
||||||
|
static const GTypeInfo vorbis_tag_info = {
|
||||||
|
sizeof (GstVorbisTagClass),
|
||||||
|
gst_vorbis_tag_base_init,
|
||||||
|
NULL,
|
||||||
|
gst_vorbis_tag_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstVorbisTag),
|
||||||
|
0,
|
||||||
|
gst_vorbis_tag_init,
|
||||||
|
};
|
||||||
|
static const GInterfaceInfo tag_setter_info = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
vorbis_tag_type = g_type_register_static(GST_TYPE_ELEMENT, "GstVorbisTag", &vorbis_tag_info, 0);
|
||||||
|
|
||||||
|
g_type_add_interface_static (vorbis_tag_type, GST_TYPE_TAG_SETTER, &tag_setter_info);
|
||||||
|
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_vorbis_tag_debug, "vorbistag", 0, "vorbis tagging element");
|
||||||
|
}
|
||||||
|
return vorbis_tag_type;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_vorbis_tag_base_init (gpointer g_class)
|
||||||
|
{
|
||||||
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
|
gst_element_class_set_details (element_class, &gst_vorbis_tag_details);
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
GST_PAD_TEMPLATE_GET (vorbis_tag_sink_template_factory));
|
||||||
|
gst_element_class_add_pad_template (element_class,
|
||||||
|
GST_PAD_TEMPLATE_GET (vorbis_tag_src_template_factory));
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_vorbis_tag_class_init (gpointer g_class, gpointer class_data)
|
||||||
|
{
|
||||||
|
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
|
||||||
|
|
||||||
|
parent_class = g_type_class_peek_parent (g_class);
|
||||||
|
|
||||||
|
gstelement_class->change_state = gst_vorbis_tag_change_state;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_vorbis_tag_init (GTypeInstance *instance, gpointer g_class)
|
||||||
|
{
|
||||||
|
GstVorbisTag *tag = GST_VORBIS_TAG (instance);
|
||||||
|
|
||||||
|
/* create the sink and src pads */
|
||||||
|
tag->sinkpad = gst_pad_new_from_template(
|
||||||
|
GST_PAD_TEMPLATE_GET (vorbis_tag_sink_template_factory), "sink");
|
||||||
|
gst_element_add_pad (GST_ELEMENT (tag), tag->sinkpad);
|
||||||
|
gst_pad_set_chain_function (tag->sinkpad, GST_DEBUG_FUNCPTR (gst_vorbis_tag_chain));
|
||||||
|
|
||||||
|
tag->srcpad = gst_pad_new_from_template(
|
||||||
|
GST_PAD_TEMPLATE_GET (vorbis_tag_src_template_factory), "src");
|
||||||
|
gst_element_add_pad (GST_ELEMENT (tag), tag->srcpad);
|
||||||
|
}
|
||||||
|
static GstTagEntryMatch tag_matches[] = {
|
||||||
|
{ GST_TAG_TITLE, "TITLE" },
|
||||||
|
{ GST_TAG_VERSION, "VERSION" },
|
||||||
|
{ GST_TAG_ALBUM, "ALBUM" },
|
||||||
|
{ GST_TAG_TRACK_NUMBER,"TRACKNUMBER" },
|
||||||
|
{ GST_TAG_ARTIST, "ARTIST" },
|
||||||
|
{ GST_TAG_PERFORMER, "PERFORMER" },
|
||||||
|
{ GST_TAG_COPYRIGHT, "COPYRIGHT" },
|
||||||
|
{ GST_TAG_LICENSE, "LICENSE" },
|
||||||
|
{ GST_TAG_ORGANIZATION,"ORGANIZATION" },
|
||||||
|
{ GST_TAG_DESCRIPTION,"DESCRIPTION" },
|
||||||
|
{ GST_TAG_GENRE, "GENRE" },
|
||||||
|
{ GST_TAG_DATE, "DATE" },
|
||||||
|
{ GST_TAG_CONTACT, "CONTACT" },
|
||||||
|
{ GST_TAG_ISRC, "ISRC" },
|
||||||
|
{ GST_TAG_COMMENT, "COMMENT" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* gst_tag_from_vorbis_tag:
|
||||||
|
* @vorbis_tag: vorbiscomment tag to convert to GStreamer tag
|
||||||
|
*
|
||||||
|
* Looks up the GStreamer tag for a vorbiscommment tag.
|
||||||
|
*
|
||||||
|
* Returns: The corresponding GStreamer tag or NULL if none exists.
|
||||||
|
*/
|
||||||
|
G_CONST_RETURN gchar *
|
||||||
|
gst_tag_from_vorbis_tag (const gchar *vorbis_tag)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
gchar *real_vorbis_tag;
|
||||||
|
|
||||||
|
g_return_val_if_fail (vorbis_tag != NULL, NULL);
|
||||||
|
|
||||||
|
real_vorbis_tag = g_ascii_strup (vorbis_tag, -1);
|
||||||
|
while (tag_matches[i].gstreamer_tag != NULL) {
|
||||||
|
if (strcmp (real_vorbis_tag, tag_matches[i].original_tag) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
g_free (real_vorbis_tag);
|
||||||
|
return tag_matches[i].gstreamer_tag;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_tag_to_vorbis_tag:
|
||||||
|
* @gst_tag: GStreamer tag to convert to vorbiscomment tag
|
||||||
|
*
|
||||||
|
* Looks up the vorbiscommment tag for a GStreamer tag.
|
||||||
|
*
|
||||||
|
* Returns: The corresponding vorbiscommment tag or NULL if none exists.
|
||||||
|
*/
|
||||||
|
G_CONST_RETURN gchar *
|
||||||
|
gst_tag_to_vorbis_tag (const gchar *gst_tag)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
g_return_val_if_fail (gst_tag != NULL, NULL);
|
||||||
|
|
||||||
|
while (tag_matches[i].gstreamer_tag != NULL) {
|
||||||
|
if (strcmp (gst_tag, tag_matches[i].gstreamer_tag) == 0) {
|
||||||
|
return tag_matches[i].original_tag;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_tag_add (GstTagList *list, const gchar *tag, const gchar *value)
|
||||||
|
{
|
||||||
|
const gchar *gst_tag = gst_tag_from_vorbis_tag (tag);
|
||||||
|
|
||||||
|
if (gst_tag == NULL) return;
|
||||||
|
|
||||||
|
switch (gst_tag_get_type (gst_tag)) {
|
||||||
|
case G_TYPE_UINT:
|
||||||
|
if (strcmp (gst_tag, GST_TAG_DATE) == 0) {
|
||||||
|
GDate *date;
|
||||||
|
guint y, d = 1, m = 1;
|
||||||
|
gchar *check = (gchar *) value;
|
||||||
|
y = strtoul (check, &check, 10);
|
||||||
|
if (*check == '-') {
|
||||||
|
check++;
|
||||||
|
m = strtoul (check, &check, 10);
|
||||||
|
if (*check == '-') {
|
||||||
|
check++;
|
||||||
|
d = strtoul (check, &check, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*check != '\0') break;
|
||||||
|
if (y == 0) break;
|
||||||
|
date = g_date_new_dmy (d, m, y);
|
||||||
|
y = g_date_get_julian (date);
|
||||||
|
g_date_free (date);
|
||||||
|
gst_tag_list_add (list, GST_TAG_MERGE_APPEND, gst_tag, y, NULL);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
guint tmp;
|
||||||
|
gchar *check;
|
||||||
|
tmp = strtoul (value, &check, 10);
|
||||||
|
if (*check == '/' && strcmp (gst_tag, GST_TAG_TRACK_NUMBER) == 0) {
|
||||||
|
guint count;
|
||||||
|
check++;
|
||||||
|
count = strtoul (check, &check, 10);
|
||||||
|
if (*check != '\0' || count == 0) break;
|
||||||
|
gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_TRACK_COUNT, count, NULL);
|
||||||
|
}
|
||||||
|
if (*check != '\0') break;
|
||||||
|
gst_tag_list_add (list, GST_TAG_MERGE_APPEND, gst_tag, tmp, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case G_TYPE_STRING:
|
||||||
|
gst_tag_list_add (list, GST_TAG_MERGE_APPEND, gst_tag, value, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_tag_list_from_vorbiscomment_buffer:
|
||||||
|
* @buffer: buffer to convert
|
||||||
|
* @id_data: identification data at start of stream
|
||||||
|
* @id_data_length: length of identification data
|
||||||
|
* @ vendor_string: pointer to a string that should take the vendor string of this
|
||||||
|
* vorbis comment or NULL if you don't need it.
|
||||||
|
*
|
||||||
|
* Creates a new tag list that contains the information parsed out of a
|
||||||
|
* vorbiscomment packet.
|
||||||
|
*
|
||||||
|
* Returns: A new #GstTagList with all tags that could be extracted from the
|
||||||
|
* given vorbiscomment buffer or NULL on error.
|
||||||
|
*/
|
||||||
|
GstTagList *
|
||||||
|
gst_tag_list_from_vorbiscomment_buffer (const GstBuffer *buffer, const guint8 *id_data,
|
||||||
|
const guint id_data_length, gchar **vendor_string)
|
||||||
|
{
|
||||||
|
#define ADVANCE(x) G_STMT_START{ \
|
||||||
|
data += x; \
|
||||||
|
size -= x; \
|
||||||
|
if (size < 4) goto error; \
|
||||||
|
cur_size = GUINT32_FROM_LE (*((guint32 *) data)); \
|
||||||
|
data += 4; \
|
||||||
|
size -= 4; \
|
||||||
|
if (cur_size >= size) goto error; \
|
||||||
|
cur = data; \
|
||||||
|
}G_STMT_END
|
||||||
|
gchar *cur, *value;
|
||||||
|
guint cur_size;
|
||||||
|
guint iterations;
|
||||||
|
guint8 *data;
|
||||||
|
guint size;
|
||||||
|
GstTagList *list;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
|
||||||
|
g_return_val_if_fail (id_data != NULL, NULL);
|
||||||
|
g_return_val_if_fail (id_data_length > 0, NULL);
|
||||||
|
|
||||||
|
data = GST_BUFFER_DATA (buffer);
|
||||||
|
size = GST_BUFFER_SIZE (buffer);
|
||||||
|
list = gst_tag_list_new ();
|
||||||
|
|
||||||
|
if (size < 11) goto error;
|
||||||
|
if (memcmp (data, id_data, id_data_length) != 0) goto error;
|
||||||
|
ADVANCE (id_data_length);
|
||||||
|
if (vendor_string) *vendor_string = g_strndup (cur, cur_size);
|
||||||
|
ADVANCE (cur_size);
|
||||||
|
iterations = cur_size;
|
||||||
|
cur_size = 0;
|
||||||
|
while (iterations) {
|
||||||
|
ADVANCE (cur_size);
|
||||||
|
iterations--;
|
||||||
|
cur = g_strndup (cur, cur_size);
|
||||||
|
value = strchr(cur, '=');
|
||||||
|
if (value == NULL) {
|
||||||
|
g_free (cur);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*value = '\0';
|
||||||
|
value++;
|
||||||
|
if (!g_utf8_validate (value, -1, NULL)) {
|
||||||
|
g_free (cur);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
gst_tag_add (list, cur, value);
|
||||||
|
g_free (cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
|
||||||
|
error:
|
||||||
|
gst_tag_list_free (list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
typedef struct {
|
||||||
|
guint count;
|
||||||
|
guint data_count;
|
||||||
|
GList *entries;
|
||||||
|
} MyForEach;
|
||||||
|
static void
|
||||||
|
write_one_tag (const GstTagList *list, const gchar *tag, gpointer user_data)
|
||||||
|
{
|
||||||
|
gchar *result;
|
||||||
|
guint i;
|
||||||
|
const gchar *vorbis_tag = gst_tag_to_vorbis_tag (tag);
|
||||||
|
MyForEach *data = (MyForEach *) user_data;
|
||||||
|
|
||||||
|
if (!vorbis_tag) return;
|
||||||
|
for (i = 0; i < gst_tag_list_get_tag_size (list, tag); i++) {
|
||||||
|
switch (gst_tag_get_type (tag)) {
|
||||||
|
case G_TYPE_UINT:
|
||||||
|
if (strcmp (tag, GST_TAG_DATE) == 0) {
|
||||||
|
GDate *date;
|
||||||
|
guint u;
|
||||||
|
|
||||||
|
g_assert (gst_tag_list_get_uint_index (list, tag, i, &u));
|
||||||
|
date = g_date_new_julian (u);
|
||||||
|
/* vorbis suggests using ISO date formats */
|
||||||
|
result = g_strdup_printf ("%s=%04d-%02d-%02d", vorbis_tag, (gint) g_date_get_year (date),
|
||||||
|
(gint) g_date_get_month (date), (gint) g_date_get_day (date));
|
||||||
|
g_date_free (date);
|
||||||
|
} else {
|
||||||
|
guint u;
|
||||||
|
|
||||||
|
g_assert (gst_tag_list_get_uint_index (list, tag, i, &u));
|
||||||
|
result = g_strdup_printf ("%s=%u", vorbis_tag, u);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case G_TYPE_STRING: {
|
||||||
|
gchar *str;
|
||||||
|
g_assert (gst_tag_list_get_string_index (list, tag, i, &str));
|
||||||
|
result = g_strdup_printf ("%s=%s", vorbis_tag, str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
GST_DEBUG ("Couldn't write tag %s", tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data->count ++;
|
||||||
|
data->data_count += strlen (result);
|
||||||
|
data->entries = g_list_prepend (data->entries, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* gst_tag_list_to_vorbiscomment_buffer:
|
||||||
|
* @buffer: tag list to convert
|
||||||
|
* @id_data: identification data at start of stream
|
||||||
|
* @id_data_length: length of identification data
|
||||||
|
* @ vendor_string: string that describes the vendor string or NULL
|
||||||
|
*
|
||||||
|
* Creates a new vorbiscomment buffer from a tag list.
|
||||||
|
*
|
||||||
|
* Returns: A new #GstBuffer containing a vorbiscomment buffer with all tags that
|
||||||
|
* could be converted from the given tag list.
|
||||||
|
*/
|
||||||
|
GstBuffer *
|
||||||
|
gst_tag_list_to_vorbiscomment_buffer (const GstTagList *list, const guint8 *id_data,
|
||||||
|
const guint id_data_length, const gchar *vendor_string)
|
||||||
|
{
|
||||||
|
GstBuffer *buffer;
|
||||||
|
guint8 *data;
|
||||||
|
guint i;
|
||||||
|
GList *l;
|
||||||
|
MyForEach my_data = { 0, 0, NULL };
|
||||||
|
guint vendor_len;
|
||||||
|
int required_size;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GST_IS_TAG_LIST (list), NULL);
|
||||||
|
g_return_val_if_fail (id_data != NULL, NULL);
|
||||||
|
g_return_val_if_fail (id_data_length > 0, NULL);
|
||||||
|
|
||||||
|
if (vendor_string == NULL)
|
||||||
|
vendor_string = "GStreamer encoded vorbiscomment";
|
||||||
|
vendor_len = strlen (vendor_string);
|
||||||
|
required_size = id_data_length + 4 + vendor_len + 4 + 1;
|
||||||
|
gst_tag_list_foreach ((GstTagList *) list, write_one_tag, &my_data);
|
||||||
|
required_size += 4 * my_data.count + my_data.data_count;
|
||||||
|
buffer = gst_buffer_new_and_alloc (required_size);
|
||||||
|
data = GST_BUFFER_DATA (buffer);
|
||||||
|
memcpy (data, id_data, id_data_length);
|
||||||
|
data += id_data_length;
|
||||||
|
*((guint32 *) data) = GUINT32_TO_LE (vendor_len);
|
||||||
|
data += 4;
|
||||||
|
memcpy (data, vendor_string, vendor_len);
|
||||||
|
data += vendor_len;
|
||||||
|
l = my_data.entries = g_list_reverse (my_data.entries);
|
||||||
|
*((guint32 *) data) = GUINT32_TO_LE (my_data.count);
|
||||||
|
data += 4;
|
||||||
|
for (i = 0; i < my_data.count; i++) {
|
||||||
|
g_assert (l != NULL);
|
||||||
|
gchar *cur = l->data;
|
||||||
|
l = g_list_next (l);
|
||||||
|
guint size = strlen (cur);
|
||||||
|
*((guint32 *) data) = GUINT32_TO_LE (size);
|
||||||
|
data += 4;
|
||||||
|
memcpy (data, cur, size);
|
||||||
|
data += size;
|
||||||
|
}
|
||||||
|
g_list_free (my_data.entries);
|
||||||
|
*data = 1;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
gst_vorbis_tag_chain (GstPad *pad, GstData *data)
|
||||||
|
{
|
||||||
|
GstVorbisTag *tag;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
|
||||||
|
buffer = GST_BUFFER (data);
|
||||||
|
tag = GST_VORBIS_TAG (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
if (tag->output == OUTPUT_UNKNOWN) {
|
||||||
|
/* caps nego */
|
||||||
|
do {
|
||||||
|
if (gst_pad_try_set_caps (tag->srcpad, GST_CAPS_NEW ("vorbis_tag_data_src", "application/x-vorbis", NULL)) >= 0) {
|
||||||
|
tag->output = OUTPUT_DATA;
|
||||||
|
} else if (gst_pad_try_set_caps (tag->srcpad, GST_CAPS_NEW ("vorbis_tag_tag_src", "application/x-gst-tags", NULL)) >= 0) {
|
||||||
|
tag->output = OUTPUT_TAGS;
|
||||||
|
} else {
|
||||||
|
GstCaps *caps = gst_pad_template_get_caps (GST_PAD_TEMPLATE_GET (vorbis_tag_src_template_factory));
|
||||||
|
if (gst_pad_recover_caps_error (tag->srcpad, caps))
|
||||||
|
continue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_BUFFER_SIZE (buffer) == 0)
|
||||||
|
gst_element_error (GST_ELEMENT (tag), "empty buffers are not allowed in vorbis data");
|
||||||
|
|
||||||
|
if (GST_BUFFER_DATA (buffer)[0] == 3) {
|
||||||
|
gchar *vendor;
|
||||||
|
GstTagList *list = gst_tag_list_from_vorbiscomment_buffer (buffer, "\003vorbis", 7, &vendor);
|
||||||
|
|
||||||
|
gst_data_unref (data);
|
||||||
|
if (list == NULL) {
|
||||||
|
gst_element_error (GST_ELEMENT (tag), "invalid data in vorbis comments");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gst_element_found_tags_for_pad (GST_ELEMENT (tag), tag->srcpad, 0,
|
||||||
|
gst_tag_list_copy (list));
|
||||||
|
gst_tag_list_merge (list, gst_tag_setter_get_list (GST_TAG_SETTER (tag)), gst_tag_setter_get_merge_mode (GST_TAG_SETTER (tag)));
|
||||||
|
data = GST_DATA (gst_tag_list_to_vorbiscomment_buffer (list, "\003vorbis", 7, vendor));
|
||||||
|
gst_tag_list_free (list);
|
||||||
|
g_free (vendor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag->output == OUTPUT_DATA) {
|
||||||
|
gst_pad_push (tag->srcpad, data);
|
||||||
|
} else {
|
||||||
|
gst_data_unref (data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static GstElementStateReturn
|
||||||
|
gst_vorbis_tag_change_state (GstElement *element)
|
||||||
|
{
|
||||||
|
GstVorbisTag *tag;
|
||||||
|
|
||||||
|
tag = GST_VORBIS_TAG (element);
|
||||||
|
|
||||||
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
|
case GST_STATE_NULL_TO_READY:
|
||||||
|
break;
|
||||||
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
/* do something to get out of the chain function faster */
|
||||||
|
break;
|
||||||
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_READY:
|
||||||
|
tag->output = OUTPUT_UNKNOWN;
|
||||||
|
break;
|
||||||
|
case GST_STATE_READY_TO_NULL:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent_class->change_state (element);
|
||||||
|
}
|
|
@ -860,6 +860,41 @@ dv_type_find (GstTypeFind *tf, gpointer private)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** application/x-vorbis *****************************************************/
|
||||||
|
|
||||||
|
#define VORBIS_CAPS GST_CAPS_NEW ("vorbis_type_find", "application/x-vorbis", NULL)
|
||||||
|
static void
|
||||||
|
vorbis_type_find (GstTypeFind *tf, gpointer private)
|
||||||
|
{
|
||||||
|
guint8 *data = gst_type_find_peek (tf, 0, 30);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
guint blocksize_0;
|
||||||
|
guint blocksize_1;
|
||||||
|
/* 1 byte packet type (identification=0x01)
|
||||||
|
6 byte string "vorbis"
|
||||||
|
4 byte vorbis version */
|
||||||
|
if (memcmp (data, "\001vorbis\000\000\000\000", 11) != 0) return;
|
||||||
|
data += 11;
|
||||||
|
/* 1 byte channels must be != 0 */
|
||||||
|
if (data[0] == 0) return;
|
||||||
|
data++;
|
||||||
|
/* 4 byte samplerate must be != 0 */
|
||||||
|
if (*((guint32 *) data) == 0) return;
|
||||||
|
data += 16;
|
||||||
|
/* blocksize checks */
|
||||||
|
blocksize_0 = data[0] & 0x0F;
|
||||||
|
blocksize_1 = (data[0] & 0xF0) >> 4;
|
||||||
|
if (blocksize_0 > blocksize_1) return;
|
||||||
|
if (blocksize_0 < 6 || blocksize_0 > 13) return;
|
||||||
|
if (blocksize_1 < 6 || blocksize_1 > 13) return;
|
||||||
|
data++;
|
||||||
|
/* framing bit */
|
||||||
|
if ((data[0] & 0x01) != 1) return;
|
||||||
|
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, VORBIS_CAPS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*** generic typefind for streams that have some data at a specific position***/
|
/*** generic typefind for streams that have some data at a specific position***/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -1046,6 +1081,8 @@ plugin_init (GstPlugin *plugin)
|
||||||
zip_exts, "PK\003\004", 4, GST_TYPE_FIND_LIKELY);
|
zip_exts, "PK\003\004", 4, GST_TYPE_FIND_LIKELY);
|
||||||
TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-compress", GST_RANK_SECONDARY,
|
TYPE_FIND_REGISTER_START_WITH (plugin, "application/x-compress", GST_RANK_SECONDARY,
|
||||||
compress_exts, "\037\235", 2, GST_TYPE_FIND_LIKELY);
|
compress_exts, "\037\235", 2, GST_TYPE_FIND_LIKELY);
|
||||||
|
TYPE_FIND_REGISTER (plugin, "application/x-vorbis", GST_RANK_PRIMARY,
|
||||||
|
vorbis_type_find, NULL, VORBIS_CAPS, NULL);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,10 @@ AC_DEFUN(AS_SLURP_FFMPEG,
|
||||||
DIRECTORY=`pwd`
|
DIRECTORY=`pwd`
|
||||||
# get/update cvs
|
# get/update cvs
|
||||||
if test ! -d $1; then mkdir -p $1; fi
|
if test ! -d $1; then mkdir -p $1; fi
|
||||||
cd $1
|
dnl we need to check $srcdir/$1 or it will always checkout ffmpeg even if it is there
|
||||||
|
dnl at least when top_srcdir != top_builddir.
|
||||||
|
dnl FIXME: unfortunately this makes the checkout go into top_srcdir
|
||||||
|
cd $srcdir/$1
|
||||||
|
|
||||||
if test ! -e ffmpeg/README; then
|
if test ! -e ffmpeg/README; then
|
||||||
# check out cvs code
|
# check out cvs code
|
||||||
|
|
102
m4/ogg.m4
Normal file
102
m4/ogg.m4
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
# Configure paths for libogg
|
||||||
|
# Jack Moffitt <jack@icecast.org> 10-21-2000
|
||||||
|
# Shamelessly stolen from Owen Taylor and Manish Singh
|
||||||
|
|
||||||
|
dnl XIPH_PATH_OGG([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
|
||||||
|
dnl Test for libogg, and define OGG_CFLAGS and OGG_LIBS
|
||||||
|
dnl
|
||||||
|
AC_DEFUN(XIPH_PATH_OGG,
|
||||||
|
[dnl
|
||||||
|
dnl Get the cflags and libraries
|
||||||
|
dnl
|
||||||
|
AC_ARG_WITH(ogg,[ --with-ogg=PFX Prefix where libogg is installed (optional)], ogg_prefix="$withval", ogg_prefix="")
|
||||||
|
AC_ARG_WITH(ogg-libraries,[ --with-ogg-libraries=DIR Directory where libogg library is installed (optional)], ogg_libraries="$withval", ogg_libraries="")
|
||||||
|
AC_ARG_WITH(ogg-includes,[ --with-ogg-includes=DIR Directory where libogg header files are installed (optional)], ogg_includes="$withval", ogg_includes="")
|
||||||
|
AC_ARG_ENABLE(oggtest, [ --disable-oggtest Do not try to compile and run a test Ogg program],, enable_oggtest=yes)
|
||||||
|
|
||||||
|
if test "x$ogg_libraries" != "x" ; then
|
||||||
|
OGG_LIBS="-L$ogg_libraries"
|
||||||
|
elif test "x$ogg_prefix" != "x" ; then
|
||||||
|
OGG_LIBS="-L$ogg_prefix/lib"
|
||||||
|
elif test "x$prefix" != "xNONE" ; then
|
||||||
|
OGG_LIBS="-L$prefix/lib"
|
||||||
|
fi
|
||||||
|
|
||||||
|
OGG_LIBS="$OGG_LIBS -logg"
|
||||||
|
|
||||||
|
if test "x$ogg_includes" != "x" ; then
|
||||||
|
OGG_CFLAGS="-I$ogg_includes"
|
||||||
|
elif test "x$ogg_prefix" != "x" ; then
|
||||||
|
OGG_CFLAGS="-I$ogg_prefix/include"
|
||||||
|
elif test "$prefix" != "xNONE"; then
|
||||||
|
OGG_CFLAGS="-I$prefix/include"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING(for Ogg)
|
||||||
|
no_ogg=""
|
||||||
|
|
||||||
|
|
||||||
|
if test "x$enable_oggtest" = "xyes" ; then
|
||||||
|
ac_save_CFLAGS="$CFLAGS"
|
||||||
|
ac_save_LIBS="$LIBS"
|
||||||
|
CFLAGS="$CFLAGS $OGG_CFLAGS"
|
||||||
|
LIBS="$LIBS $OGG_LIBS"
|
||||||
|
dnl
|
||||||
|
dnl Now check if the installed Ogg is sufficiently new.
|
||||||
|
dnl
|
||||||
|
rm -f conf.oggtest
|
||||||
|
AC_TRY_RUN([
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
system("touch conf.oggtest");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
],, no_ogg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
|
||||||
|
CFLAGS="$ac_save_CFLAGS"
|
||||||
|
LIBS="$ac_save_LIBS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$no_ogg" = "x" ; then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
ifelse([$1], , :, [$1])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
if test -f conf.oggtest ; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
echo "*** Could not run Ogg test program, checking why..."
|
||||||
|
CFLAGS="$CFLAGS $OGG_CFLAGS"
|
||||||
|
LIBS="$LIBS $OGG_LIBS"
|
||||||
|
AC_TRY_LINK([
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
], [ return 0; ],
|
||||||
|
[ echo "*** The test program compiled, but did not run. This usually means"
|
||||||
|
echo "*** that the run-time linker is not finding Ogg or finding the wrong"
|
||||||
|
echo "*** version of Ogg. If it is not finding Ogg, you'll need to set your"
|
||||||
|
echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
|
||||||
|
echo "*** to the installed location Also, make sure you have run ldconfig if that"
|
||||||
|
echo "*** is required on your system"
|
||||||
|
echo "***"
|
||||||
|
echo "*** If you have an old version installed, it is best to remove it, although"
|
||||||
|
echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
|
||||||
|
[ echo "*** The test program failed to compile or link. See the file config.log for the"
|
||||||
|
echo "*** exact error that occured. This usually means Ogg was incorrectly installed"
|
||||||
|
echo "*** or that you have moved Ogg since it was installed." ])
|
||||||
|
CFLAGS="$ac_save_CFLAGS"
|
||||||
|
LIBS="$ac_save_LIBS"
|
||||||
|
fi
|
||||||
|
OGG_CFLAGS=""
|
||||||
|
OGG_LIBS=""
|
||||||
|
ifelse([$2], , :, [$2])
|
||||||
|
fi
|
||||||
|
AC_SUBST(OGG_CFLAGS)
|
||||||
|
AC_SUBST(OGG_LIBS)
|
||||||
|
rm -f conf.oggtest
|
||||||
|
])
|
|
@ -42,7 +42,7 @@ pkgconfig_DATA = \
|
||||||
gstreamer-play-@GST_MAJORMINOR@.pc \
|
gstreamer-play-@GST_MAJORMINOR@.pc \
|
||||||
gstreamer-interfaces-@GST_MAJORMINOR@.pc
|
gstreamer-interfaces-@GST_MAJORMINOR@.pc
|
||||||
|
|
||||||
CLEANFILES = $(pcfiles) $(pcfiles_uninstalled)
|
CLEANFILES = $(pcfiles) $(pcfiles_uninstalled) $(GCONF_PC) $(GCONF_PC_UNINSTALLED)
|
||||||
EXTRA_DIST= \
|
EXTRA_DIST= \
|
||||||
gstreamer-libs.pc.in gstreamer-libs-uninstalled.pc.in \
|
gstreamer-libs.pc.in gstreamer-libs-uninstalled.pc.in \
|
||||||
gstreamer-play.pc.in gstreamer-play-uninstalled.pc.in
|
gstreamer-play.pc.in gstreamer-play-uninstalled.pc.in
|
||||||
|
|
1
tests/old/testsuite/alsa/.gitignore
vendored
1
tests/old/testsuite/alsa/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
formats
|
formats
|
||||||
|
state
|
||||||
|
|
1
testsuite/alsa/.gitignore
vendored
1
testsuite/alsa/.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
formats
|
formats
|
||||||
|
state
|
||||||
|
|
4
testsuite/autoplug/.gitignore
vendored
Normal file
4
testsuite/autoplug/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
autoplug
|
||||||
|
autoplug2
|
||||||
|
autoplug3
|
||||||
|
autoplug4
|
Loading…
Reference in a new issue