summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/Makefile.am83
-rw-r--r--ext/alsa/Makefile.am36
-rw-r--r--ext/alsa/gstalsa.c561
-rw-r--r--ext/alsa/gstalsa.h55
-rw-r--r--ext/alsa/gstalsadeviceprobe.c210
-rw-r--r--ext/alsa/gstalsadeviceprobe.h33
-rw-r--r--ext/alsa/gstalsamixer.c933
-rw-r--r--ext/alsa/gstalsamixer.h217
-rw-r--r--ext/alsa/gstalsamixerelement.c248
-rw-r--r--ext/alsa/gstalsamixerelement.h61
-rw-r--r--ext/alsa/gstalsamixeroptions.c109
-rw-r--r--ext/alsa/gstalsamixeroptions.h62
-rw-r--r--ext/alsa/gstalsamixertrack.c355
-rw-r--r--ext/alsa/gstalsamixertrack.h79
-rw-r--r--ext/alsa/gstalsaplugin.c91
-rw-r--r--ext/alsa/gstalsasink.c968
-rw-r--r--ext/alsa/gstalsasink.h86
-rw-r--r--ext/alsa/gstalsasrc.c873
-rw-r--r--ext/alsa/gstalsasrc.h86
-rw-r--r--ext/cdparanoia/Makefile.am13
-rw-r--r--ext/cdparanoia/gstcdparanoiasrc.c544
-rw-r--r--ext/cdparanoia/gstcdparanoiasrc.h100
-rw-r--r--ext/gio/Makefile.am29
-rw-r--r--ext/gio/gstgio.c259
-rw-r--r--ext/gio/gstgio.h42
-rw-r--r--ext/gio/gstgiobasesink.c377
-rw-r--r--ext/gio/gstgiobasesink.h71
-rw-r--r--ext/gio/gstgiobasesrc.c447
-rw-r--r--ext/gio/gstgiobasesrc.h72
-rw-r--r--ext/gio/gstgiosink.c319
-rw-r--r--ext/gio/gstgiosink.h68
-rw-r--r--ext/gio/gstgiosrc.c339
-rw-r--r--ext/gio/gstgiosrc.h68
-rw-r--r--ext/gio/gstgiostreamsink.c198
-rw-r--r--ext/gio/gstgiostreamsink.h68
-rw-r--r--ext/gio/gstgiostreamsrc.c191
-rw-r--r--ext/gio/gstgiostreamsrc.h68
-rw-r--r--ext/gnomevfs/Makefile.am21
-rw-r--r--ext/gnomevfs/gstgnomevfs.c143
-rw-r--r--ext/gnomevfs/gstgnomevfs.h38
-rw-r--r--ext/gnomevfs/gstgnomevfssink.c632
-rw-r--r--ext/gnomevfs/gstgnomevfssink.h84
-rw-r--r--ext/gnomevfs/gstgnomevfssrc.c897
-rw-r--r--ext/gnomevfs/gstgnomevfssrc.h87
-rw-r--r--ext/gnomevfs/gstgnomevfsuri.c90
-rw-r--r--ext/gnomevfs/gstgnomevfsuri.h32
-rw-r--r--ext/libvisual/Makefile.am8
-rw-r--r--ext/libvisual/visual.c960
-rw-r--r--ext/ogg/Makefile.am27
-rw-r--r--ext/ogg/README366
-rw-r--r--ext/ogg/dirac_parse.c501
-rw-r--r--ext/ogg/dirac_parse.h178
-rw-r--r--ext/ogg/gstogg.c48
-rw-r--r--ext/ogg/gstoggaviparse.c477
-rw-r--r--ext/ogg/gstoggdemux.c3366
-rw-r--r--ext/ogg/gstoggdemux.h176
-rw-r--r--ext/ogg/gstoggmux.c1692
-rw-r--r--ext/ogg/gstoggmux.h138
-rw-r--r--ext/ogg/gstoggparse.c698
-rw-r--r--ext/ogg/gstoggstream.c1315
-rw-r--r--ext/ogg/gstoggstream.h95
-rw-r--r--ext/ogg/gstogmparse.c972
-rw-r--r--ext/ogg/vorbis_parse.c239
-rw-r--r--ext/pango/Makefile.am28
-rw-r--r--ext/pango/gstclockoverlay.c240
-rw-r--r--ext/pango/gstclockoverlay.h62
-rw-r--r--ext/pango/gsttextoverlay.c2352
-rw-r--r--ext/pango/gsttextoverlay.h158
-rw-r--r--ext/pango/gsttextrender.c705
-rw-r--r--ext/pango/gsttextrender.h104
-rw-r--r--ext/pango/gsttimeoverlay.c151
-rw-r--r--ext/pango/gsttimeoverlay.h61
-rw-r--r--ext/theora/Makefile.am20
-rw-r--r--ext/theora/gsttheora.c52
-rw-r--r--ext/theora/gsttheoradec.c1467
-rw-r--r--ext/theora/gsttheoradec.h110
-rw-r--r--ext/theora/gsttheoraenc.c1256
-rw-r--r--ext/theora/gsttheoraenc.h116
-rw-r--r--ext/theora/gsttheoraparse.c941
-rw-r--r--ext/theora/gsttheoraparse.h87
-rw-r--r--ext/vorbis/Makefile.am46
-rw-r--r--ext/vorbis/README16
-rw-r--r--ext/vorbis/gstivorbisdec.c47
-rw-r--r--ext/vorbis/gstvorbis.c73
-rw-r--r--ext/vorbis/gstvorbiscommon.c75
-rw-r--r--ext/vorbis/gstvorbiscommon.h28
-rw-r--r--ext/vorbis/gstvorbisdec.c1228
-rw-r--r--ext/vorbis/gstvorbisdec.h90
-rw-r--r--ext/vorbis/gstvorbisdeclib.c122
-rw-r--r--ext/vorbis/gstvorbisdeclib.h163
-rw-r--r--ext/vorbis/gstvorbisenc.c1432
-rw-r--r--ext/vorbis/gstvorbisenc.h101
-rw-r--r--ext/vorbis/gstvorbisparse.c671
-rw-r--r--ext/vorbis/gstvorbisparse.h82
-rw-r--r--ext/vorbis/gstvorbistag.c151
-rw-r--r--ext/vorbis/gstvorbistag.h63
96 files changed, 0 insertions, 33997 deletions
diff --git a/ext/Makefile.am b/ext/Makefile.am
deleted file mode 100644
index 7c006ff7..00000000
--- a/ext/Makefile.am
+++ /dev/null
@@ -1,83 +0,0 @@
-if USE_ALSA
-ALSA_DIR=alsa
-else
-ALSA_DIR=
-endif
-
-if USE_CDPARANOIA
-CDPARANOIA_DIR=cdparanoia
-else
-CDPARANOIA_DIR=
-endif
-
-if USE_GIO
-GIO_DIR=gio
-else
-GIO_DIR=
-endif
-
-if USE_GNOME_VFS
-GNOMEVFS_DIR=gnomevfs
-else
-GNOMEVFS_DIR=
-endif
-
-if USE_LIBVISUAL
-LIBVISUAL_DIR=libvisual
-else
-LIBVISUAL_DIR=
-endif
-
-if USE_OGG
-OGG_DIR=ogg
-else
-OGG_DIR=
-endif
-
-if USE_PANGO
-PANGO_DIR = pango
-else
-PANGO_DIR =
-endif
-
-if USE_VORBIS
-VORBIS_DIR=vorbis
-endif
-
-if USE_IVORBIS
-VORBIS_DIR=vorbis
-endif
-
-if !USE_VORBIS
-if !USE_IVORBIS
-VORBIS_DIR=
-endif
-endif
-
-if USE_THEORA
-THEORA_DIR=theora
-else
-THEORA_DIR=
-endif
-
-SUBDIRS = \
- $(ALSA_DIR) \
- $(CDPARANOIA_DIR) \
- $(GIO_DIR) \
- $(GNOMEVFS_DIR) \
- $(LIBVISUAL_DIR) \
- $(OGG_DIR) \
- $(PANGO_DIR) \
- $(THEORA_DIR) \
- $(VORBIS_DIR)
-
-DIST_SUBDIRS = \
- alsa \
- cdparanoia \
- gio \
- gnomevfs \
- libvisual \
- ogg \
- pango \
- theora \
- vorbis
diff --git a/ext/alsa/Makefile.am b/ext/alsa/Makefile.am
deleted file mode 100644
index 38cde48a..00000000
--- a/ext/alsa/Makefile.am
+++ /dev/null
@@ -1,36 +0,0 @@
-plugin_LTLIBRARIES = libgstalsa.la
-
-libgstalsa_la_SOURCES = \
- gstalsadeviceprobe.c \
- gstalsamixer.c \
- gstalsamixerelement.c \
- gstalsamixertrack.c \
- gstalsamixeroptions.c \
- gstalsaplugin.c \
- gstalsasink.c \
- gstalsasrc.c \
- gstalsa.c
-
-libgstalsa_la_CFLAGS = \
- $(GST_PLUGINS_BASE_CFLAGS) \
- $(GST_BASE_CFLAGS) \
- $(GST_CFLAGS) \
- $(ALSA_CFLAGS)
-libgstalsa_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \
- $(top_builddir)/gst-libs/gst/audio/libgstaudio-$(GST_MAJORMINOR).la \
- $(GST_BASE_LIBS) \
- $(ALSA_LIBS)
-
-libgstalsa_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstalsa_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = \
- gstalsa.h \
- gstalsadeviceprobe.h \
- gstalsamixer.h \
- gstalsamixerelement.h \
- gstalsamixertrack.h \
- gstalsamixeroptions.h \
- gstalsasrc.h \
- gstalsasink.h
diff --git a/ext/alsa/gstalsa.c b/ext/alsa/gstalsa.c
deleted file mode 100644
index 2cc37ab1..00000000
--- a/ext/alsa/gstalsa.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "gstalsa.h"
-
-#include <gst/audio/multichannel.h>
-
-static GstCaps *
-gst_alsa_detect_rates (GstObject * obj, snd_pcm_hw_params_t * hw_params,
- GstCaps * in_caps)
-{
- GstCaps *caps;
- guint min, max;
- gint err, dir, min_rate, max_rate, i;
-
- GST_LOG_OBJECT (obj, "probing sample rates ...");
-
- if ((err = snd_pcm_hw_params_get_rate_min (hw_params, &min, &dir)) < 0)
- goto min_rate_err;
-
- if ((err = snd_pcm_hw_params_get_rate_max (hw_params, &max, &dir)) < 0)
- goto max_rate_err;
-
- min_rate = min;
- max_rate = max;
-
- if (min_rate < 4000)
- min_rate = 4000; /* random 'sensible minimum' */
-
- if (max_rate <= 0)
- max_rate = G_MAXINT; /* or maybe just use 192400 or so? */
- else if (max_rate > 0 && max_rate < 4000)
- max_rate = MAX (4000, min_rate);
-
- GST_DEBUG_OBJECT (obj, "Min. rate = %u (%d)", min_rate, min);
- GST_DEBUG_OBJECT (obj, "Max. rate = %u (%d)", max_rate, max);
-
- caps = gst_caps_make_writable (in_caps);
-
- for (i = 0; i < gst_caps_get_size (caps); ++i) {
- GstStructure *s;
-
- s = gst_caps_get_structure (caps, i);
- if (min_rate == max_rate) {
- gst_structure_set (s, "rate", G_TYPE_INT, min_rate, NULL);
- } else {
- gst_structure_set (s, "rate", GST_TYPE_INT_RANGE,
- min_rate, max_rate, NULL);
- }
- }
-
- return caps;
-
- /* ERRORS */
-min_rate_err:
- {
- GST_ERROR_OBJECT (obj, "failed to query minimum sample rate: %s",
- snd_strerror (err));
- gst_caps_unref (in_caps);
- return NULL;
- }
-max_rate_err:
- {
- GST_ERROR_OBJECT (obj, "failed to query maximum sample rate: %s",
- snd_strerror (err));
- gst_caps_unref (in_caps);
- return NULL;
- }
-}
-
-static const struct
-{
- const int width;
- const int depth;
- const int sformat;
- const int uformat;
-} pcmformats[] = {
- {
- 8, 8, SND_PCM_FORMAT_S8, SND_PCM_FORMAT_U8}, {
- 16, 16, SND_PCM_FORMAT_S16, SND_PCM_FORMAT_U16}, {
- 32, 24, SND_PCM_FORMAT_S24, SND_PCM_FORMAT_U24}, {
-#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) /* no endian-unspecific enum available */
- 24, 24, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_U24_3LE}, {
-#else
- 24, 24, SND_PCM_FORMAT_S24_3BE, SND_PCM_FORMAT_U24_3BE}, {
-#endif
- 32, 32, SND_PCM_FORMAT_S32, SND_PCM_FORMAT_U32}
-};
-
-static GstCaps *
-gst_alsa_detect_formats (GstObject * obj, snd_pcm_hw_params_t * hw_params,
- GstCaps * in_caps)
-{
- snd_pcm_format_mask_t *mask;
- GstStructure *s;
- GstCaps *caps;
- gint i;
-
- snd_pcm_format_mask_malloc (&mask);
- snd_pcm_hw_params_get_format_mask (hw_params, mask);
-
- caps = gst_caps_new_empty ();
-
- for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
- GstStructure *scopy;
- gint w, width = 0, depth = 0;
-
- s = gst_caps_get_structure (in_caps, i);
- if (!gst_structure_has_name (s, "audio/x-raw-int")) {
- GST_WARNING_OBJECT (obj, "skipping non-int format");
- continue;
- }
- if (!gst_structure_get_int (s, "width", &width) ||
- !gst_structure_get_int (s, "depth", &depth))
- continue;
- if (width == 0 || (width % 8) != 0)
- continue; /* Only full byte widths are valid */
- for (w = 0; w < G_N_ELEMENTS (pcmformats); w++)
- if (pcmformats[w].width == width && pcmformats[w].depth == depth)
- break;
- if (w == G_N_ELEMENTS (pcmformats))
- continue; /* Unknown format */
-
- if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat) &&
- snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) {
- /* template contains { true, false } or just one, leave it as it is */
- scopy = gst_structure_copy (s);
- } else if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat)) {
- scopy = gst_structure_copy (s);
- gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
- } else if (snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) {
- scopy = gst_structure_copy (s);
- gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
- } else {
- scopy = NULL;
- }
- if (scopy) {
- if (width > 8) {
- /* TODO: proper endianness detection, for now it's CPU endianness only */
- gst_structure_set (scopy, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
- }
- gst_caps_append_structure (caps, scopy);
- }
- }
-
- snd_pcm_format_mask_free (mask);
- gst_caps_unref (in_caps);
- return caps;
-}
-
-/* we don't have channel mappings for more than this many channels */
-#define GST_ALSA_MAX_CHANNELS 8
-
-static GstStructure *
-get_channel_free_structure (const GstStructure * in_structure)
-{
- GstStructure *s = gst_structure_copy (in_structure);
-
- gst_structure_remove_field (s, "channels");
- return s;
-}
-
-static void
-caps_add_channel_configuration (GstCaps * caps,
- const GstStructure * in_structure, gint min_chans, gint max_chans)
-{
- GstAudioChannelPosition pos[8] = {
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
- GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
- GST_AUDIO_CHANNEL_POSITION_LFE,
- GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
- GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
- };
- GstStructure *s = NULL;
- gint c;
-
- if (min_chans == max_chans && max_chans <= 2) {
- s = get_channel_free_structure (in_structure);
- gst_structure_set (s, "channels", G_TYPE_INT, max_chans, NULL);
- gst_caps_append_structure (caps, s);
- return;
- }
-
- g_assert (min_chans >= 1);
-
- /* mono and stereo don't need channel configurations */
- if (min_chans == 2) {
- s = get_channel_free_structure (in_structure);
- gst_structure_set (s, "channels", G_TYPE_INT, 2, NULL);
- gst_caps_append_structure (caps, s);
- } else if (min_chans == 1 && max_chans >= 2) {
- s = get_channel_free_structure (in_structure);
- gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
- gst_caps_append_structure (caps, s);
- }
-
- /* don't know whether to use 2.1 or 3.0 here - but I suspect
- * alsa might work around that/fix it somehow. Can we tell alsa
- * what our channel layout is like? */
- if (max_chans >= 3 && min_chans <= 3) {
- GstAudioChannelPosition pos_21[3] = {
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_LFE
- };
-
- s = get_channel_free_structure (in_structure);
- gst_structure_set (s, "channels", G_TYPE_INT, 3, NULL);
- gst_audio_set_channel_positions (s, pos_21);
- gst_caps_append_structure (caps, s);
- }
-
- /* everything else (4, 6, 8 channels) needs a channel layout */
- for (c = MAX (4, min_chans); c <= 8; c += 2) {
- if (max_chans >= c) {
- s = get_channel_free_structure (in_structure);
- gst_structure_set (s, "channels", G_TYPE_INT, c, NULL);
- gst_audio_set_channel_positions (s, pos);
- gst_caps_append_structure (caps, s);
- }
- }
-
- for (c = MAX (9, min_chans); c <= max_chans; ++c) {
- GstAudioChannelPosition *ch_layout;
- guint i;
-
- ch_layout = g_new (GstAudioChannelPosition, c);
- for (i = 0; i < c; ++i) {
- ch_layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
- }
- s = get_channel_free_structure (in_structure);
- gst_structure_set (s, "channels", G_TYPE_INT, c, NULL);
- gst_audio_set_channel_positions (s, ch_layout);
- gst_caps_append_structure (caps, s);
- g_free (ch_layout);
- }
-}
-
-static GstCaps *
-gst_alsa_detect_channels (GstObject * obj, snd_pcm_hw_params_t * hw_params,
- GstCaps * in_caps)
-{
- GstCaps *caps;
- guint min, max;
- gint min_chans, max_chans;
- gint err, i;
-
- GST_LOG_OBJECT (obj, "probing channels ...");
-
- if ((err = snd_pcm_hw_params_get_channels_min (hw_params, &min)) < 0)
- goto min_chan_error;
-
- if ((err = snd_pcm_hw_params_get_channels_max (hw_params, &max)) < 0)
- goto max_chan_error;
-
- /* note: the above functions may return (guint) -1 */
- min_chans = min;
- max_chans = max;
-
- if (min_chans < 0) {
- min_chans = 1;
- max_chans = GST_ALSA_MAX_CHANNELS;
- } else if (max_chans < 0) {
- max_chans = GST_ALSA_MAX_CHANNELS;
- }
-
- if (min_chans > max_chans) {
- gint temp;
-
- GST_WARNING_OBJECT (obj, "minimum channels > maximum channels (%d > %d), "
- "please fix your soundcard drivers", min, max);
- temp = min_chans;
- min_chans = max_chans;
- max_chans = temp;
- }
-
- /* pro cards seem to return large numbers for min_channels */
- if (min_chans > GST_ALSA_MAX_CHANNELS) {
- GST_DEBUG_OBJECT (obj, "min_chans = %u, looks like a pro card", min_chans);
- if (max_chans < min_chans) {
- max_chans = min_chans;
- } else {
- /* only support [max_chans; max_chans] for these cards for now
- * to avoid inflating the source caps with loads of structures ... */
- min_chans = max_chans;
- }
- } else {
- min_chans = MAX (min_chans, 1);
- max_chans = MIN (GST_ALSA_MAX_CHANNELS, max_chans);
- }
-
- GST_DEBUG_OBJECT (obj, "Min. channels = %d (%d)", min_chans, min);
- GST_DEBUG_OBJECT (obj, "Max. channels = %d (%d)", max_chans, max);
-
- caps = gst_caps_new_empty ();
-
- for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
- GstStructure *s;
- GType field_type;
- gint c_min = min_chans;
- gint c_max = max_chans;
-
- s = gst_caps_get_structure (in_caps, i);
- /* the template caps might limit the number of channels (like alsasrc),
- * in which case we don't want to return a superset, so hack around this
- * for the two common cases where the channels are either a fixed number
- * or a min/max range). Example: alsasrc template has channels = [1,2] and
- * the detection will claim to support 8 channels for device 'plughw:0' */
- field_type = gst_structure_get_field_type (s, "channels");
- if (field_type == G_TYPE_INT) {
- gst_structure_get_int (s, "channels", &c_min);
- gst_structure_get_int (s, "channels", &c_max);
- } else if (field_type == GST_TYPE_INT_RANGE) {
- const GValue *val;
-
- val = gst_structure_get_value (s, "channels");
- c_min = CLAMP (gst_value_get_int_range_min (val), min_chans, max_chans);
- c_max = CLAMP (gst_value_get_int_range_max (val), min_chans, max_chans);
- } else {
- c_min = min_chans;
- c_max = max_chans;
- }
-
- caps_add_channel_configuration (caps, s, c_min, c_max);
- }
-
- gst_caps_unref (in_caps);
-
- return caps;
-
- /* ERRORS */
-min_chan_error:
- {
- GST_ERROR_OBJECT (obj, "failed to query minimum channel count: %s",
- snd_strerror (err));
- return NULL;
- }
-max_chan_error:
- {
- GST_ERROR_OBJECT (obj, "failed to query maximum channel count: %s",
- snd_strerror (err));
- return NULL;
- }
-}
-
-snd_pcm_t *
-gst_alsa_open_iec958_pcm (GstObject * obj)
-{
- char *iec958_pcm_name = NULL;
- snd_pcm_t *pcm = NULL;
- int res;
- char devstr[256]; /* Storage for local 'default' device string */
-
- /*
- * Try and open our default iec958 device. Fall back to searching on card x
- * if this fails, which should only happen on older alsa setups
- */
-
- /* The string will be one of these:
- * SPDIF_CON: Non-audio flag not set:
- * spdif:{AES0 0x0 AES1 0x82 AES2 0x0 AES3 0x2}
- * SPDIF_CON: Non-audio flag set:
- * spdif:{AES0 0x2 AES1 0x82 AES2 0x0 AES3 0x2}
- */
- sprintf (devstr,
- "iec958:{AES0 0x%02x AES1 0x%02x AES2 0x%02x AES3 0x%02x}",
- IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
- IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
- 0, IEC958_AES3_CON_FS_48000);
-
- GST_DEBUG_OBJECT (obj, "Generated device string \"%s\"", devstr);
- iec958_pcm_name = devstr;
-
- res = snd_pcm_open (&pcm, iec958_pcm_name, SND_PCM_STREAM_PLAYBACK, 0);
- if (G_UNLIKELY (res < 0)) {
- GST_DEBUG_OBJECT (obj, "failed opening IEC958 device: %s",
- snd_strerror (res));
- pcm = NULL;
- }
-
- return pcm;
-}
-
-
-/*
- * gst_alsa_probe_supported_formats:
- *
- * Takes the template caps and returns the subset which is actually
- * supported by this device.
- *
- */
-
-GstCaps *
-gst_alsa_probe_supported_formats (GstObject * obj, snd_pcm_t * handle,
- const GstCaps * template_caps)
-{
- snd_pcm_hw_params_t *hw_params;
- snd_pcm_stream_t stream_type;
- GstCaps *caps;
- gint err;
-
- snd_pcm_hw_params_malloc (&hw_params);
- if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0)
- goto error;
-
- stream_type = snd_pcm_stream (handle);
-
- caps = gst_caps_copy (template_caps);
-
- if (!(caps = gst_alsa_detect_formats (obj, hw_params, caps)))
- goto subroutine_error;
-
- if (!(caps = gst_alsa_detect_rates (obj, hw_params, caps)))
- goto subroutine_error;
-
- if (!(caps = gst_alsa_detect_channels (obj, hw_params, caps)))
- goto subroutine_error;
-
- /* Try opening IEC958 device to see if we can support that format (playback
- * only for now but we could add SPDIF capture later) */
- if (stream_type == SND_PCM_STREAM_PLAYBACK) {
- snd_pcm_t *pcm = gst_alsa_open_iec958_pcm (obj);
-
- if (G_LIKELY (pcm)) {
- gst_caps_append (caps, gst_caps_new_simple ("audio/x-iec958", NULL));
- snd_pcm_close (pcm);
- }
- }
-
- snd_pcm_hw_params_free (hw_params);
- return caps;
-
- /* ERRORS */
-error:
- {
- GST_ERROR_OBJECT (obj, "failed to query formats: %s", snd_strerror (err));
- snd_pcm_hw_params_free (hw_params);
- return NULL;
- }
-subroutine_error:
- {
- GST_ERROR_OBJECT (obj, "failed to query formats");
- snd_pcm_hw_params_free (hw_params);
- return NULL;
- }
-}
-
-static gchar *
-gst_alsa_find_device_name_no_handle (GstObject * obj, const gchar * devcard,
- gint device_num, snd_pcm_stream_t stream)
-{
- snd_ctl_card_info_t *info = NULL;
- snd_ctl_t *ctl = NULL;
- gchar *ret = NULL;
- gint dev = -1;
-
- GST_LOG_OBJECT (obj, "[%s] device=%d", devcard, device_num);
-
- if (snd_ctl_open (&ctl, devcard, 0) < 0)
- return NULL;
-
- snd_ctl_card_info_malloc (&info);
- if (snd_ctl_card_info (ctl, info) < 0)
- goto done;
-
- while (snd_ctl_pcm_next_device (ctl, &dev) == 0 && dev >= 0) {
- if (dev == device_num) {
- snd_pcm_info_t *pcminfo;
-
- snd_pcm_info_malloc (&pcminfo);
- snd_pcm_info_set_device (pcminfo, dev);
- snd_pcm_info_set_subdevice (pcminfo, 0);
- snd_pcm_info_set_stream (pcminfo, stream);
- if (snd_ctl_pcm_info (ctl, pcminfo) < 0) {
- snd_pcm_info_free (pcminfo);
- break;
- }
-
- ret = (gchar *) snd_pcm_info_get_name (pcminfo);
- if (ret) {
- ret = g_strdup (ret);
- GST_LOG_OBJECT (obj, "name from pcminfo: %s", ret);
- }
- snd_pcm_info_free (pcminfo);
- if (ret)
- break;
- }
- }
-
- if (ret == NULL) {
- char *name = NULL;
- gint card;
-
- GST_LOG_OBJECT (obj, "no luck so far, trying backup");
- card = snd_ctl_card_info_get_card (info);
- snd_card_get_name (card, &name);
- ret = g_strdup (name);
- free (name);
- }
-
-done:
- snd_ctl_card_info_free (info);
- snd_ctl_close (ctl);
-
- return ret;
-}
-
-gchar *
-gst_alsa_find_device_name (GstObject * obj, const gchar * device,
- snd_pcm_t * handle, snd_pcm_stream_t stream)
-{
- gchar *ret = NULL;
-
- if (device != NULL) {
- gchar *dev, *comma;
- gint devnum;
-
- GST_LOG_OBJECT (obj, "Trying to get device name from string '%s'", device);
-
- /* only want name:card bit, but not devices and subdevices */
- dev = g_strdup (device);
- if ((comma = strchr (dev, ','))) {
- *comma = '\0';
- devnum = atoi (comma + 1);
- ret = gst_alsa_find_device_name_no_handle (obj, dev, devnum, stream);
- }
- g_free (dev);
- }
-
- if (ret == NULL && handle != NULL) {
- snd_pcm_info_t *info;
-
- GST_LOG_OBJECT (obj, "Trying to get device name from open handle");
- snd_pcm_info_malloc (&info);
- snd_pcm_info (handle, info);
- ret = g_strdup (snd_pcm_info_get_name (info));
- snd_pcm_info_free (info);
- }
-
- GST_LOG_OBJECT (obj, "Device name for device '%s': %s",
- GST_STR_NULL (device), GST_STR_NULL (ret));
-
- return ret;
-}
diff --git a/ext/alsa/gstalsa.h b/ext/alsa/gstalsa.h
deleted file mode 100644
index e7af889f..00000000
--- a/ext/alsa/gstalsa.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2001 CodeFactory AB
- * Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
- * Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#ifndef __GST_ALSA_H__
-#define __GST_ALSA_H__
-
-
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#define ALSA_PCM_NEW_SW_PARAMS_API
-
-#include <alsa/asoundlib.h>
-#include <alsa/control.h>
-#include <alsa/error.h>
-#include <gst/gst.h>
-
-#define GST_CHECK_ALSA_VERSION(major,minor,micro) \
- (SND_LIB_MAJOR > (major) || \
- (SND_LIB_MAJOR == (major) && SND_LIB_MINOR > (minor)) || \
- (SND_LIB_MAJOR == (major) && SND_LIB_MINOR == (minor) && \
- SND_LIB_SUBMINOR >= (micro)))
-
-GST_DEBUG_CATEGORY_EXTERN (alsa_debug);
-#define GST_CAT_DEFAULT alsa_debug
-
-snd_pcm_t * gst_alsa_open_iec958_pcm (GstObject * obj);
-
-GstCaps * gst_alsa_probe_supported_formats (GstObject * obj,
- snd_pcm_t * handle,
- const GstCaps * template_caps);
-
-gchar * gst_alsa_find_device_name (GstObject * obj,
- const gchar * device,
- snd_pcm_t * handle,
- snd_pcm_stream_t stream);
-
-#endif /* __GST_ALSA_H__ */
diff --git a/ext/alsa/gstalsadeviceprobe.c b/ext/alsa/gstalsadeviceprobe.c
deleted file mode 100644
index 83596a3f..00000000
--- a/ext/alsa/gstalsadeviceprobe.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/* Copyright (C) 2001 CodeFactory AB
- * Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
- * Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
- * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
- * Copyright (C) 2005 Tim-Philipp Müller <tim centricular net>
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstalsadeviceprobe.h"
-#include "gst/interfaces/propertyprobe.h"
-
-static const GList *
-gst_alsa_device_property_probe_get_properties (GstPropertyProbe * probe)
-{
- GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
- static GList *list = NULL;
-
- /* well, not perfect, but better than no locking at all.
- * In the worst case we leak a list node, so who cares? */
- GST_CLASS_LOCK (GST_OBJECT_CLASS (klass));
-
- if (!list) {
- GParamSpec *pspec;
-
- pspec = g_object_class_find_property (klass, "device");
- list = g_list_append (NULL, pspec);
- }
-
- GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass));
-
- return list;
-}
-
-static GList *
-gst_alsa_get_device_list (snd_pcm_stream_t stream)
-{
- snd_ctl_t *handle;
- int card, dev;
- snd_ctl_card_info_t *info;
- snd_pcm_info_t *pcminfo;
- gboolean mixer = (stream == -1);
- GList *list = NULL;
-
- if (stream == -1)
- stream = 0;
-
- snd_ctl_card_info_malloc (&info);
- snd_pcm_info_malloc (&pcminfo);
- card = -1;
-
- if (snd_card_next (&card) < 0 || card < 0) {
- /* no soundcard found */
- GST_WARNING ("No soundcard found");
- goto beach;
- }
-
- while (card >= 0) {
- gchar name[32];
-
- g_snprintf (name, sizeof (name), "hw:%d", card);
- if (snd_ctl_open (&handle, name, 0) < 0) {
- goto next_card;
- }
- if (snd_ctl_card_info (handle, info) < 0) {
- snd_ctl_close (handle);
- goto next_card;
- }
-
- if (mixer) {
- list = g_list_append (list, g_strdup (name));
- } else {
- dev = -1;
- while (1) {
- gchar *gst_device;
-
- snd_ctl_pcm_next_device (handle, &dev);
-
- if (dev < 0)
- break;
- snd_pcm_info_set_device (pcminfo, dev);
- snd_pcm_info_set_subdevice (pcminfo, 0);
- snd_pcm_info_set_stream (pcminfo, stream);
- if (snd_ctl_pcm_info (handle, pcminfo) < 0) {
- continue;
- }
-
- gst_device = g_strdup_printf ("hw:%d,%d", card, dev);
- list = g_list_append (list, gst_device);
- }
- }
- snd_ctl_close (handle);
- next_card:
- if (snd_card_next (&card) < 0) {
- break;
- }
- }
-
-beach:
- snd_ctl_card_info_free (info);
- snd_pcm_info_free (pcminfo);
-
- return list;
-}
-
-static void
-gst_alsa_device_property_probe_probe_property (GstPropertyProbe * probe,
- guint prop_id, const GParamSpec * pspec)
-{
- if (!g_str_equal (pspec->name, "device")) {
- G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
- }
-}
-
-static gboolean
-gst_alsa_device_property_probe_needs_probe (GstPropertyProbe * probe,
- guint prop_id, const GParamSpec * pspec)
-{
- /* don't cache probed data */
- return TRUE;
-}
-
-static GValueArray *
-gst_alsa_device_property_probe_get_values (GstPropertyProbe * probe,
- guint prop_id, const GParamSpec * pspec)
-{
- GstElementClass *klass;
- const GList *templates;
- snd_pcm_stream_t mode = -1;
- GValueArray *array;
- GValue value = { 0, };
- GList *l, *list;
-
- if (!g_str_equal (pspec->name, "device")) {
- G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
- return NULL;
- }
-
- klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (probe));
-
- /* I'm pretty sure ALSA has a good way to do this. However, their cool
- * auto-generated documentation is pretty much useless if you try to
- * do function-wise look-ups. */
- /* we assume one pad template at max [zero=mixer] */
- templates = gst_element_class_get_pad_template_list (klass);
- if (templates) {
- if (GST_PAD_TEMPLATE_DIRECTION (templates->data) == GST_PAD_SRC)
- mode = SND_PCM_STREAM_CAPTURE;
- else
- mode = SND_PCM_STREAM_PLAYBACK;
- }
-
- list = gst_alsa_get_device_list (mode);
-
- if (list == NULL) {
- GST_LOG_OBJECT (probe, "No devices found");
- return NULL;
- }
-
- array = g_value_array_new (g_list_length (list));
- g_value_init (&value, G_TYPE_STRING);
- for (l = list; l != NULL; l = l->next) {
- GST_LOG_OBJECT (probe, "Found device: %s", (gchar *) l->data);
- g_value_take_string (&value, (gchar *) l->data);
- l->data = NULL;
- g_value_array_append (array, &value);
- }
- g_value_unset (&value);
- g_list_free (list);
-
- return array;
-}
-
-static void
-gst_alsa_property_probe_interface_init (GstPropertyProbeInterface * iface)
-{
- iface->get_properties = gst_alsa_device_property_probe_get_properties;
- iface->probe_property = gst_alsa_device_property_probe_probe_property;
- iface->needs_probe = gst_alsa_device_property_probe_needs_probe;
- iface->get_values = gst_alsa_device_property_probe_get_values;
-}
-
-void
-gst_alsa_type_add_device_property_probe_interface (GType type)
-{
- static const GInterfaceInfo probe_iface_info = {
- (GInterfaceInitFunc) gst_alsa_property_probe_interface_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
- &probe_iface_info);
-}
diff --git a/ext/alsa/gstalsadeviceprobe.h b/ext/alsa/gstalsadeviceprobe.h
deleted file mode 100644
index b60b0fef..00000000
--- a/ext/alsa/gstalsadeviceprobe.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Copyright (C) 2001 CodeFactory AB
- * Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
- * Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __GST_ALSA_DEVICE_PROBE_H__
-#define __GST_ALSA_DEVICE_PROBE_H__
-
-#include "gstalsa.h"
-
-G_BEGIN_DECLS
-
-void gst_alsa_type_add_device_property_probe_interface (GType type);
-
-G_END_DECLS
-
-#endif /* __GST_ALSA_DEVICE_PROBE_H__ */
-
diff --git a/ext/alsa/gstalsamixer.c b/ext/alsa/gstalsamixer.c
deleted file mode 100644
index 1c5d8184..00000000
--- a/ext/alsa/gstalsamixer.c
+++ /dev/null
@@ -1,933 +0,0 @@
-/* ALSA mixer implementation.
- * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-alsamixer
- * @see_also: alsasink, alsasrc
- *
- * This element controls various aspects such as the volume and balance
- * of an audio device using the ALSA api.
- *
- * The application should query and use the interfaces provided by this
- * element to control the device.
- *
- * Last reviewed on 2006-03-01 (0.10.4)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstalsamixer.h"
-
-static void gst_alsa_mixer_update_option (GstAlsaMixer * mixer,
- GstAlsaMixerOptions * alsa_opts);
-static void gst_alsa_mixer_update_track (GstAlsaMixer * mixer,
- GstAlsaMixerTrack * alsa_track);
-static int gst_alsa_mixer_handle_callback (snd_mixer_t * handle,
- unsigned int mask, snd_mixer_elem_t * elem);
-
-/* First some utils, then the mixer implementation */
-static gboolean
-gst_alsa_mixer_open (GstAlsaMixer * mixer)
-{
- gint err;
- snd_ctl_t *ctl;
- snd_ctl_card_info_t *card_info;
-
- g_return_val_if_fail (mixer->handle == NULL, FALSE);
-
- /* open and initialize the mixer device */
- err = snd_mixer_open (&mixer->handle, 0);
- if (err < 0 || mixer->handle == NULL)
- goto open_failed;
-
- if ((err = snd_mixer_attach (mixer->handle, mixer->device)) < 0) {
- GST_WARNING ("Cannot open mixer for sound device '%s': %s", mixer->device,
- snd_strerror (err));
- goto error;
- }
-
- if ((err = snd_mixer_selem_register (mixer->handle, NULL, NULL)) < 0) {
- GST_WARNING ("Cannot register mixer elements: %s", snd_strerror (err));
- goto error;
- }
-
- if ((err = snd_mixer_load (mixer->handle)) < 0) {
- GST_WARNING ("Cannot load mixer settings: %s", snd_strerror (err));
- goto error;
- }
-
- snd_mixer_set_callback_private (mixer->handle, mixer);
- snd_mixer_set_callback (mixer->handle, gst_alsa_mixer_handle_callback);
-
- /* now get the device name, any of this is not fatal */
- g_free (mixer->cardname);
- if ((err = snd_ctl_open (&ctl, mixer->device, 0)) < 0) {
- GST_WARNING ("Cannot open CTL: %s", snd_strerror (err));
- goto no_card_name;
- }
-
- snd_ctl_card_info_malloc (&card_info);
- if ((err = snd_ctl_card_info (ctl, card_info)) < 0) {
- GST_WARNING ("Cannot get card info: %s", snd_strerror (err));
- snd_ctl_close (ctl);
- goto no_card_name;
- }
-
- mixer->cardname = g_strdup (snd_ctl_card_info_get_name (card_info));
- GST_DEBUG ("Card name = %s", GST_STR_NULL (mixer->cardname));
- snd_ctl_card_info_free (card_info);
- snd_ctl_close (ctl);
-
-no_card_name:
- if (mixer->cardname == NULL) {
- mixer->cardname = g_strdup ("Unknown");
- GST_DEBUG ("Cannot find card name");
- }
-
- GST_INFO ("Successfully opened mixer for device '%s'.", mixer->device);
-
- return TRUE;
-
- /* ERROR */
-open_failed:
- {
- GST_WARNING ("Cannot open mixer: %s", snd_strerror (err));
- mixer->handle = NULL;
- return FALSE;
- }
-error:
- {
- snd_mixer_close (mixer->handle);
- mixer->handle = NULL;
- return FALSE;
- }
-}
-
-static snd_mixer_elem_t *
-gst_alsa_mixer_find_master_mixer (GstAlsaMixer * mixer, snd_mixer_t * handle)
-{
- snd_mixer_elem_t *element;
- gint i, count;
-
- count = snd_mixer_get_count (handle);
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- /* Check if we have a playback mixer labelled as 'Master' */
- element = snd_mixer_first_elem (handle);
- for (i = 0; i < count; i++) {
- if (snd_mixer_selem_has_playback_volume (element) &&
- strcmp (snd_mixer_selem_get_name (element), "Master") == 0) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return element;
- }
- element = snd_mixer_elem_next (element);
- }
-
- /* If not, check if we have a playback mixer labelled as 'Front' */
- element = snd_mixer_first_elem (handle);
- for (i = 0; i < count; i++) {
- if (snd_mixer_selem_has_playback_volume (element) &&
- strcmp (snd_mixer_selem_get_name (element), "Front") == 0) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return element;
- }
- element = snd_mixer_elem_next (element);
- }
-
- /* If not, check if we have a playback mixer labelled as 'PCM' */
- element = snd_mixer_first_elem (handle);
- for (i = 0; i < count; i++) {
- if (snd_mixer_selem_has_playback_volume (element) &&
- strcmp (snd_mixer_selem_get_name (element), "PCM") == 0) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return element;
- }
- element = snd_mixer_elem_next (element);
- }
-
- /* If not, check if we have a playback mixer labelled as 'Speaker' */
- element = snd_mixer_first_elem (handle);
- for (i = 0; i < count; i++) {
- if (snd_mixer_selem_has_playback_volume (element) &&
- strcmp (snd_mixer_selem_get_name (element), "Speaker") == 0) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return element;
- }
- element = snd_mixer_elem_next (element);
- }
-
- /* If not, check if we have a playback mixer with both volume and switch that
- * is not mono */
- element = snd_mixer_first_elem (handle);
- for (i = 0; i < count; i++) {
- if (snd_mixer_selem_has_playback_volume (element) &&
- snd_mixer_selem_has_playback_switch (element) &&
- !snd_mixer_selem_is_playback_mono (element)) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return element;
- }
- element = snd_mixer_elem_next (element);
- }
-
- /* If not, check if we have any playback mixer with both volume and switch */
- element = snd_mixer_first_elem (handle);
- for (i = 0; i < count; i++) {
- if (snd_mixer_selem_has_playback_volume (element) &&
- snd_mixer_selem_has_playback_switch (element)) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return element;
- }
- element = snd_mixer_elem_next (element);
- }
-
- /* If not, take any playback mixer with a volume control */
- element = snd_mixer_first_elem (handle);
- for (i = 0; i < count; i++) {
- if (snd_mixer_selem_has_playback_volume (element)) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return element;
- }
- element = snd_mixer_elem_next (element);
- }
-
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- /* Looks like we're out of luck ... */
- return NULL;
-}
-
-static void
-gst_alsa_mixer_update (GstAlsaMixer * mixer, snd_mixer_elem_t * elem)
-{
- GList *item;
-
- g_return_if_fail (mixer != NULL);
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- for (item = mixer->tracklist; item != NULL; item = item->next) {
- if (GST_IS_ALSA_MIXER_TRACK (item->data)) {
- if (elem && (GST_ALSA_MIXER_TRACK (item->data)->element != elem))
- continue;
-
- gst_alsa_mixer_update_track (mixer, GST_ALSA_MIXER_TRACK (item->data));
- } else if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) {
- if (elem && (GST_ALSA_MIXER_OPTIONS (item->data)->element != elem))
- continue;
-
- gst_alsa_mixer_update_option (mixer, GST_ALSA_MIXER_OPTIONS (item->data));
- }
- }
-
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-}
-
-static int
-gst_alsa_mixer_elem_handle_callback (snd_mixer_elem_t * elem, unsigned int mask)
-{
- GstAlsaMixer *mixer =
- (GstAlsaMixer *) snd_mixer_elem_get_callback_private (elem);
-
- GST_LOG ("ALSA elem cb");
-
- g_return_val_if_fail (mixer != NULL, 1);
-
- gst_alsa_mixer_update (mixer, elem);
-
- return 0;
-}
-
-static int
-gst_alsa_mixer_handle_callback (snd_mixer_t * handle, unsigned int mask,
- snd_mixer_elem_t * elem)
-{
- GstAlsaMixer *mixer =
- (GstAlsaMixer *) snd_mixer_get_callback_private (handle);
-
- GST_LOG ("ALSA cb");
-
- g_return_val_if_fail (mixer != NULL, 1);
-
- /* Hopefully won't be call recursively and will handle pending elem events */
- snd_mixer_handle_events (mixer->handle);
-
- gst_alsa_mixer_update (mixer, elem);
-
- return 0;
-}
-
-static void
-gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer)
-{
- gint i, count;
- snd_mixer_elem_t *element, *master;
- GList *item;
-
- g_return_if_fail (mixer->handle != NULL);
-
- if (mixer->tracklist)
- return;
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- master = gst_alsa_mixer_find_master_mixer (mixer, mixer->handle);
-
- count = snd_mixer_get_count (mixer->handle);
- element = snd_mixer_first_elem (mixer->handle);
-
- /* build track list
- *
- * Some ALSA tracks may have playback and capture capabilities.
- * Here we model them as two separate GStreamer tracks.
- */
-
- for (i = 0; i < count; i++) {
- GstMixerTrack *play_track = NULL;
- GstMixerTrack *cap_track = NULL;
- const gchar *name;
- GList *item;
- gint samename = 0;
-
- name = snd_mixer_selem_get_name (element);
-
- /* prevent dup names */
- for (item = mixer->tracklist; item != NULL; item = item->next) {
- snd_mixer_elem_t *temp;
-
- if (GST_IS_ALSA_MIXER_OPTIONS (item->data))
- temp = GST_ALSA_MIXER_OPTIONS (item->data)->element;
- else
- temp = GST_ALSA_MIXER_TRACK (item->data)->element;
-
- if (strcmp (name, snd_mixer_selem_get_name (temp)) == 0)
- samename++;
- }
-
- GST_LOG ("[%s] probing element #%u, mixer->dir=%u", name, i, mixer->dir);
-
- if (mixer->dir & GST_ALSA_MIXER_PLAYBACK) {
- gboolean has_playback_switch, has_playback_volume;
-
- has_playback_switch = snd_mixer_selem_has_playback_switch (element);
- has_playback_volume = snd_mixer_selem_has_playback_volume (element);
-
- GST_LOG ("[%s] PLAYBACK: has_playback_volume=%d, has_playback_switch=%d"
- "%s", name, has_playback_volume, has_playback_switch,
- (element == master) ? " MASTER" : "");
-
- if (has_playback_volume) {
- gint flags = GST_MIXER_TRACK_OUTPUT;
-
- if (element == master)
- flags |= GST_MIXER_TRACK_MASTER;
-
- play_track = gst_alsa_mixer_track_new (element, samename, i,
- flags, FALSE, NULL, FALSE);
-
- } else if (has_playback_switch) {
- /* simple mute switch */
- play_track = gst_alsa_mixer_track_new (element, samename, i,
- GST_MIXER_TRACK_OUTPUT, TRUE, NULL, FALSE);
- }
-
- if (snd_mixer_selem_is_enumerated (element)) {
- GstMixerOptions *opts = gst_alsa_mixer_options_new (element, i);
-
- GST_LOG ("[%s] is enumerated (%d)", name, i);
- mixer->tracklist = g_list_append (mixer->tracklist, opts);
- }
- }
-
- if (mixer->dir & GST_ALSA_MIXER_CAPTURE) {
- gboolean has_capture_switch, has_common_switch;
- gboolean has_capture_volume, has_common_volume;
-
- has_capture_switch = snd_mixer_selem_has_capture_switch (element);
- has_common_switch = snd_mixer_selem_has_common_switch (element);
- has_capture_volume = snd_mixer_selem_has_capture_volume (element);
- has_common_volume = snd_mixer_selem_has_common_volume (element);
-
- GST_LOG ("[%s] CAPTURE: has_capture_volume=%d, has_common_volume=%d, "
- "has_capture_switch=%d, has_common_switch=%d, play_track=%p", name,
- has_capture_volume, has_common_volume, has_capture_switch,
- has_common_switch, play_track);
-
- if (has_capture_volume && !(play_track && has_common_volume)) {
- cap_track = gst_alsa_mixer_track_new (element, samename, i,
- GST_MIXER_TRACK_INPUT, FALSE, NULL, play_track != NULL);
- } else if (has_capture_switch && !(play_track && has_common_switch)) {
- cap_track = gst_alsa_mixer_track_new (element, samename, i,
- GST_MIXER_TRACK_INPUT, TRUE, NULL, play_track != NULL);
- }
- }
-
-
- if (play_track && cap_track) {
- GST_ALSA_MIXER_TRACK (play_track)->shared_mute =
- GST_ALSA_MIXER_TRACK (cap_track);
- GST_ALSA_MIXER_TRACK (cap_track)->shared_mute =
- GST_ALSA_MIXER_TRACK (play_track);
- }
-
- if (play_track)
- mixer->tracklist = g_list_append (mixer->tracklist, play_track);
-
- if (cap_track)
- mixer->tracklist = g_list_append (mixer->tracklist, cap_track);
-
- element = snd_mixer_elem_next (element);
- }
-
- for (item = mixer->tracklist; item != NULL; item = item->next) {
- snd_mixer_elem_t *temp;
-
- if (GST_IS_ALSA_MIXER_OPTIONS (item->data))
- temp = GST_ALSA_MIXER_OPTIONS (item->data)->element;
- else
- temp = GST_ALSA_MIXER_TRACK (item->data)->element;
-
- snd_mixer_elem_set_callback (temp, gst_alsa_mixer_elem_handle_callback);
- snd_mixer_elem_set_callback_private (temp, mixer);
- }
-
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-}
-
-static void
-task_monitor_alsa (gpointer data)
-{
- struct pollfd *pfds;
- unsigned int nfds, rnfds;
- unsigned short revents;
- GstAlsaMixer *mixer = (GstAlsaMixer *) data;
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- nfds = snd_mixer_poll_descriptors_count (mixer->handle);
- if (nfds <= 0) {
- GST_ERROR ("snd_mixer_poll_descriptors_count <= 0: %d", nfds);
- /* FIXME: sleep ? stop monitoring ? */
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return;
- }
-
- pfds = g_newa (struct pollfd, nfds + 1);
- rnfds = snd_mixer_poll_descriptors (mixer->handle, pfds, nfds);
- g_assert (rnfds <= nfds);
-
- pfds[rnfds].fd = mixer->pfd[0];
- pfds[rnfds].events = POLLIN | POLLPRI | POLLHUP | POLLERR;
- pfds[rnfds].revents = 0;
-
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-
- GST_LOG ("task loop");
- poll (pfds, rnfds + 1, -1);
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- snd_mixer_poll_descriptors_revents (mixer->handle, pfds, nfds, &revents);
- if (revents & POLLIN || revents & POLLPRI) {
- GST_DEBUG ("Handling events");
- snd_mixer_handle_events (mixer->handle);
- }
-
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-}
-
-/* API */
-
-GstAlsaMixer *
-gst_alsa_mixer_new (const char *device, GstAlsaMixerDirection dir)
-{
- GstAlsaMixer *ret = NULL;
-
- g_return_val_if_fail (device != NULL, NULL);
-
- ret = g_new0 (GstAlsaMixer, 1);
-
- if (pipe (ret->pfd) == -1)
- goto error;
-
- ret->rec_mutex = g_new (GStaticRecMutex, 1);
- g_static_rec_mutex_init (ret->rec_mutex);
-
- ret->task_mutex = g_new (GStaticRecMutex, 1);
- g_static_rec_mutex_init (ret->task_mutex);
-
- ret->task = gst_task_create (task_monitor_alsa, ret);
- gst_task_set_lock (ret->task, ret->task_mutex);
-
- ret->device = g_strdup (device);
- ret->dir = dir;
-
- if (!gst_alsa_mixer_open (ret))
- goto error;
-
- if (gst_task_start (ret->task) == FALSE) {
- GST_WARNING ("Could not start alsamixer task");
- }
-
- return ret;
-
- /* ERRORS */
-error:
- {
- gst_alsa_mixer_free (ret);
- return NULL;
- }
-}
-
-void
-gst_alsa_mixer_free (GstAlsaMixer * mixer)
-{
- g_return_if_fail (mixer != NULL);
-
- if (mixer->task) {
- if (write (mixer->pfd[1], "stop", 5) <= 0) {
- GST_ERROR ("Cannot send " "stop" " to alsamixer task");
- close (mixer->pfd[1]);
- mixer->pfd[1] = -1;
- }
-
- if (gst_task_join (mixer->task) == FALSE) {
- GST_ERROR ("Cannot join alsamixer task");
- }
-
- gst_object_unref (mixer->task);
- mixer->task = NULL;
- }
-
- g_static_rec_mutex_free (mixer->task_mutex);
- g_free (mixer->task_mutex);
- mixer->task_mutex = NULL;
-
- if (mixer->pfd[0] > 0) {
- close (mixer->pfd[0]);
- mixer->pfd[0] = -1;
- }
-
- if (mixer->pfd[1] > 0) {
- close (mixer->pfd[1]);
- mixer->pfd[1] = -1;
- }
-
- if (mixer->interface) {
- g_object_unref (G_OBJECT (mixer->interface));
- mixer->interface = NULL;
- }
-
- if (mixer->device) {
- g_free (mixer->device);
- mixer->device = NULL;
- }
-
- if (mixer->cardname) {
- g_free (mixer->cardname);
- mixer->cardname = NULL;
- }
-
- if (mixer->tracklist) {
- g_list_foreach (mixer->tracklist, (GFunc) g_object_unref, NULL);
- g_list_free (mixer->tracklist);
- mixer->tracklist = NULL;
- }
-
- if (mixer->handle) {
- snd_mixer_close (mixer->handle);
- mixer->handle = NULL;
- }
-
- g_static_rec_mutex_free (mixer->rec_mutex);
- g_free (mixer->rec_mutex);
- mixer->rec_mutex = NULL;
-
- g_free (mixer);
-}
-
-const GList *
-gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer)
-{
- g_return_val_if_fail (mixer->handle != NULL, NULL);
-
- gst_alsa_mixer_ensure_track_list (mixer);
-
- return (const GList *) mixer->tracklist;
-}
-
-void
-gst_alsa_mixer_get_volume (GstAlsaMixer * mixer, GstMixerTrack * track,
- gint * volumes)
-{
- gint i;
- GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track);
-
- g_return_if_fail (mixer->handle != NULL);
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- gst_alsa_mixer_track_update (alsa_track);
-
- if (track->flags & GST_MIXER_TRACK_OUTPUT) { /* return playback volume */
-
- /* Is emulated mute flag activated? */
- if (track->flags & GST_MIXER_TRACK_MUTE &&
- !(alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH)) {
- for (i = 0; i < track->num_channels; i++)
- volumes[i] = alsa_track->volumes[i];
- } else {
- for (i = 0; i < track->num_channels; i++) {
- long tmp = 0;
-
- snd_mixer_selem_get_playback_volume (alsa_track->element, i, &tmp);
- alsa_track->volumes[i] = volumes[i] = (gint) tmp;
- }
- }
-
- } else if (track->flags & GST_MIXER_TRACK_INPUT) { /* return capture volume */
-
- /* Is emulated record flag activated? */
- if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH ||
- track->flags & GST_MIXER_TRACK_RECORD) {
- for (i = 0; i < track->num_channels; i++) {
- long tmp = 0;
-
- snd_mixer_selem_get_capture_volume (alsa_track->element, i, &tmp);
- alsa_track->volumes[i] = volumes[i] = (gint) tmp;
- }
- } else {
- for (i = 0; i < track->num_channels; i++)
- volumes[i] = alsa_track->volumes[i];
- }
- }
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-}
-
-static gboolean
-check_if_volumes_are_the_same (guint num_channels, gint * volumes)
-{
- guint i;
-
- if (num_channels <= 1)
- return TRUE;
-
- for (i = 1; i < num_channels; i++) {
- if (volumes[i] != volumes[0])
- return FALSE;
- }
-
- return TRUE;
-}
-
-void
-gst_alsa_mixer_set_volume (GstAlsaMixer * mixer, GstMixerTrack * track,
- gint * volumes)
-{
- GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track);
- gint i;
-
- g_return_if_fail (mixer->handle != NULL);
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- gst_alsa_mixer_track_update (alsa_track);
-
- if (track->flags & GST_MIXER_TRACK_OUTPUT) {
-
- /* Is emulated mute flag activated? */
- if (track->flags & GST_MIXER_TRACK_MUTE &&
- !(alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH)) {
- for (i = 0; i < track->num_channels; i++)
- alsa_track->volumes[i] = volumes[i];
- } else {
- if (check_if_volumes_are_the_same (track->num_channels, volumes)) {
- snd_mixer_selem_set_playback_volume_all (alsa_track->element,
- volumes[0]);
- for (i = 0; i < track->num_channels; i++)
- alsa_track->volumes[i] = volumes[0];
- } else {
- for (i = 0; i < track->num_channels; i++) {
- alsa_track->volumes[i] = volumes[i];
- snd_mixer_selem_set_playback_volume (alsa_track->element, i,
- volumes[i]);
- }
- }
- }
-
- } else if (track->flags & GST_MIXER_TRACK_INPUT) {
-
- /* Is emulated record flag activated? */
- if (track->flags & GST_MIXER_TRACK_RECORD ||
- alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH) {
- if (check_if_volumes_are_the_same (track->num_channels, volumes)) {
- snd_mixer_selem_set_capture_volume_all (alsa_track->element,
- volumes[0]);
- for (i = 0; i < track->num_channels; i++)
- alsa_track->volumes[i] = volumes[0];
- } else {
- for (i = 0; i < track->num_channels; i++) {
- alsa_track->volumes[i] = volumes[i];
- snd_mixer_selem_set_capture_volume (alsa_track->element, i,
- volumes[i]);
- }
- }
- } else {
- for (i = 0; i < track->num_channels; i++)
- alsa_track->volumes[i] = volumes[i];
- }
- }
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-}
-
-void
-gst_alsa_mixer_set_mute (GstAlsaMixer * mixer, GstMixerTrack * track,
- gboolean mute)
-{
- GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track);
-
- g_return_if_fail (mixer->handle != NULL);
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- gst_alsa_mixer_track_update (alsa_track);
-
- if (!!(mute) == !!(track->flags & GST_MIXER_TRACK_MUTE)) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return;
- }
- if (mute) {
- track->flags |= GST_MIXER_TRACK_MUTE;
-
- if (alsa_track->shared_mute)
- ((GstMixerTrack *) (alsa_track->shared_mute))->flags |=
- GST_MIXER_TRACK_MUTE;
- } else {
- track->flags &= ~GST_MIXER_TRACK_MUTE;
-
- if (alsa_track->shared_mute)
- ((GstMixerTrack *) (alsa_track->shared_mute))->flags &=
- ~GST_MIXER_TRACK_MUTE;
- }
-
- if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_PSWITCH) {
- snd_mixer_selem_set_playback_switch_all (alsa_track->element, mute ? 0 : 1);
- } else {
- gint i;
- GstAlsaMixerTrack *ctrl_track;
-
- if ((track->flags & GST_MIXER_TRACK_INPUT)
- && alsa_track->shared_mute != NULL)
- ctrl_track = alsa_track->shared_mute;
- else
- ctrl_track = alsa_track;
-
- for (i = 0; i < ((GstMixerTrack *) ctrl_track)->num_channels; i++) {
- long vol =
- mute ? ((GstMixerTrack *) ctrl_track)->min_volume : ctrl_track->
- volumes[i];
- snd_mixer_selem_set_playback_volume (ctrl_track->element, i, vol);
- }
- }
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-}
-
-void
-gst_alsa_mixer_set_record (GstAlsaMixer * mixer,
- GstMixerTrack * track, gboolean record)
-{
- GstAlsaMixerTrack *alsa_track = GST_ALSA_MIXER_TRACK (track);
-
- g_return_if_fail (mixer->handle != NULL);
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
-
- gst_alsa_mixer_track_update (alsa_track);
-
- if (!!(record) == !!(track->flags & GST_MIXER_TRACK_RECORD)) {
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- return;
- }
-
- if (record) {
- track->flags |= GST_MIXER_TRACK_RECORD;
- } else {
- track->flags &= ~GST_MIXER_TRACK_RECORD;
- }
-
- if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH) {
- snd_mixer_selem_set_capture_switch_all (alsa_track->element,
- record ? 1 : 0);
-
- /* update all tracks in same exlusive cswitch group */
- if (alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH_EXCL) {
- GList *item;
-
- for (item = mixer->tracklist; item != NULL; item = item->next) {
-
- if (GST_IS_ALSA_MIXER_TRACK (item->data)) {
- GstAlsaMixerTrack *item_alsa_track =
- GST_ALSA_MIXER_TRACK (item->data);
-
- if (item_alsa_track->alsa_flags & GST_ALSA_MIXER_TRACK_CSWITCH_EXCL &&
- item_alsa_track->capture_group == alsa_track->capture_group) {
- gst_alsa_mixer_track_update (item_alsa_track);
- }
- }
- }
- }
- } else {
- gint i;
-
- for (i = 0; i < track->num_channels; i++) {
- long vol = record ? alsa_track->volumes[i] : track->min_volume;
-
- snd_mixer_selem_set_capture_volume (alsa_track->element, i, vol);
- }
- }
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-}
-
-void
-gst_alsa_mixer_set_option (GstAlsaMixer * mixer,
- GstMixerOptions * opts, gchar * value)
-{
- gint idx = -1, n = 0;
- GList *item;
- GstAlsaMixerOptions *alsa_opts = GST_ALSA_MIXER_OPTIONS (opts);
-
- g_return_if_fail (mixer->handle != NULL);
-
- for (item = opts->values; item != NULL; item = item->next, n++) {
- if (!strcmp (item->data, value)) {
- idx = n;
- break;
- }
- }
- if (idx == -1)
- return;
-
- g_static_rec_mutex_lock (mixer->rec_mutex);
- snd_mixer_selem_set_enum_item (alsa_opts->element, 0, idx);
- g_static_rec_mutex_unlock (mixer->rec_mutex);
-}
-
-const gchar *
-gst_alsa_mixer_get_option (GstAlsaMixer * mixer, GstMixerOptions * opts)
-{
- gint ret;
- guint idx;
- GstAlsaMixerOptions *alsa_opts = GST_ALSA_MIXER_OPTIONS (opts);
-
- g_return_val_if_fail (mixer->handle != NULL, NULL);
- g_static_rec_mutex_lock (mixer->rec_mutex);
- ret = snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx);
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- if (ret == 0)
- return g_list_nth_data (opts->values, idx);
- else
- return snd_strerror (ret); /* feeble attempt at error handling */
-}
-
-GstMixerFlags
-gst_alsa_mixer_get_mixer_flags (GstAlsaMixer * mixer)
-{
- g_return_val_if_fail (mixer != NULL, GST_MIXER_FLAG_NONE);
-
- return GST_MIXER_FLAG_AUTO_NOTIFICATIONS;
-}
-
-static void
-gst_alsa_mixer_update_option (GstAlsaMixer * mixer,
- GstAlsaMixerOptions * alsa_opts)
-{
- gint ret;
- guint idx;
- /* const */ gchar *option;
-
- if (mixer->interface == NULL) {
- GST_WARNING ("Cannot send update notifications, no GstMixer * given");
- return;
- }
- g_static_rec_mutex_lock (mixer->rec_mutex);
- ret = snd_mixer_selem_get_enum_item (alsa_opts->element, 0, &idx);
- g_static_rec_mutex_unlock (mixer->rec_mutex);
- if (ret == 0) {
- option = g_list_nth_data (GST_MIXER_OPTIONS (alsa_opts)->values, idx);
- gst_mixer_option_changed (mixer->interface, GST_MIXER_OPTIONS (alsa_opts),
- option);
- }
-}
-
-static void
-gst_alsa_mixer_update_track (GstAlsaMixer * mixer,
- GstAlsaMixerTrack * alsa_track)
-{
- GstMixerTrack *track = (GstMixerTrack *) alsa_track;
- gboolean old_mute;
- gboolean old_record;
- gint i, n_channels;
- gint *old_volumes;
-
- GST_DEBUG ("Updating track %" GST_PTR_FORMAT, alsa_track);
-
- if (mixer->interface == NULL) {
- GST_WARNING ("Cannot send update notifications, no GstMixer * given");
- return;
- }
-
- old_mute = !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE));
- old_record = !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD));
- old_volumes = g_new (gint, track->num_channels);
- n_channels = track->num_channels;
- memcpy (old_volumes, alsa_track->volumes,
- sizeof (gint) * track->num_channels);
-
- gst_alsa_mixer_track_update (alsa_track);
-
- if (old_record !=
- !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD))) {
- gst_mixer_record_toggled (mixer->interface, track,
- !!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD));
- }
- if (old_mute != !!(GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE))) {
- gst_mixer_mute_toggled (mixer->interface, track,
- !!GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_MUTE));
- }
-
- n_channels = MIN (n_channels, track->num_channels);
- for (i = 0; i < n_channels; i++) {
- if (old_volumes[i] != alsa_track->volumes[i]) {
- gst_mixer_volume_changed (mixer->interface, track, alsa_track->volumes);
- break;
- }
- }
- g_free (old_volumes);
-}
-
-/* utility function for gstalsamixerelement to set the interface */
-void
-_gst_alsa_mixer_set_interface (GstAlsaMixer * mixer, GstMixer * interface)
-{
- g_return_if_fail (mixer != NULL && mixer->interface == NULL);
- g_return_if_fail (interface != NULL);
-
- mixer->interface = g_object_ref (G_OBJECT (interface));
-}
diff --git a/ext/alsa/gstalsamixer.h b/ext/alsa/gstalsamixer.h
deleted file mode 100644
index ccc37845..00000000
--- a/ext/alsa/gstalsamixer.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/* ALSA mixer interface implementation.
- * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#ifndef __GST_ALSA_MIXER_H__
-#define __GST_ALSA_MIXER_H__
-
-
-#include "gstalsa.h"
-
-#include <gst/interfaces/mixer.h>
-#include "gstalsamixeroptions.h"
-#include "gstalsamixertrack.h"
-
-
-G_BEGIN_DECLS
-
-/* This does not get you what you think it does, use obj->mixer */
-/* #define GST_ALSA_MIXER(obj) ((GstAlsaMixer*)(obj)) */
-
-typedef struct _GstAlsaMixer GstAlsaMixer;
-
-typedef enum {
- GST_ALSA_MIXER_CAPTURE = 1<<0,
- GST_ALSA_MIXER_PLAYBACK = 1<<1,
- GST_ALSA_MIXER_ALL = GST_ALSA_MIXER_CAPTURE | GST_ALSA_MIXER_PLAYBACK
-} GstAlsaMixerDirection;
-
-/**
- * GstAlsaMixer:
- *
- * Opaque data structure
- */
-struct _GstAlsaMixer
-{
- GList * tracklist; /* list of available tracks */
-
- snd_mixer_t * handle;
-
- GstTask * task;
- GStaticRecMutex * task_mutex;
- GStaticRecMutex * rec_mutex;
-
- int pfd[2];
-
- GstMixer * interface;
- gchar * device;
- gchar * cardname;
-
- GstAlsaMixerDirection dir;
-};
-
-
-GstAlsaMixer* gst_alsa_mixer_new (const gchar *device,
- GstAlsaMixerDirection dir);
-void gst_alsa_mixer_free (GstAlsaMixer *mixer);
-
-const GList* gst_alsa_mixer_list_tracks (GstAlsaMixer * mixer);
-void gst_alsa_mixer_set_volume (GstAlsaMixer * mixer,
- GstMixerTrack * track,
- gint * volumes);
-void gst_alsa_mixer_get_volume (GstAlsaMixer * mixer,
- GstMixerTrack * track,
- gint * volumes);
-void gst_alsa_mixer_set_record (GstAlsaMixer * mixer,
- GstMixerTrack * track,
- gboolean record);
-void gst_alsa_mixer_set_mute (GstAlsaMixer * mixer,
- GstMixerTrack * track,
- gboolean mute);
-void gst_alsa_mixer_set_option (GstAlsaMixer * mixer,
- GstMixerOptions * opts,
- gchar * value);
-const gchar* gst_alsa_mixer_get_option (GstAlsaMixer * mixer,
- GstMixerOptions * opts);
-void _gst_alsa_mixer_set_interface (GstAlsaMixer * mixer,
- GstMixer * interface);
-GstMixerFlags gst_alsa_mixer_get_mixer_flags (GstAlsaMixer *mixer);
-
-#define GST_IMPLEMENT_ALSA_MIXER_METHODS(Type, interface_as_function) \
-static gboolean \
-interface_as_function ## _supported (Type *this, GType iface_type) \
-{ \
- g_assert (iface_type == GST_TYPE_MIXER); \
- \
- return (this->mixer != NULL); \
-} \
- \
-static const GList* \
-interface_as_function ## _list_tracks (GstMixer * mixer) \
-{ \
- Type *this = (Type*) mixer; \
- \
- g_return_val_if_fail (this != NULL, NULL); \
- g_return_val_if_fail (this->mixer != NULL, NULL); \
- \
- return gst_alsa_mixer_list_tracks (this->mixer); \
-} \
- \
-static void \
-interface_as_function ## _set_volume (GstMixer * mixer, GstMixerTrack * track, \
- gint * volumes) \
-{ \
- Type *this = (Type*) mixer; \
- \
- g_return_if_fail (this != NULL); \
- g_return_if_fail (this->mixer != NULL); \
- \
- gst_alsa_mixer_set_volume (this->mixer, track, volumes); \
-} \
- \
-static void \
-interface_as_function ## _get_volume (GstMixer * mixer, GstMixerTrack * track, \
- gint * volumes) \
-{ \
- Type *this = (Type*) mixer; \
- \
- g_return_if_fail (this != NULL); \
- g_return_if_fail (this->mixer != NULL); \
- \
- gst_alsa_mixer_get_volume (this->mixer, track, volumes); \
-} \
- \
-static void \
-interface_as_function ## _set_record (GstMixer * mixer, GstMixerTrack * track, \
- gboolean record) \
-{ \
- Type *this = (Type*) mixer; \
- \
- g_return_if_fail (this != NULL); \
- g_return_if_fail (this->mixer != NULL); \
- \
- gst_alsa_mixer_set_record (this->mixer, track, record); \
-} \
- \
-static void \
-interface_as_function ## _set_mute (GstMixer * mixer, GstMixerTrack * track, \
- gboolean mute) \
-{ \
- Type *this = (Type*) mixer; \
- \
- g_return_if_fail (this != NULL); \
- g_return_if_fail (this->mixer != NULL); \
- \
- gst_alsa_mixer_set_mute (this->mixer, track, mute); \
-} \
- \
-static void \
-interface_as_function ## _set_option (GstMixer * mixer, GstMixerOptions * opts, \
- gchar * value) \
-{ \
- Type *this = (Type*) mixer; \
- \
- g_return_if_fail (this != NULL); \
- g_return_if_fail (this->mixer != NULL); \
- \
- gst_alsa_mixer_set_option (this->mixer, opts, value); \
-} \
- \
-static const gchar* \
-interface_as_function ## _get_option (GstMixer * mixer, GstMixerOptions * opts) \
-{ \
- Type *this = (Type*) mixer; \
- \
- g_return_val_if_fail (this != NULL, NULL); \
- g_return_val_if_fail (this->mixer != NULL, NULL); \
- \
- return gst_alsa_mixer_get_option (this->mixer, opts); \
-} \
- \
-static GstMixerFlags \
-interface_as_function ## _get_mixer_flags (GstMixer * mixer) \
-{ \
- Type *this = (Type*) mixer; \
- \
- g_return_val_if_fail (this != NULL, GST_MIXER_FLAG_NONE); \
- g_return_val_if_fail (this->mixer != NULL, GST_MIXER_FLAG_NONE); \
- \
- return gst_alsa_mixer_get_mixer_flags (this->mixer); \
-} \
- \
-static void \
-interface_as_function ## _interface_init (GstMixerClass * klass) \
-{ \
- GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \
- \
- /* set up the interface hooks */ \
- klass->list_tracks = interface_as_function ## _list_tracks; \
- klass->set_volume = interface_as_function ## _set_volume; \
- klass->get_volume = interface_as_function ## _get_volume; \
- klass->set_mute = interface_as_function ## _set_mute; \
- klass->set_record = interface_as_function ## _set_record; \
- klass->set_option = interface_as_function ## _set_option; \
- klass->get_option = interface_as_function ## _get_option; \
- klass->get_mixer_flags = interface_as_function ## _get_mixer_flags; \
-}
-
-
-G_END_DECLS
-
-
-#endif /* __GST_ALSA_MIXER_H__ */
diff --git a/ext/alsa/gstalsamixerelement.c b/ext/alsa/gstalsamixerelement.c
deleted file mode 100644
index 57e35263..00000000
--- a/ext/alsa/gstalsamixerelement.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/* ALSA mixer implementation.
- * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
- *
- * 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 "gstalsamixerelement.h"
-#include "gstalsadeviceprobe.h"
-
-#define DEFAULT_PROP_DEVICE "default"
-#define DEFAULT_PROP_DEVICE_NAME ""
-
-enum
-{
- PROP_0,
- PROP_DEVICE,
- PROP_DEVICE_NAME
-};
-
-static const GstElementDetails gst_alsa_mixer_element_details =
-GST_ELEMENT_DETAILS ("Alsa mixer",
- "Generic/Audio",
- "Control sound input and output levels with ALSA",
- "Leif Johnson <leif@ambient.2y.net>");
-
-static void gst_alsa_mixer_element_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstAlsaMixerElement, gst_alsa_mixer_element,
- GstElement, GST_TYPE_ELEMENT, gst_alsa_mixer_element_init_interfaces);
-
-/* massive macro that takes care of all the GstMixer stuff */
-GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaMixerElement, gst_alsa_mixer_element);
-
-static void gst_alsa_mixer_element_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec);
-static void gst_alsa_mixer_element_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_alsa_mixer_element_finalize (GObject * object);
-
-static GstStateChangeReturn gst_alsa_mixer_element_change_state (GstElement
- * element, GstStateChange transition);
-
-static gboolean
-gst_alsa_mixer_element_interface_supported (GstAlsaMixerElement * this,
- GType interface_type)
-{
- if (interface_type == GST_TYPE_MIXER) {
- return gst_alsa_mixer_element_supported (this, interface_type);
- }
-
- g_return_val_if_reached (FALSE);
-}
-
-static void
-gst_implements_interface_init (GstImplementsInterfaceClass * klass)
-{
- klass->supported = (gpointer) gst_alsa_mixer_element_interface_supported;
-}
-
-static void
-gst_alsa_mixer_element_init_interfaces (GType type)
-{
- static const GInterfaceInfo implements_iface_info = {
- (GInterfaceInitFunc) gst_implements_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo mixer_iface_info = {
- (GInterfaceInitFunc) gst_alsa_mixer_element_interface_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
- &implements_iface_info);
- g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info);
-
- gst_alsa_type_add_device_property_probe_interface (type);
-}
-
-static void
-gst_alsa_mixer_element_base_init (gpointer klass)
-{
- gst_element_class_set_details (GST_ELEMENT_CLASS (klass),
- &gst_alsa_mixer_element_details);
-}
-
-static void
-gst_alsa_mixer_element_class_init (GstAlsaMixerElementClass * klass)
-{
- GstElementClass *element_class;
- GObjectClass *gobject_class;
-
- element_class = (GstElementClass *) klass;
- gobject_class = (GObjectClass *) klass;
-
- gobject_class->finalize = gst_alsa_mixer_element_finalize;
- gobject_class->get_property = gst_alsa_mixer_element_get_property;
- gobject_class->set_property = gst_alsa_mixer_element_set_property;
-
- g_object_class_install_property (gobject_class, PROP_DEVICE,
- g_param_spec_string ("device", "Device",
- "ALSA device, as defined in an asound configuration file",
- DEFAULT_PROP_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
- g_param_spec_string ("device-name", "Device name",
- "Human-readable name of the sound device",
- DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- element_class->change_state =
- GST_DEBUG_FUNCPTR (gst_alsa_mixer_element_change_state);
-}
-
-static void
-gst_alsa_mixer_element_finalize (GObject * obj)
-{
- GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (obj);
-
- g_free (this->device);
-
- G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-static void
-gst_alsa_mixer_element_init (GstAlsaMixerElement * this,
- GstAlsaMixerElementClass * klass)
-{
- this->mixer = NULL;
- this->device = g_strdup (DEFAULT_PROP_DEVICE);
-}
-
-static void
-gst_alsa_mixer_element_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (object);
-
- switch (prop_id) {
- case PROP_DEVICE:{
- GST_OBJECT_LOCK (this);
- g_free (this->device);
- this->device = g_value_dup_string (value);
- /* make sure we never set NULL, this is nice when we want to open the
- * device. */
- if (this->device == NULL)
- this->device = g_strdup (DEFAULT_PROP_DEVICE);
- GST_OBJECT_UNLOCK (this);
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_alsa_mixer_element_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (object);
-
- switch (prop_id) {
- case PROP_DEVICE:{
- GST_OBJECT_LOCK (this);
- g_value_set_string (value, this->device);
- GST_OBJECT_UNLOCK (this);
- break;
- }
- case PROP_DEVICE_NAME:{
- GST_OBJECT_LOCK (this);
- if (this->mixer) {
- g_value_set_string (value, this->mixer->cardname);
- } else {
- g_value_set_string (value, NULL);
- }
- GST_OBJECT_UNLOCK (this);
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GstStateChangeReturn
-gst_alsa_mixer_element_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstAlsaMixerElement *this = GST_ALSA_MIXER_ELEMENT (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- if (!this->mixer) {
- this->mixer = gst_alsa_mixer_new (this->device, GST_ALSA_MIXER_ALL);
- if (!this->mixer)
- goto open_failed;
- _gst_alsa_mixer_set_interface (this->mixer, GST_MIXER (element));
- }
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
- if (ret == GST_STATE_CHANGE_FAILURE)
- return ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_NULL:
- if (this->mixer) {
- gst_alsa_mixer_free (this->mixer);
- this->mixer = NULL;
- }
- break;
- default:
- break;
- }
-
- return ret;
-
- /* ERRORS */
-open_failed:
- {
- GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ_WRITE, (NULL),
- ("Failed to open alsa mixer device '%s'", this->device));
- return GST_STATE_CHANGE_FAILURE;
- }
-}
diff --git a/ext/alsa/gstalsamixerelement.h b/ext/alsa/gstalsamixerelement.h
deleted file mode 100644
index 16cb2458..00000000
--- a/ext/alsa/gstalsamixerelement.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* ALSA mixer interface implementation.
- * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#ifndef __GST_ALSA_MIXER_ELEMENT_H__
-#define __GST_ALSA_MIXER_ELEMENT_H__
-
-
-#include "gstalsa.h"
-#include "gstalsamixer.h"
-
-G_BEGIN_DECLS
-
-#define GST_ALSA_MIXER_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIXER_ELEMENT,GstAlsaMixerElement))
-#define GST_ALSA_MIXER_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIXER_ELEMENT,GstAlsaMixerElementClass))
-#define GST_IS_ALSA_MIXER_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIXER_ELEMENT))
-#define GST_IS_ALSA_MIXER_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIXER_ELEMENT))
-#define GST_TYPE_ALSA_MIXER_ELEMENT (gst_alsa_mixer_element_get_type())
-
-typedef struct _GstAlsaMixerElement GstAlsaMixerElement;
-typedef struct _GstAlsaMixerElementClass GstAlsaMixerElementClass;
-
-/**
- * GstAlsaMixerElement
- *
- * Opaque datastructure.
- */
-struct _GstAlsaMixerElement {
- GstElement parent;
-
- GstAlsaMixer *mixer;
- gchar *device;
-};
-
-struct _GstAlsaMixerElementClass {
- GstElementClass parent;
-};
-
-
-GType gst_alsa_mixer_element_get_type (void);
-
-
-G_END_DECLS
-
-
-#endif /* __GST_ALSA_MIXER_ELEMENT_H__ */
diff --git a/ext/alsa/gstalsamixeroptions.c b/ext/alsa/gstalsamixeroptions.c
deleted file mode 100644
index 20bb89d7..00000000
--- a/ext/alsa/gstalsamixeroptions.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/* ALSA mixer object implementation.
- * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
- *
- * 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 "gstalsamixeroptions.h"
-
-static void gst_alsa_mixer_options_init (GstAlsaMixerOptions * alsa_opts);
-static void gst_alsa_mixer_options_class_init (gpointer g_class,
- gpointer class_data);
-
-static GstMixerOptionsClass *parent_class = NULL;
-
-GType
-gst_alsa_mixer_options_get_type (void)
-{
- static GType opts_type = 0;
-
- if (!opts_type) {
- static const GTypeInfo opts_info = {
- sizeof (GstAlsaMixerOptionsClass),
- NULL,
- NULL,
- gst_alsa_mixer_options_class_init,
- NULL,
- NULL,
- sizeof (GstAlsaMixerOptions),
- 0,
- (GInstanceInitFunc) gst_alsa_mixer_options_init,
- };
-
- opts_type =
- g_type_register_static (GST_TYPE_MIXER_OPTIONS, "GstAlsaMixerOptions",
- &opts_info, 0);
- }
-
- return opts_type;
-}
-
-static void
-gst_alsa_mixer_options_class_init (gpointer g_class, gpointer class_data)
-{
- parent_class = g_type_class_peek_parent (g_class);
-}
-
-static void
-gst_alsa_mixer_options_init (GstAlsaMixerOptions * alsa_opts)
-{
-}
-
-GstMixerOptions *
-gst_alsa_mixer_options_new (snd_mixer_elem_t * element, gint track_num)
-{
- GstMixerOptions *opts;
- GstAlsaMixerOptions *alsa_opts;
- GstMixerTrack *track;
- const gchar *label;
- guint index;
- gint num, i;
- gchar str[256];
-
- label = snd_mixer_selem_get_name (element);
- index = snd_mixer_selem_get_index (element);
-
- GST_LOG ("[%s,%u]", label, index);
-
- opts = g_object_new (GST_ALSA_MIXER_OPTIONS_TYPE,
- "untranslated-label", label, "index", index, NULL);
- alsa_opts = (GstAlsaMixerOptions *) opts;
- track = (GstMixerTrack *) opts;
-
- /* set basic information */
- track->label = g_strdup (label); /* FIXME: translate this? */
- track->num_channels = 0;
- track->flags = 0;
- alsa_opts->element = element;
- alsa_opts->track_num = track_num;
-
- /* get enumerations for switch/options object */
- num = snd_mixer_selem_get_enum_items (element);
- for (i = 0; i < num; i++) {
- if (snd_mixer_selem_get_enum_item_name (element, i, 255, str) < 0) {
- g_object_unref (G_OBJECT (alsa_opts));
- return NULL;
- }
-
- opts->values = g_list_append (opts->values, g_strdup (str));
- }
-
- return opts;
-}
diff --git a/ext/alsa/gstalsamixeroptions.h b/ext/alsa/gstalsamixeroptions.h
deleted file mode 100644
index b3c36c0d..00000000
--- a/ext/alsa/gstalsamixeroptions.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* ALSA mixer options object.
- * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#ifndef __GST_ALSA_MIXER_OPTIONS_H__
-#define __GST_ALSA_MIXER_OPTIONS_H__
-
-
-#include "gstalsa.h"
-#include <gst/interfaces/mixeroptions.h>
-
-
-G_BEGIN_DECLS
-
-
-#define GST_ALSA_MIXER_OPTIONS_TYPE (gst_alsa_mixer_options_get_type ())
-#define GST_ALSA_MIXER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIXER_OPTIONS,GstAlsaMixerOptions))
-#define GST_ALSA_MIXER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIXER_OPTIONS,GstAlsaMixerOptionsClass))
-#define GST_IS_ALSA_MIXER_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIXER_OPTIONS))
-#define GST_IS_ALSA_MIXER_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIXER_OPTIONS))
-#define GST_TYPE_ALSA_MIXER_OPTIONS (gst_alsa_mixer_options_get_type())
-
-
-typedef struct _GstAlsaMixerOptions GstAlsaMixerOptions;
-typedef struct _GstAlsaMixerOptionsClass GstAlsaMixerOptionsClass;
-
-
-struct _GstAlsaMixerOptions {
- GstMixerOptions parent;
- snd_mixer_elem_t *element; /* the ALSA mixer element for this track */
- gint track_num;
-};
-
-struct _GstAlsaMixerOptionsClass {
- GstMixerOptionsClass parent;
-};
-
-
-GType gst_alsa_mixer_options_get_type (void);
-GstMixerOptions *gst_alsa_mixer_options_new (snd_mixer_elem_t * element,
- gint track_num);
-
-
-G_END_DECLS
-
-
-#endif /* __GST_ALSA_MIXER_OPTIONS_H__ */
diff --git a/ext/alsa/gstalsamixertrack.c b/ext/alsa/gstalsamixertrack.c
deleted file mode 100644
index a1fdb7f3..00000000
--- a/ext/alsa/gstalsamixertrack.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* ALSA mixer track implementation.
- * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
- *
- * 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-i18n-plugin.h>
-
-#include "gstalsamixertrack.h"
-
-static void gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track);
-static void gst_alsa_mixer_track_class_init (gpointer g_class,
- gpointer class_data);
-
-static GstMixerTrackClass *parent_class = NULL;
-
-GType
-gst_alsa_mixer_track_get_type (void)
-{
- static GType track_type = 0;
-
- if (!track_type) {
- static const GTypeInfo track_info = {
- sizeof (GstAlsaMixerTrackClass),
- NULL,
- NULL,
- gst_alsa_mixer_track_class_init,
- NULL,
- NULL,
- sizeof (GstAlsaMixerTrack),
- 0,
- (GInstanceInitFunc) gst_alsa_mixer_track_init,
- NULL
- };
-
- track_type =
- g_type_register_static (GST_TYPE_MIXER_TRACK, "GstAlsaMixerTrack",
- &track_info, 0);
- }
-
- return track_type;
-}
-
-static void
-gst_alsa_mixer_track_class_init (gpointer g_class, gpointer class_data)
-{
- parent_class = g_type_class_peek_parent (g_class);
-}
-
-static void
-gst_alsa_mixer_track_init (GstAlsaMixerTrack * alsa_track)
-{
-}
-
-static void
-gst_alsa_mixer_track_update_alsa_capabilities (GstAlsaMixerTrack * alsa_track)
-{
- alsa_track->alsa_flags = 0;
- alsa_track->capture_group = -1;
-
- /* common flags */
- if (snd_mixer_selem_has_common_volume (alsa_track->element))
- alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_VOLUME;
-
- if (snd_mixer_selem_has_common_switch (alsa_track->element))
- alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_SWITCH;
-
- /* Since we create two separate mixer track objects for alsa elements that
- * support both playback and capture, we're going to 'hide' the alsa flags
- * that don't pertain to this mixer track from alsa_flags, otherwise
- * gst_alsa_mixer_track_update() is going to do things we don't want */
-
- /* playback flags */
- if ((GST_MIXER_TRACK (alsa_track)->flags & GST_MIXER_TRACK_OUTPUT)) {
- if (snd_mixer_selem_has_playback_volume (alsa_track->element))
- alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PVOLUME;
-
- if (snd_mixer_selem_has_playback_switch (alsa_track->element))
- alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_PSWITCH;
- }
-
- /* capture flags */
- if ((GST_MIXER_TRACK (alsa_track)->flags & GST_MIXER_TRACK_INPUT)) {
- if (snd_mixer_selem_has_capture_volume (alsa_track->element))
- alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CVOLUME;
-
- if (snd_mixer_selem_has_capture_switch (alsa_track->element)) {
- alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH;
-
- if (snd_mixer_selem_has_capture_switch_exclusive (alsa_track->element)) {
- alsa_track->alsa_flags |= GST_ALSA_MIXER_TRACK_CSWITCH_EXCL;
- alsa_track->capture_group =
- snd_mixer_selem_get_capture_group (alsa_track->element);
- }
- }
- }
-
- GST_LOG ("[%s] alsa_flags=0x%08x, capture_group=%d",
- snd_mixer_selem_get_name (alsa_track->element),
- alsa_track->alsa_flags, alsa_track->capture_group);
-}
-
-inline static gboolean
-alsa_track_has_cap (GstAlsaMixerTrack * alsa_track, guint32 flag)
-{
- return ((alsa_track->alsa_flags & flag) != 0);
-}
-
-GstMixerTrack *
-gst_alsa_mixer_track_new (snd_mixer_elem_t * element,
- gint num, gint track_num, gint flags, gboolean sw,
- GstAlsaMixerTrack * shared_mute_track, gboolean append_capture)
-{
- GstAlsaMixerTrack *alsa_track;
- GstMixerTrack *track;
- const gchar *name;
- guint index;
- const gchar *label;
- gint i;
- long min = 0, max = 0;
- const struct
- {
- const gchar orig[12];
- const gchar trans[12];
- } alsa_track_labels[] = {
- {
- "Master", N_("Master")}, {
- "Bass", N_("Bass")}, {
- "Treble", N_("Treble")}, {
- "PCM", N_("PCM")}, {
- "Synth", N_("Synth")}, {
- "Line", N_("Line-in")}, {
- "CD", N_("CD")}, {
- "Mic", N_("Microphone")}, {
- "PC Speaker", N_("PC Speaker")}, {
- "Playback", N_("Playback")}, {
- "Capture", N_("Capture")}
- };
-
- name = snd_mixer_selem_get_name (element);
- index = snd_mixer_selem_get_index (element);
-
- GST_LOG
- ("[%s,%u] num=%d,track_num=%d,flags=0x%08x,sw=%s,shared_mute_track=%p",
- name, index, num, track_num, flags, (sw) ? "true" : "false",
- shared_mute_track);
-
- track = (GstMixerTrack *) g_object_new (GST_ALSA_MIXER_TRACK_TYPE,
- "untranslated-label", name, "index", index, NULL);
-
- alsa_track = (GstAlsaMixerTrack *) track;
-
- GST_LOG ("[%s] created new mixer track %p", name, track);
-
- /* This reflects the assumptions used for GstAlsaMixerTrack */
- if (!(!!(flags & GST_MIXER_TRACK_OUTPUT) ^ !!(flags & GST_MIXER_TRACK_INPUT))) {
- GST_ERROR ("Mixer track must be either output or input!");
- g_return_val_if_reached (NULL);
- }
-
- track->flags = flags;
- alsa_track->element = element;
- alsa_track->shared_mute = shared_mute_track;
- alsa_track->track_num = track_num;
- alsa_track->alsa_channels = 0;
-
- gst_alsa_mixer_track_update_alsa_capabilities (alsa_track);
-
- if (flags & GST_MIXER_TRACK_OUTPUT) {
- while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
- snd_mixer_selem_has_playback_channel (element,
- alsa_track->alsa_channels)) {
- alsa_track->alsa_channels++;
- }
- GST_LOG ("[%s] %d output channels", name, alsa_track->alsa_channels);
- } else if (flags & GST_MIXER_TRACK_INPUT) {
- while (alsa_track->alsa_channels < GST_ALSA_MAX_CHANNELS &&
- snd_mixer_selem_has_capture_channel (element,
- alsa_track->alsa_channels)) {
- alsa_track->alsa_channels++;
- }
- GST_LOG ("[%s] %d input channels", name, alsa_track->alsa_channels);
- } else {
- g_assert_not_reached ();
- }
-
- if (sw)
- track->num_channels = 0;
- else
- track->num_channels = alsa_track->alsa_channels;
-
- /* translate the name if we can */
- label = name;
- for (i = 0; i < G_N_ELEMENTS (alsa_track_labels); ++i) {
- if (g_utf8_collate (label, alsa_track_labels[i].orig) == 0) {
- label = _(alsa_track_labels[i].trans);
- break;
- }
- }
-
- if (num == 0) {
- track->label = g_strdup_printf ("%s%s%s", label,
- append_capture ? " " : "", append_capture ? _("Capture") : "");
- } else {
- track->label = g_strdup_printf ("%s%s%s %d", label,
- append_capture ? " " : "", append_capture ? _("Capture") : "", num);
- }
-
- /* set volume information */
- if (track->num_channels > 0) {
- if ((flags & GST_MIXER_TRACK_OUTPUT))
- snd_mixer_selem_get_playback_volume_range (element, &min, &max);
- else
- snd_mixer_selem_get_capture_volume_range (element, &min, &max);
- }
- track->min_volume = (gint) min;
- track->max_volume = (gint) max;
-
- for (i = 0; i < track->num_channels; i++) {
- long tmp = 0;
-
- if (flags & GST_MIXER_TRACK_OUTPUT)
- snd_mixer_selem_get_playback_volume (element, i, &tmp);
- else
- snd_mixer_selem_get_capture_volume (element, i, &tmp);
-
- alsa_track->volumes[i] = (gint) tmp;
- }
-
- gst_alsa_mixer_track_update (alsa_track);
-
- return track;
-}
-
-void
-gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track)
-{
- GstMixerTrack *track = (GstMixerTrack *) alsa_track;
- gint i;
- gint audible = !(track->flags & GST_MIXER_TRACK_MUTE);
-
- if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME)) {
- /* update playback volume */
- for (i = 0; i < track->num_channels; i++) {
- long vol = 0;
-
- snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
- alsa_track->volumes[i] = (gint) vol;
- }
- }
-
- if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME)) {
- /* update capture volume */
- for (i = 0; i < track->num_channels; i++) {
- long vol = 0;
-
- snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
- alsa_track->volumes[i] = (gint) vol;
- }
- }
-
- /* Any updates in flags? */
- if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PSWITCH)) {
- int v = 0;
-
- audible = 0;
- for (i = 0; i < alsa_track->alsa_channels; ++i) {
- snd_mixer_selem_get_playback_switch (alsa_track->element, i, &v);
- audible += v;
- }
-
- } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_PVOLUME) &&
- track->flags & GST_MIXER_TRACK_MUTE) {
- /* check if user has raised volume with a parallel running application */
-
- for (i = 0; i < track->num_channels; i++) {
- long vol = 0;
-
- snd_mixer_selem_get_playback_volume (alsa_track->element, i, &vol);
-
- if (vol > track->min_volume) {
- audible = 1;
- break;
- }
- }
- }
-
- if (!!(audible) != !(track->flags & GST_MIXER_TRACK_MUTE)) {
- if (audible) {
- track->flags &= ~GST_MIXER_TRACK_MUTE;
-
- if (alsa_track->shared_mute)
- ((GstMixerTrack *) (alsa_track->shared_mute))->flags &=
- ~GST_MIXER_TRACK_MUTE;
- } else {
- track->flags |= GST_MIXER_TRACK_MUTE;
-
- if (alsa_track->shared_mute)
- ((GstMixerTrack *) (alsa_track->shared_mute))->flags |=
- GST_MIXER_TRACK_MUTE;
- }
- }
-
- if (track->flags & GST_MIXER_TRACK_INPUT) {
- gint recording = track->flags & GST_MIXER_TRACK_RECORD;
-
- if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CSWITCH)) {
- int v = 0;
-
- recording = 0;
- for (i = 0; i < alsa_track->alsa_channels; ++i) {
- snd_mixer_selem_get_capture_switch (alsa_track->element, i, &v);
- recording += v;
- }
-
- } else if (alsa_track_has_cap (alsa_track, GST_ALSA_MIXER_TRACK_CVOLUME) &&
- !(track->flags & GST_MIXER_TRACK_RECORD)) {
- /* check if user has raised volume with a parallel running application */
-
- for (i = 0; i < track->num_channels; i++) {
- long vol = 0;
-
- snd_mixer_selem_get_capture_volume (alsa_track->element, i, &vol);
-
- if (vol > track->min_volume) {
- recording = 1;
- break;
- }
- }
- }
-
- if (recording)
- track->flags |= GST_MIXER_TRACK_RECORD;
- else
- track->flags &= ~GST_MIXER_TRACK_RECORD;
- }
-
-}
diff --git a/ext/alsa/gstalsamixertrack.h b/ext/alsa/gstalsamixertrack.h
deleted file mode 100644
index acc64cb3..00000000
--- a/ext/alsa/gstalsamixertrack.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* ALSA mixer track object.
- * Copyright (C) 2003 Leif Johnson <leif@ambient.2y.net>
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#ifndef __GST_ALSA_MIXER_TRACK_H__
-#define __GST_ALSA_MIXER_TRACK_H__
-
-
-#include "gstalsa.h"
-#include <gst/interfaces/mixertrack.h>
-
-
-G_BEGIN_DECLS
-
-
-#define GST_ALSA_MIXER_TRACK_TYPE (gst_alsa_mixer_track_get_type ())
-#define GST_ALSA_MIXER_TRACK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_MIXER_TRACK,GstAlsaMixerTrack))
-#define GST_ALSA_MIXER_TRACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_MIXER_TRACK,GstAlsaMixerTrackClass))
-#define GST_IS_ALSA_MIXER_TRACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_MIXER_TRACK))
-#define GST_IS_ALSA_MIXER_TRACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_MIXER_TRACK))
-#define GST_TYPE_ALSA_MIXER_TRACK (gst_alsa_mixer_track_get_type())
-
-typedef struct _GstAlsaMixerTrack GstAlsaMixerTrack;
-typedef struct _GstAlsaMixerTrackClass GstAlsaMixerTrackClass;
-
-#define GST_ALSA_MIXER_TRACK_VOLUME (1<<0) /* common volume */
-#define GST_ALSA_MIXER_TRACK_PVOLUME (1<<1)
-#define GST_ALSA_MIXER_TRACK_CVOLUME (1<<2)
-#define GST_ALSA_MIXER_TRACK_SWITCH (1<<3) /* common switch */
-#define GST_ALSA_MIXER_TRACK_PSWITCH (1<<4)
-#define GST_ALSA_MIXER_TRACK_CSWITCH (1<<5)
-#define GST_ALSA_MIXER_TRACK_CSWITCH_EXCL (1<<6)
-
-#define GST_ALSA_MAX_CHANNELS (SND_MIXER_SCHN_LAST+1)
-
-struct _GstAlsaMixerTrack {
- GstMixerTrack parent;
- snd_mixer_elem_t *element; /* the ALSA mixer element for this track */
- GstAlsaMixerTrack *shared_mute;
- gint track_num;
- guint32 alsa_flags; /* alsa track capabilities */
- gint alsa_channels;
- gint capture_group;
- gint volumes[GST_ALSA_MAX_CHANNELS];
-};
-
-struct _GstAlsaMixerTrackClass {
- GstMixerTrackClass parent;
-};
-
-GType gst_alsa_mixer_track_get_type (void);
-GstMixerTrack * gst_alsa_mixer_track_new (snd_mixer_elem_t * element,
- gint num,
- gint track_num,
- gint flags,
- gboolean sw, /* is simple switch? */
- GstAlsaMixerTrack * shared_mute_track,
- gboolean label_append_capture);
-void gst_alsa_mixer_track_update (GstAlsaMixerTrack * alsa_track);
-
-G_END_DECLS
-
-
-#endif /* __GST_ALSA_MIXER_TRACK_H__ */
diff --git a/ext/alsa/gstalsaplugin.c b/ext/alsa/gstalsaplugin.c
deleted file mode 100644
index 38f16e20..00000000
--- a/ext/alsa/gstalsaplugin.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2001 CodeFactory AB
- * Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
- * Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstalsasink.h"
-#include "gstalsasrc.h"
-#include "gstalsamixerelement.h"
-
-#include <gst/gst-i18n-plugin.h>
-
-GST_DEBUG_CATEGORY (alsa_debug);
-
-/* ALSA debugging wrapper */
-static void
-gst_alsa_error_wrapper (const char *file, int line, const char *function,
- int err, const char *fmt, ...)
-{
-#ifndef GST_DISABLE_GST_DEBUG
- va_list args;
- gchar *str;
-
- va_start (args, fmt);
- str = g_strdup_vprintf (fmt, args);
- va_end (args);
- /* FIXME: use GST_LEVEL_ERROR here? Currently warning is used because we're
- * able to catch enough of the errors that would be printed otherwise
- */
- gst_debug_log (alsa_debug, GST_LEVEL_WARNING, file, function, line, NULL,
- "alsalib error: %s%s%s", str, err ? ": " : "",
- err ? snd_strerror (err) : "");
- g_free (str);
-#endif
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- int err;
-
- if (!gst_element_register (plugin, "alsamixer", GST_RANK_NONE,
- GST_TYPE_ALSA_MIXER_ELEMENT))
- return FALSE;
- if (!gst_element_register (plugin, "alsasrc", GST_RANK_PRIMARY,
- GST_TYPE_ALSA_SRC))
- return FALSE;
- if (!gst_element_register (plugin, "alsasink", GST_RANK_PRIMARY,
- GST_TYPE_ALSA_SINK))
- return FALSE;
-
- GST_DEBUG_CATEGORY_INIT (alsa_debug, "alsa", 0, "alsa plugins");
-
-#if ENABLE_NLS
- GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
- LOCALEDIR);
- bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-#endif
-
- err = snd_lib_error_set_handler (gst_alsa_error_wrapper);
- if (err != 0)
- GST_WARNING ("failed to set alsa error handler");
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "alsa",
- "ALSA plugin library",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/alsa/gstalsasink.c b/ext/alsa/gstalsasink.c
deleted file mode 100644
index bc75ca6b..00000000
--- a/ext/alsa/gstalsasink.c
+++ /dev/null
@@ -1,968 +0,0 @@
-/* GStreamer
- * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
- * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
- *
- * gstalsasink.c:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-alsasink
- * @see_also: alsasrc, alsamixer
- *
- * This element renders raw audio samples using the ALSA api.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! alsasink
- * ]| Play an Ogg/Vorbis file.
- * </refsect2>
- *
- * Last reviewed on 2006-03-01 (0.10.4)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <getopt.h>
-#include <alsa/asoundlib.h>
-
-#include "gstalsa.h"
-#include "gstalsasink.h"
-#include "gstalsadeviceprobe.h"
-
-#include <gst/gst-i18n-plugin.h>
-
-/* elementfactory information */
-static const GstElementDetails gst_alsasink_details =
-GST_ELEMENT_DETAILS ("Audio sink (ALSA)",
- "Sink/Audio",
- "Output to a sound card via ALSA",
- "Wim Taymans <wim@fluendo.com>");
-
-#define DEFAULT_DEVICE "default"
-#define DEFAULT_DEVICE_NAME ""
-#define SPDIF_PERIOD_SIZE 1536
-#define SPDIF_BUFFER_SIZE 15360
-
-enum
-{
- PROP_0,
- PROP_DEVICE,
- PROP_DEVICE_NAME
-};
-
-static void gst_alsasink_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstAlsaSink, gst_alsasink, GstAudioSink,
- GST_TYPE_AUDIO_SINK, gst_alsasink_init_interfaces);
-
-static void gst_alsasink_finalise (GObject * object);
-static void gst_alsasink_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_alsasink_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec);
-
-static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink);
-
-static gboolean gst_alsasink_open (GstAudioSink * asink);
-static gboolean gst_alsasink_prepare (GstAudioSink * asink,
- GstRingBufferSpec * spec);
-static gboolean gst_alsasink_unprepare (GstAudioSink * asink);
-static gboolean gst_alsasink_close (GstAudioSink * asink);
-static guint gst_alsasink_write (GstAudioSink * asink, gpointer data,
- guint length);
-static guint gst_alsasink_delay (GstAudioSink * asink);
-static void gst_alsasink_reset (GstAudioSink * asink);
-
-static gint output_ref; /* 0 */
-static snd_output_t *output; /* NULL */
-static GStaticMutex output_mutex = G_STATIC_MUTEX_INIT;
-
-
-#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
-# define ALSA_SINK_FACTORY_ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
-#else
-# define ALSA_SINK_FACTORY_ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
-#endif
-
-static GstStaticPadTemplate alsasink_sink_factory =
- GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-raw-int, "
- "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 32, "
- "depth = (int) 32, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
- "audio/x-raw-int, "
- "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 24, "
- "depth = (int) 24, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
- "audio/x-raw-int, "
- "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 32, "
- "depth = (int) 24, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
- "audio/x-raw-int, "
- "endianness = (int) { " ALSA_SINK_FACTORY_ENDIANNESS " }, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 16, "
- "depth = (int) 16, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
- "audio/x-raw-int, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 8, "
- "depth = (int) 8, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ];"
- "audio/x-iec958")
- );
-
-static void
-gst_alsasink_finalise (GObject * object)
-{
- GstAlsaSink *sink = GST_ALSA_SINK (object);
-
- g_free (sink->device);
- g_mutex_free (sink->alsa_lock);
-
- g_static_mutex_lock (&output_mutex);
- --output_ref;
- if (output_ref == 0) {
- snd_output_close (output);
- output = NULL;
- }
- g_static_mutex_unlock (&output_mutex);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_alsasink_init_interfaces (GType type)
-{
- gst_alsa_type_add_device_property_probe_interface (type);
-}
-
-static void
-gst_alsasink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details (element_class, &gst_alsasink_details);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&alsasink_sink_factory));
-}
-
-static void
-gst_alsasink_class_init (GstAlsaSinkClass * klass)
-{
- GObjectClass *gobject_class;
- GstBaseSinkClass *gstbasesink_class;
- GstAudioSinkClass *gstaudiosink_class;
-
- gobject_class = (GObjectClass *) klass;
- gstbasesink_class = (GstBaseSinkClass *) klass;
- gstaudiosink_class = (GstAudioSinkClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->finalize = gst_alsasink_finalise;
- gobject_class->get_property = gst_alsasink_get_property;
- gobject_class->set_property = gst_alsasink_set_property;
-
- gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink_getcaps);
-
- gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_alsasink_open);
- gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasink_prepare);
- gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasink_unprepare);
- gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_alsasink_close);
- gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_alsasink_write);
- gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_alsasink_delay);
- gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_alsasink_reset);
-
- g_object_class_install_property (gobject_class, PROP_DEVICE,
- g_param_spec_string ("device", "Device",
- "ALSA device, as defined in an asound configuration file",
- DEFAULT_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
- g_param_spec_string ("device-name", "Device name",
- "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_alsasink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstAlsaSink *sink;
-
- sink = GST_ALSA_SINK (object);
-
- switch (prop_id) {
- case PROP_DEVICE:
- g_free (sink->device);
- sink->device = g_value_dup_string (value);
- /* setting NULL restores the default device */
- if (sink->device == NULL) {
- sink->device = g_strdup (DEFAULT_DEVICE);
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_alsasink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstAlsaSink *sink;
-
- sink = GST_ALSA_SINK (object);
-
- switch (prop_id) {
- case PROP_DEVICE:
- g_value_set_string (value, sink->device);
- break;
- case PROP_DEVICE_NAME:
- g_value_take_string (value,
- gst_alsa_find_device_name (GST_OBJECT_CAST (sink),
- sink->device, sink->handle, SND_PCM_STREAM_PLAYBACK));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_alsasink_init (GstAlsaSink * alsasink, GstAlsaSinkClass * g_class)
-{
- GST_DEBUG_OBJECT (alsasink, "initializing alsasink");
-
- alsasink->device = g_strdup (DEFAULT_DEVICE);
- alsasink->handle = NULL;
- alsasink->cached_caps = NULL;
- alsasink->alsa_lock = g_mutex_new ();
-
- g_static_mutex_lock (&output_mutex);
- if (output_ref == 0) {
- snd_output_stdio_attach (&output, stdout, 0);
- ++output_ref;
- }
- g_static_mutex_unlock (&output_mutex);
-}
-
-#define CHECK(call, error) \
-G_STMT_START { \
-if ((err = call) < 0) \
- goto error; \
-} G_STMT_END;
-
-static GstCaps *
-gst_alsasink_getcaps (GstBaseSink * bsink)
-{
- GstElementClass *element_class;
- GstPadTemplate *pad_template;
- GstAlsaSink *sink = GST_ALSA_SINK (bsink);
- GstCaps *caps;
-
- if (sink->handle == NULL) {
- GST_DEBUG_OBJECT (sink, "device not open, using template caps");
- return NULL; /* base class will get template caps for us */
- }
-
- if (sink->cached_caps) {
- GST_LOG_OBJECT (sink, "Returning cached caps");
- return gst_caps_ref (sink->cached_caps);
- }
-
- element_class = GST_ELEMENT_GET_CLASS (sink);
- pad_template = gst_element_class_get_pad_template (element_class, "sink");
- g_return_val_if_fail (pad_template != NULL, NULL);
-
- caps = gst_alsa_probe_supported_formats (GST_OBJECT (sink), sink->handle,
- gst_pad_template_get_caps (pad_template));
-
- if (caps) {
- sink->cached_caps = gst_caps_ref (caps);
- }
-
- GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, caps);
-
- return caps;
-}
-
-static int
-set_hwparams (GstAlsaSink * alsa)
-{
- guint rrate;
- gint err, dir;
- snd_pcm_hw_params_t *params;
- guint period_time, buffer_time;
-
- snd_pcm_hw_params_malloc (&params);
-
- GST_DEBUG_OBJECT (alsa, "Negotiating to %d channels @ %d Hz (format = %s) "
- "SPDIF (%d)", alsa->channels, alsa->rate,
- snd_pcm_format_name (alsa->format), alsa->iec958);
-
- /* start with requested values, if we cannot configure alsa for those values,
- * we set these values to -1, which will leave the default alsa values */
- buffer_time = alsa->buffer_time;
- period_time = alsa->period_time;
-
-retry:
- /* choose all parameters */
- CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config);
- /* set the interleaved read/write format */
- CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access),
- wrong_access);
- /* set the sample format */
- if (alsa->iec958) {
- /* Try to use big endian first else fallback to le and swap bytes */
- if (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format) < 0) {
- alsa->format = SND_PCM_FORMAT_S16_LE;
- alsa->need_swap = TRUE;
- GST_DEBUG_OBJECT (alsa, "falling back to little endian with swapping");
- } else {
- alsa->need_swap = FALSE;
- }
- }
- CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format),
- no_sample_format);
- /* set the count of channels */
- CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels),
- no_channels);
- /* set the stream rate */
- rrate = alsa->rate;
- CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL),
- no_rate);
- if (rrate != alsa->rate)
- goto rate_match;
-
- /* get and dump some limits */
- {
- guint min, max;
-
- snd_pcm_hw_params_get_buffer_time_min (params, &min, &dir);
- snd_pcm_hw_params_get_buffer_time_max (params, &max, &dir);
-
- GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u",
- alsa->buffer_time, min, max);
-
- snd_pcm_hw_params_get_period_time_min (params, &min, &dir);
- snd_pcm_hw_params_get_period_time_max (params, &max, &dir);
-
- GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u",
- alsa->period_time, min, max);
-
- snd_pcm_hw_params_get_periods_min (params, &min, &dir);
- snd_pcm_hw_params_get_periods_max (params, &max, &dir);
-
- GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max);
- }
-
- /* now try to configure the buffer time and period time, if one
- * of those fail, we fall back to the defaults and emit a warning. */
- if (buffer_time != -1 && !alsa->iec958) {
- /* set the buffer time */
- if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
- &buffer_time, &dir)) < 0) {
- GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set buffer time %i for playback: %s",
- buffer_time, snd_strerror (err)));
- /* disable buffer_time the next round */
- buffer_time = -1;
- goto retry;
- }
- GST_DEBUG_OBJECT (alsa, "buffer time %u", buffer_time);
- }
- if (period_time != -1 && !alsa->iec958) {
- /* set the period time */
- if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
- &period_time, &dir)) < 0) {
- GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set period time %i for playback: %s",
- period_time, snd_strerror (err)));
- /* disable period_time the next round */
- period_time = -1;
- goto retry;
- }
- GST_DEBUG_OBJECT (alsa, "period time %u", period_time);
- }
-
- /* Set buffer size and period size manually for SPDIF */
- if (G_UNLIKELY (alsa->iec958)) {
- snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE;
- snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE;
-
- CHECK (snd_pcm_hw_params_set_buffer_size_near (alsa->handle, params,
- &buffer_size), buffer_size);
- CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params,
- &period_size, NULL), period_size);
- }
-
- /* write the parameters to device */
- CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);
-
- /* now get the configured values */
- CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size),
- buffer_size);
- CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, &dir),
- period_size);
-
- GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size,
- alsa->period_size);
-
- snd_pcm_hw_params_free (params);
- return 0;
-
- /* ERRORS */
-no_config:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Broken configuration for playback: no configurations available: %s",
- snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-wrong_access:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Access type not available for playback: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-no_sample_format:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Sample format not available for playback: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-no_channels:
- {
- gchar *msg = NULL;
-
- if ((alsa->channels) == 1)
- msg = g_strdup (_("Could not open device for playback in mono mode."));
- if ((alsa->channels) == 2)
- msg = g_strdup (_("Could not open device for playback in stereo mode."));
- if ((alsa->channels) > 2)
- msg =
- g_strdup_printf (_
- ("Could not open device for playback in %d-channel mode."),
- alsa->channels);
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (msg), (snd_strerror (err)));
- g_free (msg);
- snd_pcm_hw_params_free (params);
- return err;
- }
-no_rate:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Rate %iHz not available for playback: %s",
- alsa->rate, snd_strerror (err)));
- return err;
- }
-rate_match:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Rate doesn't match (requested %iHz, get %iHz)", alsa->rate, err));
- snd_pcm_hw_params_free (params);
- return -EINVAL;
- }
-buffer_size:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to get buffer size for playback: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-period_size:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to get period size for playback: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-set_hw_params:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set hw params for playback: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-}
-
-static int
-set_swparams (GstAlsaSink * alsa)
-{
- int err;
- snd_pcm_sw_params_t *params;
-
- snd_pcm_sw_params_malloc (&params);
-
- /* get the current swparams */
- CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config);
- /* start the transfer when the buffer is almost full: */
- /* (buffer_size / avail_min) * avail_min */
- CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params,
- (alsa->buffer_size / alsa->period_size) * alsa->period_size),
- start_threshold);
-
- /* allow the transfer when at least period_size samples can be processed */
- CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params,
- alsa->period_size), set_avail);
-
-#if GST_CHECK_ALSA_VERSION(1,0,16)
- /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */
-#else
- /* align all transfers to 1 sample */
- CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align);
-#endif
-
- /* write the parameters to the playback device */
- CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);
-
- snd_pcm_sw_params_free (params);
- return 0;
-
- /* ERRORS */
-no_config:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to determine current swparams for playback: %s",
- snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-start_threshold:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set start threshold mode for playback: %s",
- snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-set_avail:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set avail min for playback: %s", snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-#if !GST_CHECK_ALSA_VERSION(1,0,16)
-set_align:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set transfer align for playback: %s", snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-#endif
-set_sw_params:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set sw params for playback: %s", snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-}
-
-static gboolean
-alsasink_parse_spec (GstAlsaSink * alsa, GstRingBufferSpec * spec)
-{
- /* Initialize our boolean */
- alsa->iec958 = FALSE;
-
- switch (spec->type) {
- case GST_BUFTYPE_LINEAR:
- GST_DEBUG_OBJECT (alsa,
- "Linear format : depth=%d, width=%d, sign=%d, bigend=%d", spec->depth,
- spec->width, spec->sign, spec->bigend);
-
- alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width,
- spec->sign ? 0 : 1, spec->bigend ? 1 : 0);
- break;
- case GST_BUFTYPE_FLOAT:
- switch (spec->format) {
- case GST_FLOAT32_LE:
- alsa->format = SND_PCM_FORMAT_FLOAT_LE;
- break;
- case GST_FLOAT32_BE:
- alsa->format = SND_PCM_FORMAT_FLOAT_BE;
- break;
- case GST_FLOAT64_LE:
- alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
- break;
- case GST_FLOAT64_BE:
- alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
- break;
- default:
- goto error;
- }
- break;
- case GST_BUFTYPE_A_LAW:
- alsa->format = SND_PCM_FORMAT_A_LAW;
- break;
- case GST_BUFTYPE_MU_LAW:
- alsa->format = SND_PCM_FORMAT_MU_LAW;
- break;
- case GST_BUFTYPE_IEC958:
- alsa->format = SND_PCM_FORMAT_S16_BE;
- alsa->iec958 = TRUE;
- break;
- default:
- goto error;
-
- }
- alsa->rate = spec->rate;
- alsa->channels = spec->channels;
- alsa->buffer_time = spec->buffer_time;
- alsa->period_time = spec->latency_time;
- alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
-
- return TRUE;
-
- /* ERRORS */
-error:
- {
- return FALSE;
- }
-}
-
-static gboolean
-gst_alsasink_open (GstAudioSink * asink)
-{
- GstAlsaSink *alsa;
- gint err;
-
- alsa = GST_ALSA_SINK (asink);
-
- /* open in non-blocking mode, we'll use snd_pcm_wait() for space to become
- * available. */
- CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_PLAYBACK,
- SND_PCM_NONBLOCK), open_error);
- GST_LOG_OBJECT (alsa, "Opened device %s", alsa->device);
-
- return TRUE;
-
- /* ERRORS */
-open_error:
- {
- if (err == -EBUSY) {
- GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY,
- (_("Could not open audio device for playback. "
- "Device is being used by another application.")),
- ("Device '%s' is busy", alsa->device));
- } else {
- GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE,
- (_("Could not open audio device for playback.")),
- ("Playback open error on device '%s': %s", alsa->device,
- snd_strerror (err)));
- }
- return FALSE;
- }
-}
-
-static gboolean
-gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
-{
- GstAlsaSink *alsa;
- gint err;
-
- alsa = GST_ALSA_SINK (asink);
-
- if (spec->format == GST_IEC958) {
- snd_pcm_close (alsa->handle);
- alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa));
- if (G_UNLIKELY (!alsa->handle)) {
- goto no_iec958;
- }
- }
-
- if (!alsasink_parse_spec (alsa, spec))
- goto spec_parse;
-
- CHECK (set_hwparams (alsa), hw_params_failed);
- CHECK (set_swparams (alsa), sw_params_failed);
-
- alsa->bytes_per_sample = spec->bytes_per_sample;
- spec->segsize = alsa->period_size * spec->bytes_per_sample;
- spec->segtotal = alsa->buffer_size / alsa->period_size;
-
- {
- snd_output_t *out_buf = NULL;
- char *msg = NULL;
-
- snd_output_buffer_open (&out_buf);
- snd_pcm_dump_hw_setup (alsa->handle, out_buf);
- snd_output_buffer_string (out_buf, &msg);
- GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg);
- snd_output_close (out_buf);
- snd_output_buffer_open (&out_buf);
- snd_pcm_dump_sw_setup (alsa->handle, out_buf);
- snd_output_buffer_string (out_buf, &msg);
- GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg);
- snd_output_close (out_buf);
- }
-
- return TRUE;
-
- /* ERRORS */
-no_iec958:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE, (NULL),
- ("Could not open IEC958 (SPDIF) device for playback"));
- return FALSE;
- }
-spec_parse:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Error parsing spec"));
- return FALSE;
- }
-hw_params_failed:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Setting of hwparams failed: %s", snd_strerror (err)));
- return FALSE;
- }
-sw_params_failed:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Setting of swparams failed: %s", snd_strerror (err)));
- return FALSE;
- }
-}
-
-static gboolean
-gst_alsasink_unprepare (GstAudioSink * asink)
-{
- GstAlsaSink *alsa;
- gint err;
-
- alsa = GST_ALSA_SINK (asink);
-
- CHECK (snd_pcm_drop (alsa->handle), drop);
-
- CHECK (snd_pcm_hw_free (alsa->handle), hw_free);
-
- return TRUE;
-
- /* ERRORS */
-drop:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Could not drop samples: %s", snd_strerror (err)));
- return FALSE;
- }
-hw_free:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Could not free hw params: %s", snd_strerror (err)));
- return FALSE;
- }
-}
-
-static gboolean
-gst_alsasink_close (GstAudioSink * asink)
-{
- GstAlsaSink *alsa = GST_ALSA_SINK (asink);
- gint err;
-
- if (alsa->handle) {
- CHECK (snd_pcm_close (alsa->handle), close_error);
- alsa->handle = NULL;
- }
- gst_caps_replace (&alsa->cached_caps, NULL);
-
- return TRUE;
-
- /* ERRORS */
-close_error:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, CLOSE, (NULL),
- ("Playback close error: %s", snd_strerror (err)));
- return FALSE;
- }
-}
-
-
-/*
- * Underrun and suspend recovery
- */
-static gint
-xrun_recovery (GstAlsaSink * alsa, snd_pcm_t * handle, gint err)
-{
- GST_DEBUG_OBJECT (alsa, "xrun recovery %d", err);
-
- if (err == -EPIPE) { /* under-run */
- err = snd_pcm_prepare (handle);
- if (err < 0)
- GST_WARNING_OBJECT (alsa,
- "Can't recovery from underrun, prepare failed: %s",
- snd_strerror (err));
- return 0;
- } else if (err == -ESTRPIPE) {
- while ((err = snd_pcm_resume (handle)) == -EAGAIN)
- g_usleep (100); /* wait until the suspend flag is released */
-
- if (err < 0) {
- err = snd_pcm_prepare (handle);
- if (err < 0)
- GST_WARNING_OBJECT (alsa,
- "Can't recovery from suspend, prepare failed: %s",
- snd_strerror (err));
- }
- return 0;
- }
- return err;
-}
-
-static guint
-gst_alsasink_write (GstAudioSink * asink, gpointer data, guint length)
-{
- GstAlsaSink *alsa;
- gint err;
- gint cptr;
- gint16 *ptr = data;
-
- alsa = GST_ALSA_SINK (asink);
-
- if (alsa->iec958 && alsa->need_swap) {
- guint i;
-
- GST_DEBUG_OBJECT (asink, "swapping bytes");
- for (i = 0; i < length / 2; i++) {
- ptr[i] = GUINT16_SWAP_LE_BE (ptr[i]);
- }
- }
-
- GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length);
-
- cptr = length / alsa->bytes_per_sample;
-
- GST_ALSA_SINK_LOCK (asink);
- while (cptr > 0) {
- /* start by doing a blocking wait for free space. Set the timeout
- * to 4 times the period time */
- err = snd_pcm_wait (alsa->handle, (4 * alsa->period_time / 1000));
- if (err < 0) {
- GST_DEBUG_OBJECT (asink, "wait error, %d", err);
- } else {
- err = snd_pcm_writei (alsa->handle, ptr, cptr);
- }
-
- GST_DEBUG_OBJECT (asink, "written %d frames out of %d", err, cptr);
- if (err < 0) {
- GST_DEBUG_OBJECT (asink, "Write error: %s", snd_strerror (err));
- if (err == -EAGAIN) {
- continue;
- } else if (xrun_recovery (alsa, alsa->handle, err) < 0) {
- goto write_error;
- }
- continue;
- }
-
- ptr += snd_pcm_frames_to_bytes (alsa->handle, err);
- cptr -= err;
- }
- GST_ALSA_SINK_UNLOCK (asink);
-
- return length - (cptr * alsa->bytes_per_sample);
-
-write_error:
- {
- GST_ALSA_SINK_UNLOCK (asink);
- return length; /* skip one period */
- }
-}
-
-static guint
-gst_alsasink_delay (GstAudioSink * asink)
-{
- GstAlsaSink *alsa;
- snd_pcm_sframes_t delay;
- int res;
-
- alsa = GST_ALSA_SINK (asink);
-
- res = snd_pcm_delay (alsa->handle, &delay);
- if (G_UNLIKELY (res < 0)) {
- /* on errors, report 0 delay */
- GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res);
- delay = 0;
- }
- if (G_UNLIKELY (delay < 0)) {
- /* make sure we never return a negative delay */
- GST_WARNING_OBJECT (alsa, "snd_pcm_delay returned negative delay");
- delay = 0;
- }
-
- return delay;
-}
-
-static void
-gst_alsasink_reset (GstAudioSink * asink)
-{
- GstAlsaSink *alsa;
- gint err;
-
- alsa = GST_ALSA_SINK (asink);
-
- GST_ALSA_SINK_LOCK (asink);
- GST_DEBUG_OBJECT (alsa, "drop");
- CHECK (snd_pcm_drop (alsa->handle), drop_error);
- GST_DEBUG_OBJECT (alsa, "prepare");
- CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
- GST_DEBUG_OBJECT (alsa, "reset done");
- GST_ALSA_SINK_UNLOCK (asink);
-
- return;
-
- /* ERRORS */
-drop_error:
- {
- GST_ERROR_OBJECT (alsa, "alsa-reset: pcm drop error: %s",
- snd_strerror (err));
- GST_ALSA_SINK_UNLOCK (asink);
- return;
- }
-prepare_error:
- {
- GST_ERROR_OBJECT (alsa, "alsa-reset: pcm prepare error: %s",
- snd_strerror (err));
- GST_ALSA_SINK_UNLOCK (asink);
- return;
- }
-}
diff --git a/ext/alsa/gstalsasink.h b/ext/alsa/gstalsasink.h
deleted file mode 100644
index 902dbf77..00000000
--- a/ext/alsa/gstalsasink.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* GStreamer
- * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstalsasink.h:
- *
- * 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_ALSASINK_H__
-#define __GST_ALSASINK_H__
-
-#include <gst/gst.h>
-#include <gst/audio/gstaudiosink.h>
-#include <alsa/asoundlib.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_ALSA_SINK (gst_alsasink_get_type())
-#define GST_ALSA_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SINK,GstAlsaSink))
-#define GST_ALSA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SINK,GstAlsaSinkClass))
-#define GST_IS_ALSA_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SINK))
-#define GST_IS_ALSA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SINK))
-#define GST_ALSA_SINK_CAST(obj) ((GstAlsaSink *) (obj))
-
-typedef struct _GstAlsaSink GstAlsaSink;
-typedef struct _GstAlsaSinkClass GstAlsaSinkClass;
-
-#define GST_ALSA_SINK_GET_LOCK(obj) (GST_ALSA_SINK_CAST (obj)->alsa_lock)
-#define GST_ALSA_SINK_LOCK(obj) (g_mutex_lock (GST_ALSA_SINK_GET_LOCK (obj)))
-#define GST_ALSA_SINK_UNLOCK(obj) (g_mutex_unlock (GST_ALSA_SINK_GET_LOCK (obj)))
-
-/**
- * GstAlsaSink:
- *
- * Opaque data structure
- */
-struct _GstAlsaSink {
- GstAudioSink sink;
-
- gchar *device;
-
- snd_pcm_t *handle;
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_sw_params_t *swparams;
-
- snd_pcm_access_t access;
- snd_pcm_format_t format;
- guint rate;
- guint channels;
- gint bytes_per_sample;
- gboolean iec958;
- gboolean need_swap;
-
- guint buffer_time;
- guint period_time;
- snd_pcm_uframes_t buffer_size;
- snd_pcm_uframes_t period_size;
-
- GstCaps *cached_caps;
-
- GMutex *alsa_lock;
-};
-
-struct _GstAlsaSinkClass {
- GstAudioSinkClass parent_class;
-};
-
-GType gst_alsasink_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_ALSASINK_H__ */
diff --git a/ext/alsa/gstalsasrc.c b/ext/alsa/gstalsasrc.c
deleted file mode 100644
index db9c3a60..00000000
--- a/ext/alsa/gstalsasrc.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/* GStreamer
- * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstalsasrc.c:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-alsasrc
- * @see_also: alsasink, alsamixer
- *
- * This element reads data from an audio card using the ALSA API.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v alsasrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
- * ]| Record from a sound card using ALSA and encode to Ogg/Vorbis.
- * </refsect2>
- *
- * Last reviewed on 2006-03-01 (0.10.4)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <getopt.h>
-#include <alsa/asoundlib.h>
-
-#include "gstalsasrc.h"
-#include "gstalsadeviceprobe.h"
-
-#include <gst/gst-i18n-plugin.h>
-
-/* elementfactory information */
-static const GstElementDetails gst_alsasrc_details =
-GST_ELEMENT_DETAILS ("Audio source (ALSA)",
- "Source/Audio",
- "Read from a sound card via ALSA",
- "Wim Taymans <wim@fluendo.com>");
-
-#define DEFAULT_PROP_DEVICE "default"
-#define DEFAULT_PROP_DEVICE_NAME ""
-
-enum
-{
- PROP_0,
- PROP_DEVICE,
- PROP_DEVICE_NAME,
-};
-
-static void gst_alsasrc_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstAlsaSrc, gst_alsasrc, GstAudioSrc,
- GST_TYPE_AUDIO_SRC, gst_alsasrc_init_interfaces);
-
-GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaSrc, gst_alsasrc_mixer);
-
-static void gst_alsasrc_finalize (GObject * object);
-static void gst_alsasrc_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_alsasrc_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec);
-
-static GstCaps *gst_alsasrc_getcaps (GstBaseSrc * bsrc);
-
-static gboolean gst_alsasrc_open (GstAudioSrc * asrc);
-static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc,
- GstRingBufferSpec * spec);
-static gboolean gst_alsasrc_unprepare (GstAudioSrc * asrc);
-static gboolean gst_alsasrc_close (GstAudioSrc * asrc);
-static guint gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length);
-static guint gst_alsasrc_delay (GstAudioSrc * asrc);
-static void gst_alsasrc_reset (GstAudioSrc * asrc);
-
-/* AlsaSrc signals and args */
-enum
-{
- LAST_SIGNAL
-};
-
-#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
-# define ALSA_SRC_FACTORY_ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
-#else
-# define ALSA_SRC_FACTORY_ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
-#endif
-
-static GstStaticPadTemplate alsasrc_src_factory =
- GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-raw-int, "
- "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 32, "
- "depth = (int) 32, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
- "audio/x-raw-int, "
- "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 32, "
- "depth = (int) 24, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
- "audio/x-raw-int, "
- "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 24, "
- "depth = (int) 24, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
- "audio/x-raw-int, "
- "endianness = (int) { " ALSA_SRC_FACTORY_ENDIANNESS " }, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 16, "
- "depth = (int) 16, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
- "audio/x-raw-int, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 8, "
- "depth = (int) 8, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
- );
-
-static void
-gst_alsasrc_finalize (GObject * object)
-{
- GstAlsaSrc *src = GST_ALSA_SRC (object);
-
- g_free (src->device);
- g_mutex_free (src->alsa_lock);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static gboolean
-gst_alsasrc_interface_supported (GstAlsaSrc * this, GType interface_type)
-{
- /* only support this one interface (wrapped by GstImplementsInterface) */
- g_assert (interface_type == GST_TYPE_MIXER);
-
- return gst_alsasrc_mixer_supported (this, interface_type);
-}
-
-static void
-gst_implements_interface_init (GstImplementsInterfaceClass * klass)
-{
- klass->supported = (gpointer) gst_alsasrc_interface_supported;
-}
-
-static void
-gst_alsasrc_init_interfaces (GType type)
-{
- static const GInterfaceInfo implements_iface_info = {
- (GInterfaceInitFunc) gst_implements_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo mixer_iface_info = {
- (GInterfaceInitFunc) gst_alsasrc_mixer_interface_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
- &implements_iface_info);
- g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info);
-
- gst_alsa_type_add_device_property_probe_interface (type);
-}
-
-static void
-gst_alsasrc_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details (element_class, &gst_alsasrc_details);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&alsasrc_src_factory));
-}
-
-static void
-gst_alsasrc_class_init (GstAlsaSrcClass * klass)
-{
- GObjectClass *gobject_class;
- GstBaseSrcClass *gstbasesrc_class;
- GstAudioSrcClass *gstaudiosrc_class;
-
- gobject_class = (GObjectClass *) klass;
- gstbasesrc_class = (GstBaseSrcClass *) klass;
- gstaudiosrc_class = (GstAudioSrcClass *) klass;
-
- gobject_class->finalize = gst_alsasrc_finalize;
- gobject_class->get_property = gst_alsasrc_get_property;
- gobject_class->set_property = gst_alsasrc_set_property;
-
- gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasrc_getcaps);
-
- gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_alsasrc_open);
- gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasrc_prepare);
- gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasrc_unprepare);
- gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_alsasrc_close);
- gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_alsasrc_read);
- gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_alsasrc_delay);
- gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_alsasrc_reset);
-
- g_object_class_install_property (gobject_class, PROP_DEVICE,
- g_param_spec_string ("device", "Device",
- "ALSA device, as defined in an asound configuration file",
- DEFAULT_PROP_DEVICE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
- g_param_spec_string ("device-name", "Device name",
- "Human-readable name of the sound device",
- DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_alsasrc_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstAlsaSrc *src;
-
- src = GST_ALSA_SRC (object);
-
- switch (prop_id) {
- case PROP_DEVICE:
- g_free (src->device);
- src->device = g_value_dup_string (value);
- if (src->device == NULL) {
- src->device = g_strdup (DEFAULT_PROP_DEVICE);
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_alsasrc_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstAlsaSrc *src;
-
- src = GST_ALSA_SRC (object);
-
- switch (prop_id) {
- case PROP_DEVICE:
- g_value_set_string (value, src->device);
- break;
- case PROP_DEVICE_NAME:
- g_value_take_string (value,
- gst_alsa_find_device_name (GST_OBJECT_CAST (src),
- src->device, src->handle, SND_PCM_STREAM_CAPTURE));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_alsasrc_init (GstAlsaSrc * alsasrc, GstAlsaSrcClass * g_class)
-{
- GST_DEBUG_OBJECT (alsasrc, "initializing");
-
- alsasrc->device = g_strdup (DEFAULT_PROP_DEVICE);
- alsasrc->cached_caps = NULL;
-
- alsasrc->alsa_lock = g_mutex_new ();
-}
-
-#define CHECK(call, error) \
-G_STMT_START { \
-if ((err = call) < 0) \
- goto error; \
-} G_STMT_END;
-
-
-static GstCaps *
-gst_alsasrc_getcaps (GstBaseSrc * bsrc)
-{
- GstElementClass *element_class;
- GstPadTemplate *pad_template;
- GstAlsaSrc *src;
- GstCaps *caps;
-
- src = GST_ALSA_SRC (bsrc);
-
- if (src->handle == NULL) {
- GST_DEBUG_OBJECT (src, "device not open, using template caps");
- return NULL; /* base class will get template caps for us */
- }
-
- if (src->cached_caps) {
- GST_LOG_OBJECT (src, "Returning cached caps");
- return gst_caps_ref (src->cached_caps);
- }
-
- element_class = GST_ELEMENT_GET_CLASS (src);
- pad_template = gst_element_class_get_pad_template (element_class, "src");
- g_return_val_if_fail (pad_template != NULL, NULL);
-
- caps = gst_alsa_probe_supported_formats (GST_OBJECT (src), src->handle,
- gst_pad_template_get_caps (pad_template));
-
- if (caps) {
- src->cached_caps = gst_caps_ref (caps);
- }
-
- GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps);
-
- return caps;
-}
-
-static int
-set_hwparams (GstAlsaSrc * alsa)
-{
- guint rrate;
- gint err, dir;
- snd_pcm_hw_params_t *params;
-
- snd_pcm_hw_params_malloc (&params);
-
- /* choose all parameters */
- CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config);
- /* set the interleaved read/write format */
- CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access),
- wrong_access);
- /* set the sample format */
- CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format),
- no_sample_format);
- /* set the count of channels */
- CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels),
- no_channels);
- /* set the stream rate */
- rrate = alsa->rate;
- CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL),
- no_rate);
- if (rrate != alsa->rate)
- goto rate_match;
-
- if (alsa->buffer_time != -1) {
- /* set the buffer time */
- CHECK (snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
- &alsa->buffer_time, &dir), buffer_time);
- }
- if (alsa->period_time != -1) {
- /* set the period time */
- CHECK (snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
- &alsa->period_time, &dir), period_time);
- }
-
- /* write the parameters to device */
- CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);
-
- CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size),
- buffer_size);
-
- CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, &dir),
- period_size);
-
- snd_pcm_hw_params_free (params);
- return 0;
-
- /* ERRORS */
-no_config:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Broken configuration for recording: no configurations available: %s",
- snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-wrong_access:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Access type not available for recording: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-no_sample_format:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Sample format not available for recording: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-no_channels:
- {
- gchar *msg = NULL;
-
- if ((alsa->channels) == 1)
- msg = g_strdup (_("Could not open device for recording in mono mode."));
- if ((alsa->channels) == 2)
- msg = g_strdup (_("Could not open device for recording in stereo mode."));
- if ((alsa->channels) > 2)
- msg =
- g_strdup_printf (_
- ("Could not open device for recording in %d-channel mode"),
- alsa->channels);
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (msg), (snd_strerror (err)));
- g_free (msg);
- snd_pcm_hw_params_free (params);
- return err;
- }
-no_rate:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Rate %iHz not available for recording: %s",
- alsa->rate, snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-rate_match:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Rate doesn't match (requested %iHz, get %iHz)", alsa->rate, err));
- snd_pcm_hw_params_free (params);
- return -EINVAL;
- }
-buffer_time:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set buffer time %i for recording: %s",
- alsa->buffer_time, snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-buffer_size:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to get buffer size for recording: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-period_time:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set period time %i for recording: %s", alsa->period_time,
- snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-period_size:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to get period size for recording: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-set_hw_params:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set hw params for recording: %s", snd_strerror (err)));
- snd_pcm_hw_params_free (params);
- return err;
- }
-}
-
-static int
-set_swparams (GstAlsaSrc * alsa)
-{
- int err;
- snd_pcm_sw_params_t *params;
-
- snd_pcm_sw_params_malloc (&params);
-
- /* get the current swparams */
- CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config);
- /* allow the transfer when at least period_size samples can be processed */
- CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params,
- alsa->period_size), set_avail);
- /* start the transfer on first read */
- CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params,
- 0), start_threshold);
-
-#if GST_CHECK_ALSA_VERSION(1,0,16)
- /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */
-#else
- /* align all transfers to 1 sample */
- CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align);
-#endif
-
- /* write the parameters to the recording device */
- CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);
-
- snd_pcm_sw_params_free (params);
- return 0;
-
- /* ERRORS */
-no_config:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to determine current swparams for playback: %s",
- snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-start_threshold:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set start threshold mode for playback: %s",
- snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-set_avail:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set avail min for playback: %s", snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-#if !GST_CHECK_ALSA_VERSION(1,0,16)
-set_align:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set transfer align for playback: %s", snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-#endif
-set_sw_params:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Unable to set sw params for playback: %s", snd_strerror (err)));
- snd_pcm_sw_params_free (params);
- return err;
- }
-}
-
-static gboolean
-alsasrc_parse_spec (GstAlsaSrc * alsa, GstRingBufferSpec * spec)
-{
- switch (spec->type) {
- case GST_BUFTYPE_LINEAR:
- alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width,
- spec->sign ? 0 : 1, spec->bigend ? 1 : 0);
- break;
- case GST_BUFTYPE_FLOAT:
- switch (spec->format) {
- case GST_FLOAT32_LE:
- alsa->format = SND_PCM_FORMAT_FLOAT_LE;
- break;
- case GST_FLOAT32_BE:
- alsa->format = SND_PCM_FORMAT_FLOAT_BE;
- break;
- case GST_FLOAT64_LE:
- alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
- break;
- case GST_FLOAT64_BE:
- alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
- break;
- default:
- goto error;
- }
- break;
- case GST_BUFTYPE_A_LAW:
- alsa->format = SND_PCM_FORMAT_A_LAW;
- break;
- case GST_BUFTYPE_MU_LAW:
- alsa->format = SND_PCM_FORMAT_MU_LAW;
- break;
- default:
- goto error;
-
- }
- alsa->rate = spec->rate;
- alsa->channels = spec->channels;
- alsa->buffer_time = spec->buffer_time;
- alsa->period_time = spec->latency_time;
- alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
-
- return TRUE;
-
- /* ERRORS */
-error:
- {
- return FALSE;
- }
-}
-
-static gboolean
-gst_alsasrc_open (GstAudioSrc * asrc)
-{
- GstAlsaSrc *alsa;
- gint err;
-
- alsa = GST_ALSA_SRC (asrc);
-
- CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_CAPTURE,
- SND_PCM_NONBLOCK), open_error);
-
- if (!alsa->mixer)
- alsa->mixer = gst_alsa_mixer_new (alsa->device, GST_ALSA_MIXER_CAPTURE);
-
- return TRUE;
-
- /* ERRORS */
-open_error:
- {
- if (err == -EBUSY) {
- GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY,
- (_("Could not open audio device for recording. "
- "Device is being used by another application.")),
- ("Device '%s' is busy", alsa->device));
- } else {
- GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
- (_("Could not open audio device for recording.")),
- ("Recording open error on device '%s': %s", alsa->device,
- snd_strerror (err)));
- }
- return FALSE;
- }
-}
-
-static gboolean
-gst_alsasrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
-{
- GstAlsaSrc *alsa;
- gint err;
-
- alsa = GST_ALSA_SRC (asrc);
-
- if (!alsasrc_parse_spec (alsa, spec))
- goto spec_parse;
-
- CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block);
-
- CHECK (set_hwparams (alsa), hw_params_failed);
- CHECK (set_swparams (alsa), sw_params_failed);
- CHECK (snd_pcm_prepare (alsa->handle), prepare_failed);
-
- alsa->bytes_per_sample = spec->bytes_per_sample;
- spec->segsize = alsa->period_size * spec->bytes_per_sample;
- spec->segtotal = alsa->buffer_size / alsa->period_size;
- spec->silence_sample[0] = 0;
- spec->silence_sample[1] = 0;
- spec->silence_sample[2] = 0;
- spec->silence_sample[3] = 0;
-
- return TRUE;
-
- /* ERRORS */
-spec_parse:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Error parsing spec"));
- return FALSE;
- }
-non_block:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Could not set device to blocking: %s", snd_strerror (err)));
- return FALSE;
- }
-hw_params_failed:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Setting of hwparams failed: %s", snd_strerror (err)));
- return FALSE;
- }
-sw_params_failed:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Setting of swparams failed: %s", snd_strerror (err)));
- return FALSE;
- }
-prepare_failed:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Prepare failed: %s", snd_strerror (err)));
- return FALSE;
- }
-}
-
-static gboolean
-gst_alsasrc_unprepare (GstAudioSrc * asrc)
-{
- GstAlsaSrc *alsa;
- gint err;
-
- alsa = GST_ALSA_SRC (asrc);
-
- CHECK (snd_pcm_drop (alsa->handle), drop);
-
- CHECK (snd_pcm_hw_free (alsa->handle), hw_free);
-
- CHECK (snd_pcm_nonblock (alsa->handle, 1), non_block);
-
- return TRUE;
-
- /* ERRORS */
-drop:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Could not drop samples: %s", snd_strerror (err)));
- return FALSE;
- }
-hw_free:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Could not free hw params: %s", snd_strerror (err)));
- return FALSE;
- }
-non_block:
- {
- GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
- ("Could not set device to nonblocking: %s", snd_strerror (err)));
- return FALSE;
- }
-}
-
-static gboolean
-gst_alsasrc_close (GstAudioSrc * asrc)
-{
- GstAlsaSrc *alsa = GST_ALSA_SRC (asrc);
-
- snd_pcm_close (alsa->handle);
- alsa->handle = NULL;
-
- if (alsa->mixer) {
- gst_alsa_mixer_free (alsa->mixer);
- alsa->mixer = NULL;
- }
-
- gst_caps_replace (&alsa->cached_caps, NULL);
-
- return TRUE;
-}
-
-/*
- * Underrun and suspend recovery
- */
-static gint
-xrun_recovery (GstAlsaSrc * alsa, snd_pcm_t * handle, gint err)
-{
- GST_DEBUG_OBJECT (alsa, "xrun recovery %d", err);
-
- if (err == -EPIPE) { /* under-run */
- err = snd_pcm_prepare (handle);
- if (err < 0)
- GST_WARNING_OBJECT (alsa,
- "Can't recovery from underrun, prepare failed: %s",
- snd_strerror (err));
- return 0;
- } else if (err == -ESTRPIPE) {
- while ((err = snd_pcm_resume (handle)) == -EAGAIN)
- g_usleep (100); /* wait until the suspend flag is released */
-
- if (err < 0) {
- err = snd_pcm_prepare (handle);
- if (err < 0)
- GST_WARNING_OBJECT (alsa,
- "Can't recovery from suspend, prepare failed: %s",
- snd_strerror (err));
- }
- return 0;
- }
- return err;
-}
-
-static guint
-gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length)
-{
- GstAlsaSrc *alsa;
- gint err;
- gint cptr;
- gint16 *ptr;
-
- alsa = GST_ALSA_SRC (asrc);
-
- cptr = length / alsa->bytes_per_sample;
- ptr = data;
-
- GST_ALSA_SRC_LOCK (asrc);
- while (cptr > 0) {
- if ((err = snd_pcm_readi (alsa->handle, ptr, cptr)) < 0) {
- if (err == -EAGAIN) {
- GST_DEBUG_OBJECT (asrc, "Read error: %s", snd_strerror (err));
- continue;
- } else if (xrun_recovery (alsa, alsa->handle, err) < 0) {
- goto read_error;
- }
- continue;
- }
-
- ptr += err * alsa->channels;
- cptr -= err;
- }
- GST_ALSA_SRC_UNLOCK (asrc);
-
- return length - cptr;
-
-read_error:
- {
- GST_ALSA_SRC_UNLOCK (asrc);
- return length; /* skip one period */
- }
-}
-
-static guint
-gst_alsasrc_delay (GstAudioSrc * asrc)
-{
- GstAlsaSrc *alsa;
- snd_pcm_sframes_t delay;
- int res;
-
- alsa = GST_ALSA_SRC (asrc);
-
- res = snd_pcm_delay (alsa->handle, &delay);
- if (G_UNLIKELY (res < 0)) {
- GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res);
- delay = 0;
- }
-
- return CLAMP (delay, 0, alsa->buffer_size);
-}
-
-static void
-gst_alsasrc_reset (GstAudioSrc * asrc)
-{
- GstAlsaSrc *alsa;
- gint err;
-
- alsa = GST_ALSA_SRC (asrc);
-
- GST_ALSA_SRC_LOCK (asrc);
- GST_DEBUG_OBJECT (alsa, "drop");
- CHECK (snd_pcm_drop (alsa->handle), drop_error);
- GST_DEBUG_OBJECT (alsa, "prepare");
- CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
- GST_DEBUG_OBJECT (alsa, "reset done");
- GST_ALSA_SRC_UNLOCK (asrc);
-
- return;
-
- /* ERRORS */
-drop_error:
- {
- GST_ERROR_OBJECT (alsa, "alsa-reset: pcm drop error: %s",
- snd_strerror (err));
- GST_ALSA_SRC_UNLOCK (asrc);
- return;
- }
-prepare_error:
- {
- GST_ERROR_OBJECT (alsa, "alsa-reset: pcm prepare error: %s",
- snd_strerror (err));
- GST_ALSA_SRC_UNLOCK (asrc);
- return;
- }
-}
diff --git a/ext/alsa/gstalsasrc.h b/ext/alsa/gstalsasrc.h
deleted file mode 100644
index d0fcbf07..00000000
--- a/ext/alsa/gstalsasrc.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/* GStreamer
- * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstalsasrc.h:
- *
- * 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_ALSASRC_H__
-#define __GST_ALSASRC_H__
-
-#include <gst/audio/gstaudiosrc.h>
-#include "gstalsa.h"
-#include "gstalsamixer.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_ALSA_SRC (gst_alsasrc_get_type())
-#define GST_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SRC,GstAlsaSrc))
-#define GST_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SRC,GstAlsaSrcClass))
-#define GST_IS_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SRC))
-#define GST_IS_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SRC))
-#define GST_ALSA_SRC_CAST(obj) ((GstAlsaSrc *)(obj))
-
-#define GST_ALSA_SRC_GET_LOCK(obj) (GST_ALSA_SRC_CAST (obj)->alsa_lock)
-#define GST_ALSA_SRC_LOCK(obj) (g_mutex_lock (GST_ALSA_SRC_GET_LOCK (obj)))
-#define GST_ALSA_SRC_UNLOCK(obj) (g_mutex_unlock (GST_ALSA_SRC_GET_LOCK (obj)))
-
-typedef struct _GstAlsaSrc GstAlsaSrc;
-typedef struct _GstAlsaSrcClass GstAlsaSrcClass;
-
-/**
- * GstAlsaSrc:
- *
- * Opaque data structure
- */
-struct _GstAlsaSrc {
- GstAudioSrc src;
-
- gchar *device;
-
- snd_pcm_t *handle;
- snd_pcm_hw_params_t *hwparams;
- snd_pcm_sw_params_t *swparams;
-
- GstCaps *cached_caps;
-
- snd_pcm_access_t access;
- snd_pcm_format_t format;
- guint rate;
- guint channels;
- gint bytes_per_sample;
-
- guint buffer_time;
- guint period_time;
- snd_pcm_uframes_t buffer_size;
- snd_pcm_uframes_t period_size;
-
- GstAlsaMixer *mixer;
-
- GMutex *alsa_lock;
-};
-
-struct _GstAlsaSrcClass {
- GstAudioSrcClass parent_class;
-};
-
-GType gst_alsasrc_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_ALSASRC_H__ */
diff --git a/ext/cdparanoia/Makefile.am b/ext/cdparanoia/Makefile.am
deleted file mode 100644
index aef35819..00000000
--- a/ext/cdparanoia/Makefile.am
+++ /dev/null
@@ -1,13 +0,0 @@
-plugin_LTLIBRARIES = libgstcdparanoia.la
-
-libgstcdparanoia_la_SOURCES = gstcdparanoiasrc.c
-libgstcdparanoia_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
-libgstcdparanoia_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/cdda/libgstcdda-$(GST_MAJORMINOR).la \
- $(GST_BASE_LIBS) \
- $(GST_LIBS) \
- $(CDPARANOIA_LIBS)
-libgstcdparanoia_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstcdparanoia_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = gstcdparanoiasrc.h
diff --git a/ext/cdparanoia/gstcdparanoiasrc.c b/ext/cdparanoia/gstcdparanoiasrc.c
deleted file mode 100644
index fb710e0d..00000000
--- a/ext/cdparanoia/gstcdparanoiasrc.c
+++ /dev/null
@@ -1,544 +0,0 @@
-/* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * <2005> Wim Taymans <wim@fluendo.com>
- * <2005> Tim-Philipp Müller <tim centricular net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include <errno.h>
-
-#include "gstcdparanoiasrc.h"
-#include "gst/gst-i18n-plugin.h"
-
-enum
-{
- TRANSPORT_ERROR,
- UNCORRECTED_ERROR,
- NUM_SIGNALS
-};
-
-enum
-{
- PROP_0,
- PROP_READ_SPEED,
- PROP_PARANOIA_MODE,
- PROP_SEARCH_OVERLAP,
- PROP_GENERIC_DEVICE,
- PROP_CACHE_SIZE
-};
-
-#define DEFAULT_READ_SPEED -1
-#define DEFAULT_SEARCH_OVERLAP -1
-#define DEFAULT_PARANOIA_MODE PARANOIA_MODE_FRAGMENT
-#define DEFAULT_GENERIC_DEVICE NULL
-#define DEFAULT_CACHE_SIZE -1
-
-GST_DEBUG_CATEGORY_STATIC (gst_cd_paranoia_src_debug);
-#define GST_CAT_DEFAULT gst_cd_paranoia_src_debug
-
-GST_BOILERPLATE (GstCdParanoiaSrc, gst_cd_paranoia_src, GstCddaBaseSrc,
- GST_TYPE_CDDA_BASE_SRC);
-
-static void gst_cd_paranoia_src_finalize (GObject * obj);
-static void gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void gst_cd_paranoia_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static GstBuffer *gst_cd_paranoia_src_read_sector (GstCddaBaseSrc * src,
- gint sector);
-static gboolean gst_cd_paranoia_src_open (GstCddaBaseSrc * src,
- const gchar * device);
-static void gst_cd_paranoia_src_close (GstCddaBaseSrc * src);
-
-static const GstElementDetails cdparanoia_details =
-GST_ELEMENT_DETAILS ("CD Audio (cdda) Source, Paranoia IV",
- "Source/File",
- "Read audio from CD in paranoid mode",
- "Erik Walthinsen <omega@cse.ogi.edu>, " "Wim Taymans <wim@fluendo.com>");
-
-/* We use these to serialize calls to paranoia_read() among several
- * cdparanoiasrc instances. We do this because it's the only reasonably
- * easy way to find out the calling object from within the paranoia
- * callback, and we need the object instance in there to emit our signals */
-static GstCdParanoiaSrc *cur_cb_source;
-static GStaticMutex cur_cb_mutex = G_STATIC_MUTEX_INIT;
-
-static gint cdpsrc_signals[NUM_SIGNALS]; /* all 0 */
-
-#define GST_TYPE_CD_PARANOIA_MODE (gst_cd_paranoia_mode_get_type())
-static GType
-gst_cd_paranoia_mode_get_type (void)
-{
- static const GFlagsValue paranoia_modes[] = {
- {PARANOIA_MODE_DISABLE, "PARANOIA_MODE_DISABLE", "disable"},
- {PARANOIA_MODE_FRAGMENT, "PARANOIA_MODE_FRAGMENT", "fragment"},
- {PARANOIA_MODE_OVERLAP, "PARANOIA_MODE_OVERLAP", "overlap"},
- {PARANOIA_MODE_SCRATCH, "PARANOIA_MODE_SCRATCH", "scratch"},
- {PARANOIA_MODE_REPAIR, "PARANOIA_MODE_REPAIR", "repair"},
- {PARANOIA_MODE_FULL, "PARANOIA_MODE_FULL", "full"},
- {0, NULL, NULL},
- };
-
- static GType type; /* 0 */
-
- if (!type) {
- type = g_flags_register_static ("GstCdParanoiaMode", paranoia_modes);
- }
-
- return type;
-}
-
-static void
-gst_cd_paranoia_src_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details (element_class, &cdparanoia_details);
-}
-
-static void
-gst_cd_paranoia_src_init (GstCdParanoiaSrc * src, GstCdParanoiaSrcClass * klass)
-{
- src->d = NULL;
- src->p = NULL;
- src->next_sector = -1;
-
- src->search_overlap = DEFAULT_SEARCH_OVERLAP;
- src->paranoia_mode = DEFAULT_PARANOIA_MODE;
- src->read_speed = DEFAULT_READ_SPEED;
- src->generic_device = g_strdup (DEFAULT_GENERIC_DEVICE);
- src->cache_size = DEFAULT_CACHE_SIZE;
-}
-
-static void
-gst_cd_paranoia_src_class_init (GstCdParanoiaSrcClass * klass)
-{
- GstCddaBaseSrcClass *cddabasesrc_class = GST_CDDA_BASE_SRC_CLASS (klass);
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gobject_class->set_property = gst_cd_paranoia_src_set_property;
- gobject_class->get_property = gst_cd_paranoia_src_get_property;
- gobject_class->finalize = gst_cd_paranoia_src_finalize;
-
- cddabasesrc_class->open = gst_cd_paranoia_src_open;
- cddabasesrc_class->close = gst_cd_paranoia_src_close;
- cddabasesrc_class->read_sector = gst_cd_paranoia_src_read_sector;
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_GENERIC_DEVICE,
- g_param_spec_string ("generic-device", "Generic device",
- "Use specified generic scsi device", DEFAULT_GENERIC_DEVICE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_READ_SPEED,
- g_param_spec_int ("read-speed", "Read speed",
- "Read from device at specified speed", -1, G_MAXINT,
- DEFAULT_READ_SPEED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PARANOIA_MODE,
- g_param_spec_flags ("paranoia-mode", "Paranoia mode",
- "Type of checking to perform", GST_TYPE_CD_PARANOIA_MODE,
- DEFAULT_PARANOIA_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEARCH_OVERLAP,
- g_param_spec_int ("search-overlap", "Search overlap",
- "Force minimum overlap search during verification to n sectors", -1,
- 75, DEFAULT_SEARCH_OVERLAP,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstCdParanoiaSrc:cache-size
- *
- * Set CD cache size to n sectors (-1 = auto)
- *
- * Since: 0.10.24
- */
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CACHE_SIZE,
- g_param_spec_int ("cache-size", "Cache size",
- "Set CD cache size to n sectors (-1 = auto)", -1,
- G_MAXINT, DEFAULT_CACHE_SIZE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /* FIXME: we don't really want signals for this, but messages on the bus,
- * but then we can't check any longer whether anyone is interested in them */
- /**
- * GstCdParanoiaSrc::transport-error
- * @cdparanoia: The CdParanoia instance
- * @sector: The sector number at which the error was encountered.
- *
- * This signal is emitted whenever an error occurs while reading.
- * CdParanoia will attempt to recover the data.
- */
- cdpsrc_signals[TRANSPORT_ERROR] =
- g_signal_new ("transport-error", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GstCdParanoiaSrcClass, transport_error),
- NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
- /**
- * GstCdParanoiaSrc::uncorrected-error
- * @cdparanoia: The CdParanoia instance
- * @sector: The sector number at which the error was encountered.
- *
- * This signal is emitted whenever an uncorrectable error occurs while
- * reading. The data could not be read.
- */
- cdpsrc_signals[UNCORRECTED_ERROR] =
- g_signal_new ("uncorrected-error", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GstCdParanoiaSrcClass, uncorrected_error),
- NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
-}
-
-static gboolean
-gst_cd_paranoia_src_open (GstCddaBaseSrc * cddabasesrc, const gchar * device)
-{
- GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc);
- gint i, cache_size;
-
- GST_DEBUG_OBJECT (src, "trying to open device %s (generic-device=%s) ...",
- device, GST_STR_NULL (src->generic_device));
-
- /* find the device */
- if (src->generic_device != NULL) {
- src->d = cdda_identify_scsi (src->generic_device, device, FALSE, NULL);
- } else {
- if (device != NULL) {
- src->d = cdda_identify (device, FALSE, NULL);
- } else {
- src->d = cdda_identify ("/dev/cdrom", FALSE, NULL);
- }
- }
-
- /* fail if the device couldn't be found */
- if (src->d == NULL)
- goto no_device;
-
- /* set verbosity mode */
- cdda_verbose_set (src->d, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);
-
- /* open the disc */
- if (cdda_open (src->d))
- goto open_failed;
-
- if (src->read_speed != -1) {
- cdda_speed_set (src->d, src->read_speed);
- }
-
- for (i = 1; i < src->d->tracks + 1; i++) {
- GstCddaBaseSrcTrack track = { 0, };
-
- track.num = i;
- track.is_audio = IS_AUDIO (src->d, i - 1);
- track.start = cdda_track_firstsector (src->d, i);
- track.end = cdda_track_lastsector (src->d, i);
- track.tags = NULL;
-
- gst_cdda_base_src_add_track (GST_CDDA_BASE_SRC (src), &track);
- }
-
- /* create the paranoia struct and set it up */
- src->p = paranoia_init (src->d);
- if (src->p == NULL)
- goto init_failed;
-
- paranoia_modeset (src->p, src->paranoia_mode);
- GST_INFO_OBJECT (src, "set paranoia mode to 0x%02x", src->paranoia_mode);
-
- if (src->search_overlap != -1) {
- paranoia_overlapset (src->p, src->search_overlap);
- GST_INFO_OBJECT (src, "search overlap set to %u", src->search_overlap);
- }
-
- cache_size = src->cache_size;
- if (cache_size == -1) {
- /* if paranoia mode is low (the default), assume we're doing playback */
- if (src->paranoia_mode <= PARANOIA_MODE_FRAGMENT)
- cache_size = 150;
- else
- cache_size = paranoia_cachemodel_size (src->p, -1);
- }
- paranoia_cachemodel_size (src->p, cache_size);
- GST_INFO_OBJECT (src, "set cachemodel size to %u", cache_size);
-
- src->next_sector = -1;
-
- return TRUE;
-
- /* ERRORS */
-no_device:
- {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
- (_("Could not open CD device for reading.")), ("cdda_identify failed"));
- return FALSE;
- }
-open_failed:
- {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
- (_("Could not open CD device for reading.")), ("cdda_open failed"));
- cdda_close (src->d);
- src->d = NULL;
- return FALSE;
- }
-init_failed:
- {
- GST_ELEMENT_ERROR (src, LIBRARY, INIT,
- ("failed to initialize paranoia"), ("failed to initialize paranoia"));
- return FALSE;
- }
-}
-
-static void
-gst_cd_paranoia_src_close (GstCddaBaseSrc * cddabasesrc)
-{
- GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc);
-
- if (src->p) {
- paranoia_free (src->p);
- src->p = NULL;
- }
-
- if (src->d) {
- cdda_close (src->d);
- src->d = NULL;
- }
-
- src->next_sector = -1;
-}
-
-static void
-gst_cd_paranoia_dummy_callback (long inpos, int function)
-{
- /* Used by instanced where no one is interested what's happening here */
-}
-
-static void
-gst_cd_paranoia_paranoia_callback (long inpos, int function)
-{
- GstCdParanoiaSrc *src = cur_cb_source;
- gint sector = (gint) (inpos / CD_FRAMEWORDS);
-
- switch (function) {
- case PARANOIA_CB_SKIP:
- GST_INFO_OBJECT (src, "Skip at sector %d", sector);
- g_signal_emit (src, cdpsrc_signals[UNCORRECTED_ERROR], 0, sector);
- break;
- case PARANOIA_CB_READERR:
- GST_INFO_OBJECT (src, "Transport error at sector %d", sector);
- g_signal_emit (src, cdpsrc_signals[TRANSPORT_ERROR], 0, sector);
- break;
- default:
- break;
- }
-}
-
-static gboolean
-gst_cd_paranoia_src_signal_is_being_watched (GstCdParanoiaSrc * src, gint sig)
-{
- return g_signal_has_handler_pending (src, cdpsrc_signals[sig], 0, FALSE);
-}
-
-static GstBuffer *
-gst_cd_paranoia_src_read_sector (GstCddaBaseSrc * cddabasesrc, gint sector)
-{
- GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (cddabasesrc);
- GstBuffer *buf;
- gboolean do_serialize;
- gint16 *cdda_buf;
-
-#if 0
- /* Do we really need to output this? (tpm) */
- /* Due to possible autocorrections of start sectors of audio tracks on
- * multisession cds, we can maybe not compute the correct discid.
- * So issue a warning.
- * See cdparanoia/interface/common-interface.c:FixupTOC */
- if (src->d && src->d->cd_extra) {
- g_message
- ("DiscID on multisession discs might be broken. Use at own risk.");
- }
-#endif
-
- if (src->next_sector == -1 || src->next_sector != sector) {
- if (paranoia_seek (src->p, sector, SEEK_SET) == -1)
- goto seek_failed;
-
- GST_DEBUG_OBJECT (src, "successfully seeked to sector %d", sector);
- src->next_sector = sector;
- }
-
- do_serialize =
- gst_cd_paranoia_src_signal_is_being_watched (src, TRANSPORT_ERROR) ||
- gst_cd_paranoia_src_signal_is_being_watched (src, UNCORRECTED_ERROR);
-
- if (do_serialize) {
- GST_LOG_OBJECT (src, "Signal handlers connected, serialising access");
- g_static_mutex_lock (&cur_cb_mutex);
- GST_LOG_OBJECT (src, "Got lock");
- cur_cb_source = src;
-
- cdda_buf = paranoia_read (src->p, gst_cd_paranoia_paranoia_callback);
-
- cur_cb_source = NULL;
- GST_LOG_OBJECT (src, "Releasing lock");
- g_static_mutex_unlock (&cur_cb_mutex);
- } else {
- cdda_buf = paranoia_read (src->p, gst_cd_paranoia_dummy_callback);
- }
-
- if (cdda_buf == NULL)
- goto read_failed;
-
- buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
- memcpy (GST_BUFFER_DATA (buf), cdda_buf, CD_FRAMESIZE_RAW);
-
- /* cdda base class will take care of timestamping etc. */
- ++src->next_sector;
-
- return buf;
-
- /* ERRORS */
-seek_failed:
- {
- GST_WARNING_OBJECT (src, "seek to sector %d failed!", sector);
- GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
- (_("Could not seek CD.")),
- ("paranoia_seek to %d failed: %s", sector, g_strerror (errno)));
- return NULL;
- }
-read_failed:
- {
- GST_WARNING_OBJECT (src, "read at sector %d failed!", sector);
- GST_ELEMENT_ERROR (src, RESOURCE, READ,
- (_("Could not read CD.")),
- ("paranoia_read at %d failed: %s", sector, g_strerror (errno)));
- return NULL;
- }
-}
-
-static void
-gst_cd_paranoia_src_finalize (GObject * obj)
-{
- GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (obj);
-
- g_free (src->generic_device);
-
- G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-static void
-gst_cd_paranoia_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object);
-
- GST_OBJECT_LOCK (src);
-
- switch (prop_id) {
- case PROP_GENERIC_DEVICE:{
- g_free (src->generic_device);
- src->generic_device = g_value_dup_string (value);
- if (src->generic_device && src->generic_device[0] == '\0') {
- g_free (src->generic_device);
- src->generic_device = NULL;
- }
- break;
- }
- case PROP_READ_SPEED:{
- src->read_speed = g_value_get_int (value);
- if (src->read_speed == 0)
- src->read_speed = -1;
- break;
- }
- case PROP_PARANOIA_MODE:{
- src->paranoia_mode = g_value_get_flags (value) & PARANOIA_MODE_FULL;
- break;
- }
- case PROP_SEARCH_OVERLAP:{
- src->search_overlap = g_value_get_int (value);
- break;
- }
- case PROP_CACHE_SIZE:{
- src->cache_size = g_value_get_int (value);
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- GST_OBJECT_UNLOCK (src);
-}
-
-static void
-gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (object);
-
- GST_OBJECT_LOCK (src);
-
- switch (prop_id) {
- case PROP_READ_SPEED:
- g_value_set_int (value, src->read_speed);
- break;
- case PROP_PARANOIA_MODE:
- g_value_set_flags (value, src->paranoia_mode);
- break;
- case PROP_GENERIC_DEVICE:
- g_value_set_string (value, src->generic_device);
- break;
- case PROP_SEARCH_OVERLAP:
- g_value_set_int (value, src->search_overlap);
- break;
- case PROP_CACHE_SIZE:
- g_value_set_int (value, src->cache_size);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- GST_OBJECT_UNLOCK (src);
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (gst_cd_paranoia_src_debug, "cdparanoiasrc", 0,
- "CD Paranoia Source");
-
- if (!gst_element_register (plugin, "cdparanoiasrc", GST_RANK_SECONDARY,
- GST_TYPE_CD_PARANOIA_SRC))
- return FALSE;
-
-#ifdef ENABLE_NLS
- GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
- LOCALEDIR);
- bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-#endif
-
-
- return TRUE;
-}
-
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "cdparanoia",
- "Read audio from CD in paranoid mode",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/cdparanoia/gstcdparanoiasrc.h b/ext/cdparanoia/gstcdparanoiasrc.h
deleted file mode 100644
index 6cec23c4..00000000
--- a/ext/cdparanoia/gstcdparanoiasrc.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* GStreamer
- * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
- *
- * 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_CD_PARANOIA_SRC_H__
-#define __GST_CD_PARANOIA_SRC_H__
-
-#include "gst/cdda/gstcddabasesrc.h"
-
-G_BEGIN_DECLS
-
-#define size16 gint16
-#define size32 gint32
-
-#ifdef CDPARANOIA_HEADERS_IN_DIR
- #include <cdda/cdda_interface.h>
- #include <cdda/cdda_paranoia.h>
-#else
- #include <cdda_interface.h>
- #include <cdda_paranoia.h>
-#endif
-
-#define GST_TYPE_CD_PARANOIA_SRC (gst_cd_paranoia_src_get_type())
-#define GST_CD_PARANOIA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CD_PARANOIA_SRC,GstCdParanoiaSrc))
-#define GST_CD_PARANOIA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CD_PARANOIA_SRC,GstCdParanoiaSrcClass))
-#define GST_IS_CD_PARANOIA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CD_PARANOIA_SRC))
-#define GST_IS_CD_PARANOIA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CD_PARANOIA_SRC))
-#define GST_CD_PARANOIA_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CDDA_BASAE_SRC, GstCdParanoiaSrcClass))
-
-typedef struct _GstCdParanoiaSrc GstCdParanoiaSrc;
-typedef struct _GstCdParanoiaSrcClass GstCdParanoiaSrcClass;
-
-/**
- * GstCdParanoiaSrc:
- *
- * The cdparanoia object structure.
- */
-struct _GstCdParanoiaSrc {
- GstCddaBaseSrc cddabasesrc;
-
- /*< private >*/
- cdrom_drive *d;
- cdrom_paranoia *p;
-
- gint next_sector; /* -1 or next sector we expect to
- * read, so we know when to do a seek */
-
- gint paranoia_mode;
- gint read_speed;
- gint search_overlap;
- gint cache_size;
-
- gchar *generic_device;
-};
-
-struct _GstCdParanoiaSrcClass {
- GstCddaBaseSrcClass parent_class;
-
- /* signal callbacks */
- /**
- * GstCdParanoiaSrcClass::transport-error:
- * @src: the GstCddaBaseSrc source element object
- * @sector: the sector at which the error happened
- *
- * This signal is emitted when a sector could not be read
- * because of a transport error.
- */
- void (*transport_error) (GstCdParanoiaSrc * src, gint sector);
- /**
- * GstCdParanoiaSrcClass::uncorrected-error:
- * @src: the GstCddaBaseSrc source element object
- * @sector: the sector at which the error happened
- *
- * This signal is emitted when a sector could not be read
- * because of a transport error.
- */
- void (*uncorrected_error) (GstCdParanoiaSrc * src, gint sector);
-};
-
-GType gst_cd_paranoia_src_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_CD_PARANOIA_SRC_H__ */
-
diff --git a/ext/gio/Makefile.am b/ext/gio/Makefile.am
deleted file mode 100644
index 237cfdd2..00000000
--- a/ext/gio/Makefile.am
+++ /dev/null
@@ -1,29 +0,0 @@
-# plugindir is set in configure
-
-plugin_LTLIBRARIES = libgstgio.la
-
-# sources used to compile this plug-in
-libgstgio_la_SOURCES = \
- gstgio.c \
- gstgiobasesink.c \
- gstgiobasesrc.c \
- gstgiosink.c \
- gstgiosrc.c \
- gstgiostreamsink.c \
- gstgiostreamsrc.c
-
-libgstgio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS)
-libgstgio_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS)
-libgstgio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(GIO_LDFLAGS)
-libgstgio_la_LIBTOOLFLAGS = --tag=disable-static
-
-# headers we need but don't want installed
-noinst_HEADERS = \
- gstgio.h \
- gstgiobasesink.h \
- gstgiobasesrc.h \
- gstgiosink.h \
- gstgiosrc.h \
- gstgiostreamsink.h \
- gstgiostreamsrc.h
-
diff --git a/ext/gio/gstgio.c b/ext/gio/gstgio.c
deleted file mode 100644
index be0a940b..00000000
--- a/ext/gio/gstgio.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * 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 "gstgio.h"
-#include "gstgiosink.h"
-#include "gstgiosrc.h"
-#include "gstgiostreamsink.h"
-#include "gstgiostreamsrc.h"
-
-#include <string.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_gio_debug);
-#define GST_CAT_DEFAULT gst_gio_debug
-
-/* @func_name: Name of the GIO function, for debugging messages.
- * @err: Error location. *err may be NULL, but err must be non-NULL.
- * @ret: Flow return location. May be NULL. Is set to either #GST_FLOW_ERROR
- * or #GST_FLOW_WRONG_STATE.
- *
- * Returns: TRUE to indicate a handled error. Error at given location err will
- * be freed and *err will be set to NULL. A FALSE return indicates an unhandled
- * error: The err location is unchanged and guaranteed to be != NULL. ret, if
- * given, is set to GST_FLOW_ERROR.
- */
-gboolean
-gst_gio_error (gpointer element, const gchar * func_name, GError ** err,
- GstFlowReturn * ret)
-{
- gboolean handled = TRUE;
-
- if (ret)
- *ret = GST_FLOW_ERROR;
-
- if (GST_GIO_ERROR_MATCHES (*err, CANCELLED)) {
- GST_DEBUG_OBJECT (element, "blocking I/O call cancelled (%s)", func_name);
- if (ret)
- *ret = GST_FLOW_WRONG_STATE;
- } else if (*err != NULL) {
- handled = FALSE;
- } else {
- GST_ELEMENT_ERROR (element, LIBRARY, FAILED, (NULL),
- ("%s call failed without error set", func_name));
- }
-
- if (handled)
- g_clear_error (err);
-
- return handled;
-}
-
-GstFlowReturn
-gst_gio_seek (gpointer element, GSeekable * stream, guint64 offset,
- GCancellable * cancel)
-{
- gboolean success;
- GstFlowReturn ret;
- GError *err = NULL;
-
- GST_LOG_OBJECT (element, "seeking to offset %" G_GINT64_FORMAT, offset);
-
- success = g_seekable_seek (stream, offset, G_SEEK_SET, cancel, &err);
-
- if (success)
- ret = GST_FLOW_OK;
- else if (!gst_gio_error (element, "g_seekable_seek", &err, &ret)) {
- GST_ELEMENT_ERROR (element, RESOURCE, SEEK, (NULL),
- ("Could not seek: %s", err->message));
- g_clear_error (&err);
- }
-
- return ret;
-}
-
-static gpointer
-_internal_get_supported_protocols (gpointer data)
-{
- const gchar *const *schemes;
- gchar **our_schemes;
- guint num;
- gint i, j;
-
- schemes = g_vfs_get_supported_uri_schemes (g_vfs_get_default ());
- num = g_strv_length ((gchar **) schemes);
-
- if (num == 0) {
- GST_WARNING ("No GIO supported URI schemes found");
- return NULL;
- }
-
- our_schemes = g_new0 (gchar *, num + 1);
-
- /* - Filter http/https as we can't support the icy stuff with GIO.
- * Use souphttpsrc if you need that.
- * - Filter cdda as it doesn't support musicbrainz stuff and everything
- * else one expects from a cdda source. Use cdparanoiasrc or cdiosrc
- * for cdda.
- */
- for (i = 0, j = 0; i < num; i++) {
- if (strcmp (schemes[i], "http") == 0 || strcmp (schemes[i], "https") == 0
- || strcmp (schemes[i], "cdda") == 0)
- continue;
-
- our_schemes[j] = g_strdup (schemes[i]);
- j++;
- }
-
- return our_schemes;
-}
-
-static gchar **
-gst_gio_get_supported_protocols (void)
-{
- static GOnce once = G_ONCE_INIT;
-
- g_once (&once, _internal_get_supported_protocols, NULL);
- return (gchar **) once.retval;
-}
-
-static GstURIType
-gst_gio_uri_handler_get_type_sink (void)
-{
- return GST_URI_SINK;
-}
-
-static GstURIType
-gst_gio_uri_handler_get_type_src (void)
-{
- return GST_URI_SRC;
-}
-
-static gchar **
-gst_gio_uri_handler_get_protocols (void)
-{
- static gchar **protocols = NULL;
-
- if (!protocols)
- protocols = gst_gio_get_supported_protocols ();
-
- return protocols;
-}
-
-static const gchar *
-gst_gio_uri_handler_get_uri (GstURIHandler * handler)
-{
- GstElement *element = GST_ELEMENT (handler);
- const gchar *uri;
-
- g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
-
- g_object_get (G_OBJECT (element), "location", &uri, NULL);
-
- return uri;
-}
-
-static gboolean
-gst_gio_uri_handler_set_uri (GstURIHandler * handler, const gchar * uri)
-{
- GstElement *element = GST_ELEMENT (handler);
-
- g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
-
- if (GST_STATE (element) == GST_STATE_PLAYING ||
- GST_STATE (element) == GST_STATE_PAUSED)
- return FALSE;
-
- g_object_set (G_OBJECT (element), "location", uri, NULL);
-
- return TRUE;
-}
-
-static void
-gst_gio_uri_handler_init (gpointer g_iface, gpointer iface_data)
-{
- GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
- gboolean sink = GPOINTER_TO_INT (iface_data); /* See in do_init below. */
-
- if (sink)
- iface->get_type = gst_gio_uri_handler_get_type_sink;
- else
- iface->get_type = gst_gio_uri_handler_get_type_src;
- iface->get_protocols = gst_gio_uri_handler_get_protocols;
- iface->get_uri = gst_gio_uri_handler_get_uri;
- iface->set_uri = gst_gio_uri_handler_set_uri;
-}
-
-void
-gst_gio_uri_handler_do_init (GType type)
-{
- GInterfaceInfo uri_handler_info = {
- gst_gio_uri_handler_init,
- NULL,
- NULL
- };
-
- /* Store information for uri_handler_init to use for distinguishing the
- * element types. This lets us use a single interface implementation for both
- * classes. */
- uri_handler_info.interface_data = GINT_TO_POINTER (g_type_is_a (type,
- GST_TYPE_BASE_SINK));
-
- g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &uri_handler_info);
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- gboolean ret = TRUE;
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_debug, "gio", 0, "GIO elements");
-
- gst_plugin_add_dependency_simple (plugin, NULL, GIO_MODULE_DIR, NULL,
- GST_PLUGIN_DEPENDENCY_FLAG_NONE);
- gst_plugin_add_dependency_simple (plugin, "LD_LIBRARY_PATH", GIO_LIBDIR,
- "gvfsd", GST_PLUGIN_DEPENDENCY_FLAG_NONE);
-
- /* FIXME: Rank is MARGINAL for now, should be at least SECONDARY+1 in the future
- * to replace gnomevfssink/src. For testing purposes PRIMARY+1 one makes sense
- * so it gets autoplugged and preferred over filesrc/sink. */
-
- ret &= gst_element_register (plugin, "giosink", GST_RANK_MARGINAL,
- GST_TYPE_GIO_SINK);
-
- ret &= gst_element_register (plugin, "giosrc", GST_RANK_MARGINAL,
- GST_TYPE_GIO_SRC);
-
- ret &= gst_element_register (plugin, "giostreamsink", GST_RANK_NONE,
- GST_TYPE_GIO_STREAM_SINK);
-
- ret &= gst_element_register (plugin, "giostreamsrc", GST_RANK_NONE,
- GST_TYPE_GIO_STREAM_SRC);
-
- return ret;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "gio",
- "GIO elements", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
- GST_PACKAGE_ORIGIN)
diff --git a/ext/gio/gstgio.h b/ext/gio/gstgio.h
deleted file mode 100644
index 01183e13..00000000
--- a/ext/gio/gstgio.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GIO_H__
-#define __GST_GIO_H__
-
-#include <gio/gio.h>
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_GIO_ERROR_MATCHES(err, code) g_error_matches (err, G_IO_ERROR, G_IO_ERROR_##code)
-
-#define GST_GIO_STREAM_IS_SEEKABLE(stream) (G_IS_SEEKABLE (stream) && g_seekable_can_seek (G_SEEKABLE (stream)))
-
-gboolean gst_gio_error (gpointer element, const gchar *func_name,
- GError **err, GstFlowReturn *ret);
-GstFlowReturn gst_gio_seek (gpointer element, GSeekable *stream, guint64 offset,
- GCancellable *cancel);
-void gst_gio_uri_handler_do_init (GType type);
-
-G_END_DECLS
-
-#endif /* __GST_GIO_H__ */
diff --git a/ext/gio/gstgiobasesink.c b/ext/gio/gstgiobasesink.c
deleted file mode 100644
index 2b16909b..00000000
--- a/ext/gio/gstgiobasesink.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * 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 "gstgiobasesink.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_gio_base_sink_debug);
-#define GST_CAT_DEFAULT gst_gio_base_sink_debug
-
-static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
-GST_BOILERPLATE (GstGioBaseSink, gst_gio_base_sink, GstBaseSink,
- GST_TYPE_BASE_SINK);
-
-static void gst_gio_base_sink_finalize (GObject * object);
-static gboolean gst_gio_base_sink_start (GstBaseSink * base_sink);
-static gboolean gst_gio_base_sink_stop (GstBaseSink * base_sink);
-static gboolean gst_gio_base_sink_unlock (GstBaseSink * base_sink);
-static gboolean gst_gio_base_sink_unlock_stop (GstBaseSink * base_sink);
-static gboolean gst_gio_base_sink_event (GstBaseSink * base_sink,
- GstEvent * event);
-static GstFlowReturn gst_gio_base_sink_render (GstBaseSink * base_sink,
- GstBuffer * buffer);
-static gboolean gst_gio_base_sink_query (GstPad * pad, GstQuery * query);
-
-static void
-gst_gio_base_sink_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_base_sink_debug, "gio_base_sink", 0,
- "GIO base sink");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory));
-}
-
-static void
-gst_gio_base_sink_class_init (GstGioBaseSinkClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
-
- gobject_class->finalize = gst_gio_base_sink_finalize;
-
- gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_gio_base_sink_start);
- gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_gio_base_sink_stop);
- gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_gio_base_sink_unlock);
- gstbasesink_class->unlock_stop =
- GST_DEBUG_FUNCPTR (gst_gio_base_sink_unlock_stop);
- gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_gio_base_sink_event);
- gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_gio_base_sink_render);
-}
-
-static void
-gst_gio_base_sink_init (GstGioBaseSink * sink, GstGioBaseSinkClass * gclass)
-{
- gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
- GST_DEBUG_FUNCPTR (gst_gio_base_sink_query));
-
- gst_base_sink_set_sync (GST_BASE_SINK (sink), FALSE);
-
- sink->cancel = g_cancellable_new ();
-}
-
-static void
-gst_gio_base_sink_finalize (GObject * object)
-{
- GstGioBaseSink *sink = GST_GIO_BASE_SINK (object);
-
- if (sink->cancel) {
- g_object_unref (sink->cancel);
- sink->cancel = NULL;
- }
-
- if (sink->stream) {
- g_object_unref (sink->stream);
- sink->stream = NULL;
- }
-
- GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
-}
-
-static gboolean
-gst_gio_base_sink_start (GstBaseSink * base_sink)
-{
- GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink);
- GstGioBaseSinkClass *gbsink_class = GST_GIO_BASE_SINK_GET_CLASS (sink);
-
- sink->position = 0;
-
- /* FIXME: This will likely block */
- sink->stream = gbsink_class->get_stream (sink);
- if (G_UNLIKELY (!G_IS_OUTPUT_STREAM (sink->stream))) {
- GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
- ("No output stream provided by subclass"));
- return FALSE;
- } else if (G_UNLIKELY (g_output_stream_is_closed (sink->stream))) {
- GST_ELEMENT_ERROR (sink, LIBRARY, FAILED, (NULL),
- ("Output stream is already closed"));
- return FALSE;
- }
-
- GST_DEBUG_OBJECT (sink, "started sink");
-
- return TRUE;
-}
-
-static gboolean
-gst_gio_base_sink_stop (GstBaseSink * base_sink)
-{
- GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink);
- GstGioBaseSinkClass *klass = GST_GIO_BASE_SINK_GET_CLASS (sink);
- gboolean success;
- GError *err = NULL;
-
- if (klass->close_on_stop && G_IS_OUTPUT_STREAM (sink->stream)) {
- GST_DEBUG_OBJECT (sink, "closing stream");
-
- /* FIXME: can block but unfortunately we can't use async operations
- * here because they require a running main loop */
- success = g_output_stream_close (sink->stream, sink->cancel, &err);
-
- if (!success && !gst_gio_error (sink, "g_output_stream_close", &err, NULL)) {
- GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
- ("gio_output_stream_close failed: %s", err->message));
- g_clear_error (&err);
- } else if (!success) {
- GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
- ("g_output_stream_close failed"));
- } else {
- GST_DEBUG_OBJECT (sink, "g_outut_stream_close succeeded");
- }
-
- g_object_unref (sink->stream);
- sink->stream = NULL;
- } else {
- success = g_output_stream_flush (sink->stream, sink->cancel, &err);
-
- if (!success && !gst_gio_error (sink, "g_output_stream_flush", &err, NULL)) {
- GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
- ("gio_output_stream_flush failed: %s", err->message));
- g_clear_error (&err);
- } else if (!success) {
- GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
- ("g_output_stream_flush failed"));
- } else {
- GST_DEBUG_OBJECT (sink, "g_outut_stream_flush succeeded");
- }
-
- g_object_unref (sink->stream);
- sink->stream = NULL;
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_gio_base_sink_unlock (GstBaseSink * base_sink)
-{
- GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink);
-
- GST_LOG_OBJECT (sink, "triggering cancellation");
-
- g_cancellable_cancel (sink->cancel);
-
- return TRUE;
-}
-
-static gboolean
-gst_gio_base_sink_unlock_stop (GstBaseSink * base_sink)
-{
- GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink);
-
- GST_LOG_OBJECT (sink, "resetting cancellable");
-
- g_cancellable_reset (sink->cancel);
-
- return TRUE;
-}
-
-static gboolean
-gst_gio_base_sink_event (GstBaseSink * base_sink, GstEvent * event)
-{
- GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink);
- GstFlowReturn ret = GST_FLOW_OK;
-
- if (sink->stream == NULL)
- return TRUE;
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
- if (G_IS_OUTPUT_STREAM (sink->stream)) {
- GstFormat format;
- gint64 offset;
-
- gst_event_parse_new_segment (event, NULL, NULL, &format, &offset, NULL,
- NULL);
-
- if (format != GST_FORMAT_BYTES) {
- GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format",
- gst_format_get_name (format));
- break;
- }
-
- if (GST_GIO_STREAM_IS_SEEKABLE (sink->stream)) {
- ret = gst_gio_seek (sink, G_SEEKABLE (sink->stream), offset,
- sink->cancel);
- if (ret == GST_FLOW_OK)
- sink->position = offset;
- } else {
- ret = GST_FLOW_NOT_SUPPORTED;
- }
- }
- break;
-
- case GST_EVENT_EOS:
- case GST_EVENT_FLUSH_START:
- if (G_IS_OUTPUT_STREAM (sink->stream)) {
- gboolean success;
- GError *err = NULL;
-
- success = g_output_stream_flush (sink->stream, sink->cancel, &err);
-
- if (!success && !gst_gio_error (sink, "g_output_stream_flush", &err,
- &ret)) {
- GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
- ("flush failed: %s", err->message));
- g_clear_error (&err);
- }
- }
- break;
-
- default:
- break;
- }
-
- return (ret == GST_FLOW_OK);
-}
-
-static GstFlowReturn
-gst_gio_base_sink_render (GstBaseSink * base_sink, GstBuffer * buffer)
-{
- GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink);
- gssize written;
- gboolean success;
- GError *err = NULL;
-
- g_return_val_if_fail (G_IS_OUTPUT_STREAM (sink->stream), GST_FLOW_ERROR);
-
- GST_LOG_OBJECT (sink, "writing %u bytes to offset %" G_GUINT64_FORMAT,
- GST_BUFFER_SIZE (buffer), sink->position);
-
- written = g_output_stream_write (sink->stream,
- GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), sink->cancel, &err);
-
- success = (written >= 0);
-
- if (G_UNLIKELY (success && written < GST_BUFFER_SIZE (buffer))) {
- /* FIXME: Can this happen? Should we handle it gracefully? gnomevfssink
- * doesn't... */
- GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
- ("Could not write to stream: (short write, only %"
- G_GSSIZE_FORMAT " bytes of %d bytes written)",
- written, GST_BUFFER_SIZE (buffer)));
- return GST_FLOW_ERROR;
- }
-
- if (success) {
- sink->position += written;
- return GST_FLOW_OK;
-
- } else {
- GstFlowReturn ret;
-
- if (!gst_gio_error (sink, "g_output_stream_write", &err, &ret)) {
- GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
- ("Could not write to stream: %s", err->message));
- g_clear_error (&err);
- }
-
- return ret;
- }
-}
-
-static gboolean
-gst_gio_base_sink_query (GstPad * pad, GstQuery * query)
-{
- GstGioBaseSink *sink = GST_GIO_BASE_SINK (GST_PAD_PARENT (pad));
- GstFormat format;
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- gst_query_parse_position (query, &format, NULL);
- switch (format) {
- case GST_FORMAT_BYTES:
- case GST_FORMAT_DEFAULT:
- gst_query_set_position (query, GST_FORMAT_BYTES, sink->position);
- return TRUE;
- default:
- return FALSE;
- }
- case GST_QUERY_FORMATS:
- gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES);
- return TRUE;
- case GST_QUERY_URI:
- if (GST_IS_URI_HANDLER (sink)) {
- const gchar *uri;
-
- uri = gst_uri_handler_get_uri (GST_URI_HANDLER (sink));
- gst_query_set_uri (query, uri);
- return TRUE;
- }
- return FALSE;
- default:
- return gst_pad_query_default (pad, query);
- }
-}
-
-void
-gst_gio_base_sink_set_stream (GstGioBaseSink * sink, GOutputStream * stream)
-{
- g_return_if_fail (G_IS_OUTPUT_STREAM (stream));
- g_return_if_fail ((GST_STATE (sink) != GST_STATE_PLAYING &&
- GST_STATE (sink) != GST_STATE_PAUSED));
-
- if (G_IS_OUTPUT_STREAM (sink->stream)) {
- gboolean success;
- GError *err = NULL;
-
- GST_DEBUG_OBJECT (sink, "closing old stream");
-
- /* FIXME: can block but unfortunately we can't use async operations
- * here because they require a running main loop */
- success = g_output_stream_close (sink->stream, sink->cancel, &err);
-
- if (!success && !gst_gio_error (sink, "g_output_stream_close", &err, NULL)) {
- GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
- ("g_output_stream_close failed: %s", err->message));
- g_clear_error (&err);
- } else if (!success) {
- GST_ELEMENT_WARNING (sink, RESOURCE, CLOSE, (NULL),
- ("g_output_stream_close failed"));
- } else {
- GST_DEBUG_OBJECT (sink, "g_output_stream_close succeeded");
- }
-
- g_object_unref (sink->stream);
- sink->stream = NULL;
- }
-
- sink->stream = stream;
-}
diff --git a/ext/gio/gstgiobasesink.h b/ext/gio/gstgiobasesink.h
deleted file mode 100644
index 7f13a854..00000000
--- a/ext/gio/gstgiobasesink.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <slomo@circular-chaos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GIO_BASE_SINK_H__
-#define __GST_GIO_BASE_SINK_H__
-
-#include "gstgio.h"
-
-#include <gst/base/gstbasesink.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GIO_BASE_SINK \
- (gst_gio_base_sink_get_type())
-#define GST_GIO_BASE_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_BASE_SINK,GstGioBaseSink))
-#define GST_GIO_BASE_SINK_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GIO_BASE_SINK, GstGioBaseSinkClass))
-#define GST_GIO_BASE_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_BASE_SINK,GstGioBaseSinkClass))
-#define GST_IS_GIO_BASE_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_BASE_SINK))
-#define GST_IS_GIO_BASE_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_BASE_SINK))
-
-typedef struct _GstGioBaseSink GstGioBaseSink;
-typedef struct _GstGioBaseSinkClass GstGioBaseSinkClass;
-
-struct _GstGioBaseSink
-{
- GstBaseSink sink;
-
- /* < protected > */
- GCancellable *cancel;
- guint64 position;
-
- /* < private > */
- GOutputStream *stream;
-};
-
-struct _GstGioBaseSinkClass
-{
- GstBaseSinkClass parent_class;
-
- GOutputStream * (*get_stream) (GstGioBaseSink *bsink);
- gboolean close_on_stop;
-};
-
-GType gst_gio_base_sink_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_GIO_BASE_SINK_H__ */
diff --git a/ext/gio/gstgiobasesrc.c b/ext/gio/gstgiobasesrc.c
deleted file mode 100644
index 133e12c2..00000000
--- a/ext/gio/gstgiobasesrc.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * 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 "gstgiobasesrc.h"
-
-#include <gst/base/gsttypefindhelper.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_gio_base_src_debug);
-#define GST_CAT_DEFAULT gst_gio_base_src_debug
-
-static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
-GST_BOILERPLATE (GstGioBaseSrc, gst_gio_base_src, GstBaseSrc,
- GST_TYPE_BASE_SRC);
-
-static void gst_gio_base_src_finalize (GObject * object);
-
-static gboolean gst_gio_base_src_start (GstBaseSrc * base_src);
-static gboolean gst_gio_base_src_stop (GstBaseSrc * base_src);
-static gboolean gst_gio_base_src_get_size (GstBaseSrc * base_src,
- guint64 * size);
-static gboolean gst_gio_base_src_is_seekable (GstBaseSrc * base_src);
-static gboolean gst_gio_base_src_unlock (GstBaseSrc * base_src);
-static gboolean gst_gio_base_src_unlock_stop (GstBaseSrc * base_src);
-static gboolean gst_gio_base_src_check_get_range (GstBaseSrc * base_src);
-static GstFlowReturn gst_gio_base_src_create (GstBaseSrc * base_src,
- guint64 offset, guint size, GstBuffer ** buf);
-static gboolean gst_gio_base_src_query (GstBaseSrc * base_src,
- GstQuery * query);
-
-static void
-gst_gio_base_src_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_base_src_debug, "gio_base_src", 0,
- "GIO base source");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_factory));
-}
-
-static void
-gst_gio_base_src_class_init (GstGioBaseSrcClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
-
- gobject_class->finalize = gst_gio_base_src_finalize;
-
- gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gio_base_src_start);
- gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gio_base_src_stop);
- gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gio_base_src_get_size);
- gstbasesrc_class->is_seekable =
- GST_DEBUG_FUNCPTR (gst_gio_base_src_is_seekable);
- gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_gio_base_src_unlock);
- gstbasesrc_class->unlock_stop =
- GST_DEBUG_FUNCPTR (gst_gio_base_src_unlock_stop);
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_gio_base_src_check_get_range);
- gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_gio_base_src_create);
- gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_gio_base_src_query);
-}
-
-static void
-gst_gio_base_src_init (GstGioBaseSrc * src, GstGioBaseSrcClass * gclass)
-{
- src->cancel = g_cancellable_new ();
-}
-
-static void
-gst_gio_base_src_finalize (GObject * object)
-{
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (object);
-
- if (src->cancel) {
- g_object_unref (src->cancel);
- src->cancel = NULL;
- }
-
- if (src->stream) {
- g_object_unref (src->stream);
- src->stream = NULL;
- }
-
- if (src->cache) {
- gst_buffer_unref (src->cache);
- src->cache = NULL;
- }
-
- GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
-}
-
-static gboolean
-gst_gio_base_src_start (GstBaseSrc * base_src)
-{
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
- GstGioBaseSrcClass *gbsrc_class = GST_GIO_BASE_SRC_GET_CLASS (src);
-
- src->position = 0;
-
- /* FIXME: This will likely block */
- src->stream = gbsrc_class->get_stream (src);
- if (G_UNLIKELY (!G_IS_INPUT_STREAM (src->stream))) {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
- ("No input stream provided by subclass"));
- return FALSE;
- } else if (G_UNLIKELY (g_input_stream_is_closed (src->stream))) {
- GST_ELEMENT_ERROR (src, LIBRARY, FAILED, (NULL),
- ("Input stream is already closed"));
- return FALSE;
- }
-
- if (G_IS_SEEKABLE (src->stream))
- src->position = g_seekable_tell (G_SEEKABLE (src->stream));
-
- GST_DEBUG_OBJECT (src, "started source");
-
- return TRUE;
-}
-
-static gboolean
-gst_gio_base_src_stop (GstBaseSrc * base_src)
-{
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
- GstGioBaseSrcClass *klass = GST_GIO_BASE_SRC_GET_CLASS (src);
- gboolean success;
- GError *err = NULL;
-
- if (klass->close_on_stop && G_IS_INPUT_STREAM (src->stream)) {
- GST_DEBUG_OBJECT (src, "closing stream");
-
- /* FIXME: can block but unfortunately we can't use async operations
- * here because they require a running main loop */
- success = g_input_stream_close (src->stream, src->cancel, &err);
-
- if (!success && !gst_gio_error (src, "g_input_stream_close", &err, NULL)) {
- GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL),
- ("g_input_stream_close failed: %s", err->message));
- g_clear_error (&err);
- } else if (!success) {
- GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL),
- ("g_input_stream_close failed"));
- } else {
- GST_DEBUG_OBJECT (src, "g_input_stream_close succeeded");
- }
-
- g_object_unref (src->stream);
- src->stream = NULL;
- } else {
- g_object_unref (src->stream);
- src->stream = NULL;
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_gio_base_src_get_size (GstBaseSrc * base_src, guint64 * size)
-{
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
-
- if (G_IS_FILE_INPUT_STREAM (src->stream)) {
- GFileInfo *info;
- GError *err = NULL;
-
- info = g_file_input_stream_query_info (G_FILE_INPUT_STREAM (src->stream),
- G_FILE_ATTRIBUTE_STANDARD_SIZE, src->cancel, &err);
-
- if (info != NULL) {
- *size = g_file_info_get_size (info);
- g_object_unref (info);
- GST_DEBUG_OBJECT (src, "found size: %" G_GUINT64_FORMAT, *size);
- return TRUE;
- }
-
- if (!gst_gio_error (src, "g_file_input_stream_query_info", &err, NULL)) {
-
- if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
- GST_DEBUG_OBJECT (src, "size information not available");
- else
- GST_WARNING_OBJECT (src, "size information retrieval failed: %s",
- err->message);
-
- g_clear_error (&err);
- }
- }
-
- if (GST_GIO_STREAM_IS_SEEKABLE (src->stream)) {
- goffset old;
- goffset stream_size;
- gboolean ret;
- GSeekable *seekable = G_SEEKABLE (src->stream);
- GError *err = NULL;
-
- old = g_seekable_tell (seekable);
-
- ret = g_seekable_seek (seekable, 0, G_SEEK_END, src->cancel, &err);
- if (!ret) {
- if (!gst_gio_error (src, "g_seekable_seek", &err, NULL)) {
- if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
- GST_DEBUG_OBJECT (src,
- "Seeking to the end of stream is not supported");
- else
- GST_WARNING_OBJECT (src, "Seeking to end of stream failed: %s",
- err->message);
- g_clear_error (&err);
- } else {
- GST_WARNING_OBJECT (src, "Seeking to end of stream failed");
- }
- return FALSE;
- }
-
- stream_size = g_seekable_tell (seekable);
-
- ret = g_seekable_seek (seekable, old, G_SEEK_SET, src->cancel, &err);
- if (!ret) {
- if (!gst_gio_error (src, "g_seekable_seek", &err, NULL)) {
- if (GST_GIO_ERROR_MATCHES (err, NOT_SUPPORTED))
- GST_ERROR_OBJECT (src, "Seeking to the old position not supported");
- else
- GST_ERROR_OBJECT (src, "Seeking to the old position failed: %s",
- err->message);
- g_clear_error (&err);
- } else {
- GST_ERROR_OBJECT (src, "Seeking to the old position faile");
- }
- return FALSE;
- }
-
- if (stream_size >= 0) {
- *size = stream_size;
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static gboolean
-gst_gio_base_src_is_seekable (GstBaseSrc * base_src)
-{
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
- gboolean seekable;
-
- seekable = GST_GIO_STREAM_IS_SEEKABLE (src->stream);
-
- GST_DEBUG_OBJECT (src, "can seek: %d", seekable);
-
- return seekable;
-}
-
-static gboolean
-gst_gio_base_src_unlock (GstBaseSrc * base_src)
-{
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
-
- GST_LOG_OBJECT (src, "triggering cancellation");
-
- g_cancellable_cancel (src->cancel);
-
- return TRUE;
-}
-
-static gboolean
-gst_gio_base_src_unlock_stop (GstBaseSrc * base_src)
-{
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
-
- GST_LOG_OBJECT (src, "resetting cancellable");
-
- g_cancellable_reset (src->cancel);
-
- return TRUE;
-}
-
-static gboolean
-gst_gio_base_src_check_get_range (GstBaseSrc * base_src)
-{
- return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS,
- check_get_range, (base_src), FALSE);
-}
-
-static GstFlowReturn
-gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
- GstBuffer ** buf_return)
-{
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
- GstBuffer *buf;
- GstFlowReturn ret = GST_FLOW_OK;
-
- g_return_val_if_fail (G_IS_INPUT_STREAM (src->stream), GST_FLOW_ERROR);
-
- /* If we have the requested part in our cache take a subbuffer of that,
- * otherwise fill the cache again with at least 4096 bytes from the
- * requested offset and return a subbuffer of that.
- *
- * We need caching because every read/seek operation will need to go
- * over DBus if our backend is GVfs and this is painfully slow. */
- if (src->cache && offset >= GST_BUFFER_OFFSET (src->cache) &&
- offset + size <= GST_BUFFER_OFFSET_END (src->cache)) {
- GST_DEBUG_OBJECT (src, "Creating subbuffer from cached buffer: offset %"
- G_GUINT64_FORMAT " length %u", offset, size);
-
- buf = gst_buffer_create_sub (src->cache,
- offset - GST_BUFFER_OFFSET (src->cache), size);
-
- GST_BUFFER_OFFSET (buf) = offset;
- GST_BUFFER_OFFSET_END (buf) = offset + size;
- GST_BUFFER_SIZE (buf) = size;
- } else {
- guint cachesize = MAX (4096, size);
- gssize read, res;
- gboolean success, eos;
- GError *err = NULL;
-
- if (src->cache) {
- gst_buffer_unref (src->cache);
- src->cache = NULL;
- }
-
- if (G_UNLIKELY (offset != src->position)) {
- if (!GST_GIO_STREAM_IS_SEEKABLE (src->stream))
- return GST_FLOW_NOT_SUPPORTED;
-
- GST_DEBUG_OBJECT (src, "Seeking to position %" G_GUINT64_FORMAT, offset);
- ret = gst_gio_seek (src, G_SEEKABLE (src->stream), offset, src->cancel);
-
- if (ret == GST_FLOW_OK)
- src->position = offset;
- else
- return ret;
- }
-
- src->cache = gst_buffer_try_new_and_alloc (cachesize);
- if (G_UNLIKELY (src->cache == NULL)) {
- GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", cachesize);
- return GST_FLOW_ERROR;
- }
-
- GST_LOG_OBJECT (src, "Reading %u bytes from offset %" G_GUINT64_FORMAT,
- cachesize, offset);
-
- /* GIO sometimes gives less bytes than requested although
- * it's not at the end of file. SMB for example only
- * supports reads up to 64k. So we loop here until we get at
- * at least the requested amount of bytes or a read returns
- * nothing. */
- read = 0;
- while (size - read > 0 && (res =
- g_input_stream_read (G_INPUT_STREAM (src->stream),
- GST_BUFFER_DATA (src->cache) + read, cachesize - read,
- src->cancel, &err)) > 0) {
- read += res;
- }
-
- success = (read >= 0);
- eos = (cachesize > 0 && read == 0);
-
- if (!success && !gst_gio_error (src, "g_input_stream_read", &err, &ret)) {
- GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
- ("Could not read from stream: %s", err->message));
- g_clear_error (&err);
- }
-
- if (success && !eos) {
- src->position += read;
- GST_BUFFER_SIZE (src->cache) = read;
-
- GST_BUFFER_OFFSET (src->cache) = offset;
- GST_BUFFER_OFFSET_END (src->cache) = offset + read;
-
- GST_DEBUG_OBJECT (src, "Read successful");
- GST_DEBUG_OBJECT (src, "Creating subbuffer from new "
- "cached buffer: offset %" G_GUINT64_FORMAT " length %u", offset,
- size);
-
- buf = gst_buffer_create_sub (src->cache, 0, MIN (size, read));
-
- GST_BUFFER_OFFSET (buf) = offset;
- GST_BUFFER_OFFSET_END (buf) = offset + MIN (size, read);
- GST_BUFFER_SIZE (buf) = MIN (size, read);
- } else {
- GST_DEBUG_OBJECT (src, "Read not successful");
- gst_buffer_unref (src->cache);
- src->cache = NULL;
- buf = NULL;
- }
-
- if (eos)
- ret = GST_FLOW_UNEXPECTED;
- }
-
- *buf_return = buf;
-
- return ret;
-}
-
-static gboolean
-gst_gio_base_src_query (GstBaseSrc * base_src, GstQuery * query)
-{
- gboolean ret = FALSE;
- GstGioBaseSrc *src = GST_GIO_BASE_SRC (base_src);
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_URI:
- if (GST_IS_URI_HANDLER (src)) {
- const gchar *uri = gst_uri_handler_get_uri (GST_URI_HANDLER (src));
- gst_query_set_uri (query, uri);
- ret = TRUE;
- }
- break;
- default:
- ret = FALSE;
- break;
- }
-
- if (!ret)
- ret = GST_BASE_SRC_CLASS (parent_class)->query (base_src, query);
-
- return ret;
-}
diff --git a/ext/gio/gstgiobasesrc.h b/ext/gio/gstgiobasesrc.h
deleted file mode 100644
index 7a14859c..00000000
--- a/ext/gio/gstgiobasesrc.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <slomo@circular-chaos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GIO_BASE_SRC_H__
-#define __GST_GIO_BASE_SRC_H__
-
-#include "gstgio.h"
-
-#include <gst/base/gstbasesrc.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GIO_BASE_SRC \
- (gst_gio_base_src_get_type())
-#define GST_GIO_BASE_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_BASE_SRC,GstGioBaseSrc))
-#define GST_GIO_BASE_SRC_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_GIO_BASE_SRC, GstGioBaseSrcClass))
-#define GST_GIO_BASE_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_BASE_SRC,GstGioBaseSrcClass))
-#define GST_IS_GIO_BASE_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_BASE_SRC))
-#define GST_IS_GIO_BASE_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_BASE_SRC))
-
-typedef struct _GstGioBaseSrc GstGioBaseSrc;
-typedef struct _GstGioBaseSrcClass GstGioBaseSrcClass;
-
-struct _GstGioBaseSrc
-{
- GstBaseSrc src;
-
- /* < protected > */
- GCancellable *cancel;
- guint64 position;
-
- /* < private > */
- GInputStream *stream;
- GstBuffer *cache;
-};
-
-struct _GstGioBaseSrcClass
-{
- GstBaseSrcClass parent_class;
-
- GInputStream * (*get_stream) (GstGioBaseSrc *bsrc);
- gboolean close_on_stop;
-};
-
-GType gst_gio_base_src_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_GIO_BASE_SRC_H__ */
diff --git a/ext/gio/gstgiosink.c b/ext/gio/gstgiosink.c
deleted file mode 100644
index 69e05e50..00000000
--- a/ext/gio/gstgiosink.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-giosink
- * @see_also: #GstFileSink, #GstGnomeVFSSink, #GstGioSrc
- *
- * This plugin writes incoming data to a local or remote location specified
- * by an URI. This location can be specified using any protocol supported by
- * the GIO library or it's VFS backends. Common protocols are 'file', 'ftp',
- * or 'smb'.
- *
- * If the URI or #GFile already exists giosink will post a message of
- * type %GST_MESSAGE_ELEMENT with name "file-exists" on the bus. The message
- * also contains the #GFile and the corresponding URI.
- * Applications can use the "file-exists" message to notify the user about
- * the problem and to set a different target location or to remove the
- * existing file. Note that right after the "file-exists" message a normal
- * error message is posted on the bus which should be ignored if "file-exists"
- * is handled by the application, for example by calling
- * gst_bus_set_flushing(bus, TRUE) after the "file-exists" message was
- * received and gst_bus_set_flushing(bus, FALSE) after the problem is
- * resolved.
- *
- * Similar to the "file-exist" message a "not-mounted" message is posted
- * on the bus if the target location is not mounted yet and needs to be
- * mounted. This message can be used by application to mount the location
- * and retry after the location was mounted successfully.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v filesrc location=input.xyz ! giosink location=file:///home/joe/out.xyz
- * ]| The above pipeline will simply copy a local file. Instead of giosink,
- * we could just as well have used the filesink element here.
- * |[
- * gst-launch -v filesrc location=foo.mp3 ! mad ! flacenc ! giosink location=smb://othercomputer/foo.flac
- * ]| The above pipeline will re-encode an mp3 file into FLAC format and store
- * it on a remote host using the Samba protocol.
- * |[
- * gst-launch -v audiotestsrc num-buffers=100 ! vorbisenc ! oggmux ! giosink location=file:///home/foo/bar.ogg
- * ]| The above pipeline will encode a 440Hz sine wave to Ogg Vorbis and stores
- * it in the home directory of user foo.
- * </refsect2>
- */
-
-/* FIXME: We would like to mount the enclosing volume of an URL
- * if it isn't mounted yet but this is possible async-only.
- * Unfortunately this requires a running main loop from the
- * default context and we can't guarantuee this!
- *
- * We would also like to do authentication while mounting.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "gstgiosink.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_gio_sink_debug);
-#define GST_CAT_DEFAULT gst_gio_sink_debug
-
-/* Filter signals and args */
-enum
-{
- LAST_SIGNAL
-};
-
-enum
-{
- PROP_0,
- PROP_LOCATION,
- PROP_FILE
-};
-
-GST_BOILERPLATE_FULL (GstGioSink, gst_gio_sink, GstGioBaseSink,
- GST_TYPE_GIO_BASE_SINK, gst_gio_uri_handler_do_init);
-
-static void gst_gio_sink_finalize (GObject * object);
-static void gst_gio_sink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_gio_sink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static GOutputStream *gst_gio_sink_get_stream (GstGioBaseSink * base_sink);
-
-static void
-gst_gio_sink_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_sink_debug, "gio_sink", 0, "GIO sink");
-
- gst_element_class_set_details_simple (element_class, "GIO sink",
- "Sink/File",
- "Write to any GIO-supported location",
- "Ren\xc3\xa9 Stadler <mail@renestadler.de>, "
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
-gst_gio_sink_class_init (GstGioSinkClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstGioBaseSinkClass *gstgiobasesink_class = (GstGioBaseSinkClass *) klass;
-
- gobject_class->finalize = gst_gio_sink_finalize;
- gobject_class->set_property = gst_gio_sink_set_property;
- gobject_class->get_property = gst_gio_sink_get_property;
-
- g_object_class_install_property (gobject_class, PROP_LOCATION,
- g_param_spec_string ("location", "Location", "URI location to write to",
- NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstGioSink:file
- *
- * %GFile to write to.
- *
- * Since: 0.10.20
- **/
- g_object_class_install_property (gobject_class, PROP_FILE,
- g_param_spec_object ("file", "File", "GFile to write to",
- G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstgiobasesink_class->get_stream =
- GST_DEBUG_FUNCPTR (gst_gio_sink_get_stream);
- gstgiobasesink_class->close_on_stop = TRUE;
-}
-
-static void
-gst_gio_sink_init (GstGioSink * sink, GstGioSinkClass * gclass)
-{
-}
-
-static void
-gst_gio_sink_finalize (GObject * object)
-{
- GstGioSink *sink = GST_GIO_SINK (object);
-
- if (sink->file) {
- g_object_unref (sink->file);
- sink->file = NULL;
- }
-
- GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
-}
-
-static void
-gst_gio_sink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstGioSink *sink = GST_GIO_SINK (object);
-
- switch (prop_id) {
- case PROP_LOCATION:{
- const gchar *uri = NULL;
-
- if (GST_STATE (sink) == GST_STATE_PLAYING ||
- GST_STATE (sink) == GST_STATE_PAUSED) {
- GST_WARNING
- ("Setting a new location or GFile not supported in PLAYING or PAUSED state");
- break;
- }
-
- GST_OBJECT_LOCK (GST_OBJECT (sink));
- if (sink->file)
- g_object_unref (sink->file);
-
- uri = g_value_get_string (value);
-
- if (uri) {
- sink->file = g_file_new_for_uri (uri);
-
- if (!sink->file) {
- GST_ERROR ("Could not create GFile for URI '%s'", uri);
- }
- } else {
- sink->file = NULL;
- }
- GST_OBJECT_UNLOCK (GST_OBJECT (sink));
- break;
- }
- case PROP_FILE:
- if (GST_STATE (sink) == GST_STATE_PLAYING ||
- GST_STATE (sink) == GST_STATE_PAUSED) {
- GST_WARNING
- ("Setting a new location or GFile not supported in PLAYING or PAUSED state");
- break;
- }
-
- GST_OBJECT_LOCK (GST_OBJECT (sink));
- if (sink->file)
- g_object_unref (sink->file);
-
- sink->file = g_value_dup_object (value);
-
- GST_OBJECT_UNLOCK (GST_OBJECT (sink));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_gio_sink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstGioSink *sink = GST_GIO_SINK (object);
-
- switch (prop_id) {
- case PROP_LOCATION:{
- gchar *uri;
-
- GST_OBJECT_LOCK (GST_OBJECT (sink));
- if (sink->file) {
- uri = g_file_get_uri (sink->file);
- g_value_set_string (value, uri);
- g_free (uri);
- } else {
- g_value_set_string (value, NULL);
- }
- GST_OBJECT_UNLOCK (GST_OBJECT (sink));
- break;
- }
- case PROP_FILE:
- GST_OBJECT_LOCK (GST_OBJECT (sink));
- g_value_set_object (value, sink->file);
- GST_OBJECT_UNLOCK (GST_OBJECT (sink));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GOutputStream *
-gst_gio_sink_get_stream (GstGioBaseSink * bsink)
-{
- GstGioSink *sink = GST_GIO_SINK (bsink);
- GOutputStream *stream;
- GCancellable *cancel = GST_GIO_BASE_SINK (sink)->cancel;
- GError *err = NULL;
- gchar *uri;
-
- if (sink->file == NULL) {
- GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
- ("No location or GFile given"));
- return NULL;
- }
-
- uri = g_file_get_uri (sink->file);
- if (!uri)
- uri = g_strdup ("(null)");
-
- stream =
- G_OUTPUT_STREAM (g_file_create (sink->file, G_FILE_CREATE_NONE, cancel,
- &err));
-
- if (!stream) {
- if (!gst_gio_error (sink, "g_file_create", &err, NULL)) {
- /*if (GST_GIO_ERROR_MATCHES (err, EXISTS)) */
- /* FIXME: Retry with replace if overwrite == TRUE! */
-
- if (GST_GIO_ERROR_MATCHES (err, NOT_FOUND)) {
- GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, (NULL),
- ("Could not open location %s for writing: %s", uri, err->message));
- } else if (GST_GIO_ERROR_MATCHES (err, EXISTS)) {
- gst_element_post_message (GST_ELEMENT_CAST (sink),
- gst_message_new_element (GST_OBJECT_CAST (sink),
- gst_structure_new ("file-exists", "file", G_TYPE_FILE,
- sink->file, "uri", G_TYPE_STRING, uri, NULL)));
-
- GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
- ("Location %s already exists: %s", uri, err->message));
- } else if (GST_GIO_ERROR_MATCHES (err, NOT_MOUNTED)) {
- gst_element_post_message (GST_ELEMENT_CAST (sink),
- gst_message_new_element (GST_OBJECT_CAST (sink),
- gst_structure_new ("not-mounted", "file", G_TYPE_FILE,
- sink->file, "uri", G_TYPE_STRING, uri, NULL)));
-
- GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
- ("Location %s not mounted: %s", uri, err->message));
- } else {
- GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL),
- ("Could not open location %s for writing: %s", uri, err->message));
- }
-
- g_clear_error (&err);
- }
- g_free (uri);
- return NULL;
- }
-
- GST_DEBUG_OBJECT (sink, "opened location %s", uri);
-
- g_free (uri);
-
- return stream;
-}
diff --git a/ext/gio/gstgiosink.h b/ext/gio/gstgiosink.h
deleted file mode 100644
index 494d5db3..00000000
--- a/ext/gio/gstgiosink.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <slomo@circular-chaos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GIO_SINK_H__
-#define __GST_GIO_SINK_H__
-
-#include "gstgio.h"
-#include "gstgiobasesink.h"
-
-#include <gst/base/gstbasesink.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GIO_SINK \
- (gst_gio_sink_get_type())
-#define GST_GIO_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_SINK,GstGioSink))
-#define GST_GIO_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_SINK,GstGioSinkClass))
-#define GST_IS_GIO_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_SINK))
-#define GST_IS_GIO_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_SINK))
-
-typedef struct _GstGioSink GstGioSink;
-typedef struct _GstGioSinkClass GstGioSinkClass;
-
-/**
- * GstGioSink:
- *
- * Opaque data structure.
- */
-struct _GstGioSink
-{
- GstGioBaseSink sink;
-
- /*< private >*/
- GFile *file;
-};
-
-struct _GstGioSinkClass
-{
- GstGioBaseSinkClass parent_class;
-};
-
-GType gst_gio_sink_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_GIO_SINK_H__ */
diff --git a/ext/gio/gstgiosrc.c b/ext/gio/gstgiosrc.c
deleted file mode 100644
index 5fd810e7..00000000
--- a/ext/gio/gstgiosrc.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-giosrc
- * @see_also: #GstFileSrc, #GstGnomeVFSSrc, #GstGioSink
- *
- * This plugin reads data from a local or remote location specified
- * by an URI. This location can be specified using any protocol supported by
- * the GIO library or it's VFS backends. Common protocols are 'file', 'http',
- * 'ftp', or 'smb'.
- *
- * If an URI or #GFile is not mounted giosrc will post a message of type
- * %GST_MESSAGE_ELEMENT with name "not-mounted" on the bus. The message
- * also contains the #GFile and the corresponding URI.
- * Applications can use the "not-mounted" message to mount the #GFile
- * by calling g_file_mount_enclosing_volume() and then restart the
- * pipeline after the mounting has succeeded. Note that right after the
- * "not-mounted" message a normal error message is posted on the bus which
- * should be ignored if "not-mounted" is handled by the application, for
- * example by calling gst_bus_set_flushing(bus, TRUE) after the "not-mounted"
- * message was received and gst_bus_set_flushing(bus, FALSE) after the
- * mounting was successful.
- *
- * <refsect2>
- * <title>Example launch lines</title>
- * |[
- * gst-launch -v giosrc location=file:///home/joe/foo.xyz ! fakesink
- * ]| The above pipeline will simply read a local file and do nothing with the
- * data read. Instead of giosrc, we could just as well have used the
- * filesrc element here.
- * |[
- * gst-launch -v giosrc location=smb://othercomputer/foo.xyz ! filesink location=/home/joe/foo.xyz
- * ]| The above pipeline will copy a file from a remote host to the local file
- * system using the Samba protocol.
- * |[
- * gst-launch -v giosrc location=http://music.foobar.com/demo.mp3 ! mad ! audioconvert ! audioresample ! alsasink
- * ]| The above pipeline will read and decode and play an mp3 file from a
- * web server using the http protocol.
- * </refsect2>
- */
-
-/* FIXME: We would like to mount the enclosing volume of an URL
- * if it isn't mounted yet but this is possible async-only.
- * Unfortunately this requires a running main loop from the
- * default context and we can't guarantuee this!
- *
- * We would also like to do authentication while mounting.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "gstgiosrc.h"
-#include <string.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_gio_src_debug);
-#define GST_CAT_DEFAULT gst_gio_src_debug
-
-enum
-{
- PROP_0,
- PROP_LOCATION,
- PROP_FILE
-};
-
-GST_BOILERPLATE_FULL (GstGioSrc, gst_gio_src, GstGioBaseSrc,
- GST_TYPE_GIO_BASE_SRC, gst_gio_uri_handler_do_init);
-
-static void gst_gio_src_finalize (GObject * object);
-
-static void gst_gio_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_gio_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static GInputStream *gst_gio_src_get_stream (GstGioBaseSrc * bsrc);
-
-static gboolean gst_gio_src_check_get_range (GstBaseSrc * base_src);
-
-static void
-gst_gio_src_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_src_debug, "gio_src", 0, "GIO source");
-
- gst_element_class_set_details_simple (element_class, "GIO source",
- "Source/File",
- "Read from any GIO-supported location",
- "Ren\xc3\xa9 Stadler <mail@renestadler.de>, "
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
-gst_gio_src_class_init (GstGioSrcClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
- GstGioBaseSrcClass *gstgiobasesrc_class = (GstGioBaseSrcClass *) klass;
-
- gobject_class->finalize = gst_gio_src_finalize;
- gobject_class->set_property = gst_gio_src_set_property;
- gobject_class->get_property = gst_gio_src_get_property;
-
- g_object_class_install_property (gobject_class, PROP_LOCATION,
- g_param_spec_string ("location", "Location", "URI location to read from",
- NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstGioSrc:file
- *
- * %GFile to read from.
- *
- * Since: 0.10.20
- **/
- g_object_class_install_property (gobject_class, PROP_FILE,
- g_param_spec_object ("file", "File", "GFile to read from",
- G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_gio_src_check_get_range);
-
- gstgiobasesrc_class->get_stream = GST_DEBUG_FUNCPTR (gst_gio_src_get_stream);
- gstgiobasesrc_class->close_on_stop = TRUE;
-}
-
-static void
-gst_gio_src_init (GstGioSrc * src, GstGioSrcClass * gclass)
-{
-}
-
-static void
-gst_gio_src_finalize (GObject * object)
-{
- GstGioSrc *src = GST_GIO_SRC (object);
-
- if (src->file) {
- g_object_unref (src->file);
- src->file = NULL;
- }
-
- GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
-}
-
-static void
-gst_gio_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstGioSrc *src = GST_GIO_SRC (object);
-
- switch (prop_id) {
- case PROP_LOCATION:{
- const gchar *uri = NULL;
-
- if (GST_STATE (src) == GST_STATE_PLAYING ||
- GST_STATE (src) == GST_STATE_PAUSED) {
- GST_WARNING
- ("Setting a new location or GFile not supported in PLAYING or PAUSED state");
- break;
- }
-
- GST_OBJECT_LOCK (GST_OBJECT (src));
- if (src->file)
- g_object_unref (src->file);
-
- uri = g_value_get_string (value);
-
- if (uri) {
- src->file = g_file_new_for_uri (uri);
-
- if (!src->file) {
- GST_ERROR ("Could not create GFile for URI '%s'", uri);
- }
- } else {
- src->file = NULL;
- }
- GST_OBJECT_UNLOCK (GST_OBJECT (src));
- break;
- }
- case PROP_FILE:
- if (GST_STATE (src) == GST_STATE_PLAYING ||
- GST_STATE (src) == GST_STATE_PAUSED) {
- GST_WARNING
- ("Setting a new location or GFile not supported in PLAYING or PAUSED state");
- break;
- }
-
- GST_OBJECT_LOCK (GST_OBJECT (src));
- if (src->file)
- g_object_unref (src->file);
-
- src->file = g_value_dup_object (value);
-
- GST_OBJECT_UNLOCK (GST_OBJECT (src));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_gio_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstGioSrc *src = GST_GIO_SRC (object);
-
- switch (prop_id) {
- case PROP_LOCATION:{
- gchar *uri;
-
- GST_OBJECT_LOCK (GST_OBJECT (src));
- if (src->file) {
- uri = g_file_get_uri (src->file);
- g_value_set_string (value, uri);
- g_free (uri);
- } else {
- g_value_set_string (value, NULL);
- }
- GST_OBJECT_UNLOCK (GST_OBJECT (src));
- break;
- }
- case PROP_FILE:
- GST_OBJECT_LOCK (GST_OBJECT (src));
- g_value_set_object (value, src->file);
- GST_OBJECT_UNLOCK (GST_OBJECT (src));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static gboolean
-gst_gio_src_check_get_range (GstBaseSrc * base_src)
-{
- GstGioSrc *src = GST_GIO_SRC (base_src);
- gchar *scheme;
-
- if (src->file == NULL)
- goto done;
-
- scheme = g_file_get_uri_scheme (src->file);
- if (scheme == NULL)
- goto done;
-
- if (strcmp (scheme, "file") == 0) {
- GST_LOG_OBJECT (src, "local URI, assuming random access is possible");
- g_free (scheme);
- return TRUE;
- } else if (strcmp (scheme, "http") == 0 || strcmp (scheme, "https") == 0) {
- GST_LOG_OBJECT (src, "blacklisted protocol '%s', "
- "no random access possible", scheme);
- g_free (scheme);
- return FALSE;
- }
-
- g_free (scheme);
-
-done:
-
- GST_DEBUG_OBJECT (src, "undecided about random access, asking base class");
-
- return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS,
- check_get_range, (base_src), FALSE);
-}
-
-
-static GInputStream *
-gst_gio_src_get_stream (GstGioBaseSrc * bsrc)
-{
- GstGioSrc *src = GST_GIO_SRC (bsrc);
- GError *err = NULL;
- GInputStream *stream;
- GCancellable *cancel = bsrc->cancel;
- gchar *uri = NULL;
-
- if (src->file == NULL) {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
- ("No location or GFile given"));
- return NULL;
- }
-
- uri = g_file_get_uri (src->file);
- if (!uri)
- uri = g_strdup ("(null)");
-
- stream = G_INPUT_STREAM (g_file_read (src->file, cancel, &err));
-
- if (stream == NULL && !gst_gio_error (src, "g_file_read", &err, NULL)) {
- if (GST_GIO_ERROR_MATCHES (err, NOT_FOUND)) {
- GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
- ("Could not open location %s for reading: %s", uri, err->message));
- } else if (GST_GIO_ERROR_MATCHES (err, NOT_MOUNTED)) {
- gst_element_post_message (GST_ELEMENT_CAST (src),
- gst_message_new_element (GST_OBJECT_CAST (src),
- gst_structure_new ("not-mounted", "file", G_TYPE_FILE, src->file,
- "uri", G_TYPE_STRING, uri, NULL)));
-
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
- ("Location %s not mounted: %s", uri, err->message));
- } else {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
- ("Could not open location %s for reading: %s", uri, err->message));
- }
-
- g_free (uri);
- g_clear_error (&err);
- return NULL;
- } else if (stream == NULL) {
- g_free (uri);
- return NULL;
- }
-
- GST_DEBUG_OBJECT (src, "opened location %s", uri);
- g_free (uri);
-
- return stream;
-}
diff --git a/ext/gio/gstgiosrc.h b/ext/gio/gstgiosrc.h
deleted file mode 100644
index 080d3d8f..00000000
--- a/ext/gio/gstgiosrc.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <slomo@circular-chaos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GIO_SRC_H__
-#define __GST_GIO_SRC_H__
-
-#include "gstgio.h"
-#include "gstgiobasesrc.h"
-
-#include <gst/base/gstbasesrc.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GIO_SRC \
- (gst_gio_src_get_type())
-#define GST_GIO_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_SRC,GstGioSrc))
-#define GST_GIO_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_SRC,GstGioSrcClass))
-#define GST_IS_GIO_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_SRC))
-#define GST_IS_GIO_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_SRC))
-
-typedef struct _GstGioSrc GstGioSrc;
-typedef struct _GstGioSrcClass GstGioSrcClass;
-
-/**
- * GstGioSrc:
- *
- * Opaque data structure.
- */
-struct _GstGioSrc
-{
- GstGioBaseSrc src;
-
- /*< private >*/
- GFile *file;
-};
-
-struct _GstGioSrcClass
-{
- GstGioBaseSrcClass parent_class;
-};
-
-GType gst_gio_src_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_GIO_SRC_H__ */
diff --git a/ext/gio/gstgiostreamsink.c b/ext/gio/gstgiostreamsink.c
deleted file mode 100644
index 02dac71f..00000000
--- a/ext/gio/gstgiostreamsink.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-giostreamsink
- *
- * This plugin writes incoming data to a custom GIO #GOutputStream.
- *
- * It can, for example, be used to write a stream to memory with a
- * #GMemoryOuputStream or to write to a file with a #GFileOuputStream.
- *
- * <refsect2>
- * <title>Example code</title>
- * <para>
- * The following example writes the received data to a #GMemoryOutputStream.
- * |[
-
-#include &lt;gst/gst.h&gt;
-#include &lt;gio/gio.h&gt;
-
-...
-
-GstElement *sink;
-GMemoryOuputStream *stream;
-// out_data will contain the received data
-guint8 *out_data;
-
-...
-
-stream = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new (NULL, 0,
- (GReallocFunc) g_realloc, (GDestroyNotify) g_free));
-sink = gst_element_factory_make ("giostreamsink", "sink");
-g_object_set (G_OBJECT (sink), "stream", stream, NULL);
-
-...
-
-// after processing get the written data
-out_data = g_memory_ouput_stream_get_data (G_MEMORY_OUTPUT_STREAM (stream));
-
-...
-
- * ]|
- * </para>
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "gstgiostreamsink.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_gio_stream_sink_debug);
-#define GST_CAT_DEFAULT gst_gio_stream_sink_debug
-
-/* Filter signals and args */
-enum
-{
- LAST_SIGNAL
-};
-
-enum
-{
- PROP_0,
- PROP_STREAM
-};
-
-GST_BOILERPLATE (GstGioStreamSink, gst_gio_stream_sink, GstGioBaseSink,
- GST_TYPE_GIO_BASE_SINK);
-
-static void gst_gio_stream_sink_finalize (GObject * object);
-static void gst_gio_stream_sink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_gio_stream_sink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static GOutputStream *gst_gio_stream_sink_get_stream (GstGioBaseSink * bsink);
-
-static void
-gst_gio_stream_sink_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_stream_sink_debug, "gio_stream_sink", 0,
- "GIO stream sink");
-
- gst_element_class_set_details_simple (element_class, "GIO stream sink",
- "Sink",
- "Write to any GIO stream",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
-gst_gio_stream_sink_class_init (GstGioStreamSinkClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstGioBaseSinkClass *ggbsink_class = (GstGioBaseSinkClass *) klass;
-
- gobject_class->finalize = gst_gio_stream_sink_finalize;
- gobject_class->set_property = gst_gio_stream_sink_set_property;
- gobject_class->get_property = gst_gio_stream_sink_get_property;
-
- g_object_class_install_property (gobject_class, PROP_STREAM,
- g_param_spec_object ("stream", "Stream", "Stream to write to",
- G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- ggbsink_class->get_stream =
- GST_DEBUG_FUNCPTR (gst_gio_stream_sink_get_stream);
-}
-
-static void
-gst_gio_stream_sink_init (GstGioStreamSink * sink,
- GstGioStreamSinkClass * gclass)
-{
-}
-
-static void
-gst_gio_stream_sink_finalize (GObject * object)
-{
- GstGioStreamSink *sink = GST_GIO_STREAM_SINK (object);
-
- if (sink->stream) {
- g_object_unref (sink->stream);
- sink->stream = NULL;
- }
-
- GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
-}
-
-static void
-gst_gio_stream_sink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstGioStreamSink *sink = GST_GIO_STREAM_SINK (object);
-
- switch (prop_id) {
- case PROP_STREAM:{
- GObject *stream;
-
- if (GST_STATE (sink) == GST_STATE_PLAYING ||
- GST_STATE (sink) == GST_STATE_PAUSED) {
- GST_WARNING
- ("Setting a new stream not supported in PLAYING or PAUSED state");
- break;
- }
-
- stream = g_value_dup_object (value);
- if (sink->stream)
- g_object_unref (sink->stream);
- sink->stream = G_OUTPUT_STREAM (stream);
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_gio_stream_sink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstGioStreamSink *sink = GST_GIO_STREAM_SINK (object);
-
- switch (prop_id) {
- case PROP_STREAM:
- g_value_set_object (value, GST_GIO_BASE_SINK (sink)->stream);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GOutputStream *
-gst_gio_stream_sink_get_stream (GstGioBaseSink * bsink)
-{
- GstGioStreamSink *sink = GST_GIO_STREAM_SINK (bsink);
-
- return (sink->stream) ? g_object_ref (sink->stream) : NULL;
-}
diff --git a/ext/gio/gstgiostreamsink.h b/ext/gio/gstgiostreamsink.h
deleted file mode 100644
index 5e6206b5..00000000
--- a/ext/gio/gstgiostreamsink.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <slomo@circular-chaos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GIO_STREAM_SINK_H__
-#define __GST_GIO_STREAM_SINK_H__
-
-#include "gstgio.h"
-#include "gstgiobasesink.h"
-
-#include <gst/base/gstbasesink.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GIO_STREAM_SINK \
- (gst_gio_stream_sink_get_type())
-#define GST_GIO_STREAM_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_STREAM_SINK,GstGioStreamSink))
-#define GST_GIO_STREAM_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_STREAM_SINK,GstGioStreamSinkClass))
-#define GST_IS_GIO_STREAM_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_STREAM_SINK))
-#define GST_IS_GIO_STREAM_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_STREAM_SINK))
-
-typedef struct _GstGioStreamSink GstGioStreamSink;
-typedef struct _GstGioStreamSinkClass GstGioStreamSinkClass;
-
-/**
- * GstGioStreamSink:
- *
- * Opaque data structure.
- */
-struct _GstGioStreamSink
-{
- GstGioBaseSink sink;
-
- /* < private > */
- GOutputStream *stream;
-};
-
-struct _GstGioStreamSinkClass
-{
- GstGioBaseSinkClass parent_class;
-};
-
-GType gst_gio_stream_sink_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_GIO_STREAM_SINK_H__ */
diff --git a/ext/gio/gstgiostreamsrc.c b/ext/gio/gstgiostreamsrc.c
deleted file mode 100644
index b031de6b..00000000
--- a/ext/gio/gstgiostreamsrc.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-giostreamsrc
- *
- * This plugin reads data from a custom GIO #GInputStream.
- *
- * It can, for example, be used to read data from memory with a
- * #GMemoryInputStream or to read from a file with a
- * #GFileInputStream.
- *
- * <refsect2>
- * <title>Example code</title>
- * <para>
- * The following example reads data from a #GMemoryOutputStream.
- * |[
-
-#include &lt;gst/gst.h&gt;
-#include &lt;gio/gio.h&gt;
-
-...
-
-GstElement *src;
-GMemoryInputStream *stream;
-// in_data will contain the data to send
-guint8 *in_data;
-gint i;
-
-...
-in_data = g_new (guint8, 512);
-for (i = 0; i < 512; i++)
- in_data[i] = i % 256;
-
-stream = G_MEMORY_INPUT_STREAM (g_memory_input_stream_new_from_data (in_data, 512,
- (GDestroyNotify) g_free));
-src = gst_element_factory_make ("giostreamsrc", "src");
-g_object_set (G_OBJECT (src), "stream", stream, NULL);
-
-...
-
- * ]|
- * </para>
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "gstgiostreamsrc.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_gio_stream_src_debug);
-#define GST_CAT_DEFAULT gst_gio_stream_src_debug
-
-enum
-{
- PROP_0,
- PROP_STREAM
-};
-
-GST_BOILERPLATE (GstGioStreamSrc, gst_gio_stream_src, GstGioBaseSrc,
- GST_TYPE_GIO_BASE_SRC);
-
-static void gst_gio_stream_src_finalize (GObject * object);
-static void gst_gio_stream_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_gio_stream_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static GInputStream *gst_gio_stream_src_get_stream (GstGioBaseSrc * bsrc);
-
-static void
-gst_gio_stream_src_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_stream_src_debug, "gio_stream_src", 0,
- "GIO source");
-
- gst_element_class_set_details_simple (element_class, "GIO stream source",
- "Source",
- "Read from any GIO stream",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
-gst_gio_stream_src_class_init (GstGioStreamSrcClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstGioBaseSrcClass *gstgiobasesrc_class = (GstGioBaseSrcClass *) klass;
-
- gobject_class->finalize = gst_gio_stream_src_finalize;
- gobject_class->set_property = gst_gio_stream_src_set_property;
- gobject_class->get_property = gst_gio_stream_src_get_property;
-
- g_object_class_install_property (gobject_class, PROP_STREAM,
- g_param_spec_object ("stream", "Stream", "Stream to read from",
- G_TYPE_INPUT_STREAM, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstgiobasesrc_class->get_stream =
- GST_DEBUG_FUNCPTR (gst_gio_stream_src_get_stream);
-}
-
-static void
-gst_gio_stream_src_init (GstGioStreamSrc * src, GstGioStreamSrcClass * gclass)
-{
-}
-
-static void
-gst_gio_stream_src_finalize (GObject * object)
-{
- GstGioStreamSrc *src = GST_GIO_STREAM_SRC (object);
-
- if (src->stream) {
- g_object_unref (src->stream);
- src->stream = NULL;
- }
-
- GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
-}
-
-static void
-gst_gio_stream_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstGioStreamSrc *src = GST_GIO_STREAM_SRC (object);
-
- switch (prop_id) {
- case PROP_STREAM:{
- GObject *stream;
-
- if (GST_STATE (src) == GST_STATE_PLAYING ||
- GST_STATE (src) == GST_STATE_PAUSED) {
- GST_WARNING
- ("Setting a new stream not supported in PLAYING or PAUSED state");
- break;
- }
-
- stream = g_value_dup_object (value);
- if (src->stream)
- g_object_unref (src->stream);
- src->stream = G_INPUT_STREAM (stream);
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_gio_stream_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstGioStreamSrc *src = GST_GIO_STREAM_SRC (object);
-
- switch (prop_id) {
- case PROP_STREAM:
- g_value_set_object (value, src->stream);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GInputStream *
-gst_gio_stream_src_get_stream (GstGioBaseSrc * bsrc)
-{
- GstGioStreamSrc *src = GST_GIO_STREAM_SRC (bsrc);
-
- return (src->stream) ? g_object_ref (src->stream) : NULL;
-}
diff --git a/ext/gio/gstgiostreamsrc.h b/ext/gio/gstgiostreamsrc.h
deleted file mode 100644
index 975a2775..00000000
--- a/ext/gio/gstgiostreamsrc.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2007 Rene Stadler <mail@renestadler.de>
- * Copyright (C) 2007-2009 Sebastian Dröge <slomo@circular-chaos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GIO_STREAM_SRC_H__
-#define __GST_GIO_STREAM_SRC_H__
-
-#include "gstgio.h"
-#include "gstgiobasesrc.h"
-
-#include <gst/base/gstbasesrc.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GIO_STREAM_SRC \
- (gst_gio_stream_src_get_type())
-#define GST_GIO_STREAM_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GIO_STREAM_SRC,GstGioStreamSrc))
-#define GST_GIO_STREAM_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GIO_STREAM_SRC,GstGioStreamSrcClass))
-#define GST_IS_GIO_STREAM_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GIO_STREAM_SRC))
-#define GST_IS_GIO_STREAM_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GIO_STREAM_SRC))
-
-typedef struct _GstGioStreamSrc GstGioStreamSrc;
-typedef struct _GstGioStreamSrcClass GstGioStreamSrcClass;
-
-/**
- * GstGioStreamSrc:
- *
- * Opaque data structure.
- */
-struct _GstGioStreamSrc
-{
- GstGioBaseSrc src;
-
- /* < private > */
- GInputStream *stream;
-};
-
-struct _GstGioStreamSrcClass
-{
- GstGioBaseSrcClass parent_class;
-};
-
-GType gst_gio_stream_src_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_GIO_STREAM_SRC_H__ */
diff --git a/ext/gnomevfs/Makefile.am b/ext/gnomevfs/Makefile.am
deleted file mode 100644
index f87a94b3..00000000
--- a/ext/gnomevfs/Makefile.am
+++ /dev/null
@@ -1,21 +0,0 @@
-plugin_LTLIBRARIES = libgstgnomevfs.la
-
-libgstgnomevfs_la_SOURCES = \
- gstgnomevfs.c \
- gstgnomevfssink.c \
- gstgnomevfssrc.c \
- gstgnomevfsuri.c
-
-libgstgnomevfs_la_CFLAGS = \
- $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GNOME_VFS_CFLAGS)
-libgstgnomevfs_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/tag/libgsttag-$(GST_MAJORMINOR).la \
- $(GST_BASE_LIBS) $(GNOME_VFS_LIBS)
-libgstgnomevfs_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstgnomevfs_la_LIBTOOLFLAGS = --tag=disable-static
-
-noinst_HEADERS = \
- gstgnomevfs.h \
- gstgnomevfssink.h \
- gstgnomevfssrc.h \
- gstgnomevfsuri.h
diff --git a/ext/gnomevfs/gstgnomevfs.c b/ext/gnomevfs/gstgnomevfs.c
deleted file mode 100644
index 747f1cf0..00000000
--- a/ext/gnomevfs/gstgnomevfs.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* GStreamer
- * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
- *
- * gnomevfs.c: register gnomevfs elements
- *
- * 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-i18n-plugin.h"
-
-#include "gstgnomevfs.h"
-#include "gstgnomevfssrc.h"
-#include "gstgnomevfssink.h"
-
-#include <libgnomevfs/gnome-vfs.h>
-#include <gst/gst.h>
-
-#include <string.h>
-
-gchar *
-gst_gnome_vfs_location_to_uri_string (const gchar * location)
-{
- gchar *newloc, *ret;
-
- if (location == NULL)
- return NULL;
-
- /* already an URI string? */
- if (strstr (location, "://"))
- return g_strdup (location);
-
- newloc = gnome_vfs_escape_path_string (location);
-
- if (newloc && *newloc == '/') {
- ret = g_strdup_printf ("file://%s", newloc);
- } else {
- gchar *curdir;
-
- curdir = g_get_current_dir ();
- ret = g_strdup_printf ("file://%s/%s", curdir, newloc);
- g_free (curdir);
- }
-
- g_free (newloc);
- return ret;
-}
-
-GType
-gst_gnome_vfs_uri_get_type (void)
-{
- static GType type; /* 0 */
-
- if (type == 0) {
- type = g_boxed_type_register_static ("GnomeVFSURI",
- (GBoxedCopyFunc) gnome_vfs_uri_ref,
- (GBoxedFreeFunc) gnome_vfs_uri_unref);
- }
-
- return type;
-}
-
-static gpointer
-gst_gnome_vfs_handle_copy (gpointer handle)
-{
- return handle;
-}
-
-static void
-gst_gnome_vfs_handle_free (gpointer handle)
-{
- return;
-}
-
-GType
-gst_gnome_vfs_handle_get_type (void)
-{
- static GType type; /* 0 */
-
- if (type == 0) {
- /* hackish, but makes it show up nicely in gst-inspect */
- type = g_boxed_type_register_static ("GnomeVFSHandle",
- (GBoxedCopyFunc) gst_gnome_vfs_handle_copy,
- (GBoxedFreeFunc) gst_gnome_vfs_handle_free);
- }
-
- return type;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- /* gnome vfs engine init */
- if (!gnome_vfs_initialized ()) {
- if (!gnome_vfs_init ()) {
- GST_WARNING ("Failed to initialize GnomeVFS - not registering plugin!");
- return FALSE;
- }
- }
-
- gst_plugin_add_dependency_simple (plugin, NULL, GNOME_VFS_MODULES_DIR, NULL,
- GST_PLUGIN_DEPENDENCY_FLAG_NONE);
-
- if (!gst_element_register (plugin, "gnomevfssrc", GST_RANK_SECONDARY,
- gst_gnome_vfs_src_get_type ()))
- return FALSE;
-
- if (!gst_element_register (plugin, "gnomevfssink", GST_RANK_SECONDARY,
- gst_gnome_vfs_sink_get_type ()))
- return FALSE;
-
-#ifdef ENABLE_NLS
-/* FIXME: add category
- GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE, LOCALEDIR);
- */
- bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-#endif /* ENABLE_NLS */
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "gnomevfs",
- "elements to read from and write to Gnome-VFS uri's",
- plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/gnomevfs/gstgnomevfs.h b/ext/gnomevfs/gstgnomevfs.h
deleted file mode 100644
index f2228bea..00000000
--- a/ext/gnomevfs/gstgnomevfs.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* 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_GNOME_VFS_H__
-#define __GST_GNOME_VFS_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GNOME_VFS_URI (gst_gnome_vfs_uri_get_type ())
-#define GST_TYPE_GNOME_VFS_HANDLE (gst_gnome_vfs_handle_get_type ())
-
-GType gst_gnome_vfs_uri_get_type (void);
-GType gst_gnome_vfs_handle_get_type (void);
-
-gchar * gst_gnome_vfs_location_to_uri_string (const gchar * location);
-
-G_END_DECLS
-
-#endif /* __GST_GNOME_VFS_H__ */
diff --git a/ext/gnomevfs/gstgnomevfssink.c b/ext/gnomevfs/gstgnomevfssink.c
deleted file mode 100644
index 431c9fda..00000000
--- a/ext/gnomevfs/gstgnomevfssink.c
+++ /dev/null
@@ -1,632 +0,0 @@
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2001 Bastien Nocera <hadess@hadess.net>
- * 2003 Colin Walters <walters@verbum.org>
- * 2005 Tim-Philipp Müller <tim centricular net>
- *
- * gstgnomevfssink.c:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-gnomevfssink
- * @see_also: #GstFileSink, #GstGnomeVFSSrc
- *
- * This plugin writes incoming data to a local or remote location specified
- * by an URI. This location can be specified using any protocol supported by
- * the GnomeVFS library. Common protocols are 'file', 'ftp', or 'smb'.
- *
- * Applications can connect to the #GstGnomeVFSSink::allow-overwrite signal to
- * receive a callback when an existing file will be overwritten. The return
- * value of the signal will determine if gnomevfssink will overwrite the
- * resource or abort with an error.
- *
- * <refsect2>
- * <title>Example launch lines</title>
- * |[
- * gst-launch -v filesrc location=input.xyz ! gnomevfssink location=file:///home/joe/out.xyz
- * ]| The above pipeline will simply copy a local file. Instead of gnomevfssink,
- * we could just as well have used the filesink element here.
- * |[
- * gst-launch -v filesrc location=foo.mp3 ! mad ! flacenc ! gnomevfssink location=smb://othercomputer/foo.flac
- * ]| The above pipeline will re-encode an mp3 file into FLAC format and store
- * it on a remote host using the Samba protocol.
- * </refsect2>
- *
- * Last reviewed on 2006-02-28 (0.10.4)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstgnomevfssink.h"
-
-#include "gst/gst-i18n-plugin.h"
-
-#include <gst/gst.h>
-#include <libgnomevfs/gnome-vfs.h>
-#include <string.h>
-#include <errno.h>
-
-static const GstElementDetails gst_gnome_vfs_sink_details =
-GST_ELEMENT_DETAILS ("GnomeVFS Sink",
- "Sink/File",
- "Write a stream to a GnomeVFS URI",
- "Bastien Nocera <hadess@hadess.net>");
-
-enum
-{
- SIGNAL_ERASE_ASK,
- LAST_SIGNAL
-};
-
-enum
-{
- ARG_0,
- ARG_LOCATION,
- ARG_URI,
- ARG_HANDLE
-};
-
-static void gst_gnome_vfs_sink_finalize (GObject * obj);
-
-static void gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface,
- gpointer iface_data);
-
-static void gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static gboolean gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink);
-static void gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink);
-static gboolean gst_gnome_vfs_sink_start (GstBaseSink * basesink);
-static gboolean gst_gnome_vfs_sink_stop (GstBaseSink * basesink);
-static GstFlowReturn gst_gnome_vfs_sink_render (GstBaseSink * basesink,
- GstBuffer * buffer);
-static gboolean gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink,
- GstEvent * event);
-static gboolean gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query);
-
-static guint gst_gnome_vfs_sink_signals[LAST_SIGNAL]; /* all 0 */
-
-static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
-GST_DEBUG_CATEGORY_STATIC (gst_gnome_vfs_sink_debug);
-#define GST_CAT_DEFAULT gst_gnome_vfs_sink_debug
-
-static void
-gst_gnome_vfs_sink_do_init (GType type)
-{
- static const GInterfaceInfo urihandler_info = {
- gst_gnome_vfs_sink_uri_handler_init,
- NULL,
- NULL
- };
-
- g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
-
- GST_DEBUG_CATEGORY_INIT (gst_gnome_vfs_sink_debug, "gnomevfssink", 0,
- "Gnome VFS sink element");
-}
-
-GST_BOILERPLATE_FULL (GstGnomeVFSSink, gst_gnome_vfs_sink, GstBaseSink,
- GST_TYPE_BASE_SINK, gst_gnome_vfs_sink_do_init);
-
-static void
-gst_gnome_vfs_sink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sinktemplate));
-
- gst_element_class_set_details (element_class, &gst_gnome_vfs_sink_details);
-}
-
-static gboolean
-_gst_boolean_allow_overwrite_accumulator (GSignalInvocationHint * ihint,
- GValue * return_accu, const GValue * handler_return, gpointer dummy)
-{
- gboolean allow_overwrite;
-
- allow_overwrite = g_value_get_boolean (handler_return);
- if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
- g_value_set_boolean (return_accu, allow_overwrite);
-
- /* stop emission if signal doesn't allow overwriting */
- return allow_overwrite;
-}
-
-static void
-gst_gnome_vfs_sink_class_init (GstGnomeVFSSinkClass * klass)
-{
- GstBaseSinkClass *basesink_class;
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
- basesink_class = (GstBaseSinkClass *) klass;
-
- gobject_class->set_property = gst_gnome_vfs_sink_set_property;
- gobject_class->get_property = gst_gnome_vfs_sink_get_property;
- gobject_class->finalize = gst_gnome_vfs_sink_finalize;
-
- g_object_class_install_property (gobject_class, ARG_LOCATION,
- g_param_spec_string ("location", "File Location",
- "Location of the file to write", NULL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_URI,
- g_param_spec_boxed ("uri", "GnomeVFSURI", "URI for GnomeVFS",
- GST_TYPE_GNOME_VFS_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_HANDLE,
- g_param_spec_boxed ("handle", "GnomeVFSHandle", "Handle for GnomeVFS",
- GST_TYPE_GNOME_VFS_HANDLE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstGnomeVFSSink::allow-overwrite
- * @sink: the object which received the signal
- * @uri: the URI to be overwritten
- *
- * This signal is fired when gnomevfssink is about to overwrite an
- * existing resource. The application can connect to this signal and ask
- * the user if the resource may be overwritten.
- *
- * Returns: A boolean indicating that the resource may be overwritten.
- */
- gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK] =
- g_signal_new ("allow-overwrite", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_CLEANUP, G_STRUCT_OFFSET (GstGnomeVFSSinkClass, erase_ask),
- _gst_boolean_allow_overwrite_accumulator, NULL,
- gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_GNOME_VFS_URI);
-
- basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_stop);
- basesink_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_start);
- basesink_class->event = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_handle_event);
- basesink_class->render = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_render);
- basesink_class->get_times = NULL;
-}
-
-static void
-gst_gnome_vfs_sink_finalize (GObject * obj)
-{
- GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (obj);
-
- if (sink->uri) {
- gnome_vfs_uri_unref (sink->uri);
- sink->uri = NULL;
- }
-
- if (sink->uri_name) {
- g_free (sink->uri_name);
- sink->uri_name = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-static void
-gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass)
-{
- gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
- GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query));
-
- sink->uri = NULL;
- sink->uri_name = NULL;
- sink->handle = NULL;
- sink->own_handle = FALSE;
- sink->current_pos = 0;
-
- GST_BASE_SINK (sink)->sync = FALSE;
-}
-
-static void
-gst_gnome_vfs_sink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstGnomeVFSSink *sink;
- GstState cur_state;
-
- sink = GST_GNOME_VFS_SINK (object);
-
- gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
-
- if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) {
- GST_WARNING_OBJECT (sink, "cannot set property when PAUSED or PLAYING");
- return;
- }
-
- GST_OBJECT_LOCK (sink);
-
- switch (prop_id) {
- case ARG_LOCATION:{
- const gchar *new_location;
-
- if (sink->uri) {
- gnome_vfs_uri_unref (sink->uri);
- sink->uri = NULL;
- }
- if (sink->uri_name) {
- g_free (sink->uri_name);
- sink->uri_name = NULL;
- }
-
- new_location = g_value_get_string (value);
- if (new_location) {
- sink->uri_name = gst_gnome_vfs_location_to_uri_string (new_location);
- sink->uri = gnome_vfs_uri_new (sink->uri_name);
- }
- break;
- }
- case ARG_URI:{
- if (sink->uri) {
- gnome_vfs_uri_unref (sink->uri);
- sink->uri = NULL;
- }
- if (sink->uri_name) {
- g_free (sink->uri_name);
- sink->uri_name = NULL;
- }
- if (g_value_get_boxed (value)) {
- sink->uri = (GnomeVFSURI *) g_value_dup_boxed (value);
- sink->uri_name = gnome_vfs_uri_to_string (sink->uri, 0);
- }
- break;
- }
- case ARG_HANDLE:{
- if (sink->uri) {
- gnome_vfs_uri_unref (sink->uri);
- sink->uri = NULL;
- }
- if (sink->uri_name) {
- g_free (sink->uri_name);
- sink->uri_name = NULL;
- }
- sink->handle = g_value_get_boxed (value);
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- GST_OBJECT_UNLOCK (sink);
-}
-
-static void
-gst_gnome_vfs_sink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstGnomeVFSSink *sink;
-
- sink = GST_GNOME_VFS_SINK (object);
-
- GST_OBJECT_LOCK (sink);
-
- switch (prop_id) {
- case ARG_LOCATION:
- g_value_set_string (value, sink->uri_name);
- break;
- case ARG_URI:
- g_value_set_boxed (value, sink->uri);
- break;
- case ARG_HANDLE:
- g_value_set_boxed (value, sink->handle);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- GST_OBJECT_UNLOCK (sink);
-}
-
-static gboolean
-gst_gnome_vfs_sink_open_file (GstGnomeVFSSink * sink)
-{
- GnomeVFSResult result;
-
- if (sink->uri) {
- /* open the file, all permissions, umask will apply */
- result = gnome_vfs_create_uri (&(sink->handle), sink->uri,
- GNOME_VFS_OPEN_WRITE, TRUE,
- GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE |
- GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE |
- GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE);
-
- /* if the file existed and the property says to ask, then ask! */
- if (result == GNOME_VFS_ERROR_FILE_EXISTS) {
- gboolean erase_anyway = FALSE;
-
- g_signal_emit (G_OBJECT (sink),
- gst_gnome_vfs_sink_signals[SIGNAL_ERASE_ASK], 0, sink->uri,
- &erase_anyway);
- if (erase_anyway) {
- result = gnome_vfs_create_uri (&(sink->handle), sink->uri,
- GNOME_VFS_OPEN_WRITE, FALSE,
- GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_USER_WRITE |
- GNOME_VFS_PERM_GROUP_READ | GNOME_VFS_PERM_GROUP_WRITE |
- GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_OTHER_WRITE);
- }
- }
-
- GST_DEBUG_OBJECT (sink, "open: %s", gnome_vfs_result_to_string (result));
-
- if (result != GNOME_VFS_OK) {
- gchar *filename = gnome_vfs_uri_to_string (sink->uri,
- GNOME_VFS_URI_HIDE_PASSWORD);
-
- GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
- (_("Could not open vfs file \"%s\" for writing: %s."),
- filename, gnome_vfs_result_to_string (result)), GST_ERROR_SYSTEM);
- g_free (filename);
- return FALSE;
- }
- sink->own_handle = TRUE;
- } else if (!sink->handle) {
- GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (_("No filename given")),
- (NULL));
- return FALSE;
- } else {
- sink->own_handle = FALSE;
- }
-
- sink->current_pos = 0;
-
- return TRUE;
-}
-
-static void
-gst_gnome_vfs_sink_close_file (GstGnomeVFSSink * sink)
-{
- GnomeVFSResult result;
-
- if (sink->own_handle) {
- /* close the file */
- result = gnome_vfs_close (sink->handle);
-
- if (result != GNOME_VFS_OK) {
- gchar *filename = gnome_vfs_uri_to_string (sink->uri,
- GNOME_VFS_URI_HIDE_PASSWORD);
-
- GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
- (_("Could not close vfs file \"%s\"."), filename), GST_ERROR_SYSTEM);
- g_free (filename);
- }
-
- sink->own_handle = FALSE;
- sink->handle = NULL;
- }
-}
-
-static gboolean
-gst_gnome_vfs_sink_start (GstBaseSink * basesink)
-{
- gboolean ret;
-
- ret = gst_gnome_vfs_sink_open_file (GST_GNOME_VFS_SINK (basesink));
-
- return ret;
-}
-
-static gboolean
-gst_gnome_vfs_sink_stop (GstBaseSink * basesink)
-{
- GST_DEBUG_OBJECT (basesink, "closing ...");
- gst_gnome_vfs_sink_close_file (GST_GNOME_VFS_SINK (basesink));
- return TRUE;
-}
-
-static gboolean
-gst_gnome_vfs_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
-{
- GstGnomeVFSSink *sink;
- gboolean ret = TRUE;
-
- sink = GST_GNOME_VFS_SINK (basesink);
-
- GST_DEBUG_OBJECT (sink, "processing %s event", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:{
- GnomeVFSResult res;
- GstFormat format;
- gint64 offset;
-
- gst_event_parse_new_segment (event, NULL, NULL, &format, &offset,
- NULL, NULL);
-
- if (format != GST_FORMAT_BYTES) {
- GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format",
- gst_format_get_name (format));
- break;
- }
-
- GST_LOG_OBJECT (sink, "seeking to offset %" G_GINT64_FORMAT, offset);
- res = gnome_vfs_seek (sink->handle, GNOME_VFS_SEEK_START, offset);
-
- if (res != GNOME_VFS_OK) {
- GST_ERROR_OBJECT (sink, "Failed to seek to offset %"
- G_GINT64_FORMAT ": %s", offset, gnome_vfs_result_to_string (res));
- ret = FALSE;
- } else {
- sink->current_pos = offset;
- }
-
- break;
- }
-
- case GST_EVENT_FLUSH_START:
- case GST_EVENT_EOS:{
- /* No need to flush with GnomeVfs */
- break;
- }
- default:
- break;
- }
-
- return ret;
-}
-
-static gboolean
-gst_gnome_vfs_sink_query (GstPad * pad, GstQuery * query)
-{
- GstGnomeVFSSink *sink;
- GstFormat format;
-
- sink = GST_GNOME_VFS_SINK (GST_PAD_PARENT (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- gst_query_parse_position (query, &format, NULL);
- switch (format) {
- case GST_FORMAT_DEFAULT:
- case GST_FORMAT_BYTES:
- gst_query_set_position (query, GST_FORMAT_BYTES, sink->current_pos);
- return TRUE;
- default:
- return FALSE;
- }
-
- case GST_QUERY_FORMATS:
- gst_query_set_formats (query, 2, GST_FORMAT_DEFAULT, GST_FORMAT_BYTES);
- return TRUE;
-
- case GST_QUERY_URI:
- gst_query_set_uri (query, sink->uri_name);
- return TRUE;
-
- default:
- return gst_pad_query_default (pad, query);
- }
-}
-
-static GstFlowReturn
-gst_gnome_vfs_sink_render (GstBaseSink * basesink, GstBuffer * buf)
-{
- GnomeVFSFileSize written, cur_pos;
- GstGnomeVFSSink *sink;
- GnomeVFSResult result;
- GstFlowReturn ret;
-
- sink = GST_GNOME_VFS_SINK (basesink);
-
- if (gnome_vfs_tell (sink->handle, &cur_pos) == GNOME_VFS_OK) {
- /* bring up to date with current position for proper reporting */
- sink->current_pos = cur_pos;
- }
-
- result = gnome_vfs_write (sink->handle, GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf), &written);
-
- switch (result) {
- case GNOME_VFS_OK:{
- GST_DEBUG_OBJECT (sink, "wrote %" G_GINT64_FORMAT " bytes at %"
- G_GINT64_FORMAT, (gint64) written, (gint64) cur_pos);
-
- if (written < GST_BUFFER_SIZE (buf)) {
- /* FIXME: what to do here? (tpm) */
- g_warning ("%s: %d bytes should be written, only %"
- G_GUINT64_FORMAT " bytes written", G_STRLOC,
- GST_BUFFER_SIZE (buf), written);
- }
-
- sink->current_pos += GST_BUFFER_SIZE (buf);
- ret = GST_FLOW_OK;
- break;
- }
- case GNOME_VFS_ERROR_NO_SPACE:{
- /* TODO: emit signal/send msg on out-of-diskspace and
- * handle this gracefully (see open bug) (tpm) */
- GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL),
- ("bufsize=%u, written=%u", GST_BUFFER_SIZE (buf), (guint) written));
- ret = GST_FLOW_ERROR;
- break;
- }
- default:{
- gchar *filename = gnome_vfs_uri_to_string (sink->uri,
- GNOME_VFS_URI_HIDE_PASSWORD);
-
- GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
- (_("Error while writing to file \"%s\"."), filename),
- ("%s, bufsize=%u, written=%u", gnome_vfs_result_to_string (result),
- GST_BUFFER_SIZE (buf), (guint) written));
-
- g_free (filename);
- ret = GST_FLOW_ERROR;
- break;
- }
- }
-
- return GST_FLOW_OK;
-}
-
-/*** GSTURIHANDLER INTERFACE *************************************************/
-
-static GstURIType
-gst_gnome_vfs_sink_uri_get_type (void)
-{
- return GST_URI_SINK;
-}
-
-static gchar **
-gst_gnome_vfs_sink_uri_get_protocols (void)
-{
- return gst_gnomevfs_get_supported_uris ();
-}
-
-static const gchar *
-gst_gnome_vfs_sink_uri_get_uri (GstURIHandler * handler)
-{
- GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler);
-
- return sink->uri_name;
-}
-
-static gboolean
-gst_gnome_vfs_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
-{
- GstGnomeVFSSink *sink = GST_GNOME_VFS_SINK (handler);
- GstState cur_state;
-
- gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0);
-
- if (cur_state == GST_STATE_PLAYING || cur_state == GST_STATE_PAUSED) {
- GST_WARNING_OBJECT (sink, "cannot set uri when PAUSED or PLAYING");
- return FALSE;
- }
-
- g_object_set (sink, "location", uri, NULL);
-
- return TRUE;
-}
-
-static void
-gst_gnome_vfs_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
-{
- GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
-
- iface->get_type = gst_gnome_vfs_sink_uri_get_type;
- iface->get_protocols = gst_gnome_vfs_sink_uri_get_protocols;
- iface->get_uri = gst_gnome_vfs_sink_uri_get_uri;
- iface->set_uri = gst_gnome_vfs_sink_uri_set_uri;
-}
diff --git a/ext/gnomevfs/gstgnomevfssink.h b/ext/gnomevfs/gstgnomevfssink.h
deleted file mode 100644
index 409add96..00000000
--- a/ext/gnomevfs/gstgnomevfssink.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2001 Bastien Nocera <hadess@hadess.net>
- * 2003 Colin Walters <walters@verbum.org>
- * 2005 Tim-Philipp Müller <tim centricular net>
- *
- * 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_GNOME_VFS_SINK_H__
-#define __GST_GNOME_VFS_SINK_H__
-
-#include "gstgnomevfs.h"
-#include "gstgnomevfsuri.h"
-#include <gst/base/gstbasesink.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GNOME_VFS_SINK \
- (gst_gnome_vfs_sink_get_type())
-#define GST_GNOME_VFS_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GNOME_VFS_SINK,GstGnomeVFSSink))
-#define GST_GNOME_VFS_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GNOME_VFS_SINK,GstGnomeVFSSinkClass))
-#define GST_IS_GNOME_VFS_SINK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GNOME_VFS_SINK))
-#define GST_IS_GNOME_VFS_SINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GNOME_VFS_SINK))
-
-typedef struct _GstGnomeVFSSink GstGnomeVFSSink;
-typedef struct _GstGnomeVFSSinkClass GstGnomeVFSSinkClass;
-
-/**
- * GstGnomeVFSSink:
- *
- * Opaque data structure.
- */
-struct _GstGnomeVFSSink
-{
- GstBaseSink basesink;
-
- /*< private >*/
-
- /* uri */
- GnomeVFSURI *uri;
- gchar *uri_name;
-
- /* handle */
- GnomeVFSHandle *handle;
-
- /* whether we opened the handle ourselves */
- gboolean own_handle;
-
- guint64 current_pos;
-};
-
-struct _GstGnomeVFSSinkClass
-{
- GstBaseSinkClass basesink_class;
-
- /* signals */
- gboolean (*erase_ask) (GstElement * element, GnomeVFSURI * uri);
-};
-
-GType gst_gnome_vfs_sink_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_GNOME_VFS_SINK_H__ */
-
diff --git a/ext/gnomevfs/gstgnomevfssrc.c b/ext/gnomevfs/gstgnomevfssrc.c
deleted file mode 100644
index cf26b30e..00000000
--- a/ext/gnomevfs/gstgnomevfssrc.c
+++ /dev/null
@@ -1,897 +0,0 @@
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2001 Bastien Nocera <hadess@hadess.net>
- * 2002 Kristian Rietveld <kris@gtk.org>
- * 2002,2003 Colin Walters <walters@gnu.org>
- *
- * gnomevfssrc.c:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-gnomevfssrc
- * @see_also: #GstFileSrc, #GstGnomeVFSSink
- *
- * This plugin reads data from a local or remote location specified
- * by an URI. This location can be specified using any protocol supported by
- * the GnomeVFS library. Common protocols are 'file', 'http', 'ftp', or 'smb'.
- *
- * In case the #GstGnomeVFSSrc:iradio-mode property is set and the
- * location is a http resource, gnomevfssrc will send special icecast http
- * headers to the server to request additional icecast metainformation. If
- * the server is not an icecast server, it will display the same behaviour
- * as if the #GstGnomeVFSSrc:iradio-mode property was not set. However,
- * if the server is in fact an icecast server, gnomevfssrc will output
- * data with a media type of application/x-icy, in which case you will
- * need to use the #GstICYDemux element as follow-up element to extract
- * the icecast meta data and to determine the underlying media type.
- *
- * <refsect2>
- * <title>Example launch lines</title>
- * |[
- * gst-launch -v gnomevfssrc location=file:///home/joe/foo.xyz ! fakesink
- * ]| The above pipeline will simply read a local file and do nothing with the
- * data read. Instead of gnomevfssrc, we could just as well have used the
- * filesrc element here.
- * |[
- * gst-launch -v gnomevfssrc location=smb://othercomputer/foo.xyz ! filesink location=/home/joe/foo.xyz
- * ]| The above pipeline will copy a file from a remote host to the local file
- * system using the Samba protocol.
- * |[
- * gst-launch -v gnomevfssrc location=http://music.foobar.com/demo.mp3 ! mad ! audioconvert ! audioresample ! alsasink
- * ]| The above pipeline will read and decode and play an mp3 file from a
- * web server using the http protocol.
- * </refsect2>
- */
-
-
-#define BROKEN_SIG 1
-/*#undef BROKEN_SIG */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gst/gst-i18n-plugin.h"
-
-#include "gstgnomevfssrc.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <string.h>
-
-#include <gst/gst.h>
-#include <gst/tag/tag.h>
-
-/* gnome-vfs.h doesn't include the following header, which we need: */
-#include <libgnomevfs/gnome-vfs-standard-callbacks.h>
-
-GST_DEBUG_CATEGORY_STATIC (gnomevfssrc_debug);
-#define GST_CAT_DEFAULT gnomevfssrc_debug
-
-static const GstElementDetails gst_gnome_vfs_src_details =
-GST_ELEMENT_DETAILS ("GnomeVFS Source",
- "Source/File",
- "Read from any GnomeVFS-supported file",
- "Bastien Nocera <hadess@hadess.net>\n"
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-
-static GStaticMutex count_lock = G_STATIC_MUTEX_INIT;
-static gint ref_count = 0;
-static gboolean vfs_owner = FALSE;
-
-static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
-
-enum
-{
- ARG_0,
- ARG_HANDLE,
- ARG_LOCATION,
- ARG_IRADIO_MODE,
- ARG_IRADIO_NAME,
- ARG_IRADIO_GENRE,
- ARG_IRADIO_URL,
- ARG_IRADIO_TITLE
-};
-
-static void gst_gnome_vfs_src_base_init (gpointer g_class);
-static void gst_gnome_vfs_src_class_init (GstGnomeVFSSrcClass * klass);
-static void gst_gnome_vfs_src_init (GstGnomeVFSSrc * gnomevfssrc);
-static void gst_gnome_vfs_src_finalize (GObject * object);
-static void gst_gnome_vfs_src_uri_handler_init (gpointer g_iface,
- gpointer iface_data);
-
-static void gst_gnome_vfs_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_gnome_vfs_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static gboolean gst_gnome_vfs_src_stop (GstBaseSrc * src);
-static gboolean gst_gnome_vfs_src_start (GstBaseSrc * src);
-static gboolean gst_gnome_vfs_src_is_seekable (GstBaseSrc * src);
-static gboolean gst_gnome_vfs_src_check_get_range (GstBaseSrc * src);
-static gboolean gst_gnome_vfs_src_get_size (GstBaseSrc * src, guint64 * size);
-static GstFlowReturn gst_gnome_vfs_src_create (GstBaseSrc * basesrc,
- guint64 offset, guint size, GstBuffer ** buffer);
-static gboolean gst_gnome_vfs_src_query (GstBaseSrc * src, GstQuery * query);
-
-static GstElementClass *parent_class = NULL;
-
-GType
-gst_gnome_vfs_src_get_type (void)
-{
- static GType gnomevfssrc_type = 0;
-
- if (!gnomevfssrc_type) {
- static const GTypeInfo gnomevfssrc_info = {
- sizeof (GstGnomeVFSSrcClass),
- gst_gnome_vfs_src_base_init,
- NULL,
- (GClassInitFunc) gst_gnome_vfs_src_class_init,
- NULL,
- NULL,
- sizeof (GstGnomeVFSSrc),
- 0,
- (GInstanceInitFunc) gst_gnome_vfs_src_init,
- };
- static const GInterfaceInfo urihandler_info = {
- gst_gnome_vfs_src_uri_handler_init,
- NULL,
- NULL
- };
-
- gnomevfssrc_type =
- g_type_register_static (GST_TYPE_BASE_SRC,
- "GstGnomeVFSSrc", &gnomevfssrc_info, 0);
- g_type_add_interface_static (gnomevfssrc_type, GST_TYPE_URI_HANDLER,
- &urihandler_info);
- }
- return gnomevfssrc_type;
-}
-
-static void
-gst_gnome_vfs_src_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&srctemplate));
- gst_element_class_set_details (element_class, &gst_gnome_vfs_src_details);
-
- GST_DEBUG_CATEGORY_INIT (gnomevfssrc_debug, "gnomevfssrc", 0,
- "Gnome-VFS Source");
-}
-
-static void
-gst_gnome_vfs_src_class_init (GstGnomeVFSSrcClass * klass)
-{
- GObjectClass *gobject_class;
- GstBaseSrcClass *gstbasesrc_class;
-
- gobject_class = G_OBJECT_CLASS (klass);
- gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->finalize = gst_gnome_vfs_src_finalize;
- gobject_class->set_property = gst_gnome_vfs_src_set_property;
- gobject_class->get_property = gst_gnome_vfs_src_get_property;
-
- /* properties */
- gst_element_class_install_std_props (GST_ELEMENT_CLASS (klass),
- "location", ARG_LOCATION, G_PARAM_READWRITE, NULL);
- g_object_class_install_property (gobject_class,
- ARG_HANDLE,
- g_param_spec_boxed ("handle",
- "GnomeVFSHandle", "Handle for GnomeVFS",
- GST_TYPE_GNOME_VFS_HANDLE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /* icecast stuff */
- g_object_class_install_property (gobject_class,
- ARG_IRADIO_MODE,
- g_param_spec_boolean ("iradio-mode",
- "iradio-mode",
- "Enable internet radio mode (extraction of shoutcast/icecast metadata)",
- FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class,
- ARG_IRADIO_NAME,
- g_param_spec_string ("iradio-name",
- "iradio-name", "Name of the stream", NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_IRADIO_GENRE,
- g_param_spec_string ("iradio-genre", "iradio-genre",
- "Genre of the stream", NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_IRADIO_URL,
- g_param_spec_string ("iradio-url", "iradio-url",
- "Homepage URL for radio stream", NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_IRADIO_TITLE,
- g_param_spec_string ("iradio-title", "iradio-title",
- "Name of currently playing song", NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_start);
- gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_stop);
- gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_get_size);
- gstbasesrc_class->is_seekable =
- GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_is_seekable);
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_check_get_range);
- gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_create);
- gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_query);
-}
-
-static void
-gst_gnome_vfs_src_init (GstGnomeVFSSrc * gnomevfssrc)
-{
- gnomevfssrc->uri = NULL;
- gnomevfssrc->uri_name = NULL;
- gnomevfssrc->handle = NULL;
- gnomevfssrc->curoffset = 0;
- gnomevfssrc->seekable = FALSE;
-
- gnomevfssrc->iradio_mode = FALSE;
- gnomevfssrc->http_callbacks_pushed = FALSE;
- gnomevfssrc->iradio_name = NULL;
- gnomevfssrc->iradio_genre = NULL;
- gnomevfssrc->iradio_url = NULL;
- gnomevfssrc->iradio_title = NULL;
-
- g_static_mutex_lock (&count_lock);
- if (ref_count == 0) {
- /* gnome vfs engine init */
- if (gnome_vfs_initialized () == FALSE) {
- gnome_vfs_init ();
- vfs_owner = TRUE;
- }
- }
- ref_count++;
- g_static_mutex_unlock (&count_lock);
-}
-
-static void
-gst_gnome_vfs_src_finalize (GObject * object)
-{
- GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (object);
-
- g_static_mutex_lock (&count_lock);
- ref_count--;
- if (ref_count == 0 && vfs_owner) {
- if (gnome_vfs_initialized () == TRUE) {
- gnome_vfs_shutdown ();
- }
- }
- g_static_mutex_unlock (&count_lock);
-
- if (src->uri) {
- gnome_vfs_uri_unref (src->uri);
- src->uri = NULL;
- }
-
- g_free (src->uri_name);
- src->uri_name = NULL;
-
- g_free (src->iradio_name);
- src->iradio_name = NULL;
-
- g_free (src->iradio_genre);
- src->iradio_genre = NULL;
-
- g_free (src->iradio_url);
- src->iradio_url = NULL;
-
- g_free (src->iradio_title);
- src->iradio_title = NULL;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-/*
- * URI interface support.
- */
-
-static GstURIType
-gst_gnome_vfs_src_uri_get_type (void)
-{
- return GST_URI_SRC;
-}
-
-static gchar **
-gst_gnome_vfs_src_uri_get_protocols (void)
-{
- return gst_gnomevfs_get_supported_uris ();
-}
-
-static const gchar *
-gst_gnome_vfs_src_uri_get_uri (GstURIHandler * handler)
-{
- GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (handler);
-
- return src->uri_name;
-}
-
-static gboolean
-gst_gnome_vfs_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
-{
- GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (handler);
-
- if (GST_STATE (src) == GST_STATE_PLAYING ||
- GST_STATE (src) == GST_STATE_PAUSED)
- return FALSE;
-
- g_object_set (G_OBJECT (src), "location", uri, NULL);
-
- return TRUE;
-}
-
-static void
-gst_gnome_vfs_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
-{
- GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
-
- iface->get_type = gst_gnome_vfs_src_uri_get_type;
- iface->get_protocols = gst_gnome_vfs_src_uri_get_protocols;
- iface->get_uri = gst_gnome_vfs_src_uri_get_uri;
- iface->set_uri = gst_gnome_vfs_src_uri_set_uri;
-}
-
-static void
-gst_gnome_vfs_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstGnomeVFSSrc *src;
-
- src = GST_GNOME_VFS_SRC (object);
-
- switch (prop_id) {
- case ARG_LOCATION:{
- const gchar *new_location;
-
- /* the element must be stopped or paused in order to do this */
- if (GST_STATE (src) == GST_STATE_PLAYING ||
- GST_STATE (src) == GST_STATE_PAUSED)
- break;
-
- if (src->uri) {
- gnome_vfs_uri_unref (src->uri);
- src->uri = NULL;
- }
- if (src->uri_name) {
- g_free (src->uri_name);
- src->uri_name = NULL;
- }
-
- new_location = g_value_get_string (value);
- if (new_location) {
- src->uri_name = gst_gnome_vfs_location_to_uri_string (new_location);
- src->uri = gnome_vfs_uri_new (src->uri_name);
- }
- break;
- }
- case ARG_HANDLE:
- if (GST_STATE (src) == GST_STATE_NULL ||
- GST_STATE (src) == GST_STATE_READY) {
- if (src->uri) {
- gnome_vfs_uri_unref (src->uri);
- src->uri = NULL;
- }
- if (src->uri_name) {
- g_free (src->uri_name);
- src->uri_name = NULL;
- }
- src->handle = g_value_get_boxed (value);
- }
- break;
- case ARG_IRADIO_MODE:
- src->iradio_mode = g_value_get_boolean (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_gnome_vfs_src_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstGnomeVFSSrc *src;
-
- src = GST_GNOME_VFS_SRC (object);
-
- switch (prop_id) {
- case ARG_LOCATION:
- g_value_set_string (value, src->uri_name);
- break;
- case ARG_HANDLE:
- g_value_set_boxed (value, src->handle);
- break;
- case ARG_IRADIO_MODE:
- g_value_set_boolean (value, src->iradio_mode);
- break;
- case ARG_IRADIO_NAME:
- g_value_set_string (value, src->iradio_name);
- break;
- case ARG_IRADIO_GENRE:
- g_value_set_string (value, src->iradio_genre);
- break;
- case ARG_IRADIO_URL:
- g_value_set_string (value, src->iradio_url);
- break;
- case ARG_IRADIO_TITLE:
- g_value_set_string (value, src->iradio_title);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static char *
-gst_gnome_vfs_src_unicodify (const char *str)
-{
- const gchar *env_vars[] = { "GST_ICY_TAG_ENCODING",
- "GST_TAG_ENCODING", NULL
- };
-
- return gst_tag_freeform_string_to_utf8 (str, -1, env_vars);
-}
-
-static void
-gst_gnome_vfs_src_send_additional_headers_callback (gconstpointer in,
- gsize in_size, gpointer out, gsize out_size, gpointer callback_data)
-{
- GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (callback_data);
- GnomeVFSModuleCallbackAdditionalHeadersOut *out_args =
- (GnomeVFSModuleCallbackAdditionalHeadersOut *) out;
-
- if (!src->iradio_mode)
- return;
- GST_DEBUG_OBJECT (src, "sending headers\n");
-
- out_args->headers = g_list_append (out_args->headers,
- g_strdup ("icy-metadata:1\r\n"));
-}
-
-static void
-gst_gnome_vfs_src_received_headers_callback (gconstpointer in,
- gsize in_size, gpointer out, gsize out_size, gpointer callback_data)
-{
- GList *i;
- gint icy_metaint;
- GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (callback_data);
- GnomeVFSModuleCallbackReceivedHeadersIn *in_args =
- (GnomeVFSModuleCallbackReceivedHeadersIn *) in;
-
- /* This is only used for internet radio stuff right now */
- if (!src->iradio_mode)
- return;
-
- GST_DEBUG_OBJECT (src, "receiving internet radio metadata\n");
-
- /* FIXME: Could we use "Accept-Ranges: bytes"
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.5
- * to enable pull-mode?
- */
-
- for (i = in_args->headers; i; i = i->next) {
- char *data = (char *) i->data;
- char *key = data;
- char *value = strchr (data, ':');
-
- if (!value)
- continue;
-
- value++;
- g_strstrip (value);
- if (!strlen (value))
- continue;
-
- GST_LOG_OBJECT (src, "data %s", data);
-
- /* Icecast stuff */
- if (strncmp (data, "icy-metaint:", 12) == 0) { /* ugh */
- if (sscanf (data + 12, "%d", &icy_metaint) == 1) {
- if (icy_metaint > 0) {
- GstCaps *icy_caps;
-
- icy_caps = gst_caps_new_simple ("application/x-icy",
- "metadata-interval", G_TYPE_INT, icy_metaint, NULL);
- gst_pad_set_caps (GST_BASE_SRC_PAD (src), icy_caps);
- gst_caps_unref (icy_caps);
- }
- }
- continue;
- }
-
- if (!strncmp (data, "icy-", 4))
- key = data + 4;
- else
- continue;
-
- GST_DEBUG_OBJECT (src, "key: %s", key);
- if (!strncmp (key, "name", 4)) {
- g_free (src->iradio_name);
- src->iradio_name = gst_gnome_vfs_src_unicodify (value);
- if (src->iradio_name)
- g_object_notify (G_OBJECT (src), "iradio-name");
- } else if (!strncmp (key, "genre", 5)) {
- g_free (src->iradio_genre);
- src->iradio_genre = gst_gnome_vfs_src_unicodify (value);
- if (src->iradio_genre)
- g_object_notify (G_OBJECT (src), "iradio-genre");
- } else if (!strncmp (key, "url", 3)) {
- g_free (src->iradio_url);
- src->iradio_url = gst_gnome_vfs_src_unicodify (value);
- if (src->iradio_url)
- g_object_notify (G_OBJECT (src), "iradio-url");
- }
- }
-}
-
-static void
-gst_gnome_vfs_src_push_callbacks (GstGnomeVFSSrc * src)
-{
- if (src->http_callbacks_pushed)
- return;
-
- GST_DEBUG_OBJECT (src, "pushing callbacks");
- gnome_vfs_module_callback_push
- (GNOME_VFS_MODULE_CALLBACK_HTTP_SEND_ADDITIONAL_HEADERS,
- gst_gnome_vfs_src_send_additional_headers_callback, src, NULL);
- gnome_vfs_module_callback_push
- (GNOME_VFS_MODULE_CALLBACK_HTTP_RECEIVED_HEADERS,
- gst_gnome_vfs_src_received_headers_callback, src, NULL);
-
- src->http_callbacks_pushed = TRUE;
-}
-
-static void
-gst_gnome_vfs_src_pop_callbacks (GstGnomeVFSSrc * src)
-{
- if (!src->http_callbacks_pushed)
- return;
-
- GST_DEBUG_OBJECT (src, "popping callbacks");
- gnome_vfs_module_callback_pop
- (GNOME_VFS_MODULE_CALLBACK_HTTP_SEND_ADDITIONAL_HEADERS);
- gnome_vfs_module_callback_pop
- (GNOME_VFS_MODULE_CALLBACK_HTTP_RECEIVED_HEADERS);
-
- src->http_callbacks_pushed = FALSE;
-}
-
-/*
- * Read a new buffer from src->reqoffset, takes care of events
- * and seeking and such.
- */
-static GstFlowReturn
-gst_gnome_vfs_src_create (GstBaseSrc * basesrc, guint64 offset, guint size,
- GstBuffer ** buffer)
-{
- GnomeVFSResult res;
- GstBuffer *buf;
- GnomeVFSFileSize readbytes;
- guint8 *data;
- guint todo;
- GstGnomeVFSSrc *src;
-
- src = GST_GNOME_VFS_SRC (basesrc);
-
- GST_DEBUG ("now at %" G_GINT64_FORMAT ", reading from %" G_GUINT64_FORMAT
- ", size %u", src->curoffset, offset, size);
-
- /* seek if required */
- if (G_UNLIKELY (src->curoffset != offset)) {
- GST_DEBUG ("need to seek");
- if (src->seekable) {
- GST_DEBUG ("seeking to %" G_GUINT64_FORMAT, offset);
- res = gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_START, offset);
- if (res != GNOME_VFS_OK)
- goto seek_failed;
- src->curoffset = offset;
- } else {
- goto cannot_seek;
- }
- }
-
- buf = gst_buffer_try_new_and_alloc (size);
- if (G_UNLIKELY (buf == NULL && size == 0)) {
- GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", size);
- return GST_FLOW_ERROR;
- }
-
- data = GST_BUFFER_DATA (buf);
-
- todo = size;
- while (todo > 0) {
- /* this can return less that we ask for */
- res = gnome_vfs_read (src->handle, data, todo, &readbytes);
-
- if (G_UNLIKELY (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK
- && readbytes == 0)))
- goto eos;
-
- if (G_UNLIKELY (res != GNOME_VFS_OK))
- goto read_failed;
-
- if (readbytes < todo) {
- data = &data[readbytes];
- todo -= readbytes;
- } else {
- todo = 0;
- }
- GST_LOG (" got size %" G_GUINT64_FORMAT, readbytes);
- }
- GST_BUFFER_OFFSET (buf) = src->curoffset;
- src->curoffset += size;
-
- /* we're done, return the buffer */
- *buffer = buf;
-
- return GST_FLOW_OK;
-
-seek_failed:
- {
- GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL),
- ("Failed to seek to requested position %" G_GINT64_FORMAT ": %s",
- offset, gnome_vfs_result_to_string (res)));
- return GST_FLOW_ERROR;
- }
-cannot_seek:
- {
- GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL),
- ("Requested seek from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT
- " on non-seekable stream", src->curoffset, offset));
- return GST_FLOW_ERROR;
- }
-read_failed:
- {
- gst_buffer_unref (buf);
- GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
- ("Failed to read data: %s", gnome_vfs_result_to_string (res)));
- return GST_FLOW_ERROR;
- }
-eos:
- {
- gst_buffer_unref (buf);
- GST_DEBUG_OBJECT (src, "Reading data gave EOS");
- return GST_FLOW_UNEXPECTED;
- }
-}
-
-static gboolean
-gst_gnome_vfs_src_query (GstBaseSrc * basesrc, GstQuery * query)
-{
- gboolean ret = FALSE;
- GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (basesrc);
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_URI:
- gst_query_set_uri (query, src->uri_name);
- ret = TRUE;
- break;
- default:
- ret = FALSE;
- break;
- }
-
- if (!ret)
- ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
-
- return ret;
-}
-
-static gboolean
-gst_gnome_vfs_src_is_seekable (GstBaseSrc * basesrc)
-{
- GstGnomeVFSSrc *src;
-
- src = GST_GNOME_VFS_SRC (basesrc);
-
- return src->seekable;
-}
-
-static gboolean
-gst_gnome_vfs_src_check_get_range (GstBaseSrc * basesrc)
-{
- GstGnomeVFSSrc *src;
- const gchar *protocol;
-
- src = GST_GNOME_VFS_SRC (basesrc);
-
- if (src->uri == NULL) {
- GST_WARNING_OBJECT (src, "no URI set yet");
- return FALSE;
- }
-
- if (gnome_vfs_uri_is_local (src->uri)) {
- GST_LOG_OBJECT (src, "local URI (%s), assuming random access is possible",
- GST_STR_NULL (src->uri_name));
- return TRUE;
- }
-
- /* blacklist certain protocols we know won't work getrange-based */
- protocol = gnome_vfs_uri_get_scheme (src->uri);
- if (protocol == NULL)
- goto undecided;
-
- if (strcmp (protocol, "http") == 0 || strcmp (protocol, "https") == 0) {
- GST_LOG_OBJECT (src, "blacklisted protocol '%s', no random access possible"
- " (URI=%s)", protocol, GST_STR_NULL (src->uri_name));
- return FALSE;
- }
-
- /* fall through to undecided */
-
-undecided:
- {
- /* don't know what to do, let the basesrc class decide for us */
- GST_LOG_OBJECT (src, "undecided about URI '%s', let base class handle it",
- GST_STR_NULL (src->uri_name));
-
- if (GST_BASE_SRC_CLASS (parent_class)->check_get_range)
- return GST_BASE_SRC_CLASS (parent_class)->check_get_range (basesrc);
-
- return FALSE;
- }
-}
-
-static gboolean
-gst_gnome_vfs_src_get_size (GstBaseSrc * basesrc, guint64 * size)
-{
- GstGnomeVFSSrc *src;
- GnomeVFSFileInfo *info;
- GnomeVFSFileInfoOptions options;
- GnomeVFSResult res;
-
- src = GST_GNOME_VFS_SRC (basesrc);
-
- *size = -1;
- info = gnome_vfs_file_info_new ();
- options = GNOME_VFS_FILE_INFO_DEFAULT | GNOME_VFS_FILE_INFO_FOLLOW_LINKS;
- res = gnome_vfs_get_file_info_from_handle (src->handle, info, options);
- if (res == GNOME_VFS_OK) {
- if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0) {
- *size = info->size;
- GST_DEBUG_OBJECT (src, "from handle: %" G_GUINT64_FORMAT " bytes", *size);
- } else if (src->own_handle && gnome_vfs_uri_is_local (src->uri)) {
- GST_DEBUG_OBJECT (src,
- "file size not known, file local, trying fallback");
- res = gnome_vfs_get_file_info_uri (src->uri, info, options);
- if (res == GNOME_VFS_OK &&
- (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) != 0) {
- *size = info->size;
- GST_DEBUG_OBJECT (src, "from uri: %" G_GUINT64_FORMAT " bytes", *size);
- }
- }
- } else {
- GST_WARNING_OBJECT (src, "getting info failed: %s",
- gnome_vfs_result_to_string (res));
- }
- gnome_vfs_file_info_unref (info);
-
- if (*size == (GnomeVFSFileSize) - 1)
- return FALSE;
-
- GST_DEBUG_OBJECT (src, "return size %" G_GUINT64_FORMAT, *size);
-
- return TRUE;
-}
-
-/* open the file, do stuff necessary to go to PAUSED state */
-static gboolean
-gst_gnome_vfs_src_start (GstBaseSrc * basesrc)
-{
- GnomeVFSResult res;
- GstGnomeVFSSrc *src;
-
- src = GST_GNOME_VFS_SRC (basesrc);
-
- gst_gnome_vfs_src_push_callbacks (src);
-
- if (src->uri != NULL) {
- GnomeVFSOpenMode mode = GNOME_VFS_OPEN_READ;
-
- /* this can block... */
- res = gnome_vfs_open_uri (&src->handle, src->uri, mode);
- if (res != GNOME_VFS_OK)
- goto open_failed;
- src->own_handle = TRUE;
- } else if (!src->handle) {
- goto no_filename;
- } else {
- src->own_handle = FALSE;
- }
-
- if (gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_CURRENT, 0) == GNOME_VFS_OK) {
- src->seekable = TRUE;
- } else {
- src->seekable = FALSE;
- }
-
- return TRUE;
-
- /* ERRORS */
-open_failed:
- {
- gchar *filename = gnome_vfs_uri_to_string (src->uri,
- GNOME_VFS_URI_HIDE_PASSWORD);
-
- gst_gnome_vfs_src_pop_callbacks (src);
-
- if (res == GNOME_VFS_ERROR_NOT_FOUND ||
- res == GNOME_VFS_ERROR_HOST_NOT_FOUND ||
- res == GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE) {
- GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
- ("Could not open vfs file \"%s\" for reading: %s (%d)",
- filename, gnome_vfs_result_to_string (res), res));
- } else {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
- ("Could not open vfs file \"%s\" for reading: %s (%d)",
- filename, gnome_vfs_result_to_string (res), res));
- }
- g_free (filename);
- return FALSE;
- }
-no_filename:
- {
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("No filename given"));
- return FALSE;
- }
-}
-
-static gboolean
-gst_gnome_vfs_src_stop (GstBaseSrc * basesrc)
-{
- GstGnomeVFSSrc *src;
-
- src = GST_GNOME_VFS_SRC (basesrc);
-
- gst_gnome_vfs_src_pop_callbacks (src);
-
- if (src->own_handle) {
- GnomeVFSResult res;
-
- res = gnome_vfs_close (src->handle);
- if (res != GNOME_VFS_OK) {
- GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, (NULL),
- ("Could not close vfs handle: %s", gnome_vfs_result_to_string (res)));
- }
- src->handle = NULL;
- }
- src->curoffset = 0;
-
- return TRUE;
-}
diff --git a/ext/gnomevfs/gstgnomevfssrc.h b/ext/gnomevfs/gstgnomevfssrc.h
deleted file mode 100644
index 31c1f65c..00000000
--- a/ext/gnomevfs/gstgnomevfssrc.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2001 Bastien Nocera <hadess@hadess.net>
- * 2002 Kristian Rietveld <kris@gtk.org>
- * 2002,2003 Colin Walters <walters@gnu.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GNOME_VFS_SRC_H__
-#define __GST_GNOME_VFS_SRC_H__
-
-#include <gst/base/gstbasesrc.h>
-
-#include "gstgnomevfs.h"
-#include "gstgnomevfsuri.h"
-#include <libgnomevfs/gnome-vfs.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GNOME_VFS_SRC \
- (gst_gnome_vfs_src_get_type())
-#define GST_GNOME_VFS_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GNOME_VFS_SRC,GstGnomeVFSSrc))
-#define GST_GNOME_VFS_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GNOME_VFS_SRC,GstGnomeVFSSrcClass))
-#define GST_IS_GNOME_VFS_SRC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GNOME_VFS_SRC))
-#define GST_IS_GNOME_VFS_SRC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GNOME_VFS_SRC))
-
-typedef struct _GstGnomeVFSSrc GstGnomeVFSSrc;
-typedef struct _GstGnomeVFSSrcClass GstGnomeVFSSrcClass;
-
-/**
- * GstGnomeVFSSrc:
- *
- * Opaque data structure.
- */
-struct _GstGnomeVFSSrc
-{
- GstBaseSrc basesrc;
-
- /* uri, file, ... */
- GnomeVFSURI *uri;
- gchar *uri_name;
- GnomeVFSHandle *handle;
- gboolean own_handle;
- GnomeVFSFileOffset curoffset; /* current offset in file */
- gboolean seekable;
-
- /* shoutcast/icecast metadata extraction handling */
- gboolean iradio_mode;
- gboolean http_callbacks_pushed;
-
- gchar *iradio_name;
- gchar *iradio_genre;
- gchar *iradio_url;
- gchar *iradio_title;
-};
-
-struct _GstGnomeVFSSrcClass
-{
- GstBaseSrcClass basesrc_class;
-};
-
-GType gst_gnome_vfs_src_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_GNOME_VFS_SRC_H__ */
-
-
diff --git a/ext/gnomevfs/gstgnomevfsuri.c b/ext/gnomevfs/gstgnomevfsuri.c
deleted file mode 100644
index e811c31b..00000000
--- a/ext/gnomevfs/gstgnomevfsuri.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2001 Bastien Nocera <hadess@hadess.net>
- * 2003 Colin Walters <walters@verbum.org>
- *
- * gstgnomevfssink.c:
- *
- * 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 <libgnomevfs/gnome-vfs.h>
-#include "gstgnomevfsuri.h"
-
-#include <gst/gst.h>
-
-/* FIXME: move this to source and sink and remove this file:
- * e.g. sinks cannot save to http:// and src cannot read from burn://
- */
-static gpointer
-_internal_get_supported_uris (gpointer data)
-{
- /* no dav/davs in the list, because they don't appear to be reliable enough */
- const gchar *uris[] = {
- "http://localhost/bla",
- "https://localhost/bla",
- "file:///bla",
- "smb://localhost/bla",
- "ftp://localhost/bla",
- "sftp://localhost/bla",
- "nfs://localhost/bla",
- "ssh://localhost/bla",
- "burn://"
- };
- GnomeVFSURI *uri;
- gchar **result;
- gint n, r = 0;
-
- result = g_new0 (gchar *, G_N_ELEMENTS (uris) + 1);
- for (n = 0; n < G_N_ELEMENTS (uris); n++) {
- uri = gnome_vfs_uri_new (uris[n]);
- if (uri != NULL) {
- gchar *protocol = g_strdup (uris[n]);
- gint n;
-
- gnome_vfs_uri_unref (uri);
- for (n = 0; protocol[n] != '\0'; n++) {
- if (protocol[n] == ':') {
- protocol[n] = '\0';
- break;
- }
- }
-
- GST_DEBUG ("adding protocol '%s'", protocol);
- result[r++] = protocol;
- } else {
- GST_DEBUG ("could not create GnomeVfsUri from '%s'", uris[n]);
- }
- }
- result[r] = NULL;
-
- return result;
-}
-
-gchar **
-gst_gnomevfs_get_supported_uris (void)
-{
- static GOnce once = G_ONCE_INIT;
-
- g_once (&once, _internal_get_supported_uris, NULL);
- return (gchar **) once.retval;
-}
diff --git a/ext/gnomevfs/gstgnomevfsuri.h b/ext/gnomevfs/gstgnomevfsuri.h
deleted file mode 100644
index f99b1f7e..00000000
--- a/ext/gnomevfs/gstgnomevfsuri.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 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_GNOME_VFS_URI_H__
-#define __GST_GNOME_VFS_URI_H__
-
-#include <libgnomevfs/gnome-vfs.h>
-
-G_BEGIN_DECLS
-
-gchar **gst_gnomevfs_get_supported_uris (void);
-
-G_END_DECLS
-
-#endif /* __GST_GNOME_VFS_URI_H__ */
diff --git a/ext/libvisual/Makefile.am b/ext/libvisual/Makefile.am
deleted file mode 100644
index d5d02136..00000000
--- a/ext/libvisual/Makefile.am
+++ /dev/null
@@ -1,8 +0,0 @@
-plugin_LTLIBRARIES = libgstlibvisual.la
-
-libgstlibvisual_la_SOURCES = visual.c
-libgstlibvisual_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(LIBVISUAL_CFLAGS)
-libgstlibvisual_la_LIBADD = $(GST_BASE_LIBS) $(LIBVISUAL_LIBS)
-libgstlibvisual_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstlibvisual_la_LIBTOOLFLAGS = --tag=disable-static
-
diff --git a/ext/libvisual/visual.c b/ext/libvisual/visual.c
deleted file mode 100644
index 8e0ef0ea..00000000
--- a/ext/libvisual/visual.c
+++ /dev/null
@@ -1,960 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst.h>
-#include <gst/base/gstadapter.h>
-#include <gst/video/video.h>
-#include <gst/audio/audio.h>
-#include <libvisual/libvisual.h>
-
-#define GST_TYPE_VISUAL (gst_visual_get_type())
-#define GST_IS_VISUAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VISUAL))
-#define GST_VISUAL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VISUAL,GstVisual))
-#define GST_IS_VISUAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VISUAL))
-#define GST_VISUAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VISUAL,GstVisualClass))
-#define GST_VISUAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VISUAL, GstVisualClass))
-
-typedef struct _GstVisual GstVisual;
-typedef struct _GstVisualClass GstVisualClass;
-
-GST_DEBUG_CATEGORY_STATIC (libvisual_debug);
-#define GST_CAT_DEFAULT (libvisual_debug)
-
-struct _GstVisual
-{
- GstElement element;
-
- /* pads */
- GstPad *sinkpad;
- GstPad *srcpad;
- GstSegment segment;
-
- /* libvisual stuff */
- VisAudio *audio;
- VisVideo *video;
- VisActor *actor;
-
- /* audio/video state */
- gint channels;
- gint rate; /* Input samplerate */
- gint bps;
-
- /* framerate numerator & denominator */
- gint fps_n;
- gint fps_d;
- gint width;
- gint height;
- GstClockTime duration;
- guint outsize;
-
- /* samples per frame based on caps */
- guint spf;
-
- /* state stuff */
- GstAdapter *adapter;
- guint count;
-
- /* QoS stuff *//* with LOCK */
- gdouble proportion;
- GstClockTime earliest_time;
-};
-
-struct _GstVisualClass
-{
- GstElementClass parent_class;
-
- VisPluginRef *plugin;
-};
-
-GType gst_visual_get_type (void);
-
-
-static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN "; "
-#if G_BYTE_ORDER == G_BIG_ENDIAN
- GST_VIDEO_CAPS_RGB "; "
-#else
- GST_VIDEO_CAPS_BGR "; "
-#endif
- GST_VIDEO_CAPS_RGB_16)
- );
-
-static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-raw-int, "
- "width = (int) 16, "
- "depth = (int) 16, "
- "endianness = (int) BYTE_ORDER, "
- "signed = (boolean) TRUE, " "channels = (int) { 1, 2 }, "
-#if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
- "rate = (int) { 8000, 11250, 22500, 32000, 44100, 48000, 96000 }"
-#else
- "rate = (int) [ 1000, MAX ]"
-#endif
- )
- );
-
-
-static void gst_visual_class_init (gpointer g_class, gpointer class_data);
-static void gst_visual_init (GstVisual * visual);
-static void gst_visual_dispose (GObject * object);
-
-static GstStateChangeReturn gst_visual_change_state (GstElement * element,
- GstStateChange transition);
-static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer);
-static gboolean gst_visual_sink_event (GstPad * pad, GstEvent * event);
-static gboolean gst_visual_src_event (GstPad * pad, GstEvent * event);
-
-static gboolean gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_visual_src_setcaps (GstPad * pad, GstCaps * caps);
-static GstCaps *gst_visual_getcaps (GstPad * pad);
-static void libvisual_log_handler (const char *message, const char *funcname,
- void *priv);
-
-static GstElementClass *parent_class = NULL;
-
-GType
-gst_visual_get_type (void)
-{
- static GType type = 0;
-
- if (G_UNLIKELY (type == 0)) {
- static const GTypeInfo info = {
- sizeof (GstVisualClass),
- NULL,
- NULL,
- gst_visual_class_init,
- NULL,
- NULL,
- sizeof (GstVisual),
- 0,
- (GInstanceInitFunc) gst_visual_init,
- };
-
- type = g_type_register_static (GST_TYPE_ELEMENT, "GstVisual", &info, 0);
- }
- return type;
-}
-
-static void
-libvisual_log_handler (const char *message, const char *funcname, void *priv)
-{
- GST_CAT_LEVEL_LOG (libvisual_debug, (GstDebugLevel) (priv), NULL, "%s - %s",
- funcname, message);
-}
-
-static void
-gst_visual_class_init (gpointer g_class, gpointer class_data)
-{
- GstVisualClass *klass = GST_VISUAL_CLASS (g_class);
- GstElementClass *element = GST_ELEMENT_CLASS (g_class);
- GObjectClass *object = G_OBJECT_CLASS (g_class);
-
- klass->plugin = class_data;
-
- element->change_state = gst_visual_change_state;
-
- if (class_data == NULL) {
- parent_class = g_type_class_peek_parent (g_class);
- } else {
- GstElementDetails details = {
- NULL,
- "Visualization",
- klass->plugin->info->about,
- "Benjamin Otte <otte@gnome.org>"
- };
-
- details.longname = g_strdup_printf ("libvisual %s plugin v.%s",
- klass->plugin->info->name, klass->plugin->info->version);
-
- /* FIXME: improve to only register what plugin supports? */
- gst_element_class_add_pad_template (element,
- gst_static_pad_template_get (&src_template));
- gst_element_class_add_pad_template (element,
- gst_static_pad_template_get (&sink_template));
- gst_element_class_set_details (element, &details);
- g_free (details.longname);
- }
-
- object->dispose = gst_visual_dispose;
-}
-
-static void
-gst_visual_init (GstVisual * visual)
-{
- /* create the sink and src pads */
- visual->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
- gst_pad_set_setcaps_function (visual->sinkpad, gst_visual_sink_setcaps);
- gst_pad_set_chain_function (visual->sinkpad, gst_visual_chain);
- gst_pad_set_event_function (visual->sinkpad, gst_visual_sink_event);
- gst_element_add_pad (GST_ELEMENT (visual), visual->sinkpad);
-
- visual->srcpad = gst_pad_new_from_static_template (&src_template, "src");
- gst_pad_set_setcaps_function (visual->srcpad, gst_visual_src_setcaps);
- gst_pad_set_getcaps_function (visual->srcpad, gst_visual_getcaps);
- gst_pad_set_event_function (visual->srcpad, gst_visual_src_event);
- gst_element_add_pad (GST_ELEMENT (visual), visual->srcpad);
-
- visual->adapter = gst_adapter_new ();
-}
-
-static void
-gst_visual_clear_actors (GstVisual * visual)
-{
- if (visual->actor) {
- visual_object_unref (VISUAL_OBJECT (visual->actor));
- visual->actor = NULL;
- }
- if (visual->video) {
- visual_object_unref (VISUAL_OBJECT (visual->video));
- visual->video = NULL;
- }
- if (visual->audio) {
- visual_object_unref (VISUAL_OBJECT (visual->audio));
- visual->audio = NULL;
- }
-}
-
-static void
-gst_visual_dispose (GObject * object)
-{
- GstVisual *visual = GST_VISUAL (object);
-
- if (visual->adapter) {
- g_object_unref (visual->adapter);
- visual->adapter = NULL;
- }
- gst_visual_clear_actors (visual);
-
- GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
-}
-
-static void
-gst_visual_reset (GstVisual * visual)
-{
- gst_adapter_clear (visual->adapter);
- gst_segment_init (&visual->segment, GST_FORMAT_UNDEFINED);
-
- GST_OBJECT_LOCK (visual);
- visual->proportion = 1.0;
- visual->earliest_time = -1;
- GST_OBJECT_UNLOCK (visual);
-}
-
-static GstCaps *
-gst_visual_getcaps (GstPad * pad)
-{
- GstCaps *ret;
- GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
- int depths;
-
- if (!visual->actor) {
- ret = gst_caps_copy (gst_pad_get_pad_template_caps (visual->srcpad));
- goto beach;
- }
-
- ret = gst_caps_new_empty ();
- depths = visual_actor_get_supported_depth (visual->actor);
- if (depths < 0) {
- /* FIXME: set an error */
- goto beach;
- }
- if (depths == VISUAL_VIDEO_DEPTH_GL) {
- /* We can't handle GL only plugins */
- goto beach;
- }
-
- GST_DEBUG_OBJECT (visual, "libvisual plugin supports depths %u (0x%04x)",
- depths, depths);
- /* if (depths & VISUAL_VIDEO_DEPTH_32BIT) Always supports 32bit output */
- gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN));
-
- if (depths & VISUAL_VIDEO_DEPTH_24BIT) {
-#if G_BYTE_ORDER == G_BIG_ENDIAN
- gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_RGB));
-#else
- gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_BGR));
-#endif
- }
- if (depths & VISUAL_VIDEO_DEPTH_16BIT) {
- gst_caps_append (ret, gst_caps_from_string (GST_VIDEO_CAPS_RGB_16));
- }
-
-beach:
-
- GST_DEBUG_OBJECT (visual, "returning caps %" GST_PTR_FORMAT, ret);
- gst_object_unref (visual);
- return ret;
-}
-
-static gboolean
-gst_visual_src_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
- GstStructure *structure;
- gint depth, pitch;
-
- structure = gst_caps_get_structure (caps, 0);
-
- GST_DEBUG_OBJECT (visual, "src pad got caps %" GST_PTR_FORMAT, caps);
-
- if (!gst_structure_get_int (structure, "width", &visual->width))
- goto error;
- if (!gst_structure_get_int (structure, "height", &visual->height))
- goto error;
- if (!gst_structure_get_int (structure, "bpp", &depth))
- goto error;
- if (!gst_structure_get_fraction (structure, "framerate", &visual->fps_n,
- &visual->fps_d))
- goto error;
-
- visual_video_set_depth (visual->video,
- visual_video_depth_enum_from_value (depth));
- visual_video_set_dimension (visual->video, visual->width, visual->height);
- pitch = GST_ROUND_UP_4 (visual->width * visual->video->bpp);
- visual_video_set_pitch (visual->video, pitch);
- visual_actor_video_negotiate (visual->actor, 0, FALSE, FALSE);
-
- /* precalc some values */
- visual->outsize = visual->video->height * pitch;
- visual->spf =
- gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n);
- visual->duration =
- gst_util_uint64_scale_int (GST_SECOND, visual->fps_d, visual->fps_n);
-
- gst_object_unref (visual);
- return TRUE;
-
- /* ERRORS */
-error:
- {
- GST_DEBUG_OBJECT (visual, "error parsing caps");
- gst_object_unref (visual);
- return FALSE;
- }
-}
-
-static gboolean
-gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
- GstStructure *structure;
-
- structure = gst_caps_get_structure (caps, 0);
-
- gst_structure_get_int (structure, "channels", &visual->channels);
- gst_structure_get_int (structure, "rate", &visual->rate);
-
- /* this is how many samples we need to fill one frame at the requested
- * framerate. */
- if (visual->fps_n != 0) {
- visual->spf =
- gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n);
- }
- visual->bps = visual->channels * sizeof (gint16);
-
- gst_object_unref (visual);
- return TRUE;
-}
-
-static gboolean
-gst_vis_src_negotiate (GstVisual * visual)
-{
- GstCaps *othercaps, *target, *intersect;
- GstStructure *structure;
- GstCaps *caps;
-
- caps = gst_pad_get_caps (visual->srcpad);
-
- /* see what the peer can do */
- othercaps = gst_pad_peer_get_caps (visual->srcpad);
- if (othercaps) {
- intersect = gst_caps_intersect (othercaps, caps);
- gst_caps_unref (othercaps);
- gst_caps_unref (caps);
-
- if (gst_caps_is_empty (intersect))
- goto no_format;
-
- target = gst_caps_copy_nth (intersect, 0);
- gst_caps_unref (intersect);
- } else {
- /* need a copy, we'll be modifying it when fixating */
- target = gst_caps_copy (caps);
- gst_caps_unref (caps);
- }
-
- /* fixate in case something is not fixed. This does nothing if the value is
- * already fixed. For video we always try to fixate to something like
- * 320x240x30 by convention. */
- structure = gst_caps_get_structure (target, 0);
- gst_structure_fixate_field_nearest_int (structure, "width", 320);
- gst_structure_fixate_field_nearest_int (structure, "height", 240);
- gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
-
- gst_pad_set_caps (visual->srcpad, target);
- gst_caps_unref (target);
-
- return TRUE;
-
- /* ERRORS */
-no_format:
- {
- GST_ELEMENT_ERROR (visual, STREAM, FORMAT, (NULL),
- ("could not negotiate output format"));
- gst_caps_unref (intersect);
- return FALSE;
- }
-}
-
-static gboolean
-gst_visual_sink_event (GstPad * pad, GstEvent * event)
-{
- GstVisual *visual;
- gboolean res;
-
- visual = GST_VISUAL (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- res = gst_pad_push_event (visual->srcpad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- /* reset QoS and adapter. */
- gst_visual_reset (visual);
- res = gst_pad_push_event (visual->srcpad, event);
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
- gboolean update;
-
- /* the newsegment values are used to clip the input samples
- * and to convert the incomming timestamps to running time so
- * we can do QoS */
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
-
- /* now configure the values */
- gst_segment_set_newsegment_full (&visual->segment, update,
- rate, arate, format, start, stop, time);
-
- /* and forward */
- res = gst_pad_push_event (visual->srcpad, event);
- break;
- }
- default:
- res = gst_pad_push_event (visual->srcpad, event);
- break;
- }
-
- gst_object_unref (visual);
- return res;
-}
-
-static gboolean
-gst_visual_src_event (GstPad * pad, GstEvent * event)
-{
- GstVisual *visual;
- gboolean res;
-
- visual = GST_VISUAL (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_QOS:
- {
- gdouble proportion;
- GstClockTimeDiff diff;
- GstClockTime timestamp;
-
- gst_event_parse_qos (event, &proportion, &diff, &timestamp);
-
- /* save stuff for the _chain function */
- GST_OBJECT_LOCK (visual);
- visual->proportion = proportion;
- if (diff >= 0)
- /* we're late, this is a good estimate for next displayable
- * frame (see part-qos.txt) */
- visual->earliest_time = timestamp + 2 * diff + visual->duration;
- else
- visual->earliest_time = timestamp + diff;
-
- GST_OBJECT_UNLOCK (visual);
-
- res = gst_pad_push_event (visual->sinkpad, event);
- break;
- }
- default:
- res = gst_pad_push_event (visual->sinkpad, event);
- break;
- }
-
- gst_object_unref (visual);
- return res;
-}
-
-/* allocate and output buffer, if no format was negotiated, this
- * function will negotiate one. After calling this function, a
- * reverse negotiation could have happened. */
-static GstFlowReturn
-get_buffer (GstVisual * visual, GstBuffer ** outbuf)
-{
- GstFlowReturn ret;
-
- /* we don't know an output format yet, pick one */
- if (GST_PAD_CAPS (visual->srcpad) == NULL) {
- if (!gst_vis_src_negotiate (visual))
- return GST_FLOW_NOT_NEGOTIATED;
- }
-
- GST_DEBUG_OBJECT (visual, "allocating output buffer with caps %"
- GST_PTR_FORMAT, GST_PAD_CAPS (visual->srcpad));
-
- /* now allocate a buffer with the last negotiated format.
- * Downstream could renegotiate a new format, which will trigger
- * our setcaps function on the source pad. */
- ret =
- gst_pad_alloc_buffer_and_set_caps (visual->srcpad,
- GST_BUFFER_OFFSET_NONE, visual->outsize,
- GST_PAD_CAPS (visual->srcpad), outbuf);
-
- /* no buffer allocated, we don't care why. */
- if (ret != GST_FLOW_OK)
- return ret;
-
- return GST_FLOW_OK;
-}
-
-static GstFlowReturn
-gst_visual_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstBuffer *outbuf = NULL;
- guint i;
- GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
- GstFlowReturn ret = GST_FLOW_OK;
- guint avail;
-
- GST_DEBUG_OBJECT (visual, "chain function called");
-
- /* If we don't have an output format yet, preallocate a buffer to try and
- * set one */
- if (GST_PAD_CAPS (visual->srcpad) == NULL) {
- ret = get_buffer (visual, &outbuf);
- if (ret != GST_FLOW_OK) {
- gst_buffer_unref (buffer);
- goto beach;
- }
- }
-
- /* resync on DISCONT */
- if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
- gst_adapter_clear (visual->adapter);
- }
-
- GST_DEBUG_OBJECT (visual,
- "Input buffer has %d samples, time=%" G_GUINT64_FORMAT,
- GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer));
-
- gst_adapter_push (visual->adapter, buffer);
-
- while (TRUE) {
- gboolean need_skip;
- const guint16 *data;
- guint64 dist, timestamp;
-
- GST_DEBUG_OBJECT (visual, "processing buffer");
-
- avail = gst_adapter_available (visual->adapter);
- GST_DEBUG_OBJECT (visual, "avail now %u", avail);
-
- /* we need at least 512 samples */
- if (avail < 512 * visual->bps)
- break;
-
- /* we need at least enough samples to make one frame */
- if (avail < visual->spf * visual->bps)
- break;
-
- /* get timestamp of the current adapter byte */
- timestamp = gst_adapter_prev_timestamp (visual->adapter, &dist);
- if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
- /* convert bytes to time */
- dist /= visual->bps;
- timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, visual->rate);
- }
-
- if (timestamp != -1) {
- gint64 qostime;
-
- /* QoS is done on running time */
- qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME,
- timestamp);
-
- GST_OBJECT_LOCK (visual);
- /* check for QoS, don't compute buffers that are known to be late */
- need_skip = visual->earliest_time != -1 &&
- qostime <= visual->earliest_time;
- GST_OBJECT_UNLOCK (visual);
-
- if (need_skip) {
- GST_WARNING_OBJECT (visual,
- "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time));
- goto skip;
- }
- }
-
- /* Read 512 samples per channel */
- data =
- (const guint16 *) gst_adapter_peek (visual->adapter, 512 * visual->bps);
-
-#if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
- {
- VisBuffer *lbuf, *rbuf;
- guint16 ldata[512], rdata[512];
- VisAudioSampleRateType rate;
-
- lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL);
- rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL);
-
- if (visual->channels == 2) {
- for (i = 0; i < 512; i++) {
- ldata[i] = *data++;
- rdata[i] = *data++;
- }
- } else {
- for (i = 0; i < 512; i++) {
- ldata[i] = *data;
- rdata[i] = *data++;
- }
- }
-
- switch (visual->rate) {
- case 8000:
- rate = VISUAL_AUDIO_SAMPLE_RATE_8000;
- break;
- case 11250:
- rate = VISUAL_AUDIO_SAMPLE_RATE_11250;
- break;
- case 22500:
- rate = VISUAL_AUDIO_SAMPLE_RATE_22500;
- break;
- case 32000:
- rate = VISUAL_AUDIO_SAMPLE_RATE_32000;
- break;
- case 44100:
- rate = VISUAL_AUDIO_SAMPLE_RATE_44100;
- break;
- case 48000:
- rate = VISUAL_AUDIO_SAMPLE_RATE_48000;
- break;
- case 96000:
- rate = VISUAL_AUDIO_SAMPLE_RATE_96000;
- break;
- default:
- visual_object_unref (VISUAL_OBJECT (lbuf));
- visual_object_unref (VISUAL_OBJECT (rbuf));
- GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate);
- ret = GST_FLOW_ERROR;
- goto beach;
- break;
- }
-
- visual_audio_samplepool_input_channel (visual->audio->samplepool,
- lbuf,
- rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, VISUAL_AUDIO_CHANNEL_LEFT);
- visual_audio_samplepool_input_channel (visual->audio->samplepool,
- rbuf,
- rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, VISUAL_AUDIO_CHANNEL_RIGHT);
-
- visual_object_unref (VISUAL_OBJECT (lbuf));
- visual_object_unref (VISUAL_OBJECT (rbuf));
-
- }
-#else
- if (visual->channels == 2) {
- for (i = 0; i < 512; i++) {
- visual->audio->plugpcm[0][i] = *data++;
- visual->audio->plugpcm[1][i] = *data++;
- }
- } else {
- for (i = 0; i < 512; i++) {
- visual->audio->plugpcm[0][i] = *data;
- visual->audio->plugpcm[1][i] = *data++;
- }
- }
-#endif
-
- /* alloc a buffer if we don't have one yet, this happens
- * when we pushed a buffer in this while loop before */
- if (outbuf == NULL) {
- ret = get_buffer (visual, &outbuf);
- if (ret != GST_FLOW_OK) {
- goto beach;
- }
- }
- visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf));
- visual_audio_analyze (visual->audio);
- visual_actor_run (visual->actor, visual->audio);
- visual_video_set_buffer (visual->video, NULL);
- GST_DEBUG_OBJECT (visual, "rendered one frame");
-
- GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
- GST_BUFFER_DURATION (outbuf) = visual->duration;
-
- ret = gst_pad_push (visual->srcpad, outbuf);
- outbuf = NULL;
-
- skip:
- GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input",
- visual->spf);
-
- /* Flush out the number of samples per frame */
- gst_adapter_flush (visual->adapter, visual->spf * visual->bps);
-
- /* quit the loop if something was wrong */
- if (ret != GST_FLOW_OK)
- break;
- }
-
-beach:
-
- if (outbuf != NULL)
- gst_buffer_unref (outbuf);
-
- gst_object_unref (visual);
-
- return ret;
-}
-
-static GstStateChangeReturn
-gst_visual_change_state (GstElement * element, GstStateChange transition)
-{
- GstVisual *visual = GST_VISUAL (element);
- GstStateChangeReturn ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- visual->actor =
- visual_actor_new (GST_VISUAL_GET_CLASS (visual)->plugin->info->
- plugname);
- visual->video = visual_video_new ();
- visual->audio = visual_audio_new ();
- /* can't have a play without actors */
- if (!visual->actor || !visual->video)
- goto no_actors;
-
- if (visual_actor_realize (visual->actor) != 0)
- goto no_realize;
-
- visual_actor_set_video (visual->actor, visual->video);
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- gst_visual_reset (visual);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- gst_visual_clear_actors (visual);
- break;
- default:
- break;
- }
-
- return ret;
-
- /* ERRORS */
-no_actors:
- {
- GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
- ("could not create actors"));
- gst_visual_clear_actors (visual);
- return GST_STATE_CHANGE_FAILURE;
- }
-no_realize:
- {
- GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL),
- ("could not realize actor"));
- gst_visual_clear_actors (visual);
- return GST_STATE_CHANGE_FAILURE;
- }
-}
-
-static void
-make_valid_name (char *name)
-{
- /*
- * Replace invalid chars with _ in the type name
- */
- static const gchar extra_chars[] = "-_+";
- gchar *p = name;
-
- for (; *p; p++) {
- int valid = ((p[0] >= 'A' && p[0] <= 'Z') ||
- (p[0] >= 'a' && p[0] <= 'z') ||
- (p[0] >= '0' && p[0] <= '9') || strchr (extra_chars, p[0]));
- if (!valid)
- *p = '_';
- }
-}
-
-static gboolean
-gst_visual_actor_plugin_is_gl (VisObject * plugin, const gchar * name)
-{
- gboolean is_gl;
- gint depth;
-
-#if !defined(VISUAL_API_VERSION)
-
- depth = VISUAL_PLUGIN_ACTOR (plugin)->depth;
- is_gl = (depth == VISUAL_VIDEO_DEPTH_GL);
-
-#elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
-
- depth = VISUAL_ACTOR_PLUGIN (plugin)->vidoptions.depth;
- /* FIXME: how to figure this out correctly in 0.4? */
- is_gl = (depth & VISUAL_VIDEO_DEPTH_GL) == VISUAL_VIDEO_DEPTH_GL;
-
-#else
-# error what libvisual version is this?
-#endif
-
- if (!is_gl) {
- GST_DEBUG ("plugin %s is not a GL plugin (%d), registering", name, depth);
- } else {
- GST_DEBUG ("plugin %s is a GL plugin (%d), ignoring", name, depth);
- }
-
- return is_gl;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- guint i, count;
- VisList *list;
-
- GST_DEBUG_CATEGORY_INIT (libvisual_debug, "libvisual", 0,
- "libvisual audio visualisations");
-
-#ifdef LIBVISUAL_PLUGINSBASEDIR
- gst_plugin_add_dependency_simple (plugin, "HOME/.libvisual/actor",
- LIBVISUAL_PLUGINSBASEDIR "/actor", NULL, GST_PLUGIN_DEPENDENCY_FLAG_NONE);
-#endif
-
- visual_log_set_verboseness (VISUAL_LOG_VERBOSENESS_LOW);
- visual_log_set_info_handler (libvisual_log_handler, (void *) GST_LEVEL_INFO);
- visual_log_set_warning_handler (libvisual_log_handler,
- (void *) GST_LEVEL_WARNING);
- visual_log_set_critical_handler (libvisual_log_handler,
- (void *) GST_LEVEL_ERROR);
- visual_log_set_error_handler (libvisual_log_handler,
- (void *) GST_LEVEL_ERROR);
-
- if (!visual_is_initialized ())
- if (visual_init (NULL, NULL) != 0)
- return FALSE;
-
- list = visual_actor_get_list ();
-
-#if !defined(VISUAL_API_VERSION)
- count = visual_list_count (list);
-#elif VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
- count = visual_collection_size (VISUAL_COLLECTION (list));
-#endif
-
- for (i = 0; i < count; i++) {
- VisPluginRef *ref = visual_list_get (list, i);
- VisPluginData *visplugin = NULL;
- gboolean skip = FALSE;
- GType type;
- gchar *name;
- GTypeInfo info = {
- sizeof (GstVisualClass),
- NULL,
- NULL,
- gst_visual_class_init,
- NULL,
- ref,
- sizeof (GstVisual),
- 0,
- NULL
- };
-
- visplugin = visual_plugin_load (ref);
-
- if (ref->info->plugname == NULL)
- continue;
-
- /* Blacklist some plugins */
- if (strcmp (ref->info->plugname, "gstreamer") == 0 ||
- strcmp (ref->info->plugname, "gdkpixbuf") == 0) {
- skip = TRUE;
- } else {
- /* Ignore plugins that only support GL output for now */
- skip = gst_visual_actor_plugin_is_gl (visplugin->info->plugin,
- visplugin->info->plugname);
- }
-
- visual_plugin_unload (visplugin);
-
- if (!skip) {
- name = g_strdup_printf ("GstVisual%s", ref->info->plugname);
- make_valid_name (name);
- type = g_type_register_static (GST_TYPE_VISUAL, name, &info, 0);
- g_free (name);
-
- name = g_strdup_printf ("libvisual_%s", ref->info->plugname);
- make_valid_name (name);
- if (!gst_element_register (plugin, name, GST_RANK_NONE, type)) {
- g_free (name);
- return FALSE;
- }
- g_free (name);
- }
- }
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "libvisual",
- "libvisual visualization plugins",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/ogg/Makefile.am b/ext/ogg/Makefile.am
deleted file mode 100644
index 2d152335..00000000
--- a/ext/ogg/Makefile.am
+++ /dev/null
@@ -1,27 +0,0 @@
-plugin_LTLIBRARIES = libgstogg.la
-
-libgstogg_la_SOURCES = \
- gstogg.c \
- gstoggdemux.c \
- gstoggmux.c \
- gstogmparse.c \
- gstoggaviparse.c \
- gstoggparse.c \
- gstoggstream.c \
- gstoggstream.h \
- dirac_parse.c \
- dirac_parse.h \
- vorbis_parse.c
-
-noinst_HEADERS = \
- gstoggdemux.h gstoggmux.h
-
-libgstogg_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(OGG_CFLAGS)
-libgstogg_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/riff/libgstriff-$(GST_MAJORMINOR).la \
- $(top_builddir)/gst-libs/gst/tag/libgsttag-$(GST_MAJORMINOR).la \
- $(GST_BASE_LIBS) \
- $(OGG_LIBS)
-libgstogg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstogg_la_LIBTOOLFLAGS = --tag=disable-static
-
diff --git a/ext/ogg/README b/ext/ogg/README
deleted file mode 100644
index 557e9d50..00000000
--- a/ext/ogg/README
+++ /dev/null
@@ -1,366 +0,0 @@
-This document describes some things to know about the Ogg format, as well
-as implementation details in GStreamer.
-
-INTRODUCTION
-============
-
-ogg and the granulepos
-----------------------
-
-An ogg stream contains pages with a serial number and a granulepos.
-The granulepos is a 64 bit signed integer. It is a value that in some way
-represents a time since the start of the stream.
-The interpretation as such is however both codec-specific and
-stream-specific.
-
-ogg has no notion of time: it only knows about bytes and granulepos values
-on pages.
-
-The granule position is just a number; the only guarantee for a valid ogg
-stream is that within a logical stream, this number never decreases.
-
-While logically a granulepos value can be constructed for every ogg packet,
-the page is marked with only one granulepos value: the granulepos of the
-last packet to end on that page.
-
-theora and the granulepos
--------------------------
-
-The granulepos in theora is an encoding of the frame number of the last
-key frame ("i frame"), and the number of frames since the last key frame
-("p frame"). The granulepos is constructed as the sum of the first number,
-shifted to the left for granuleshift bits, and the second number:
-granulepos = pframe << granuleshift + iframe
-
-(This means that given a framenumber or a timestamp, one cannot generate
- the one and only granulepos for that page; several granulepos possibilities
- correspond to this frame number. You also need the last keyframe, as well
- as the granuleshift.
- However, given a granulepos, the theora codec can still map that to a
- unique timestamp and frame number for that theora stream)
-
- Note: currently theora stores the "presentation time" as the granulepos;
- ie. a first data page with one packet contains one video frame and
- will be marked with 0/0. Changing that to be 1/0 (so that it
- represents the number of decodable frames up to that point, like
- for Vorbis) is being discussed.
-
-vorbis and granulepos
----------------------
-
-In Vorbis, the granulepos represents the number of samples that can be
-decoded from all packets up to that point.
-
-In GStreamer, the vorbisenc elements produces a stream where:
-- OFFSET is the time corresponding to the granulepos
- number of bytes produced before
-- OFFSET_END is the granulepos of the produced vorbis buffer
-- TIMESTAMP is the timestamp matching the begin of the buffer
-- DURATION is set to the length in time of the buffer
-
-Ogg media mapping
------------------
-
-Ogg defines a mapping for each media type that it embeds.
-
-For Vorbis:
-
- - 3 header pages, with granulepos 0.
- - 1 page with 1 packet header identification
- - N pages with 2 packets comments and codebooks
- - granulepos is samplenumber of next page
- - one packet can contain a variable number of samples but one frame
- that should be handed to the vorbis decoder.
-
-For Theora
-
- - 3 header pages, with granulepos 0.
- - 1 page with 1 packet header identification
- - N pages with 2 packets comments and codebooks
- - granulepos is framenumber of last packet in page, where framenumber
- is a combination of keyframe number and p frames since keyframe.
- - one packet contains 1 frame
-
-
-
-
-DEMUXING
-========
-
-ogg demuxer
------------
-
-This ogg demuxer has two modes of operation, which both share a significant
-amount of code. The first mode is the streaming mode which is automatically
-selected when the demuxer is connected to a non-getrange based element. When
-connected to a getrange based element the ogg demuxer can do full seeking
-with great efficiency.
-
-1) the streaming mode.
-
-In this mode, the ogg demuxer receives buffers in the _chain() function which
-are then simply submited to the ogg sync layer. Pages are then processed when
-the sync layer detects them, pads are created for new chains and packets are
-sent to the peer elements of the pads.
-
-In this mode, no seeking is possible. This is the typical case when the
-stream is read from a network source.
-
-In this mode, no setup is done at startup, the pages are just read and decoded.
-A new logical chain is detected when one of the pages has the BOS flag set. At
-this point the existing pads are removed and new pads are created for all the
-logical streams in this new chain.
-
-
-2) the random access mode.
-
- In this mode, the ogg file is first scanned to detect the position and length
-of all chains. This scanning is performed using a recursive binary search
-algorithm that is explained below.
-
- find_chains(start, end)
- {
- ret1 = read_next_pages (start);
- ret2 = read_prev_page (end);
-
- if (WAS_HEADER (ret1)) {
- }
- else {
- }
-
- }
-
- a) read first and last pages
-
- start end
- V V
- +-----------------------+-------------+--------------------+
- | 111 | 222 | 333 |
- BOS BOS BOS EOS
-
-
- after reading start, serial 111, BOS, chain[0] = 111
- after reading end, serial 333, EOS
-
- start serialno != end serialno, binary search start, (end-start)/2
-
- start bisect end
- V V V
- +-----------------------+-------------+--------------------+
- | 111 | 222 | 333 |
-
-
- after reading start, serial 111, BOS, chain[0] = 111
- after reading end, serial 222, EOS
-
- while (
-
-
-
-testcases
----------
-
- a) stream without BOS
-
- +----------------------------------------------------------+
- 111 |
- EOS
-
- b) chained stream, first chain without BOS
-
- +-------------------+--------------------------------------+
- 111 | 222 |
- BOS EOS
-
-
- c) chained stream
-
- +-------------------+--------------------------------------+
- | 111 | 222 |
- BOS BOS EOS
-
-
- d) chained stream, second without BOS
-
- +-------------------+--------------------------------------+
- | 111 | 222 |
- BOS EOS
-
-What can an ogg demuxer do?
----------------------------
-
-An ogg demuxer can read pages and get the granulepos from them.
-It can ask the decoder elements to convert a granulepos to time.
-
-An ogg demuxer can also get the granulepos of the first and the last page of a
-stream to get the start and end timestamp of that stream.
-It can also get the length in bytes of the stream
-(when the peer is seekable, that is).
-
-An ogg demuxer is therefore basically able to seek to any byte position and
-timestamp.
-
-When asked to seek to a given granulepos, the ogg demuxer should always convert
-the value to a timestamp using the peer decoder element conversion function. It
-can then binary search the file to eventually end up on the page with the given
-granule pos or a granulepos with the same timestamp.
-
-Seeking in ogg currently
-------------------------
-
-When seeking in an ogg, the decoders can choose to forward the seek event as a
-granulepos or a timestamp to the ogg demuxer.
-
-In the case of a granulepos, the ogg demuxer will seek back to the beginning of
-the stream and skip pages until it finds one with the requested timestamp.
-
-In the case of a timestamp, the ogg demuxer also seeks back to the beginning of
-the stream. For each page it reads, it asks the decoder element to convert the
-granulepos back to a timestamp. The ogg demuxer keeps on skipping pages until
-the page has a timestamp bigger or equal to the requested one.
-
-It is therefore important that the decoder elements in vorbis can convert a
-granulepos into a timestamp or never seek on timestamp on the oggdemuxer.
-
-The default format on the oggdemuxer source pads is currently defined as a the
-granulepos of the packets, it is also the value of the OFFSET field in the
-GstBuffer.
-
-MUXING
-======
-
-Oggmux
-------
-
-The ogg muxer's job is to output complete Ogg pages such that the absolute
-time represented by the valid (ie, not -1) granulepos values on those pages
-never decreases. This has to be true for all logical streams in the group at
-the same time.
-
-To achieve this, encoders are required to pass along the exact time that the
-granulepos represents for each ogg packet that it pushes to the ogg muxer.
-This is ESSENTIAL: without this exact time representation of the granulepos,
-the muxer can not produce valid streams.
-
-The ogg muxer has a packet queue per sink pad. From this queue a page can
-be flushed when:
- - total byte size of queued packets exceeds a given value
- - total time duration of queued packets exceeds a given value
- - total byte size of queued packets exceeds maximum Ogg page size
- - eos of the pad
- - encoder sent a command to flush out an ogg page after this new packet
- (in 0.8, through a flush event; in 0.10, with a GstOggBuffer)
- - muxer wants a flush to happen (so it can output pages)
-
-The ogg muxer also has a page queue per sink pad. This queue collects
-Ogg pages from the corresponding packet queue. Each page is also marked
-with the timestamp that the granulepos in the header represents.
-
-A page can be flushed from this collection of page queues when:
-- ideally, every page queue has at least one page with a valid granulepos
- -> choose the page, from all queues, with the lowest timestamp value
-- if not, muxer can wait if the following limits aren't reached:
- - total byte size of any page queue exceeds a limit
- - total time duration of any page queue exceeds a limit
-- if this limit is reached, then:
- - request a page flush from packet queue to page queue for each queue
- that does not have pages
- - now take the page from all queues with the lowest timestamp value
- - make sure all later-coming data is marked as old, either to be still
- output (but producing an invalid stream, though it can be fixed later)
- or dropped (which means it's gone forever)
-
-The oggmuxer uses the offset fields to fill in the granulepos in the pages.
-
-GStreamer implementation details
---------------------------------
-As said before, the basic rule is that the ogg muxer needs an exact time
-representation for each granulepos. This needs to be provided by the encoder.
-
-Potential problems are:
- - initial offsets for a raw stream need to be preserved somehow. Example:
- if the first audio sample has time 0.5, the granulepos in the vorbis encoder
- needs to be adjusted to take this into account.
- - initial offsets may need be on rate boundaries. Example:
- if the framerate is 5 fps, and the first video frame has time 0.1 s, the
- granulepos cannot correctly represent this timestamp.
- This can be handled out-of-band (initial offset in another muxing format,
- skeleton track with initial offsets, ...)
-
-Given that the basic rule for muxing is that the muxer needs an exact timestamp
-matching the granulepos, we need some way of communicating this time value
-from encoders to the Ogg muxer. So we need a mechanism to communicate
-a granulepos and its time representation for each GstBuffer.
-
-(This is an instance of a more generic problem - having a way to attach
- more fields to a GstBuffer)
-
-Possible ways:
-- setting TIMESTAMP to this value: bad - this value represents the end time
- of the buffer, and thus conflicts with GStreamer's idea of what TIMESTAMP
- is. This would cause problems muxing the encoded stream in other muxing
- formats, or for streaming. Note that this is what was done in GStreamer 0.8
-- setting DURATION to GP_TIME - TIMESTAMP: bad - this breaks the concept of
- duration for this frame. Take the video example above; each buffer would
- have a correct timestamp, but always a 0.1 s duration as opposed to the
- correct 0.2 s duration
-- subclassing GstBuffer: clean, but requires a common header used between
- ogg muxer and all encoders that can be muxed into ogg. Also, what if
- a format can be muxed into more than one container, and they each have
- their own "extra" info to communicate ?
-- adding key/value pairs to GstBuffer: clean, but requires changes to
- core. Also, the overhead of allocating e.g. a GstStructure for *each* buffer
- may be expensive.
-- "cheating":
- - abuse OFFSET to store the timestamp matching this granulepos
- - abuse OFFSET_END to store the granulepos value
- The drawback here is that before, it made sense to use OFFSET and OFFSET_END
- to store a byte count. Given that this is not used for anything critical
- (you can't store a raw theora or vorbis stream in a file anyway),
- this is what's being done for now.
-
-In practice
------------
-- all encoders of formats that can be muxed into Ogg produce a stream where:
- - OFFSET is abused to be the timestamp corresponding exactly to the
- granulepos
- - OFFSET_END is abused to be the granulepos of the encoded theora buffer
- - TIMESTAMP is the timestamp matching the begin of the buffer
- - DURATION is the length in time of the buffer
-
-- initial delays should be handled in the GStreamer encoders by mangling
- the granulepos of the encoded packet to take the delay into account as
- best as possible and store that in OFFSET;
- this then brings TIMESTAMP + DURATION to within less
- than a frame period of the granulepos's time representation
- The ogg muxer will then create new ogg packets with this OFFSET as
- the granulepos. So in effect, the granulepos produced by the encoders
- does not get used directly.
-
-TODO
-----
-- decide on a proper mechanism for communicating extra per-buffer fields
-- the ogg muxer sets timestamp and duration on outgoing ogg pages based on
- timestamp/duration of incoming ogg packets.
- Note that:
- - since the ogg muxer *has* to output pages sorted by gp time, representing
- end time of the page, this means that the buffer's timestamps are not
- necessarily monotonically increasing
- - timestamp + duration of buffers don't match up; the duration represents
- the length of the ogg page *for that stream*. Hence, for a normal
- two-stream file, the sum of all durations is twice the length of the
- muxed file.
-
-TESTING
--------
-Proper muxing can be tested by generating test files with command lines like:
-- video and audio start from 0:
-gst-launch -v videotestsrc ! theoraenc ! oggmux audiotestsrc ! audioconvert ! vorbisenc ! identity ! oggmux0. oggmux0. ! filesink location=test.ogg
-
-- video starts after audio:
-gst-launch -v videotestsrc timestamp-offset=500000000 ! theoraenc ! oggmux audiotestsrc ! audioconvert ! vorbisenc ! identity ! oggmux0. oggmux0. ! filesink location=test.ogg
-
-- audio starts after video:
-gst-launch -v videotestsrc ! theoraenc ! oggmux audiotestsrc timestamp-offset=500000000 ! audioconvert ! vorbisenc ! identity ! oggmux0. oggmux0. ! filesink location=test.ogg
-
-The resulting files can be verified with oggz-validate for correctness.
diff --git a/ext/ogg/dirac_parse.c b/ext/ogg/dirac_parse.c
deleted file mode 100644
index f7b483dc..00000000
--- a/ext/ogg/dirac_parse.c
+++ /dev/null
@@ -1,501 +0,0 @@
-
-#include "dirac_parse.h"
-#include <string.h>
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
-typedef struct _Unpack Unpack;
-
-struct _Unpack
-{
- unsigned char *data;
- int n_bits_left;
- int index;
- int guard_bit;
-};
-
-static void schro_unpack_init_with_data (Unpack * unpack, unsigned char *data,
- int n_bytes, unsigned int guard_bit);
-
-static unsigned int schro_unpack_decode_bit (Unpack * unpack);
-static unsigned int schro_unpack_decode_uint (Unpack * unpack);
-
-
-void schro_video_format_set_std_video_format (DiracSequenceHeader * format,
- int index);
-void schro_video_format_set_std_frame_rate (DiracSequenceHeader * format,
- int index);
-void schro_video_format_set_std_aspect_ratio (DiracSequenceHeader * format,
- int index);
-void schro_video_format_set_std_signal_range (DiracSequenceHeader * format,
- int index);
-void schro_video_format_set_std_colour_spec (DiracSequenceHeader * format,
- int index);
-
-
-
-
-int
-dirac_sequence_header_parse (DiracSequenceHeader * header,
- unsigned char *data, int n_bytes)
-{
- int bit;
- int index;
- Unpack _unpack;
- Unpack *unpack = &_unpack;
- int major_version;
- int minor_version;
- int profile;
- int level;
-
- memset (header, 0, sizeof (*header));
-
- schro_unpack_init_with_data (unpack, data, n_bytes, 1);
-
- /* parse parameters */
- major_version = schro_unpack_decode_uint (unpack);
- minor_version = schro_unpack_decode_uint (unpack);
- profile = schro_unpack_decode_uint (unpack);
- level = schro_unpack_decode_uint (unpack);
-
- /* base video header */
- index = schro_unpack_decode_uint (unpack);
- schro_video_format_set_std_video_format (header, index);
-
- header->major_version = major_version;
- header->minor_version = minor_version;
- header->profile = profile;
- header->level = level;
-
- /* source parameters */
- /* frame dimensions */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- header->width = schro_unpack_decode_uint (unpack);
- header->height = schro_unpack_decode_uint (unpack);
- }
-
- /* chroma header */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- header->chroma_format = schro_unpack_decode_uint (unpack);
- }
-
- /* scan header */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- header->interlaced = schro_unpack_decode_bit (unpack);
- if (header->interlaced) {
- header->top_field_first = schro_unpack_decode_bit (unpack);
- }
- }
-
- /* frame rate */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- index = schro_unpack_decode_uint (unpack);
- if (index == 0) {
- header->frame_rate_numerator = schro_unpack_decode_uint (unpack);
- header->frame_rate_denominator = schro_unpack_decode_uint (unpack);
- } else {
- schro_video_format_set_std_frame_rate (header, index);
- }
- }
-
- /* aspect ratio */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- index = schro_unpack_decode_uint (unpack);
- if (index == 0) {
- header->aspect_ratio_numerator = schro_unpack_decode_uint (unpack);
- header->aspect_ratio_denominator = schro_unpack_decode_uint (unpack);
- } else {
- schro_video_format_set_std_aspect_ratio (header, index);
- }
- }
-
- /* clean area */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- header->clean_width = schro_unpack_decode_uint (unpack);
- header->clean_height = schro_unpack_decode_uint (unpack);
- header->left_offset = schro_unpack_decode_uint (unpack);
- header->top_offset = schro_unpack_decode_uint (unpack);
- }
-
- /* signal range */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- index = schro_unpack_decode_uint (unpack);
- if (index == 0) {
- header->luma_offset = schro_unpack_decode_uint (unpack);
- header->luma_excursion = schro_unpack_decode_uint (unpack);
- header->chroma_offset = schro_unpack_decode_uint (unpack);
- header->chroma_excursion = schro_unpack_decode_uint (unpack);
- } else {
- schro_video_format_set_std_signal_range (header, index);
- }
- }
-
- /* colour spec */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- index = schro_unpack_decode_uint (unpack);
- schro_video_format_set_std_colour_spec (header, index);
- if (index == 0) {
- /* colour primaries */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- header->colour_primaries = schro_unpack_decode_uint (unpack);
- }
- /* colour matrix */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- header->colour_matrix = schro_unpack_decode_uint (unpack);
- }
- /* transfer function */
- bit = schro_unpack_decode_bit (unpack);
- if (bit) {
- header->transfer_function = schro_unpack_decode_uint (unpack);
- }
- }
- }
-
- header->interlaced_coding = schro_unpack_decode_uint (unpack);
-
- return 1;
-}
-
-/* standard stuff */
-
-static DiracSequenceHeader schro_video_formats[] = {
- {0, 0, 0, 0,
- 0, /* custom */
- 640, 480, SCHRO_CHROMA_420,
- FALSE, FALSE,
- 24000, 1001, 1, 1,
- 640, 480, 0, 0,
- 0, 255, 128, 255,
- 0, 0, 0},
- {0, 0, 0, 0,
- 1, /* QSIF525 */
- 176, 120, SCHRO_CHROMA_420,
- FALSE, FALSE,
- 15000, 1001, 10, 11,
- 176, 120, 0, 0,
- 0, 255, 128, 255,
- 1, 1, 0},
- {0, 0, 0, 0,
- 2, /* QCIF */
- 176, 144, SCHRO_CHROMA_420,
- FALSE, TRUE,
- 25, 2, 12, 11,
- 176, 144, 0, 0,
- 0, 255, 128, 255,
- 2, 1, 0},
- {0, 0, 0, 0,
- 3, /* SIF525 */
- 352, 240, SCHRO_CHROMA_420,
- FALSE, FALSE,
- 15000, 1001, 10, 11,
- 352, 240, 0, 0,
- 0, 255, 128, 255,
- 1, 1, 0},
- {0, 0, 0, 0,
- 4, /* CIF */
- 352, 288, SCHRO_CHROMA_420,
- FALSE, TRUE,
- 25, 2, 12, 11,
- 352, 288, 0, 0,
- 0, 255, 128, 255,
- 2, 1, 0},
- {0, 0, 0, 0,
- 5, /* 4SIF525 */
- 704, 480, SCHRO_CHROMA_420,
- FALSE, FALSE,
- 15000, 1001, 10, 11,
- 704, 480, 0, 0,
- 0, 255, 128, 255,
- 1, 1, 0},
- {0, 0, 0, 0,
- 6, /* 4CIF */
- 704, 576, SCHRO_CHROMA_420,
- FALSE, TRUE,
- 25, 2, 12, 11,
- 704, 576, 0, 0,
- 0, 255, 128, 255,
- 2, 1, 0},
- {0, 0, 0, 0,
- 7, /* SD480I-60 */
- 720, 480, SCHRO_CHROMA_422,
- TRUE, FALSE,
- 30000, 1001, 10, 11,
- 704, 480, 8, 0,
- 64, 876, 512, 896,
- 1, 1, 0},
- {0, 0, 0, 0,
- 8, /* SD576I-50 */
- 720, 576, SCHRO_CHROMA_422,
- TRUE, TRUE,
- 25, 1, 12, 11,
- 704, 576, 8, 0,
- 64, 876, 512, 896,
- 2, 1, 0},
- {0, 0, 0, 0,
- 9, /* HD720P-60 */
- 1280, 720, SCHRO_CHROMA_422,
- FALSE, TRUE,
- 60000, 1001, 1, 1,
- 1280, 720, 0, 0,
- 64, 876, 512, 896,
- 0, 0, 0},
- {0, 0, 0, 0,
- 10, /* HD720P-50 */
- 1280, 720, SCHRO_CHROMA_422,
- FALSE, TRUE,
- 50, 1, 1, 1,
- 1280, 720, 0, 0,
- 64, 876, 512, 896,
- 0, 0, 0},
- {0, 0, 0, 0,
- 11, /* HD1080I-60 */
- 1920, 1080, SCHRO_CHROMA_422,
- TRUE, TRUE,
- 30000, 1001, 1, 1,
- 1920, 1080, 0, 0,
- 64, 876, 512, 896,
- 0, 0, 0},
- {0, 0, 0, 0,
- 12, /* HD1080I-50 */
- 1920, 1080, SCHRO_CHROMA_422,
- TRUE, TRUE,
- 25, 1, 1, 1,
- 1920, 1080, 0, 0,
- 64, 876, 512, 896,
- 0, 0, 0},
- {0, 0, 0, 0,
- 13, /* HD1080P-60 */
- 1920, 1080, SCHRO_CHROMA_422,
- FALSE, TRUE,
- 60000, 1001, 1, 1,
- 1920, 1080, 0, 0,
- 64, 876, 512, 896,
- 0, 0, 0},
- {0, 0, 0, 0,
- 14, /* HD1080P-50 */
- 1920, 1080, SCHRO_CHROMA_422,
- FALSE, TRUE,
- 50, 1, 1, 1,
- 1920, 1080, 0, 0,
- 64, 876, 512, 896,
- 0, 0, 0},
- {0, 0, 0, 0,
- 15, /* DC2K */
- 2048, 1080, SCHRO_CHROMA_444,
- FALSE, TRUE,
- 24, 1, 1, 1,
- 2048, 1080, 0, 0,
- 256, 3504, 2048, 3584,
- 3, 0, 0},
- {0, 0, 0, 0,
- 16, /* DC4K */
- 4096, 2160, SCHRO_CHROMA_444,
- FALSE, TRUE,
- 24, 1, 1, 1,
- 2048, 1536, 0, 0,
- 256, 3504, 2048, 3584,
- 3, 0, 0},
-};
-
-void
-schro_video_format_set_std_video_format (DiracSequenceHeader * format,
- int index)
-{
-
- if (index < 0 || index >= ARRAY_SIZE (schro_video_formats)) {
- return;
- }
-
- memcpy (format, schro_video_formats + index, sizeof (DiracSequenceHeader));
-}
-
-typedef struct _SchroFrameRate SchroFrameRate;
-struct _SchroFrameRate
-{
- int numerator;
- int denominator;
-};
-
-static SchroFrameRate schro_frame_rates[] = {
- {0, 0},
- {24000, 1001},
- {24, 1},
- {25, 1},
- {30000, 1001},
- {30, 1},
- {50, 1},
- {60000, 1001},
- {60, 1},
- {15000, 1001},
- {25, 2}
-};
-
-void
-schro_video_format_set_std_frame_rate (DiracSequenceHeader * format, int index)
-{
- if (index < 1 || index >= ARRAY_SIZE (schro_frame_rates)) {
- return;
- }
-
- format->frame_rate_numerator = schro_frame_rates[index].numerator;
- format->frame_rate_denominator = schro_frame_rates[index].denominator;
-}
-
-typedef struct _SchroPixelAspectRatio SchroPixelAspectRatio;
-struct _SchroPixelAspectRatio
-{
- int numerator;
- int denominator;
-};
-
-static const SchroPixelAspectRatio schro_aspect_ratios[] = {
- {0, 0},
- {1, 1},
- {10, 11},
- {12, 11},
- {40, 33},
- {16, 11},
- {4, 3}
-};
-
-void
-schro_video_format_set_std_aspect_ratio (DiracSequenceHeader * format,
- int index)
-{
- if (index < 1 || index >= ARRAY_SIZE (schro_aspect_ratios)) {
- return;
- }
-
- format->aspect_ratio_numerator = schro_aspect_ratios[index].numerator;
- format->aspect_ratio_denominator = schro_aspect_ratios[index].denominator;
-
-}
-
-typedef struct _SchroSignalRangeStruct SchroSignalRangeStruct;
-struct _SchroSignalRangeStruct
-{
- int luma_offset;
- int luma_excursion;
- int chroma_offset;
- int chroma_excursion;
-};
-
-static const SchroSignalRangeStruct schro_signal_ranges[] = {
- {0, 0, 0, 0},
- {0, 255, 128, 255},
- {16, 219, 128, 224},
- {64, 876, 512, 896},
- {256, 3504, 2048, 3584}
-};
-
-void
-schro_video_format_set_std_signal_range (DiracSequenceHeader * format, int i)
-{
- if (i < 1 || i >= ARRAY_SIZE (schro_signal_ranges)) {
- return;
- }
-
- format->luma_offset = schro_signal_ranges[i].luma_offset;
- format->luma_excursion = schro_signal_ranges[i].luma_excursion;
- format->chroma_offset = schro_signal_ranges[i].chroma_offset;
- format->chroma_excursion = schro_signal_ranges[i].chroma_excursion;
-}
-
-typedef struct _SchroColourSpecStruct SchroColourSpecStruct;
-struct _SchroColourSpecStruct
-{
- int colour_primaries;
- int colour_matrix;
- int transfer_function;
-};
-
-static const SchroColourSpecStruct schro_colour_specs[] = {
- { /* Custom */
- SCHRO_COLOUR_PRIMARY_HDTV,
- SCHRO_COLOUR_MATRIX_HDTV,
- SCHRO_TRANSFER_CHAR_TV_GAMMA},
- { /* SDTV 525 */
- SCHRO_COLOUR_PRIMARY_SDTV_525,
- SCHRO_COLOUR_MATRIX_SDTV,
- SCHRO_TRANSFER_CHAR_TV_GAMMA},
- { /* SDTV 625 */
- SCHRO_COLOUR_PRIMARY_SDTV_625,
- SCHRO_COLOUR_MATRIX_SDTV,
- SCHRO_TRANSFER_CHAR_TV_GAMMA},
- { /* HDTV */
- SCHRO_COLOUR_PRIMARY_HDTV,
- SCHRO_COLOUR_MATRIX_HDTV,
- SCHRO_TRANSFER_CHAR_TV_GAMMA},
- { /* Cinema */
- SCHRO_COLOUR_PRIMARY_CINEMA,
- SCHRO_COLOUR_MATRIX_HDTV,
- SCHRO_TRANSFER_CHAR_TV_GAMMA}
-};
-
-void
-schro_video_format_set_std_colour_spec (DiracSequenceHeader * format, int i)
-{
- if (i < 0 || i >= ARRAY_SIZE (schro_colour_specs)) {
- return;
- }
-
- format->colour_primaries = schro_colour_specs[i].colour_primaries;
- format->colour_matrix = schro_colour_specs[i].colour_matrix;
- format->transfer_function = schro_colour_specs[i].transfer_function;
-}
-
-
-/* unpack */
-
-static void
-schro_unpack_init_with_data (Unpack * unpack, unsigned char *data,
- int n_bytes, unsigned int guard_bit)
-{
- memset (unpack, 0, sizeof (Unpack));
-
- unpack->data = data;
- unpack->n_bits_left = 8 * n_bytes;
- unpack->guard_bit = guard_bit;
-}
-
-static unsigned int
-schro_unpack_decode_bit (Unpack * unpack)
-{
- int bit;
-
- if (unpack->n_bits_left < 1) {
- return unpack->guard_bit;
- }
- bit = (unpack->data[unpack->index >> 3] >> (7 - (unpack->index & 7))) & 1;
- unpack->index++;
- unpack->n_bits_left--;
-
- return bit;
-}
-
-static unsigned int
-schro_unpack_decode_uint (Unpack * unpack)
-{
- int count;
- int value;
-
- count = 0;
- value = 0;
- while (!schro_unpack_decode_bit (unpack)) {
- count++;
- value <<= 1;
- value |= schro_unpack_decode_bit (unpack);
- }
-
- return (1 << count) - 1 + value;
-}
diff --git a/ext/ogg/dirac_parse.h b/ext/ogg/dirac_parse.h
deleted file mode 100644
index 9dc4ffec..00000000
--- a/ext/ogg/dirac_parse.h
+++ /dev/null
@@ -1,178 +0,0 @@
-
-#ifndef __DIRAC_PARSE_H__
-#define __DIRAC_PARSE_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-typedef enum _SchroParseCode {
- SCHRO_PARSE_CODE_SEQUENCE_HEADER = 0x00,
- SCHRO_PARSE_CODE_END_OF_SEQUENCE = 0x10,
- SCHRO_PARSE_CODE_AUXILIARY_DATA = 0x20,
- SCHRO_PARSE_CODE_PADDING = 0x30,
-
- SCHRO_PARSE_CODE_INTRA_REF = 0x0c,
- SCHRO_PARSE_CODE_INTRA_NON_REF = 0x08,
- SCHRO_PARSE_CODE_INTRA_REF_NOARITH = 0x4c,
- SCHRO_PARSE_CODE_INTRA_NON_REF_NOARITH = 0x48,
-
- SCHRO_PARSE_CODE_INTER_REF_1 = 0x0d,
- SCHRO_PARSE_CODE_INTER_REF_1_NOARITH = 0x4d,
- SCHRO_PARSE_CODE_INTER_REF_2 = 0x0e,
- SCHRO_PARSE_CODE_INTER_REF_2_NOARITH = 0x4e,
-
- SCHRO_PARSE_CODE_INTER_NON_REF_1 = 0x09,
- SCHRO_PARSE_CODE_INTER_NON_REF_1_NOARITH = 0x49,
- SCHRO_PARSE_CODE_INTER_NON_REF_2 = 0x0a,
- SCHRO_PARSE_CODE_INTER_NON_REF_2_NOARITH = 0x4a,
-
- SCHRO_PARSE_CODE_LD_INTRA_REF = 0xcc,
- SCHRO_PARSE_CODE_LD_INTRA_NON_REF = 0xc8
-} SchroParseCode;
-
-#define SCHRO_PARSE_CODE_PICTURE(is_ref,n_refs,is_lowdelay,is_noarith) \
- (8 | ((is_ref)<<2) | (n_refs) | ((is_lowdelay)<<7) | ((is_noarith)<<6))
-
-#define SCHRO_PARSE_CODE_IS_SEQ_HEADER(x) ((x) == SCHRO_PARSE_CODE_SEQUENCE_HEADER)
-#define SCHRO_PARSE_CODE_IS_END_OF_SEQUENCE(x) ((x) == SCHRO_PARSE_CODE_END_OF_SEQUENCE)
-#define SCHRO_PARSE_CODE_IS_AUXILIARY_DATA(x) ((x) == SCHRO_PARSE_CODE_AUXILIARY_DATA)
-#define SCHRO_PARSE_CODE_IS_PADDING(x) ((x) == SCHRO_PARSE_CODE_PADDING)
-#define SCHRO_PARSE_CODE_IS_PICTURE(x) ((x) & 0x8)
-#define SCHRO_PARSE_CODE_IS_LOW_DELAY(x) (((x) & 0x88) == 0x88)
-#define SCHRO_PARSE_CODE_IS_CORE_SYNTAX(x) (((x) & 0x88) == 0x08)
-#define SCHRO_PARSE_CODE_USING_AC(x) (((x) & 0x48) == 0x08)
-#define SCHRO_PARSE_CODE_IS_REFERENCE(x) (((x) & 0xc) == 0x0c)
-#define SCHRO_PARSE_CODE_IS_NON_REFERENCE(x) (((x) & 0xc) == 0x08)
-#define SCHRO_PARSE_CODE_NUM_REFS(x) ((x) & 0x3)
-#define SCHRO_PARSE_CODE_IS_INTRA(x) (SCHRO_PARSE_CODE_IS_PICTURE(x) && SCHRO_PARSE_CODE_NUM_REFS(x) == 0)
-#define SCHRO_PARSE_CODE_IS_INTER(x) (SCHRO_PARSE_CODE_IS_PICTURE(x) && SCHRO_PARSE_CODE_NUM_REFS(x) > 0)
-
-#define SCHRO_PARSE_HEADER_SIZE (4+1+4+4)
-
-typedef enum _SchroVideoFormatEnum {
- SCHRO_VIDEO_FORMAT_CUSTOM = 0,
- SCHRO_VIDEO_FORMAT_QSIF,
- SCHRO_VIDEO_FORMAT_QCIF,
- SCHRO_VIDEO_FORMAT_SIF,
- SCHRO_VIDEO_FORMAT_CIF,
- SCHRO_VIDEO_FORMAT_4SIF,
- SCHRO_VIDEO_FORMAT_4CIF,
- SCHRO_VIDEO_FORMAT_SD480I_60,
- SCHRO_VIDEO_FORMAT_SD576I_50,
- SCHRO_VIDEO_FORMAT_HD720P_60,
- SCHRO_VIDEO_FORMAT_HD720P_50,
- SCHRO_VIDEO_FORMAT_HD1080I_60,
- SCHRO_VIDEO_FORMAT_HD1080I_50,
- SCHRO_VIDEO_FORMAT_HD1080P_60,
- SCHRO_VIDEO_FORMAT_HD1080P_50,
- SCHRO_VIDEO_FORMAT_DC2K_24,
- SCHRO_VIDEO_FORMAT_DC4K_24
-} SchroVideoFormatEnum;
-
-typedef enum _SchroChromaFormat {
- SCHRO_CHROMA_444 = 0,
- SCHRO_CHROMA_422,
- SCHRO_CHROMA_420
-} SchroChromaFormat;
-
-#define SCHRO_CHROMA_FORMAT_H_SHIFT(format) (((format) == SCHRO_CHROMA_444)?0:1)
-#define SCHRO_CHROMA_FORMAT_V_SHIFT(format) (((format) == SCHRO_CHROMA_420)?1:0)
-
-typedef enum _SchroSignalRange {
- SCHRO_SIGNAL_RANGE_CUSTOM = 0,
- SCHRO_SIGNAL_RANGE_8BIT_FULL = 1,
- SCHRO_SIGNAL_RANGE_8BIT_VIDEO = 2,
- SCHRO_SIGNAL_RANGE_10BIT_VIDEO = 3,
- SCHRO_SIGNAL_RANGE_12BIT_VIDEO = 4
-} SchroSignalRange;
-
-typedef enum _SchroColourSpec {
- SCHRO_COLOUR_SPEC_CUSTOM = 0,
- SCHRO_COLOUR_SPEC_SDTV_525 = 1,
- SCHRO_COLOUR_SPEC_SDTV_625 = 2,
- SCHRO_COLOUR_SPEC_HDTV = 3,
- SCHRO_COLOUR_SPEC_CINEMA = 4
-} SchroColourSpec;
-
-typedef enum _SchroColourPrimaries {
- SCHRO_COLOUR_PRIMARY_HDTV = 0,
- SCHRO_COLOUR_PRIMARY_SDTV_525 = 1,
- SCHRO_COLOUR_PRIMARY_SDTV_625 = 2,
- SCHRO_COLOUR_PRIMARY_CINEMA = 3
-} SchroColourPrimaries;
-
-typedef enum _SchroColourMatrix {
- SCHRO_COLOUR_MATRIX_HDTV = 0,
- SCHRO_COLOUR_MATRIX_SDTV = 1,
- SCHRO_COLOUR_MATRIX_REVERSIBLE = 2
-}SchroColourMatrix;
-
-typedef enum _SchroTransferFunction {
- SCHRO_TRANSFER_CHAR_TV_GAMMA = 0,
- SCHRO_TRANSFER_CHAR_EXTENDED_GAMUT = 1,
- SCHRO_TRANSFER_CHAR_LINEAR = 2,
- SCHRO_TRANSFER_CHAR_DCI_GAMMA = 3
-} SchroTransferFunction;
-
-
-
-typedef struct _DiracSequenceHeader DiracSequenceHeader;
-
-struct _DiracSequenceHeader {
- int major_version;
- int minor_version;
- int profile;
- int level;
-
- int index;
- int width;
- int height;
- int chroma_format;
-
- int interlaced;
- int top_field_first;
-
- int frame_rate_numerator;
- int frame_rate_denominator;
- int aspect_ratio_numerator;
- int aspect_ratio_denominator;
-
- int clean_width;
- int clean_height;
- int left_offset;
- int top_offset;
-
- int luma_offset;
- int luma_excursion;
- int chroma_offset;
- int chroma_excursion;
-
- int colour_primaries;
- int colour_matrix;
- int transfer_function;
-
- int interlaced_coding;
-
- int unused0;
- int unused1;
- int unused2;
-};
-
-
-int dirac_sequence_header_parse (DiracSequenceHeader *header,
- unsigned char *data, int length);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
diff --git a/ext/ogg/gstogg.c b/ext/ogg/gstogg.c
deleted file mode 100644
index d525aaa4..00000000
--- a/ext/ogg/gstogg.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * 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>
-
-extern gboolean gst_ogg_demux_plugin_init (GstPlugin * plugin);
-extern gboolean gst_ogg_mux_plugin_init (GstPlugin * plugin);
-extern gboolean gst_ogm_parse_plugin_init (GstPlugin * plugin);
-extern gboolean gst_ogg_parse_plugin_init (GstPlugin * plugin);
-extern gboolean gst_ogg_avi_parse_plugin_init (GstPlugin * plugin);
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- gst_ogg_demux_plugin_init (plugin);
- gst_ogg_mux_plugin_init (plugin);
- gst_ogm_parse_plugin_init (plugin);
- gst_ogg_parse_plugin_init (plugin);
- gst_ogg_avi_parse_plugin_init (plugin);
-
- return TRUE;
-}
-
-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_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/ogg/gstoggaviparse.c b/ext/ogg/gstoggaviparse.c
deleted file mode 100644
index 4b51e01e..00000000
--- a/ext/ogg/gstoggaviparse.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/* GStreamer
- * Copyright (C) 2006 Wim Taymans <wim@fluendo.com>
- *
- * gstoggaviparse.c: ogg avi stream parser
- *
- * 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.
- */
-
-/*
- * Ogg in AVI is mostly done for vorbis audio. In the codec_data we receive the
- * first 3 packets of the raw vorbis data. On the sinkpad we receive full-blown Ogg
- * pages.
- * Before extracting the packets out of the ogg pages, we push the raw vorbis
- * header packets to the decoder.
- * We don't use the incomming timestamps but use the ganulepos on the ogg pages
- * directly.
- * This parser only does ogg/vorbis for now.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <gst/gst.h>
-#include <ogg/ogg.h>
-#include <string.h>
-
-static const GstElementDetails gst_ogg_avi_parse_details =
-GST_ELEMENT_DETAILS ("Ogg AVI parser",
- "Codec/Parser",
- "parse an ogg avi stream into pages (info about ogg: http://xiph.org)",
- "Wim Taymans <wim@fluendo.com>");
-
-GST_DEBUG_CATEGORY_STATIC (gst_ogg_avi_parse_debug);
-#define GST_CAT_DEFAULT gst_ogg_avi_parse_debug
-
-#define GST_TYPE_OGG_AVI_PARSE (gst_ogg_avi_parse_get_type())
-#define GST_OGG_AVI_PARSE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_AVI_PARSE, GstOggAviParse))
-#define GST_OGG_AVI_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_AVI_PARSE, GstOggAviParse))
-#define GST_IS_OGG_AVI_PARSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_AVI_PARSE))
-#define GST_IS_OGG_AVI_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_AVI_PARSE))
-
-static GType gst_ogg_avi_parse_get_type (void);
-
-typedef struct _GstOggAviParse GstOggAviParse;
-typedef struct _GstOggAviParseClass GstOggAviParseClass;
-
-struct _GstOggAviParse
-{
- GstElement element;
-
- GstPad *sinkpad;
- GstPad *srcpad;
-
- gboolean discont;
- gint serial;
-
- ogg_sync_state sync;
- ogg_stream_state stream;
-};
-
-struct _GstOggAviParseClass
-{
- GstElementClass parent_class;
-};
-
-static void gst_ogg_avi_parse_base_init (gpointer g_class);
-static void gst_ogg_avi_parse_class_init (GstOggAviParseClass * klass);
-static void gst_ogg_avi_parse_init (GstOggAviParse * ogg);
-static GstElementClass *parent_class = NULL;
-
-static GType
-gst_ogg_avi_parse_get_type (void)
-{
- static GType ogg_avi_parse_type = 0;
-
- if (!ogg_avi_parse_type) {
- static const GTypeInfo ogg_avi_parse_info = {
- sizeof (GstOggAviParseClass),
- gst_ogg_avi_parse_base_init,
- NULL,
- (GClassInitFunc) gst_ogg_avi_parse_class_init,
- NULL,
- NULL,
- sizeof (GstOggAviParse),
- 0,
- (GInstanceInitFunc) gst_ogg_avi_parse_init,
- };
-
- ogg_avi_parse_type =
- g_type_register_static (GST_TYPE_ELEMENT, "GstOggAviParse",
- &ogg_avi_parse_info, 0);
- }
- return ogg_avi_parse_type;
-}
-
-enum
-{
- PROP_0
-};
-
-static GstStaticPadTemplate ogg_avi_parse_src_template_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-vorbis")
- );
-
-static GstStaticPadTemplate ogg_avi_parse_sink_template_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/x-ogg-avi")
- );
-
-static void gst_ogg_avi_parse_finalize (GObject * object);
-static GstStateChangeReturn gst_ogg_avi_parse_change_state (GstElement *
- element, GstStateChange transition);
-static gboolean gst_ogg_avi_parse_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_ogg_avi_parse_chain (GstPad * pad, GstBuffer * buffer);
-static gboolean gst_ogg_avi_parse_setcaps (GstPad * pad, GstCaps * caps);
-
-static void
-gst_ogg_avi_parse_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details (element_class, &gst_ogg_avi_parse_details);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&ogg_avi_parse_sink_template_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&ogg_avi_parse_src_template_factory));
-}
-
-static void
-gst_ogg_avi_parse_class_init (GstOggAviParseClass * klass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- gstelement_class->change_state = gst_ogg_avi_parse_change_state;
-
- gobject_class->finalize = gst_ogg_avi_parse_finalize;
-}
-
-static void
-gst_ogg_avi_parse_init (GstOggAviParse * ogg)
-{
- /* create the sink and source pads */
- ogg->sinkpad =
- gst_pad_new_from_static_template (&ogg_avi_parse_sink_template_factory,
- "sink");
- gst_pad_set_setcaps_function (ogg->sinkpad, gst_ogg_avi_parse_setcaps);
- gst_pad_set_event_function (ogg->sinkpad, gst_ogg_avi_parse_event);
- gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_avi_parse_chain);
- gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
-
- ogg->srcpad =
- gst_pad_new_from_static_template (&ogg_avi_parse_src_template_factory,
- "src");
- gst_pad_use_fixed_caps (ogg->srcpad);
- gst_element_add_pad (GST_ELEMENT (ogg), ogg->srcpad);
-}
-
-static void
-gst_ogg_avi_parse_finalize (GObject * object)
-{
- GstOggAviParse *ogg = GST_OGG_AVI_PARSE (object);
-
- GST_LOG_OBJECT (ogg, "Disposing of object %p", ogg);
-
- ogg_sync_clear (&ogg->sync);
- ogg_stream_clear (&ogg->stream);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static gboolean
-gst_ogg_avi_parse_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstOggAviParse *ogg;
- GstStructure *structure;
- const GValue *codec_data;
- GstBuffer *buffer;
- guint8 *data;
- guint size;
- guint32 sizes[3];
- GstCaps *outcaps;
- gint i, offs;
-
- ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad));
-
- structure = gst_caps_get_structure (caps, 0);
-
- /* take codec data */
- codec_data = gst_structure_get_value (structure, "codec_data");
- if (codec_data == NULL)
- goto no_data;
-
- /* only buffers are valid */
- if (G_VALUE_TYPE (codec_data) != GST_TYPE_BUFFER)
- goto wrong_format;
-
- /* Now parse the data */
- buffer = gst_value_get_buffer (codec_data);
-
- /* first 22 bytes are bits_per_sample, channel_mask, GUID
- * Then we get 3 LE guint32 with the 3 header sizes
- * then we get the bytes of the 3 headers. */
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
-
- GST_LOG_OBJECT (ogg, "configuring codec_data of size %u", size);
-
- /* skip headers */
- data += 22;
- size -= 22;
-
- /* we need at least 12 bytes for the packet sizes of the 3 headers */
- if (size < 12)
- goto buffer_too_small;
-
- /* read sizes of the 3 headers */
- sizes[0] = GST_READ_UINT32_LE (data);
- sizes[1] = GST_READ_UINT32_LE (data + 4);
- sizes[2] = GST_READ_UINT32_LE (data + 8);
-
- GST_DEBUG_OBJECT (ogg, "header sizes: %u %u %u", sizes[0], sizes[1],
- sizes[2]);
-
- size -= 12;
-
- /* and we need at least enough data for all the headers */
- if (size < sizes[0] + sizes[1] + sizes[2])
- goto buffer_too_small;
-
- /* set caps */
- outcaps = gst_caps_new_simple ("audio/x-vorbis", NULL);
- gst_pad_set_caps (ogg->srcpad, outcaps);
-
- /* copy header data */
- offs = 34;
- for (i = 0; i < 3; i++) {
- GstBuffer *out;
-
- /* now output the raw vorbis header packets */
- out = gst_buffer_create_sub (buffer, offs, sizes[i]);
- gst_buffer_set_caps (out, outcaps);
- gst_pad_push (ogg->srcpad, out);
-
- offs += sizes[i];
- }
- gst_caps_unref (outcaps);
-
- return TRUE;
-
- /* ERRORS */
-no_data:
- {
- GST_DEBUG_OBJECT (ogg, "no codec_data found in caps");
- return FALSE;
- }
-wrong_format:
- {
- GST_DEBUG_OBJECT (ogg, "codec_data is not a buffer");
- return FALSE;
- }
-buffer_too_small:
- {
- GST_DEBUG_OBJECT (ogg, "codec_data is too small");
- return FALSE;
- }
-}
-
-static gboolean
-gst_ogg_avi_parse_event (GstPad * pad, GstEvent * event)
-{
- GstOggAviParse *ogg;
- gboolean ret;
-
- ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- ret = gst_pad_push_event (ogg->srcpad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- ogg_sync_reset (&ogg->sync);
- ogg_stream_reset (&ogg->stream);
- ogg->discont = TRUE;
- ret = gst_pad_push_event (ogg->srcpad, event);
- break;
- default:
- ret = gst_pad_push_event (ogg->srcpad, event);
- break;
- }
- return ret;
-}
-
-static GstFlowReturn
-gst_ogg_avi_parse_push_packet (GstOggAviParse * ogg, ogg_packet * packet)
-{
- GstBuffer *buffer;
- GstFlowReturn result;
-
- /* allocate space for header and body */
- buffer = gst_buffer_new_and_alloc (packet->bytes);
- memcpy (GST_BUFFER_DATA (buffer), packet->packet, packet->bytes);
-
- GST_LOG_OBJECT (ogg, "created buffer %p from page", buffer);
-
- GST_BUFFER_OFFSET_END (buffer) = packet->granulepos;
-
- if (ogg->discont) {
- GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
- ogg->discont = FALSE;
- }
-
- result = gst_pad_push (ogg->srcpad, buffer);
-
- return result;
-}
-
-static GstFlowReturn
-gst_ogg_avi_parse_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstFlowReturn result = GST_FLOW_OK;
- GstOggAviParse *ogg;
- guint8 *data;
- guint size;
- gchar *oggbuf;
- gint ret = -1;
-
- ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad));
-
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
-
- GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d", size);
-
- if (GST_BUFFER_IS_DISCONT (buffer)) {
- ogg_sync_reset (&ogg->sync);
- ogg->discont = TRUE;
- }
-
- /* write data to sync layer */
- oggbuf = ogg_sync_buffer (&ogg->sync, size);
- memcpy (oggbuf, data, size);
- ogg_sync_wrote (&ogg->sync, size);
- gst_buffer_unref (buffer);
-
- /* try to get as many packets out of the stream as possible */
- do {
- ogg_page page;
-
- /* try to swap out a page */
- ret = ogg_sync_pageout (&ogg->sync, &page);
- if (ret == 0) {
- GST_DEBUG_OBJECT (ogg, "need more data");
- break;
- } else if (ret == -1) {
- GST_DEBUG_OBJECT (ogg, "discont in pages");
- ogg->discont = TRUE;
- } else {
- /* new unknown stream, init the ogg stream with the serial number of the
- * page. */
- if (ogg->serial == -1) {
- ogg->serial = ogg_page_serialno (&page);
- ogg_stream_init (&ogg->stream, ogg->serial);
- }
-
- /* submit page */
- if (ogg_stream_pagein (&ogg->stream, &page) != 0) {
- GST_WARNING_OBJECT (ogg, "ogg stream choked on page resetting stream");
- ogg_sync_reset (&ogg->sync);
- ogg->discont = TRUE;
- continue;
- }
-
- /* try to get as many packets as possible out of the page */
- do {
- ogg_packet packet;
-
- ret = ogg_stream_packetout (&ogg->stream, &packet);
- GST_LOG_OBJECT (ogg, "packetout gave %d", ret);
- switch (ret) {
- case 0:
- break;
- case -1:
- /* out of sync, We mark a DISCONT. */
- ogg->discont = TRUE;
- break;
- case 1:
- result = gst_ogg_avi_parse_push_packet (ogg, &packet);
- if (GST_FLOW_IS_FATAL (result))
- goto done;
- break;
- default:
- GST_WARNING_OBJECT (ogg,
- "invalid return value %d for ogg_stream_packetout, resetting stream",
- ret);
- break;
- }
- }
- while (ret != 0);
- }
- }
- while (ret != 0);
-
-done:
- return result;
-}
-
-static GstStateChangeReturn
-gst_ogg_avi_parse_change_state (GstElement * element, GstStateChange transition)
-{
- GstOggAviParse *ogg;
- GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
-
- ogg = GST_OGG_AVI_PARSE (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- ogg_sync_init (&ogg->sync);
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- ogg_sync_reset (&ogg->sync);
- ogg_stream_reset (&ogg->stream);
- ogg->serial = -1;
- ogg->discont = TRUE;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- result = parent_class->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- ogg_sync_clear (&ogg->sync);
- break;
- default:
- break;
- }
- return result;
-}
-
-gboolean
-gst_ogg_avi_parse_plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (gst_ogg_avi_parse_debug, "oggaviparse", 0,
- "ogg avi parser");
-
- return gst_element_register (plugin, "oggaviparse", GST_RANK_PRIMARY,
- GST_TYPE_OGG_AVI_PARSE);
-}
diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c
deleted file mode 100644
index d8f00efb..00000000
--- a/ext/ogg/gstoggdemux.c
+++ /dev/null
@@ -1,3366 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
- *
- * gstoggdemux.c: ogg stream demuxer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-oggdemux
- * @see_also: <link linkend="gst-plugins-base-plugins-oggmux">oggmux</link>
- *
- * This element demuxes ogg files into their encoded audio and video components.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v filesrc location=test.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink
- * ]| Decodes the vorbis audio stored inside an ogg container.
- * </refsect2>
- *
- * Last reviewed on 2006-12-30 (0.10.5)
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <string.h>
-#include <gst/gst-i18n-plugin.h>
-#include <gst/tag/tag.h>
-
-#include "gstoggdemux.h"
-
-static const GstElementDetails gst_ogg_demux_details =
-GST_ELEMENT_DETAILS ("Ogg demuxer",
- "Codec/Demuxer",
- "demux ogg streams (info about ogg: http://xiph.org)",
- "Wim Taymans <wim@fluendo.com>");
-
-#define CHUNKSIZE (8500) /* this is out of vorbisfile */
-#define SKELETON_FISHEAD_SIZE 64
-#define SKELETON_FISBONE_MIN_SIZE 52
-
-#define GST_FLOW_LIMIT GST_FLOW_CUSTOM_ERROR
-
-#define GST_CHAIN_LOCK(ogg) g_mutex_lock((ogg)->chain_lock)
-#define GST_CHAIN_UNLOCK(ogg) g_mutex_unlock((ogg)->chain_lock)
-
-GST_DEBUG_CATEGORY (gst_ogg_demux_debug);
-GST_DEBUG_CATEGORY (gst_ogg_demux_setup_debug);
-#define GST_CAT_DEFAULT gst_ogg_demux_debug
-
-
-static ogg_packet *
-_ogg_packet_copy (const ogg_packet * packet)
-{
- ogg_packet *ret = g_new0 (ogg_packet, 1);
-
- *ret = *packet;
- ret->packet = g_memdup (packet->packet, packet->bytes);
-
- return ret;
-}
-
-static void
-_ogg_packet_free (ogg_packet * packet)
-{
- g_free (packet->packet);
- g_free (packet);
-}
-
-static ogg_page *
-gst_ogg_page_copy (ogg_page * page)
-{
- ogg_page *p = g_new0 (ogg_page, 1);
-
- /* make a copy of the page */
- p->header = g_memdup (page->header, page->header_len);
- p->header_len = page->header_len;
- p->body = g_memdup (page->body, page->body_len);
- p->body_len = page->body_len;
-
- return p;
-}
-
-static void
-gst_ogg_page_free (ogg_page * page)
-{
- g_free (page->header);
- g_free (page->body);
- g_free (page);
-}
-
-static gboolean gst_ogg_demux_collect_chain_info (GstOggDemux * ogg,
- GstOggChain * chain);
-static gboolean gst_ogg_demux_activate_chain (GstOggDemux * ogg,
- GstOggChain * chain, GstEvent * event);
-static void gst_ogg_chain_mark_discont (GstOggChain * chain);
-
-static gboolean gst_ogg_demux_perform_seek (GstOggDemux * ogg,
- GstEvent * event);
-static gboolean gst_ogg_demux_receive_event (GstElement * element,
- GstEvent * event);
-
-static void gst_ogg_pad_class_init (GstOggPadClass * klass);
-static void gst_ogg_pad_init (GstOggPad * pad);
-static void gst_ogg_pad_dispose (GObject * object);
-static void gst_ogg_pad_finalize (GObject * object);
-
-static const GstQueryType *gst_ogg_pad_query_types (GstPad * pad);
-static gboolean gst_ogg_pad_src_query (GstPad * pad, GstQuery * query);
-static gboolean gst_ogg_pad_event (GstPad * pad, GstEvent * event);
-static GstCaps *gst_ogg_pad_getcaps (GstPad * pad);
-static GstOggPad *gst_ogg_chain_get_stream (GstOggChain * chain,
- glong serialno);
-
-static GstFlowReturn gst_ogg_demux_combine_flows (GstOggDemux * ogg,
- GstOggPad * pad, GstFlowReturn ret);
-static void gst_ogg_demux_sync_streams (GstOggDemux * ogg);
-
-G_DEFINE_TYPE (GstOggPad, gst_ogg_pad, GST_TYPE_PAD);
-
-static void
-gst_ogg_pad_class_init (GstOggPadClass * klass)
-{
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
-
- gobject_class->dispose = gst_ogg_pad_dispose;
- gobject_class->finalize = gst_ogg_pad_finalize;
-}
-
-static void
-gst_ogg_pad_init (GstOggPad * pad)
-{
- gst_pad_set_event_function (GST_PAD (pad),
- GST_DEBUG_FUNCPTR (gst_ogg_pad_event));
- gst_pad_set_getcaps_function (GST_PAD (pad),
- GST_DEBUG_FUNCPTR (gst_ogg_pad_getcaps));
- gst_pad_set_query_type_function (GST_PAD (pad),
- GST_DEBUG_FUNCPTR (gst_ogg_pad_query_types));
- gst_pad_set_query_function (GST_PAD (pad),
- GST_DEBUG_FUNCPTR (gst_ogg_pad_src_query));
-
- pad->mode = GST_OGG_PAD_MODE_INIT;
-
- pad->current_granule = -1;
- pad->keyframe_granule = -1;
-
- pad->start_time = GST_CLOCK_TIME_NONE;
-
- pad->last_stop = GST_CLOCK_TIME_NONE;
-
- pad->have_type = FALSE;
- pad->continued = NULL;
- pad->map.headers = NULL;
- pad->map.queued = NULL;
-}
-
-static void
-gst_ogg_pad_dispose (GObject * object)
-{
- GstOggPad *pad = GST_OGG_PAD (object);
-
- pad->chain = NULL;
- pad->ogg = NULL;
-
- g_list_foreach (pad->map.headers, (GFunc) _ogg_packet_free, NULL);
- g_list_free (pad->map.headers);
- pad->map.headers = NULL;
- g_list_foreach (pad->map.queued, (GFunc) _ogg_packet_free, NULL);
- g_list_free (pad->map.queued);
- pad->map.queued = NULL;
-
- /* clear continued pages */
- g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
- g_list_free (pad->continued);
- pad->continued = NULL;
-
- ogg_stream_reset (&pad->map.stream);
-
- G_OBJECT_CLASS (gst_ogg_pad_parent_class)->dispose (object);
-}
-
-static void
-gst_ogg_pad_finalize (GObject * object)
-{
- GstOggPad *pad = GST_OGG_PAD (object);
-
- ogg_stream_clear (&pad->map.stream);
-
- G_OBJECT_CLASS (gst_ogg_pad_parent_class)->finalize (object);
-}
-
-static const GstQueryType *
-gst_ogg_pad_query_types (GstPad * pad)
-{
- static const GstQueryType query_types[] = {
- GST_QUERY_DURATION,
- GST_QUERY_SEEKING,
- 0
- };
-
- return query_types;
-}
-
-static GstCaps *
-gst_ogg_pad_getcaps (GstPad * pad)
-{
- return gst_caps_ref (GST_PAD_CAPS (pad));
-}
-
-static gboolean
-gst_ogg_pad_src_query (GstPad * pad, GstQuery * query)
-{
- gboolean res = TRUE;
- GstOggDemux *ogg;
-
- ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_DURATION:
- {
- GstFormat format;
- gint64 total_time;
-
- gst_query_parse_duration (query, &format, NULL);
- /* can only get position in time */
- if (format != GST_FORMAT_TIME)
- goto wrong_format;
-
- if (ogg->pullmode) {
- /* we must return the total length */
- total_time = ogg->total_time;
- } else {
- /* in push mode we can answer the query and we must return -1 */
- total_time = -1;
- }
-
- gst_query_set_duration (query, GST_FORMAT_TIME, total_time);
- break;
- }
- case GST_QUERY_SEEKING:
- {
- GstFormat format;
-
- gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
- if (format == GST_FORMAT_TIME) {
- gst_query_set_seeking (query, GST_FORMAT_TIME, ogg->pullmode,
- 0, ogg->total_time);
- } else {
- res = FALSE;
- }
- break;
- }
-
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-done:
- gst_object_unref (ogg);
-
- return res;
-
- /* ERRORS */
-wrong_format:
- {
- GST_DEBUG_OBJECT (ogg, "only query duration on TIME is supported");
- res = FALSE;
- goto done;
- }
-}
-
-static gboolean
-gst_ogg_demux_receive_event (GstElement * element, GstEvent * event)
-{
- gboolean res;
- GstOggDemux *ogg;
-
- ogg = GST_OGG_DEMUX (element);
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- /* can't seek if we are not pullmode, FIXME could pass the
- * seek query upstream after converting it to bytes using
- * the average bitrate of the stream. */
- if (!ogg->pullmode) {
- GST_DEBUG_OBJECT (ogg, "seek on pull mode stream not implemented yet");
- goto error;
- }
-
- /* now do the seek */
- res = gst_ogg_demux_perform_seek (ogg, event);
- gst_event_unref (event);
- break;
- default:
- GST_DEBUG_OBJECT (ogg, "We only handle seek events here");
- goto error;
- }
-
- return res;
-
- /* ERRORS */
-error:
- {
- GST_DEBUG_OBJECT (ogg, "error handling event");
- gst_event_unref (event);
- return FALSE;
- }
-}
-
-static gboolean
-gst_ogg_pad_event (GstPad * pad, GstEvent * event)
-{
- gboolean res;
- GstOggDemux *ogg;
-
- ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- /* can't seek if we are not pullmode, FIXME could pass the
- * seek query upstream after converting it to bytes using
- * the average bitrate of the stream. */
- if (!ogg->pullmode) {
- GST_DEBUG_OBJECT (ogg, "seek on pull mode stream not implemented yet");
- goto error;
- }
-
- /* now do the seek */
- res = gst_ogg_demux_perform_seek (ogg, event);
- gst_event_unref (event);
- break;
- default:
- res = gst_pad_event_default (pad, event);
- break;
- }
-done:
- gst_object_unref (ogg);
-
- return res;
-
- /* ERRORS */
-error:
- {
- GST_DEBUG_OBJECT (ogg, "error handling event");
- gst_event_unref (event);
- res = FALSE;
- goto done;
- }
-}
-
-static void
-gst_ogg_pad_reset (GstOggPad * pad)
-{
- ogg_stream_reset (&pad->map.stream);
-
- GST_DEBUG_OBJECT (pad, "doing reset");
-
- /* clear continued pages */
- g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
- g_list_free (pad->continued);
- pad->continued = NULL;
-
- pad->last_ret = GST_FLOW_OK;
- pad->last_stop = GST_CLOCK_TIME_NONE;
- pad->current_granule = -1;
- pad->keyframe_granule = -1;
-}
-
-/* called when the skeleton fishead is found. Caller ensures the packet is
- * precisely the correct size; we don't re-check this here. */
-static void
-gst_ogg_pad_parse_skeleton_fishead (GstOggPad * pad, ogg_packet * packet)
-{
- GstOggDemux *ogg = pad->ogg;
- guint8 *data = packet->packet;
- guint16 major, minor;
- gint64 prestime_n, prestime_d;
- gint64 basetime_n, basetime_d;
-
- /* skip "fishead\0" */
- major = GST_READ_UINT16_LE (data + 8);
- minor = GST_READ_UINT16_LE (data + 10);
- prestime_n = (gint64) GST_READ_UINT64_LE (data + 12);
- prestime_d = (gint64) GST_READ_UINT64_LE (data + 20);
- basetime_n = (gint64) GST_READ_UINT64_LE (data + 28);
- basetime_d = (gint64) GST_READ_UINT64_LE (data + 36);
-
- ogg->basetime = gst_util_uint64_scale (GST_SECOND, basetime_n, basetime_d);
- ogg->prestime = gst_util_uint64_scale (GST_SECOND, prestime_n, prestime_d);
- ogg->have_fishead = TRUE;
- pad->map.is_skeleton = TRUE;
- pad->start_time = GST_CLOCK_TIME_NONE;
- GST_INFO_OBJECT (ogg, "skeleton fishead parsed (basetime: %"
- GST_TIME_FORMAT ", prestime: %" GST_TIME_FORMAT ")",
- GST_TIME_ARGS (ogg->basetime), GST_TIME_ARGS (ogg->prestime));
-}
-
-/* function called when a skeleton fisbone is found. Caller ensures that
- * the packet length is sufficient */
-static void
-gst_ogg_pad_parse_skeleton_fisbone (GstOggPad * pad, ogg_packet * packet)
-{
- GstOggPad *fisbone_pad;
- gint64 start_granule;
- guint32 serialno;
- guint8 *data = packet->packet;
-
- serialno = GST_READ_UINT32_LE (data + 12);
-
- fisbone_pad = gst_ogg_chain_get_stream (pad->chain, serialno);
- if (fisbone_pad) {
- if (fisbone_pad->map.have_fisbone)
- /* already parsed */
- return;
-
- fisbone_pad->map.have_fisbone = TRUE;
-
- fisbone_pad->map.granulerate_n = GST_READ_UINT64_LE (data + 20);
- fisbone_pad->map.granulerate_d = GST_READ_UINT64_LE (data + 28);
- start_granule = GST_READ_UINT64_LE (data + 36);
- fisbone_pad->map.preroll = GST_READ_UINT32_LE (data + 44);
- fisbone_pad->map.granuleshift = GST_READ_UINT8 (data + 48);
-
- GST_INFO_OBJECT (pad->ogg, "skeleton fisbone parsed "
- "(serialno: %08x start time: %" GST_TIME_FORMAT
- " granulerate_n: %d granulerate_d: %d "
- " preroll: %" G_GUINT32_FORMAT " granuleshift: %d)",
- serialno, GST_TIME_ARGS (fisbone_pad->start_time),
- fisbone_pad->map.granulerate_n, fisbone_pad->map.granulerate_d,
- fisbone_pad->map.preroll, fisbone_pad->map.granuleshift);
- } else {
- GST_WARNING_OBJECT (pad->ogg,
- "found skeleton fisbone for an unknown stream %" G_GUINT32_FORMAT,
- serialno);
- }
-}
-
-/* queue data, basically takes the packet, puts it in a buffer and store the
- * buffer in the queued list. */
-static GstFlowReturn
-gst_ogg_demux_queue_data (GstOggPad * pad, ogg_packet * packet)
-{
-#ifndef GST_DISABLE_GST_DEBUG
- GstOggDemux *ogg = pad->ogg;
-#endif
-
- GST_DEBUG_OBJECT (ogg, "%p queueing data serial %08lx", pad,
- pad->map.serialno);
-
- pad->map.queued = g_list_append (pad->map.queued, _ogg_packet_copy (packet));
-
- /* we are ok now */
- return GST_FLOW_OK;
-}
-
-static GstFlowReturn
-gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
- gboolean push_headers)
-{
- GstBuffer *buf = NULL;
- GstFlowReturn ret, cret;
- GstOggDemux *ogg = pad->ogg;
- gint64 current_time;
- GstOggChain *chain;
- gint64 duration;
- gint offset;
- gint trim;
- GstClockTime out_timestamp, out_duration;
- guint64 out_offset, out_offset_end;
- gboolean delta_unit = FALSE;
-
- GST_DEBUG_OBJECT (ogg,
- "%p streaming to peer serial %08lx", pad, pad->map.serialno);
-
- if (pad->map.is_ogm) {
- const guint8 *data;
- long bytes;
-
- data = packet->packet;
- bytes = packet->bytes;
-
- if (bytes < 1)
- goto empty_packet;
-
- if (data[0] & 1) {
- /* We don't push header packets for OGM */
- cret = gst_ogg_demux_combine_flows (ogg, pad, GST_FLOW_OK);
- goto done;
- } else if (data[0] & 3 && pad->map.is_ogm_text) {
- GstTagList *tags;
-
- /* We don't push comment packets either for text streams,
- * other streams will handle the comment packets in the
- * decoder */
- buf = gst_buffer_new ();
-
- GST_BUFFER_DATA (buf) = (guint8 *) data;
- GST_BUFFER_SIZE (buf) = bytes;
-
- tags = gst_tag_list_from_vorbiscomment_buffer (buf,
- (guint8 *) "\003vorbis", 7, NULL);
- gst_buffer_unref (buf);
- buf = NULL;
-
- if (tags) {
- GST_DEBUG_OBJECT (ogg, "tags = %" GST_PTR_FORMAT, tags);
- gst_element_found_tags_for_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad),
- tags);
- } else {
- GST_DEBUG_OBJECT (ogg, "failed to extract tags from vorbis comment");
- }
-
- cret = gst_ogg_demux_combine_flows (ogg, pad, GST_FLOW_OK);
- goto done;
- }
-
- offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
- delta_unit = (((data[0] & 0x08) >> 3) == 0);
-
- trim = 0;
-
- /* Strip trailing \0 for subtitles */
- if (pad->map.is_ogm_text) {
- while (bytes && data[bytes - 1] == 0) {
- trim++;
- bytes--;
- }
- }
- } else {
- offset = 0;
- trim = 0;
- }
-
- /* get timing info for the packet */
- duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
- GST_DEBUG_OBJECT (ogg, "packet duration %" G_GUINT64_FORMAT, duration);
-
- if (packet->b_o_s) {
- out_timestamp = GST_CLOCK_TIME_NONE;
- out_duration = GST_CLOCK_TIME_NONE;
- out_offset = 0;
- out_offset_end = -1;
- } else {
- if (packet->granulepos != -1) {
- pad->current_granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
- packet->granulepos);
- pad->keyframe_granule =
- gst_ogg_stream_granulepos_to_key_granule (&pad->map,
- packet->granulepos);
- GST_DEBUG_OBJECT (ogg, "new granule %" G_GUINT64_FORMAT,
- pad->current_granule);
- } else if (ogg->segment.rate > 0.0 && pad->current_granule != -1) {
- pad->current_granule += duration;
- GST_DEBUG_OBJECT (ogg, "interpollating granule %" G_GUINT64_FORMAT,
- pad->current_granule);
- }
- if (ogg->segment.rate < 0.0 && packet->granulepos == -1) {
- /* negative rates, only set timestamp on the packets with a granulepos */
- out_timestamp = -1;
- out_duration = -1;
- out_offset = -1;
- out_offset_end = -1;
- } else {
- /* we only push buffers after we have a valid granule. This is done so that
- * we nicely skip packets without a timestamp after a seek. This is ok
- * because we base or seek on the packet after the page with the smaller
- * timestamp. */
- if (pad->current_granule == -1)
- goto no_timestamp;
-
- if (pad->map.is_ogm) {
- out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
- pad->current_granule);
- out_duration = gst_util_uint64_scale (duration,
- GST_SECOND * pad->map.granulerate_d, pad->map.granulerate_n);
- } else if (pad->is_sparse) {
- out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
- pad->current_granule);
- out_duration = GST_CLOCK_TIME_NONE;
- } else {
- out_timestamp = gst_ogg_stream_granule_to_time (&pad->map,
- pad->current_granule - duration);
- out_duration =
- gst_ogg_stream_granule_to_time (&pad->map,
- pad->current_granule) - out_timestamp;
- }
- out_offset_end =
- gst_ogg_stream_granule_to_granulepos (&pad->map, pad->current_granule,
- pad->keyframe_granule);
- out_offset =
- gst_ogg_stream_granule_to_time (&pad->map, pad->current_granule);
- }
- }
-
- /* check for invalid buffer sizes */
- if (G_UNLIKELY (offset + trim >= packet->bytes))
- goto empty_packet;
-
- ret =
- gst_pad_alloc_buffer_and_set_caps (GST_PAD_CAST (pad),
- GST_BUFFER_OFFSET_NONE, packet->bytes - offset - trim,
- GST_PAD_CAPS (pad), &buf);
-
- /* combine flows */
- cret = gst_ogg_demux_combine_flows (ogg, pad, ret);
- if (ret != GST_FLOW_OK)
- goto no_buffer;
-
- /* set delta flag for OGM content */
- if (delta_unit)
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
-
- /* copy packet in buffer */
- memcpy (buf->data, packet->packet + offset, packet->bytes - offset - trim);
-
- GST_BUFFER_TIMESTAMP (buf) = out_timestamp;
- GST_BUFFER_DURATION (buf) = out_duration;
- GST_BUFFER_OFFSET (buf) = out_offset;
- GST_BUFFER_OFFSET_END (buf) = out_offset_end;
-
- /* Mark discont on the buffer */
- if (pad->discont) {
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
- pad->discont = FALSE;
- }
-
- pad->last_stop = ogg->segment.last_stop;
-
- /* don't push the header packets when we are asked to skip them */
- if (!packet->b_o_s || push_headers) {
- ret = gst_pad_push (GST_PAD_CAST (pad), buf);
- buf = NULL;
-
- /* combine flows */
- cret = gst_ogg_demux_combine_flows (ogg, pad, ret);
- }
-
- /* we're done with skeleton stuff */
- if (pad->map.is_skeleton)
- goto done;
-
- /* check if valid granulepos, then we can calculate the current
- * position. We know the granule for each packet but we only want to update
- * the last_stop when we have a valid granulepos on the packet because else
- * our time jumps around for the different streams. */
- if (packet->granulepos < 0)
- goto done;
-
- /* convert to time */
- current_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
- packet->granulepos);
-
- /* convert to stream time */
- if ((chain = pad->chain)) {
- gint64 chain_start = 0;
-
- if (chain->segment_start != GST_CLOCK_TIME_NONE)
- chain_start = chain->segment_start;
-
- current_time = current_time - chain_start + chain->begin_time;
- }
-
- /* and store as the current position */
- gst_segment_set_last_stop (&ogg->segment, GST_FORMAT_TIME, current_time);
-
- GST_DEBUG_OBJECT (ogg, "ogg current time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (current_time));
-
-done:
- if (buf)
- gst_buffer_unref (buf);
- /* return combined flow result */
- return cret;
-
- /* special cases */
-empty_packet:
- {
- GST_DEBUG_OBJECT (ogg, "Skipping empty packet");
- cret = gst_ogg_demux_combine_flows (ogg, pad, GST_FLOW_OK);
- goto done;
- }
-no_timestamp:
- {
- GST_DEBUG_OBJECT (ogg, "skipping packet: no valid granule found yet");
- cret = gst_ogg_demux_combine_flows (ogg, pad, GST_FLOW_OK);
- goto done;
- }
-no_buffer:
- {
- GST_DEBUG_OBJECT (ogg,
- "%p could not get buffer from peer %08lx, %d (%s), combined %d (%s)",
- pad, pad->map.serialno, ret, gst_flow_get_name (ret),
- cret, gst_flow_get_name (cret));
- goto done;
- }
-}
-
-/* submit a packet to the oggpad, this function will run the
- * typefind code for the pad if this is the first packet for this
- * stream
- */
-static GstFlowReturn
-gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
-{
- gint64 granule;
- GstFlowReturn ret = GST_FLOW_OK;
-
- GstOggDemux *ogg = pad->ogg;
-
- GST_DEBUG_OBJECT (ogg, "%p submit packet serial %08lx", pad,
- pad->map.serialno);
-
- if (!pad->have_type) {
- if (!ogg->have_fishead && packet->bytes == SKELETON_FISHEAD_SIZE &&
- !memcmp (packet->packet, "fishead\0", 8)) {
- gst_ogg_pad_parse_skeleton_fishead (pad, packet);
- }
- pad->have_type = gst_ogg_stream_setup_map (&pad->map, packet);
- if (!pad->have_type) {
- pad->map.caps = gst_caps_new_simple ("application/x-unknown", NULL);
- }
- if (pad->map.caps) {
- gst_pad_set_caps (GST_PAD (pad), pad->map.caps);
- } else {
- GST_WARNING_OBJECT (ogg, "stream parser didn't create src pad caps");
- }
- }
-
- if (ogg->have_fishead && packet->bytes >= SKELETON_FISBONE_MIN_SIZE &&
- !memcmp (packet->packet, "fisbone\0", 8)) {
- gst_ogg_pad_parse_skeleton_fisbone (pad, packet);
- }
-
- granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
- packet->granulepos);
- if (granule != -1) {
- GST_DEBUG_OBJECT (ogg, "%p has granulepos %" G_GINT64_FORMAT, pad, granule);
- pad->current_granule = granule;
- }
-
- /* restart header packet count when seeing a b_o_s page;
- * particularly useful following a seek or even following chain finding */
- if (packet->b_o_s) {
- GST_DEBUG_OBJECT (ogg, "b_o_s packet, resetting header packet count");
- pad->map.n_header_packets_seen = 0;
- if (!pad->map.have_headers) {
- GST_DEBUG_OBJECT (ogg, "clearing header packets");
- g_list_foreach (pad->map.headers, (GFunc) _ogg_packet_free, NULL);
- g_list_free (pad->map.headers);
- pad->map.headers = NULL;
- }
- }
-
- /* Overload the value of b_o_s in ogg_packet with a flag whether or
- * not this is a header packet. Maybe some day this could be cleaned
- * up. */
- packet->b_o_s = gst_ogg_stream_packet_is_header (&pad->map, packet);
- if (!packet->b_o_s) {
- pad->map.have_headers = TRUE;
- if (pad->start_time == GST_CLOCK_TIME_NONE) {
- gint64 duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
- GST_DEBUG ("duration %" G_GINT64_FORMAT, duration);
- if (duration != -1) {
- pad->map.accumulated_granule += duration;
- GST_DEBUG ("accumulated granule %" G_GINT64_FORMAT,
- pad->map.accumulated_granule);
- }
-
- if (packet->granulepos != -1) {
- ogg_int64_t start_granule;
- gint64 granule;
-
- granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
- packet->granulepos);
-
- if (granule > pad->map.accumulated_granule)
- start_granule = granule - pad->map.accumulated_granule;
- else
- start_granule = 0;
-
- pad->start_time = gst_ogg_stream_granule_to_time (&pad->map,
- start_granule);
- GST_DEBUG ("start time %" G_GINT64_FORMAT, pad->start_time);
- } else {
- packet->granulepos = gst_ogg_stream_granule_to_granulepos (&pad->map,
- pad->map.accumulated_granule, pad->keyframe_granule);
- }
- }
- } else {
- pad->map.n_header_packets_seen++;
- if (!pad->map.have_headers) {
- pad->map.headers =
- g_list_append (pad->map.headers, _ogg_packet_copy (packet));
- GST_DEBUG ("keeping header packet %d", pad->map.n_header_packets_seen);
- }
- }
-
- /* we know the start_time of the pad data, see if we
- * can activate the complete chain if this is a dynamic
- * chain. */
- if (pad->start_time != GST_CLOCK_TIME_NONE) {
- GstOggChain *chain = pad->chain;
-
- /* check if complete chain has start time */
- if (chain == ogg->building_chain) {
-
- /* see if we have enough info to activate the chain, we have enough info
- * when all streams have a valid start time. */
- if (gst_ogg_demux_collect_chain_info (ogg, chain)) {
- GstEvent *event;
-
- GST_DEBUG_OBJECT (ogg, "segment_start: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (chain->segment_start));
- GST_DEBUG_OBJECT (ogg, "segment_stop: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (chain->segment_stop));
- GST_DEBUG_OBJECT (ogg, "segment_time: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (chain->begin_time));
-
- /* create the newsegment event we are going to send out */
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- GST_FORMAT_TIME, chain->segment_start, chain->segment_stop,
- chain->begin_time);
- gst_event_set_seqnum (event, ogg->seqnum);
-
- gst_ogg_demux_activate_chain (ogg, chain, event);
-
- ogg->building_chain = NULL;
- }
- }
- }
-
- /* if we are building a chain, store buffer for when we activate
- * it. This path is taken if we operate in streaming mode. */
- if (ogg->building_chain) {
- /* bos packets where stored in the header list so we can discard
- * them here*/
- if (!packet->b_o_s)
- ret = gst_ogg_demux_queue_data (pad, packet);
- }
- /* else we are completely streaming to the peer */
- else {
- ret = gst_ogg_demux_chain_peer (pad, packet, !ogg->pullmode);
- }
- return ret;
-}
-
-/* flush at most @npackets from the stream layer. All packets if
- * @npackets is 0;
- */
-static GstFlowReturn
-gst_ogg_pad_stream_out (GstOggPad * pad, gint npackets)
-{
- GstFlowReturn result = GST_FLOW_OK;
- gboolean done = FALSE;
- GstOggDemux *ogg;
-
- ogg = pad->ogg;
-
- while (!done) {
- int ret;
- ogg_packet packet;
-
- ret = ogg_stream_packetout (&pad->map.stream, &packet);
- switch (ret) {
- case 0:
- GST_LOG_OBJECT (ogg, "packetout done");
- done = TRUE;
- break;
- case -1:
- GST_LOG_OBJECT (ogg, "packetout discont");
- gst_ogg_chain_mark_discont (pad->chain);
- break;
- case 1:
- GST_LOG_OBJECT (ogg, "packetout gave packet of size %ld", packet.bytes);
- result = gst_ogg_pad_submit_packet (pad, &packet);
- if (GST_FLOW_IS_FATAL (result))
- goto could_not_submit;
- break;
- default:
- GST_WARNING_OBJECT (ogg,
- "invalid return value %d for ogg_stream_packetout, resetting stream",
- ret);
- gst_ogg_pad_reset (pad);
- break;
- }
- if (npackets > 0) {
- npackets--;
- done = (npackets == 0);
- }
- }
- return result;
-
- /* ERRORS */
-could_not_submit:
- {
- GST_WARNING_OBJECT (ogg,
- "could not submit packet for stream %08lx, error: %d",
- pad->map.serialno, result);
- gst_ogg_pad_reset (pad);
- return result;
- }
-}
-
-/* submit a page to an oggpad, this function will then submit all
- * the packets in the page.
- */
-static GstFlowReturn
-gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page)
-{
- GstFlowReturn result = GST_FLOW_OK;
- GstOggDemux *ogg;
- gboolean continued = FALSE;
-
- ogg = pad->ogg;
-
- /* for negative rates we read pages backwards and must therefore be carefull
- * with continued pages */
- if (ogg->segment.rate < 0.0) {
- gint npackets;
-
- continued = ogg_page_continued (page);
-
- /* number of completed packets in the page */
- npackets = ogg_page_packets (page);
- if (!continued) {
- /* page is not continued so it contains at least one packet start. It's
- * possible that no packet ends on this page (npackets == 0). In that
- * case, the next (continued) page(s) we kept contain the remainder of the
- * packets. We mark npackets=1 to make us start decoding the pages in the
- * remainder of the algorithm. */
- if (npackets == 0)
- npackets = 1;
- }
- GST_LOG_OBJECT (ogg, "continued: %d, %d packets", continued, npackets);
-
- if (npackets == 0) {
- GST_LOG_OBJECT (ogg, "no decodable packets, we need a previous page");
- goto done;
- }
- }
-
- if (ogg_stream_pagein (&pad->map.stream, page) != 0)
- goto choked;
-
- /* flush all packets in the stream layer, this might not give a packet if
- * the page had no packets finishing on the page (npackets == 0). */
- result = gst_ogg_pad_stream_out (pad, 0);
-
- if (pad->continued) {
- ogg_packet packet;
-
- /* now send the continued pages to the stream layer */
- while (pad->continued) {
- ogg_page *p = (ogg_page *) pad->continued->data;
-
- GST_LOG_OBJECT (ogg, "submitting continued page %p", p);
- if (ogg_stream_pagein (&pad->map.stream, p) != 0)
- goto choked;
-
- pad->continued = g_list_delete_link (pad->continued, pad->continued);
-
- /* free the page */
- gst_ogg_page_free (p);
- }
-
- GST_LOG_OBJECT (ogg, "flushing last continued packet");
- /* flush 1 continued packet in the stream layer */
- result = gst_ogg_pad_stream_out (pad, 1);
-
- /* flush all remaining packets, we pushed them in the previous round.
- * We don't use _reset() because we still want to get the discont when
- * we submit a next page. */
- while (ogg_stream_packetout (&pad->map.stream, &packet) != 0);
- }
-
-done:
- /* keep continued pages (only in reverse mode) */
- if (continued) {
- ogg_page *p = gst_ogg_page_copy (page);
-
- GST_LOG_OBJECT (ogg, "keeping continued page %p", p);
- pad->continued = g_list_prepend (pad->continued, p);
- }
-
- return result;
-
-choked:
- {
- GST_WARNING_OBJECT (ogg,
- "ogg stream choked on page (serial %08lx), resetting stream",
- pad->map.serialno);
- gst_ogg_pad_reset (pad);
- /* we continue to recover */
- return GST_FLOW_OK;
- }
-}
-
-
-static GstOggChain *
-gst_ogg_chain_new (GstOggDemux * ogg)
-{
- GstOggChain *chain = g_new0 (GstOggChain, 1);
-
- GST_DEBUG_OBJECT (ogg, "creating new chain %p", chain);
- chain->ogg = ogg;
- chain->offset = -1;
- chain->bytes = -1;
- chain->have_bos = FALSE;
- chain->streams = g_array_new (FALSE, TRUE, sizeof (GstOggPad *));
- chain->begin_time = GST_CLOCK_TIME_NONE;
- chain->segment_start = GST_CLOCK_TIME_NONE;
- chain->segment_stop = GST_CLOCK_TIME_NONE;
- chain->total_time = GST_CLOCK_TIME_NONE;
-
- return chain;
-}
-
-static void
-gst_ogg_chain_free (GstOggChain * chain)
-{
- gint i;
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- gst_object_unref (pad);
- }
- g_array_free (chain->streams, TRUE);
- g_free (chain);
-}
-
-static void
-gst_ogg_chain_mark_discont (GstOggChain * chain)
-{
- gint i;
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- pad->discont = TRUE;
- pad->map.last_size = 0;
- }
-}
-
-static void
-gst_ogg_chain_reset (GstOggChain * chain)
-{
- gint i;
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- gst_ogg_pad_reset (pad);
- }
-}
-
-static GstOggPad *
-gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno)
-{
- GstOggPad *ret;
- GstTagList *list;
- gchar *name;
-
- GST_DEBUG_OBJECT (chain->ogg, "creating new stream %08lx in chain %p",
- serialno, chain);
-
- ret = g_object_new (GST_TYPE_OGG_PAD, NULL);
- /* we own this one */
- gst_object_ref (ret);
- gst_object_sink (ret);
-
- GST_PAD_DIRECTION (ret) = GST_PAD_SRC;
- ret->discont = TRUE;
- ret->map.last_size = 0;
-
- ret->chain = chain;
- ret->ogg = chain->ogg;
-
- ret->map.serialno = serialno;
- if (ogg_stream_init (&ret->map.stream, serialno) != 0)
- goto init_failed;
-
- name = g_strdup_printf ("serial_%08lx", serialno);
- gst_object_set_name (GST_OBJECT (ret), name);
- g_free (name);
-
- /* FIXME: either do something with it or remove it */
- list = gst_tag_list_new ();
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_SERIAL, serialno,
- NULL);
- gst_tag_list_free (list);
-
- GST_DEBUG_OBJECT (chain->ogg,
- "created new ogg src %p for stream with serial %08lx", ret, serialno);
-
- g_array_append_val (chain->streams, ret);
-
- return ret;
-
- /* ERRORS */
-init_failed:
- {
- GST_ERROR ("Could not initialize ogg_stream struct for serial %08lx.",
- serialno);
- gst_object_unref (ret);
- return NULL;
- }
-}
-
-static GstOggPad *
-gst_ogg_chain_get_stream (GstOggChain * chain, glong serialno)
-{
- gint i;
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- if (pad->map.serialno == serialno)
- return pad;
- }
- return NULL;
-}
-
-static gboolean
-gst_ogg_chain_has_stream (GstOggChain * chain, glong serialno)
-{
- return gst_ogg_chain_get_stream (chain, serialno) != NULL;
-}
-
-#define CURRENT_CHAIN(ogg) (&g_array_index ((ogg)->chains, GstOggChain, (ogg)->current_chain))
-
-/* signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
-enum
-{
- ARG_0
- /* FILL ME */
-};
-
-static GstStaticPadTemplate ogg_demux_src_template_factory =
-GST_STATIC_PAD_TEMPLATE ("src_%d",
- GST_PAD_SRC,
- GST_PAD_SOMETIMES,
- GST_STATIC_CAPS_ANY);
-
-static GstStaticPadTemplate ogg_demux_sink_template_factory =
- GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/ogg; application/x-annodex")
- );
-
-static void gst_ogg_demux_finalize (GObject * object);
-
-static GstFlowReturn gst_ogg_demux_read_chain (GstOggDemux * ogg,
- GstOggChain ** chain);
-static GstFlowReturn gst_ogg_demux_read_end_chain (GstOggDemux * ogg,
- GstOggChain * chain);
-
-static gboolean gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event);
-static void gst_ogg_demux_loop (GstOggPad * pad);
-static GstFlowReturn gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer);
-static gboolean gst_ogg_demux_sink_activate (GstPad * sinkpad);
-static gboolean gst_ogg_demux_sink_activate_pull (GstPad * sinkpad,
- gboolean active);
-static gboolean gst_ogg_demux_sink_activate_push (GstPad * sinkpad,
- gboolean active);
-static GstStateChangeReturn gst_ogg_demux_change_state (GstElement * element,
- GstStateChange transition);
-static void gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event);
-
-static void gst_ogg_print (GstOggDemux * demux);
-
-GST_BOILERPLATE (GstOggDemux, gst_ogg_demux, GstElement, GST_TYPE_ELEMENT);
-
-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_static_pad_template_get (&ogg_demux_sink_template_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&ogg_demux_src_template_factory));
-}
-
-static void
-gst_ogg_demux_class_init (GstOggDemuxClass * klass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gstelement_class->change_state = gst_ogg_demux_change_state;
- gstelement_class->send_event = gst_ogg_demux_receive_event;
-
- gobject_class->finalize = gst_ogg_demux_finalize;
-}
-
-static void
-gst_ogg_demux_init (GstOggDemux * ogg, GstOggDemuxClass * g_class)
-{
- /* create the sink pad */
- ogg->sinkpad =
- gst_pad_new_from_static_template (&ogg_demux_sink_template_factory,
- "sink");
-
- gst_pad_set_event_function (ogg->sinkpad, gst_ogg_demux_sink_event);
- gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_demux_chain);
- gst_pad_set_activate_function (ogg->sinkpad, gst_ogg_demux_sink_activate);
- gst_pad_set_activatepull_function (ogg->sinkpad,
- gst_ogg_demux_sink_activate_pull);
- gst_pad_set_activatepush_function (ogg->sinkpad,
- gst_ogg_demux_sink_activate_push);
- gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
-
- ogg->chain_lock = g_mutex_new ();
- ogg->chains = g_array_new (FALSE, TRUE, sizeof (GstOggChain *));
-
- ogg->newsegment = NULL;
-}
-
-static void
-gst_ogg_demux_finalize (GObject * object)
-{
- GstOggDemux *ogg;
-
- ogg = GST_OGG_DEMUX (object);
-
- g_array_free (ogg->chains, TRUE);
- g_mutex_free (ogg->chain_lock);
- ogg_sync_clear (&ogg->sync);
-
- if (ogg->newsegment)
- gst_event_unref (ogg->newsegment);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static gboolean
-gst_ogg_demux_sink_event (GstPad * pad, GstEvent * event)
-{
- gboolean res;
- GstOggDemux *ogg;
-
- ogg = GST_OGG_DEMUX (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
- /* FIXME */
- GST_DEBUG_OBJECT (ogg, "got a new segment event");
- ogg_sync_reset (&ogg->sync);
- gst_event_unref (event);
- res = TRUE;
- break;
- case GST_EVENT_EOS:
- {
- GST_DEBUG_OBJECT (ogg, "got an EOS event");
- res = gst_pad_event_default (pad, event);
- if (ogg->current_chain == NULL) {
- GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL),
- ("can't get first chain"));
- }
- break;
- }
- default:
- res = gst_pad_event_default (pad, event);
- break;
- }
- gst_object_unref (ogg);
-
- return res;
-}
-
-/* submit the given buffer to the ogg sync.
- *
- * Returns the number of bytes submited.
- */
-static GstFlowReturn
-gst_ogg_demux_submit_buffer (GstOggDemux * ogg, GstBuffer * buffer)
-{
- gint size;
- guint8 *data;
- gchar *oggbuffer;
- GstFlowReturn ret = GST_FLOW_OK;
-
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
-
- GST_DEBUG_OBJECT (ogg, "submitting %u bytes", size);
- if (G_UNLIKELY (size == 0))
- goto done;
-
- oggbuffer = ogg_sync_buffer (&ogg->sync, size);
- if (G_UNLIKELY (oggbuffer == NULL))
- goto no_buffer;
-
- memcpy (oggbuffer, data, size);
- if (G_UNLIKELY (ogg_sync_wrote (&ogg->sync, size) < 0))
- goto write_failed;
-
-done:
- gst_buffer_unref (buffer);
-
- return ret;
-
- /* ERRORS */
-no_buffer:
- {
- GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
- (NULL), ("failed to get ogg sync buffer"));
- ret = GST_FLOW_ERROR;
- goto done;
- }
-write_failed:
- {
- GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
- (NULL), ("failed to write %d bytes to the sync buffer", size));
- ret = GST_FLOW_ERROR;
- goto done;
- }
-}
-
-/* in random access mode this code updates the current read position
- * and resets the ogg sync buffer so that the next read will happen
- * from this new location.
- */
-static void
-gst_ogg_demux_seek (GstOggDemux * ogg, gint64 offset)
-{
- GST_LOG_OBJECT (ogg, "seeking to %" G_GINT64_FORMAT, offset);
-
- ogg->offset = offset;
- ogg->read_offset = offset;
- ogg_sync_reset (&ogg->sync);
-}
-
-/* read more data from the current offset and submit to
- * the ogg sync layer.
- */
-static GstFlowReturn
-gst_ogg_demux_get_data (GstOggDemux * ogg, gint64 end_offset)
-{
- GstFlowReturn ret;
- GstBuffer *buffer;
-
- GST_LOG_OBJECT (ogg,
- "get data %" G_GINT64_FORMAT " %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
- ogg->read_offset, ogg->length, end_offset);
-
- if (end_offset > 0 && ogg->read_offset >= end_offset)
- goto boundary_reached;
-
- if (ogg->read_offset == ogg->length)
- goto eos;
-
- ret = gst_pad_pull_range (ogg->sinkpad, ogg->read_offset, CHUNKSIZE, &buffer);
- if (ret != GST_FLOW_OK)
- goto error;
-
- ogg->read_offset += GST_BUFFER_SIZE (buffer);
-
- ret = gst_ogg_demux_submit_buffer (ogg, buffer);
-
- return ret;
-
- /* ERROR */
-boundary_reached:
- {
- GST_LOG_OBJECT (ogg, "reached boundary");
- return GST_FLOW_LIMIT;
- }
-eos:
- {
- GST_LOG_OBJECT (ogg, "reached EOS");
- return GST_FLOW_UNEXPECTED;
- }
-error:
- {
- GST_WARNING_OBJECT (ogg, "got %d (%s) from pull range", ret,
- gst_flow_get_name (ret));
- return ret;
- }
-}
-
-/* Read the next page from the current offset.
- * boundary: number of bytes ahead we allow looking for;
- * -1 if no boundary
- *
- * @offset will contain the offset the next page starts at when this function
- * returns GST_FLOW_OK.
- *
- * GST_FLOW_UNEXPECTED is returned on EOS.
- *
- * GST_FLOW_LIMIT is returned when we did not find a page before the
- * boundary. If @boundary is -1, this is never returned.
- *
- * Any other error returned while retrieving data from the peer is returned as
- * is.
- */
-static GstFlowReturn
-gst_ogg_demux_get_next_page (GstOggDemux * ogg, ogg_page * og, gint64 boundary,
- gint64 * offset)
-{
- gint64 end_offset = -1;
- GstFlowReturn ret;
-
- GST_LOG_OBJECT (ogg,
- "get next page, current offset %" G_GINT64_FORMAT ", bytes boundary %"
- G_GINT64_FORMAT, ogg->offset, boundary);
-
- if (boundary >= 0)
- end_offset = ogg->offset + boundary;
-
- while (TRUE) {
- glong more;
-
- if (end_offset > 0 && ogg->offset >= end_offset)
- goto boundary_reached;
-
- more = ogg_sync_pageseek (&ogg->sync, og);
-
- GST_LOG_OBJECT (ogg, "pageseek gave %ld", more);
-
- if (more < 0) {
- /* skipped n bytes */
- ogg->offset -= more;
- GST_LOG_OBJECT (ogg, "skipped %ld bytes, offset %" G_GINT64_FORMAT, more,
- ogg->offset);
- } else if (more == 0) {
- /* we need more data */
- if (boundary == 0)
- goto boundary_reached;
-
- GST_LOG_OBJECT (ogg, "need more data");
- ret = gst_ogg_demux_get_data (ogg, end_offset);
- if (ret != GST_FLOW_OK)
- break;
- } else {
- gint64 res_offset = ogg->offset;
-
- /* got a page. Return the offset at the page beginning,
- advance the internal offset past the page end */
- if (offset)
- *offset = res_offset;
- ret = GST_FLOW_OK;
-
- ogg->offset += more;
-
- GST_LOG_OBJECT (ogg,
- "got page at %" G_GINT64_FORMAT ", serial %08x, end at %"
- G_GINT64_FORMAT ", granule %" G_GINT64_FORMAT, res_offset,
- ogg_page_serialno (og), ogg->offset,
- (gint64) ogg_page_granulepos (og));
- break;
- }
- }
- GST_LOG_OBJECT (ogg, "returning %d", ret);
-
- return ret;
-
- /* ERRORS */
-boundary_reached:
- {
- GST_LOG_OBJECT (ogg,
- "offset %" G_GINT64_FORMAT " >= end_offset %" G_GINT64_FORMAT,
- ogg->offset, end_offset);
- return GST_FLOW_LIMIT;
- }
-}
-
-/* from the current offset, find the previous page, seeking backwards
- * until we find the page.
- */
-static GstFlowReturn
-gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset)
-{
- GstFlowReturn ret;
- gint64 begin = ogg->offset;
- gint64 end = begin;
- gint64 cur_offset = -1;
-
- GST_LOG_OBJECT (ogg, "getting page before %" G_GINT64_FORMAT, begin);
-
- while (cur_offset == -1) {
- begin -= CHUNKSIZE;
- if (begin < 0)
- begin = 0;
-
- /* seek CHUNKSIZE back */
- gst_ogg_demux_seek (ogg, begin);
-
- /* now continue reading until we run out of data, if we find a page
- * start, we save it. It might not be the final page as there could be
- * another page after this one. */
- while (ogg->offset < end) {
- gint64 new_offset;
-
- ret =
- gst_ogg_demux_get_next_page (ogg, og, end - ogg->offset, &new_offset);
- /* we hit the upper limit, offset contains the last page start */
- if (ret == GST_FLOW_LIMIT) {
- GST_LOG_OBJECT (ogg, "hit limit");
- break;
- }
- /* something went wrong */
- if (ret == GST_FLOW_UNEXPECTED) {
- new_offset = 0;
- GST_LOG_OBJECT (ogg, "got unexpected");
- } else if (ret != GST_FLOW_OK) {
- GST_LOG_OBJECT (ogg, "got error %d", ret);
- return ret;
- }
-
- GST_LOG_OBJECT (ogg, "found page at %" G_GINT64_FORMAT, new_offset);
-
- /* offset is next page start */
- cur_offset = new_offset;
- }
- }
-
- GST_LOG_OBJECT (ogg, "found previous page at %" G_GINT64_FORMAT, cur_offset);
-
- /* we have the offset. Actually snork and hold the page now */
- gst_ogg_demux_seek (ogg, cur_offset);
- ret = gst_ogg_demux_get_next_page (ogg, og, -1, NULL);
- if (ret != GST_FLOW_OK) {
- GST_WARNING_OBJECT (ogg, "can't get last page at %" G_GINT64_FORMAT,
- cur_offset);
- /* this shouldn't be possible */
- return ret;
- }
-
- if (offset)
- *offset = cur_offset;
-
- return ret;
-}
-
-static gboolean
-gst_ogg_demux_deactivate_current_chain (GstOggDemux * ogg)
-{
- gint i;
- GstOggChain *chain = ogg->current_chain;
-
- if (chain == NULL)
- return TRUE;
-
- GST_DEBUG_OBJECT (ogg, "deactivating chain %p", chain);
-
- /* send EOS on all the pads */
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
- GstEvent *event;
-
- if (!pad->added)
- continue;
-
- event = gst_event_new_eos ();
- gst_event_set_seqnum (event, ogg->seqnum);
- gst_pad_push_event (GST_PAD_CAST (pad), event);
-
- GST_DEBUG_OBJECT (ogg, "removing pad %" GST_PTR_FORMAT, pad);
-
- /* deactivate first */
- gst_pad_set_active (GST_PAD_CAST (pad), FALSE);
-
- gst_element_remove_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad));
-
- pad->added = FALSE;
- }
- /* if we cannot seek back to the chain, we can destroy the chain
- * completely */
- if (!ogg->pullmode) {
- gst_ogg_chain_free (chain);
- }
- ogg->current_chain = NULL;
-
- return TRUE;
-}
-
-static gboolean
-gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
- GstEvent * event)
-{
- gint i;
-
- if (chain == ogg->current_chain) {
- if (event)
- gst_event_unref (event);
- return TRUE;
- }
-
- /* FIXME, should not be called with NULL */
- if (chain != NULL) {
- GST_DEBUG_OBJECT (ogg, "activating chain %p", chain);
-
- /* first add the pads */
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad;
- GstStructure *structure;
-
- pad = g_array_index (chain->streams, GstOggPad *, i);
-
- if (pad->map.is_skeleton || pad->added || GST_PAD_CAPS (pad) == NULL)
- continue;
-
- GST_DEBUG_OBJECT (ogg, "adding pad %" GST_PTR_FORMAT, pad);
-
- /* mark discont */
- pad->discont = TRUE;
- pad->map.last_size = 0;
- pad->last_ret = GST_FLOW_OK;
- pad->added = TRUE;
-
- structure = gst_caps_get_structure (GST_PAD_CAPS (pad), 0);
- pad->is_sparse =
- gst_structure_has_name (structure, "application/x-ogm-text") ||
- gst_structure_has_name (structure, "text/x-cmml") ||
- gst_structure_has_name (structure, "subtitle/x-kate") ||
- gst_structure_has_name (structure, "application/x-kate");
-
- /* activate first */
- gst_pad_set_active (GST_PAD_CAST (pad), TRUE);
-
- gst_element_add_pad (GST_ELEMENT (ogg), GST_PAD_CAST (pad));
- }
- }
-
- /* after adding the new pads, remove the old pads */
- gst_ogg_demux_deactivate_current_chain (ogg);
-
- ogg->current_chain = chain;
-
- /* we are finished now */
- gst_element_no_more_pads (GST_ELEMENT (ogg));
-
- /* FIXME, must be sent from the streaming thread */
- if (event) {
- gst_ogg_demux_send_event (ogg, event);
-
- gst_element_found_tags (GST_ELEMENT_CAST (ogg),
- gst_tag_list_new_full (GST_TAG_CONTAINER_FORMAT, "Ogg", NULL));
- }
-
- GST_DEBUG_OBJECT (ogg, "starting chain");
-
- /* then send out any headers and queued packets */
- for (i = 0; i < chain->streams->len; i++) {
- GList *walk;
- GstOggPad *pad;
-
- pad = g_array_index (chain->streams, GstOggPad *, i);
-
- GST_DEBUG_OBJECT (ogg, "pushing headers");
- /* push headers */
- for (walk = pad->map.headers; walk; walk = g_list_next (walk)) {
- ogg_packet *p = walk->data;
-
- gst_ogg_demux_chain_peer (pad, p, TRUE);
- }
-
- GST_DEBUG_OBJECT (ogg, "pushing queued buffers");
- /* push queued packets */
- for (walk = pad->map.queued; walk; walk = g_list_next (walk)) {
- ogg_packet *p = walk->data;
-
- gst_ogg_demux_chain_peer (pad, p, TRUE);
- _ogg_packet_free (p);
- }
- /* and free the queued buffers */
- g_list_free (pad->map.queued);
- pad->map.queued = NULL;
- }
- return TRUE;
-}
-
-static gboolean
-do_binary_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
- gint64 end, gint64 begintime, gint64 endtime, gint64 target,
- gint64 * offset)
-{
- gint64 best;
- GstFlowReturn ret;
- gint64 result = 0;
-
- best = begin;
-
- GST_DEBUG_OBJECT (ogg,
- "chain offset %" G_GINT64_FORMAT ", end offset %" G_GINT64_FORMAT, begin,
- end);
- GST_DEBUG_OBJECT (ogg,
- "chain begin time %" GST_TIME_FORMAT ", end time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (begintime), GST_TIME_ARGS (endtime));
- GST_DEBUG_OBJECT (ogg, "target %" GST_TIME_FORMAT, GST_TIME_ARGS (target));
-
- /* perform the seek */
- while (begin < end) {
- gint64 bisect;
-
- if ((end - begin < CHUNKSIZE) || (endtime == begintime)) {
- bisect = begin;
- } else {
- /* take a (pretty decent) guess, avoiding overflow */
- gint64 rate = (end - begin) * GST_MSECOND / (endtime - begintime);
-
- bisect = (target - begintime) / GST_MSECOND * rate + begin - CHUNKSIZE;
-
- if (bisect <= begin)
- bisect = begin;
- GST_DEBUG_OBJECT (ogg, "Initial guess: %" G_GINT64_FORMAT, bisect);
- }
- gst_ogg_demux_seek (ogg, bisect);
-
- while (begin < end) {
- ogg_page og;
-
- GST_DEBUG_OBJECT (ogg,
- "after seek, bisect %" G_GINT64_FORMAT ", begin %" G_GINT64_FORMAT
- ", end %" G_GINT64_FORMAT, bisect, begin, end);
-
- ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result);
- GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT,
- result);
-
- if (ret == GST_FLOW_LIMIT) {
- /* we hit the upper limit, go back a bit */
- if (bisect <= begin + 1) {
- end = begin; /* found it */
- } else {
- if (bisect == 0)
- goto seek_error;
-
- bisect -= CHUNKSIZE;
- if (bisect <= begin)
- bisect = begin + 1;
-
- gst_ogg_demux_seek (ogg, bisect);
- }
- } else if (ret == GST_FLOW_OK) {
- /* found offset of next ogg page */
- gint64 granulepos;
- GstClockTime granuletime;
- GstOggPad *pad;
-
- /* get the granulepos */
- GST_LOG_OBJECT (ogg, "found next ogg page at %" G_GINT64_FORMAT,
- result);
- granulepos = ogg_page_granulepos (&og);
- if (granulepos == -1) {
- GST_LOG_OBJECT (ogg, "granulepos of next page is -1");
- continue;
- }
-
- /* get the stream */
- pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og));
- if (pad == NULL || pad->map.is_skeleton)
- continue;
-
- /* convert granulepos to time */
- granuletime = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
- granulepos);
- if (granuletime < pad->start_time)
- continue;
-
- GST_LOG_OBJECT (ogg, "granulepos %" G_GINT64_FORMAT " maps to time %"
- GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (granuletime));
-
- granuletime -= pad->start_time;
- granuletime += chain->begin_time;
-
- GST_DEBUG_OBJECT (ogg,
- "found page with granule %" G_GINT64_FORMAT " and time %"
- GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (granuletime));
-
- if (granuletime < target) {
- best = result; /* raw offset of packet with granulepos */
- begin = ogg->offset; /* raw offset of next page */
- begintime = granuletime;
-
- bisect = begin; /* *not* begin + 1 */
- } else {
- if (bisect <= begin + 1) {
- end = begin; /* found it */
- } else {
- if (end == ogg->offset) { /* we're pretty close - we'd be stuck in */
- end = result;
- bisect -= CHUNKSIZE; /* an endless loop otherwise. */
- if (bisect <= begin)
- bisect = begin + 1;
- gst_ogg_demux_seek (ogg, bisect);
- } else {
- end = result;
- endtime = granuletime;
- break;
- }
- }
- }
- } else
- goto seek_error;
- }
- }
- GST_DEBUG_OBJECT (ogg, "seeking to %" G_GINT64_FORMAT, best);
- gst_ogg_demux_seek (ogg, best);
- *offset = best;
-
- return TRUE;
-
- /* ERRORS */
-seek_error:
- {
- GST_DEBUG_OBJECT (ogg, "got a seek error");
- return FALSE;
- }
-}
-
-/*
- * do seek to time @position, return FALSE or chain and TRUE
- */
-static gboolean
-gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
- gboolean accurate, gboolean keyframe, GstOggChain ** rchain)
-{
- guint64 position;
- GstOggChain *chain = NULL;
- gint64 begin, end;
- gint64 begintime, endtime;
- gint64 target, keytarget;
- gint64 best;
- gint64 total;
- gint64 result = 0;
- GstFlowReturn ret;
- gint i, pending, len;
-
- position = segment->last_stop;
-
- /* first find the chain to search in */
- total = ogg->total_time;
- if (ogg->chains->len == 0)
- goto no_chains;
-
- for (i = ogg->chains->len - 1; i >= 0; i--) {
- chain = g_array_index (ogg->chains, GstOggChain *, i);
- total -= chain->total_time;
- if (position >= total)
- break;
- }
-
- /* first step, locate page containing the required data */
- begin = chain->offset;
- end = chain->end_offset;
- begintime = chain->begin_time;
- endtime = begintime + chain->total_time;
- target = position - total + begintime;
-
- if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, target,
- &best))
- goto seek_error;
-
- /* second step: find pages for all streams, we use the keyframe_granule to keep
- * track of which ones we saw. If we have seen a page for each stream we can
- * calculate the positions of each keyframe. */
- GST_DEBUG_OBJECT (ogg, "find keyframes");
- len = pending = chain->streams->len;
-
- /* figure out where the keyframes are */
- keytarget = target;
-
- while (TRUE) {
- ogg_page og;
- gint64 granulepos;
- GstOggPad *pad;
- GstClockTime keyframe_time, granule_time;
-
- ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, &result);
- GST_LOG_OBJECT (ogg, "looking for next page returned %" G_GINT64_FORMAT,
- result);
- if (ret == GST_FLOW_LIMIT) {
- GST_LOG_OBJECT (ogg, "reached limit");
- break;
- }
-
- /* get the stream */
- pad = gst_ogg_chain_get_stream (chain, ogg_page_serialno (&og));
- if (pad == NULL)
- continue;
-
- if (pad->map.is_skeleton)
- goto next;
-
- granulepos = ogg_page_granulepos (&og);
- if (granulepos == -1) {
- GST_LOG_OBJECT (ogg, "granulepos of next page is -1");
- continue;
- }
-
- /* in reverse we want to go past the page with the lower timestamp */
- if (segment->rate < 0.0) {
- /* get time for this pad */
- granule_time = gst_ogg_stream_get_end_time_for_granulepos (&pad->map,
- granulepos);
-
- GST_LOG_OBJECT (ogg,
- "looking at page with ts %" GST_TIME_FORMAT ", target %"
- GST_TIME_FORMAT, GST_TIME_ARGS (granule_time),
- GST_TIME_ARGS (target));
- if (granule_time < target)
- continue;
- }
-
- /* we've seen this pad before */
- if (pad->keyframe_granule != -1)
- continue;
-
- /* convert granule of this pad to the granule of the keyframe */
- pad->keyframe_granule = gst_ogg_stream_granulepos_to_key_granule (&pad->map,
- granulepos);
- GST_LOG_OBJECT (ogg, "marking stream granule %" G_GINT64_FORMAT,
- pad->keyframe_granule);
-
- /* get time of the keyframe */
- keyframe_time =
- gst_ogg_stream_granule_to_time (&pad->map, pad->keyframe_granule);
- GST_LOG_OBJECT (ogg, "stream %08lx granule time %" GST_TIME_FORMAT,
- pad->map.serialno, GST_TIME_ARGS (keyframe_time));
-
- /* collect smallest value */
- if (keyframe_time != -1) {
- keyframe_time += begintime;
- if (keyframe_time < keytarget)
- keytarget = keyframe_time;
- }
-
- next:
- pending--;
- if (pending == 0)
- break;
- }
-
- /* for negative rates we will get to the keyframe backwards */
- if (segment->rate < 0.0)
- goto done;
-
- if (keytarget != target) {
- GST_LOG_OBJECT (ogg, "final seek to target %" GST_TIME_FORMAT,
- GST_TIME_ARGS (keytarget));
-
- /* last step, seek to the location of the keyframe */
- if (!do_binary_search (ogg, chain, begin, end, begintime, endtime,
- keytarget, &best))
- goto seek_error;
- } else {
- /* seek back to previous position */
- GST_LOG_OBJECT (ogg, "keyframe on target");
- gst_ogg_demux_seek (ogg, best);
- }
-
-done:
- if (keyframe) {
- if (segment->rate > 0.0)
- segment->time = keytarget;
- segment->last_stop = keytarget - begintime;
- }
-
- *rchain = chain;
-
- return TRUE;
-
-no_chains:
- {
- GST_DEBUG_OBJECT (ogg, "no chains");
- return FALSE;
- }
-seek_error:
- {
- GST_DEBUG_OBJECT (ogg, "got a seek error");
- return FALSE;
- }
-}
-
-/* does not take ownership of the event */
-static gboolean
-gst_ogg_demux_perform_seek (GstOggDemux * ogg, GstEvent * event)
-{
- GstOggChain *chain = NULL;
- gboolean res;
- gboolean flush, accurate, keyframe;
- GstFormat format;
- gdouble rate;
- GstSeekFlags flags;
- GstSeekType cur_type, stop_type;
- gint64 cur, stop;
- gboolean update;
- guint32 seqnum;
- GstEvent *tevent;
-
- if (event) {
- GST_DEBUG_OBJECT (ogg, "seek with event");
-
- gst_event_parse_seek (event, &rate, &format, &flags,
- &cur_type, &cur, &stop_type, &stop);
-
- /* we can only seek on time */
- if (format != GST_FORMAT_TIME) {
- GST_DEBUG_OBJECT (ogg, "can only seek on TIME");
- goto error;
- }
- seqnum = gst_event_get_seqnum (event);
- } else {
- GST_DEBUG_OBJECT (ogg, "seek without event");
-
- flags = 0;
- rate = 1.0;
- seqnum = gst_util_seqnum_next ();
- }
-
- GST_DEBUG_OBJECT (ogg, "seek, rate %g", rate);
-
- flush = flags & GST_SEEK_FLAG_FLUSH;
- accurate = flags & GST_SEEK_FLAG_ACCURATE;
- keyframe = flags & GST_SEEK_FLAG_KEY_UNIT;
-
- /* first step is to unlock the streaming thread if it is
- * blocked in a chain call, we do this by starting the flush. because
- * we cannot yet hold any streaming lock, we have to protect the chains
- * with their own lock. */
- if (flush) {
- gint i;
-
- tevent = gst_event_new_flush_start ();
- gst_event_set_seqnum (tevent, seqnum);
-
- gst_event_ref (tevent);
- gst_pad_push_event (ogg->sinkpad, tevent);
-
- GST_CHAIN_LOCK (ogg);
- for (i = 0; i < ogg->chains->len; i++) {
- GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
- gint j;
-
- for (j = 0; j < chain->streams->len; j++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, j);
-
- gst_event_ref (tevent);
- gst_pad_push_event (GST_PAD (pad), tevent);
- }
- }
- GST_CHAIN_UNLOCK (ogg);
-
- gst_event_unref (tevent);
- } else {
- gst_pad_pause_task (ogg->sinkpad);
- }
-
- /* now grab the stream lock so that streaming cannot continue, for
- * non flushing seeks when the element is in PAUSED this could block
- * forever. */
- GST_PAD_STREAM_LOCK (ogg->sinkpad);
-
- if (ogg->segment_running && !flush) {
- /* create the segment event to close the current segment */
- if ((chain = ogg->current_chain)) {
- GstEvent *newseg;
- gint64 chain_start = 0;
-
- if (chain->segment_start != GST_CLOCK_TIME_NONE)
- chain_start = chain->segment_start;
-
- newseg = gst_event_new_new_segment (TRUE, ogg->segment.rate,
- GST_FORMAT_TIME, ogg->segment.start + chain_start,
- ogg->segment.last_stop + chain_start, ogg->segment.time);
- /* set the seqnum of the running segment */
- gst_event_set_seqnum (newseg, ogg->seqnum);
-
- /* send segment on old chain, FIXME, must be sent from streaming thread. */
- gst_ogg_demux_send_event (ogg, newseg);
- }
- }
-
- if (event) {
- gst_segment_set_seek (&ogg->segment, rate, format, flags,
- cur_type, cur, stop_type, stop, &update);
- }
-
- GST_DEBUG_OBJECT (ogg, "segment positions set to %" GST_TIME_FORMAT "-%"
- GST_TIME_FORMAT, GST_TIME_ARGS (ogg->segment.start),
- GST_TIME_ARGS (ogg->segment.stop));
-
- /* we need to stop flushing on the srcpad as we're going to use it
- * next. We can do this as we have the STREAM lock now. */
- if (flush) {
- tevent = gst_event_new_flush_stop ();
- gst_event_set_seqnum (tevent, seqnum);
- gst_pad_push_event (ogg->sinkpad, tevent);
- }
-
- {
- gint i;
-
- /* reset all ogg streams now, need to do this from within the lock to
- * make sure the streaming thread is not messing with the stream */
- for (i = 0; i < ogg->chains->len; i++) {
- GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
-
- gst_ogg_chain_reset (chain);
- }
- }
-
- /* for reverse we will already seek accurately */
- res = gst_ogg_demux_do_seek (ogg, &ogg->segment, accurate, keyframe, &chain);
-
- /* seek failed, make sure we continue the current chain */
- if (!res) {
- GST_DEBUG_OBJECT (ogg, "seek failed");
- chain = ogg->current_chain;
- } else {
- GST_DEBUG_OBJECT (ogg, "seek success");
- }
-
- if (!chain)
- goto no_chain;
-
- /* now we have a new position, prepare for streaming again */
- {
- GstEvent *event;
- gint64 stop;
- gint64 start;
- gint64 last_stop, begin_time;
-
- /* we have to send the flush to the old chain, not the new one */
- if (flush) {
- tevent = gst_event_new_flush_stop ();
- gst_event_set_seqnum (tevent, seqnum);
- gst_ogg_demux_send_event (ogg, tevent);
- }
-
- /* we need this to see how far inside the chain we need to start */
- if (chain->begin_time != GST_CLOCK_TIME_NONE)
- begin_time = chain->begin_time;
- else
- begin_time = 0;
-
- /* segment.start gives the start over all chains, we calculate the amount
- * of time into this chain we need to start */
- start = ogg->segment.start - begin_time;
- if (chain->segment_start != GST_CLOCK_TIME_NONE)
- start += chain->segment_start;
-
- if ((stop = ogg->segment.stop) == -1)
- stop = ogg->segment.duration;
-
- /* segment.stop gives the stop time over all chains, calculate the amount of
- * time we need to stop in this chain */
- if (stop != -1) {
- if (stop > begin_time)
- stop -= begin_time;
- else
- stop = 0;
- stop += chain->segment_start;
- /* we must stop when this chain ends and switch to the next chain to play
- * the remainder of the segment. */
- stop = MIN (stop, chain->segment_stop);
- }
-
- last_stop = ogg->segment.last_stop;
- if (chain->segment_start != GST_CLOCK_TIME_NONE)
- last_stop += chain->segment_start;
-
- /* create the segment event we are going to send out */
- if (ogg->segment.rate >= 0.0)
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- ogg->segment.format, last_stop, stop, ogg->segment.time);
- else
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- ogg->segment.format, start, last_stop, ogg->segment.time);
-
- gst_event_set_seqnum (event, seqnum);
-
- if (chain != ogg->current_chain) {
- /* switch to different chain, send segment on new chain */
- gst_ogg_demux_activate_chain (ogg, chain, event);
- } else {
- /* mark discont and send segment on current chain */
- gst_ogg_chain_mark_discont (chain);
- /* This event should be sent from the streaming thread (sink pad task) */
- if (ogg->newsegment)
- gst_event_unref (ogg->newsegment);
- ogg->newsegment = event;
- }
-
- /* notify start of new segment */
- if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
- GstMessage *message;
-
- message = gst_message_new_segment_start (GST_OBJECT (ogg),
- GST_FORMAT_TIME, ogg->segment.last_stop);
- gst_message_set_seqnum (message, seqnum);
-
- gst_element_post_message (GST_ELEMENT (ogg), message);
- }
-
- ogg->segment_running = TRUE;
- ogg->seqnum = seqnum;
- /* restart our task since it might have been stopped when we did the
- * flush. */
- gst_pad_start_task (ogg->sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
- ogg->sinkpad);
- }
-
- /* streaming can continue now */
- GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
-
- return res;
-
-error:
- {
- GST_DEBUG_OBJECT (ogg, "seek failed");
- return FALSE;
- }
-no_chain:
- {
- GST_DEBUG_OBJECT (ogg, "no chain to seek in");
- GST_PAD_STREAM_UNLOCK (ogg->sinkpad);
- return FALSE;
- }
-}
-
-/* finds each bitstream link one at a time using a bisection search
- * (has to begin by knowing the offset of the lb's initial page).
- * Recurses for each link so it can alloc the link storage after
- * finding them all, then unroll and fill the cache at the same time
- */
-static GstFlowReturn
-gst_ogg_demux_bisect_forward_serialno (GstOggDemux * ogg,
- gint64 begin, gint64 searched, gint64 end, GstOggChain * chain, glong m)
-{
- gint64 endsearched = end;
- gint64 next = end;
- ogg_page og;
- GstFlowReturn ret;
- gint64 offset;
- GstOggChain *nextchain;
-
- GST_LOG_OBJECT (ogg,
- "bisect begin: %" G_GINT64_FORMAT ", searched: %" G_GINT64_FORMAT
- ", end %" G_GINT64_FORMAT ", chain: %p", begin, searched, end, chain);
-
- /* the below guards against garbage seperating the last and
- * first pages of two links. */
- while (searched < endsearched) {
- gint64 bisect;
-
- if (endsearched - searched < CHUNKSIZE) {
- bisect = searched;
- } else {
- bisect = (searched + endsearched) / 2;
- }
-
- gst_ogg_demux_seek (ogg, bisect);
- ret = gst_ogg_demux_get_next_page (ogg, &og, -1, &offset);
-
- if (ret == GST_FLOW_UNEXPECTED) {
- endsearched = bisect;
- } else if (ret == GST_FLOW_OK) {
- glong serial = ogg_page_serialno (&og);
-
- if (!gst_ogg_chain_has_stream (chain, serial)) {
- endsearched = bisect;
- next = offset;
- } else {
- searched = offset + og.header_len + og.body_len;
- }
- } else
- return ret;
- }
-
- GST_LOG_OBJECT (ogg, "current chain ends at %" G_GINT64_FORMAT, searched);
-
- chain->end_offset = searched;
- ret = gst_ogg_demux_read_end_chain (ogg, chain);
- if (ret != GST_FLOW_OK)
- return ret;
-
- GST_LOG_OBJECT (ogg, "found begin at %" G_GINT64_FORMAT, next);
-
- gst_ogg_demux_seek (ogg, next);
- ret = gst_ogg_demux_read_chain (ogg, &nextchain);
- if (ret == GST_FLOW_UNEXPECTED) {
- nextchain = NULL;
- ret = GST_FLOW_OK;
- GST_LOG_OBJECT (ogg, "no next chain");
- } else if (ret != GST_FLOW_OK)
- goto done;
-
- if (searched < end && nextchain != NULL) {
- ret = gst_ogg_demux_bisect_forward_serialno (ogg, next, ogg->offset,
- end, nextchain, m + 1);
- if (ret != GST_FLOW_OK)
- goto done;
- }
- GST_LOG_OBJECT (ogg, "adding chain %p", chain);
-
- g_array_insert_val (ogg->chains, 0, chain);
-
-done:
- return ret;
-}
-
-/* read a chain from the ogg file. This code will
- * read all BOS pages and will create and return a GstOggChain
- * structure with the results.
- *
- * This function will also read N pages from each stream in the
- * chain and submit them to the decoders. When the decoder has
- * decoded the first buffer, we know the timestamp of the first
- * page in the chain.
- */
-static GstFlowReturn
-gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
-{
- GstFlowReturn ret;
- GstOggChain *chain = NULL;
- gint64 offset = ogg->offset;
- ogg_page op;
- gboolean done;
- gint i;
-
- GST_LOG_OBJECT (ogg, "reading chain at %" G_GINT64_FORMAT, offset);
-
- /* first read the BOS pages, do typefind on them, create
- * the decoders, send data to the decoders. */
- while (TRUE) {
- GstOggPad *pad;
- glong serial;
-
- ret = gst_ogg_demux_get_next_page (ogg, &op, -1, NULL);
- if (ret != GST_FLOW_OK) {
- GST_WARNING_OBJECT (ogg, "problem reading BOS page: ret=%d", ret);
- break;
- }
- if (!ogg_page_bos (&op)) {
- GST_WARNING_OBJECT (ogg, "page is not BOS page");
- /* if we did not find a chain yet, assume this is a bogus stream and
- * ignore it */
- if (!chain)
- ret = GST_FLOW_UNEXPECTED;
- break;
- }
-
- if (chain == NULL) {
- chain = gst_ogg_chain_new (ogg);
- chain->offset = offset;
- }
-
- serial = ogg_page_serialno (&op);
- if (gst_ogg_chain_get_stream (chain, serial) != NULL) {
- GST_WARNING_OBJECT (ogg, "found serial %08lx BOS page twice, ignoring",
- serial);
- continue;
- }
-
- pad = gst_ogg_chain_new_stream (chain, serial);
- gst_ogg_pad_submit_page (pad, &op);
- }
-
- if (ret != GST_FLOW_OK || chain == NULL) {
- if (ret == GST_FLOW_OK) {
- GST_WARNING_OBJECT (ogg, "no chain was found");
- ret = GST_FLOW_ERROR;
- } else if (ret != GST_FLOW_UNEXPECTED) {
- GST_WARNING_OBJECT (ogg, "failed to read chain");
- } else {
- GST_DEBUG_OBJECT (ogg, "done reading chains");
- }
- if (chain) {
- gst_ogg_chain_free (chain);
- }
- if (res_chain)
- *res_chain = NULL;
- return ret;
- }
-
- chain->have_bos = TRUE;
- GST_LOG_OBJECT (ogg, "read bos pages, init decoder now");
-
- /* now read pages until we receive a buffer from each of the
- * stream decoders, this will tell us the timestamp of the
- * first packet in the chain then */
-
- /* save the offset to the first non bos page in the chain: if searching for
- * pad->first_time we read past the end of the chain, we'll seek back to this
- * position
- */
- offset = ogg->offset;
-
- done = FALSE;
- while (!done) {
- glong serial;
- gboolean known_serial = FALSE;
- GstFlowReturn ret;
-
- serial = ogg_page_serialno (&op);
- done = TRUE;
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- GST_LOG_OBJECT (ogg, "serial %08lx time %" GST_TIME_FORMAT,
- pad->map.serialno, GST_TIME_ARGS (pad->start_time));
-
- if (pad->map.serialno == serial) {
- known_serial = TRUE;
-
- /* submit the page now, this will fill in the start_time when the
- * internal decoder finds it */
- gst_ogg_pad_submit_page (pad, &op);
-
- if (!pad->map.is_skeleton && pad->start_time == -1
- && ogg_page_eos (&op)) {
- /* got EOS on a pad before we could find its start_time.
- * We have no chance of finding a start_time for every pad so
- * stop searching for the other start_time(s).
- */
- done = TRUE;
- break;
- }
- }
- /* the timestamp will be filled in when we submit the pages */
- if (!pad->map.is_skeleton)
- done &= (pad->start_time != GST_CLOCK_TIME_NONE);
-
- GST_LOG_OBJECT (ogg, "done %08lx now %d", pad->map.serialno, done);
- }
-
- /* we read a page not belonging to the current chain: seek back to the
- * beginning of the chain
- */
- if (!known_serial) {
- GST_LOG_OBJECT (ogg, "unknown serial %08lx", serial);
- gst_ogg_demux_seek (ogg, offset);
- break;
- }
-
- if (!done) {
- ret = gst_ogg_demux_get_next_page (ogg, &op, -1, NULL);
- if (ret != GST_FLOW_OK)
- break;
- }
- }
- GST_LOG_OBJECT (ogg, "done reading chain");
- /* now we can fill in the missing info using queries */
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- if (pad->map.is_skeleton)
- continue;
-
- pad->mode = GST_OGG_PAD_MODE_STREAMING;
- }
-
- if (res_chain)
- *res_chain = chain;
-
- return GST_FLOW_OK;
-}
-
-/* read the last pages from the ogg stream to get the final
- * page end_offsets.
- */
-static GstFlowReturn
-gst_ogg_demux_read_end_chain (GstOggDemux * ogg, GstOggChain * chain)
-{
- gint64 begin = chain->end_offset;
- gint64 end = begin;
- gint64 last_granule = -1;
- GstOggPad *last_pad = NULL;
- GstFlowReturn ret;
- gboolean done = FALSE;
- ogg_page og;
- gint i;
-
- while (!done) {
- begin -= CHUNKSIZE;
- if (begin < 0)
- begin = 0;
-
- gst_ogg_demux_seek (ogg, begin);
-
- /* now continue reading until we run out of data, if we find a page
- * start, we save it. It might not be the final page as there could be
- * another page after this one. */
- while (ogg->offset < end) {
- ret = gst_ogg_demux_get_next_page (ogg, &og, end - ogg->offset, NULL);
-
- if (ret == GST_FLOW_LIMIT)
- break;
- if (ret != GST_FLOW_OK)
- return ret;
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- if (pad->map.is_skeleton)
- continue;
-
- if (pad->map.serialno == ogg_page_serialno (&og)) {
- gint64 granulepos = ogg_page_granulepos (&og);
-
- if (last_granule == -1 || last_granule < granulepos) {
- last_granule = granulepos;
- last_pad = pad;
- }
- if (last_granule != -1) {
- done = TRUE;
- }
- break;
- }
- }
- }
- }
-
- if (last_pad) {
- chain->segment_stop =
- gst_ogg_stream_get_end_time_for_granulepos (&last_pad->map,
- last_granule);
- } else {
- chain->segment_stop = GST_CLOCK_TIME_NONE;
- }
-
- GST_INFO ("segment stop %" G_GUINT64_FORMAT, chain->segment_stop);
-
- return GST_FLOW_OK;
-}
-
-/* find a pad with a given serial number
- */
-static GstOggPad *
-gst_ogg_demux_find_pad (GstOggDemux * ogg, glong serialno)
-{
- GstOggPad *pad;
- gint i;
-
- /* first look in building chain if any */
- if (ogg->building_chain) {
- pad = gst_ogg_chain_get_stream (ogg->building_chain, serialno);
- if (pad)
- return pad;
- }
-
- /* then look in current chain if any */
- if (ogg->current_chain) {
- pad = gst_ogg_chain_get_stream (ogg->current_chain, serialno);
- if (pad)
- return pad;
- }
-
- for (i = 0; i < ogg->chains->len; i++) {
- GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
-
- pad = gst_ogg_chain_get_stream (chain, serialno);
- if (pad)
- return pad;
- }
- return NULL;
-}
-
-/* find a chain with a given serial number
- */
-static GstOggChain *
-gst_ogg_demux_find_chain (GstOggDemux * ogg, glong serialno)
-{
- GstOggPad *pad;
-
- pad = gst_ogg_demux_find_pad (ogg, serialno);
- if (pad) {
- return pad->chain;
- }
- return NULL;
-}
-
-/* returns TRUE if all streams have valid start time */
-static gboolean
-gst_ogg_demux_collect_chain_info (GstOggDemux * ogg, GstOggChain * chain)
-{
- gint i;
- gboolean res = TRUE;
-
- chain->total_time = GST_CLOCK_TIME_NONE;
- chain->segment_start = G_MAXUINT64;
-
- GST_DEBUG_OBJECT (ogg, "trying to collect chain info");
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- if (pad->map.is_skeleton)
- continue;
-
- /* can do this if the pad start time is not defined */
- if (pad->start_time == GST_CLOCK_TIME_NONE)
- res = FALSE;
- else
- chain->segment_start = MIN (chain->segment_start, pad->start_time);
- }
-
- if (chain->segment_stop != GST_CLOCK_TIME_NONE
- && chain->segment_start != G_MAXUINT64)
- chain->total_time = chain->segment_stop - chain->segment_start;
-
- GST_DEBUG ("total time %" G_GUINT64_FORMAT, chain->total_time);
-
- GST_DEBUG_OBJECT (ogg, "return %d", res);
-
- return res;
-}
-
-static void
-gst_ogg_demux_collect_info (GstOggDemux * ogg)
-{
- gint i;
-
- /* collect all info */
- ogg->total_time = 0;
-
- for (i = 0; i < ogg->chains->len; i++) {
- GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
-
- chain->begin_time = ogg->total_time;
-
- gst_ogg_demux_collect_chain_info (ogg, chain);
-
- ogg->total_time += chain->total_time;
- }
- gst_segment_set_duration (&ogg->segment, GST_FORMAT_TIME, ogg->total_time);
-}
-
-/* find all the chains in the ogg file, this reads the first and
- * last page of the ogg stream, if they match then the ogg file has
- * just one chain, else we do a binary search for all chains.
- */
-static GstFlowReturn
-gst_ogg_demux_find_chains (GstOggDemux * ogg)
-{
- ogg_page og;
- GstPad *peer;
- GstFormat format;
- gboolean res;
- gulong serialno;
- GstOggChain *chain;
- GstFlowReturn ret;
-
- /* get peer to figure out length */
- if ((peer = gst_pad_get_peer (ogg->sinkpad)) == NULL)
- goto no_peer;
-
- /* find length to read last page, we store this for later use. */
- format = GST_FORMAT_BYTES;
- res = gst_pad_query_duration (peer, &format, &ogg->length);
- gst_object_unref (peer);
- if (!res || ogg->length <= 0)
- goto no_length;
-
- GST_DEBUG_OBJECT (ogg, "file length %" G_GINT64_FORMAT, ogg->length);
-
- /* read chain from offset 0, this is the first chain of the
- * ogg file. */
- gst_ogg_demux_seek (ogg, 0);
- ret = gst_ogg_demux_read_chain (ogg, &chain);
- if (ret != GST_FLOW_OK)
- goto no_first_chain;
-
- /* read page from end offset, we use this page to check if its serial
- * number is contained in the first chain. If this is the case then
- * this ogg is not a chained ogg and we can skip the scanning. */
- gst_ogg_demux_seek (ogg, ogg->length);
- ret = gst_ogg_demux_get_prev_page (ogg, &og, NULL);
- if (ret != GST_FLOW_OK)
- goto no_last_page;
-
- serialno = ogg_page_serialno (&og);
-
- if (!gst_ogg_chain_has_stream (chain, serialno)) {
- /* the last page is not in the first stream, this means we should
- * find all the chains in this chained ogg. */
- ret =
- gst_ogg_demux_bisect_forward_serialno (ogg, 0, 0, ogg->length, chain,
- 0);
- } else {
- /* we still call this function here but with an empty range so that
- * we can reuse the setup code in this routine. */
- ret =
- gst_ogg_demux_bisect_forward_serialno (ogg, 0, ogg->length, ogg->length,
- chain, 0);
- }
- if (ret != GST_FLOW_OK)
- goto done;
-
- /* all fine, collect and print */
- gst_ogg_demux_collect_info (ogg);
-
- /* dump our chains and streams */
- gst_ogg_print (ogg);
-
-done:
- return ret;
-
- /*** error cases ***/
-no_peer:
- {
- GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("we don't have a peer"));
- return GST_FLOW_NOT_LINKED;
- }
-no_length:
- {
- GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("can't get file length"));
- return GST_FLOW_NOT_SUPPORTED;
- }
-no_first_chain:
- {
- GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL), ("can't get first chain"));
- return GST_FLOW_ERROR;
- }
-no_last_page:
- {
- GST_DEBUG_OBJECT (ogg, "can't get last page");
- if (chain)
- gst_ogg_chain_free (chain);
- return ret;
- }
-}
-
-static GstFlowReturn
-gst_ogg_demux_handle_page (GstOggDemux * ogg, ogg_page * page)
-{
- GstOggPad *pad;
- gint64 granule;
- glong serialno;
- GstFlowReturn result = GST_FLOW_OK;
-
- serialno = ogg_page_serialno (page);
- granule = ogg_page_granulepos (page);
-
- GST_LOG_OBJECT (ogg,
- "processing ogg page (serial %08lx, pageno %ld, granulepos %"
- G_GINT64_FORMAT ", bos %d)",
- serialno, ogg_page_pageno (page), granule, ogg_page_bos (page));
-
- if (ogg_page_bos (page)) {
- GstOggChain *chain;
-
- /* first page */
- /* see if we know about the chain already */
- chain = gst_ogg_demux_find_chain (ogg, serialno);
- if (chain) {
- GstEvent *event;
- gint64 start = 0;
-
- if (chain->segment_start != GST_CLOCK_TIME_NONE)
- start = chain->segment_start;
-
- /* create the newsegment event we are going to send out */
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- GST_FORMAT_TIME, start, chain->segment_stop, chain->begin_time);
- gst_event_set_seqnum (event, ogg->seqnum);
-
- GST_DEBUG_OBJECT (ogg,
- "segment: start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT
- ", time %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
- GST_TIME_ARGS (chain->segment_stop),
- GST_TIME_ARGS (chain->begin_time));
-
- /* activate it as it means we have a non-header, this will also deactivate
- * the currently running chain. */
- gst_ogg_demux_activate_chain (ogg, chain, event);
- pad = gst_ogg_demux_find_pad (ogg, serialno);
- } else {
- GstClockTime chain_time;
- GstOggChain *current_chain;
- gint64 current_time;
-
- /* this can only happen in push mode */
- if (ogg->pullmode)
- goto unknown_chain;
-
- current_chain = ogg->current_chain;
- current_time = ogg->segment.last_stop;
-
- /* time of new chain is current time */
- chain_time = current_time;
-
- if (ogg->building_chain == NULL) {
- GstOggChain *newchain;
-
- newchain = gst_ogg_chain_new (ogg);
- newchain->offset = 0;
- /* set new chain begin time aligned with end time of old chain */
- newchain->begin_time = chain_time;
- GST_DEBUG_OBJECT (ogg, "new chain, begin time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (chain_time));
-
- /* and this is the one we are building now */
- ogg->building_chain = newchain;
- }
- pad = gst_ogg_chain_new_stream (ogg->building_chain, serialno);
- }
- } else {
- pad = gst_ogg_demux_find_pad (ogg, serialno);
- }
- if (pad) {
- result = gst_ogg_pad_submit_page (pad, page);
- } else {
- /* no pad. This means an ogg page without bos has been seen for this
- * serialno. we just ignore it but post a warning... */
- GST_ELEMENT_WARNING (ogg, STREAM, DECODE,
- (NULL), ("unknown ogg pad for serial %08lx detected", serialno));
- return GST_FLOW_OK;
- }
- return result;
-
- /* ERRORS */
-unknown_chain:
- {
- GST_ELEMENT_ERROR (ogg, STREAM, DECODE,
- (NULL), ("unknown ogg chain for serial %08lx detected", serialno));
- return GST_FLOW_ERROR;
- }
-}
-
-/* streaming mode, receive a buffer, parse it, create pads for
- * the serialno, submit pages and packets to the oggpads
- */
-static GstFlowReturn
-gst_ogg_demux_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstOggDemux *ogg;
- gint ret = 0;
- GstFlowReturn result = GST_FLOW_OK;
-
- ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
-
- GST_DEBUG_OBJECT (ogg, "chain");
- result = gst_ogg_demux_submit_buffer (ogg, buffer);
-
- while (result == GST_FLOW_OK) {
- ogg_page page;
-
- ret = ogg_sync_pageout (&ogg->sync, &page);
- if (ret == 0)
- /* need more data */
- break;
- if (ret == -1) {
- /* discontinuity in the pages */
- GST_DEBUG_OBJECT (ogg, "discont in page found, continuing");
- } else {
- result = gst_ogg_demux_handle_page (ogg, &page);
- }
- }
- if (ret == 0 || result == GST_FLOW_OK) {
- gst_ogg_demux_sync_streams (ogg);
- }
- return result;
-}
-
-static void
-gst_ogg_demux_send_event (GstOggDemux * ogg, GstEvent * event)
-{
- GstOggChain *chain = ogg->current_chain;
-
- if (chain) {
- gint i;
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
-
- gst_event_ref (event);
- GST_DEBUG_OBJECT (pad, "Pushing event %" GST_PTR_FORMAT, event);
- gst_pad_push_event (GST_PAD (pad), event);
- }
- }
- gst_event_unref (event);
-}
-
-static GstFlowReturn
-gst_ogg_demux_combine_flows (GstOggDemux * ogg, GstOggPad * pad,
- GstFlowReturn ret)
-{
- GstOggChain *chain;
-
- /* store the value */
- pad->last_ret = ret;
-
- /* any other error that is not-linked can be returned right
- * away */
- if (ret != GST_FLOW_NOT_LINKED)
- goto done;
-
- /* only return NOT_LINKED if all other pads returned NOT_LINKED */
- chain = ogg->current_chain;
- if (chain) {
- gint i;
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *opad = g_array_index (chain->streams, GstOggPad *, i);
-
- ret = opad->last_ret;
- /* some other return value (must be SUCCESS but we can return
- * other values as well) */
- if (ret != GST_FLOW_NOT_LINKED)
- goto done;
- }
- /* if we get here, all other pads were unlinked and we return
- * NOT_LINKED then */
- }
-done:
- return ret;
-}
-
-static GstFlowReturn
-gst_ogg_demux_loop_forward (GstOggDemux * ogg)
-{
- GstFlowReturn ret;
- GstBuffer *buffer;
-
- if (ogg->offset == ogg->length) {
- GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT
- " == %" G_GINT64_FORMAT, ogg->offset, ogg->length);
- ret = GST_FLOW_UNEXPECTED;
- goto done;
- }
-
- GST_LOG_OBJECT (ogg, "pull data %" G_GINT64_FORMAT, ogg->offset);
- ret = gst_pad_pull_range (ogg->sinkpad, ogg->offset, CHUNKSIZE, &buffer);
- if (ret != GST_FLOW_OK) {
- GST_LOG_OBJECT (ogg, "Failed pull_range");
- goto done;
- }
-
- ogg->offset += GST_BUFFER_SIZE (buffer);
-
- if (G_UNLIKELY (ogg->newsegment)) {
- gst_ogg_demux_send_event (ogg, ogg->newsegment);
- ogg->newsegment = NULL;
- }
-
- ret = gst_ogg_demux_chain (ogg->sinkpad, buffer);
- if (ret != GST_FLOW_OK) {
- GST_LOG_OBJECT (ogg, "Failed demux_chain");
- goto done;
- }
-
- /* check for the end of the segment */
- if (ogg->segment.stop != -1 && ogg->segment.last_stop != -1) {
- if (ogg->segment.last_stop > ogg->segment.stop) {
- ret = GST_FLOW_UNEXPECTED;
- goto done;
- }
- }
-done:
- return ret;
-}
-
-/* reverse mode.
- *
- * We read the pages backwards and send the packets forwards. The first packet
- * in the page will be pushed with the DISCONT flag set.
- *
- * Special care has to be taken for continued pages, which we can only decode
- * when we have the previous page(s).
- */
-static GstFlowReturn
-gst_ogg_demux_loop_reverse (GstOggDemux * ogg)
-{
- GstFlowReturn ret;
- ogg_page page;
- gint64 offset;
-
- if (ogg->offset == 0) {
- GST_LOG_OBJECT (ogg, "no more data to pull %" G_GINT64_FORMAT
- " == 0", ogg->offset);
- ret = GST_FLOW_UNEXPECTED;
- goto done;
- }
-
- GST_LOG_OBJECT (ogg, "read page from %" G_GINT64_FORMAT, ogg->offset);
- ret = gst_ogg_demux_get_prev_page (ogg, &page, &offset);
- if (ret != GST_FLOW_OK)
- goto done;
-
- ogg->offset = offset;
-
- if (G_UNLIKELY (ogg->newsegment)) {
- gst_ogg_demux_send_event (ogg, ogg->newsegment);
- ogg->newsegment = NULL;
- }
-
- ret = gst_ogg_demux_handle_page (ogg, &page);
- if (ret != GST_FLOW_OK)
- goto done;
-
- /* check for the end of the segment */
- if (ogg->segment.start != -1 && ogg->segment.last_stop != -1) {
- if (ogg->segment.last_stop <= ogg->segment.start) {
- ret = GST_FLOW_UNEXPECTED;
- goto done;
- }
- }
-done:
- return ret;
-}
-
-static void
-gst_ogg_demux_sync_streams (GstOggDemux * ogg)
-{
- GstClockTime cur;
- GstOggChain *chain;
- guint i;
-
- chain = ogg->current_chain;
- cur = ogg->segment.last_stop;
- if (chain == NULL || cur == -1)
- return;
-
- for (i = 0; i < chain->streams->len; i++) {
- GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, i);
-
- /* Theoretically, we should be doing this for all streams, but we're only
- * doing it for known-to-be-sparse streams at the moment in order not to
- * break things for wrongly-muxed streams (like we used to produce once) */
- if (stream->is_sparse && stream->last_stop != GST_CLOCK_TIME_NONE) {
-
- /* Does this stream lag? Random threshold of 2 seconds */
- if (GST_CLOCK_DIFF (stream->last_stop, cur) > (2 * GST_SECOND)) {
- GST_DEBUG_OBJECT (stream, "synchronizing stream with others by "
- "advancing time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (stream->last_stop), GST_TIME_ARGS (cur));
- stream->last_stop = cur;
- /* advance stream time (FIXME: is this right, esp. time_pos?) */
- gst_pad_push_event (GST_PAD_CAST (stream),
- gst_event_new_new_segment (TRUE, ogg->segment.rate,
- GST_FORMAT_TIME, stream->last_stop, -1, stream->last_stop));
- }
- }
- }
-}
-
-/* random access code
- *
- * - first find all the chains and streams by scanning the file.
- * - then get and chain buffers, just like the streaming case.
- * - when seeking, we can use the chain info to perform the seek.
- */
-static void
-gst_ogg_demux_loop (GstOggPad * pad)
-{
- GstOggDemux *ogg;
- GstFlowReturn ret;
- GstEvent *event;
-
- ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (pad));
-
- if (ogg->need_chains) {
- gboolean res;
-
- /* this is the only place where we write chains and thus need to lock. */
- GST_CHAIN_LOCK (ogg);
- ret = gst_ogg_demux_find_chains (ogg);
- GST_CHAIN_UNLOCK (ogg);
- if (ret != GST_FLOW_OK)
- goto chain_read_failed;
-
- ogg->need_chains = FALSE;
-
- GST_OBJECT_LOCK (ogg);
- ogg->running = TRUE;
- event = ogg->event;
- ogg->event = NULL;
- GST_OBJECT_UNLOCK (ogg);
-
- /* and seek to configured positions without FLUSH */
- res = gst_ogg_demux_perform_seek (ogg, event);
- if (event)
- gst_event_unref (event);
-
- if (!res)
- goto seek_failed;
- }
-
- if (ogg->segment.rate >= 0.0)
- ret = gst_ogg_demux_loop_forward (ogg);
- else
- ret = gst_ogg_demux_loop_reverse (ogg);
-
- if (ret != GST_FLOW_OK)
- goto pause;
-
- gst_ogg_demux_sync_streams (ogg);
- return;
-
- /* ERRORS */
-chain_read_failed:
- {
- /* error was posted */
- goto pause;
- }
-seek_failed:
- {
- GST_ELEMENT_ERROR (ogg, STREAM, DEMUX, (NULL),
- ("failed to start demuxing ogg"));
- ret = GST_FLOW_ERROR;
- goto pause;
- }
-pause:
- {
- const gchar *reason = gst_flow_get_name (ret);
- GstEvent *event = NULL;
-
- GST_LOG_OBJECT (ogg, "pausing task, reason %s", reason);
- ogg->segment_running = FALSE;
- gst_pad_pause_task (ogg->sinkpad);
-
- if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
- if (ret == GST_FLOW_UNEXPECTED) {
- /* perform EOS logic */
- if (ogg->segment.flags & GST_SEEK_FLAG_SEGMENT) {
- gint64 stop;
- GstMessage *message;
-
- /* for segment playback we need to post when (in stream time)
- * we stopped, this is either stop (when set) or the duration. */
- if ((stop = ogg->segment.stop) == -1)
- stop = ogg->segment.duration;
-
- GST_LOG_OBJECT (ogg, "Sending segment done, at end of segment");
- message =
- gst_message_new_segment_done (GST_OBJECT (ogg), GST_FORMAT_TIME,
- stop);
- gst_message_set_seqnum (message, ogg->seqnum);
-
- gst_element_post_message (GST_ELEMENT (ogg), message);
- } else {
- /* normal playback, send EOS to all linked pads */
- GST_LOG_OBJECT (ogg, "Sending EOS, at end of stream");
- event = gst_event_new_eos ();
- }
- } else {
- GST_ELEMENT_ERROR (ogg, STREAM, FAILED,
- (_("Internal data stream error.")),
- ("stream stopped, reason %s", reason));
- event = gst_event_new_eos ();
- }
- if (event) {
- gst_event_set_seqnum (event, ogg->seqnum);
- gst_ogg_demux_send_event (ogg, event);
- }
- }
- return;
- }
-}
-
-static void
-gst_ogg_demux_clear_chains (GstOggDemux * ogg)
-{
- gint i;
-
- gst_ogg_demux_deactivate_current_chain (ogg);
-
- GST_CHAIN_LOCK (ogg);
- for (i = 0; i < ogg->chains->len; i++) {
- GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
-
- gst_ogg_chain_free (chain);
- }
- ogg->chains = g_array_set_size (ogg->chains, 0);
- GST_CHAIN_UNLOCK (ogg);
-}
-
-/* this function is called when the pad is activated and should start
- * processing data.
- *
- * We check if we can do random access to decide if we work push or
- * pull based.
- */
-static gboolean
-gst_ogg_demux_sink_activate (GstPad * sinkpad)
-{
- if (gst_pad_check_pull_range (sinkpad)) {
- GST_DEBUG_OBJECT (sinkpad, "activating pull");
- return gst_pad_activate_pull (sinkpad, TRUE);
- } else {
- GST_DEBUG_OBJECT (sinkpad, "activating push");
- return gst_pad_activate_push (sinkpad, TRUE);
- }
-}
-
-/* this function gets called when we activate ourselves in push mode.
- * We cannot seek (ourselves) in the stream */
-static gboolean
-gst_ogg_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
-{
- GstOggDemux *ogg;
-
- ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad));
-
- ogg->pullmode = FALSE;
-
- return TRUE;
-}
-
-/* this function gets called when we activate ourselves in pull mode.
- * We can perform random access to the resource and we start a task
- * to start reading */
-static gboolean
-gst_ogg_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
-{
- GstOggDemux *ogg;
-
- ogg = GST_OGG_DEMUX (GST_OBJECT_PARENT (sinkpad));
-
- if (active) {
- ogg->need_chains = TRUE;
- ogg->pullmode = TRUE;
-
- return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_ogg_demux_loop,
- sinkpad);
- } else {
- return gst_pad_stop_task (sinkpad);
- }
-}
-
-static GstStateChangeReturn
-gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
-{
- GstOggDemux *ogg;
- GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
-
- ogg = GST_OGG_DEMUX (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- ogg->basetime = 0;
- ogg->have_fishead = FALSE;
- ogg_sync_init (&ogg->sync);
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- ogg_sync_reset (&ogg->sync);
- ogg->running = FALSE;
- ogg->segment_running = FALSE;
- gst_segment_init (&ogg->segment, GST_FORMAT_TIME);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- result = parent_class->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_ogg_demux_clear_chains (ogg);
- GST_OBJECT_LOCK (ogg);
- ogg->running = FALSE;
- ogg->segment_running = FALSE;
- ogg->have_fishead = FALSE;
- GST_OBJECT_UNLOCK (ogg);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- ogg_sync_clear (&ogg->sync);
- break;
- default:
- break;
- }
- return result;
-}
-
-gboolean
-gst_ogg_demux_plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_debug, "oggdemux", 0, "ogg demuxer");
- GST_DEBUG_CATEGORY_INIT (gst_ogg_demux_setup_debug, "oggdemux_setup", 0,
- "ogg demuxer setup stage when parsing pipeline");
-
-#if ENABLE_NLS
- GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
- LOCALEDIR);
- bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-#endif
-
- return gst_element_register (plugin, "oggdemux", GST_RANK_PRIMARY,
- GST_TYPE_OGG_DEMUX);
-}
-
-/* prints all info about the element */
-#undef GST_CAT_DEFAULT
-#define GST_CAT_DEFAULT gst_ogg_demux_setup_debug
-
-#ifdef GST_DISABLE_GST_DEBUG
-
-static void
-gst_ogg_print (GstOggDemux * ogg)
-{
- /* NOP */
-}
-
-#else /* !GST_DISABLE_GST_DEBUG */
-
-static void
-gst_ogg_print (GstOggDemux * ogg)
-{
- guint j, i;
-
- GST_INFO_OBJECT (ogg, "%u chains", ogg->chains->len);
- GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (ogg->total_time));
-
- for (i = 0; i < ogg->chains->len; i++) {
- GstOggChain *chain = g_array_index (ogg->chains, GstOggChain *, i);
-
- GST_INFO_OBJECT (ogg, " chain %d (%u streams):", i, chain->streams->len);
- GST_INFO_OBJECT (ogg, " offset: %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT,
- chain->offset, chain->end_offset);
- GST_INFO_OBJECT (ogg, " begin time: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (chain->begin_time));
- GST_INFO_OBJECT (ogg, " total time: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (chain->total_time));
- GST_INFO_OBJECT (ogg, " segment start: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (chain->segment_start));
- GST_INFO_OBJECT (ogg, " segment stop: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (chain->segment_stop));
-
- for (j = 0; j < chain->streams->len; j++) {
- GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j);
-
- GST_INFO_OBJECT (ogg, " stream %08lx:", stream->map.serialno);
- GST_INFO_OBJECT (ogg, " start time: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (stream->start_time));
- }
- }
-}
-#endif /* GST_DISABLE_GST_DEBUG */
diff --git a/ext/ogg/gstoggdemux.h b/ext/ogg/gstoggdemux.h
deleted file mode 100644
index a47642b3..00000000
--- a/ext/ogg/gstoggdemux.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
- *
- * gstoggdemux.c: ogg stream demuxer
- *
- * 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_DEMUX_H__
-#define __GST_OGG_DEMUX_H__
-
-#include <ogg/ogg.h>
-
-#include <gst/gst.h>
-
-#include "gstoggstream.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_OGG_PAD (gst_ogg_pad_get_type())
-#define GST_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_PAD, GstOggPad))
-#define GST_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_PAD, GstOggPad))
-#define GST_IS_OGG_PAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_PAD))
-#define GST_IS_OGG_PAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_PAD))
-
-typedef struct _GstOggPad GstOggPad;
-typedef struct _GstOggPadClass GstOggPadClass;
-
-#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(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_DEMUX))
-
-GType gst_ogg_demux_get_type (void);
-
-typedef struct _GstOggDemux GstOggDemux;
-typedef struct _GstOggDemuxClass GstOggDemuxClass;
-typedef struct _GstOggChain GstOggChain;
-
-/* all information needed for one ogg chain (relevant for chained bitstreams) */
-struct _GstOggChain
-{
- GstOggDemux *ogg;
-
- gint64 offset; /* starting offset of chain */
- gint64 end_offset; /* end offset of chain */
- gint64 bytes; /* number of bytes */
-
- gboolean have_bos;
-
- GArray *streams;
-
- GstClockTime total_time; /* the total time of this chain, this is the MAX of
- the totals of all streams */
- GstClockTime begin_time; /* when this chain starts in the stream */
-
- GstClockTime segment_start; /* the timestamp of the first sample, this is the MIN of
- the start times of all streams. */
- GstClockTime segment_stop; /* the timestamp of the last page, this is the MAX of the
- streams. */
-};
-
-/* different modes for the pad */
-typedef enum
-{
- GST_OGG_PAD_MODE_INIT, /* we are feeding our internal decoder to get info */
- GST_OGG_PAD_MODE_STREAMING, /* we are streaming buffers to the outside */
-} GstOggPadMode;
-
-/* all information needed for one ogg stream */
-struct _GstOggPad
-{
- GstPad pad; /* subclass GstPad */
-
- gboolean have_type;
- GstOggPadMode mode;
-
- GstOggChain *chain; /* the chain we are part of */
- GstOggDemux *ogg; /* the ogg demuxer we are part of */
-
- GstOggStream map;
-
- gint64 packetno;
- gint64 current_granule;
- gint64 keyframe_granule;
-
- GstClockTime start_time; /* the timestamp of the first sample */
-
- gint64 first_granule; /* the granulepos of first page == first sample in next page */
- GstClockTime first_time; /* the timestamp of the second page or granuletime of first page */
-
- gboolean is_sparse; /* TRUE if this is a subtitle pad or some other sparse stream */
- GstClockTime last_stop; /* last_stop when last push occured; used to detect when we
- * need to send a newsegment update event for sparse streams */
-
- GList *continued;
-
- gboolean discont;
- GstFlowReturn last_ret; /* last return of _pad_push() */
-
- gboolean added;
-};
-
-struct _GstOggPadClass
-{
- GstPadClass parent_class;
-};
-
-/**
- * GstOggDemux:
- *
- * The ogg demuxer object structure.
- */
-struct _GstOggDemux
-{
- GstElement element;
-
- GstPad *sinkpad;
-
- gint64 length;
- gint64 read_offset;
- gint64 offset;
-
- gboolean pullmode;
- gboolean running;
-
- gboolean need_chains;
-
- /* state */
- GMutex *chain_lock; /* we need the lock to protect the chains */
- GArray *chains; /* list of chains we know */
- GstClockTime total_time;
-
- GstOggChain *current_chain;
- GstOggChain *building_chain;
-
- /* playback start/stop positions */
- GstSegment segment;
- gboolean segment_running;
- guint32 seqnum;
-
- GstEvent *event;
- GstEvent *newsegment; /* pending newsegment to be sent from _loop */
-
- /* annodex stuff */
- gboolean have_fishead;
- gint64 basetime;
- gint64 prestime;
-
- /* ogg stuff */
- ogg_sync_state sync;
-};
-
-struct _GstOggDemuxClass
-{
- GstElementClass parent_class;
-};
-
-
-G_END_DECLS
-
-#endif /* __GST_OGG_DEMUX_H__ */
diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c
deleted file mode 100644
index b37a5638..00000000
--- a/ext/ogg/gstoggmux.c
+++ /dev/null
@@ -1,1692 +0,0 @@
-/* OGG muxer plugin for GStreamer
- * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
- * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-oggmux
- * @see_also: <link linkend="gst-plugins-base-plugins-deoggmux">oggdemux</link>
- *
- * This element merges streams (audio and video) into ogg files.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch v4l2src num-buffers=500 ! video/x-raw-yuv,width=320,height=240 ! ffmpegcolorspace ! theoraenc ! oggmux ! filesink location=video.ogg
- * ]| Encodes a video stream captured from a v4l2-compatible camera to Ogg/Theora
- * (the encoding will stop automatically after 500 frames)
- * </refsect2>
- *
- * Last reviewed on 2008-02-06 (0.10.17)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/gst.h>
-#include <gst/base/gstcollectpads.h>
-
-#include "gstoggmux.h"
-
-/* memcpy - if someone knows a way to get rid of it, please speak up
- * note: the ogg docs even say you need this... */
-#include <string.h>
-#include <time.h>
-#include <stdlib.h> /* rand, srand, atoi */
-
-GST_DEBUG_CATEGORY_STATIC (gst_ogg_mux_debug);
-#define GST_CAT_DEFAULT gst_ogg_mux_debug
-
-/* This isn't generally what you'd want with an end-time macro, because
- technically the end time of a buffer with invalid duration is invalid. But
- for sorting ogg pages this is what we want. */
-#define GST_BUFFER_END_TIME(buf) \
- (GST_BUFFER_DURATION_IS_VALID (buf) \
- ? GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf) \
- : GST_BUFFER_TIMESTAMP (buf))
-
-#define GST_GP_FORMAT "[gp %8" G_GINT64_FORMAT "]"
-#define GST_GP_CAST(_gp) ((gint64) _gp)
-
-typedef enum
-{
- GST_OGG_FLAG_BOS = GST_ELEMENT_FLAG_LAST,
- GST_OGG_FLAG_EOS
-}
-GstOggFlag;
-
-/* elementfactory information */
-static const GstElementDetails gst_ogg_mux_details =
-GST_ELEMENT_DETAILS ("Ogg muxer",
- "Codec/Muxer",
- "mux ogg streams (info about ogg: http://xiph.org)",
- "Wim Taymans <wim@fluendo.com>");
-
-/* OggMux signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
-/* set to 0.5 seconds by default */
-#define DEFAULT_MAX_DELAY G_GINT64_CONSTANT(500000000)
-#define DEFAULT_MAX_PAGE_DELAY G_GINT64_CONSTANT(500000000)
-enum
-{
- ARG_0,
- ARG_MAX_DELAY,
- ARG_MAX_PAGE_DELAY,
-};
-
-static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/ogg")
- );
-
-static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d",
- GST_PAD_SINK,
- GST_PAD_REQUEST,
- GST_STATIC_CAPS ("video/x-theora; "
- "audio/x-vorbis; audio/x-flac; audio/x-speex; audio/x-celt; "
- "application/x-ogm-video; application/x-ogm-audio; video/x-dirac; "
- "video/x-smoke; text/x-cmml, encoded = (boolean) TRUE; "
- "subtitle/x-kate; application/x-kate")
- );
-
-static void gst_ogg_mux_base_init (gpointer g_class);
-static void gst_ogg_mux_class_init (GstOggMuxClass * klass);
-static void gst_ogg_mux_init (GstOggMux * ogg_mux);
-static void gst_ogg_mux_finalize (GObject * object);
-
-static GstFlowReturn
-gst_ogg_mux_collected (GstCollectPads * pads, GstOggMux * ogg_mux);
-static gboolean gst_ogg_mux_handle_src_event (GstPad * pad, GstEvent * event);
-static GstPad *gst_ogg_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
-static void gst_ogg_mux_release_pad (GstElement * element, GstPad * pad);
-
-static void gst_ogg_mux_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_ogg_mux_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec);
-static GstStateChangeReturn gst_ogg_mux_change_state (GstElement * element,
- GstStateChange transition);
-
-static GstElementClass *parent_class = NULL;
-
-/*static guint gst_ogg_mux_signals[LAST_SIGNAL] = { 0 }; */
-
-GType
-gst_ogg_mux_get_type (void)
-{
- static GType ogg_mux_type = 0;
-
- if (G_UNLIKELY (ogg_mux_type == 0)) {
- static const GTypeInfo ogg_mux_info = {
- sizeof (GstOggMuxClass),
- gst_ogg_mux_base_init,
- NULL,
- (GClassInitFunc) gst_ogg_mux_class_init,
- NULL,
- NULL,
- sizeof (GstOggMux),
- 0,
- (GInstanceInitFunc) gst_ogg_mux_init,
- };
- static const GInterfaceInfo preset_info = {
- NULL,
- NULL,
- NULL
- };
-
- ogg_mux_type =
- g_type_register_static (GST_TYPE_ELEMENT, "GstOggMux", &ogg_mux_info,
- 0);
-
- g_type_add_interface_static (ogg_mux_type, GST_TYPE_PRESET, &preset_info);
- }
- return ogg_mux_type;
-}
-
-static void
-gst_ogg_mux_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory));
-
- gst_element_class_set_details (element_class, &gst_ogg_mux_details);
-}
-
-static void
-gst_ogg_mux_class_init (GstOggMuxClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->finalize = gst_ogg_mux_finalize;
- gobject_class->get_property = gst_ogg_mux_get_property;
- gobject_class->set_property = gst_ogg_mux_set_property;
-
- gstelement_class->request_new_pad = gst_ogg_mux_request_new_pad;
- gstelement_class->release_pad = gst_ogg_mux_release_pad;
-
- g_object_class_install_property (gobject_class, ARG_MAX_DELAY,
- g_param_spec_uint64 ("max-delay", "Max delay",
- "Maximum delay in multiplexing streams", 0, G_MAXUINT64,
- DEFAULT_MAX_DELAY,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_MAX_PAGE_DELAY,
- g_param_spec_uint64 ("max-page-delay", "Max page delay",
- "Maximum delay for sending out a page", 0, G_MAXUINT64,
- DEFAULT_MAX_PAGE_DELAY,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state = gst_ogg_mux_change_state;
-
-}
-
-#if 0
-static const GstEventMask *
-gst_ogg_mux_get_sink_event_masks (GstPad * pad)
-{
- static const GstEventMask gst_ogg_mux_sink_event_masks[] = {
- {GST_EVENT_EOS, 0},
- {GST_EVENT_DISCONTINUOUS, 0},
- {0,}
- };
-
- return gst_ogg_mux_sink_event_masks;
-}
-#endif
-
-static void
-gst_ogg_mux_clear (GstOggMux * ogg_mux)
-{
- ogg_mux->pulling = NULL;
- ogg_mux->need_headers = TRUE;
- ogg_mux->delta_pad = NULL;
- ogg_mux->offset = 0;
- ogg_mux->next_ts = 0;
- ogg_mux->last_ts = GST_CLOCK_TIME_NONE;
-}
-
-static void
-gst_ogg_mux_init (GstOggMux * ogg_mux)
-{
- GstElementClass *klass = GST_ELEMENT_GET_CLASS (ogg_mux);
-
- ogg_mux->srcpad =
- gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
- "src"), "src");
- gst_pad_set_event_function (ogg_mux->srcpad, gst_ogg_mux_handle_src_event);
- gst_element_add_pad (GST_ELEMENT (ogg_mux), ogg_mux->srcpad);
-
- GST_OBJECT_FLAG_SET (GST_ELEMENT (ogg_mux), GST_OGG_FLAG_BOS);
-
- /* seed random number generator for creation of serial numbers */
- srand (time (NULL));
-
- ogg_mux->collect = gst_collect_pads_new ();
- gst_collect_pads_set_function (ogg_mux->collect,
- (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_ogg_mux_collected),
- ogg_mux);
-
- ogg_mux->max_delay = DEFAULT_MAX_DELAY;
- ogg_mux->max_page_delay = DEFAULT_MAX_PAGE_DELAY;
-
- gst_ogg_mux_clear (ogg_mux);
-}
-
-static void
-gst_ogg_mux_finalize (GObject * object)
-{
- GstOggMux *ogg_mux;
-
- ogg_mux = GST_OGG_MUX (object);
-
- if (ogg_mux->collect) {
- gst_object_unref (ogg_mux->collect);
- ogg_mux->collect = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_ogg_mux_ogg_pad_destroy_notify (GstCollectData * data)
-{
- GstOggPad *oggpad = (GstOggPad *) data;
- GstBuffer *buf;
-
- ogg_stream_clear (&oggpad->stream);
-
- if (oggpad->pagebuffers) {
- while ((buf = g_queue_pop_head (oggpad->pagebuffers)) != NULL) {
- gst_buffer_unref (buf);
- }
- g_queue_free (oggpad->pagebuffers);
- oggpad->pagebuffers = NULL;
- }
-}
-
-static GstPadLinkReturn
-gst_ogg_mux_sinkconnect (GstPad * pad, GstPad * peer)
-{
- GstOggMux *ogg_mux;
-
- ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (ogg_mux, "sinkconnect triggered on %s", GST_PAD_NAME (pad));
-
- gst_object_unref (ogg_mux);
-
- return GST_PAD_LINK_OK;
-}
-
-static gboolean
-gst_ogg_mux_sink_event (GstPad * pad, GstEvent * event)
-{
- GstOggMux *ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad));
- GstOggPad *ogg_pad = (GstOggPad *) gst_pad_get_element_private (pad);
- gboolean ret;
-
- GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
- GST_DEBUG_PAD_NAME (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
- /* We don't support NEWSEGMENT events */
- gst_event_unref (event);
- ret = FALSE;
- break;
- default:
- ret = TRUE;
- break;
- }
-
- /* now GstCollectPads can take care of the rest, e.g. EOS */
- if (ret)
- ret = ogg_pad->collect_event (pad, event);
-
- gst_object_unref (ogg_mux);
- return ret;
-}
-
-static GstPad *
-gst_ogg_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * req_name)
-{
- GstOggMux *ogg_mux;
- GstPad *newpad;
- GstElementClass *klass;
-
- g_return_val_if_fail (templ != NULL, NULL);
-
- if (templ->direction != GST_PAD_SINK)
- goto wrong_direction;
-
- g_return_val_if_fail (GST_IS_OGG_MUX (element), NULL);
- ogg_mux = GST_OGG_MUX (element);
-
- klass = GST_ELEMENT_GET_CLASS (element);
-
- if (templ != gst_element_class_get_pad_template (klass, "sink_%d"))
- goto wrong_template;
-
- {
- gint serial;
- gchar *name;
-
- if (req_name == NULL || strlen (req_name) < 6) {
- /* no name given when requesting the pad, use random serial number */
- serial = rand ();
- } else {
- /* parse serial number from requested padname */
- serial = atoi (&req_name[5]);
- }
- /* create new pad with the name */
- GST_DEBUG_OBJECT (ogg_mux, "Creating new pad for serial %d", serial);
- name = g_strdup_printf ("sink_%d", serial);
- newpad = gst_pad_new_from_template (templ, name);
- g_free (name);
-
- /* construct our own wrapper data structure for the pad to
- * keep track of its status */
- {
- GstOggPad *oggpad;
-
- oggpad = (GstOggPad *)
- gst_collect_pads_add_pad_full (ogg_mux->collect, newpad,
- sizeof (GstOggPad), gst_ogg_mux_ogg_pad_destroy_notify);
- ogg_mux->active_pads++;
-
- oggpad->serial = serial;
- ogg_stream_init (&oggpad->stream, serial);
- oggpad->packetno = 0;
- oggpad->pageno = 0;
- oggpad->eos = FALSE;
- /* we assume there will be some control data first for this pad */
- oggpad->state = GST_OGG_PAD_STATE_CONTROL;
- oggpad->new_page = TRUE;
- oggpad->first_delta = FALSE;
- oggpad->prev_delta = FALSE;
- oggpad->pagebuffers = g_queue_new ();
-
- oggpad->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
- gst_pad_set_event_function (newpad,
- GST_DEBUG_FUNCPTR (gst_ogg_mux_sink_event));
- }
- }
-
- /* setup some pad functions */
- gst_pad_set_link_function (newpad, gst_ogg_mux_sinkconnect);
-
- /* dd the pad to the element */
- gst_element_add_pad (element, newpad);
-
- return newpad;
-
- /* ERRORS */
-wrong_direction:
- {
- g_warning ("ogg_mux: request pad that is not a SINK pad\n");
- return NULL;
- }
-wrong_template:
- {
- g_warning ("ogg_mux: this is not our template!\n");
- return NULL;
- }
-}
-
-static void
-gst_ogg_mux_release_pad (GstElement * element, GstPad * pad)
-{
- GstOggMux *ogg_mux;
-
- ogg_mux = GST_OGG_MUX (gst_pad_get_parent (pad));
-
- gst_collect_pads_remove_pad (ogg_mux->collect, pad);
- gst_element_remove_pad (element, pad);
-
- gst_object_unref (ogg_mux);
-}
-
-/* handle events */
-static gboolean
-gst_ogg_mux_handle_src_event (GstPad * pad, GstEvent * event)
-{
- GstEventType type;
-
- type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
-
- switch (type) {
- case GST_EVENT_SEEK:
- /* disable seeking for now */
- return FALSE;
- default:
- break;
- }
-
- return gst_pad_event_default (pad, event);
-}
-
-static GstBuffer *
-gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta)
-{
- GstBuffer *buffer;
-
- /* allocate space for header and body */
- buffer = gst_buffer_new_and_alloc (page->header_len + page->body_len);
- memcpy (GST_BUFFER_DATA (buffer), page->header, page->header_len);
- memcpy (GST_BUFFER_DATA (buffer) + page->header_len,
- page->body, page->body_len);
-
- /* Here we set granulepos as our OFFSET_END to give easy direct access to
- * this value later. Before we push it, we reset this to OFFSET + SIZE
- * (see gst_ogg_mux_push_buffer). */
- GST_BUFFER_OFFSET_END (buffer) = ogg_page_granulepos (page);
- if (delta)
- GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
-
- GST_LOG_OBJECT (mux, GST_GP_FORMAT
- " created buffer %p from ogg page",
- GST_GP_CAST (ogg_page_granulepos (page)), buffer);
-
- return buffer;
-}
-
-static GstFlowReturn
-gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer)
-{
- GstCaps *caps;
-
- /* fix up OFFSET and OFFSET_END again */
- GST_BUFFER_OFFSET (buffer) = mux->offset;
- mux->offset += GST_BUFFER_SIZE (buffer);
- GST_BUFFER_OFFSET_END (buffer) = mux->offset;
-
- /* Ensure we have monotonically increasing timestamps in the output. */
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
- if (mux->last_ts != GST_CLOCK_TIME_NONE &&
- GST_BUFFER_TIMESTAMP (buffer) < mux->last_ts)
- GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts;
- else
- mux->last_ts = GST_BUFFER_TIMESTAMP (buffer);
- }
-
- caps = gst_pad_get_negotiated_caps (mux->srcpad);
- gst_buffer_set_caps (buffer, caps);
- if (caps)
- gst_caps_unref (caps);
-
- return gst_pad_push (mux->srcpad, buffer);
-}
-
-/* if all queues have at least one page, dequeue the page with the lowest
- * timestamp */
-static gboolean
-gst_ogg_mux_dequeue_page (GstOggMux * mux, GstFlowReturn * flowret)
-{
- GSList *walk;
- GstOggPad *opad = NULL; /* "oldest" pad */
- GstClockTime oldest = GST_CLOCK_TIME_NONE;
- GstBuffer *buf = NULL;
- gboolean ret = FALSE;
-
- *flowret = GST_FLOW_OK;
-
- walk = mux->collect->data;
- while (walk) {
- GstOggPad *pad = (GstOggPad *) walk->data;
-
- /* We need each queue to either be at EOS, or have one or more pages
- * available with a set granulepos (i.e. not -1), otherwise we don't have
- * enough data yet to determine which stream needs to go next for correct
- * time ordering. */
- if (pad->pagebuffers->length == 0) {
- if (pad->eos) {
- GST_LOG_OBJECT (pad->collect.pad,
- "pad is EOS, skipping for dequeue decision");
- } else {
- GST_LOG_OBJECT (pad->collect.pad,
- "no pages in this queue, can't dequeue");
- return FALSE;
- }
- } else {
- /* We then need to check for a non-negative granulepos */
- int i;
- gboolean valid = FALSE;
-
- for (i = 0; i < pad->pagebuffers->length; i++) {
- buf = g_queue_peek_nth (pad->pagebuffers, i);
- /* Here we check the OFFSET_END, which is actually temporarily the
- * granulepos value for this buffer */
- if (GST_BUFFER_OFFSET_END (buf) != -1) {
- valid = TRUE;
- break;
- }
- }
- if (!valid) {
- GST_LOG_OBJECT (pad->collect.pad,
- "No page timestamps in queue, can't dequeue");
- return FALSE;
- }
- }
-
- walk = g_slist_next (walk);
- }
-
- walk = mux->collect->data;
- while (walk) {
- GstOggPad *pad = (GstOggPad *) walk->data;
-
- /* any page with a granulepos of -1 can be pushed immediately.
- * TODO: it CAN be, but it seems silly to do so? */
- buf = g_queue_peek_head (pad->pagebuffers);
- while (buf && GST_BUFFER_OFFSET_END (buf) == -1) {
- GST_LOG_OBJECT (pad->collect.pad, "[gp -1] pushing page");
- g_queue_pop_head (pad->pagebuffers);
- *flowret = gst_ogg_mux_push_buffer (mux, buf);
- buf = g_queue_peek_head (pad->pagebuffers);
- ret = TRUE;
- }
-
- if (buf) {
- /* if no oldest buffer yet, take this one */
- if (oldest == GST_CLOCK_TIME_NONE) {
- GST_LOG_OBJECT (mux, "no oldest yet, taking buffer %p from pad %"
- GST_PTR_FORMAT " with gp time %" GST_TIME_FORMAT,
- buf, pad->collect.pad, GST_TIME_ARGS (GST_BUFFER_OFFSET (buf)));
- oldest = GST_BUFFER_OFFSET (buf);
- opad = pad;
- } else {
- /* if we have an oldest, compare with this one */
- if (GST_BUFFER_OFFSET (buf) < oldest) {
- GST_LOG_OBJECT (mux, "older buffer %p, taking from pad %"
- GST_PTR_FORMAT " with gp time %" GST_TIME_FORMAT,
- buf, pad->collect.pad, GST_TIME_ARGS (GST_BUFFER_OFFSET (buf)));
- oldest = GST_BUFFER_OFFSET (buf);
- opad = pad;
- }
- }
- }
- walk = g_slist_next (walk);
- }
-
- if (oldest != GST_CLOCK_TIME_NONE) {
- g_assert (opad);
- buf = g_queue_pop_head (opad->pagebuffers);
- GST_LOG_OBJECT (opad->collect.pad,
- GST_GP_FORMAT " pushing oldest page buffer %p (granulepos time %"
- GST_TIME_FORMAT ")", GST_BUFFER_OFFSET_END (buf), buf,
- GST_TIME_ARGS (GST_BUFFER_OFFSET (buf)));
- *flowret = gst_ogg_mux_push_buffer (mux, buf);
- ret = TRUE;
- }
-
- return ret;
-}
-
-/* put the given ogg page on a per-pad queue, timestamping it correctly.
- * after that, dequeue and push as many pages as possible.
- * Caller should make sure:
- * pad->timestamp was set with the timestamp of the first packet put
- * on the page
- * pad->timestamp_end was set with the timestamp + duration of the last packet
- * put on the page
- * pad->gp_time was set with the time matching the gp of the last
- * packet put on the page
- *
- * will also reset timestamp and timestamp_end, so caller func can restart
- * counting.
- */
-static GstFlowReturn
-gst_ogg_mux_pad_queue_page (GstOggMux * mux, GstOggPad * pad, ogg_page * page,
- gboolean delta)
-{
- GstFlowReturn ret;
- GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page, delta);
-
- /* take the timestamp of the first packet on this page */
- GST_BUFFER_TIMESTAMP (buffer) = pad->timestamp;
- GST_BUFFER_DURATION (buffer) = pad->timestamp_end - pad->timestamp;
- /* take the gp time of the last completed packet on this page */
- GST_BUFFER_OFFSET (buffer) = pad->gp_time;
-
- /* the next page will start where the current page's end time leaves off */
- pad->timestamp = pad->timestamp_end;
-
- g_queue_push_tail (pad->pagebuffers, buffer);
- GST_LOG_OBJECT (pad->collect.pad, GST_GP_FORMAT
- " queued buffer page %p (gp time %"
- GST_TIME_FORMAT ", timestamp %" GST_TIME_FORMAT
- "), %d page buffers queued", GST_GP_CAST (ogg_page_granulepos (page)),
- buffer, GST_TIME_ARGS (GST_BUFFER_OFFSET (buffer)),
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
- g_queue_get_length (pad->pagebuffers));
-
- while (gst_ogg_mux_dequeue_page (mux, &ret)) {
- if (ret != GST_FLOW_OK)
- break;
- }
-
- return ret;
-}
-
-/*
- * Given two pads, compare the buffers queued on it.
- * Returns:
- * 0 if they have an equal priority
- * -1 if the first is better
- * 1 if the second is better
- * Priority decided by: a) validity, b) older timestamp, c) smaller number
- * of muxed pages
- */
-static gint
-gst_ogg_mux_compare_pads (GstOggMux * ogg_mux, GstOggPad * first,
- GstOggPad * second)
-{
- guint64 firsttime, secondtime;
-
- /* if the first pad doesn't contain anything or is even NULL, return
- * the second pad as best candidate and vice versa */
- if (first == NULL || (first->buffer == NULL && first->next_buffer == NULL))
- return 1;
- if (second == NULL || (second->buffer == NULL && second->next_buffer == NULL))
- return -1;
-
- /* no timestamp on first buffer, it must go first */
- if (first->buffer)
- firsttime = GST_BUFFER_TIMESTAMP (first->buffer);
- else
- firsttime = GST_BUFFER_TIMESTAMP (first->next_buffer);
- if (firsttime == GST_CLOCK_TIME_NONE)
- return -1;
-
- /* no timestamp on second buffer, it must go first */
- if (second->buffer)
- secondtime = GST_BUFFER_TIMESTAMP (second->buffer);
- else
- secondtime = GST_BUFFER_TIMESTAMP (second->next_buffer);
- if (secondtime == GST_CLOCK_TIME_NONE)
- return 1;
-
- /* first buffer has higher timestamp, second one should go first */
- if (secondtime < firsttime)
- return 1;
- /* second buffer has higher timestamp, first one should go first */
- else if (secondtime > firsttime)
- return -1;
- else {
- /* buffers with equal timestamps, prefer the pad that has the
- * least number of pages muxed */
- if (second->pageno < first->pageno)
- return 1;
- else if (second->pageno > first->pageno)
- return -1;
- }
-
- /* same priority if all of the above failed */
- return 0;
-}
-
-/* make sure at least one buffer is queued on all pads, two if possible
- *
- * if pad->buffer == NULL, pad->next_buffer != NULL, then
- * we do not know if the buffer is the last or not
- * if pad->buffer != NULL, pad->next_buffer != NULL, then
- * pad->buffer is not the last buffer for the pad
- * if pad->buffer != NULL, pad->next_buffer == NULL, then
- * pad->buffer if the last buffer for the pad
- *
- * returns a pointer to an oggpad that holds the best buffer, or
- * NULL when no pad was usable. "best" means the buffer marked
- * with the lowest timestamp. If best->buffer == NULL then nothing
- * should be done until more data arrives */
-static GstOggPad *
-gst_ogg_mux_queue_pads (GstOggMux * ogg_mux)
-{
- GstOggPad *bestpad = NULL, *still_hungry = NULL;
- GSList *walk;
-
- /* try to make sure we have a buffer from each usable pad first */
- walk = ogg_mux->collect->data;
- while (walk) {
- GstOggPad *pad;
- GstCollectData *data;
-
- data = (GstCollectData *) walk->data;
- pad = (GstOggPad *) data;
-
- walk = g_slist_next (walk);
-
- GST_LOG_OBJECT (data->pad, "looking at pad for buffer");
-
- /* try to get a new buffer for this pad if needed and possible */
- if (pad->buffer == NULL) {
- GstBuffer *buf;
- gboolean incaps;
-
- /* shift the buffer along if needed (it's okay if next_buffer is NULL) */
- if (pad->buffer == NULL) {
- GST_LOG_OBJECT (data->pad, "shifting buffer %" GST_PTR_FORMAT,
- pad->next_buffer);
- pad->buffer = pad->next_buffer;
- pad->next_buffer = NULL;
- }
-
- buf = gst_collect_pads_pop (ogg_mux->collect, data);
- GST_LOG_OBJECT (data->pad, "popped buffer %" GST_PTR_FORMAT, buf);
-
- /* On EOS we get a NULL buffer */
- if (buf != NULL) {
- if (ogg_mux->delta_pad == NULL &&
- GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
- ogg_mux->delta_pad = pad;
-
- incaps = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
- /* if we need headers */
- if (pad->state == GST_OGG_PAD_STATE_CONTROL) {
- /* and we have one */
- if (incaps) {
- GST_DEBUG_OBJECT (ogg_mux,
- "got incaps buffer in control state, ignoring");
- /* just ignore */
- gst_buffer_unref (buf);
- buf = NULL;
- } else {
- GST_DEBUG_OBJECT (ogg_mux,
- "got data buffer in control state, switching " "to data mode");
- /* this is a data buffer so switch to data state */
- pad->state = GST_OGG_PAD_STATE_DATA;
- }
- }
- } else {
- GST_DEBUG_OBJECT (data->pad, "EOS on pad");
- if (!pad->eos) {
- ogg_page page;
- GstFlowReturn ret;
-
- /* it's no longer active */
- ogg_mux->active_pads--;
-
- /* Just gone to EOS. Flush existing page(s) */
- pad->eos = TRUE;
-
- while (ogg_stream_flush (&pad->stream, &page)) {
- /* Place page into the per-pad queue */
- ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page,
- pad->first_delta);
- /* increment the page number counter */
- pad->pageno++;
- /* mark other pages as delta */
- pad->first_delta = TRUE;
- }
- }
- }
-
- pad->next_buffer = buf;
- }
-
- /* we should have a buffer now, see if it is the best pad to
- * pull on */
- if (pad->buffer || pad->next_buffer) {
- if (gst_ogg_mux_compare_pads (ogg_mux, bestpad, pad) > 0) {
- GST_LOG_OBJECT (data->pad,
- "new best pad, with buffers %" GST_PTR_FORMAT
- " and %" GST_PTR_FORMAT, pad->buffer, pad->next_buffer);
-
- bestpad = pad;
- }
- } else if (!pad->eos) {
- GST_LOG_OBJECT (data->pad, "hungry pad");
- still_hungry = pad;
- }
- }
-
- if (still_hungry)
- /* drop back into collectpads... */
- return still_hungry;
- else
- return bestpad;
-}
-
-static GList *
-gst_ogg_mux_get_headers (GstOggPad * pad)
-{
- GList *res = NULL;
- GstStructure *structure;
- GstCaps *caps;
- GstPad *thepad;
-
- thepad = pad->collect.pad;
-
- GST_LOG_OBJECT (thepad, "getting headers");
-
- caps = gst_pad_get_negotiated_caps (thepad);
- if (caps != NULL) {
- const GValue *streamheader;
-
- structure = gst_caps_get_structure (caps, 0);
- streamheader = gst_structure_get_value (structure, "streamheader");
- if (streamheader != NULL) {
- GST_LOG_OBJECT (thepad, "got header");
- if (G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY) {
- GArray *bufarr = g_value_peek_pointer (streamheader);
- gint i;
-
- GST_LOG_OBJECT (thepad, "got fixed list");
-
- for (i = 0; i < bufarr->len; i++) {
- GValue *bufval = &g_array_index (bufarr, GValue, i);
-
- GST_LOG_OBJECT (thepad, "item %d", i);
- if (G_VALUE_TYPE (bufval) == GST_TYPE_BUFFER) {
- GstBuffer *buf = g_value_peek_pointer (bufval);
-
- GST_LOG_OBJECT (thepad, "adding item %d to header list", i);
-
- gst_buffer_ref (buf);
- res = g_list_append (res, buf);
- }
- }
- } else {
- GST_LOG_OBJECT (thepad, "streamheader is not fixed list");
- }
- } else if (gst_structure_has_name (structure, "video/x-dirac")) {
- res = g_list_append (res, pad->buffer);
- pad->buffer = pad->next_buffer;
- pad->next_buffer = NULL;
- pad->always_flush_page = TRUE;
- } else {
- GST_LOG_OBJECT (thepad, "caps don't have streamheader");
- }
- gst_caps_unref (caps);
- } else {
- GST_LOG_OBJECT (thepad, "got empty caps as negotiated format");
- }
- return res;
-}
-
-static GstCaps *
-gst_ogg_mux_set_header_on_caps (GstCaps * caps, GList * buffers)
-{
- GstStructure *structure;
- GValue array = { 0 };
- GList *walk = buffers;
-
- caps = gst_caps_make_writable (caps);
-
- structure = gst_caps_get_structure (caps, 0);
-
- /* put buffers in a fixed list */
- g_value_init (&array, GST_TYPE_ARRAY);
-
- while (walk) {
- GstBuffer *buf = GST_BUFFER (walk->data);
- GstBuffer *copy;
- GValue value = { 0 };
-
- walk = walk->next;
-
- /* mark buffer */
- GST_LOG ("Setting IN_CAPS on buffer of length %d", GST_BUFFER_SIZE (buf));
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
-
- g_value_init (&value, GST_TYPE_BUFFER);
- copy = gst_buffer_copy (buf);
- gst_value_set_buffer (&value, copy);
- gst_buffer_unref (copy);
- gst_value_array_append_value (&array, &value);
- g_value_unset (&value);
- }
- gst_structure_set_value (structure, "streamheader", &array);
- g_value_unset (&array);
-
- return caps;
-}
-
-/*
- * For each pad we need to write out one (small) header in one
- * page that allows decoders to identify the type of the stream.
- * After that we need to write out all extra info for the decoders.
- * In the case of a codec that also needs data as configuration, we can
- * find that info in the streamcaps.
- * After writing the headers we must start a new page for the data.
- */
-static GstFlowReturn
-gst_ogg_mux_send_headers (GstOggMux * mux)
-{
- GSList *walk;
- GList *hbufs, *hwalk;
- GstCaps *caps;
- GstFlowReturn ret;
-
- hbufs = NULL;
- ret = GST_FLOW_OK;
-
- GST_LOG_OBJECT (mux, "collecting headers");
-
- walk = mux->collect->data;
- while (walk) {
- GstOggPad *pad;
- GstPad *thepad;
-
- pad = (GstOggPad *) walk->data;
- thepad = pad->collect.pad;
-
- walk = g_slist_next (walk);
-
- GST_LOG_OBJECT (mux, "looking at pad %s:%s", GST_DEBUG_PAD_NAME (thepad));
-
- /* if the pad has no buffer, we don't care */
- if (pad->buffer == NULL && pad->next_buffer == NULL)
- continue;
-
- /* now figure out the headers */
- pad->headers = gst_ogg_mux_get_headers (pad);
- }
-
- GST_LOG_OBJECT (mux, "creating BOS pages");
- walk = mux->collect->data;
- while (walk) {
- GstOggPad *pad;
- GstBuffer *buf;
- ogg_packet packet;
- ogg_page page;
- GstPad *thepad;
- GstCaps *caps;
- GstStructure *structure;
- GstBuffer *hbuf;
-
- pad = (GstOggPad *) walk->data;
- thepad = pad->collect.pad;
- caps = gst_pad_get_negotiated_caps (thepad);
- structure = gst_caps_get_structure (caps, 0);
-
- walk = walk->next;
-
- pad->packetno = 0;
-
- GST_LOG_OBJECT (thepad, "looping over headers");
-
- if (pad->headers) {
- buf = GST_BUFFER (pad->headers->data);
- pad->headers = g_list_remove (pad->headers, buf);
- } else if (pad->buffer) {
- buf = pad->buffer;
- gst_buffer_ref (buf);
- } else if (pad->next_buffer) {
- buf = pad->next_buffer;
- gst_buffer_ref (buf);
- } else {
- /* fixme -- should be caught in the previous list traversal. */
- GST_OBJECT_LOCK (pad);
- g_critical ("No headers or buffers on pad %s:%s",
- GST_DEBUG_PAD_NAME (pad));
- GST_OBJECT_UNLOCK (pad);
- continue;
- }
-
- /* create a packet from the buffer */
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
- packet.granulepos = GST_BUFFER_OFFSET_END (buf);
- if (packet.granulepos == -1)
- packet.granulepos = 0;
- /* mark BOS and packet number */
- packet.b_o_s = (pad->packetno == 0);
- packet.packetno = pad->packetno++;
- /* mark EOS */
- packet.e_o_s = 0;
-
- /* swap the packet in */
- ogg_stream_packetin (&pad->stream, &packet);
- gst_buffer_unref (buf);
-
- GST_LOG_OBJECT (thepad, "flushing out BOS page");
- if (!ogg_stream_flush (&pad->stream, &page))
- g_critical ("Could not flush BOS page");
-
- hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
-
- GST_LOG_OBJECT (mux, "swapped out page with mime type %s",
- gst_structure_get_name (structure));
-
- /* quick hack: put Theora and Dirac video pages at the front.
- * Ideally, we would have a settable enum for which Ogg
- * profile we work with, and order based on that.
- * (FIXME: if there is more than one video stream, shouldn't we only put
- * one's BOS into the first page, followed by an audio stream's BOS, and
- * only then followed by the remaining video and audio streams?) */
- if (gst_structure_has_name (structure, "video/x-theora")) {
- GST_DEBUG_OBJECT (thepad, "putting %s page at the front", "Theora");
- hbufs = g_list_prepend (hbufs, hbuf);
- pad->always_flush_page = TRUE;
- } else if (gst_structure_has_name (structure, "video/x-dirac")) {
- GST_DEBUG_OBJECT (thepad, "putting %s page at the front", "Dirac");
- hbufs = g_list_prepend (hbufs, hbuf);
- pad->always_flush_page = TRUE;
- } else {
- hbufs = g_list_append (hbufs, hbuf);
- }
- gst_caps_unref (caps);
- }
-
- GST_LOG_OBJECT (mux, "creating next headers");
- walk = mux->collect->data;
- while (walk) {
- GstOggPad *pad;
- GstPad *thepad;
-
- pad = (GstOggPad *) walk->data;
- thepad = pad->collect.pad;
-
- walk = walk->next;
-
- GST_LOG_OBJECT (mux, "looping over headers for pad %s:%s",
- GST_DEBUG_PAD_NAME (thepad));
-
- hwalk = pad->headers;
- while (hwalk) {
- GstBuffer *buf = GST_BUFFER (hwalk->data);
- ogg_packet packet;
- ogg_page page;
-
- hwalk = hwalk->next;
-
- /* create a packet from the buffer */
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
- packet.granulepos = GST_BUFFER_OFFSET_END (buf);
- if (packet.granulepos == -1)
- packet.granulepos = 0;
- /* mark BOS and packet number */
- packet.b_o_s = (pad->packetno == 0);
- packet.packetno = pad->packetno++;
- /* mark EOS */
- packet.e_o_s = 0;
-
- /* swap the packet in */
- ogg_stream_packetin (&pad->stream, &packet);
- gst_buffer_unref (buf);
-
- /* if last header, flush page */
- if (hwalk == NULL) {
- GST_LOG_OBJECT (mux,
- "flushing page as packet %" G_GUINT64_FORMAT " is first or "
- "last packet", pad->packetno);
- while (ogg_stream_flush (&pad->stream, &page)) {
- GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
-
- GST_LOG_OBJECT (mux, "swapped out page");
- hbufs = g_list_append (hbufs, hbuf);
- }
- } else {
- GST_LOG_OBJECT (mux, "try to swap out page");
- /* just try to swap out a page then */
- while (ogg_stream_pageout (&pad->stream, &page) > 0) {
- GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
-
- GST_LOG_OBJECT (mux, "swapped out page");
- hbufs = g_list_append (hbufs, hbuf);
- }
- }
- }
- g_list_free (pad->headers);
- pad->headers = NULL;
- }
- /* hbufs holds all buffers for the headers now */
-
- /* create caps with the buffers */
- caps = gst_pad_get_caps (mux->srcpad);
- if (caps) {
- caps = gst_ogg_mux_set_header_on_caps (caps, hbufs);
- gst_pad_set_caps (mux->srcpad, caps);
- gst_caps_unref (caps);
- }
- /* and send the buffers */
- while (hbufs != NULL) {
- GstBuffer *buf = GST_BUFFER (hbufs->data);
-
- hbufs = g_list_delete_link (hbufs, hbufs);
-
- if ((ret = gst_ogg_mux_push_buffer (mux, buf)) != GST_FLOW_OK)
- break;
- }
- /* free any remaining nodes/buffers in case we couldn't push them */
- g_list_foreach (hbufs, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (hbufs);
-
- return ret;
-}
-
-/* this function is called to process data on the best pending pad.
- *
- * basic idea:
- *
- * 1) store the selected pad and keep on pulling until we fill a
- * complete ogg page or the ogg page is filled above the max-delay
- * threshold. This is needed because the ogg spec says that
- * you should fill a complete page with data from the same logical
- * stream. When the page is filled, go back to 1).
- * 2) before filling a page, read ahead one more buffer to see if this
- * packet is the last of the stream. We need to do this because the ogg
- * spec mandates that the last packet should have the EOS flag set before
- * sending it to ogg. if pad->buffer is NULL we need to wait to find out
- * whether there are any more buffers.
- * 3) pages get queued on a per-pad queue. Every time a page is queued, a
- * dequeue is called, which will dequeue the oldest page on any pad, provided
- * that ALL pads have at least one marked page in the queue (or remaining
- * pads are at EOS)
- */
-static GstFlowReturn
-gst_ogg_mux_process_best_pad (GstOggMux * ogg_mux, GstOggPad * best)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- gboolean delta_unit;
- gint64 granulepos = 0;
- GstClockTime timestamp, gp_time;
-
- GST_LOG_OBJECT (ogg_mux, "best pad %" GST_PTR_FORMAT
- ", currently pulling from %" GST_PTR_FORMAT, best->collect.pad,
- ogg_mux->pulling);
-
- /* best->buffer is non-NULL, either the pad is EOS's or there is a next
- * buffer */
- if (best->next_buffer == NULL && !best->eos) {
- GST_WARNING_OBJECT (ogg_mux, "no subsequent buffer and EOS not reached");
- return GST_FLOW_WRONG_STATE;
- }
-
- /* if we were already pulling from one pad, but the new "best" buffer is
- * from another pad, we need to check if we have reason to flush a page
- * for the pad we were pulling from before */
- if (ogg_mux->pulling && best &&
- ogg_mux->pulling != best && ogg_mux->pulling->buffer) {
- GstOggPad *pad = ogg_mux->pulling;
-
- GstClockTime last_ts = GST_BUFFER_END_TIME (pad->buffer);
-
- /* if the next packet in the current page is going to make the page
- * too long, we need to flush */
- if (last_ts > ogg_mux->next_ts + ogg_mux->max_delay) {
- ogg_page page;
-
- GST_LOG_OBJECT (pad->collect.pad,
- GST_GP_FORMAT " stored packet %" G_GINT64_FORMAT
- " will make page too long, flushing",
- GST_BUFFER_OFFSET_END (pad->buffer), (gint64) pad->stream.packetno);
-
- while (ogg_stream_flush (&pad->stream, &page)) {
- /* end time of this page is the timestamp of the next buffer */
- ogg_mux->pulling->timestamp_end = GST_BUFFER_TIMESTAMP (pad->buffer);
- /* Place page into the per-pad queue */
- ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page,
- pad->first_delta);
- /* increment the page number counter */
- pad->pageno++;
- /* mark other pages as delta */
- pad->first_delta = TRUE;
- }
- pad->new_page = TRUE;
- ogg_mux->pulling = NULL;
- }
- }
-
- /* if we don't know which pad to pull on, use the best one */
- if (ogg_mux->pulling == NULL) {
- ogg_mux->pulling = best;
- GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "pulling from best pad");
-
- /* remember timestamp and gp time of first buffer for this new pad */
- if (ogg_mux->pulling != NULL) {
- ogg_mux->next_ts = GST_BUFFER_TIMESTAMP (ogg_mux->pulling->buffer);
- GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "updated times, next ts %"
- GST_TIME_FORMAT, GST_TIME_ARGS (ogg_mux->next_ts));
- } else {
- /* no pad to pull on, send EOS */
- gst_pad_push_event (ogg_mux->srcpad, gst_event_new_eos ());
- return GST_FLOW_WRONG_STATE;
- }
- }
-
- if (ogg_mux->need_headers) {
- ret = gst_ogg_mux_send_headers (ogg_mux);
- ogg_mux->need_headers = FALSE;
- }
-
- /* we are pulling from a pad, continue to do so until a page
- * has been filled and queued */
- if (ogg_mux->pulling != NULL) {
- ogg_packet packet;
- ogg_page page;
- GstBuffer *buf, *tmpbuf;
- GstOggPad *pad = ogg_mux->pulling;
- gint64 duration;
- gboolean force_flush;
-
- GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "pulling from pad");
-
- /* now see if we have a buffer */
- buf = pad->buffer;
- if (buf == NULL) {
- GST_DEBUG_OBJECT (ogg_mux, "pad was EOS");
- ogg_mux->pulling = NULL;
- return GST_FLOW_OK;
- }
-
- delta_unit = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
- duration = GST_BUFFER_DURATION (buf);
-
- /* if the current "next timestamp" on the pad is unset, then this is the
- * first packet on the new page. Update our pad's page timestamp */
- if (ogg_mux->pulling->timestamp == GST_CLOCK_TIME_NONE) {
- ogg_mux->pulling->timestamp = GST_BUFFER_TIMESTAMP (buf);
- GST_LOG_OBJECT (ogg_mux->pulling->collect.pad,
- "updated pad timestamp to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
- }
- /* create a packet from the buffer */
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
- packet.granulepos = GST_BUFFER_OFFSET_END (buf);
- if (packet.granulepos == -1)
- packet.granulepos = 0;
- /* mark BOS and packet number */
- packet.b_o_s = (pad->packetno == 0);
- packet.packetno = pad->packetno++;
- GST_LOG_OBJECT (pad->collect.pad, GST_GP_FORMAT
- " packet %" G_GINT64_FORMAT " (%ld bytes) created from buffer",
- GST_GP_CAST (packet.granulepos), (gint64) packet.packetno,
- packet.bytes);
-
- packet.e_o_s = (pad->eos ? 1 : 0);
- tmpbuf = NULL;
-
- /* we flush when we see a new keyframe */
- force_flush = (pad->prev_delta && !delta_unit) || pad->always_flush_page;
- if (duration != -1) {
- pad->duration += duration;
- /* if page duration exceeds max, flush page */
- if (pad->duration > ogg_mux->max_page_delay) {
- force_flush = TRUE;
- pad->duration = 0;
- }
- }
-
- if (GST_BUFFER_IS_DISCONT (buf)) {
- GST_LOG_OBJECT (pad->collect.pad, "got discont");
- packet.packetno++;
- /* No public API for this; hack things in */
- pad->stream.pageno++;
- force_flush = TRUE;
- }
-
- /* flush the currently built page if necessary */
- if (force_flush) {
- GST_LOG_OBJECT (pad->collect.pad,
- GST_GP_FORMAT " forced flush of page before this packet",
- GST_BUFFER_OFFSET_END (pad->buffer));
- while (ogg_stream_flush (&pad->stream, &page)) {
- /* end time of this page is the timestamp of the next buffer */
- ogg_mux->pulling->timestamp_end = GST_BUFFER_TIMESTAMP (pad->buffer);
- ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page,
- pad->first_delta);
-
- /* increment the page number counter */
- pad->pageno++;
- /* mark other pages as delta */
- pad->first_delta = TRUE;
- }
- pad->new_page = TRUE;
- }
-
- /* if this is the first packet of a new page figure out the delta flag */
- if (pad->new_page) {
- if (delta_unit) {
- /* mark the page as delta */
- pad->first_delta = TRUE;
- } else {
- /* got a keyframe */
- if (ogg_mux->delta_pad == pad) {
- /* if we get it on the pad with deltaunits,
- * we mark the page as non delta */
- pad->first_delta = FALSE;
- } else if (ogg_mux->delta_pad != NULL) {
- /* if there are pads with delta frames, we
- * must mark this one as delta */
- pad->first_delta = TRUE;
- } else {
- pad->first_delta = FALSE;
- }
- }
- pad->new_page = FALSE;
- }
-
- /* save key unit to track delta->key unit transitions */
- pad->prev_delta = delta_unit;
-
- /* swap the packet in */
- if (packet.e_o_s == 1)
- GST_DEBUG_OBJECT (pad->collect.pad, "swapping in EOS packet");
- if (packet.b_o_s == 1)
- GST_DEBUG_OBJECT (pad->collect.pad, "swapping in BOS packet");
-
- ogg_stream_packetin (&pad->stream, &packet);
-
- gp_time = GST_BUFFER_OFFSET (pad->buffer);
- granulepos = GST_BUFFER_OFFSET_END (pad->buffer);
- timestamp = GST_BUFFER_TIMESTAMP (pad->buffer);
-
- GST_LOG_OBJECT (pad->collect.pad,
- GST_GP_FORMAT " packet %" G_GINT64_FORMAT ", gp time %"
- GST_TIME_FORMAT ", timestamp %" GST_TIME_FORMAT " packetin'd",
- granulepos, (gint64) packet.packetno, GST_TIME_ARGS (gp_time),
- GST_TIME_ARGS (timestamp));
- /* don't need the old buffer anymore */
- gst_buffer_unref (pad->buffer);
- /* store new readahead buffer */
- pad->buffer = tmpbuf;
-
- /* let ogg write out the pages now. The packet we got could end
- * up in more than one page so we need to write them all */
- if (ogg_stream_pageout (&pad->stream, &page) > 0) {
- /* we have a new page, so we need to timestamp it correctly.
- * if this fresh packet ends on this page, then the page's granulepos
- * comes from that packet, and we should set this buffer's timestamp */
-
- GST_LOG_OBJECT (pad->collect.pad,
- GST_GP_FORMAT " packet %" G_GINT64_FORMAT ", time %"
- GST_TIME_FORMAT ") caused new page",
- granulepos, (gint64) packet.packetno, GST_TIME_ARGS (timestamp));
- GST_LOG_OBJECT (pad->collect.pad,
- GST_GP_FORMAT " new page %ld",
- GST_GP_CAST (ogg_page_granulepos (&page)), pad->stream.pageno);
-
- if (ogg_page_granulepos (&page) == granulepos) {
- /* the packet we streamed in finishes on the current page,
- * because the page's granulepos is the granulepos of the last
- * packet completed on that page,
- * so update the timestamp that we will give to the page */
- GST_LOG_OBJECT (pad->collect.pad,
- GST_GP_FORMAT
- " packet finishes on current page, updating gp time to %"
- GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (gp_time));
- pad->gp_time = gp_time;
- } else {
- GST_LOG_OBJECT (pad->collect.pad,
- GST_GP_FORMAT
- " packet spans beyond current page, keeping old gp time %"
- GST_TIME_FORMAT, granulepos, GST_TIME_ARGS (pad->gp_time));
- }
-
- /* push the page */
- /* end time of this page is the timestamp of the next buffer */
- pad->timestamp_end = timestamp;
- ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page, pad->first_delta);
- pad->pageno++;
- /* mark next pages as delta */
- pad->first_delta = TRUE;
-
- /* use an inner loop here to flush the remaining pages and
- * mark them as delta frames as well */
- while (ogg_stream_pageout (&pad->stream, &page) > 0) {
- if (ogg_page_granulepos (&page) == granulepos) {
- /* the page has taken up the new packet completely, which means
- * the packet ends the page and we can update the gp time
- * before pushing out */
- pad->gp_time = gp_time;
- }
-
- /* we have a complete page now, we can push the page
- * and make sure to pull on a new pad the next time around */
- ret = gst_ogg_mux_pad_queue_page (ogg_mux, pad, &page,
- pad->first_delta);
- /* increment the page number counter */
- pad->pageno++;
- }
- /* need a new page as well */
- pad->new_page = TRUE;
- pad->duration = 0;
- /* we're done pulling on this pad, make sure to choose a new
- * pad for pulling in the next iteration */
- ogg_mux->pulling = NULL;
- }
-
- /* Update the gp time, if necessary, since any future page will have at
- * least this gp time.
- */
- if (pad->gp_time < gp_time) {
- pad->gp_time = gp_time;
- GST_LOG_OBJECT (pad->collect.pad,
- "Updated running gp time of pad %" GST_PTR_FORMAT
- " to %" GST_TIME_FORMAT, pad->collect.pad, GST_TIME_ARGS (gp_time));
- }
- }
-
- return ret;
-}
-
-/* all_pads_eos:
- *
- * Checks if all pads are EOS'd by peeking.
- *
- * Returns TRUE if all pads are EOS.
- */
-static gboolean
-all_pads_eos (GstCollectPads * pads)
-{
- GSList *walk;
- gboolean alleos = TRUE;
-
- walk = pads->data;
- while (walk) {
- GstBuffer *buf;
- GstCollectData *data = (GstCollectData *) walk->data;
-
- buf = gst_collect_pads_peek (pads, data);
- if (buf) {
- alleos = FALSE;
- gst_buffer_unref (buf);
- goto beach;
- }
- walk = walk->next;
- }
-beach:
- return alleos;
-}
-
-/* This function is called when there is data on all pads.
- *
- * It finds a pad to pull on, this is done by looking at the buffers
- * to decide which one to use, and using the 'oldest' one first. It then calls
- * gst_ogg_mux_process_best_pad() to process as much data as possible.
- *
- * If all the pads have received EOS, it flushes out all data by continually
- * getting the best pad and calling gst_ogg_mux_process_best_pad() until they
- * are all empty, and then sends EOS.
- */
-static GstFlowReturn
-gst_ogg_mux_collected (GstCollectPads * pads, GstOggMux * ogg_mux)
-{
- GstOggPad *best;
- GstFlowReturn ret;
- gint activebefore;
-
- GST_LOG_OBJECT (ogg_mux, "collected");
-
- activebefore = ogg_mux->active_pads;
-
- /* queue buffers on all pads; find a buffer with the lowest timestamp */
- best = gst_ogg_mux_queue_pads (ogg_mux);
- if (best && !best->buffer) {
- GST_DEBUG_OBJECT (ogg_mux, "No buffer available on best pad");
- return GST_FLOW_OK;
- }
-
- if (!best) {
- return GST_FLOW_WRONG_STATE;
- }
-
- ret = gst_ogg_mux_process_best_pad (ogg_mux, best);
-
- if (ogg_mux->active_pads < activebefore) {
- /* If the active pad count went down, this mean at least one pad has gone
- * EOS. Since CollectPads only calls _collected() once when all pads are
- * EOS, and our code doesn't _pop() from all pads we need to check that by
- * peeking on all pads, else we won't be called again and the muxing will
- * not terminate (push out EOS). */
-
- /* if all the pads have been removed, flush all pending data */
- if ((ret == GST_FLOW_OK) && all_pads_eos (pads)) {
- GST_LOG_OBJECT (ogg_mux, "no pads remaining, flushing data");
-
- do {
- best = gst_ogg_mux_queue_pads (ogg_mux);
- if (best)
- ret = gst_ogg_mux_process_best_pad (ogg_mux, best);
- } while ((ret == GST_FLOW_OK) && (best != NULL));
-
- GST_DEBUG_OBJECT (ogg_mux, "Pushing EOS");
- gst_pad_push_event (ogg_mux->srcpad, gst_event_new_eos ());
- }
- }
-
- return ret;
-}
-
-static void
-gst_ogg_mux_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec)
-{
- GstOggMux *ogg_mux;
-
- ogg_mux = GST_OGG_MUX (object);
-
- switch (prop_id) {
- case ARG_MAX_DELAY:
- g_value_set_uint64 (value, ogg_mux->max_delay);
- break;
- case ARG_MAX_PAGE_DELAY:
- g_value_set_uint64 (value, ogg_mux->max_page_delay);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_ogg_mux_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec)
-{
- GstOggMux *ogg_mux;
-
- ogg_mux = GST_OGG_MUX (object);
-
- switch (prop_id) {
- case ARG_MAX_DELAY:
- ogg_mux->max_delay = g_value_get_uint64 (value);
- break;
- case ARG_MAX_PAGE_DELAY:
- ogg_mux->max_page_delay = g_value_get_uint64 (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/* reset all variables in the ogg pads. */
-static void
-gst_ogg_mux_init_collectpads (GstCollectPads * collect)
-{
- GSList *walk;
-
- walk = collect->data;
- while (walk) {
- GstOggPad *oggpad = (GstOggPad *) walk->data;
-
- ogg_stream_init (&oggpad->stream, oggpad->serial);
- oggpad->packetno = 0;
- oggpad->pageno = 0;
- oggpad->eos = FALSE;
- /* we assume there will be some control data first for this pad */
- oggpad->state = GST_OGG_PAD_STATE_CONTROL;
- oggpad->new_page = TRUE;
- oggpad->first_delta = FALSE;
- oggpad->prev_delta = FALSE;
- oggpad->pagebuffers = g_queue_new ();
-
- walk = g_slist_next (walk);
- }
-}
-
-/* Clear all buffers from the collectpads object */
-static void
-gst_ogg_mux_clear_collectpads (GstCollectPads * collect)
-{
- GSList *walk;
-
- for (walk = collect->data; walk; walk = g_slist_next (walk)) {
- GstOggPad *oggpad = (GstOggPad *) walk->data;
- GstBuffer *buf;
-
- ogg_stream_clear (&oggpad->stream);
-
- while ((buf = g_queue_pop_head (oggpad->pagebuffers)) != NULL) {
- gst_buffer_unref (buf);
- }
- g_queue_free (oggpad->pagebuffers);
- oggpad->pagebuffers = NULL;
-
- if (oggpad->buffer) {
- gst_buffer_unref (oggpad->buffer);
- oggpad->buffer = NULL;
- }
- if (oggpad->next_buffer) {
- gst_buffer_unref (oggpad->next_buffer);
- oggpad->next_buffer = NULL;
- }
- }
-}
-
-static GstStateChangeReturn
-gst_ogg_mux_change_state (GstElement * element, GstStateChange transition)
-{
- GstOggMux *ogg_mux;
- GstStateChangeReturn ret;
-
- ogg_mux = GST_OGG_MUX (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- gst_ogg_mux_clear (ogg_mux);
- gst_ogg_mux_init_collectpads (ogg_mux->collect);
- gst_collect_pads_start (ogg_mux->collect);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_collect_pads_stop (ogg_mux->collect);
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_ogg_mux_clear_collectpads (ogg_mux->collect);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-gboolean
-gst_ogg_mux_plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (gst_ogg_mux_debug, "oggmux", 0, "ogg muxer");
-
- return gst_element_register (plugin, "oggmux", GST_RANK_PRIMARY,
- GST_TYPE_OGG_MUX);
-}
diff --git a/ext/ogg/gstoggmux.h b/ext/ogg/gstoggmux.h
deleted file mode 100644
index fc0944f2..00000000
--- a/ext/ogg/gstoggmux.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/* OGG muxer plugin for GStreamer
- * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
- * Copyright (C) 2006 Thomas Vander Stichele <thomas at apestaart dot org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_OGG_MUX_H__
-#define __GST_OGGEMUX_H__
-
-#include <ogg/ogg.h>
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_OGG_MUX (gst_ogg_mux_get_type())
-#define GST_OGG_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_MUX, GstOggMux))
-#define GST_OGG_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_MUX, GstOggMux))
-#define GST_IS_OGG_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_MUX))
-#define GST_IS_OGG_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_MUX))
-
-typedef struct _GstOggMux GstOggMux;
-typedef struct _GstOggMuxClass GstOggMuxClass;
-
-typedef enum
-{
- GST_OGG_PAD_STATE_CONTROL = 0,
- GST_OGG_PAD_STATE_DATA = 1
-}
-GstOggPadState;
-
-/* all information needed for one ogg stream */
-typedef struct
-{
- GstCollectData collect; /* we extend the CollectData */
-
- /* These two buffers make a very simple queue - they enter as 'next_buffer'
- * and (usually) leave as 'buffer', except at EOS, when buffer will be NULL */
- GstBuffer *buffer; /* the first waiting buffer for the pad */
- GstBuffer *next_buffer; /* the second waiting buffer for the pad */
-
- gint serial;
- ogg_stream_state stream;
- gint64 packetno; /* number of next packet */
- gint64 pageno; /* number of next page */
- guint64 duration; /* duration of current page */
- gboolean eos;
- gint64 offset;
- GstClockTime timestamp; /* timestamp of the first packet on the next
- * page to be dequeued */
- GstClockTime timestamp_end; /* end timestamp of last complete packet on
- the next page to be dequeued */
- GstClockTime gp_time; /* time corresponding to the gp value of the
- last complete packet on the next page to be
- dequeued */
-
- GstOggPadState state; /* state of the pad */
-
- GList *headers;
-
- GQueue *pagebuffers; /* List of pages in buffers ready for pushing */
-
- gboolean new_page; /* starting a new page */
- gboolean first_delta; /* was the first packet in the page a delta */
- gboolean prev_delta; /* was the previous buffer a delta frame */
-
- GstPadEventFunction collect_event;
-
- gboolean always_flush_page;
-}
-GstOggPad;
-
-/**
- * GstOggMux:
- *
- * The ogg muxer object structure.
- */
-struct _GstOggMux
-{
- GstElement element;
-
- /* source pad */
- GstPad *srcpad;
-
- /* sinkpads */
- GstCollectPads *collect;
-
- /* number of pads which have not received EOS */
- gint active_pads;
-
- /* the pad we are currently using to fill a page */
- GstOggPad *pulling;
-
- /* next timestamp for the page */
- GstClockTime next_ts;
-
- /* Last timestamp actually output on src pad */
- GstClockTime last_ts;
-
- /* offset in stream */
- guint64 offset;
-
- /* need_headers */
- gboolean need_headers;
-
- guint64 max_delay;
- guint64 max_page_delay;
-
- GstOggPad *delta_pad; /* when a delta frame is detected on a stream, we mark
- pages as delta frames up to the page that has the
- keyframe */
-
-};
-
-struct _GstOggMuxClass
-{
- GstElementClass parent_class;
-};
-
-GType gst_ogg_mux_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_OGG_MUX_H__ */
diff --git a/ext/ogg/gstoggparse.c b/ext/ogg/gstoggparse.c
deleted file mode 100644
index a86958b5..00000000
--- a/ext/ogg/gstoggparse.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/* GStreamer
- * Copyright (C) 2005 Michael Smith <msmith@fluendo.com>
- *
- * gstoggparse.c: ogg stream parser
- *
- * 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.
- */
-
-/* This ogg parser is essentially a subset of the ogg demuxer - rather than
- * fully demuxing into packets, we only parse out the pages, create one
- * GstBuffer per page, set all the appropriate flags on those pages, set caps
- * appropriately (particularly the 'streamheader' which gives all the header
- * pages required for initialing decode).
- *
- * It's dramatically simpler than the full demuxer as it does not support
- * seeking.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <gst/gst.h>
-#include <ogg/ogg.h>
-#include <string.h>
-
-#include "gstoggstream.h"
-
-static const GstElementDetails gst_ogg_parse_details =
-GST_ELEMENT_DETAILS ("Ogg parser",
- "Codec/Parser",
- "parse ogg streams into pages (info about ogg: http://xiph.org)",
- "Michael Smith <msmith@fluendo.com>");
-
-GST_DEBUG_CATEGORY_STATIC (gst_ogg_parse_debug);
-#define GST_CAT_DEFAULT gst_ogg_parse_debug
-
-#define GST_TYPE_OGG_PARSE (gst_ogg_parse_get_type())
-#define GST_OGG_PARSE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_PARSE, GstOggParse))
-#define GST_OGG_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_PARSE, GstOggParse))
-#define GST_IS_OGG_PARSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_PARSE))
-#define GST_IS_OGG_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_PARSE))
-
-static GType gst_ogg_parse_get_type (void);
-
-typedef struct _GstOggParse GstOggParse;
-typedef struct _GstOggParseClass GstOggParseClass;
-
-struct _GstOggParse
-{
- GstElement element;
-
- GstPad *sinkpad; /* Sink pad we're reading data from */
-
- GstPad *srcpad; /* Source pad we're writing to */
-
- GSList *oggstreams; /* list of GstOggStreams for known streams */
-
- gint64 offset; /* Current stream offset */
-
- gboolean in_headers; /* Set if we're reading headers for streams */
-
- gboolean last_page_not_bos; /* Set if we've seen a non-BOS page */
-
- ogg_sync_state sync; /* Ogg page synchronisation */
-
- GstCaps *caps; /* Our src caps */
-};
-
-struct _GstOggParseClass
-{
- GstElementClass parent_class;
-};
-
-static void gst_ogg_parse_base_init (gpointer g_class);
-static void gst_ogg_parse_class_init (GstOggParseClass * klass);
-static void gst_ogg_parse_init (GstOggParse * ogg);
-static GstElementClass *parent_class = NULL;
-
-static GType
-gst_ogg_parse_get_type (void)
-{
- static GType ogg_parse_type = 0;
-
- if (!ogg_parse_type) {
- static const GTypeInfo ogg_parse_info = {
- sizeof (GstOggParseClass),
- gst_ogg_parse_base_init,
- NULL,
- (GClassInitFunc) gst_ogg_parse_class_init,
- NULL,
- NULL,
- sizeof (GstOggParse),
- 0,
- (GInstanceInitFunc) gst_ogg_parse_init,
- };
-
- ogg_parse_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOggParse",
- &ogg_parse_info, 0);
- }
- return ogg_parse_type;
-}
-
-static void
-free_stream (GstOggStream * stream)
-{
- g_list_foreach (stream->headers, (GFunc) gst_mini_object_unref, NULL);
- g_list_foreach (stream->unknown_pages, (GFunc) gst_mini_object_unref, NULL);
-
- g_free (stream);
-}
-
-static void
-gst_ogg_parse_delete_all_streams (GstOggParse * ogg)
-{
- g_slist_foreach (ogg->oggstreams, (GFunc) free_stream, NULL);
- g_slist_free (ogg->oggstreams);
- ogg->oggstreams = NULL;
-}
-
-static GstOggStream *
-gst_ogg_parse_new_stream (GstOggParse * parser, ogg_page * page)
-{
- GstOggStream *stream;
- ogg_packet packet;
- int ret;
- guint32 serialno;
-
- serialno = ogg_page_serialno (page);
-
- GST_DEBUG_OBJECT (parser, "creating new stream %08x", serialno);
-
- stream = g_new0 (GstOggStream, 1);
-
- stream->serialno = serialno;
- stream->in_headers = 1;
-
- if (ogg_stream_init (&stream->stream, serialno) != 0) {
- GST_ERROR ("Could not initialize ogg_stream struct for serial %08x.",
- serialno);
- return NULL;
- }
-
- /* FIXME check return */
- ogg_stream_pagein (&stream->stream, page);
-
- /* FIXME check return */
- ret = ogg_stream_packetout (&stream->stream, &packet);
- if (ret == 1) {
- gst_ogg_stream_setup_map (stream, &packet);
- }
-
- parser->oggstreams = g_slist_append (parser->oggstreams, stream);
-
- return stream;
-}
-
-static GstOggStream *
-gst_ogg_parse_find_stream (GstOggParse * parser, guint32 serialno)
-{
- GSList *l;
-
- for (l = parser->oggstreams; l != NULL; l = l->next) {
- GstOggStream *stream = (GstOggStream *) l->data;
-
- if (stream->serialno == serialno)
- return stream;
- }
- return NULL;
-}
-
-/* signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
-enum
-{
- ARG_0
- /* FILL ME */
-};
-
-static GstStaticPadTemplate ogg_parse_src_template_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/ogg")
- );
-
-static GstStaticPadTemplate ogg_parse_sink_template_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/ogg")
- );
-
-static void gst_ogg_parse_dispose (GObject * object);
-static GstStateChangeReturn gst_ogg_parse_change_state (GstElement * element,
- GstStateChange transition);
-static GstFlowReturn gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer);
-
-static void
-gst_ogg_parse_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details (element_class, &gst_ogg_parse_details);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&ogg_parse_sink_template_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&ogg_parse_src_template_factory));
-}
-
-static void
-gst_ogg_parse_class_init (GstOggParseClass * klass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- gstelement_class->change_state = gst_ogg_parse_change_state;
-
- gobject_class->dispose = gst_ogg_parse_dispose;
-}
-
-static void
-gst_ogg_parse_init (GstOggParse * ogg)
-{
- /* create the sink and source pads */
- ogg->sinkpad =
- gst_pad_new_from_static_template (&ogg_parse_sink_template_factory,
- "sink");
- ogg->srcpad =
- gst_pad_new_from_static_template (&ogg_parse_src_template_factory, "src");
-
- /* TODO: Are there any events we must handle? */
- /* gst_pad_set_event_function (ogg->sinkpad, gst_ogg_parse_handle_event); */
- gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_parse_chain);
-
- gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
- gst_element_add_pad (GST_ELEMENT (ogg), ogg->srcpad);
-
- ogg->oggstreams = NULL;
-}
-
-static void
-gst_ogg_parse_dispose (GObject * object)
-{
- GstOggParse *ogg = GST_OGG_PARSE (object);
-
- GST_LOG_OBJECT (ogg, "Disposing of object %p", ogg);
-
- ogg_sync_clear (&ogg->sync);
- gst_ogg_parse_delete_all_streams (ogg);
-
- if (ogg->caps) {
- gst_caps_unref (ogg->caps);
- ogg->caps = NULL;
- }
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-/* submit the given buffer to the ogg sync.
- *
- * Returns the number of bytes submited.
- */
-static gint
-gst_ogg_parse_submit_buffer (GstOggParse * ogg, GstBuffer * buffer)
-{
- guint size;
- guint8 *data;
- gchar *oggbuffer;
-
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
-
- /* We now have a buffer, submit it to the ogg sync layer */
- oggbuffer = ogg_sync_buffer (&ogg->sync, size);
- memcpy (oggbuffer, data, size);
- ogg_sync_wrote (&ogg->sync, size);
-
- /* We've copied all the neccesary data, so we're done with the buffer */
- gst_buffer_unref (buffer);
-
- return size;
-}
-
-static void
-gst_ogg_parse_append_header (GValue * array, GstBuffer * buf)
-{
- GValue value = { 0 };
- /* We require a copy to avoid circular refcounts */
- GstBuffer *buffer = gst_buffer_copy (buf);
-
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
-
- g_value_init (&value, GST_TYPE_BUFFER);
- gst_value_set_buffer (&value, buffer);
- gst_value_array_append_value (array, &value);
- g_value_unset (&value);
-
-}
-
-typedef enum
-{
- PAGE_HEADER, /* Header page */
- PAGE_DATA, /* Data page */
- PAGE_PENDING, /* We don't know yet, we'll have to see some future pages */
-} page_type;
-
-static page_type
-gst_ogg_parse_is_header (GstOggParse * ogg, GstOggStream * stream,
- ogg_page * page)
-{
- ogg_int64_t gpos = ogg_page_granulepos (page);
-
- if (gpos < 0)
- return PAGE_PENDING;
-
- /* This is good enough for now, but technically requires codec-specific
- * behaviour to be perfect. This is where we need the mooted library for
- * this stuff, which nobody has written.
- */
- if (gpos > 0)
- return PAGE_DATA;
- else
- return PAGE_HEADER;
-}
-
-static GstBuffer *
-gst_ogg_parse_buffer_from_page (ogg_page * page,
- guint64 offset, gboolean delta, GstClockTime timestamp)
-{
- int size = page->header_len + page->body_len;
- GstBuffer *buf = gst_buffer_new_and_alloc (size);
-
- memcpy (GST_BUFFER_DATA (buf), page->header, page->header_len);
- memcpy (GST_BUFFER_DATA (buf) + page->header_len, page->body, page->body_len);
-
- GST_BUFFER_TIMESTAMP (buf) = timestamp;
- GST_BUFFER_OFFSET (buf) = offset;
- GST_BUFFER_OFFSET_END (buf) = offset + size;
-
- return buf;
-}
-
-
-/* Reads in buffers, parses them, reframes into one-buffer-per-ogg-page, submits
- * pages to output pad.
- */
-static GstFlowReturn
-gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstOggParse *ogg;
- GstFlowReturn result = GST_FLOW_OK;
- gint ret = -1;
- guint32 serialno;
- GstBuffer *pagebuffer;
- GstClockTime buffertimestamp = GST_BUFFER_TIMESTAMP (buffer);
-
- ogg = GST_OGG_PARSE (GST_OBJECT_PARENT (pad));
-
- GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d",
- GST_BUFFER_SIZE (buffer));
-
- gst_ogg_parse_submit_buffer (ogg, buffer);
-
- while (ret != 0 && result == GST_FLOW_OK) {
- ogg_page page;
-
- /* We use ogg_sync_pageseek() rather than ogg_sync_pageout() so that we can
- * track how many bytes the ogg layer discarded (in the case of sync errors,
- * etc.); this allows us to accurately track the current stream offset
- */
- ret = ogg_sync_pageseek (&ogg->sync, &page);
- if (ret == 0) {
- /* need more data, that's fine... */
- break;
- } else if (ret < 0) {
- /* discontinuity; track how many bytes we skipped (-ret) */
- ogg->offset -= ret;
- } else {
- gint64 granule = ogg_page_granulepos (&page);
-#ifndef GST_DISABLE_GST_DEBUG
- int bos = ogg_page_bos (&page);
-#endif
- guint64 startoffset = ogg->offset;
- GstOggStream *stream;
-
- serialno = ogg_page_serialno (&page);
- stream = gst_ogg_parse_find_stream (ogg, serialno);
-
- GST_LOG_OBJECT (ogg, "Timestamping outgoing buffer as %" GST_TIME_FORMAT,
- GST_TIME_ARGS (buffertimestamp));
-
- buffertimestamp = gst_ogg_stream_get_end_time_for_granulepos (stream,
- granule);
- pagebuffer = gst_ogg_parse_buffer_from_page (&page, startoffset, FALSE,
- buffertimestamp);
-
- /* We read out 'ret' bytes, so we set the next offset appropriately */
- ogg->offset += ret;
-
- GST_LOG_OBJECT (ogg,
- "processing ogg page (serial %08x, pageno %ld, "
- "granule pos %" G_GUINT64_FORMAT ", bos %d, offset %"
- G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ")",
- serialno, ogg_page_pageno (&page),
- granule, bos, startoffset, ogg->offset);
-
- if (ogg_page_bos (&page)) {
- /* If we've seen this serialno before, this is technically an error,
- * we log this case but accept it - this one replaces the previous
- * stream with this serialno. We can do this since we're streaming, and
- * not supporting seeking...
- */
- GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno);
-
- if (stream != NULL) {
- GST_LOG_OBJECT (ogg, "Incorrect stream; repeats serial number %u "
- "at offset %" G_GINT64_FORMAT, serialno, ogg->offset);
- }
-
- if (ogg->last_page_not_bos) {
- GST_LOG_OBJECT (ogg, "Deleting all referenced streams, found a new "
- "chain starting with serial %u", serialno);
- gst_ogg_parse_delete_all_streams (ogg);
- }
-
- stream = gst_ogg_parse_new_stream (ogg, &page);
-
- ogg->last_page_not_bos = FALSE;
-
- gst_buffer_ref (pagebuffer);
- stream->headers = g_list_append (stream->headers, pagebuffer);
-
- if (!ogg->in_headers) {
- GST_LOG_OBJECT (ogg,
- "Found start of new chain at offset %" G_GUINT64_FORMAT,
- startoffset);
- ogg->in_headers = 1;
- }
-
- /* For now, we just keep the header buffer in the stream->headers list;
- * it actually gets output once we've collected the entire set
- */
- } else {
- /* Non-BOS page. Either: we're outside headers, and this isn't a
- * header (normal data), outside headers and this is (error!), inside
- * headers, this is (append header), or inside headers and this isn't
- * (we've found the end of headers; flush the lot!)
- *
- * Before that, we flag that the last page seen (this one) was not a
- * BOS page; that way we know that when we next see a BOS page it's a
- * new chain, and we can flush all existing streams.
- */
- page_type type;
- GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno);
-
- if (!stream) {
- GST_LOG_OBJECT (ogg,
- "Non-BOS page unexpectedly found at %" G_GINT64_FORMAT,
- ogg->offset);
- goto failure;
- }
-
- ogg->last_page_not_bos = TRUE;
-
- type = gst_ogg_parse_is_header (ogg, stream, &page);
-
- if (type == PAGE_PENDING && ogg->in_headers) {
- gst_buffer_ref (pagebuffer);
-
- stream->unknown_pages = g_list_append (stream->unknown_pages,
- pagebuffer);
- } else if (type == PAGE_HEADER) {
- if (!ogg->in_headers) {
- GST_LOG_OBJECT (ogg, "Header page unexpectedly found outside "
- "headers at offset %" G_GINT64_FORMAT, ogg->offset);
- goto failure;
- } else {
- /* Append the header to the buffer list, after any unknown previous
- * pages
- */
- stream->headers = g_list_concat (stream->headers,
- stream->unknown_pages);
- g_list_free (stream->unknown_pages);
- gst_buffer_ref (pagebuffer);
- stream->headers = g_list_append (stream->headers, pagebuffer);
- }
- } else { /* PAGE_DATA, or PAGE_PENDING but outside headers */
- if (ogg->in_headers) {
- /* First non-header page... set caps, flush headers.
- *
- * First up, we build a single GValue list of all the pagebuffers
- * we're using for the headers, in order.
- * Then we set this on the caps structure. Then we can start pushing
- * buffers for the headers, and finally we send this non-header
- * page.
- */
- GstCaps *caps;
- GstStructure *structure;
- GValue array = { 0 };
- gint count = 0;
- gboolean found_pending_headers = FALSE;
- GSList *l;
-
- g_value_init (&array, GST_TYPE_ARRAY);
-
- for (l = ogg->oggstreams; l != NULL; l = l->next) {
- GstOggStream *stream = (GstOggStream *) l->data;
-
- if (g_list_length (stream->headers) == 0) {
- GST_LOG_OBJECT (ogg, "No primary header found for stream %08lx",
- stream->serialno);
- goto failure;
- }
-
- gst_ogg_parse_append_header (&array,
- GST_BUFFER (stream->headers->data));
- count++;
- }
-
- for (l = ogg->oggstreams; l != NULL; l = l->next) {
- GstOggStream *stream = (GstOggStream *) l->data;
- int j;
-
- for (j = 1; j < g_list_length (stream->headers); j++) {
- gst_ogg_parse_append_header (&array,
- GST_BUFFER (g_list_nth_data (stream->headers, j)));
- count++;
- }
- }
-
- caps = gst_pad_get_caps (ogg->srcpad);
- caps = gst_caps_make_writable (caps);
-
- structure = gst_caps_get_structure (caps, 0);
- gst_structure_set_value (structure, "streamheader", &array);
-
- gst_pad_set_caps (ogg->srcpad, caps);
-
- g_value_unset (&array);
-
- if (ogg->caps)
- gst_caps_unref (ogg->caps);
- ogg->caps = caps;
-
- GST_LOG_OBJECT (ogg, "Set \"streamheader\" caps with %d buffers "
- "(one per page)", count);
-
- /* Now, we do the same thing, but push buffers... */
- for (l = ogg->oggstreams; l != NULL; l = l->next) {
- GstOggStream *stream = (GstOggStream *) l->data;
- GstBuffer *buf = GST_BUFFER (stream->headers->data);
-
- gst_buffer_set_caps (buf, caps);
-
- result = gst_pad_push (ogg->srcpad, buf);
- if (result != GST_FLOW_OK)
- return result;
- }
- for (l = ogg->oggstreams; l != NULL; l = l->next) {
- GstOggStream *stream = (GstOggStream *) l->data;
- int j;
-
- for (j = 1; j < g_list_length (stream->headers); j++) {
- GstBuffer *buf =
- GST_BUFFER (g_list_nth_data (stream->headers, j));
- gst_buffer_set_caps (buf, caps);
-
- result = gst_pad_push (ogg->srcpad, buf);
- if (result != GST_FLOW_OK)
- return result;
- }
- }
-
- ogg->in_headers = 0;
-
- /* And finally the pending data pages */
- for (l = ogg->oggstreams; l != NULL; l = l->next) {
- GstOggStream *stream = (GstOggStream *) l->data;
- GList *k;
-
- if (stream->unknown_pages == NULL)
- continue;
-
- if (found_pending_headers) {
- GST_WARNING_OBJECT (ogg, "Incorrectly muxed headers found at "
- "approximate offset %" G_GINT64_FORMAT, ogg->offset);
- }
- found_pending_headers = TRUE;
-
- GST_LOG_OBJECT (ogg, "Pushing %d pending pages after headers",
- g_list_length (stream->unknown_pages) + 1);
-
- for (k = stream->unknown_pages; k != NULL; k = k->next) {
- GstBuffer *buf;
-
- buf = GST_BUFFER (k->data);
- gst_buffer_set_caps (buf, caps);
- result = gst_pad_push (ogg->srcpad, buf);
- if (result != GST_FLOW_OK)
- return result;
- }
- g_list_foreach (stream->unknown_pages,
- (GFunc) gst_mini_object_unref, NULL);
- g_list_free (stream->unknown_pages);
- stream->unknown_pages = NULL;
- }
-
- gst_buffer_set_caps (pagebuffer, caps);
-
- result = gst_pad_push (ogg->srcpad, GST_BUFFER (pagebuffer));
- if (result != GST_FLOW_OK)
- return result;
- } else {
- /* Normal data page, submit buffer */
- gst_buffer_set_caps (pagebuffer, ogg->caps);
- result = gst_pad_push (ogg->srcpad, GST_BUFFER (pagebuffer));
- if (result != GST_FLOW_OK)
- return result;
- }
- }
- }
- }
- }
-
- return result;
-
-failure:
- gst_pad_push_event (GST_PAD (ogg->srcpad), gst_event_new_eos ());
- return GST_FLOW_ERROR;
-}
-
-static GstStateChangeReturn
-gst_ogg_parse_change_state (GstElement * element, GstStateChange transition)
-{
- GstOggParse *ogg;
- GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
-
- ogg = GST_OGG_PARSE (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- ogg_sync_init (&ogg->sync);
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- ogg_sync_reset (&ogg->sync);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- result = parent_class->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- ogg_sync_clear (&ogg->sync);
- break;
- default:
- break;
- }
- return result;
-}
-
-gboolean
-gst_ogg_parse_plugin_init (GstPlugin * plugin)
-{
- GST_DEBUG_CATEGORY_INIT (gst_ogg_parse_debug, "oggparse", 0, "ogg parser");
-
- return gst_element_register (plugin, "oggparse", GST_RANK_NONE,
- GST_TYPE_OGG_PARSE);
-}
diff --git a/ext/ogg/gstoggstream.c b/ext/ogg/gstoggstream.c
deleted file mode 100644
index 3dac5ad0..00000000
--- a/ext/ogg/gstoggstream.c
+++ /dev/null
@@ -1,1315 +0,0 @@
-/* GStreamer Ogg Granulepos Mapping Utility Functions
- * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
- * Copyright (C) 2009 David Schleef <ds@schleef.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstoggstream.h"
-#include "dirac_parse.h"
-
-#include <gst/riff/riff-media.h>
-
-#include <string.h>
-
-GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_debug);
-GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_setup_debug);
-#define GST_CAT_DEFAULT gst_ogg_demux_debug
-
-typedef struct _GstOggMap GstOggMap;
-
-typedef gboolean (*GstOggMapSetupFunc) (GstOggStream * pad,
- ogg_packet * packet);
-typedef GstClockTime (*GstOggMapToTimeFunc) (GstOggStream * pad,
- gint64 granulepos);
-typedef gint64 (*GstOggMapToGranuleFunc) (GstOggStream * pad,
- gint64 granulepos);
-typedef gint64 (*GstOggMapToGranuleposFunc) (GstOggStream * pad,
- gint64 granule, gint64 keyframe_granule);
-
-/* returns TRUE if the granulepos denotes a key frame */
-typedef gboolean (*GstOggMapIsKeyFrameFunc) (GstOggStream * pad,
- gint64 granulepos);
-
-/* returns TRUE if the given packet is a stream header packet */
-typedef gboolean (*GstOggMapIsHeaderPacketFunc) (GstOggStream * pad,
- ogg_packet * packet);
-typedef gint64 (*GstOggMapPacketDurationFunc) (GstOggStream * pad,
- ogg_packet * packet);
-
-
-
-#define SKELETON_FISBONE_MIN_SIZE 52
-
-
-struct _GstOggMap
-{
- const gchar *id;
- int id_length;
- int min_packet_size;
- const gchar *media_type;
- GstOggMapSetupFunc setup_func;
- GstOggMapToGranuleFunc granulepos_to_granule_func;
- GstOggMapToGranuleposFunc granule_to_granulepos_func;
- GstOggMapIsKeyFrameFunc is_key_frame_func;
- GstOggMapIsHeaderPacketFunc is_header_func;
- GstOggMapPacketDurationFunc packet_duration_func;
-};
-
-static const GstOggMap mappers[];
-
-GstClockTime
-gst_ogg_stream_get_packet_start_time (GstOggStream * pad, ogg_packet * packet)
-{
- int duration;
-
- if (packet->granulepos == -1) {
- return GST_CLOCK_TIME_NONE;
- }
-
- duration = gst_ogg_stream_get_packet_duration (pad, packet);
- if (duration == -1) {
- return GST_CLOCK_TIME_NONE;
- }
-
- return gst_ogg_stream_granule_to_time (pad,
- gst_ogg_stream_granulepos_to_granule (pad,
- packet->granulepos) - duration);
-}
-
-GstClockTime
-gst_ogg_stream_get_start_time_for_granulepos (GstOggStream * pad,
- gint64 granulepos)
-{
- if (pad->frame_size == 0)
- return GST_CLOCK_TIME_NONE;
-
- return gst_ogg_stream_granule_to_time (pad,
- gst_ogg_stream_granulepos_to_granule (pad, granulepos));
-}
-
-GstClockTime
-gst_ogg_stream_get_end_time_for_granulepos (GstOggStream * pad,
- gint64 granulepos)
-{
- return gst_ogg_stream_granule_to_time (pad,
- gst_ogg_stream_granulepos_to_granule (pad, granulepos));
-}
-
-GstClockTime
-gst_ogg_stream_granule_to_time (GstOggStream * pad, gint64 granule)
-{
- if (granule == 0 || pad->granulerate_n == 0 || pad->granulerate_d == 0)
- return 0;
-
- return gst_util_uint64_scale (granule, GST_SECOND * pad->granulerate_d,
- pad->granulerate_n);
-}
-
-gint64
-gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos)
-{
- if (granulepos == -1 || granulepos == 0) {
- return granulepos;
- }
-
- if (mappers[pad->map].granulepos_to_granule_func == NULL) {
- GST_WARNING ("Failed to convert granulepos to granule");
- return -1;
- }
-
- return mappers[pad->map].granulepos_to_granule_func (pad, granulepos);
-}
-
-gint64
-gst_ogg_stream_granulepos_to_key_granule (GstOggStream * pad, gint64 granulepos)
-{
- if (granulepos == -1 || granulepos == 0) {
- return granulepos;
- }
-
- return granulepos >> pad->granuleshift;
-}
-
-gint64
-gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule,
- gint64 keyframe_granule)
-{
- if (granule == -1 || granule == 0) {
- return granule;
- }
-
- if (mappers[pad->map].granule_to_granulepos_func == NULL) {
- GST_WARNING ("Failed to convert granule to granulepos");
- return -1;
- }
-
- return mappers[pad->map].granule_to_granulepos_func (pad, granule,
- keyframe_granule);
-}
-
-gboolean
-gst_ogg_stream_packet_granulepos_is_key_frame (GstOggStream * pad,
- gint64 granulepos)
-{
- if (granulepos == -1) {
- return FALSE;
- }
-
- if (mappers[pad->map].is_key_frame_func == NULL) {
- GST_WARNING ("Failed to determine key frame");
- return FALSE;
- }
-
- return mappers[pad->map].is_key_frame_func (pad, granulepos);
-}
-
-gboolean
-gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet)
-{
- if (mappers[pad->map].is_header_func == NULL) {
- GST_WARNING ("Failed to determine header");
- return FALSE;
- }
-
- return mappers[pad->map].is_header_func (pad, packet);
-}
-
-gint64
-gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet)
-{
- if (mappers[pad->map].packet_duration_func == NULL) {
- GST_WARNING ("Failed to determine packet duration");
- return -1;
- }
-
- return mappers[pad->map].packet_duration_func (pad, packet);
-}
-
-
-
-
-/* some generic functions */
-
-static gboolean
-is_keyframe_true (GstOggStream * pad, gint64 granulepos)
-{
- return TRUE;
-}
-
-static gint64
-granulepos_to_granule_default (GstOggStream * pad, gint64 granulepos)
-{
- gint64 keyindex, keyoffset;
-
- if (pad->granuleshift != 0) {
- keyindex = granulepos >> pad->granuleshift;
- keyoffset = granulepos - (keyindex << pad->granuleshift);
- return keyindex + keyoffset;
- } else {
- return granulepos;
- }
-}
-
-
-static gint64
-granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
- gint64 keyframe_granule)
-{
- gint64 keyoffset;
-
- if (pad->granuleshift != 0) {
- keyoffset = granule - keyframe_granule;
- return (keyframe_granule << pad->granuleshift) | keyoffset;
- } else {
- return granule;
- }
-}
-
-#ifdef unused
-static gboolean
-is_header_unknown (GstOggStream * pad, ogg_packet * packet)
-{
- GST_WARNING ("don't know how to detect header");
- return FALSE;
-}
-#endif
-
-static gboolean
-is_header_true (GstOggStream * pad, ogg_packet * packet)
-{
- return TRUE;
-}
-
-static gboolean
-is_header_count (GstOggStream * pad, ogg_packet * packet)
-{
- if (pad->n_header_packets_seen < pad->n_header_packets) {
- return TRUE;
- }
- return FALSE;
-}
-
-static gint64
-packet_duration_constant (GstOggStream * pad, ogg_packet * packet)
-{
- return pad->frame_size;
-}
-
-/* theora */
-
-static gboolean
-setup_theora_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- guint w, h, par_d, par_n;
-
- w = GST_READ_UINT24_BE (data + 14) & 0xFFFFF0;
- h = GST_READ_UINT24_BE (data + 17) & 0xFFFFF0;
-
- pad->granulerate_n = GST_READ_UINT32_BE (data + 22);
- pad->granulerate_d = GST_READ_UINT32_BE (data + 26);
-
- par_n = GST_READ_UINT24_BE (data + 30);
- par_d = GST_READ_UINT24_BE (data + 33);
-
- GST_LOG ("fps = %d/%d, PAR = %u/%u, width = %u, height = %u",
- pad->granulerate_n, pad->granulerate_d, par_n, par_d, w, h);
-
- /* 2 bits + 3 bits = 5 bits KFGSHIFT */
- pad->granuleshift = ((GST_READ_UINT8 (data + 40) & 0x03) << 3) +
- (GST_READ_UINT8 (data + 41) >> 5);
-
- pad->n_header_packets = 3;
- pad->frame_size = 1;
-
- if (pad->granulerate_n == 0 || pad->granulerate_d == 0) {
- GST_WARNING ("frame rate %d/%d", pad->granulerate_n, pad->granulerate_d);
- return FALSE;
- }
-
- pad->caps = gst_caps_new_simple ("video/x-theora", NULL);
-
- if (w > 0 && h > 0) {
- gst_caps_set_simple (pad->caps, "width", G_TYPE_INT, w, "height",
- G_TYPE_INT, h, NULL);
- }
-
- /* PAR of 0:N, N:0 and 0:0 is allowed and maps to 1:1 */
- if (par_n == 0 || par_d == 0)
- par_n = par_d = 1;
-
- /* only add framerate now so caps look prettier, with width/height first */
- gst_caps_set_simple (pad->caps, "framerate", GST_TYPE_FRACTION,
- pad->granulerate_n, pad->granulerate_d, "pixel-aspect-ratio",
- GST_TYPE_FRACTION, par_n, par_d, NULL);
-
- return TRUE;
-}
-
-static gint64
-granulepos_to_granule_theora (GstOggStream * pad, gint64 granulepos)
-{
- gint64 keyindex, keyoffset;
-
- if (pad->granuleshift != 0) {
- keyindex = granulepos >> pad->granuleshift;
- keyoffset = granulepos - (keyindex << pad->granuleshift);
- if (keyoffset == 0) {
- pad->theora_has_zero_keyoffset = TRUE;
- }
- if (pad->theora_has_zero_keyoffset) {
- keyoffset++;
- }
- return keyindex + keyoffset;
- } else {
- return granulepos;
- }
-}
-
-static gboolean
-is_keyframe_theora (GstOggStream * pad, gint64 granulepos)
-{
- gint64 frame_mask;
-
- if (granulepos == (gint64) - 1)
- return FALSE;
-
- frame_mask = (1 << (pad->granuleshift + 1)) - 1;
-
- return ((granulepos & frame_mask) == 0);
-}
-
-static gboolean
-is_header_theora (GstOggStream * pad, ogg_packet * packet)
-{
- return (packet->bytes > 0 && (packet->packet[0] & 0x80) == 0x80);
-}
-
-/* dirac */
-
-static gboolean
-setup_dirac_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- int ret;
- DiracSequenceHeader header;
-
- ret = dirac_sequence_header_parse (&header, packet->packet + 13,
- packet->bytes - 13);
- if (ret == 0) {
- GST_DEBUG ("Failed to parse Dirac sequence header");
- return FALSE;
- }
-
- pad->granulerate_n = header.frame_rate_numerator * 2;
- pad->granulerate_d = header.frame_rate_denominator;
- pad->granuleshift = 22;
- pad->n_header_packets = 1;
- pad->frame_size = 2;
-
- if (header.interlaced_coding != 0) {
- GST_DEBUG ("non-progressive Dirac coding not implemented");
- return FALSE;
- }
-
- pad->caps = gst_caps_new_simple ("video/x-dirac",
- "width", G_TYPE_INT, header.width,
- "height", G_TYPE_INT, header.height,
- "interlaced", G_TYPE_BOOLEAN, header.interlaced,
- "pixel-aspect-ratio", GST_TYPE_FRACTION,
- header.aspect_ratio_numerator, header.aspect_ratio_denominator,
- "framerate", GST_TYPE_FRACTION, header.frame_rate_numerator,
- header.frame_rate_denominator, NULL);
-
- return TRUE;
-}
-
-#define OGG_DIRAC_GRANULE_LOW_MASK ((1<<22) - 1)
-static gboolean
-is_keyframe_dirac (GstOggStream * pad, gint64 granulepos)
-{
- gint64 pt;
- int dist_h;
- int dist_l;
- int dist;
- int delay;
- gint64 dt;
-
- if (granulepos == -1)
- return -1;
-
- pt = ((granulepos >> 22) + (granulepos & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
- dist_h = (granulepos >> 22) & 0xff;
- dist_l = granulepos & 0xff;
- dist = (dist_h << 8) | dist_l;
- delay = (granulepos >> 9) & 0x1fff;
- dt = pt - delay;
-
- return (dist == 0);
-}
-
-static gint64
-granulepos_to_granule_dirac (GstOggStream * pad, gint64 gp)
-{
- gint64 pt;
- int dist_h;
- int dist_l;
- int dist;
- int delay;
- gint64 dt;
-
- pt = ((gp >> 22) + (gp & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
- dist_h = (gp >> 22) & 0xff;
- dist_l = gp & 0xff;
- dist = (dist_h << 8) | dist_l;
- delay = (gp >> 9) & 0x1fff;
- dt = pt - delay;
-
- GST_DEBUG ("pt %" G_GINT64_FORMAT " delay %d", pt, delay);
-
- return dt + 4;
-}
-
-static gint64
-granule_to_granulepos_dirac (GstOggStream * pad, gint64 granule,
- gint64 keyframe_granule)
-{
- /* This conversion requires knowing more details about the Dirac
- * stream. */
- return -1;
-}
-
-
-/* vorbis */
-
-void parse_vorbis_header_packet (GstOggStream * pad, ogg_packet * op);
-void parse_vorbis_setup_packet (GstOggStream * pad, ogg_packet * op);
-
-
-static gboolean
-setup_vorbis_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- guint chans;
-
- data += 1 + 6 + 4;
- chans = GST_READ_UINT8 (data);
- data += 1;
- pad->granulerate_n = GST_READ_UINT32_LE (data);
- pad->granulerate_d = 1;
- pad->granuleshift = 0;
- pad->last_size = 0;
- GST_LOG ("sample rate: %d", pad->granulerate_n);
-
- pad->n_header_packets = 3;
-
- if (pad->granulerate_n == 0)
- return FALSE;
-
- parse_vorbis_header_packet (pad, packet);
-
- pad->caps = gst_caps_new_simple ("audio/x-vorbis",
- "rate", G_TYPE_INT, pad->granulerate_n, "channels", G_TYPE_INT, chans,
- NULL);
-
- return TRUE;
-}
-
-static gboolean
-is_header_vorbis (GstOggStream * pad, ogg_packet * packet)
-{
- if (packet->bytes > 0 && (packet->packet[0] & 0x01) == 0)
- return FALSE;
-
- if (packet->packet[0] == 5) {
- parse_vorbis_setup_packet (pad, packet);
- }
-
- return TRUE;
-}
-
-static gint64
-packet_duration_vorbis (GstOggStream * pad, ogg_packet * packet)
-{
- int mode;
- int size;
- int duration;
-
- if (packet->packet[0] & 1)
- return 0;
-
- mode = (packet->packet[0] >> 1) & ((1 << pad->vorbis_log2_num_modes) - 1);
- size = pad->vorbis_mode_sizes[mode] ? pad->long_size : pad->short_size;
-
- if (pad->last_size == 0) {
- duration = 0;
- } else {
- duration = pad->last_size / 4 + size / 4;
- }
- pad->last_size = size;
-
- GST_DEBUG ("duration %d", (int) duration);
-
- return duration;
-}
-
-/* speex */
-
-
-static gboolean
-setup_speex_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- guint chans;
-
- data += 8 + 20 + 4 + 4;
- pad->granulerate_n = GST_READ_UINT32_LE (data);
- pad->granulerate_d = 1;
- pad->granuleshift = 0;
-
- data += 4 + 4 + 4;
- chans = GST_READ_UINT32_LE (data);
-
- GST_LOG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
-
- pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 68) + 2;
- pad->frame_size = GST_READ_UINT32_LE (packet->packet + 64) *
- GST_READ_UINT32_LE (packet->packet + 56);
-
- if (pad->granulerate_n == 0)
- return FALSE;
-
- pad->caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT,
- pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
-
- return TRUE;
-}
-
-
-/* flac */
-
-static gboolean
-setup_fLaC_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- pad->granulerate_n = 0;
- pad->granulerate_d = 1;
- pad->granuleshift = 0;
-
- pad->n_header_packets = 3;
-
- pad->caps = gst_caps_new_simple ("audio/x-flac", NULL);
-
- return TRUE;
-}
-
-static gboolean
-is_header_fLaC (GstOggStream * pad, ogg_packet * packet)
-{
- if (pad->n_header_packets_seen == 1) {
- pad->granulerate_n = (packet->packet[14] << 12) |
- (packet->packet[15] << 4) | ((packet->packet[16] >> 4) & 0xf);
- }
-
- if (pad->n_header_packets_seen < pad->n_header_packets) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-setup_flac_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- guint chans;
-
- /* see http://flac.sourceforge.net/ogg_mapping.html */
-
- pad->granulerate_n = (GST_READ_UINT32_BE (data + 27) & 0xFFFFF000) >> 12;
- pad->granulerate_d = 1;
- pad->granuleshift = 0;
- chans = ((GST_READ_UINT32_BE (data + 27) & 0x00000E00) >> 9) + 1;
-
- GST_DEBUG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
-
- pad->n_header_packets = GST_READ_UINT16_BE (packet->packet + 7);
-
- if (pad->granulerate_n == 0)
- return FALSE;
-
- pad->caps = gst_caps_new_simple ("audio/x-flac", "rate", G_TYPE_INT,
- pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
-
- return TRUE;
-}
-
-static gboolean
-is_header_flac (GstOggStream * pad, ogg_packet * packet)
-{
- return (packet->bytes > 0 && (packet->packet[0] != 0xff));
-}
-
-static gint64
-packet_duration_flac (GstOggStream * pad, ogg_packet * packet)
-{
- int block_size_index;
-
- if (packet->bytes < 4)
- return -1;
-
- block_size_index = packet->packet[2] >> 4;
- if (block_size_index == 1)
- return 192;
- if (block_size_index >= 2 && block_size_index <= 5) {
- return 576 << (block_size_index - 2);
- }
- if (block_size_index >= 8) {
- return 256 << (block_size_index - 8);
- }
- if (block_size_index == 6 || block_size_index == 7) {
- guint len, bytes = (block_size_index - 6) + 1;
- guint8 tmp;
-
- if (packet->bytes < 4 + 1 + bytes)
- return -1;
- tmp = packet->packet[4];
- /* utf-8 prefix */
- len = 0;
- while (tmp & 0x80) {
- len++;
- tmp <<= 1;
- }
- if (len == 2)
- return -1;
- if (len == 0)
- len++;
- if (packet->bytes < 4 + len + bytes)
- return -1;
- if (bytes == 1) {
- return packet->packet[4 + len] + 1;
- } else {
- return GST_READ_UINT16_BE (packet->packet + 4 + len) + 1;
- }
- }
- return -1;
-}
-
-/* fishead */
-
-static gboolean
-setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data;
- gint64 prestime_n, prestime_d;
- gint64 basetime_n, basetime_d;
- gint64 basetime;
-
- data = packet->packet;
-
- data += 8 + 2 + 2; /* header + major/minor version */
-
- prestime_n = (gint64) GST_READ_UINT64_LE (data);
- data += 8;
- prestime_d = (gint64) GST_READ_UINT64_LE (data);
- data += 8;
- basetime_n = (gint64) GST_READ_UINT64_LE (data);
- data += 8;
- basetime_d = (gint64) GST_READ_UINT64_LE (data);
- data += 8;
-
- /* FIXME: we don't use basetime anywhere in the demuxer! */
- if (basetime_d != 0)
- basetime = gst_util_uint64_scale (GST_SECOND, basetime_n, basetime_d);
- else
- basetime = -1;
-
- GST_INFO ("skeleton fishead parsed (basetime: %" GST_TIME_FORMAT ")",
- GST_TIME_ARGS (basetime));
-
- return TRUE;
-}
-
-gboolean
-gst_ogg_map_add_fisbone (GstOggStream * pad,
- const guint8 * data, guint size, GstClockTime * p_start_time,
- guint32 * p_preroll)
-{
- GstClockTime start_time;
- gint64 start_granule;
- guint32 preroll;
-
- if (size < SKELETON_FISBONE_MIN_SIZE || memcmp (data, "fisbone\0", 8) != 0) {
- GST_WARNING ("invalid fisbone packet, ignoring");
- return FALSE;
- }
-
- if (pad->have_fisbone) {
- GST_DEBUG ("already have fisbone, ignoring second one");
- return FALSE;
- }
-
- /* skip "fisbone\0" + headers offset + serialno + num headers */
- data += 8 + 4 + 4 + 4;
-
- pad->have_fisbone = TRUE;
-
- /* we just overwrite whatever was set before by the format-specific setup */
- pad->granulerate_n = GST_READ_UINT64_LE (data);
- pad->granulerate_d = GST_READ_UINT64_LE (data + 8);
-
- start_granule = GST_READ_UINT64_LE (data + 16);
- preroll = GST_READ_UINT32_LE (data + 24);
- pad->granuleshift = GST_READ_UINT8 (data + 28);
-
- start_time = granulepos_to_granule_default (pad, start_granule);
-
- if (p_start_time)
- *p_start_time = start_time;
-
- if (p_preroll)
- *p_preroll = preroll;
-
- return TRUE;
-}
-
-/* Do we need these for something?
- * ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
- * ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
- * ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[25]);
- * ogm->hdr.default_len = GST_READ_UINT32_LE (&data[33]);
- * ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[37]);
- * ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
- */
-
-static gboolean
-is_header_ogm (GstOggStream * pad, ogg_packet * packet)
-{
- if (packet->bytes >= 1 && (packet->packet[0] & 0x01))
- return TRUE;
-
- return FALSE;
-}
-
-static gint64
-packet_duration_ogm (GstOggStream * pad, ogg_packet * packet)
-{
- const guint8 *data;
- int samples;
- int offset;
- int n;
-
- data = packet->packet;
- offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
-
- if (offset > packet->bytes) {
- GST_ERROR ("buffer too small");
- return -1;
- }
-
- samples = 0;
- for (n = offset - 1; n > 0; n--) {
- samples = (samples << 8) | data[n];
- }
-
- return samples;
-}
-
-static gboolean
-setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- guint32 fourcc;
-
- pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
- pad->granulerate_d = 1;
-
- fourcc = GST_READ_UINT32_LE (data + 9);
- GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
-
- pad->caps = gst_riff_create_audio_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
-
- GST_LOG ("sample rate: %d", pad->granulerate_n);
- if (pad->granulerate_n == 0)
- return FALSE;
-
- if (pad->caps) {
- gst_caps_set_simple (pad->caps,
- "rate", G_TYPE_INT, pad->granulerate_n, NULL);
- } else {
- pad->caps = gst_caps_new_simple ("audio/x-ogm-unknown",
- "fourcc", GST_TYPE_FOURCC, fourcc,
- "rate", G_TYPE_INT, pad->granulerate_n, NULL);
- }
-
- pad->n_header_packets = 1;
- pad->is_ogm = TRUE;
-
- return TRUE;
-}
-
-static gboolean
-setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- guint32 fourcc;
- int width, height;
- gint64 time_unit;
-
- GST_DEBUG ("time unit %d", GST_READ_UINT32_LE (data + 16));
- GST_DEBUG ("samples per unit %d", GST_READ_UINT32_LE (data + 24));
-
- pad->granulerate_n = 10000000;
- time_unit = GST_READ_UINT64_LE (data + 17);
- if (time_unit > G_MAXINT || time_unit < G_MININT) {
- GST_WARNING ("timeunit is out of range");
- }
- pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
-
- GST_LOG ("fps = %d/%d = %.3f",
- pad->granulerate_n, pad->granulerate_d,
- (double) pad->granulerate_n / pad->granulerate_d);
-
- fourcc = GST_READ_UINT32_LE (data + 9);
- width = GST_READ_UINT32_LE (data + 45);
- height = GST_READ_UINT32_LE (data + 49);
- GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
-
- pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
-
- if (pad->caps == NULL) {
- pad->caps = gst_caps_new_simple ("video/x-ogm-unknown",
- "fourcc", GST_TYPE_FOURCC, fourcc,
- "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
- pad->granulerate_d, NULL);
- } else {
- gst_caps_set_simple (pad->caps,
- "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
- pad->granulerate_d,
- "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
- }
- GST_DEBUG ("caps: %" GST_PTR_FORMAT, pad->caps);
-
- pad->n_header_packets = 1;
- pad->frame_size = 1;
- pad->is_ogm = TRUE;
-
- return TRUE;
-}
-
-static gboolean
-setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- gint64 time_unit;
-
- pad->granulerate_n = 10000000;
- time_unit = GST_READ_UINT64_LE (data + 17);
- if (time_unit > G_MAXINT || time_unit < G_MININT) {
- GST_WARNING ("timeunit is out of range");
- }
- pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
-
- GST_LOG ("fps = %d/%d = %.3f",
- pad->granulerate_n, pad->granulerate_d,
- (double) pad->granulerate_n / pad->granulerate_d);
-
- if (pad->granulerate_d <= 0)
- return FALSE;
-
- pad->caps = gst_caps_new_simple ("text/plain", NULL);
-
- pad->n_header_packets = 1;
- pad->is_ogm = TRUE;
- pad->is_ogm_text = TRUE;
-
- return TRUE;
-}
-
-/* PCM */
-
-#define OGGPCM_FMT_S8 0x00000000 /* Signed integer 8 bit */
-#define OGGPCM_FMT_U8 0x00000001 /* Unsigned integer 8 bit */
-#define OGGPCM_FMT_S16_LE 0x00000002 /* Signed integer 16 bit little endian */
-#define OGGPCM_FMT_S16_BE 0x00000003 /* Signed integer 16 bit big endian */
-#define OGGPCM_FMT_S24_LE 0x00000004 /* Signed integer 24 bit little endian */
-#define OGGPCM_FMT_S24_BE 0x00000005 /* Signed integer 24 bit big endian */
-#define OGGPCM_FMT_S32_LE 0x00000006 /* Signed integer 32 bit little endian */
-#define OGGPCM_FMT_S32_BE 0x00000007 /* Signed integer 32 bit big endian */
-
-#define OGGPCM_FMT_ULAW 0x00000010 /* G.711 u-law encoding (8 bit) */
-#define OGGPCM_FMT_ALAW 0x00000011 /* G.711 A-law encoding (8 bit) */
-
-#define OGGPCM_FMT_FLT32_LE 0x00000020 /* IEEE Float [-1,1] 32 bit little endian */
-#define OGGPCM_FMT_FLT32_BE 0x00000021 /* IEEE Float [-1,1] 32 bit big endian */
-#define OGGPCM_FMT_FLT64_LE 0x00000022 /* IEEE Float [-1,1] 64 bit little endian */
-#define OGGPCM_FMT_FLT64_BE 0x00000023 /* IEEE Float [-1,1] 64 bit big endian */
-
-
-static gboolean
-setup_pcm_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- int format;
- int channels;
- GstCaps *caps;
-
- pad->granulerate_n = GST_READ_UINT32_LE (data + 16);
- pad->granulerate_d = 1;
- GST_LOG ("sample rate: %d", pad->granulerate_n);
-
- format = GST_READ_UINT32_LE (data + 12);
- channels = GST_READ_UINT8 (data + 21);
-
- pad->n_header_packets = 2 + GST_READ_UINT32_LE (data + 24);
-
- if (pad->granulerate_n == 0)
- return FALSE;
-
- switch (format) {
- case OGGPCM_FMT_S8:
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "depth", G_TYPE_INT, 8,
- "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
- break;
- case OGGPCM_FMT_U8:
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "depth", G_TYPE_INT, 8,
- "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
- break;
- case OGGPCM_FMT_S16_LE:
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "depth", G_TYPE_INT, 16,
- "width", G_TYPE_INT, 16,
- "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
- "signed", G_TYPE_BOOLEAN, TRUE, NULL);
- break;
- case OGGPCM_FMT_S16_BE:
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "depth", G_TYPE_INT, 16,
- "width", G_TYPE_INT, 16,
- "endianness", G_TYPE_INT, G_BIG_ENDIAN,
- "signed", G_TYPE_BOOLEAN, TRUE, NULL);
- break;
- case OGGPCM_FMT_S24_LE:
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "depth", G_TYPE_INT, 24,
- "width", G_TYPE_INT, 24,
- "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
- "signed", G_TYPE_BOOLEAN, TRUE, NULL);
- break;
- case OGGPCM_FMT_S24_BE:
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "depth", G_TYPE_INT, 24,
- "width", G_TYPE_INT, 24,
- "endianness", G_TYPE_INT, G_BIG_ENDIAN,
- "signed", G_TYPE_BOOLEAN, TRUE, NULL);
- break;
- case OGGPCM_FMT_S32_LE:
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "depth", G_TYPE_INT, 32,
- "width", G_TYPE_INT, 32,
- "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
- "signed", G_TYPE_BOOLEAN, TRUE, NULL);
- break;
- case OGGPCM_FMT_S32_BE:
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "depth", G_TYPE_INT, 32,
- "width", G_TYPE_INT, 32,
- "endianness", G_TYPE_INT, G_BIG_ENDIAN,
- "signed", G_TYPE_BOOLEAN, TRUE, NULL);
- break;
- case OGGPCM_FMT_ULAW:
- caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
- break;
- case OGGPCM_FMT_ALAW:
- caps = gst_caps_new_simple ("audio/x-alaw", NULL);
- break;
- case OGGPCM_FMT_FLT32_LE:
- caps = gst_caps_new_simple ("audio/x-raw-float",
- "width", G_TYPE_INT, 32,
- "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
- break;
- case OGGPCM_FMT_FLT32_BE:
- caps = gst_caps_new_simple ("audio/x-raw-float",
- "width", G_TYPE_INT, 32,
- "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
- break;
- case OGGPCM_FMT_FLT64_LE:
- caps = gst_caps_new_simple ("audio/x-raw-float",
- "width", G_TYPE_INT, 64,
- "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
- break;
- case OGGPCM_FMT_FLT64_BE:
- caps = gst_caps_new_simple ("audio/x-raw-float",
- "width", G_TYPE_INT, 64,
- "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
- break;
- default:
- return FALSE;
- }
-
- gst_caps_set_simple (caps, "audio/x-raw-int",
- "rate", G_TYPE_INT, pad->granulerate_n,
- "channels", G_TYPE_INT, channels, NULL);
- pad->caps = caps;
-
- return TRUE;
-}
-
-/* cmml */
-
-static gboolean
-setup_cmml_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
-
- pad->granulerate_n = GST_READ_UINT64_LE (data + 12);
- pad->granulerate_d = GST_READ_UINT64_LE (data + 20);
- pad->granuleshift = data[28];
- GST_LOG ("sample rate: %d", pad->granulerate_n);
-
- pad->n_header_packets = 3;
-
- if (pad->granulerate_n == 0)
- return FALSE;
-
- data += 4 + (4 + 4 + 4);
- GST_DEBUG ("blocksize0: %u", 1 << (data[0] >> 4));
- GST_DEBUG ("blocksize1: %u", 1 << (data[0] & 0x0F));
-
- pad->caps = gst_caps_new_simple ("text/x-cmml", NULL);
-
- return TRUE;
-}
-
-/* celt */
-
-static gboolean
-setup_celt_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
-
- pad->granulerate_n = GST_READ_UINT32_LE (data + 36);
- pad->granulerate_d = 1;
- pad->granuleshift = 0;
- GST_LOG ("sample rate: %d", pad->granulerate_n);
-
- pad->frame_size = GST_READ_UINT32_LE (packet->packet + 44);
- pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 56) + 2;
-
- if (pad->granulerate_n == 0)
- return FALSE;
-
- pad->caps = gst_caps_new_simple ("audio/x-celt",
- "rate", G_TYPE_INT, pad->granulerate_n, NULL);
-
- return TRUE;
-}
-
-/* kate */
-
-static gboolean
-setup_kate_mapper (GstOggStream * pad, ogg_packet * packet)
-{
- guint8 *data = packet->packet;
- const char *category;
-
- if (packet->bytes < 64)
- return FALSE;
-
- pad->granulerate_n = GST_READ_UINT32_LE (data + 24);
- pad->granulerate_d = GST_READ_UINT32_LE (data + 28);
- pad->granuleshift = GST_READ_UINT8 (data + 15);
- GST_LOG ("sample rate: %d", pad->granulerate_n);
-
- pad->n_header_packets = GST_READ_UINT8 (data + 11);
-
- if (pad->granulerate_n == 0)
- return FALSE;
-
- category = (const char *) data + 48;
- if (strcmp (category, "subtitles") == 0 || strcmp (category, "SUB") == 0 ||
- strcmp (category, "spu-subtitles") == 0 ||
- strcmp (category, "K-SPU") == 0) {
- pad->caps = gst_caps_new_simple ("subtitle/x-kate", NULL);
- } else {
- pad->caps = gst_caps_new_simple ("application/x-kate", NULL);
- }
-
- return TRUE;
-}
-
-
-/* *INDENT-OFF* */
-/* indent hates our freedoms */
-static const GstOggMap mappers[] = {
- {
- "\200theora", 7, 42,
- "video/x-theora",
- setup_theora_mapper,
- granulepos_to_granule_theora,
- granule_to_granulepos_default,
- is_keyframe_theora,
- is_header_theora,
- packet_duration_constant
- },
- {
- "\001vorbis", 7, 22,
- "audio/x-vorbis",
- setup_vorbis_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- is_keyframe_true,
- is_header_vorbis,
- packet_duration_vorbis
- },
- {
- "Speex", 5, 80,
- "audio/x-speex",
- setup_speex_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- is_keyframe_true,
- is_header_count,
- packet_duration_constant
- },
- {
- "PCM ", 8, 0,
- "audio/x-raw-int",
- setup_pcm_mapper,
- NULL,
- NULL,
- NULL,
- is_header_count,
- NULL
- },
- {
- "CMML\0\0\0\0", 8, 0,
- "text/x-cmml",
- setup_cmml_mapper,
- NULL,
- NULL,
- NULL,
- is_header_count,
- NULL
- },
- {
- "Annodex", 7, 0,
- "application/x-annodex",
- setup_fishead_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- NULL,
- is_header_count,
- NULL
- },
- {
- "fishead", 7, 64,
- "application/octet-stream",
- setup_fishead_mapper,
- NULL,
- NULL,
- NULL,
- is_header_true,
- NULL
- },
- {
- "fLaC", 4, 0,
- "audio/x-flac",
- setup_fLaC_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- is_keyframe_true,
- is_header_fLaC,
- NULL
- },
- {
- "\177FLAC", 5, 36,
- "audio/x-flac",
- setup_flac_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- is_keyframe_true,
- is_header_flac,
- packet_duration_flac
- },
- {
- "AnxData", 7, 0,
- "application/octet-stream",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- },
- {
- "CELT ", 8, 0,
- "audio/x-celt",
- setup_celt_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- NULL,
- is_header_count,
- packet_duration_constant
- },
- {
- "\200kate\0\0\0", 8, 0,
- "text/x-kate",
- setup_kate_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- NULL,
- is_header_count,
- NULL
- },
- {
- "BBCD\0", 5, 13,
- "video/x-dirac",
- setup_dirac_mapper,
- granulepos_to_granule_dirac,
- granule_to_granulepos_dirac,
- is_keyframe_dirac,
- is_header_count,
- packet_duration_constant
- },
- {
- "\001audio\0\0\0", 9, 53,
- "application/x-ogm-audio",
- setup_ogmaudio_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- is_keyframe_true,
- is_header_ogm,
- packet_duration_ogm
- },
- {
- "\001video\0\0\0", 9, 53,
- "application/x-ogm-video",
- setup_ogmvideo_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- NULL,
- is_header_ogm,
- packet_duration_constant
- },
- {
- "\001text\0\0\0", 9, 9,
- "application/x-ogm-text",
- setup_ogmtext_mapper,
- granulepos_to_granule_default,
- granule_to_granulepos_default,
- is_keyframe_true,
- is_header_ogm,
- packet_duration_ogm
- }
-};
-/* *INDENT-ON* */
-
-gboolean
-gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
-{
- int i;
- gboolean ret;
-
- for (i = 0; i < G_N_ELEMENTS (mappers); i++) {
- if (packet->bytes >= mappers[i].min_packet_size &&
- packet->bytes >= mappers[i].id_length &&
- memcmp (packet->packet, mappers[i].id, mappers[i].id_length) == 0) {
-
- GST_DEBUG ("found mapper for '%s'", mappers[i].id);
-
- if (mappers[i].setup_func)
- ret = mappers[i].setup_func (pad, packet);
- else
- continue;
-
- if (ret) {
- GST_DEBUG ("got stream type %" GST_PTR_FORMAT, pad->caps);
- pad->map = i;
- return TRUE;
- } else {
- GST_WARNING ("mapper '%s' did not accept setup header",
- mappers[i].media_type);
- }
- }
- }
-
- return FALSE;
-}
diff --git a/ext/ogg/gstoggstream.h b/ext/ogg/gstoggstream.h
deleted file mode 100644
index 78b55c06..00000000
--- a/ext/ogg/gstoggstream.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* GStreamer
- * Copyright (C) 2009 David Schleef <ds@schleef.org>
- *
- * gstoggstream.h: header for GstOggStream
- *
- * 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_STREAM_H__
-#define __GST_OGG_STREAM_H__
-
-#include <ogg/ogg.h>
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-typedef struct _GstOggStream GstOggStream;
-
-struct _GstOggStream
-{
- ogg_stream_state stream;
-
- glong serialno;
- GList *headers;
- gboolean have_headers;
- GList *queued;
-
- /* for oggparse */
- gboolean in_headers;
- GList *unknown_pages;
-
- gint map;
- gboolean is_skeleton;
- gboolean have_fisbone;
- gint granulerate_n;
- gint granulerate_d;
- guint32 preroll;
- guint granuleshift;
- gint n_header_packets;
- gint n_header_packets_seen;
- gint64 accumulated_granule;
- gint frame_size;
-
- GstCaps *caps;
-
- /* vorbis stuff */
- int nln_increments[4];
- int nsn_increment;
- int short_size;
- int long_size;
- int vorbis_log2_num_modes;
- int vorbis_mode_sizes[256];
- int last_size;
- /* theora stuff */
- gboolean theora_has_zero_keyoffset;
- /* OGM stuff */
- gboolean is_ogm;
- gboolean is_ogm_text;
-};
-
-
-gboolean gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet *packet);
-GstClockTime gst_ogg_stream_get_end_time_for_granulepos (GstOggStream *pad,
- gint64 granulepos);
-GstClockTime gst_ogg_stream_get_start_time_for_granulepos (GstOggStream *pad,
- gint64 granulepos);
-GstClockTime gst_ogg_stream_granule_to_time (GstOggStream *pad, gint64 granule);
-gint64 gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos);
-gint64 gst_ogg_stream_granulepos_to_key_granule (GstOggStream * pad, gint64 granulepos);
-gint64 gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule, gint64 keyframe_granule);
-GstClockTime gst_ogg_stream_get_packet_start_time (GstOggStream *pad,
- ogg_packet *packet);
-gboolean gst_ogg_stream_granulepos_is_key_frame (GstOggStream *pad,
- gint64 granulepos);
-gboolean gst_ogg_stream_packet_is_header (GstOggStream *pad, ogg_packet *packet);
-gint64 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet *packet);
-
-
-G_END_DECLS
-
-#endif /* __GST_OGG_STREAM_H__ */
diff --git a/ext/ogg/gstogmparse.c b/ext/ogg/gstogmparse.c
deleted file mode 100644
index 31dcd905..00000000
--- a/ext/ogg/gstogmparse.c
+++ /dev/null
@@ -1,972 +0,0 @@
-/* GStreamer OGM parsing
- * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
- * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
- *
- * 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 <stdio.h>
-#include <string.h>
-
-#include <gst/gst.h>
-#include <gst/tag/tag.h>
-#include <gst/riff/riff-media.h>
-#include <gst/riff/riff-read.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_ogm_parse_debug);
-#define GST_CAT_DEFAULT gst_ogm_parse_debug
-
-#define GST_TYPE_OGM_VIDEO_PARSE (gst_ogm_video_parse_get_type())
-#define GST_IS_OGM_VIDEO_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_VIDEO_PARSE))
-
-#define GST_TYPE_OGM_AUDIO_PARSE (gst_ogm_audio_parse_get_type())
-#define GST_IS_OGM_AUDIO_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_AUDIO_PARSE))
-
-#define GST_TYPE_OGM_TEXT_PARSE (gst_ogm_text_parse_get_type())
-#define GST_IS_OGM_TEXT_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_TEXT_PARSE))
-
-#define GST_TYPE_OGM_PARSE (gst_ogm_parse_get_type())
-#define GST_OGM_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OGM_PARSE, GstOgmParse))
-#define GST_OGM_PARSE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OGM_PARSE, GstOgmParse))
-#define GST_IS_OGM_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_PARSE))
-#define GST_IS_OGM_PARSE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OGM_PARSE))
-#define GST_OGM_PARSE_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_OGM_PARSE, GstOgmParseClass))
-
-static const GstElementDetails gst_ogm_audio_parse_details =
-GST_ELEMENT_DETAILS ("OGM audio stream parser",
- "Codec/Decoder/Audio",
- "parse an OGM audio header and stream",
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-
-static const GstElementDetails gst_ogm_video_parse_details =
-GST_ELEMENT_DETAILS ("OGM video stream parser",
- "Codec/Decoder/Video",
- "parse an OGM video header and stream",
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-
-static const GstElementDetails gst_ogm_text_parse_details =
-GST_ELEMENT_DETAILS ("OGM text stream parser",
- "Codec/Decoder/Subtitle",
- "parse an OGM text header and stream",
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-
-typedef struct _stream_header_video
-{
- gint32 width;
- gint32 height;
-} stream_header_video;
-
-typedef struct _stream_header_audio
-{
- gint16 channels;
- gint16 blockalign;
- gint32 avgbytespersec;
-} stream_header_audio;
-
-/* sizeof(stream_header) might differ due to structure packing and
- * alignment differences on some architectures, so not using that */
-#define OGM_STREAM_HEADER_SIZE (8+4+4+8+8+4+4+4+8)
-
-typedef struct _stream_header
-{
- gchar streamtype[8];
- gchar subtype[4 + 1];
-
- /* size of the structure */
- gint32 size;
-
- /* in reference time */
- gint64 time_unit;
-
- gint64 samples_per_unit;
-
- /* in media time */
- gint32 default_len;
-
- gint32 buffersize;
- gint32 bits_per_sample;
-
- union
- {
- stream_header_video video;
- stream_header_audio audio;
- /* text has no additional data */
- } s;
-} stream_header;
-
-typedef struct _GstOgmParse
-{
- GstElement element;
-
- /* pads */
- GstPad *srcpad, *sinkpad;
- GstPadTemplate *srcpadtempl;
-
- /* we need to cache events that we receive before creating the source pad */
- GList *cached_events;
-
- /* audio or video */
- stream_header hdr;
-
- /* expected next granulepos (used for timestamp guessing) */
- guint64 next_granulepos;
-} GstOgmParse;
-
-typedef struct _GstOgmParseClass
-{
- GstElementClass parent_class;
-} GstOgmParseClass;
-
-static GstStaticPadTemplate sink_factory_video =
-GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/x-ogm-video"));
-static GstStaticPadTemplate sink_factory_audio =
-GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/x-ogm-audio"));
-static GstStaticPadTemplate sink_factory_text =
-GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/x-ogm-text"));
-static GstPadTemplate *video_src_templ, *audio_src_templ, *text_src_templ;
-
-static GType gst_ogm_audio_parse_get_type (void);
-static GType gst_ogm_video_parse_get_type (void);
-static GType gst_ogm_text_parse_get_type (void);
-static GType gst_ogm_parse_get_type (void);
-
-static void gst_ogm_audio_parse_base_init (GstOgmParseClass * klass);
-static void gst_ogm_video_parse_base_init (GstOgmParseClass * klass);
-static void gst_ogm_text_parse_base_init (GstOgmParseClass * klass);
-static void gst_ogm_parse_class_init (GstOgmParseClass * klass);
-static void gst_ogm_parse_init (GstOgmParse * ogm);
-static void gst_ogm_video_parse_init (GstOgmParse * ogm);
-static void gst_ogm_audio_parse_init (GstOgmParse * ogm);
-static void gst_ogm_text_parse_init (GstOgmParse * ogm);
-
-static const GstQueryType *gst_ogm_parse_get_sink_querytypes (GstPad * pad);
-static gboolean gst_ogm_parse_sink_event (GstPad * pad, GstEvent * event);
-static gboolean gst_ogm_parse_sink_query (GstPad * pad, GstQuery * query);
-static gboolean gst_ogm_parse_sink_convert (GstPad * pad, GstFormat src_format,
- gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
-
-static GstFlowReturn gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer);
-
-static GstStateChangeReturn gst_ogm_parse_change_state (GstElement * element,
- GstStateChange transition);
-
-static GstElementClass *parent_class = NULL;
-
-static GType
-gst_ogm_parse_get_type (void)
-{
- static GType ogm_parse_type = 0;
-
- if (!ogm_parse_type) {
- static const GTypeInfo ogm_parse_info = {
- sizeof (GstOgmParseClass),
- NULL,
- NULL,
- (GClassInitFunc) gst_ogm_parse_class_init,
- NULL,
- NULL,
- sizeof (GstOgmParse),
- 0,
- (GInstanceInitFunc) gst_ogm_parse_init,
- };
-
- ogm_parse_type =
- g_type_register_static (GST_TYPE_ELEMENT,
- "GstOgmParse", &ogm_parse_info, 0);
- }
-
- return ogm_parse_type;
-}
-
-static GType
-gst_ogm_audio_parse_get_type (void)
-{
- static GType ogm_audio_parse_type = 0;
-
- if (!ogm_audio_parse_type) {
- static const GTypeInfo ogm_audio_parse_info = {
- sizeof (GstOgmParseClass),
- (GBaseInitFunc) gst_ogm_audio_parse_base_init,
- NULL,
- NULL,
- NULL,
- NULL,
- sizeof (GstOgmParse),
- 0,
- (GInstanceInitFunc) gst_ogm_audio_parse_init,
- };
-
- ogm_audio_parse_type =
- g_type_register_static (GST_TYPE_OGM_PARSE,
- "GstOgmAudioParse", &ogm_audio_parse_info, 0);
- }
-
- return ogm_audio_parse_type;
-}
-
-static GType
-gst_ogm_video_parse_get_type (void)
-{
- static GType ogm_video_parse_type = 0;
-
- if (!ogm_video_parse_type) {
- static const GTypeInfo ogm_video_parse_info = {
- sizeof (GstOgmParseClass),
- (GBaseInitFunc) gst_ogm_video_parse_base_init,
- NULL,
- NULL,
- NULL,
- NULL,
- sizeof (GstOgmParse),
- 0,
- (GInstanceInitFunc) gst_ogm_video_parse_init,
- };
-
- ogm_video_parse_type =
- g_type_register_static (GST_TYPE_OGM_PARSE,
- "GstOgmVideoParse", &ogm_video_parse_info, 0);
- }
-
- return ogm_video_parse_type;
-}
-
-static GType
-gst_ogm_text_parse_get_type (void)
-{
- static GType ogm_text_parse_type = 0;
-
- if (!ogm_text_parse_type) {
- static const GTypeInfo ogm_text_parse_info = {
- sizeof (GstOgmParseClass),
- (GBaseInitFunc) gst_ogm_text_parse_base_init,
- NULL,
- NULL,
- NULL,
- NULL,
- sizeof (GstOgmParse),
- 0,
- (GInstanceInitFunc) gst_ogm_text_parse_init,
- };
-
- ogm_text_parse_type =
- g_type_register_static (GST_TYPE_OGM_PARSE,
- "GstOgmTextParse", &ogm_text_parse_info, 0);
- }
-
- return ogm_text_parse_type;
-}
-
-static void
-gst_ogm_audio_parse_base_init (GstOgmParseClass * klass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- GstCaps *caps = gst_riff_create_audio_template_caps ();
-
- gst_element_class_set_details (element_class, &gst_ogm_audio_parse_details);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory_audio));
- audio_src_templ = gst_pad_template_new ("src",
- GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
- gst_element_class_add_pad_template (element_class, audio_src_templ);
-}
-
-static void
-gst_ogm_video_parse_base_init (GstOgmParseClass * klass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- GstCaps *caps = gst_riff_create_video_template_caps ();
-
- gst_element_class_set_details (element_class, &gst_ogm_video_parse_details);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory_video));
- video_src_templ = gst_pad_template_new ("src",
- GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
- gst_element_class_add_pad_template (element_class, video_src_templ);
-}
-
-static void
-gst_ogm_text_parse_base_init (GstOgmParseClass * klass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- GstCaps *caps = gst_caps_new_simple ("text/plain", NULL, NULL);
-
- gst_element_class_set_details (element_class, &gst_ogm_text_parse_details);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory_text));
- text_src_templ = gst_pad_template_new ("src",
- GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
- gst_element_class_add_pad_template (element_class, text_src_templ);
-}
-
-static void
-gst_ogm_parse_class_init (GstOgmParseClass * klass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_ogm_parse_change_state);
-}
-
-static void
-gst_ogm_parse_init (GstOgmParse * ogm)
-{
- memset (&ogm->hdr, 0, sizeof (ogm->hdr));
- ogm->next_granulepos = 0;
- ogm->srcpad = NULL;
- ogm->cached_events = NULL;
-}
-
-static void
-gst_ogm_audio_parse_init (GstOgmParse * ogm)
-{
- ogm->sinkpad = gst_pad_new_from_static_template (&sink_factory_audio, "sink");
- gst_pad_set_query_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_query));
- gst_pad_set_chain_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_chain));
- gst_pad_set_event_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_event));
- gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad);
-
- ogm->srcpad = NULL;
- ogm->srcpadtempl = audio_src_templ;
-}
-
-static void
-gst_ogm_video_parse_init (GstOgmParse * ogm)
-{
- ogm->sinkpad = gst_pad_new_from_static_template (&sink_factory_video, "sink");
- gst_pad_set_query_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_query));
- gst_pad_set_chain_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_chain));
- gst_pad_set_event_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_event));
- gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad);
-
- ogm->srcpad = NULL;
- ogm->srcpadtempl = video_src_templ;
-}
-
-static void
-gst_ogm_text_parse_init (GstOgmParse * ogm)
-{
- ogm->sinkpad = gst_pad_new_from_static_template (&sink_factory_text, "sink");
- gst_pad_set_query_type_function (ogm->sinkpad,
- gst_ogm_parse_get_sink_querytypes);
- gst_pad_set_query_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_query));
- gst_pad_set_chain_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_chain));
- gst_pad_set_event_function (ogm->sinkpad,
- GST_DEBUG_FUNCPTR (gst_ogm_parse_sink_event));
- gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad);
-
- ogm->srcpad = NULL;
- ogm->srcpadtempl = text_src_templ;
-}
-
-static const GstQueryType *
-gst_ogm_parse_get_sink_querytypes (GstPad * pad)
-{
- static const GstQueryType types[] = {
- GST_QUERY_POSITION,
- 0
- };
-
- return types;
-}
-
-static gboolean
-gst_ogm_parse_sink_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = FALSE;
- GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad));
-
- switch (src_format) {
- case GST_FORMAT_DEFAULT:
- switch (*dest_format) {
- case GST_FORMAT_TIME:
- switch (ogm->hdr.streamtype[0]) {
- case 'a':
- *dest_value = GST_SECOND * src_value / ogm->hdr.samples_per_unit;
- res = TRUE;
- break;
- case 'v':
- case 't':
- *dest_value = (GST_SECOND / 10000000) *
- ogm->hdr.time_unit * src_value;
- res = TRUE;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- break;
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_DEFAULT:
- switch (ogm->hdr.streamtype[0]) {
- case 'a':
- *dest_value = ogm->hdr.samples_per_unit * src_value / GST_SECOND;
- res = TRUE;
- break;
- case 'v':
- case 't':
- *dest_value = src_value /
- ((GST_SECOND / 10000000) * ogm->hdr.time_unit);
- res = TRUE;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- gst_object_unref (ogm);
- return res;
-}
-
-static gboolean
-gst_ogm_parse_sink_query (GstPad * pad, GstQuery * query)
-{
- GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad));
- GstFormat format;
- gboolean res = FALSE;
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- {
- gint64 val;
-
- gst_query_parse_position (query, &format, NULL);
-
- if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME)
- break;
-
- if ((res = gst_ogm_parse_sink_convert (pad,
- GST_FORMAT_DEFAULT, ogm->next_granulepos, &format, &val))) {
- /* don't know the total length here.. */
- gst_query_set_position (query, format, val);
- }
- break;
- }
- case GST_QUERY_CONVERT:
- {
- GstFormat src_fmt, dest_fmt;
- gint64 src_val, dest_val;
-
- /* peel off input */
- gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
- if ((res = gst_ogm_parse_sink_convert (pad, src_fmt, src_val,
- &dest_fmt, &dest_val))) {
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- }
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-
- gst_object_unref (ogm);
- return res;
-}
-
-static GstFlowReturn
-gst_ogm_parse_stream_header (GstOgmParse * ogm, const guint8 * data, guint size)
-{
- GstCaps *caps = NULL;
-
- /* stream header */
- if (size < OGM_STREAM_HEADER_SIZE)
- goto buffer_too_small;
-
- if (!memcmp (data, "video\000\000\000", 8)) {
- ogm->hdr.s.video.width = GST_READ_UINT32_LE (&data[44]);
- ogm->hdr.s.video.height = GST_READ_UINT32_LE (&data[48]);
- } else if (!memcmp (data, "audio\000\000\000", 8)) {
- ogm->hdr.s.audio.channels = GST_READ_UINT32_LE (&data[44]);
- ogm->hdr.s.audio.blockalign = GST_READ_UINT32_LE (&data[46]);
- ogm->hdr.s.audio.avgbytespersec = GST_READ_UINT32_LE (&data[48]);
- } else if (!memcmp (data, "text\000\000\000\000", 8)) {
- /* nothing here */
- } else {
- goto cannot_decode;
- }
- memcpy (ogm->hdr.streamtype, &data[0], 8);
- memcpy (ogm->hdr.subtype, &data[8], 4);
- ogm->hdr.subtype[4] = '\0';
- ogm->hdr.size = GST_READ_UINT32_LE (&data[12]);
- ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[16]);
- ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[24]);
- ogm->hdr.default_len = GST_READ_UINT32_LE (&data[32]);
- ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[36]);
- ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[40]);
-
- switch (ogm->hdr.streamtype[0]) {
- case 'a':{
- guint codec_id = 0;
-
- if (sscanf (ogm->hdr.subtype, "%04x", &codec_id) != 1) {
- GST_WARNING_OBJECT (ogm, "cannot parse subtype %s", ogm->hdr.subtype);
- }
-
- caps =
- gst_riff_create_audio_caps (codec_id, NULL, NULL, NULL, NULL, NULL);
-
- if (caps == NULL) {
- GST_WARNING_OBJECT (ogm, "no audio caps for codec %u found", codec_id);
- caps = gst_caps_new_simple ("audio/x-ogm-unknown", "codec_id",
- G_TYPE_INT, (gint) codec_id, NULL);
- }
-
- gst_caps_set_simple (caps,
- "channels", G_TYPE_INT, ogm->hdr.s.audio.channels,
- "rate", G_TYPE_INT, ogm->hdr.samples_per_unit, NULL);
-
- GST_LOG_OBJECT (ogm, "Type: %s, subtype: 0x%04x, channels: %d, "
- "samplerate: %d, blockalign: %d, bps: %d, caps = %" GST_PTR_FORMAT,
- ogm->hdr.streamtype, codec_id, ogm->hdr.s.audio.channels,
- (gint) ogm->hdr.samples_per_unit, ogm->hdr.s.audio.blockalign,
- ogm->hdr.s.audio.avgbytespersec, caps);
- break;
- }
- case 'v':{
- guint32 fourcc;
- gint time_unit;
-
- fourcc = GST_MAKE_FOURCC (ogm->hdr.subtype[0],
- ogm->hdr.subtype[1], ogm->hdr.subtype[2], ogm->hdr.subtype[3]);
-
- caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
-
- if (caps == NULL) {
- GST_WARNING_OBJECT (ogm, "could not find video caps for fourcc %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
- caps = gst_caps_new_simple ("video/x-ogm-unknown", "fourcc",
- GST_TYPE_FOURCC, fourcc, NULL);
- break;
- }
-
- GST_LOG_OBJECT (ogm, "Type: %s, subtype: %" GST_FOURCC_FORMAT
- ", size: %dx%d, timeunit: %" G_GINT64_FORMAT
- " (fps: %lf), s/u: %" G_GINT64_FORMAT ", "
- "def.len: %d, bufsize: %d, bps: %d, caps = %" GST_PTR_FORMAT,
- ogm->hdr.streamtype, GST_FOURCC_ARGS (fourcc),
- ogm->hdr.s.video.width, ogm->hdr.s.video.height,
- ogm->hdr.time_unit, 10000000. / ogm->hdr.time_unit,
- ogm->hdr.samples_per_unit, ogm->hdr.default_len,
- ogm->hdr.buffersize, ogm->hdr.bits_per_sample, caps);
-
- /* GST_TYPE_FRACTION contains gint */
- if (ogm->hdr.time_unit > G_MAXINT || ogm->hdr.time_unit < G_MININT)
- GST_WARNING_OBJECT (ogm, "timeunit is out of range");
-
- time_unit = (gint) CLAMP (ogm->hdr.time_unit, G_MININT, G_MAXINT);
- gst_caps_set_simple (caps,
- "width", G_TYPE_INT, ogm->hdr.s.video.width,
- "height", G_TYPE_INT, ogm->hdr.s.video.height,
- "framerate", GST_TYPE_FRACTION, 10000000, time_unit, NULL);
- break;
- }
- case 't':{
- GST_LOG_OBJECT (ogm, "Type: %s, s/u: %" G_GINT64_FORMAT
- ", timeunit=%" G_GINT64_FORMAT,
- ogm->hdr.streamtype, ogm->hdr.samples_per_unit, ogm->hdr.time_unit);
- caps = gst_caps_new_simple ("text/plain", NULL);
- break;
- }
- default:
- g_assert_not_reached ();
- }
-
- if (caps == NULL)
- goto cannot_decode;
-
- if (ogm->srcpad) {
- GstCaps *current_caps = GST_PAD_CAPS (ogm->srcpad);
-
- if (current_caps && caps && !gst_caps_is_equal (current_caps, caps)) {
- GST_WARNING_OBJECT (ogm, "Already an existing pad %s:%s",
- GST_DEBUG_PAD_NAME (ogm->srcpad));
- gst_pad_set_active (ogm->srcpad, FALSE);
- gst_element_remove_pad (GST_ELEMENT (ogm), ogm->srcpad);
- ogm->srcpad = NULL;
- } else {
- GST_DEBUG_OBJECT (ogm, "Existing pad has the same caps, do nothing");
- }
- }
-
- if (ogm->srcpad == NULL) {
- GList *l, *cached_events;
-
- ogm->srcpad = gst_pad_new_from_template (ogm->srcpadtempl, "src");
- gst_pad_use_fixed_caps (ogm->srcpad);
- gst_pad_set_caps (ogm->srcpad, caps);
- gst_pad_set_active (ogm->srcpad, TRUE);
- gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
- GST_INFO_OBJECT (ogm, "Added pad %s:%s with caps %" GST_PTR_FORMAT,
- GST_DEBUG_PAD_NAME (ogm->srcpad), caps);
-
- GST_OBJECT_LOCK (ogm);
- cached_events = ogm->cached_events;
- ogm->cached_events = NULL;
- GST_OBJECT_UNLOCK (ogm);
-
- for (l = cached_events; l; l = l->next) {
- GstEvent *event = GST_EVENT_CAST (l->data);
-
- GST_DEBUG_OBJECT (ogm, "Pushing cached event %" GST_PTR_FORMAT, event);
- gst_pad_push_event (ogm->srcpad, event);
- }
- g_list_free (cached_events);
-
- {
- GstTagList *tags;
-
- tags = gst_tag_list_new ();
- gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_SUBTITLE_CODEC,
- "Ogm", NULL);
- gst_element_found_tags_for_pad (GST_ELEMENT (ogm), ogm->srcpad, tags);
- }
- }
-
- gst_caps_unref (caps);
-
- return GST_FLOW_OK;
-
-/* ERRORS */
-buffer_too_small:
- {
- GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE, ("Buffer too small"), (NULL));
- return GST_FLOW_ERROR;
- }
-cannot_decode:
- {
- GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL), ("unknown ogm format"));
- return GST_FLOW_ERROR;
- }
-}
-
-static GstFlowReturn
-gst_ogm_parse_comment_packet (GstOgmParse * ogm, GstBuffer * buf)
-{
- GstFlowReturn ret;
-
- if (ogm->srcpad == NULL) {
- GST_DEBUG ("no source pad");
- return GST_FLOW_WRONG_STATE;
- }
-
- /* if this is not a subtitle stream, push the vorbiscomment packet
- * on downstream, the respective decoder will handle it; if it is
- * a subtitle stream, we will have to handle the comment ourself */
- if (ogm->hdr.streamtype[0] == 't') {
- GstTagList *tags;
-
- tags = gst_tag_list_from_vorbiscomment_buffer (buf,
- (guint8 *) "\003vorbis", 7, NULL);
-
- if (tags) {
- GST_DEBUG_OBJECT (ogm, "tags = %" GST_PTR_FORMAT, tags);
- gst_element_found_tags_for_pad (GST_ELEMENT (ogm), ogm->srcpad, tags);
- } else {
- GST_DEBUG_OBJECT (ogm, "failed to extract tags from vorbis comment");
- }
- /* do not push packet downstream, just let parent unref it */
- ret = GST_FLOW_OK;
- } else {
- buf = gst_buffer_copy (buf);
- gst_buffer_set_caps (buf, GST_PAD_CAPS (ogm->srcpad));
- ret = gst_pad_push (ogm->srcpad, buf);
- }
-
- return ret;
-}
-
-static void
-gst_ogm_text_parse_strip_trailing_zeroes (GstOgmParse * ogm, GstBuffer * buf)
-{
- const guint8 *data;
- guint size;
-
- g_assert (gst_buffer_is_metadata_writable (buf));
-
- /* zeroes are not valid UTF-8 characters, so strip them from output */
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
- while (size > 0 && data[size - 1] == '\0') {
- --size;
- }
-
- GST_BUFFER_SIZE (buf) = size;
-}
-
-static GstFlowReturn
-gst_ogm_parse_data_packet (GstOgmParse * ogm, GstBuffer * buf)
-{
- GstFlowReturn ret;
- const guint8 *data;
- GstBuffer *sbuf;
- gboolean keyframe;
- guint size, len, n, xsize = 0;
-
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
-
- if ((data[0] & 0x01) != 0)
- goto invalid_startcode;
-
- /* data - push on */
- len = ((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1);
- keyframe = (((data[0] & 0x08) >> 3) != 0);
-
- if ((1 + len) > size)
- goto buffer_too_small;
-
- for (n = len; n > 0; n--) {
- xsize = (xsize << 8) | data[n];
- }
-
- GST_LOG_OBJECT (ogm, "[0x%02x] samples: %d, hdrbytes: %d, datasize: %d",
- data[0], xsize, len, size - len - 1);
-
- sbuf = gst_buffer_create_sub (buf, len + 1, size - len - 1);
-
- if (GST_BUFFER_OFFSET_END_IS_VALID (buf))
- ogm->next_granulepos = GST_BUFFER_OFFSET_END (buf);
-
- switch (ogm->hdr.streamtype[0]) {
- case 't':
- case 'v':{
- GstClockTime ts, next_ts;
- guint samples;
-
- samples = (ogm->hdr.streamtype[0] == 'v') ? 1 : xsize;
-
- if (!keyframe) {
- GST_BUFFER_FLAG_SET (sbuf, GST_BUFFER_FLAG_DELTA_UNIT);
- }
-
- /* shouldn't this be granulepos - samples? (tpm) */
- ts = gst_util_uint64_scale (ogm->next_granulepos,
- ogm->hdr.time_unit * GST_SECOND, 10000000);
- next_ts = gst_util_uint64_scale (ogm->next_granulepos + samples,
- ogm->hdr.time_unit * GST_SECOND, 10000000);
-
- GST_BUFFER_TIMESTAMP (sbuf) = ts;
- GST_BUFFER_DURATION (sbuf) = next_ts - ts;
-
- ogm->next_granulepos += samples;
-
- if (ogm->hdr.streamtype[0] == 't') {
- gst_ogm_text_parse_strip_trailing_zeroes (ogm, sbuf);
- }
- break;
- }
- case 'a':{
- GstClockTime ts, next_ts;
-
- /* shouldn't this be granulepos - samples? (tpm) */
- ts = gst_util_uint64_scale_int (ogm->next_granulepos,
- GST_SECOND, ogm->hdr.samples_per_unit);
- next_ts = gst_util_uint64_scale_int (ogm->next_granulepos + xsize,
- GST_SECOND, ogm->hdr.samples_per_unit);
-
- GST_BUFFER_TIMESTAMP (sbuf) = ts;
- GST_BUFFER_DURATION (sbuf) = next_ts - ts;
-
- ogm->next_granulepos += xsize;
- break;
- }
- default:
- g_assert_not_reached ();
- break;
- }
-
- if (ogm->srcpad) {
- gst_buffer_set_caps (sbuf, GST_PAD_CAPS (ogm->srcpad));
- GST_LOG_OBJECT (ogm, "Pushing buffer with ts=%" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sbuf)));
- ret = gst_pad_push (ogm->srcpad, sbuf);
- if (ret != GST_FLOW_OK) {
- GST_DEBUG_OBJECT (ogm, "Flow on %s:%s = %s",
- GST_DEBUG_PAD_NAME (ogm->srcpad), gst_flow_get_name (ret));
- }
- } else {
- ret = GST_FLOW_WRONG_STATE;
- }
-
- return ret;
-
-/* ERRORS */
-invalid_startcode:
- {
- GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL),
- ("unexpected packet startcode 0x%02x", data[0]));
- return GST_FLOW_ERROR;
- }
-buffer_too_small:
- {
- GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL),
- ("buffer too small, len+1=%u, size=%u", len + 1, size));
- return GST_FLOW_ERROR;
- }
-}
-
-static GstFlowReturn
-gst_ogm_parse_chain (GstPad * pad, GstBuffer * buf)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- GstOgmParse *ogm = GST_OGM_PARSE (GST_PAD_PARENT (pad));
- guint8 *data = GST_BUFFER_DATA (buf);
- guint size = GST_BUFFER_SIZE (buf);
-
- if (size < 1)
- goto buffer_too_small;
-
- GST_LOG_OBJECT (ogm, "Packet with start code 0x%02x", data[0]);
-
- switch (data[0]) {
- case 0x01:{
- ret = gst_ogm_parse_stream_header (ogm, data + 1, size - 1);
- break;
- }
- case 0x03:{
- ret = gst_ogm_parse_comment_packet (ogm, buf);
- break;
- }
- default:{
- ret = gst_ogm_parse_data_packet (ogm, buf);
- break;
- }
- }
-
- gst_buffer_unref (buf);
-
- if (ret != GST_FLOW_OK) {
- GST_DEBUG_OBJECT (ogm, "Flow: %s", gst_flow_get_name (ret));
- }
-
- return ret;
-
-/* ERRORS */
-buffer_too_small:
- {
- GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL), ("buffer too small"));
- gst_buffer_unref (buf);
- return GST_FLOW_ERROR;
- }
-}
-
-static gboolean
-gst_ogm_parse_sink_event (GstPad * pad, GstEvent * event)
-{
- GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad));
- gboolean res;
-
- GST_LOG_OBJECT (ogm, "processing %s event", GST_EVENT_TYPE_NAME (event));
-
- GST_OBJECT_LOCK (ogm);
- if (ogm->srcpad == NULL) {
- ogm->cached_events = g_list_append (ogm->cached_events, event);
- GST_OBJECT_UNLOCK (ogm);
- res = TRUE;
- } else {
- GST_OBJECT_UNLOCK (ogm);
- res = gst_pad_event_default (pad, event);
- }
-
- gst_object_unref (ogm);
- return res;
-}
-
-static GstStateChangeReturn
-gst_ogm_parse_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret;
- GstOgmParse *ogm = GST_OGM_PARSE (element);
-
- ret = parent_class->change_state (element, transition);
- if (ret != GST_STATE_CHANGE_SUCCESS)
- return ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- if (ogm->srcpad) {
- gst_pad_set_active (ogm->srcpad, FALSE);
- gst_element_remove_pad (element, ogm->srcpad);
- ogm->srcpad = NULL;
- }
- memset (&ogm->hdr, 0, sizeof (ogm->hdr));
- ogm->next_granulepos = 0;
- g_list_foreach (ogm->cached_events, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (ogm->cached_events);
- ogm->cached_events = NULL;
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-gboolean
-gst_ogm_parse_plugin_init (GstPlugin * plugin)
-{
- gst_riff_init ();
-
- GST_DEBUG_CATEGORY_INIT (gst_ogm_parse_debug, "ogmparse", 0, "ogm parser");
-
- return gst_element_register (plugin, "ogmaudioparse", GST_RANK_PRIMARY,
- GST_TYPE_OGM_AUDIO_PARSE) &&
- gst_element_register (plugin, "ogmvideoparse", GST_RANK_PRIMARY,
- GST_TYPE_OGM_VIDEO_PARSE) &&
- gst_element_register (plugin, "ogmtextparse", GST_RANK_PRIMARY,
- GST_TYPE_OGM_TEXT_PARSE);
-}
diff --git a/ext/ogg/vorbis_parse.c b/ext/ogg/vorbis_parse.c
deleted file mode 100644
index f9ba746d..00000000
--- a/ext/ogg/vorbis_parse.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- This file borrowed from liboggz
- */
-/*
- Copyright (C) 2003 Commonwealth Scientific and Industrial Research
- Organisation (CSIRO) Australia
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- - Neither the name of CSIRO Australia nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/*
- * oggz_auto.c
- *
- * Conrad Parker <conrad@annodex.net>
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "gstoggstream.h"
-
-/*
- * Vorbis packets can be short or long, and each packet overlaps the previous
- * and next packets. The granulepos of a packet is always the last sample
- * that is completely decoded at the end of decoding that packet - i.e. the
- * last packet before the first overlapping packet. If the sizes of packets
- * are 's' and 'l', then the increment will depend on the previous and next
- * packet types:
- * v prev<<1 | next
- * lll: l/2 3
- * lls: 3l/4 - s/4 2
- * lsl: s/2
- * lss: s/2
- * sll: l/4 + s/4 1
- * sls: l/2 0
- * ssl: s/2
- * sss: s/2
- *
- * The previous and next packet types can be inferred from the current packet
- * (additional information is not required)
- *
- * The two blocksizes can be determined from the first header packet, by reading
- * byte 28. 1 << (packet[28] >> 4) == long_size.
- * 1 << (packet[28] & 0xF) == short_size.
- *
- * (see http://xiph.org/vorbis/doc/Vorbis_I_spec.html for specification)
- */
-
-
-void
-parse_vorbis_header_packet (GstOggStream * pad, ogg_packet * packet)
-{
- /*
- * on the first (b_o_s) packet, determine the long and short sizes,
- * and then calculate l/2, l/4 - s/4, 3 * l/4 - s/4, l/2 - s/2 and s/2
- */
- int short_size;
- int long_size;
-
- long_size = 1 << (packet->packet[28] >> 4);
- short_size = 1 << (packet->packet[28] & 0xF);
-
- pad->nln_increments[3] = long_size >> 1;
- pad->nln_increments[2] = 3 * (long_size >> 2) - (short_size >> 2);
- pad->nln_increments[1] = (long_size >> 2) + (short_size >> 2);
- pad->nln_increments[0] = pad->nln_increments[3];
- pad->short_size = short_size;
- pad->long_size = long_size;
- pad->nsn_increment = short_size >> 1;
-}
-
-void
-parse_vorbis_setup_packet (GstOggStream * pad, ogg_packet * op)
-{
- /*
- * the code pages, a whole bunch of other fairly useless stuff, AND,
- * RIGHT AT THE END (of a bunch of variable-length compressed rubbish that
- * basically has only one actual set of values that everyone uses BUT YOU
- * CAN'T BE SURE OF THAT, OH NO YOU CAN'T) is the only piece of data that's
- * actually useful to us - the packet modes (because it's inconceivable to
- * think people might want _just that_ and nothing else, you know, for
- * seeking and stuff).
- *
- * Fortunately, because of the mandate that non-used bits must be zero
- * at the end of the packet, we might be able to sneakily work backwards
- * and find out the information we need (namely a mapping of modes to
- * packet sizes)
- */
- unsigned char *current_pos = &op->packet[op->bytes - 1];
- int offset;
- int size;
- int size_check;
- int *mode_size_ptr;
- int i;
- int ii;
-
- /*
- * This is the format of the mode data at the end of the packet for all
- * Vorbis Version 1 :
- *
- * [ 6:number_of_modes ]
- * [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
- * [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
- * [ 1:size | 16:window_type(0) | 16:transform_type(0) | 8:mapping ]
- * [ 1:framing(1) ]
- *
- * e.g.:
- *
- * <-
- * 0 0 0 0 0 1 0 0
- * 0 0 1 0 0 0 0 0
- * 0 0 1 0 0 0 0 0
- * 0 0 1|0 0 0 0 0
- * 0 0 0 0|0|0 0 0
- * 0 0 0 0 0 0 0 0
- * 0 0 0 0|0 0 0 0
- * 0 0 0 0 0 0 0 0
- * 0 0 0 0|0 0 0 0
- * 0 0 0|1|0 0 0 0 |
- * 0 0 0 0 0 0 0 0 V
- * 0 0 0|0 0 0 0 0
- * 0 0 0 0 0 0 0 0
- * 0 0 1|0 0 0 0 0
- * 0 0|1|0 0 0 0 0
- *
- *
- * i.e. each entry is an important bit, 32 bits of 0, 8 bits of blah, a
- * bit of 1.
- * Let's find our last 1 bit first.
- *
- */
-
- size = 0;
-
- offset = 8;
- while (!((1 << --offset) & *current_pos)) {
- if (offset == 0) {
- offset = 8;
- current_pos -= 1;
- }
- }
-
- while (1) {
-
- /*
- * from current_pos-5:(offset+1) to current_pos-1:(offset+1) should
- * be zero
- */
- offset = (offset + 7) % 8;
- if (offset == 7)
- current_pos -= 1;
-
- if (((current_pos[-5] & ~((1 << (offset + 1)) - 1)) != 0)
- ||
- current_pos[-4] != 0
- ||
- current_pos[-3] != 0
- ||
- current_pos[-2] != 0
- || ((current_pos[-1] & ((1 << (offset + 1)) - 1)) != 0)
- ) {
- break;
- }
-
- size += 1;
-
- current_pos -= 5;
-
- }
-
- /* Give ourselves a chance to recover if we went back too far by using
- * the size check. */
- for (ii = 0; ii < 2; ii++) {
- if (offset > 4) {
- size_check = (current_pos[0] >> (offset - 5)) & 0x3F;
- } else {
- /* mask part of byte from current_pos */
- size_check = (current_pos[0] & ((1 << (offset + 1)) - 1));
- /* shift to appropriate position */
- size_check <<= (5 - offset);
- /* or in part of byte from current_pos - 1 */
- size_check |= (current_pos[-1] & ~((1 << (offset + 3)) - 1)) >>
- (offset + 3);
- }
-
- size_check += 1;
- if (size_check == size) {
- break;
- }
- offset = (offset + 1) % 8;
- if (offset == 0)
- current_pos += 1;
- current_pos += 5;
- size -= 1;
- }
-
- /* Store mode size information in our info struct */
- i = -1;
- while ((1 << (++i)) < size);
- pad->vorbis_log2_num_modes = i;
-
- mode_size_ptr = pad->vorbis_mode_sizes;
-
- for (i = 0; i < size; i++) {
- offset = (offset + 1) % 8;
- if (offset == 0)
- current_pos += 1;
- *mode_size_ptr++ = (current_pos[0] >> offset) & 0x1;
- current_pos += 5;
- }
-
-}
diff --git a/ext/pango/Makefile.am b/ext/pango/Makefile.am
deleted file mode 100644
index 197ed338..00000000
--- a/ext/pango/Makefile.am
+++ /dev/null
@@ -1,28 +0,0 @@
-plugin_LTLIBRARIES = libgstpango.la
-
-noinst_HEADERS = \
- gstclockoverlay.h \
- gsttextoverlay.h \
- gsttextrender.h \
- gsttimeoverlay.h
-
-libgstpango_la_SOURCES = \
- gstclockoverlay.c \
- gsttextoverlay.c \
- gsttextrender.c \
- gsttimeoverlay.c
-
-libgstpango_la_CFLAGS = \
- $(GST_PLUGINS_BASE_CFLAGS) \
- $(GST_BASE_CFLAGS) \
- $(GST_CFLAGS) \
- $(PANGO_CFLAGS)
-libgstpango_la_LIBADD = \
- $(GST_PLUGINS_BASE_LIBS) \
- $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la \
- $(GST_BASE_LIBS) \
- $(GST_LIBS) \
- $(PANGO_LIBS)
-libgstpango_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstpango_la_LIBTOOLFLAGS = --tag=disable-static
-
diff --git a/ext/pango/gstclockoverlay.c b/ext/pango/gstclockoverlay.c
deleted file mode 100644
index 5db475bc..00000000
--- a/ext/pango/gstclockoverlay.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) <2005> Tim-Philipp Müller <tim@centricular.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-clockoverlay
- * @see_also: #GstTextOverlay, #GstTimeOverlay
- *
- * This element overlays the current clock time on top of a video
- * stream. You can position the text and configure the font details
- * using the properties of the #GstTextOverlay class. By default, the
- * time is displayed in the top left corner of the picture, with some
- * padding to the left and to the top.
- *
- * <refsect2>
- * <title>Example launch lines</title>
- * |[
- * gst-launch -v videotestsrc ! clockoverlay ! xvimagesink
- * ]| Display the current time in the top left corner of the video picture
- * |[
- * gst-launch -v videotestsrc ! clockoverlay halign=right valign=bottom text="Edge City" shaded-background=true ! ffmpegcolorspace ! ximagesink
- * ]| Another pipeline that displays the current time with some leading
- * text in the bottom right corner of the video picture, with the background
- * of the text being shaded in order to make it more legible on top of a
- * bright video background.
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gstclockoverlay.h>
-#include <gst/video/video.h>
-#include <time.h>
-
-
-#define DEFAULT_PROP_TIMEFORMAT "%H:%M:%S"
-
-enum
-{
- PROP_0,
- PROP_TIMEFORMAT,
- PROP_LAST
-};
-
-GST_BOILERPLATE (GstClockOverlay, gst_clock_overlay, GstTextOverlay,
- GST_TYPE_TEXT_OVERLAY);
-
-static void
-gst_clock_overlay_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class, "Clock overlay",
- "Filter/Editor/Video",
- "Overlays the current clock time on a video stream",
- "Tim-Philipp Müller <tim@centricular.net>");
-}
-
-
-static void gst_clock_overlay_finalize (GObject * object);
-static void gst_clock_overlay_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_clock_overlay_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static gchar *
-gst_clock_overlay_render_time (GstClockOverlay * overlay)
-{
- struct tm *t;
- time_t now;
- gchar buf[256];
-
-#ifdef HAVE_LOCALTIME_R
- struct tm dummy;
-#endif
-
- now = time (NULL);
-
-#ifdef HAVE_LOCALTIME_R
- /* Need to call tzset explicitly when calling localtime_r for changes
- to the timezone between calls to be visible. */
- tzset ();
- t = localtime_r (&now, &dummy);
-#else
- /* on win32 this apparently returns a per-thread struct which would be fine */
- t = localtime (&now);
-#endif
-
- if (t == NULL)
- return g_strdup ("--:--:--");
-
- if (strftime (buf, sizeof (buf), overlay->format, t) == 0)
- return g_strdup ("");
- return g_strdup (buf);
-}
-
-/* Called with lock held */
-static gchar *
-gst_clock_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame)
-{
- gchar *time_str, *txt, *ret;
-
- overlay->need_render = TRUE;
-
- txt = g_strdup (overlay->default_text);
-
- time_str = gst_clock_overlay_render_time (GST_CLOCK_OVERLAY (overlay));
- if (txt != NULL && *txt != '\0') {
- ret = g_strdup_printf ("%s %s", txt, time_str);
- } else {
- ret = time_str;
- time_str = NULL;
- }
-
- g_free (txt);
- g_free (time_str);
-
- return ret;
-}
-
-static void
-gst_clock_overlay_class_init (GstClockOverlayClass * klass)
-{
- GObjectClass *gobject_class;
- GstTextOverlayClass *gsttextoverlay_class;
-
- gobject_class = (GObjectClass *) klass;
- gsttextoverlay_class = (GstTextOverlayClass *) klass;
-
- gobject_class->finalize = gst_clock_overlay_finalize;
- gobject_class->set_property = gst_clock_overlay_set_property;
- gobject_class->get_property = gst_clock_overlay_get_property;
-
- gsttextoverlay_class->get_text = gst_clock_overlay_get_text;
-
- g_object_class_install_property (gobject_class, PROP_TIMEFORMAT,
- g_param_spec_string ("time-format", "Date/Time Format",
- "Format to use for time and date value, as in strftime.",
- DEFAULT_PROP_TIMEFORMAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-
-static void
-gst_clock_overlay_finalize (GObject * object)
-{
- GstClockOverlay *overlay = GST_CLOCK_OVERLAY (object);
-
- g_free (overlay->format);
- overlay->format = NULL;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-
-static void
-gst_clock_overlay_init (GstClockOverlay * overlay, GstClockOverlayClass * klass)
-{
- PangoFontDescription *font_description;
- GstTextOverlay *textoverlay;
- PangoContext *context;
-
- textoverlay = GST_TEXT_OVERLAY (overlay);
-
- context = GST_TEXT_OVERLAY_CLASS (klass)->pango_context;
-
- pango_context_set_language (context, pango_language_from_string ("en_US"));
- pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
-
- font_description = pango_font_description_new ();
- pango_font_description_set_family_static (font_description, "Monospace");
- pango_font_description_set_style (font_description, PANGO_STYLE_NORMAL);
- pango_font_description_set_variant (font_description, PANGO_VARIANT_NORMAL);
- pango_font_description_set_weight (font_description, PANGO_WEIGHT_NORMAL);
- pango_font_description_set_stretch (font_description, PANGO_STRETCH_NORMAL);
- pango_font_description_set_size (font_description, 18 * PANGO_SCALE);
- pango_context_set_font_description (context, font_description);
- pango_font_description_free (font_description);
-
- textoverlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP;
- textoverlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT;
-
- overlay->format = g_strdup (DEFAULT_PROP_TIMEFORMAT);
-}
-
-
-static void
-gst_clock_overlay_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstClockOverlay *overlay = GST_CLOCK_OVERLAY (object);
-
- GST_OBJECT_LOCK (overlay);
- switch (prop_id) {
- case PROP_TIMEFORMAT:
- g_free (overlay->format);
- overlay->format = g_value_dup_string (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
- GST_OBJECT_UNLOCK (overlay);
-}
-
-
-static void
-gst_clock_overlay_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstClockOverlay *overlay = GST_CLOCK_OVERLAY (object);
-
- GST_OBJECT_LOCK (overlay);
- switch (prop_id) {
- case PROP_TIMEFORMAT:
- g_value_set_string (value, overlay->format);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
- GST_OBJECT_UNLOCK (overlay);
-}
diff --git a/ext/pango/gstclockoverlay.h b/ext/pango/gstclockoverlay.h
deleted file mode 100644
index 74e32e36..00000000
--- a/ext/pango/gstclockoverlay.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) <2005> Tim-Philipp Müller <tim@centricular.net>
- *
- * 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_CLOCK_OVERLAY_H__
-#define __GST_CLOCK_OVERLAY_H__
-
-#include "gsttextoverlay.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_CLOCK_OVERLAY \
- (gst_clock_overlay_get_type())
-#define GST_CLOCK_OVERLAY(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLOCK_OVERLAY,GstClockOverlay))
-#define GST_CLOCK_OVERLAY_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLOCK_OVERLAY,GstClockOverlayClass))
-#define GST_IS_CLOCK_OVERLAY(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLOCK_OVERLAY))
-#define GST_IS_CLOCK_OVERLAY_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLOCK_OVERLAY))
-
-typedef struct _GstClockOverlay GstClockOverlay;
-typedef struct _GstClockOverlayClass GstClockOverlayClass;
-
-/**
- * GstClockOverlay:
- *
- * Opaque clockoverlay data structure.
- */
-struct _GstClockOverlay {
- GstTextOverlay textoverlay;
- gchar *format; /* as in strftime () */
-};
-
-struct _GstClockOverlayClass {
- GstTextOverlayClass parent_class;
-};
-
-GType gst_clock_overlay_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_CLOCK_OVERLAY_H__ */
-
diff --git a/ext/pango/gsttextoverlay.c b/ext/pango/gsttextoverlay.c
deleted file mode 100644
index 3e4a0ee7..00000000
--- a/ext/pango/gsttextoverlay.c
+++ /dev/null
@@ -1,2352 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) <2003> David Schleef <ds@schleef.org>
- * Copyright (C) <2006> Julien Moutte <julien@moutte.net>
- * Copyright (C) <2006> Zeeshan Ali <zeeshan.ali@nokia.com>
- * Copyright (C) <2006-2008> Tim-Philipp Müller <tim centricular net>
- * Copyright (C) <2009> Young-Ho Cha <ganadist@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-textoverlay
- * @see_also: #GstTextRender, #GstClockOverlay, #GstTimeOverlay, #GstSubParse
- *
- * This plugin renders text on top of a video stream. This can be either
- * static text or text from buffers received on the text sink pad, e.g.
- * as produced by the subparse element. If the text sink pad is not linked,
- * the text set via the "text" property will be rendered. If the text sink
- * pad is linked, text will be rendered as it is received on that pad,
- * honouring and matching the buffer timestamps of both input streams.
- *
- * The text can contain newline characters and text wrapping is enabled by
- * default.
- *
- * <refsect2>
- * <title>Example launch lines</title>
- * |[
- * gst-launch -v videotestsrc ! textoverlay text="Room A" valign=top halign=left ! xvimagesink
- * ]| Here is a simple pipeline that displays a static text in the top left
- * corner of the video picture
- * |[
- * gst-launch -v filesrc location=subtitles.srt ! subparse ! txt. videotestsrc ! timeoverlay ! textoverlay name=txt shaded-background=yes ! xvimagesink
- * ]| Here is another pipeline that displays subtitles from an .srt subtitle
- * file, centered at the bottom of the picture and with a rectangular shading
- * around the text in the background:
- * <para>
- * If you do not have such a subtitle file, create one looking like this
- * in a text editor:
- * |[
- * 1
- * 00:00:03,000 --> 00:00:05,000
- * Hello? (3-5s)
- *
- * 2
- * 00:00:08,000 --> 00:00:13,000
- * Yes, this is a subtitle. Don&apos;t
- * you like it? (8-13s)
- *
- * 3
- * 00:00:18,826 --> 00:01:02,886
- * Uh? What are you talking about?
- * I don&apos;t understand (18-62s)
- * ]|
- * </para>
- * </refsect2>
- */
-
-/* FIXME: alloc segment as part of instance struct */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gst/video/video.h>
-
-#include "gsttextoverlay.h"
-#include "gsttimeoverlay.h"
-#include "gstclockoverlay.h"
-#include "gsttextrender.h"
-#include <string.h>
-
-/* FIXME:
- * - use proper strides and offset for I420
- * - if text is wider than the video picture, it does not get
- * clipped properly during blitting (if wrapping is disabled)
- * - make 'shading_value' a property (or enum: light/normal/dark/verydark)?
- */
-
-GST_DEBUG_CATEGORY (pango_debug);
-#define GST_CAT_DEFAULT pango_debug
-
-#define DEFAULT_PROP_TEXT ""
-#define DEFAULT_PROP_SHADING FALSE
-#define DEFAULT_PROP_VALIGNMENT GST_TEXT_OVERLAY_VALIGN_BASELINE
-#define DEFAULT_PROP_HALIGNMENT GST_TEXT_OVERLAY_HALIGN_CENTER
-#define DEFAULT_PROP_VALIGN "baseline"
-#define DEFAULT_PROP_HALIGN "center"
-#define DEFAULT_PROP_XPAD 25
-#define DEFAULT_PROP_YPAD 25
-#define DEFAULT_PROP_DELTAX 0
-#define DEFAULT_PROP_DELTAY 0
-#define DEFAULT_PROP_WRAP_MODE GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR
-#define DEFAULT_PROP_FONT_DESC ""
-#define DEFAULT_PROP_SILENT FALSE
-#define DEFAULT_PROP_LINE_ALIGNMENT GST_TEXT_OVERLAY_LINE_ALIGN_CENTER
-#define DEFAULT_PROP_WAIT_TEXT TRUE
-#define DEFAULT_PROP_AUTO_ADJUST_SIZE TRUE
-#define DEFAULT_PROP_VERTICAL_RENDER FALSE
-
-/* make a property of me */
-#define DEFAULT_SHADING_VALUE -80
-
-#define MINIMUM_OUTLINE_OFFSET 1.0
-#define DEFAULT_SCALE_BASIS 640
-
-#define COMP_Y(ret, r, g, b) \
-{ \
- ret = (int) (((19595 * r) >> 16) + ((38470 * g) >> 16) + ((7471 * b) >> 16)); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define COMP_U(ret, r, g, b) \
-{ \
- ret = (int) (-((11059 * r) >> 16) - ((21709 * g) >> 16) + ((32768 * b) >> 16) + 128); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define COMP_V(ret, r, g, b) \
-{ \
- ret = (int) (((32768 * r) >> 16) - ((27439 * g) >> 16) - ((5329 * b) >> 16) + 128); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define BLEND(ret, alpha, v0, v1) \
-{ \
- ret = (v0 * alpha + v1 * (255 - alpha)) / 255; \
-}
-
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-# define CAIRO_ARGB_A 3
-# define CAIRO_ARGB_R 2
-# define CAIRO_ARGB_G 1
-# define CAIRO_ARGB_B 0
-#else
-# define CAIRO_ARGB_A 0
-# define CAIRO_ARGB_R 1
-# define CAIRO_ARGB_G 2
-# define CAIRO_ARGB_B 3
-#endif
-
-enum
-{
- PROP_0,
- PROP_TEXT,
- PROP_SHADING,
- PROP_VALIGN, /* deprecated */
- PROP_HALIGN, /* deprecated */
- PROP_HALIGNMENT,
- PROP_VALIGNMENT,
- PROP_XPAD,
- PROP_YPAD,
- PROP_DELTAX,
- PROP_DELTAY,
- PROP_WRAP_MODE,
- PROP_FONT_DESC,
- PROP_SILENT,
- PROP_LINE_ALIGNMENT,
- PROP_WAIT_TEXT,
- PROP_AUTO_ADJUST_SIZE,
- PROP_VERTICAL_RENDER,
- PROP_LAST
-};
-
-static GstStaticPadTemplate src_template_factory =
- GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";"
- GST_VIDEO_CAPS_xRGB ";"
- GST_VIDEO_CAPS_YUV ("I420") ";" GST_VIDEO_CAPS_YUV ("UYVY"))
- );
-
-static GstStaticPadTemplate video_sink_template_factory =
- GST_STATIC_PAD_TEMPLATE ("video_sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";"
- GST_VIDEO_CAPS_xRGB ";"
- GST_VIDEO_CAPS_YUV ("I420") ";" GST_VIDEO_CAPS_YUV ("UYVY"))
- );
-
-static GstStaticPadTemplate text_sink_template_factory =
- GST_STATIC_PAD_TEMPLATE ("text_sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("text/x-pango-markup; text/plain")
- );
-
-#define GST_TYPE_TEXT_OVERLAY_VALIGN (gst_text_overlay_valign_get_type())
-static GType
-gst_text_overlay_valign_get_type (void)
-{
- static GType text_overlay_valign_type = 0;
- static const GEnumValue text_overlay_valign[] = {
- {GST_TEXT_OVERLAY_VALIGN_BASELINE, "baseline", "baseline"},
- {GST_TEXT_OVERLAY_VALIGN_BOTTOM, "bottom", "bottom"},
- {GST_TEXT_OVERLAY_VALIGN_TOP, "top", "top"},
- {0, NULL, NULL},
- };
-
- if (!text_overlay_valign_type) {
- text_overlay_valign_type =
- g_enum_register_static ("GstTextOverlayVAlign", text_overlay_valign);
- }
- return text_overlay_valign_type;
-}
-
-#define GST_TYPE_TEXT_OVERLAY_HALIGN (gst_text_overlay_halign_get_type())
-static GType
-gst_text_overlay_halign_get_type (void)
-{
- static GType text_overlay_halign_type = 0;
- static const GEnumValue text_overlay_halign[] = {
- {GST_TEXT_OVERLAY_HALIGN_LEFT, "left", "left"},
- {GST_TEXT_OVERLAY_HALIGN_CENTER, "center", "center"},
- {GST_TEXT_OVERLAY_HALIGN_RIGHT, "right", "right"},
- {0, NULL, NULL},
- };
-
- if (!text_overlay_halign_type) {
- text_overlay_halign_type =
- g_enum_register_static ("GstTextOverlayHAlign", text_overlay_halign);
- }
- return text_overlay_halign_type;
-}
-
-
-#define GST_TYPE_TEXT_OVERLAY_WRAP_MODE (gst_text_overlay_wrap_mode_get_type())
-static GType
-gst_text_overlay_wrap_mode_get_type (void)
-{
- static GType text_overlay_wrap_mode_type = 0;
- static const GEnumValue text_overlay_wrap_mode[] = {
- {GST_TEXT_OVERLAY_WRAP_MODE_NONE, "none", "none"},
- {GST_TEXT_OVERLAY_WRAP_MODE_WORD, "word", "word"},
- {GST_TEXT_OVERLAY_WRAP_MODE_CHAR, "char", "char"},
- {GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR, "wordchar", "wordchar"},
- {0, NULL, NULL},
- };
-
- if (!text_overlay_wrap_mode_type) {
- text_overlay_wrap_mode_type =
- g_enum_register_static ("GstTextOverlayWrapMode",
- text_overlay_wrap_mode);
- }
- return text_overlay_wrap_mode_type;
-}
-
-#define GST_TYPE_TEXT_OVERLAY_LINE_ALIGN (gst_text_overlay_line_align_get_type())
-static GType
-gst_text_overlay_line_align_get_type (void)
-{
- static GType text_overlay_line_align_type = 0;
- static const GEnumValue text_overlay_line_align[] = {
- {GST_TEXT_OVERLAY_LINE_ALIGN_LEFT, "left", "left"},
- {GST_TEXT_OVERLAY_LINE_ALIGN_CENTER, "center", "center"},
- {GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT, "right", "right"},
- {0, NULL, NULL}
- };
-
- if (!text_overlay_line_align_type) {
- text_overlay_line_align_type =
- g_enum_register_static ("GstTextOverlayLineAlign",
- text_overlay_line_align);
- }
- return text_overlay_line_align_type;
-}
-
-#define GST_TEXT_OVERLAY_GET_COND(ov) (((GstTextOverlay *)ov)->cond)
-#define GST_TEXT_OVERLAY_WAIT(ov) (g_cond_wait (GST_TEXT_OVERLAY_GET_COND (ov), GST_OBJECT_GET_LOCK (ov)))
-#define GST_TEXT_OVERLAY_SIGNAL(ov) (g_cond_signal (GST_TEXT_OVERLAY_GET_COND (ov)))
-#define GST_TEXT_OVERLAY_BROADCAST(ov)(g_cond_broadcast (GST_TEXT_OVERLAY_GET_COND (ov)))
-
-static GstStateChangeReturn gst_text_overlay_change_state (GstElement * element,
- GstStateChange transition);
-
-static GstCaps *gst_text_overlay_getcaps (GstPad * pad);
-static gboolean gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_text_overlay_setcaps_txt (GstPad * pad, GstCaps * caps);
-static gboolean gst_text_overlay_src_event (GstPad * pad, GstEvent * event);
-static gboolean gst_text_overlay_src_query (GstPad * pad, GstQuery * query);
-
-static gboolean gst_text_overlay_video_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_text_overlay_video_chain (GstPad * pad,
- GstBuffer * buffer);
-static GstFlowReturn gst_text_overlay_video_bufferalloc (GstPad * pad,
- guint64 offset, guint size, GstCaps * caps, GstBuffer ** buffer);
-
-static gboolean gst_text_overlay_text_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_text_overlay_text_chain (GstPad * pad,
- GstBuffer * buffer);
-static GstPadLinkReturn gst_text_overlay_text_pad_link (GstPad * pad,
- GstPad * peer);
-static void gst_text_overlay_text_pad_unlink (GstPad * pad);
-static void gst_text_overlay_pop_text (GstTextOverlay * overlay);
-static void gst_text_overlay_update_render_mode (GstTextOverlay * overlay);
-
-static void gst_text_overlay_finalize (GObject * object);
-static void gst_text_overlay_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_text_overlay_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void gst_text_overlay_adjust_values_with_fontdesc (GstTextOverlay *
- overlay, PangoFontDescription * desc);
-
-GST_BOILERPLATE (GstTextOverlay, gst_text_overlay, GstElement,
- GST_TYPE_ELEMENT);
-
-static void
-gst_text_overlay_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_template_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&video_sink_template_factory));
-
- /* ugh */
- if (!GST_IS_TIME_OVERLAY_CLASS (g_class) &&
- !GST_IS_CLOCK_OVERLAY_CLASS (g_class)) {
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&text_sink_template_factory));
- }
-
- gst_element_class_set_details_simple (element_class, "Text overlay",
- "Filter/Editor/Video",
- "Adds text strings on top of a video buffer",
- "David Schleef <ds@schleef.org>, " "Zeeshan Ali <zeeshan.ali@nokia.com>");
-}
-
-static gchar *
-gst_text_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame)
-{
- return g_strdup (overlay->default_text);
-}
-
-static void
-gst_text_overlay_class_init (GstTextOverlayClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
- PangoFontMap *fontmap;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- gobject_class->finalize = gst_text_overlay_finalize;
- gobject_class->set_property = gst_text_overlay_set_property;
- gobject_class->get_property = gst_text_overlay_get_property;
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_text_overlay_change_state);
-
- klass->get_text = gst_text_overlay_get_text;
- fontmap = pango_cairo_font_map_get_default ();
- klass->pango_context =
- pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TEXT,
- g_param_spec_string ("text", "text",
- "Text to be display.", DEFAULT_PROP_TEXT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SHADING,
- g_param_spec_boolean ("shaded-background", "shaded background",
- "Whether to shade the background under the text area",
- DEFAULT_PROP_SHADING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGNMENT,
- g_param_spec_enum ("valignment", "vertical alignment",
- "Vertical alignment of the text", GST_TYPE_TEXT_OVERLAY_VALIGN,
- DEFAULT_PROP_VALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGNMENT,
- g_param_spec_enum ("halignment", "horizontal alignment",
- "Horizontal alignment of the text", GST_TYPE_TEXT_OVERLAY_HALIGN,
- DEFAULT_PROP_HALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGN,
- g_param_spec_string ("valign", "vertical alignment",
- "Vertical alignment of the text (deprecated; use valignment)",
- DEFAULT_PROP_VALIGN, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGN,
- g_param_spec_string ("halign", "horizontal alignment",
- "Horizontal alignment of the text (deprecated; use halignment)",
- DEFAULT_PROP_HALIGN, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPAD,
- g_param_spec_int ("xpad", "horizontal paddding",
- "Horizontal paddding when using left/right alignment", 0, G_MAXINT,
- DEFAULT_PROP_XPAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_YPAD,
- g_param_spec_int ("ypad", "vertical padding",
- "Vertical padding when using top/bottom alignment", 0, G_MAXINT,
- DEFAULT_PROP_YPAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELTAX,
- g_param_spec_int ("deltax", "X position modifier",
- "Shift X position to the left or to the right. Unit is pixels.",
- G_MININT, G_MAXINT, DEFAULT_PROP_DELTAX,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELTAY,
- g_param_spec_int ("deltay", "Y position modifier",
- "Shift Y position up or down. Unit is pixels.", G_MININT, G_MAXINT,
- DEFAULT_PROP_DELTAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WRAP_MODE,
- g_param_spec_enum ("wrap-mode", "wrap mode",
- "Whether to wrap the text and if so how.",
- GST_TYPE_TEXT_OVERLAY_WRAP_MODE, DEFAULT_PROP_WRAP_MODE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FONT_DESC,
- g_param_spec_string ("font-desc", "font description",
- "Pango font description of font to be used for rendering. "
- "See documentation of pango_font_description_from_string "
- "for syntax.", DEFAULT_PROP_FONT_DESC,
- G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:line-alignment
- *
- * Alignment of text lines relative to each other (for multi-line text)
- *
- * Since: 0.10.15
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LINE_ALIGNMENT,
- g_param_spec_enum ("line-alignment", "line alignment",
- "Alignment of text lines relative to each other.",
- GST_TYPE_TEXT_OVERLAY_LINE_ALIGN, DEFAULT_PROP_LINE_ALIGNMENT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:silent
- *
- * If set, no text is rendered. Useful to switch off text rendering
- * temporarily without removing the textoverlay element from the pipeline.
- *
- * Since: 0.10.15
- **/
- /* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
- g_param_spec_boolean ("silent", "silent",
- "Whether to render the text string",
- DEFAULT_PROP_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:wait-text
- *
- * If set, the video will block until a subtitle is received on the text pad.
- * If video and subtitles are sent in sync, like from the same demuxer, this
- * property should be set.
- *
- * Since: 0.10.20
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WAIT_TEXT,
- g_param_spec_boolean ("wait-text", "Wait Text",
- "Whether to wait for subtitles",
- DEFAULT_PROP_WAIT_TEXT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass),
- PROP_AUTO_ADJUST_SIZE, g_param_spec_boolean ("auto-resize", "auto resize",
- "Automatically adjust font size to screen-size.",
- DEFAULT_PROP_AUTO_ADJUST_SIZE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VERTICAL_RENDER,
- g_param_spec_boolean ("vertical-render", "vertical render",
- "Vertical Render.", DEFAULT_PROP_VERTICAL_RENDER,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_text_overlay_finalize (GObject * object)
-{
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (object);
-
- g_free (overlay->default_text);
-
- if (overlay->text_image) {
- g_free (overlay->text_image);
- overlay->text_image = NULL;
- }
-
- if (overlay->layout) {
- g_object_unref (overlay->layout);
- overlay->layout = NULL;
- }
-
- if (overlay->text_buffer) {
- gst_buffer_unref (overlay->text_buffer);
- overlay->text_buffer = NULL;
- }
-
- if (overlay->cond) {
- g_cond_free (overlay->cond);
- overlay->cond = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_text_overlay_init (GstTextOverlay * overlay, GstTextOverlayClass * klass)
-{
- GstPadTemplate *template;
- PangoFontDescription *desc;
-
- /* video sink */
- template = gst_static_pad_template_get (&video_sink_template_factory);
- overlay->video_sinkpad = gst_pad_new_from_template (template, "video_sink");
- gst_object_unref (template);
- gst_pad_set_getcaps_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps));
- gst_pad_set_setcaps_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_setcaps));
- gst_pad_set_event_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_video_event));
- gst_pad_set_chain_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_video_chain));
- gst_pad_set_bufferalloc_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_video_bufferalloc));
- gst_element_add_pad (GST_ELEMENT (overlay), overlay->video_sinkpad);
-
- if (!GST_IS_TIME_OVERLAY_CLASS (klass) && !GST_IS_CLOCK_OVERLAY_CLASS (klass)) {
- /* text sink */
- template = gst_static_pad_template_get (&text_sink_template_factory);
- overlay->text_sinkpad = gst_pad_new_from_template (template, "text_sink");
- gst_object_unref (template);
- gst_pad_set_setcaps_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_setcaps_txt));
- gst_pad_set_event_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_text_event));
- gst_pad_set_chain_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_text_chain));
- gst_pad_set_link_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_link));
- gst_pad_set_unlink_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_unlink));
- gst_element_add_pad (GST_ELEMENT (overlay), overlay->text_sinkpad);
- }
-
- /* (video) source */
- template = gst_static_pad_template_get (&src_template_factory);
- overlay->srcpad = gst_pad_new_from_template (template, "src");
- gst_object_unref (template);
- gst_pad_set_getcaps_function (overlay->srcpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps));
- gst_pad_set_event_function (overlay->srcpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_src_event));
- gst_pad_set_query_function (overlay->srcpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_src_query));
- gst_element_add_pad (GST_ELEMENT (overlay), overlay->srcpad);
-
- overlay->line_align = DEFAULT_PROP_LINE_ALIGNMENT;
- overlay->layout =
- pango_layout_new (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_context);
- desc =
- pango_context_get_font_description (GST_TEXT_OVERLAY_GET_CLASS
- (overlay)->pango_context);
- gst_text_overlay_adjust_values_with_fontdesc (overlay, desc);
-
- overlay->halign = DEFAULT_PROP_HALIGNMENT;
- overlay->valign = DEFAULT_PROP_VALIGNMENT;
- overlay->xpad = DEFAULT_PROP_XPAD;
- overlay->ypad = DEFAULT_PROP_YPAD;
- overlay->deltax = DEFAULT_PROP_DELTAX;
- overlay->deltay = DEFAULT_PROP_DELTAY;
-
- overlay->wrap_mode = DEFAULT_PROP_WRAP_MODE;
-
- overlay->want_shading = DEFAULT_PROP_SHADING;
- overlay->shading_value = DEFAULT_SHADING_VALUE;
- overlay->silent = DEFAULT_PROP_SILENT;
- overlay->wait_text = DEFAULT_PROP_WAIT_TEXT;
- overlay->auto_adjust_size = DEFAULT_PROP_AUTO_ADJUST_SIZE;
-
- overlay->default_text = g_strdup (DEFAULT_PROP_TEXT);
- overlay->need_render = TRUE;
- overlay->text_image = NULL;
- overlay->use_vertical_render = DEFAULT_PROP_VERTICAL_RENDER;
- gst_text_overlay_update_render_mode (overlay);
-
- overlay->fps_n = 0;
- overlay->fps_d = 1;
-
- overlay->text_buffer = NULL;
- overlay->text_linked = FALSE;
- overlay->cond = g_cond_new ();
- gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
-}
-
-static void
-gst_text_overlay_update_wrap_mode (GstTextOverlay * overlay)
-{
- if (overlay->wrap_mode == GST_TEXT_OVERLAY_WRAP_MODE_NONE) {
- GST_DEBUG_OBJECT (overlay, "Set wrap mode NONE");
- pango_layout_set_width (overlay->layout, -1);
- } else {
- int width;
-
- if (overlay->auto_adjust_size) {
- width = DEFAULT_SCALE_BASIS * PANGO_SCALE;
- if (overlay->use_vertical_render) {
- width = width * (overlay->height - overlay->ypad * 2) / overlay->width;
- }
- } else {
- width =
- (overlay->use_vertical_render ? overlay->height : overlay->width) *
- PANGO_SCALE;
- }
-
- GST_DEBUG_OBJECT (overlay, "Set layout width %d", overlay->width);
- GST_DEBUG_OBJECT (overlay, "Set wrap mode %d", overlay->wrap_mode);
- pango_layout_set_width (overlay->layout, width);
- pango_layout_set_wrap (overlay->layout, (PangoWrapMode) overlay->wrap_mode);
- }
-}
-
-static void
-gst_text_overlay_update_render_mode (GstTextOverlay * overlay)
-{
- PangoMatrix matrix = PANGO_MATRIX_INIT;
- PangoContext *context = pango_layout_get_context (overlay->layout);
-
- if (overlay->use_vertical_render) {
- pango_matrix_rotate (&matrix, -90);
- pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO);
- pango_context_set_matrix (context, &matrix);
- pango_layout_set_alignment (overlay->layout, PANGO_ALIGN_LEFT);
- } else {
- pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH);
- pango_context_set_matrix (context, &matrix);
- pango_layout_set_alignment (overlay->layout, overlay->line_align);
- }
-}
-
-static gboolean
-gst_text_overlay_setcaps_txt (GstPad * pad, GstCaps * caps)
-{
- GstTextOverlay *overlay;
- GstStructure *structure;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- structure = gst_caps_get_structure (caps, 0);
- overlay->have_pango_markup =
- gst_structure_has_name (structure, "text/x-pango-markup");
-
- gst_object_unref (overlay);
-
- return TRUE;
-}
-
-/* FIXME: upstream nego (e.g. when the video window is resized) */
-
-static gboolean
-gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstTextOverlay *overlay;
- GstStructure *structure;
- gboolean ret = FALSE;
- const GValue *fps;
-
- if (!GST_PAD_IS_SINK (pad))
- return TRUE;
-
- g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- overlay->width = 0;
- overlay->height = 0;
- structure = gst_caps_get_structure (caps, 0);
- fps = gst_structure_get_value (structure, "framerate");
-
- if (fps
- && gst_video_format_parse_caps (caps, &overlay->format, &overlay->width,
- &overlay->height)) {
- ret = gst_pad_set_caps (overlay->srcpad, caps);
- }
-
- overlay->fps_n = gst_value_get_fraction_numerator (fps);
- overlay->fps_d = gst_value_get_fraction_denominator (fps);
-
- if (ret) {
- GST_OBJECT_LOCK (overlay);
- gst_text_overlay_update_wrap_mode (overlay);
- GST_OBJECT_UNLOCK (overlay);
- }
-
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static void
-gst_text_overlay_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (object);
-
- GST_OBJECT_LOCK (overlay);
- switch (prop_id) {
- case PROP_TEXT:
- g_free (overlay->default_text);
- overlay->default_text = g_value_dup_string (value);
- overlay->need_render = TRUE;
- break;
- case PROP_SHADING:
- overlay->want_shading = g_value_get_boolean (value);
- break;
- case PROP_XPAD:
- overlay->xpad = g_value_get_int (value);
- break;
- case PROP_YPAD:
- overlay->ypad = g_value_get_int (value);
- break;
- case PROP_DELTAX:
- overlay->deltax = g_value_get_int (value);
- break;
- case PROP_DELTAY:
- overlay->deltay = g_value_get_int (value);
- break;
- case PROP_HALIGN:{
- const gchar *s = g_value_get_string (value);
-
- if (s && g_ascii_strcasecmp (s, "left") == 0)
- overlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT;
- else if (s && g_ascii_strcasecmp (s, "center") == 0)
- overlay->halign = GST_TEXT_OVERLAY_HALIGN_CENTER;
- else if (s && g_ascii_strcasecmp (s, "right") == 0)
- overlay->halign = GST_TEXT_OVERLAY_HALIGN_RIGHT;
- else
- g_warning ("Invalid value '%s' for textoverlay property 'halign'",
- GST_STR_NULL (s));
- break;
- }
- case PROP_VALIGN:{
- const gchar *s = g_value_get_string (value);
-
- if (s && g_ascii_strcasecmp (s, "baseline") == 0)
- overlay->valign = GST_TEXT_OVERLAY_VALIGN_BASELINE;
- else if (s && g_ascii_strcasecmp (s, "bottom") == 0)
- overlay->valign = GST_TEXT_OVERLAY_VALIGN_BOTTOM;
- else if (s && g_ascii_strcasecmp (s, "top") == 0)
- overlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP;
- else
- g_warning ("Invalid value '%s' for textoverlay property 'valign'",
- GST_STR_NULL (s));
- break;
- }
- case PROP_VALIGNMENT:
- overlay->valign = g_value_get_enum (value);
- break;
- case PROP_HALIGNMENT:
- overlay->halign = g_value_get_enum (value);
- break;
- case PROP_WRAP_MODE:
- overlay->wrap_mode = g_value_get_enum (value);
- gst_text_overlay_update_wrap_mode (overlay);
- break;
- case PROP_FONT_DESC:
- {
- PangoFontDescription *desc;
- const gchar *fontdesc_str;
-
- fontdesc_str = g_value_get_string (value);
- desc = pango_font_description_from_string (fontdesc_str);
- if (desc) {
- GST_LOG_OBJECT (overlay, "font description set: %s", fontdesc_str);
- pango_layout_set_font_description (overlay->layout, desc);
- gst_text_overlay_adjust_values_with_fontdesc (overlay, desc);
- pango_font_description_free (desc);
- } else {
- GST_WARNING_OBJECT (overlay, "font description parse failed: %s",
- fontdesc_str);
- }
- break;
- }
- case PROP_SILENT:
- overlay->silent = g_value_get_boolean (value);
- break;
- case PROP_LINE_ALIGNMENT:
- overlay->line_align = g_value_get_enum (value);
- pango_layout_set_alignment (overlay->layout,
- (PangoAlignment) overlay->line_align);
- break;
- case PROP_WAIT_TEXT:
- overlay->wait_text = g_value_get_boolean (value);
- break;
- case PROP_AUTO_ADJUST_SIZE:
- {
- overlay->auto_adjust_size = g_value_get_boolean (value);
- overlay->need_render = TRUE;
- }
- case PROP_VERTICAL_RENDER:
- overlay->use_vertical_render = g_value_get_boolean (value);
- gst_text_overlay_update_render_mode (overlay);
- overlay->need_render = TRUE;
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- overlay->need_render = TRUE;
- GST_OBJECT_UNLOCK (overlay);
-}
-
-static void
-gst_text_overlay_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (object);
-
- GST_OBJECT_LOCK (overlay);
- switch (prop_id) {
- case PROP_TEXT:
- g_value_set_string (value, overlay->default_text);
- break;
- case PROP_SHADING:
- g_value_set_boolean (value, overlay->want_shading);
- break;
- case PROP_XPAD:
- g_value_set_int (value, overlay->xpad);
- break;
- case PROP_YPAD:
- g_value_set_int (value, overlay->ypad);
- break;
- case PROP_DELTAX:
- g_value_set_int (value, overlay->deltax);
- break;
- case PROP_DELTAY:
- g_value_set_int (value, overlay->deltay);
- break;
- case PROP_VALIGNMENT:
- g_value_set_enum (value, overlay->valign);
- break;
- case PROP_HALIGNMENT:
- g_value_set_enum (value, overlay->halign);
- break;
- case PROP_WRAP_MODE:
- g_value_set_enum (value, overlay->wrap_mode);
- break;
- case PROP_SILENT:
- g_value_set_boolean (value, overlay->silent);
- break;
- case PROP_LINE_ALIGNMENT:
- g_value_set_enum (value, overlay->line_align);
- break;
- case PROP_WAIT_TEXT:
- g_value_set_boolean (value, overlay->wait_text);
- break;
- case PROP_AUTO_ADJUST_SIZE:
- g_value_set_boolean (value, overlay->auto_adjust_size);
- break;
- case PROP_VERTICAL_RENDER:
- g_value_set_boolean (value, overlay->use_vertical_render);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- overlay->need_render = TRUE;
- GST_OBJECT_UNLOCK (overlay);
-}
-
-static gboolean
-gst_text_overlay_src_query (GstPad * pad, GstQuery * query)
-{
- gboolean ret = FALSE;
- GstTextOverlay *overlay = NULL;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- ret = gst_pad_peer_query (overlay->video_sinkpad, query);
-
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static gboolean
-gst_text_overlay_src_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret = FALSE;
- GstTextOverlay *overlay = NULL;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:{
- GstSeekFlags flags;
-
- /* We don't handle seek if we have not text pad */
- if (!overlay->text_linked) {
- GST_DEBUG_OBJECT (overlay, "seek received, pushing upstream");
- ret = gst_pad_push_event (overlay->video_sinkpad, event);
- goto beach;
- }
-
- GST_DEBUG_OBJECT (overlay, "seek received, driving from here");
-
- gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
-
- /* Flush downstream, only for flushing seek */
- if (flags & GST_SEEK_FLAG_FLUSH)
- gst_pad_push_event (overlay->srcpad, gst_event_new_flush_start ());
-
- /* Mark ourself as flushing, unblock chains */
- GST_OBJECT_LOCK (overlay);
- overlay->video_flushing = TRUE;
- overlay->text_flushing = TRUE;
- gst_text_overlay_pop_text (overlay);
- GST_OBJECT_UNLOCK (overlay);
-
- /* Seek on each sink pad */
- gst_event_ref (event);
- ret = gst_pad_push_event (overlay->video_sinkpad, event);
- if (ret) {
- ret = gst_pad_push_event (overlay->text_sinkpad, event);
- } else {
- gst_event_unref (event);
- }
- break;
- }
- default:
- if (overlay->text_linked) {
- gst_event_ref (event);
- ret = gst_pad_push_event (overlay->video_sinkpad, event);
- gst_pad_push_event (overlay->text_sinkpad, event);
- } else {
- ret = gst_pad_push_event (overlay->video_sinkpad, event);
- }
- break;
- }
-
-beach:
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static GstCaps *
-gst_text_overlay_getcaps (GstPad * pad)
-{
- GstTextOverlay *overlay;
- GstPad *otherpad;
- GstCaps *caps;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- if (pad == overlay->srcpad)
- otherpad = overlay->video_sinkpad;
- else
- otherpad = overlay->srcpad;
-
- /* we can do what the peer can */
- caps = gst_pad_peer_get_caps (otherpad);
- if (caps) {
- GstCaps *temp;
- const GstCaps *templ;
-
- GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
-
- /* filtered against our padtemplate */
- templ = gst_pad_get_pad_template_caps (otherpad);
- GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
- temp = gst_caps_intersect (caps, templ);
- GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
- gst_caps_unref (caps);
- /* this is what we can do */
- caps = temp;
- } else {
- /* no peer, our padtemplate is enough then */
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
- }
-
- GST_DEBUG_OBJECT (overlay, "returning %" GST_PTR_FORMAT, caps);
-
- gst_object_unref (overlay);
-
- return caps;
-}
-
-static void
-gst_text_overlay_adjust_values_with_fontdesc (GstTextOverlay * overlay,
- PangoFontDescription * desc)
-{
- gint font_size = pango_font_description_get_size (desc) / PANGO_SCALE;
- overlay->shadow_offset = (double) (font_size) / 13.0;
- overlay->outline_offset = (double) (font_size) / 15.0;
- if (overlay->outline_offset < MINIMUM_OUTLINE_OFFSET)
- overlay->outline_offset = MINIMUM_OUTLINE_OFFSET;
-}
-
-#define CAIRO_UNPREMULTIPLY(a,r,g,b) G_STMT_START { \
- b = (a > 0) ? MIN ((b * 255 + a / 2) / a, 255) : 0; \
- g = (a > 0) ? MIN ((g * 255 + a / 2) / a, 255) : 0; \
- r = (a > 0) ? MIN ((r * 255 + a / 2) / a, 255) : 0; \
-} G_STMT_END
-
-static inline void
-gst_text_overlay_blit_1 (GstTextOverlay * overlay, guchar * dest, gint xpos,
- gint ypos, guchar * text_image, guint dest_stride)
-{
- gint i, j = 0;
- gint x, y;
- guchar r, g, b, a;
- guchar *pimage;
- guchar *py;
- gint width = overlay->image_width;
- gint height = overlay->image_height;
-
- if (xpos < 0) {
- xpos = 0;
- }
-
- if (xpos + width > overlay->width) {
- width = overlay->width - xpos;
- }
-
- if (ypos + height > overlay->height) {
- height = overlay->height - ypos;
- }
-
- dest += (ypos / 1) * dest_stride;
-
- for (i = 0; i < height; i++) {
- pimage = text_image + 4 * (i * overlay->image_width);
- py = dest + i * dest_stride + xpos;
- for (j = 0; j < width; j++) {
- b = pimage[CAIRO_ARGB_B];
- g = pimage[CAIRO_ARGB_G];
- r = pimage[CAIRO_ARGB_R];
- a = pimage[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a, r, g, b);
-
- pimage += 4;
- if (a == 0) {
- py++;
- continue;
- }
- COMP_Y (y, r, g, b);
- x = *py;
- BLEND (*py++, a, y, x);
- }
- }
-}
-
-static inline void
-gst_text_overlay_blit_sub2x2cbcr (GstTextOverlay * overlay,
- guchar * destcb, guchar * destcr, gint xpos, gint ypos, guchar * text_image,
- guint destcb_stride, guint destcr_stride)
-{
- gint i, j;
- gint x, cb, cr;
- gushort r, g, b, a;
- gushort r1, g1, b1, a1;
- guchar *pimage1, *pimage2;
- guchar *pcb, *pcr;
- gint width = overlay->image_width - 2;
- gint height = overlay->image_height - 2;
-
- if (xpos < 0) {
- xpos = 0;
- }
-
- if (xpos + width > overlay->width) {
- width = overlay->width - xpos;
- }
-
- if (ypos + height > overlay->height) {
- height = overlay->height - ypos;
- }
-
- destcb += (ypos / 2) * destcb_stride;
- destcr += (ypos / 2) * destcr_stride;
-
- for (i = 0; i < height; i += 2) {
- pimage1 = text_image + 4 * (i * overlay->image_width);
- pimage2 = pimage1 + 4 * overlay->image_width;
- pcb = destcb + (i / 2) * destcb_stride + xpos / 2;
- pcr = destcr + (i / 2) * destcr_stride + xpos / 2;
- for (j = 0; j < width; j += 2) {
- b = pimage1[CAIRO_ARGB_B];
- g = pimage1[CAIRO_ARGB_G];
- r = pimage1[CAIRO_ARGB_R];
- a = pimage1[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a, r, g, b);
- pimage1 += 4;
-
- b1 = pimage1[CAIRO_ARGB_B];
- g1 = pimage1[CAIRO_ARGB_G];
- r1 = pimage1[CAIRO_ARGB_R];
- a1 = pimage1[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
- b += b1;
- g += g1;
- r += r1;
- a += a1;
- pimage1 += 4;
-
- b1 = pimage2[CAIRO_ARGB_B];
- g1 = pimage2[CAIRO_ARGB_G];
- r1 = pimage2[CAIRO_ARGB_R];
- a1 = pimage2[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
- b += b1;
- g += g1;
- r += r1;
- a += a1;
- pimage2 += 4;
-
- /* + 2 for rounding */
- b1 = pimage2[CAIRO_ARGB_B];
- g1 = pimage2[CAIRO_ARGB_G];
- r1 = pimage2[CAIRO_ARGB_R];
- a1 = pimage2[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
- b += b1 + 2;
- g += g1 + 2;
- r += r1 + 2;
- a += a1 + 2;
- pimage2 += 4;
-
- b /= 4;
- g /= 4;
- r /= 4;
- a /= 4;
-
- if (a == 0) {
- pcb++;
- pcr++;
- continue;
- }
- COMP_U (cb, r, g, b);
- COMP_V (cr, r, g, b);
-
- x = *pcb;
- BLEND (*pcb++, a, cb, x);
- x = *pcr;
- BLEND (*pcr++, a, cr, x);
- }
- }
-}
-
-static void
-gst_text_overlay_render_pangocairo (GstTextOverlay * overlay,
- const gchar * string, gint textlen)
-{
- cairo_t *cr;
- cairo_surface_t *surface;
- PangoRectangle ink_rect, logical_rect;
- cairo_matrix_t cairo_matrix;
- int width, height;
- double scalef = 1.0;
-
- if (overlay->auto_adjust_size) {
- /* 640 pixel is default */
- scalef = (double) (overlay->width) / DEFAULT_SCALE_BASIS;
- }
- pango_layout_set_width (overlay->layout, -1);
- /* set text on pango layout */
- pango_layout_set_markup (overlay->layout, string, textlen);
-
- /* get subtitle image size */
- pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
-
- width = (logical_rect.width + overlay->shadow_offset) * scalef;
-
- if (width + overlay->deltax >
- (overlay->use_vertical_render ? overlay->height : overlay->width)) {
- /*
- * subtitle image width is larger then overlay width
- * so rearrange overlay wrap mode.
- */
- gst_text_overlay_update_wrap_mode (overlay);
- pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
- width = overlay->width;
- }
-
- height =
- (logical_rect.height + logical_rect.y + overlay->shadow_offset) * scalef;
- if (height > overlay->height) {
- height = overlay->height;
- }
- if (overlay->use_vertical_render) {
- PangoRectangle rect;
- PangoContext *context;
- PangoMatrix matrix = PANGO_MATRIX_INIT;
- int tmp;
-
- context = pango_layout_get_context (overlay->layout);
-
- pango_matrix_rotate (&matrix, -90);
-
- rect.x = rect.y = 0;
- rect.width = width;
- rect.height = height;
- pango_matrix_transform_pixel_rectangle (&matrix, &rect);
- matrix.x0 = -rect.x;
- matrix.y0 = -rect.y;
-
- pango_context_set_matrix (context, &matrix);
-
- cairo_matrix.xx = matrix.xx;
- cairo_matrix.yx = matrix.yx;
- cairo_matrix.xy = matrix.xy;
- cairo_matrix.yy = matrix.yy;
- cairo_matrix.x0 = matrix.x0;
- cairo_matrix.y0 = matrix.y0;
- cairo_matrix_scale (&cairo_matrix, scalef, scalef);
-
- tmp = height;
- height = width;
- width = tmp;
- } else {
- cairo_matrix_init_scale (&cairo_matrix, scalef, scalef);
- }
-
- /* reallocate surface */
- overlay->text_image = g_realloc (overlay->text_image, 4 * width * height);
-
- surface = cairo_image_surface_create_for_data (overlay->text_image,
- CAIRO_FORMAT_ARGB32, width, height, width * 4);
- cr = cairo_create (surface);
-
- /* clear surface */
- cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
- cairo_paint (cr);
-
- cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-
- if (overlay->want_shading)
- cairo_paint_with_alpha (cr, overlay->shading_value);
-
- /* apply transformations */
- cairo_set_matrix (cr, &cairo_matrix);
-
- /* FIXME: We use show_layout everywhere except for the surface
- * because it's really faster and internally does all kinds of
- * caching. Unfortunately we have to paint to a cairo path for
- * the outline and this is slow. Once Pango supports user fonts
- * we should use them, see
- * https://bugzilla.gnome.org/show_bug.cgi?id=598695
- *
- * Idea would the be, to create a cairo user font that
- * does shadow, outline, text painting in the
- * render_glyph function.
- */
-
- /* draw shadow text */
- cairo_save (cr);
- cairo_translate (cr, overlay->shadow_offset, overlay->shadow_offset);
- cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
- pango_cairo_show_layout (cr, overlay->layout);
- cairo_restore (cr);
-
- /* draw outline text */
- cairo_save (cr);
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_set_line_width (cr, overlay->outline_offset);
- pango_cairo_layout_path (cr, overlay->layout);
- cairo_stroke (cr);
- cairo_restore (cr);
-
- /* draw text */
- cairo_save (cr);
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- pango_cairo_show_layout (cr, overlay->layout);
- cairo_restore (cr);
-
- cairo_destroy (cr);
- cairo_surface_destroy (surface);
- overlay->image_width = width;
- overlay->image_height = height;
- overlay->baseline_y = ink_rect.y;
-}
-
-#define BOX_XPAD 6
-#define BOX_YPAD 6
-
-static inline void
-gst_text_overlay_shade_I420_y (GstTextOverlay * overlay, guchar * dest,
- gint x0, gint x1, gint y0, gint y1)
-{
- gint i, j, dest_stride;
-
- dest_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0,
- overlay->width);
-
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
- for (i = y0; i < y1; ++i) {
- for (j = x0; j < x1; ++j) {
- gint y = dest[(i * dest_stride) + j] + overlay->shading_value;
-
- dest[(i * dest_stride) + j] = CLAMP (y, 0, 255);
- }
- }
-}
-
-static inline void
-gst_text_overlay_shade_UYVY_y (GstTextOverlay * overlay, guchar * dest,
- gint x0, gint x1, gint y0, gint y1)
-{
- gint i, j;
- guint dest_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_UYVY, 0,
- overlay->width);
-
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
- for (i = y0; i < y1; i++) {
- for (j = x0; j < x1; j++) {
- gint y;
- gint y_pos;
-
- y_pos = (i * dest_stride) + j * 2 + 1;
- y = dest[y_pos] + overlay->shading_value;
-
- dest[y_pos] = CLAMP (y, 0, 255);
- }
- }
-}
-
-#define gst_text_overlay_shade_BGRx gst_text_overlay_shade_xRGB
-static inline void
-gst_text_overlay_shade_xRGB (GstTextOverlay * overlay, guchar * dest,
- gint x0, gint x1, gint y0, gint y1)
-{
- gint i, j;
-
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
- for (i = y0; i < y1; i++) {
- for (j = x0; j < x1; j++) {
- gint y, y_pos, k;
-
- y_pos = (i * 4 * overlay->width) + j * 4;
- for (k = 0; k < 4; k++) {
- y = dest[y_pos + k] + overlay->shading_value;
- dest[y_pos + k] = CLAMP (y, 0, 255);
- }
- }
- }
-}
-
-/* FIXME:
- * - use proper strides and offset for I420
- * - don't draw over the edge of the picture (try a longer
- * text with a huge font size)
- */
-
-static inline void
-gst_text_overlay_blit_I420 (GstTextOverlay * overlay,
- guint8 * yuv_pixels, gint xpos, gint ypos)
-{
- int y_stride, u_stride, v_stride;
- int u_offset, v_offset;
- int h, w;
-
- w = overlay->width;
- h = overlay->height;
-
- y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, w);
- u_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, w);
- v_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, w);
- u_offset =
- gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1, w, h);
- v_offset =
- gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2, w, h);
-
- gst_text_overlay_blit_1 (overlay, yuv_pixels, xpos, ypos, overlay->text_image,
- y_stride);
- gst_text_overlay_blit_sub2x2cbcr (overlay, yuv_pixels + u_offset,
- yuv_pixels + v_offset, xpos, ypos, overlay->text_image, u_stride,
- v_stride);
-}
-
-static inline void
-gst_text_overlay_blit_UYVY (GstTextOverlay * overlay,
- guint8 * yuv_pixels, gint xpos, gint ypos)
-{
- int a0, r0, g0, b0;
- int a1, r1, g1, b1;
- int y0, y1, u, v;
- int i, j;
- int h, w;
- guchar *pimage, *dest;
-
- w = overlay->image_width - 2;
- h = overlay->image_height - 2;
-
- if (xpos < 0) {
- xpos = 0;
- }
-
- if (xpos + w > overlay->width) {
- w = overlay->width - xpos;
- }
-
- if (ypos + h > overlay->height) {
- h = overlay->height - ypos;
- }
-
- for (i = 0; i < h; i++) {
- pimage = overlay->text_image + i * overlay->image_width * 4;
- dest = yuv_pixels + (i + ypos) * overlay->width * 2 + xpos * 2;
- for (j = 0; j < w; j += 2) {
- b0 = pimage[CAIRO_ARGB_B];
- g0 = pimage[CAIRO_ARGB_G];
- r0 = pimage[CAIRO_ARGB_R];
- a0 = pimage[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a0, r0, g0, b0);
- pimage += 4;
-
- b1 = pimage[CAIRO_ARGB_B];
- g1 = pimage[CAIRO_ARGB_G];
- r1 = pimage[CAIRO_ARGB_R];
- a1 = pimage[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
- pimage += 4;
-
- a0 += a1 + 2;
- a0 /= 2;
- if (a0 == 0) {
- dest += 4;
- continue;
- }
-
- COMP_Y (y0, r0, g0, b0);
- COMP_Y (y1, r1, g1, b1);
-
- b0 += b1 + 2;
- g0 += g1 + 2;
- r0 += r1 + 2;
-
- b0 /= 2;
- g0 /= 2;
- r0 /= 2;
-
- COMP_U (u, r0, g0, b0);
- COMP_V (v, r0, g0, b0);
-
- BLEND (*dest, a0, u, *dest);
- dest++;
- BLEND (*dest, a0, y0, *dest);
- dest++;
- BLEND (*dest, a0, v, *dest);
- dest++;
- BLEND (*dest, a0, y1, *dest);
- dest++;
- }
- }
-}
-
-#define xRGB_BLIT_FUNCTION(name, R, G, B) \
-static inline void \
-gst_text_overlay_blit_##name (GstTextOverlay * overlay, \
- guint8 * rgb_pixels, gint xpos, gint ypos) \
-{ \
- int a, r, g, b; \
- int i, j; \
- int h, w; \
- guchar *pimage, *dest; \
- \
- w = overlay->image_width; \
- h = overlay->image_height; \
- \
- if (xpos < 0) { \
- xpos = 0; \
- } \
- \
- if (xpos + w > overlay->width) { \
- w = overlay->width - xpos; \
- } \
- \
- if (ypos + h > overlay->height) { \
- h = overlay->height - ypos; \
- } \
- \
- for (i = 0; i < h; i++) { \
- pimage = overlay->text_image + i * overlay->image_width * 4; \
- dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4; \
- for (j = 0; j < w; j++) { \
- a = pimage[CAIRO_ARGB_A]; \
- b = pimage[CAIRO_ARGB_B]; \
- g = pimage[CAIRO_ARGB_G]; \
- r = pimage[CAIRO_ARGB_R]; \
- CAIRO_UNPREMULTIPLY (a, r, g, b); \
- b = (b*a + dest[B] * (255-a)) / 255; \
- g = (g*a + dest[G] * (255-a)) / 255; \
- r = (r*a + dest[R] * (255-a)) / 255; \
- \
- dest[B] = b; \
- dest[G] = g; \
- dest[R] = r; \
- pimage += 4; \
- dest += 4; \
- } \
- } \
-}
-xRGB_BLIT_FUNCTION (xRGB, 1, 2, 3);
-xRGB_BLIT_FUNCTION (BGRx, 2, 1, 0);
-
-static void
-gst_text_overlay_render_text (GstTextOverlay * overlay,
- const gchar * text, gint textlen)
-{
- gchar *string;
-
- if (!overlay->need_render) {
- GST_DEBUG ("Using previously rendered text.");
- return;
- }
-
- /* -1 is the whole string */
- if (text != NULL && textlen < 0) {
- textlen = strlen (text);
- }
-
- if (text != NULL) {
- string = g_strndup (text, textlen);
- } else { /* empty string */
- string = g_strdup (" ");
- }
- g_strdelimit (string, "\r\t", ' ');
- textlen = strlen (string);
-
- /* FIXME: should we check for UTF-8 here? */
-
- GST_DEBUG ("Rendering '%s'", string);
- gst_text_overlay_render_pangocairo (overlay, string, textlen);
-
- g_free (string);
-
- overlay->need_render = FALSE;
-}
-
-static GstFlowReturn
-gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame)
-{
- gint xpos, ypos;
- gint width, height;
- GstTextOverlayVAlign valign;
- GstTextOverlayHAlign halign;
-
- width = overlay->image_width;
- height = overlay->image_height;
-
- video_frame = gst_buffer_make_writable (video_frame);
-
- if (overlay->use_vertical_render)
- halign = GST_TEXT_OVERLAY_HALIGN_RIGHT;
- else
- halign = overlay->halign;
-
- switch (halign) {
- case GST_TEXT_OVERLAY_HALIGN_LEFT:
- xpos = overlay->xpad;
- break;
- case GST_TEXT_OVERLAY_HALIGN_CENTER:
- xpos = (overlay->width - width) / 2;
- break;
- case GST_TEXT_OVERLAY_HALIGN_RIGHT:
- xpos = overlay->width - width - overlay->xpad;
- break;
- default:
- xpos = 0;
- }
- xpos += overlay->deltax;
-
- if (overlay->use_vertical_render)
- valign = GST_TEXT_OVERLAY_VALIGN_TOP;
- else
- valign = overlay->valign;
-
- switch (valign) {
- case GST_TEXT_OVERLAY_VALIGN_BOTTOM:
- ypos = overlay->height - height - overlay->ypad;
- break;
- case GST_TEXT_OVERLAY_VALIGN_BASELINE:
- ypos = overlay->height - (height + overlay->ypad);
- break;
- case GST_TEXT_OVERLAY_VALIGN_TOP:
- ypos = overlay->ypad;
- break;
- default:
- ypos = overlay->ypad;
- break;
- }
- ypos += overlay->deltay;
-
- /* shaded background box */
- if (overlay->want_shading) {
- switch (overlay->format) {
- case GST_VIDEO_FORMAT_I420:
- gst_text_overlay_shade_I420_y (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_UYVY:
- gst_text_overlay_shade_UYVY_y (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_xRGB:
- gst_text_overlay_shade_xRGB (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_BGRx:
- gst_text_overlay_shade_BGRx (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- default:
- g_assert_not_reached ();
- }
- }
-
- if (ypos < 0)
- ypos = 0;
-
- if (overlay->text_image) {
- switch (overlay->format) {
- case GST_VIDEO_FORMAT_I420:
- gst_text_overlay_blit_I420 (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_UYVY:
- gst_text_overlay_blit_UYVY (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_BGRx:
- gst_text_overlay_blit_BGRx (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_xRGB:
- gst_text_overlay_blit_xRGB (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- default:
- g_assert_not_reached ();
- }
- }
- return gst_pad_push (overlay->srcpad, video_frame);
-}
-
-static GstPadLinkReturn
-gst_text_overlay_text_pad_link (GstPad * pad, GstPad * peer)
-{
- GstTextOverlay *overlay;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (overlay, "Text pad linked");
-
- overlay->text_linked = TRUE;
-
- gst_object_unref (overlay);
-
- return GST_PAD_LINK_OK;
-}
-
-static void
-gst_text_overlay_text_pad_unlink (GstPad * pad)
-{
- GstTextOverlay *overlay;
-
- /* don't use gst_pad_get_parent() here, will deadlock */
- overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad));
-
- GST_DEBUG_OBJECT (overlay, "Text pad unlinked");
-
- overlay->text_linked = FALSE;
-
- gst_segment_init (&overlay->text_segment, GST_FORMAT_UNDEFINED);
-}
-
-static gboolean
-gst_text_overlay_text_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret = FALSE;
- GstTextOverlay *overlay = NULL;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- GST_LOG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:{
- GstFormat fmt;
- gboolean update;
- gdouble rate, applied_rate;
- gint64 cur, stop, time;
-
- overlay->text_eos = FALSE;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &fmt, &cur, &stop, &time);
-
- if (fmt == GST_FORMAT_TIME) {
- GST_OBJECT_LOCK (overlay);
- gst_segment_set_newsegment_full (&overlay->text_segment, update, rate,
- applied_rate, GST_FORMAT_TIME, cur, stop, time);
- GST_DEBUG_OBJECT (overlay, "TEXT SEGMENT now: %" GST_SEGMENT_FORMAT,
- &overlay->text_segment);
- GST_OBJECT_UNLOCK (overlay);
- } else {
- GST_ELEMENT_WARNING (overlay, STREAM, MUX, (NULL),
- ("received non-TIME newsegment event on text input"));
- }
-
- gst_event_unref (event);
- ret = TRUE;
-
- /* wake up the video chain, it might be waiting for a text buffer or
- * a text segment update */
- GST_OBJECT_LOCK (overlay);
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- GST_OBJECT_UNLOCK (overlay);
- break;
- }
- case GST_EVENT_FLUSH_STOP:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "text flush stop");
- overlay->text_flushing = FALSE;
- overlay->text_eos = FALSE;
- gst_text_overlay_pop_text (overlay);
- gst_segment_init (&overlay->text_segment, GST_FORMAT_TIME);
- GST_OBJECT_UNLOCK (overlay);
- gst_event_unref (event);
- ret = TRUE;
- break;
- case GST_EVENT_FLUSH_START:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "text flush start");
- overlay->text_flushing = TRUE;
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- GST_OBJECT_UNLOCK (overlay);
- gst_event_unref (event);
- ret = TRUE;
- break;
- case GST_EVENT_EOS:
- GST_OBJECT_LOCK (overlay);
- overlay->text_eos = TRUE;
- GST_INFO_OBJECT (overlay, "text EOS");
- /* wake up the video chain, it might be waiting for a text buffer or
- * a text segment update */
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- GST_OBJECT_UNLOCK (overlay);
- gst_event_unref (event);
- ret = TRUE;
- break;
- default:
- ret = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static gboolean
-gst_text_overlay_video_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret = FALSE;
- GstTextOverlay *overlay = NULL;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
- {
- GstFormat format;
- gdouble rate;
- gint64 start, stop, time;
- gboolean update;
-
- GST_DEBUG_OBJECT (overlay, "received new segment");
-
- gst_event_parse_new_segment (event, &update, &rate, &format, &start,
- &stop, &time);
-
- if (format == GST_FORMAT_TIME) {
- GST_DEBUG_OBJECT (overlay, "VIDEO SEGMENT now: %" GST_SEGMENT_FORMAT,
- &overlay->segment);
-
- gst_segment_set_newsegment (&overlay->segment, update, rate, format,
- start, stop, time);
- } else {
- GST_ELEMENT_WARNING (overlay, STREAM, MUX, (NULL),
- ("received non-TIME newsegment event on video input"));
- }
-
- ret = gst_pad_event_default (pad, event);
- break;
- }
- case GST_EVENT_EOS:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "video EOS");
- overlay->video_eos = TRUE;
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_pad_event_default (pad, event);
- break;
- case GST_EVENT_FLUSH_START:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "video flush start");
- overlay->video_flushing = TRUE;
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_pad_event_default (pad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "video flush stop");
- overlay->video_flushing = FALSE;
- overlay->video_eos = FALSE;
- gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_pad_event_default (pad, event);
- break;
- default:
- ret = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static GstFlowReturn
-gst_text_overlay_video_bufferalloc (GstPad * pad, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buffer)
-{
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
- GstFlowReturn ret = GST_FLOW_WRONG_STATE;
- GstPad *allocpad;
-
- GST_OBJECT_LOCK (overlay);
- allocpad = overlay->srcpad ? gst_object_ref (overlay->srcpad) : NULL;
- GST_OBJECT_UNLOCK (overlay);
-
- if (allocpad) {
- ret = gst_pad_alloc_buffer (allocpad, offset, size, caps, buffer);
- gst_object_unref (allocpad);
- }
-
- gst_object_unref (overlay);
- return ret;
-}
-
-/* Called with lock held */
-static void
-gst_text_overlay_pop_text (GstTextOverlay * overlay)
-{
- g_return_if_fail (GST_IS_TEXT_OVERLAY (overlay));
-
- if (overlay->text_buffer) {
- GST_DEBUG_OBJECT (overlay, "releasing text buffer %p",
- overlay->text_buffer);
- gst_buffer_unref (overlay->text_buffer);
- overlay->text_buffer = NULL;
- }
-
- /* Let the text task know we used that buffer */
- GST_TEXT_OVERLAY_BROADCAST (overlay);
-}
-
-/* We receive text buffers here. If they are out of segment we just ignore them.
- If the buffer is in our segment we keep it internally except if another one
- is already waiting here, in that case we wait that it gets kicked out */
-static GstFlowReturn
-gst_text_overlay_text_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- GstTextOverlay *overlay = NULL;
- gboolean in_seg = FALSE;
- gint64 clip_start = 0, clip_stop = 0;
-
- overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad));
-
- GST_OBJECT_LOCK (overlay);
-
- if (overlay->text_flushing) {
- GST_OBJECT_UNLOCK (overlay);
- ret = GST_FLOW_WRONG_STATE;
- GST_LOG_OBJECT (overlay, "text flushing");
- goto beach;
- }
-
- if (overlay->text_eos) {
- GST_OBJECT_UNLOCK (overlay);
- ret = GST_FLOW_UNEXPECTED;
- GST_LOG_OBJECT (overlay, "text EOS");
- goto beach;
- }
-
- GST_LOG_OBJECT (overlay, "%" GST_SEGMENT_FORMAT " BUFFER: ts=%"
- GST_TIME_FORMAT ", end=%" GST_TIME_FORMAT, &overlay->segment,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer) +
- GST_BUFFER_DURATION (buffer)));
-
- if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))) {
- GstClockTime stop;
-
- if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buffer)))
- stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
- else
- stop = GST_CLOCK_TIME_NONE;
-
- in_seg = gst_segment_clip (&overlay->text_segment, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (buffer), stop, &clip_start, &clip_stop);
- } else {
- in_seg = TRUE;
- }
-
- if (in_seg) {
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
- GST_BUFFER_TIMESTAMP (buffer) = clip_start;
- else if (GST_BUFFER_DURATION_IS_VALID (buffer))
- GST_BUFFER_DURATION (buffer) = clip_stop - clip_start;
-
- /* Wait for the previous buffer to go away */
- while (overlay->text_buffer != NULL) {
- GST_DEBUG ("Pad %s:%s has a buffer queued, waiting",
- GST_DEBUG_PAD_NAME (pad));
- GST_TEXT_OVERLAY_WAIT (overlay);
- GST_DEBUG ("Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad));
- if (overlay->text_flushing) {
- GST_OBJECT_UNLOCK (overlay);
- ret = GST_FLOW_WRONG_STATE;
- goto beach;
- }
- }
-
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
- gst_segment_set_last_stop (&overlay->text_segment, GST_FORMAT_TIME,
- clip_start);
-
- overlay->text_buffer = buffer;
- /* That's a new text buffer we need to render */
- overlay->need_render = TRUE;
-
- /* in case the video chain is waiting for a text buffer, wake it up */
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- }
-
- GST_OBJECT_UNLOCK (overlay);
-
-beach:
-
- return ret;
-}
-
-static GstFlowReturn
-gst_text_overlay_video_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstTextOverlayClass *klass;
- GstTextOverlay *overlay;
- GstFlowReturn ret = GST_FLOW_OK;
- gboolean in_seg = FALSE;
- gint64 start, stop, clip_start = 0, clip_stop = 0;
- gchar *text = NULL;
-
- overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad));
- klass = GST_TEXT_OVERLAY_GET_CLASS (overlay);
-
- if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
- goto missing_timestamp;
-
- /* ignore buffers that are outside of the current segment */
- start = GST_BUFFER_TIMESTAMP (buffer);
-
- if (!GST_BUFFER_DURATION_IS_VALID (buffer)) {
- stop = GST_CLOCK_TIME_NONE;
- } else {
- stop = start + GST_BUFFER_DURATION (buffer);
- }
-
- GST_LOG_OBJECT (overlay, "%" GST_SEGMENT_FORMAT " BUFFER: ts=%"
- GST_TIME_FORMAT ", end=%" GST_TIME_FORMAT, &overlay->segment,
- GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
-
- /* segment_clip() will adjust start unconditionally to segment_start if
- * no stop time is provided, so handle this ourselves */
- if (stop == GST_CLOCK_TIME_NONE && start < overlay->segment.start)
- goto out_of_segment;
-
- in_seg = gst_segment_clip (&overlay->segment, GST_FORMAT_TIME, start, stop,
- &clip_start, &clip_stop);
-
- if (!in_seg)
- goto out_of_segment;
-
- /* if the buffer is only partially in the segment, fix up stamps */
- if (clip_start != start || (stop != -1 && clip_stop != stop)) {
- GST_DEBUG_OBJECT (overlay, "clipping buffer timestamp/duration to segment");
- buffer = gst_buffer_make_metadata_writable (buffer);
- GST_BUFFER_TIMESTAMP (buffer) = clip_start;
- if (stop != -1)
- GST_BUFFER_DURATION (buffer) = clip_stop - clip_start;
- }
-
- /* now, after we've done the clipping, fix up end time if there's no
- * duration (we only use those estimated values internally though, we
- * don't want to set bogus values on the buffer itself) */
- if (stop == -1) {
- GstStructure *s;
- gint fps_num, fps_denom;
-
- s = gst_caps_get_structure (GST_PAD_CAPS (pad), 0);
- if (gst_structure_get_fraction (s, "framerate", &fps_num, &fps_denom) &&
- fps_num && fps_denom) {
- GST_DEBUG_OBJECT (overlay, "estimating duration based on framerate");
- stop = start + gst_util_uint64_scale_int (GST_SECOND, fps_denom, fps_num);
- } else {
- GST_WARNING_OBJECT (overlay, "no duration, assuming minimal duration");
- stop = start + 1; /* we need to assume some interval */
- }
- }
-
-wait_for_text_buf:
-
- GST_OBJECT_LOCK (overlay);
-
- if (overlay->video_flushing)
- goto flushing;
-
- if (overlay->video_eos)
- goto have_eos;
-
- if (overlay->silent) {
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_pad_push (overlay->srcpad, buffer);
-
- /* Update last_stop */
- gst_segment_set_last_stop (&overlay->segment, GST_FORMAT_TIME, clip_start);
-
- return ret;
- }
-
- /* Text pad not linked, rendering internal text */
- if (!overlay->text_linked) {
- if (klass->get_text) {
- text = klass->get_text (overlay, buffer);
- } else {
- text = g_strdup (overlay->default_text);
- }
-
- GST_LOG_OBJECT (overlay, "Text pad not linked, rendering default "
- "text: '%s'", GST_STR_NULL (text));
-
- GST_OBJECT_UNLOCK (overlay);
-
- if (text != NULL && *text != '\0') {
- /* Render and push */
- gst_text_overlay_render_text (overlay, text, -1);
- ret = gst_text_overlay_push_frame (overlay, buffer);
- } else {
- /* Invalid or empty string */
- ret = gst_pad_push (overlay->srcpad, buffer);
- }
- } else {
- /* Text pad linked, check if we have a text buffer queued */
- if (overlay->text_buffer) {
- gboolean pop_text = FALSE, valid_text_time = TRUE;
- GstClockTime text_start = GST_CLOCK_TIME_NONE;
- GstClockTime text_end = GST_CLOCK_TIME_NONE;
- GstClockTime text_running_time = GST_CLOCK_TIME_NONE;
- GstClockTime text_running_time_end = GST_CLOCK_TIME_NONE;
- GstClockTime vid_running_time, vid_running_time_end;
-
- /* if the text buffer isn't stamped right, pop it off the
- * queue and display it for the current video frame only */
- if (!GST_BUFFER_TIMESTAMP_IS_VALID (overlay->text_buffer) ||
- !GST_BUFFER_DURATION_IS_VALID (overlay->text_buffer)) {
- GST_WARNING_OBJECT (overlay,
- "Got text buffer with invalid timestamp or duration");
- pop_text = TRUE;
- valid_text_time = FALSE;
- } else {
- text_start = GST_BUFFER_TIMESTAMP (overlay->text_buffer);
- text_end = text_start + GST_BUFFER_DURATION (overlay->text_buffer);
- }
-
- vid_running_time =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- start);
- vid_running_time_end =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- stop);
-
- /* If timestamp and duration are valid */
- if (valid_text_time) {
- text_running_time =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- text_start);
- text_running_time_end =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- text_end);
- }
-
- GST_LOG_OBJECT (overlay, "T: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
- GST_TIME_ARGS (text_running_time),
- GST_TIME_ARGS (text_running_time_end));
- GST_LOG_OBJECT (overlay, "V: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
- GST_TIME_ARGS (vid_running_time),
- GST_TIME_ARGS (vid_running_time_end));
-
- /* Text too old or in the future */
- if (valid_text_time && text_running_time_end <= vid_running_time) {
- /* text buffer too old, get rid of it and do nothing */
- GST_LOG_OBJECT (overlay, "text buffer too old, popping");
- pop_text = FALSE;
- gst_text_overlay_pop_text (overlay);
- GST_OBJECT_UNLOCK (overlay);
- goto wait_for_text_buf;
- } else if (valid_text_time && vid_running_time_end <= text_running_time) {
- GST_LOG_OBJECT (overlay, "text in future, pushing video buf");
- GST_OBJECT_UNLOCK (overlay);
- /* Push the video frame */
- ret = gst_pad_push (overlay->srcpad, buffer);
- } else {
- gchar *in_text;
- gsize in_size;
-
- in_text = (gchar *) GST_BUFFER_DATA (overlay->text_buffer);
- in_size = GST_BUFFER_SIZE (overlay->text_buffer);
-
- /* g_markup_escape_text() absolutely requires valid UTF8 input, it
- * might crash otherwise. We don't fall back on GST_SUBTITLE_ENCODING
- * here on purpose, this is something that needs fixing upstream */
- if (!g_utf8_validate (in_text, in_size, NULL)) {
- const gchar *end = NULL;
-
- GST_WARNING_OBJECT (overlay, "received invalid UTF-8");
- in_text = g_strndup (in_text, in_size);
- while (!g_utf8_validate (in_text, in_size, &end) && end)
- *((gchar *) end) = '*';
- }
-
- /* Get the string */
- if (overlay->have_pango_markup) {
- text = g_strndup (in_text, in_size);
- } else {
- text = g_markup_escape_text (in_text, in_size);
- }
-
- if (text != NULL && *text != '\0') {
- gint text_len = strlen (text);
-
- while (text_len > 0 && (text[text_len - 1] == '\n' ||
- text[text_len - 1] == '\r')) {
- --text_len;
- }
- GST_DEBUG_OBJECT (overlay, "Rendering text '%*s'", text_len, text);
- gst_text_overlay_render_text (overlay, text, text_len);
- } else {
- GST_DEBUG_OBJECT (overlay, "No text to render (empty buffer)");
- gst_text_overlay_render_text (overlay, " ", 1);
- }
-
- if (in_text != (gchar *) GST_BUFFER_DATA (overlay->text_buffer))
- g_free (in_text);
-
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_text_overlay_push_frame (overlay, buffer);
-
- if (valid_text_time && text_running_time_end <= vid_running_time_end) {
- GST_LOG_OBJECT (overlay, "text buffer not needed any longer");
- pop_text = TRUE;
- }
- }
- if (pop_text) {
- GST_OBJECT_LOCK (overlay);
- gst_text_overlay_pop_text (overlay);
- GST_OBJECT_UNLOCK (overlay);
- }
- } else {
- gboolean wait_for_text_buf = TRUE;
-
- if (overlay->text_eos)
- wait_for_text_buf = FALSE;
-
- if (!overlay->wait_text)
- wait_for_text_buf = FALSE;
-
- /* Text pad linked, but no text buffer available - what now? */
- if (overlay->text_segment.format == GST_FORMAT_TIME) {
- GstClockTime text_start_running_time, text_last_stop_running_time;
- GstClockTime vid_running_time;
-
- vid_running_time =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (buffer));
- text_start_running_time =
- gst_segment_to_running_time (&overlay->text_segment,
- GST_FORMAT_TIME, overlay->text_segment.start);
- text_last_stop_running_time =
- gst_segment_to_running_time (&overlay->text_segment,
- GST_FORMAT_TIME, overlay->text_segment.last_stop);
-
- if ((GST_CLOCK_TIME_IS_VALID (text_start_running_time) &&
- vid_running_time < text_start_running_time) ||
- (GST_CLOCK_TIME_IS_VALID (text_last_stop_running_time) &&
- vid_running_time < text_last_stop_running_time)) {
- wait_for_text_buf = FALSE;
- }
- }
-
- if (wait_for_text_buf) {
- GST_DEBUG_OBJECT (overlay, "no text buffer, need to wait for one");
- GST_TEXT_OVERLAY_WAIT (overlay);
- GST_DEBUG_OBJECT (overlay, "resuming");
- GST_OBJECT_UNLOCK (overlay);
- goto wait_for_text_buf;
- } else {
- GST_OBJECT_UNLOCK (overlay);
- GST_LOG_OBJECT (overlay, "no need to wait for a text buffer");
- ret = gst_pad_push (overlay->srcpad, buffer);
- }
- }
- }
-
- g_free (text);
-
- /* Update last_stop */
- gst_segment_set_last_stop (&overlay->segment, GST_FORMAT_TIME, clip_start);
-
- return ret;
-
-missing_timestamp:
- {
- GST_WARNING_OBJECT (overlay, "buffer without timestamp, discarding");
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
- }
-
-flushing:
- {
- GST_OBJECT_UNLOCK (overlay);
- GST_DEBUG_OBJECT (overlay, "flushing, discarding buffer");
- gst_buffer_unref (buffer);
- return GST_FLOW_WRONG_STATE;
- }
-have_eos:
- {
- GST_OBJECT_UNLOCK (overlay);
- GST_DEBUG_OBJECT (overlay, "eos, discarding buffer");
- gst_buffer_unref (buffer);
- return GST_FLOW_UNEXPECTED;
- }
-out_of_segment:
- {
- GST_DEBUG_OBJECT (overlay, "buffer out of segment, discarding");
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
- }
-}
-
-static GstStateChangeReturn
-gst_text_overlay_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_OBJECT_LOCK (overlay);
- overlay->text_flushing = TRUE;
- overlay->video_flushing = TRUE;
- /* pop_text will broadcast on the GCond and thus also make the video
- * chain exit if it's waiting for a text buffer */
- gst_text_overlay_pop_text (overlay);
- GST_OBJECT_UNLOCK (overlay);
- break;
- default:
- break;
- }
-
- ret = parent_class->change_state (element, transition);
- if (ret == GST_STATE_CHANGE_FAILURE)
- return ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- GST_OBJECT_LOCK (overlay);
- overlay->text_flushing = FALSE;
- overlay->video_flushing = FALSE;
- overlay->video_eos = FALSE;
- overlay->text_eos = FALSE;
- gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
- gst_segment_init (&overlay->text_segment, GST_FORMAT_TIME);
- GST_OBJECT_UNLOCK (overlay);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- if (!gst_element_register (plugin, "textoverlay", GST_RANK_NONE,
- GST_TYPE_TEXT_OVERLAY) ||
- !gst_element_register (plugin, "timeoverlay", GST_RANK_NONE,
- GST_TYPE_TIME_OVERLAY) ||
- !gst_element_register (plugin, "clockoverlay", GST_RANK_NONE,
- GST_TYPE_CLOCK_OVERLAY) ||
- !gst_element_register (plugin, "textrender", GST_RANK_NONE,
- GST_TYPE_TEXT_RENDER)) {
- return FALSE;
- }
-
- /*texttestsrc_plugin_init(module, plugin); */
-
- GST_DEBUG_CATEGORY_INIT (pango_debug, "pango", 0, "Pango elements");
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
- "pango", "Pango-based text rendering and overlay", plugin_init,
- VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/pango/gsttextoverlay.h b/ext/pango/gsttextoverlay.h
deleted file mode 100644
index 4590b270..00000000
--- a/ext/pango/gsttextoverlay.h
+++ /dev/null
@@ -1,158 +0,0 @@
-#ifndef __GST_TEXT_OVERLAY_H__
-#define __GST_TEXT_OVERLAY_H__
-
-#include <gst/gst.h>
-#include <gst/video/video.h>
-#include <pango/pangocairo.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_TEXT_OVERLAY (gst_text_overlay_get_type())
-#define GST_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
- GST_TYPE_TEXT_OVERLAY, GstTextOverlay))
-#define GST_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
- GST_TYPE_TEXT_OVERLAY,GstTextOverlayClass))
-#define GST_TEXT_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
- GST_TYPE_TEXT_OVERLAY, GstTextOverlayClass))
-#define GST_IS_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
- GST_TYPE_TEXT_OVERLAY))
-#define GST_IS_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
- GST_TYPE_TEXT_OVERLAY))
-
-typedef struct _GstTextOverlay GstTextOverlay;
-typedef struct _GstTextOverlayClass GstTextOverlayClass;
-
-/**
- * GstTextOverlayVAlign:
- * @GST_TEXT_OVERLAY_VALIGN_BASELINE: draw text on the baseline
- * @GST_TEXT_OVERLAY_VALIGN_BOTTOM: draw text on the bottom
- * @GST_TEXT_OVERLAY_VALIGN_TOP: draw test on top
- *
- * Vertical alignment of the text.
- */
-typedef enum {
- GST_TEXT_OVERLAY_VALIGN_BASELINE,
- GST_TEXT_OVERLAY_VALIGN_BOTTOM,
- GST_TEXT_OVERLAY_VALIGN_TOP
-} GstTextOverlayVAlign;
-
-/**
- * GstTextOverlayHAlign:
- * @GST_TEXT_OVERLAY_HALIGN_LEFT: align text left
- * @GST_TEXT_OVERLAY_HALIGN_CENTER: align text center
- * @GST_TEXT_OVERLAY_HALIGN_RIGHT: align text right
- *
- * Horizontal alignment of the text.
- */
-typedef enum {
- GST_TEXT_OVERLAY_HALIGN_LEFT,
- GST_TEXT_OVERLAY_HALIGN_CENTER,
- GST_TEXT_OVERLAY_HALIGN_RIGHT
-} GstTextOverlayHAlign;
-
-/**
- * GstTextOverlayWrapMode:
- * @GST_TEXT_OVERLAY_WRAP_MODE_NONE: no wrapping
- * @GST_TEXT_OVERLAY_WRAP_MODE_WORD: do word wrapping
- * @GST_TEXT_OVERLAY_WRAP_MODE_CHAR: do char wrapping
- * @GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR: do word and char wrapping
- *
- * Whether to wrap the text and if so how.
- */
-typedef enum {
- GST_TEXT_OVERLAY_WRAP_MODE_NONE = -1,
- GST_TEXT_OVERLAY_WRAP_MODE_WORD = PANGO_WRAP_WORD,
- GST_TEXT_OVERLAY_WRAP_MODE_CHAR = PANGO_WRAP_CHAR,
- GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR = PANGO_WRAP_WORD_CHAR
-} GstTextOverlayWrapMode;
-
-/**
- * GstTextOverlayLineAlign:
- * @GST_TEXT_OVERLAY_LINE_ALIGN_LEFT: lines are left-aligned
- * @GST_TEXT_OVERLAY_LINE_ALIGN_CENTER: lines are center-aligned
- * @GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT: lines are right-aligned
- *
- * Alignment of text lines relative to each other
- */
-typedef enum {
- GST_TEXT_OVERLAY_LINE_ALIGN_LEFT = PANGO_ALIGN_LEFT,
- GST_TEXT_OVERLAY_LINE_ALIGN_CENTER = PANGO_ALIGN_CENTER,
- GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT = PANGO_ALIGN_RIGHT
-} GstTextOverlayLineAlign;
-
-/**
- * GstTextOverlay:
- *
- * Opaque textoverlay object structure
- */
-struct _GstTextOverlay {
- GstElement element;
-
- GstPad *video_sinkpad;
- GstPad *text_sinkpad;
- GstPad *srcpad;
-
- GstSegment segment;
- GstSegment text_segment;
- GstBuffer *text_buffer;
- gboolean text_linked;
- gboolean video_flushing;
- gboolean video_eos;
- gboolean text_flushing;
- gboolean text_eos;
-
- GCond *cond; /* to signal removal of a queued text
- * buffer, arrival of a text buffer,
- * a text segment update, or a change
- * in status (e.g. shutdown, flushing) */
-
- gint width;
- gint height;
- gint fps_n;
- gint fps_d;
- GstVideoFormat format;
-
- GstTextOverlayVAlign valign;
- GstTextOverlayHAlign halign;
- GstTextOverlayWrapMode wrap_mode;
- GstTextOverlayLineAlign line_align;
-
- gint xpad;
- gint ypad;
- gint deltax;
- gint deltay;
- gchar *default_text;
- gboolean want_shading;
- gboolean silent;
- gboolean wait_text;
-
- PangoLayout *layout;
- gdouble shadow_offset;
- gdouble outline_offset;
- guchar *text_image;
- gint image_width;
- gint image_height;
- gint baseline_y;
-
- gboolean auto_adjust_size;
- gboolean need_render;
-
- gint shading_value; /* for timeoverlay subclass */
-
- gboolean have_pango_markup;
- gboolean use_vertical_render;
-};
-
-struct _GstTextOverlayClass {
- GstElementClass parent_class;
-
- PangoContext *pango_context;
-
- gchar * (*get_text) (GstTextOverlay *overlay, GstBuffer *video_frame);
-};
-
-GType gst_text_overlay_get_type(void) G_GNUC_CONST;
-
-G_END_DECLS
-
-#endif /* __GST_TEXT_OVERLAY_H */
diff --git a/ext/pango/gsttextrender.c b/ext/pango/gsttextrender.c
deleted file mode 100644
index c9372449..00000000
--- a/ext/pango/gsttextrender.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) <2003> David Schleef <ds@schleef.org>
- * Copyright (C) <2009> Young-Ho Cha <ganadist@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-/**
- * SECTION:element-textrender
- * @see_also: #GstTextOverlay
- *
- * This plugin renders text received on the text sink pad to a video
- * buffer (retaining the alpha channel), so it can later be overlayed
- * on top of video streams using other elements.
- *
- * The text can contain newline characters. (FIXME: What about text
- * wrapping? It does not make sense in this context)
- *
- * <refsect2>
- * <title>Example launch lines</title>
- * |[
- * gst-launch -v filesrc location=subtitles.srt ! subparse ! textrender ! xvimagesink
- * ]|
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gst/gst.h>
-#include <gst/video/video.h>
-
-#include "gsttextrender.h"
-#include <string.h>
-
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-# define CAIRO_ARGB_A 3
-# define CAIRO_ARGB_R 2
-# define CAIRO_ARGB_G 1
-# define CAIRO_ARGB_B 0
-#else
-# define CAIRO_ARGB_A 0
-# define CAIRO_ARGB_R 1
-# define CAIRO_ARGB_G 2
-# define CAIRO_ARGB_B 3
-#endif
-
-GST_DEBUG_CATEGORY_EXTERN (pango_debug);
-#define GST_CAT_DEFAULT pango_debug
-
-#define MINIMUM_OUTLINE_OFFSET 1.0
-
-#define DEFAULT_PROP_VALIGNMENT GST_TEXT_RENDER_VALIGN_BASELINE
-#define DEFAULT_PROP_HALIGNMENT GST_TEXT_RENDER_HALIGN_CENTER
-#define DEFAULT_PROP_LINE_ALIGNMENT GST_TEXT_RENDER_LINE_ALIGN_CENTER
-#define DEFAULT_PROP_XPAD 25
-#define DEFAULT_PROP_YPAD 25
-
-#define DEFAULT_RENDER_WIDTH 720
-#define DEFAULT_RENDER_HEIGHT 576
-
-enum
-{
- PROP_0,
- PROP_HALIGNMENT,
- PROP_VALIGNMENT,
- PROP_LINE_ALIGNMENT,
- PROP_XPAD,
- PROP_YPAD,
- PROP_FONT_DESC
-};
-
-
-static GstStaticPadTemplate src_template_factory =
- GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" GST_VIDEO_CAPS_ARGB)
- );
-
-static GstStaticPadTemplate sink_template_factory =
- GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("text/x-pango-markup; text/plain")
- );
-
-#define GST_TYPE_TEXT_RENDER_VALIGN (gst_text_render_valign_get_type())
-static GType
-gst_text_render_valign_get_type (void)
-{
- static GType text_render_valign_type = 0;
- static const GEnumValue text_render_valign[] = {
- {GST_TEXT_RENDER_VALIGN_BASELINE, "baseline", "baseline"},
- {GST_TEXT_RENDER_VALIGN_BOTTOM, "bottom", "bottom"},
- {GST_TEXT_RENDER_VALIGN_TOP, "top", "top"},
- {0, NULL, NULL},
- };
-
- if (!text_render_valign_type) {
- text_render_valign_type =
- g_enum_register_static ("GstTextRenderVAlign", text_render_valign);
- }
- return text_render_valign_type;
-}
-
-#define GST_TYPE_TEXT_RENDER_HALIGN (gst_text_render_halign_get_type())
-static GType
-gst_text_render_halign_get_type (void)
-{
- static GType text_render_halign_type = 0;
- static const GEnumValue text_render_halign[] = {
- {GST_TEXT_RENDER_HALIGN_LEFT, "left", "left"},
- {GST_TEXT_RENDER_HALIGN_CENTER, "center", "center"},
- {GST_TEXT_RENDER_HALIGN_RIGHT, "right", "right"},
- {0, NULL, NULL},
- };
-
- if (!text_render_halign_type) {
- text_render_halign_type =
- g_enum_register_static ("GstTextRenderHAlign", text_render_halign);
- }
- return text_render_halign_type;
-}
-
-#define GST_TYPE_TEXT_RENDER_LINE_ALIGN (gst_text_render_line_align_get_type())
-static GType
-gst_text_render_line_align_get_type (void)
-{
- static GType text_render_line_align_type = 0;
- static const GEnumValue text_render_line_align[] = {
- {GST_TEXT_RENDER_LINE_ALIGN_LEFT, "left", "left"},
- {GST_TEXT_RENDER_LINE_ALIGN_CENTER, "center", "center"},
- {GST_TEXT_RENDER_LINE_ALIGN_RIGHT, "right", "right"},
- {0, NULL, NULL}
- };
-
- if (!text_render_line_align_type) {
- text_render_line_align_type =
- g_enum_register_static ("GstTextRenderLineAlign",
- text_render_line_align);
- }
- return text_render_line_align_type;
-}
-
-static void gst_text_render_adjust_values_with_fontdesc (GstTextRender *
- render, PangoFontDescription * desc);
-
-GST_BOILERPLATE (GstTextRender, gst_text_render, GstElement, GST_TYPE_ELEMENT);
-
-static void gst_text_render_finalize (GObject * object);
-static void gst_text_render_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_text_render_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec);
-
-static void
-gst_text_render_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_template_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_template_factory));
-
- gst_element_class_set_details_simple (element_class, "Text renderer",
- "Filter/Editor/Video",
- "Renders a text string to an image bitmap",
- "David Schleef <ds@schleef.org>, "
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-}
-
-static void
-gst_text_render_class_init (GstTextRenderClass * klass)
-{
- GObjectClass *gobject_class;
- PangoFontMap *fontmap;
-
- gobject_class = (GObjectClass *) klass;
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->finalize = gst_text_render_finalize;
- gobject_class->set_property = gst_text_render_set_property;
- gobject_class->get_property = gst_text_render_get_property;
-
- fontmap = pango_cairo_font_map_get_default ();
- klass->pango_context =
- pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FONT_DESC,
- g_param_spec_string ("font-desc", "font description",
- "Pango font description of font "
- "to be used for rendering. "
- "See documentation of "
- "pango_font_description_from_string"
- " for syntax.", "", G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGNMENT,
- g_param_spec_enum ("valignment", "vertical alignment",
- "Vertical alignment of the text", GST_TYPE_TEXT_RENDER_VALIGN,
- DEFAULT_PROP_VALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGNMENT,
- g_param_spec_enum ("halignment", "horizontal alignment",
- "Horizontal alignment of the text", GST_TYPE_TEXT_RENDER_HALIGN,
- DEFAULT_PROP_HALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPAD,
- g_param_spec_int ("xpad", "horizontal paddding",
- "Horizontal paddding when using left/right alignment", 0, G_MAXINT,
- DEFAULT_PROP_XPAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_YPAD,
- g_param_spec_int ("ypad", "vertical padding",
- "Vertical padding when using top/bottom alignment", 0, G_MAXINT,
- DEFAULT_PROP_YPAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LINE_ALIGNMENT,
- g_param_spec_enum ("line-alignment", "line alignment",
- "Alignment of text lines relative to each other.",
- GST_TYPE_TEXT_RENDER_LINE_ALIGN, DEFAULT_PROP_LINE_ALIGNMENT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_text_render_adjust_values_with_fontdesc (GstTextRender * render,
- PangoFontDescription * desc)
-{
- gint font_size = pango_font_description_get_size (desc) / PANGO_SCALE;
-
- render->shadow_offset = (double) (font_size) / 13.0;
- render->outline_offset = (double) (font_size) / 15.0;
- if (render->outline_offset < MINIMUM_OUTLINE_OFFSET)
- render->outline_offset = MINIMUM_OUTLINE_OFFSET;
-}
-
-static void
-gst_text_render_render_pangocairo (GstTextRender * render)
-{
- cairo_t *cr;
- cairo_surface_t *surface;
- cairo_t *cr_shadow;
- cairo_surface_t *surface_shadow;
- PangoRectangle ink_rect, logical_rect;
- gint width, height;
-
- pango_layout_get_pixel_extents (render->layout, &ink_rect, &logical_rect);
-
- width = logical_rect.width + render->shadow_offset;
- height = logical_rect.height + logical_rect.y + render->shadow_offset;
-
- surface_shadow = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
- cr_shadow = cairo_create (surface_shadow);
-
- /* clear shadow surface */
- cairo_set_operator (cr_shadow, CAIRO_OPERATOR_CLEAR);
- cairo_paint (cr_shadow);
- cairo_set_operator (cr_shadow, CAIRO_OPERATOR_OVER);
-
- /* draw shadow text */
- cairo_save (cr_shadow);
- cairo_set_source_rgba (cr_shadow, 0.0, 0.0, 0.0, 0.5);
- cairo_translate (cr_shadow, render->shadow_offset, render->shadow_offset);
- pango_cairo_show_layout (cr_shadow, render->layout);
- cairo_restore (cr_shadow);
-
- /* draw outline text */
- cairo_save (cr_shadow);
- cairo_set_source_rgb (cr_shadow, 0.0, 0.0, 0.0);
- cairo_set_line_width (cr_shadow, render->outline_offset);
- pango_cairo_layout_path (cr_shadow, render->layout);
- cairo_stroke (cr_shadow);
- cairo_restore (cr_shadow);
-
- cairo_destroy (cr_shadow);
-
- render->text_image = g_realloc (render->text_image, 4 * width * height);
-
- surface = cairo_image_surface_create_for_data (render->text_image,
- CAIRO_FORMAT_ARGB32, width, height, width * 4);
- cr = cairo_create (surface);
- cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
- cairo_paint (cr);
- cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-
- /* set default color */
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
-
- cairo_save (cr);
- /* draw text */
- pango_cairo_show_layout (cr, render->layout);
- cairo_restore (cr);
-
- /* composite shadow with offset */
- cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
- cairo_set_source_surface (cr, surface_shadow, 0.0, 0.0);
- cairo_paint (cr);
-
- cairo_destroy (cr);
- cairo_surface_destroy (surface_shadow);
- cairo_surface_destroy (surface);
- render->image_width = width;
- render->image_height = height;
-}
-
-static void
-gst_text_render_check_argb (GstTextRender * render)
-{
- GstCaps *peer_caps;
- peer_caps = gst_pad_get_allowed_caps (render->srcpad);
- if (G_LIKELY (peer_caps)) {
- guint i = 0, n = 0;
-
- n = gst_caps_get_size (peer_caps);
- GST_DEBUG_OBJECT (render, "peer allowed caps (%u structure(s)) are %"
- GST_PTR_FORMAT, n, peer_caps);
-
- /* Check if AYUV or ARGB is first */
- for (i = 0; i < n; i++) {
- GstStructure *s = gst_caps_get_structure (peer_caps, i);
- if (gst_structure_has_name (s, "video/x-raw-rgb") &&
- gst_structure_has_field (s, "alpha_mask")) {
- render->use_ARGB = TRUE;
- break;
- } else if (gst_structure_has_name (s, "video/x-raw-yuv")) {
- guint fourcc;
- if (gst_structure_get_fourcc (s, "format", &fourcc) &&
- fourcc == GST_MAKE_FOURCC ('A', 'Y', 'U', 'V')) {
- render->use_ARGB = FALSE;
- break;
- }
- }
- }
- gst_caps_unref (peer_caps);
- }
-}
-
-static gboolean
-gst_text_render_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstTextRender *render = GST_TEXT_RENDER (gst_pad_get_parent (pad));
- GstStructure *structure;
- gboolean ret = FALSE;
- gint width = 0, height = 0;
-
- structure = gst_caps_get_structure (caps, 0);
- gst_structure_get_int (structure, "width", &width);
- gst_structure_get_int (structure, "height", &height);
-
- GST_DEBUG ("Got caps %" GST_PTR_FORMAT, caps);
-
- if (width >= render->image_width && height >= render->image_height) {
- render->width = width;
- render->height = height;
- ret = TRUE;
- }
-
- gst_text_render_check_argb (render);
-
- gst_object_unref (render);
- return ret;
-}
-
-static void
-gst_text_render_fixate_caps (GstPad * pad, GstCaps * caps)
-{
- GstTextRender *render = GST_TEXT_RENDER (gst_pad_get_parent (pad));
- GstStructure *s = gst_caps_get_structure (caps, 0);
-
- GST_DEBUG ("Fixating caps %" GST_PTR_FORMAT, caps);
- gst_structure_fixate_field_nearest_int (s, "width", render->image_width);
- gst_structure_fixate_field_nearest_int (s, "height", render->image_height);
- GST_DEBUG ("Fixated to %" GST_PTR_FORMAT, caps);
-
- gst_object_unref (render);
-}
-
-#define CAIRO_UNPREMULTIPLY(a,r,g,b) G_STMT_START { \
- b = (a > 0) ? MIN ((b * 255 + a / 2) / a, 255) : 0; \
- g = (a > 0) ? MIN ((g * 255 + a / 2) / a, 255) : 0; \
- r = (a > 0) ? MIN ((r * 255 + a / 2) / a, 255) : 0; \
-} G_STMT_END
-
-static void
-gst_text_renderer_image_to_ayuv (GstTextRender * render, guchar * pixbuf,
- int xpos, int ypos, int stride)
-{
- int y; /* text bitmap coordinates */
- guchar *p, *bitp;
- guchar a, r, g, b;
- int width, height;
-
- width = render->image_width;
- height = render->image_height;
- bitp = render->text_image;
-
- for (y = 0; y < height; y++) {
- int n;
- p = pixbuf + (ypos + y) * stride + xpos * 4;
- for (n = 0; n < width; n++) {
- b = bitp[CAIRO_ARGB_B];
- g = bitp[CAIRO_ARGB_G];
- r = bitp[CAIRO_ARGB_R];
- a = bitp[CAIRO_ARGB_A];
- bitp += 4;
-
- /* Cairo uses pre-multiplied ARGB, unpremultiply it */
- CAIRO_UNPREMULTIPLY (a, r, g, b);
-
- *p++ = a;
- *p++ = CLAMP ((int) (((19595 * r) >> 16) + ((38470 * g) >> 16) +
- ((7471 * b) >> 16)), 0, 255);
- *p++ = CLAMP ((int) (-((11059 * r) >> 16) - ((21709 * g) >> 16) +
- ((32768 * b) >> 16) + 128), 0, 255);
- *p++ = CLAMP ((int) (((32768 * r) >> 16) - ((27439 * g) >> 16) -
- ((5329 * b) >> 16) + 128), 0, 255);
- }
- }
-}
-
-static void
-gst_text_renderer_image_to_argb (GstTextRender * render, guchar * pixbuf,
- int xpos, int ypos, int stride)
-{
- int i, j;
- guchar *p, *bitp;
- int width, height;
-
- width = render->image_width;
- height = render->image_height;
- bitp = render->text_image;
-
- for (i = 0; i < height; i++) {
- p = pixbuf + (ypos + i) * stride + xpos * 4;
- for (j = 0; j < width; j++) {
- p[0] = bitp[CAIRO_ARGB_A];
- p[1] = bitp[CAIRO_ARGB_R];
- p[2] = bitp[CAIRO_ARGB_G];
- p[3] = bitp[CAIRO_ARGB_B];
-
- /* Cairo uses pre-multiplied ARGB, unpremultiply it */
- CAIRO_UNPREMULTIPLY (p[0], p[1], p[2], p[3]);
-
- bitp += 4;
- p += 4;
- }
- }
-}
-
-static GstFlowReturn
-gst_text_render_chain (GstPad * pad, GstBuffer * inbuf)
-{
- GstTextRender *render;
- GstFlowReturn ret;
- GstBuffer *outbuf;
- GstCaps *caps = NULL;
- guint8 *data = GST_BUFFER_DATA (inbuf);
- guint size = GST_BUFFER_SIZE (inbuf);
- gint n;
- gint xpos, ypos;
-
- render = GST_TEXT_RENDER (gst_pad_get_parent (pad));
-
- /* somehow pango barfs over "\0" buffers... */
- while (size > 0 &&
- (data[size - 1] == '\r' ||
- data[size - 1] == '\n' || data[size - 1] == '\0')) {
- size--;
- }
-
- /* render text */
- GST_DEBUG ("rendering '%*s'", size, data);
- pango_layout_set_markup (render->layout, (gchar *) data, size);
- gst_text_render_render_pangocairo (render);
-
- gst_text_render_check_argb (render);
-
- if (!render->use_ARGB) {
- caps =
- gst_video_format_new_caps (GST_VIDEO_FORMAT_AYUV, render->width,
- render->height, 1, 1, 1, 1);
- } else {
- caps =
- gst_video_format_new_caps (GST_VIDEO_FORMAT_ARGB, render->width,
- render->height, 1, 1, 1, 1);
- }
-
- if (!gst_pad_set_caps (render->srcpad, caps)) {
- gst_caps_unref (caps);
- GST_ELEMENT_ERROR (render, CORE, NEGOTIATION, (NULL), (NULL));
- ret = GST_FLOW_ERROR;
- goto done;
- }
-
- GST_DEBUG ("Allocating buffer WxH = %dx%d", render->width, render->height);
- ret =
- gst_pad_alloc_buffer_and_set_caps (render->srcpad, GST_BUFFER_OFFSET_NONE,
- render->width * render->height * 4, caps, &outbuf);
-
- if (ret != GST_FLOW_OK)
- goto done;
-
- gst_buffer_copy_metadata (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS);
- data = GST_BUFFER_DATA (outbuf);
-
- if (render->use_ARGB) {
- memset (data, 0, render->width * render->height * 4);
- } else {
- for (n = 0; n < render->width * render->height; n++) {
- data[n * 4] = data[n * 4 + 1] = 0;
- data[n * 4 + 2] = data[n * 4 + 3] = 128;
- }
- }
-
- switch (render->halign) {
- case GST_TEXT_RENDER_HALIGN_LEFT:
- xpos = render->xpad;
- break;
- case GST_TEXT_RENDER_HALIGN_CENTER:
- xpos = (render->width - render->image_width) / 2;
- break;
- case GST_TEXT_RENDER_HALIGN_RIGHT:
- xpos = render->width - render->image_width - render->xpad;
- break;
- default:
- xpos = 0;
- }
-
- switch (render->valign) {
- case GST_TEXT_RENDER_VALIGN_BOTTOM:
- ypos = render->height - render->image_height - render->ypad;
- break;
- case GST_TEXT_RENDER_VALIGN_BASELINE:
- ypos = render->height - (render->image_height + render->ypad);
- break;
- case GST_TEXT_RENDER_VALIGN_TOP:
- ypos = render->ypad;
- break;
- default:
- ypos = render->ypad;
- break;
- }
-
- if (render->text_image) {
- if (render->use_ARGB) {
- gst_text_renderer_image_to_argb (render, data, xpos, ypos,
- render->width * 4);
- } else {
- gst_text_renderer_image_to_ayuv (render, data, xpos, ypos,
- render->width * 4);
- }
- }
-
- ret = gst_pad_push (render->srcpad, outbuf);
-
-done:
- if (caps)
- gst_caps_unref (caps);
- gst_buffer_unref (inbuf);
- gst_object_unref (render);
- return ret;
-}
-
-static void
-gst_text_render_finalize (GObject * object)
-{
- GstTextRender *render = GST_TEXT_RENDER (object);
-
- g_free (render->text_image);
-
- if (render->layout)
- g_object_unref (render->layout);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_text_render_init (GstTextRender * render, GstTextRenderClass * klass)
-{
- GstPadTemplate *template;
-
- /* sink */
- template = gst_static_pad_template_get (&sink_template_factory);
- render->sinkpad = gst_pad_new_from_template (template, "sink");
- gst_object_unref (template);
- gst_pad_set_chain_function (render->sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_render_chain));
- gst_element_add_pad (GST_ELEMENT (render), render->sinkpad);
-
- /* source */
- template = gst_static_pad_template_get (&src_template_factory);
- render->srcpad = gst_pad_new_from_template (template, "src");
- gst_object_unref (template);
- gst_pad_set_fixatecaps_function (render->srcpad,
- GST_DEBUG_FUNCPTR (gst_text_render_fixate_caps));
- gst_pad_set_setcaps_function (render->srcpad,
- GST_DEBUG_FUNCPTR (gst_text_render_setcaps));
-
- gst_element_add_pad (GST_ELEMENT (render), render->srcpad);
-
- render->line_align = DEFAULT_PROP_LINE_ALIGNMENT;
- render->layout =
- pango_layout_new (GST_TEXT_RENDER_GET_CLASS (render)->pango_context);
- pango_layout_set_alignment (render->layout,
- (PangoAlignment) render->line_align);
-
- render->halign = DEFAULT_PROP_HALIGNMENT;
- render->valign = DEFAULT_PROP_VALIGNMENT;
- render->xpad = DEFAULT_PROP_XPAD;
- render->ypad = DEFAULT_PROP_YPAD;
-
- render->width = DEFAULT_RENDER_WIDTH;
- render->height = DEFAULT_RENDER_HEIGHT;
-
- render->use_ARGB = FALSE;
-}
-
-static void
-gst_text_render_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstTextRender *render = GST_TEXT_RENDER (object);
-
- switch (prop_id) {
- case PROP_VALIGNMENT:
- render->valign = g_value_get_enum (value);
- break;
- case PROP_HALIGNMENT:
- render->halign = g_value_get_enum (value);
- break;
- case PROP_LINE_ALIGNMENT:
- render->line_align = g_value_get_enum (value);
- pango_layout_set_alignment (render->layout,
- (PangoAlignment) render->line_align);
- break;
- case PROP_XPAD:
- render->xpad = g_value_get_int (value);
- break;
- case PROP_YPAD:
- render->ypad = g_value_get_int (value);
- break;
- case PROP_FONT_DESC:
- {
- PangoFontDescription *desc;
-
- desc = pango_font_description_from_string (g_value_get_string (value));
- if (desc) {
- GST_LOG ("font description set: %s", g_value_get_string (value));
- GST_OBJECT_LOCK (render);
- pango_layout_set_font_description (render->layout, desc);
- gst_text_render_adjust_values_with_fontdesc (render, desc);
- pango_font_description_free (desc);
- gst_text_render_render_pangocairo (render);
- GST_OBJECT_UNLOCK (render);
- } else {
- GST_WARNING ("font description parse failed: %s",
- g_value_get_string (value));
- }
- break;
- }
-
- default:
- break;
- }
-}
-
-static void
-gst_text_render_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstTextRender *render = GST_TEXT_RENDER (object);
-
- switch (prop_id) {
- case PROP_VALIGNMENT:
- g_value_set_enum (value, render->valign);
- break;
- case PROP_HALIGNMENT:
- g_value_set_enum (value, render->halign);
- break;
- case PROP_LINE_ALIGNMENT:
- g_value_set_enum (value, render->line_align);
- break;
- case PROP_XPAD:
- g_value_set_int (value, render->xpad);
- break;
- case PROP_YPAD:
- g_value_set_int (value, render->ypad);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
diff --git a/ext/pango/gsttextrender.h b/ext/pango/gsttextrender.h
deleted file mode 100644
index 66d37dbf..00000000
--- a/ext/pango/gsttextrender.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef __GST_TEXT_RENDER_H__
-#define __GST_TEXT_RENDER_H__
-
-#include <gst/gst.h>
-#include <pango/pangocairo.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_TEXT_RENDER (gst_text_render_get_type())
-#define GST_TEXT_RENDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
- GST_TYPE_TEXT_RENDER, GstTextRender))
-#define GST_TEXT_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
- GST_TYPE_TEXT_RENDER, GstTextRenderClass))
-#define GST_TEXT_RENDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
- GST_TYPE_TEXT_RENDER, GstTextRenderClass))
-#define GST_IS_TEXT_RENDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
- GST_TYPE_TEXT_RENDER))
-#define GST_IS_TEXT_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
- GST_TYPE_TEXT_RENDER))
-
-typedef struct _GstTextRender GstTextRender;
-typedef struct _GstTextRenderClass GstTextRenderClass;
-
-/**
- * GstTextRenderVAlign:
- * @GST_TEXT_RENDER_VALIGN_BASELINE: draw text on the baseline
- * @GST_TEXT_RENDER_VALIGN_BOTTOM: draw text on the bottom
- * @GST_TEXT_RENDER_VALIGN_TOP: draw test on top
- *
- * Vertical alignment of the text.
- */
-typedef enum {
- GST_TEXT_RENDER_VALIGN_BASELINE,
- GST_TEXT_RENDER_VALIGN_BOTTOM,
- GST_TEXT_RENDER_VALIGN_TOP
-} GstTextRenderVAlign;
-
-/**
- * GstTextRenderHAlign:
- * @GST_TEXT_RENDER_HALIGN_LEFT: align text left
- * @GST_TEXT_RENDER_HALIGN_CENTER: align text center
- * @GST_TEXT_RENDER_HALIGN_RIGHT: align text right
- *
- * Horizontal alignment of the text.
- */
-typedef enum {
- GST_TEXT_RENDER_HALIGN_LEFT,
- GST_TEXT_RENDER_HALIGN_CENTER,
- GST_TEXT_RENDER_HALIGN_RIGHT
-} GstTextRenderHAlign;
-
-/**
- * GstTextRenderLineAlign:
- * @GST_TEXT_RENDER_LINE_ALIGN_LEFT: lines are left-aligned
- * @GST_TEXT_RENDER_LINE_ALIGN_CENTER: lines are center-aligned
- * @GST_TEXT_RENDER_LINE_ALIGN_RIGHT: lines are right-aligned
- *
- * Alignment of text lines relative to each other
- */
-typedef enum {
- GST_TEXT_RENDER_LINE_ALIGN_LEFT = PANGO_ALIGN_LEFT,
- GST_TEXT_RENDER_LINE_ALIGN_CENTER = PANGO_ALIGN_CENTER,
- GST_TEXT_RENDER_LINE_ALIGN_RIGHT = PANGO_ALIGN_RIGHT
-} GstTextRenderLineAlign;
-
-/**
- * GstTextRender:
- *
- * Opaque textrender data structure.
- */
-struct _GstTextRender {
- GstElement element;
-
- GstPad *sinkpad, *srcpad;
- gint width;
- gint height;
- PangoLayout *layout;
- gdouble shadow_offset;
- gdouble outline_offset;
- guchar *text_image;
- gint image_width;
- gint image_height;
- gint baseline_y;
- gboolean use_ARGB;
-
- GstTextRenderVAlign valign;
- GstTextRenderHAlign halign;
- GstTextRenderLineAlign line_align;
-
- gint xpad;
- gint ypad;
-};
-
-struct _GstTextRenderClass {
- GstElementClass parent_class;
-
- PangoContext *pango_context;
-};
-
-GType gst_text_render_get_type(void) G_GNUC_CONST;
-
-G_END_DECLS
-
-#endif /* __GST_TEXT_RENDER_H */
diff --git a/ext/pango/gsttimeoverlay.c b/ext/pango/gsttimeoverlay.c
deleted file mode 100644
index a342a51e..00000000
--- a/ext/pango/gsttimeoverlay.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) <2005> Tim-Philipp Müller <tim@centricular.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-timeoverlay
- * @see_also: #GstTextOverlay, #GstClockOverlay
- *
- * This element overlays the buffer time stamps of a video stream on
- * top of itself. You can position the text and configure the font details
- * using the properties of the #GstTextOverlay class. By default, the
- * time stamp is displayed in the top left corner of the picture, with some
- * padding to the left and to the top.
- *
- * <refsect2>
- * |[
- * gst-launch -v videotestsrc ! timeoverlay ! xvimagesink
- * ]| Display the time stamps in the top left
- * corner of the video picture.
- * |[
- * gst-launch -v videotestsrc ! timeoverlay halign=right valign=bottom text="Stream time:" shaded-background=true ! xvimagesink
- * ]| Another pipeline that displays the time stamps with some leading
- * text in the bottom right corner of the video picture, with the background
- * of the text being shaded in order to make it more legible on top of a
- * bright video background.
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gst/video/video.h>
-
-#include <gsttimeoverlay.h>
-
-GST_BOILERPLATE (GstTimeOverlay, gst_time_overlay, GstTextOverlay,
- GST_TYPE_TEXT_OVERLAY);
-
-static void
-gst_time_overlay_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class, "Time overlay",
- "Filter/Editor/Video",
- "Overlays buffer time stamps on a video stream",
- "Tim-Philipp Müller <tim@centricular.net>");
-}
-
-static gchar *
-gst_time_overlay_render_time (GstTimeOverlay * overlay, GstClockTime time)
-{
- guint hours, mins, secs, msecs;
-
- if (!GST_CLOCK_TIME_IS_VALID (time))
- return g_strdup ("");
-
- hours = (guint) (time / (GST_SECOND * 60 * 60));
- mins = (guint) ((time / (GST_SECOND * 60)) % 60);
- secs = (guint) ((time / GST_SECOND) % 60);
- msecs = (guint) ((time % GST_SECOND) / (1000 * 1000));
-
- return g_strdup_printf ("%u:%02u:%02u.%03u", hours, mins, secs, msecs);
-}
-
-/* Called with lock held */
-static gchar *
-gst_time_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame)
-{
- GstClockTime time = GST_BUFFER_TIMESTAMP (video_frame);
- gchar *time_str, *txt, *ret;
-
- overlay->need_render = TRUE;
-
- if (!GST_CLOCK_TIME_IS_VALID (time)) {
- GST_DEBUG ("buffer without valid timestamp");
- return g_strdup ("");
- }
-
- GST_DEBUG ("buffer with timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (time));
-
- txt = g_strdup (overlay->default_text);
-
- time_str = gst_time_overlay_render_time (GST_TIME_OVERLAY (overlay), time);
- if (txt != NULL && *txt != '\0') {
- ret = g_strdup_printf ("%s %s", txt, time_str);
- } else {
- ret = time_str;
- time_str = NULL;
- }
-
- g_free (txt);
- g_free (time_str);
-
- return ret;
-}
-
-static void
-gst_time_overlay_class_init (GstTimeOverlayClass * klass)
-{
- GstTextOverlayClass *gsttextoverlay_class;
-
- gsttextoverlay_class = (GstTextOverlayClass *) klass;
-
- gsttextoverlay_class->get_text = gst_time_overlay_get_text;
-}
-
-static void
-gst_time_overlay_init (GstTimeOverlay * overlay, GstTimeOverlayClass * klass)
-{
- PangoFontDescription *font_description;
- GstTextOverlay *textoverlay;
- PangoContext *context;
-
- textoverlay = GST_TEXT_OVERLAY (overlay);
-
- context = GST_TEXT_OVERLAY_CLASS (klass)->pango_context;
-
- pango_context_set_language (context, pango_language_from_string ("en_US"));
- pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
-
- font_description = pango_font_description_new ();
- pango_font_description_set_family_static (font_description, "Monospace");
- pango_font_description_set_style (font_description, PANGO_STYLE_NORMAL);
- pango_font_description_set_variant (font_description, PANGO_VARIANT_NORMAL);
- pango_font_description_set_weight (font_description, PANGO_WEIGHT_NORMAL);
- pango_font_description_set_stretch (font_description, PANGO_STRETCH_NORMAL);
- pango_font_description_set_size (font_description, 18 * PANGO_SCALE);
- pango_context_set_font_description (context, font_description);
- pango_font_description_free (font_description);
-
- textoverlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP;
- textoverlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT;
-}
diff --git a/ext/pango/gsttimeoverlay.h b/ext/pango/gsttimeoverlay.h
deleted file mode 100644
index 5fbfba97..00000000
--- a/ext/pango/gsttimeoverlay.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) <2005> Tim-Philipp Müller <tim@centricular.net>
- *
- * 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_TIME_OVERLAY_H__
-#define __GST_TIME_OVERLAY_H__
-
-#include "gsttextoverlay.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_TIME_OVERLAY \
- (gst_time_overlay_get_type())
-#define GST_TIME_OVERLAY(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TIME_OVERLAY,GstTimeOverlay))
-#define GST_TIME_OVERLAY_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TIME_OVERLAY,GstTimeOverlayClass))
-#define GST_IS_TIME_OVERLAY(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TIME_OVERLAY))
-#define GST_IS_TIME_OVERLAY_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TIME_OVERLAY))
-
-typedef struct _GstTimeOverlay GstTimeOverlay;
-typedef struct _GstTimeOverlayClass GstTimeOverlayClass;
-
-/**
- * GstTimeOverlay:
- *
- * Opaque timeoverlay data structure.
- */
-struct _GstTimeOverlay {
- GstTextOverlay textoverlay;
-};
-
-struct _GstTimeOverlayClass {
- GstTextOverlayClass parent_class;
-};
-
-GType gst_time_overlay_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_TIME_OVERLAY_H__ */
-
diff --git a/ext/theora/Makefile.am b/ext/theora/Makefile.am
deleted file mode 100644
index 52164b04..00000000
--- a/ext/theora/Makefile.am
+++ /dev/null
@@ -1,20 +0,0 @@
-plugin_LTLIBRARIES = libgsttheora.la
-
-noinst_HEADERS = gsttheoraenc.h \
- gsttheoradec.h \
- gsttheoraparse.h
-
-libgsttheora_la_SOURCES = gsttheora.c \
- gsttheoraenc.c \
- gsttheoradec.c \
- gsttheoraparse.c
-
-libgsttheora_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(THEORA_CFLAGS)
-libgsttheora_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/tag/libgsttag-$(GST_MAJORMINOR).la \
- $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la \
- $(GST_LIBS) \
- $(THEORA_LIBS)
-libgsttheora_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgsttheora_la_LIBTOOLFLAGS = --tag=disable-static
-
diff --git a/ext/theora/gsttheora.c b/ext/theora/gsttheora.c
deleted file mode 100644
index 37f32114..00000000
--- a/ext/theora/gsttheora.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 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.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <gst/gst.h>
-
-extern GType gst_theora_dec_get_type (void);
-extern GType gst_theora_enc_get_type (void);
-extern GType gst_theora_parse_get_type (void);
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- if (!gst_element_register (plugin, "theoradec", GST_RANK_PRIMARY,
- gst_theora_dec_get_type ()))
- return FALSE;
-
- if (!gst_element_register (plugin, "theoraenc", GST_RANK_PRIMARY,
- gst_theora_enc_get_type ()))
- return FALSE;
-
- if (!gst_element_register (plugin, "theoraparse", GST_RANK_NONE,
- gst_theora_parse_get_type ()))
- return FALSE;
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "theora",
- "Theora plugin library",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/theora/gsttheoradec.c b/ext/theora/gsttheoradec.c
deleted file mode 100644
index 7ec3e920..00000000
--- a/ext/theora/gsttheoradec.c
+++ /dev/null
@@ -1,1467 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 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.
- */
-
-/**
- * SECTION:element-theoradec
- * @see_also: theoraenc, oggdemux
- *
- * This element decodes theora streams into raw video
- * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
- * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
- * Foundation</ulink>, based on the VP3 codec.
- *
- * <refsect2>
- * <title>Example pipeline</title>
- * |[
- * gst-launch -v filesrc location=videotestsrc.ogg ! oggdemux ! theoradec ! xvimagesink
- * ]| This example pipeline will decode an ogg stream and decodes the theora video. Refer to
- * the theoraenc example to create the ogg file.
- * </refsect2>
- *
- * Last reviewed on 2006-03-01 (0.10.4)
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gsttheoradec.h"
-#include <gst/tag/tag.h>
-#include <gst/video/video.h>
-
-#define GST_CAT_DEFAULT theoradec_debug
-GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
-
-#define THEORA_DEF_CROP TRUE
-enum
-{
- ARG_0,
- ARG_CROP
-};
-
-static const GstElementDetails theora_dec_details =
-GST_ELEMENT_DETAILS ("Theora video decoder",
- "Codec/Decoder/Video",
- "decode raw theora streams to raw YUV video",
- "Benjamin Otte <in7y118@public.uni-hamburg.de>, "
- "Wim Taymans <wim@fluendo.com>");
-
-static GstStaticPadTemplate theora_dec_src_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-raw-yuv, "
- "format = (fourcc) { I420, Y42B, Y444 }, "
- "framerate = (fraction) [0/1, MAX], "
- "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
- );
-
-static GstStaticPadTemplate theora_dec_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-theora")
- );
-
-GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, GST_TYPE_ELEMENT);
-
-static void theora_dec_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void theora_dec_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-
-static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event);
-static gboolean theora_dec_setcaps (GstPad * pad, GstCaps * caps);
-static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buffer);
-static GstStateChangeReturn theora_dec_change_state (GstElement * element,
- GstStateChange transition);
-static gboolean theora_dec_src_event (GstPad * pad, GstEvent * event);
-static gboolean theora_dec_src_query (GstPad * pad, GstQuery * query);
-static gboolean theora_dec_src_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value);
-
-#if 0
-static const GstFormat *theora_get_formats (GstPad * pad);
-#endif
-#if 0
-static const GstEventMask *theora_get_event_masks (GstPad * pad);
-#endif
-static const GstQueryType *theora_get_query_types (GstPad * pad);
-
-
-static void
-gst_theora_dec_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_dec_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_dec_sink_factory));
- gst_element_class_set_details (element_class, &theora_dec_details);
-}
-
-static void
-gst_theora_dec_class_init (GstTheoraDecClass * klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gobject_class->set_property = theora_dec_set_property;
- gobject_class->get_property = theora_dec_get_property;
-
- g_object_class_install_property (gobject_class, ARG_CROP,
- g_param_spec_boolean ("crop", "Crop",
- "Crop the image to the visible region", THEORA_DEF_CROP,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state = theora_dec_change_state;
-
- GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
-}
-
-static void
-gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class)
-{
- dec->sinkpad =
- gst_pad_new_from_static_template (&theora_dec_sink_factory, "sink");
- gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
- gst_pad_set_setcaps_function (dec->sinkpad, theora_dec_setcaps);
- gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain);
- gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
-
- dec->srcpad =
- gst_pad_new_from_static_template (&theora_dec_src_factory, "src");
- gst_pad_set_event_function (dec->srcpad, theora_dec_src_event);
- gst_pad_set_query_type_function (dec->srcpad, theora_get_query_types);
- gst_pad_set_query_function (dec->srcpad, theora_dec_src_query);
- gst_pad_use_fixed_caps (dec->srcpad);
-
- gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
-
- dec->crop = THEORA_DEF_CROP;
- dec->gather = NULL;
- dec->decode = NULL;
- dec->queued = NULL;
- dec->pendingevents = NULL;
-}
-
-static void
-gst_theora_dec_reset (GstTheoraDec * dec)
-{
- dec->need_keyframe = TRUE;
- dec->last_timestamp = -1;
- dec->discont = TRUE;
- dec->frame_nr = -1;
- dec->seqnum = gst_util_seqnum_next ();
- gst_segment_init (&dec->segment, GST_FORMAT_TIME);
-
- GST_OBJECT_LOCK (dec);
- dec->proportion = 1.0;
- dec->earliest_time = -1;
- GST_OBJECT_UNLOCK (dec);
-
- g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (dec->queued);
- dec->queued = NULL;
- g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (dec->gather);
- dec->gather = NULL;
- g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (dec->decode);
- dec->decode = NULL;
- g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (dec->pendingevents);
- dec->pendingevents = NULL;
-
- if (dec->tags) {
- gst_tag_list_free (dec->tags);
- dec->tags = NULL;
- }
-}
-
-#if 0
-static const GstFormat *
-theora_get_formats (GstPad * pad)
-{
- static GstFormat src_formats[] = {
- GST_FORMAT_DEFAULT, /* frames in this case */
- GST_FORMAT_TIME,
- GST_FORMAT_BYTES,
- 0
- };
- static GstFormat sink_formats[] = {
- GST_FORMAT_DEFAULT,
- GST_FORMAT_TIME,
- 0
- };
-
- return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
-}
-#endif
-
-#if 0
-static const GstEventMask *
-theora_get_event_masks (GstPad * pad)
-{
- static const GstEventMask theora_src_event_masks[] = {
- {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_FLUSH},
- {0,}
- };
-
- return theora_src_event_masks;
-}
-#endif
-
-static const GstQueryType *
-theora_get_query_types (GstPad * pad)
-{
- static const GstQueryType theora_src_query_types[] = {
- GST_QUERY_POSITION,
- GST_QUERY_DURATION,
- GST_QUERY_CONVERT,
- 0
- };
-
- return theora_src_query_types;
-}
-
-
-static gboolean
-theora_dec_src_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = TRUE;
- GstTheoraDec *dec;
- guint64 scale = 1;
-
- if (src_format == *dest_format) {
- *dest_value = src_value;
- return TRUE;
- }
-
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
-
- /* we need the info part before we can done something */
- if (!dec->have_header)
- goto no_header;
-
- switch (src_format) {
- case GST_FORMAT_BYTES:
- switch (*dest_format) {
- case GST_FORMAT_DEFAULT:
- *dest_value = gst_util_uint64_scale_int (src_value, 8,
- dec->info.pic_height * dec->info.pic_width * dec->output_bpp);
- break;
- case GST_FORMAT_TIME:
- /* seems like a rather silly conversion, implement me if you like */
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- scale =
- dec->output_bpp * (dec->info.pic_width * dec->info.pic_height) /
- 8;
- case GST_FORMAT_DEFAULT:
- *dest_value = scale * gst_util_uint64_scale (src_value,
- dec->info.fps_numerator, dec->info.fps_denominator * GST_SECOND);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_DEFAULT:
- switch (*dest_format) {
- case GST_FORMAT_TIME:
- *dest_value = gst_util_uint64_scale (src_value,
- GST_SECOND * dec->info.fps_denominator, dec->info.fps_numerator);
- break;
- case GST_FORMAT_BYTES:
- *dest_value = gst_util_uint64_scale_int (src_value,
- dec->output_bpp * dec->info.pic_width * dec->info.pic_height, 8);
- break;
- default:
- res = FALSE;
- }
- break;
- default:
- res = FALSE;
- }
-done:
- gst_object_unref (dec);
- return res;
-
- /* ERRORS */
-no_header:
- {
- GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
- res = FALSE;
- goto done;
- }
-}
-
-#if 0
-static gboolean
-theora_dec_sink_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = TRUE;
- GstTheoraDec *dec;
-
- if (src_format == *dest_format) {
- *dest_value = src_value;
- return TRUE;
- }
-
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
-
- /* we need the info part before we can done something */
- if (!dec->have_header)
- goto no_header;
-
- switch (src_format) {
- case GST_FORMAT_DEFAULT:
- switch (*dest_format) {
- case GST_FORMAT_TIME:
- *dest_value = _theora_granule_start_time (dec, src_value);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_DEFAULT:
- {
- guint rest;
-
- /* framecount */
- *dest_value = gst_util_uint64_scale (src_value,
- dec->info.fps_numerator, GST_SECOND * dec->info.fps_denominator);
-
- /* funny way of calculating granulepos in theora */
- rest = *dest_value / dec->info.keyframe_granule_shift;
- *dest_value -= rest;
- *dest_value <<= dec->granule_shift;
- *dest_value += rest;
- break;
- }
- default:
- res = FALSE;
- break;
- }
- break;
- default:
- res = FALSE;
- }
-done:
- gst_object_unref (dec);
- return res;
-
- /* ERRORS */
-no_header:
- {
- GST_DEBUG_OBJECT (dec, "no header yet, cannot convert");
- res = FALSE;
- goto done;
- }
-}
-#endif
-
-static gboolean
-theora_dec_src_query (GstPad * pad, GstQuery * query)
-{
- GstTheoraDec *dec;
-
- gboolean res = FALSE;
-
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- {
- gint64 value;
- GstFormat format;
- gint64 time;
-
- /* parse format */
- gst_query_parse_position (query, &format, NULL);
-
- time = dec->last_timestamp;
- time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
-
- GST_LOG_OBJECT (dec,
- "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
-
- if (!(res =
- theora_dec_src_convert (pad, GST_FORMAT_TIME, time, &format,
- &value)))
- goto error;
-
- gst_query_set_position (query, format, value);
-
- GST_LOG_OBJECT (dec,
- "query %p: we return %" G_GINT64_FORMAT " (format %u)", query, value,
- format);
- break;
- }
- case GST_QUERY_DURATION:
- {
- /* forward to peer for total */
- res = gst_pad_peer_query (dec->sinkpad, query);
- if (!res)
- goto error;
-
- break;
- }
- case GST_QUERY_CONVERT:
- {
- GstFormat src_fmt, dest_fmt;
- gint64 src_val, dest_val;
-
- gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
- if (!(res =
- theora_dec_src_convert (pad, src_fmt, src_val, &dest_fmt,
- &dest_val)))
- goto error;
-
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-done:
- gst_object_unref (dec);
-
- return res;
-
- /* ERRORS */
-error:
- {
- GST_DEBUG_OBJECT (dec, "query failed");
- goto done;
- }
-}
-
-static gboolean
-theora_dec_src_event (GstPad * pad, GstEvent * event)
-{
- gboolean res = TRUE;
- GstTheoraDec *dec;
-
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- {
- GstFormat format, tformat;
- gdouble rate;
- GstEvent *real_seek;
- GstSeekFlags flags;
- GstSeekType cur_type, stop_type;
- gint64 cur, stop;
- gint64 tcur, tstop;
- guint32 seqnum;
-
- gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
- &stop_type, &stop);
- seqnum = gst_event_get_seqnum (event);
- gst_event_unref (event);
-
- /* we have to ask our peer to seek to time here as we know
- * nothing about how to generate a granulepos from the src
- * formats or anything.
- *
- * First bring the requested format to time
- */
- tformat = GST_FORMAT_TIME;
- if (!(res = theora_dec_src_convert (pad, format, cur, &tformat, &tcur)))
- goto convert_error;
- if (!(res = theora_dec_src_convert (pad, format, stop, &tformat, &tstop)))
- goto convert_error;
-
- /* then seek with time on the peer */
- real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
- flags, cur_type, tcur, stop_type, tstop);
- gst_event_set_seqnum (real_seek, seqnum);
-
- res = gst_pad_push_event (dec->sinkpad, real_seek);
- break;
- }
- case GST_EVENT_QOS:
- {
- gdouble proportion;
- GstClockTimeDiff diff;
- GstClockTime timestamp;
-
- gst_event_parse_qos (event, &proportion, &diff, &timestamp);
-
- /* we cannot randomly skip frame decoding since we don't have
- * B frames. we can however use the timestamp and diff to not
- * push late frames. This would at least save us the time to
- * crop/memcpy the data. */
- GST_OBJECT_LOCK (dec);
- dec->proportion = proportion;
- dec->earliest_time = timestamp + diff;
- GST_OBJECT_UNLOCK (dec);
-
- GST_DEBUG_OBJECT (dec, "got QoS %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
- GST_TIME_ARGS (timestamp), diff);
-
- res = gst_pad_push_event (dec->sinkpad, event);
- break;
- }
- default:
- res = gst_pad_push_event (dec->sinkpad, event);
- break;
- }
-done:
- gst_object_unref (dec);
-
- return res;
-
- /* ERRORS */
-convert_error:
- {
- GST_DEBUG_OBJECT (dec, "could not convert format");
- goto done;
- }
-}
-
-static gboolean
-theora_dec_sink_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret = FALSE;
- GstTheoraDec *dec;
-
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
-
- GST_LOG_OBJECT (dec, "handling event");
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- ret = gst_pad_push_event (dec->srcpad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- gst_theora_dec_reset (dec);
- ret = gst_pad_push_event (dec->srcpad, event);
- break;
- case GST_EVENT_EOS:
- ret = gst_pad_push_event (dec->srcpad, event);
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- gboolean update;
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
-
- /* we need TIME format */
- if (format != GST_FORMAT_TIME)
- goto newseg_wrong_format;
-
- GST_DEBUG_OBJECT (dec,
- "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
- ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
- update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
- GST_TIME_ARGS (time));
-
- /* now configure the values */
- gst_segment_set_newsegment_full (&dec->segment, update,
- rate, arate, format, start, stop, time);
- dec->seqnum = gst_event_get_seqnum (event);
-
- /* We don't forward this unless/until the decoder is initialised */
- if (dec->have_header) {
- ret = gst_pad_push_event (dec->srcpad, event);
- } else {
- dec->pendingevents = g_list_append (dec->pendingevents, event);
- ret = TRUE;
- }
- break;
- }
- case GST_EVENT_TAG:
- {
- if (dec->have_header)
- /* and forward */
- ret = gst_pad_push_event (dec->srcpad, event);
- else {
- /* store it to send once we're initialized */
- dec->pendingevents = g_list_append (dec->pendingevents, event);
- ret = TRUE;
- }
- break;
- }
- default:
- ret = gst_pad_push_event (dec->srcpad, event);
- break;
- }
-done:
- gst_object_unref (dec);
-
- return ret;
-
- /* ERRORS */
-newseg_wrong_format:
- {
- GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
- gst_event_unref (event);
- goto done;
- }
-}
-
-static gboolean
-theora_dec_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstTheoraDec *dec;
- GstStructure *s;
- const GValue *codec_data;
-
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
-
- s = gst_caps_get_structure (caps, 0);
-
- /* parse the par, this overrides the encoded par */
- dec->have_par = gst_structure_get_fraction (s, "pixel-aspect-ratio",
- &dec->par_num, &dec->par_den);
-
- if ((codec_data = gst_structure_get_value (s, "codec_data"))) {
- if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
- GstBuffer *buffer;
- guint8 *data;
- guint size;
- guint offset;
-
- buffer = gst_value_get_buffer (codec_data);
-
- offset = 0;
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
-
- while (size > 2) {
- guint psize;
- GstBuffer *buf;
-
- psize = (data[0] << 8) | data[1];
- /* skip header */
- data += 2;
- size -= 2;
- offset += 2;
-
- /* make sure we don't read too much */
- psize = MIN (psize, size);
-
- buf = gst_buffer_create_sub (buffer, offset, psize);
-
- /* first buffer is a discont buffer */
- if (offset == 2)
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
-
- /* now feed it to the decoder we can ignore the error */
- theora_dec_chain (pad, buf);
-
- /* skip the data */
- size -= psize;
- data += psize;
- offset += psize;
- }
- }
- }
-
- gst_object_unref (dec);
-
- return TRUE;
-}
-
-static GstFlowReturn
-theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
-{
- gchar *encoder = NULL;
- GstBuffer *buf;
- GstTagList *list;
-
- GST_DEBUG_OBJECT (dec, "parsing comment packet");
-
- buf = gst_buffer_new ();
- GST_BUFFER_SIZE (buf) = packet->bytes;
- GST_BUFFER_DATA (buf) = packet->packet;
-
- list =
- gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\201theora", 7,
- &encoder);
-
- gst_buffer_unref (buf);
-
- if (!list) {
- GST_ERROR_OBJECT (dec, "couldn't decode comments");
- list = gst_tag_list_new ();
- }
- if (encoder) {
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
- GST_TAG_ENCODER, encoder, NULL);
- g_free (encoder);
- }
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
- GST_TAG_ENCODER_VERSION, dec->info.version_major,
- GST_TAG_VIDEO_CODEC, "Theora", NULL);
-
- if (dec->info.target_bitrate > 0) {
- gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
- GST_TAG_BITRATE, dec->info.target_bitrate,
- GST_TAG_NOMINAL_BITRATE, dec->info.target_bitrate, NULL);
- }
-
- dec->tags = list;
-
- return GST_FLOW_OK;
-}
-
-static GstFlowReturn
-theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
-{
- GstCaps *caps;
- gint par_num, par_den;
- GstFlowReturn ret = GST_FLOW_OK;
- GList *walk;
- guint32 fourcc;
-
- GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
- dec->info.fps_numerator, dec->info.fps_denominator,
- dec->info.aspect_numerator, dec->info.aspect_denominator);
-
- /* calculate par
- * the info.aspect_* values reflect PAR;
- * 0:x and x:0 are allowed and can be interpreted as 1:1.
- */
- if (dec->have_par) {
- /* we had a par on the sink caps, override the encoded par */
- GST_DEBUG_OBJECT (dec, "overriding with input PAR");
- par_num = dec->par_num;
- par_den = dec->par_den;
- } else {
- /* take encoded par */
- par_num = dec->info.aspect_numerator;
- par_den = dec->info.aspect_denominator;
- }
- if (par_num == 0 || par_den == 0) {
- par_num = par_den = 1;
- }
- /* theora has:
- *
- * width/height : dimension of the encoded frame
- * pic_width/pic_height : dimension of the visible part
- * pic_x/pic_y : offset in encoded frame where visible part starts
- */
- GST_DEBUG_OBJECT (dec, "dimension %dx%d, PAR %d/%d", dec->info.pic_width,
- dec->info.pic_height, par_num, par_den);
- GST_DEBUG_OBJECT (dec, "frame dimension %dx%d, offset %d:%d",
- dec->info.pic_width, dec->info.pic_height,
- dec->info.pic_x, dec->info.pic_y);
-
- if (dec->info.pixel_fmt == TH_PF_420) {
- dec->output_bpp = 12; /* Average bits per pixel. */
- fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
- } else if (dec->info.pixel_fmt == TH_PF_422) {
- dec->output_bpp = 16;
- fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
- } else if (dec->info.pixel_fmt == TH_PF_444) {
- dec->output_bpp = 24;
- fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
- } else {
- GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
- return GST_FLOW_ERROR;
- }
-
- if (dec->crop) {
- dec->width = dec->info.pic_width;
- dec->height = dec->info.pic_height;
- dec->offset_x = dec->info.pic_x;
- dec->offset_y = dec->info.pic_y;
- /* Ensure correct offsets in chroma for formats that need it
- * by rounding the offset. libtheora will add proper pixels,
- * so no need to handle them ourselves. */
- if (dec->offset_x & 1 && dec->info.pixel_fmt != TH_PF_444) {
- dec->offset_x--;
- dec->width++;
- }
- if (dec->offset_y & 1 && dec->info.pixel_fmt == TH_PF_420) {
- dec->offset_y--;
- dec->height++;
- }
- } else {
- /* no cropping, use the encoded dimensions */
- dec->width = dec->info.frame_width;
- dec->height = dec->info.frame_height;
- dec->offset_x = 0;
- dec->offset_y = 0;
- }
-
- GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
- dec->width, dec->height, dec->offset_x, dec->offset_y);
-
- /* done */
- dec->decoder = th_decode_alloc (&dec->info, dec->setup);
-
- caps = gst_caps_new_simple ("video/x-raw-yuv",
- "format", GST_TYPE_FOURCC, fourcc,
- "framerate", GST_TYPE_FRACTION,
- dec->info.fps_numerator, dec->info.fps_denominator,
- "pixel-aspect-ratio", GST_TYPE_FRACTION, par_num, par_den,
- "width", G_TYPE_INT, dec->width, "height", G_TYPE_INT, dec->height, NULL);
- gst_pad_set_caps (dec->srcpad, caps);
- gst_caps_unref (caps);
-
- dec->have_header = TRUE;
-
- if (dec->pendingevents) {
- for (walk = dec->pendingevents; walk; walk = g_list_next (walk))
- gst_pad_push_event (dec->srcpad, GST_EVENT_CAST (walk->data));
- g_list_free (dec->pendingevents);
- dec->pendingevents = NULL;
- }
-
- if (dec->tags) {
- gst_element_found_tags_for_pad (GST_ELEMENT_CAST (dec), dec->srcpad,
- dec->tags);
- dec->tags = NULL;
- }
-
- return ret;
-}
-
-static GstFlowReturn
-theora_handle_header_packet (GstTheoraDec * dec, ogg_packet * packet)
-{
- GstFlowReturn res;
- int ret;
-
- GST_DEBUG_OBJECT (dec, "parsing header packet");
-
- ret = th_decode_headerin (&dec->info, &dec->comment, &dec->setup, packet);
- if (ret < 0)
- goto header_read_error;
-
- switch (packet->packet[0]) {
- case 0x81:
- res = theora_handle_comment_packet (dec, packet);
- break;
- case 0x82:
- res = theora_handle_type_packet (dec, packet);
- break;
- default:
- /* ignore */
- g_warning ("unknown theora header packet found");
- case 0x80:
- /* nothing special, this is the identification header */
- res = GST_FLOW_OK;
- break;
- }
- return res;
-
- /* ERRORS */
-header_read_error:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
- (NULL), ("couldn't read header packet"));
- return GST_FLOW_ERROR;
- }
-}
-
-/* returns TRUE if buffer is within segment, else FALSE.
- * if Buffer is on segment border, it's timestamp and duration will be clipped */
-static gboolean
-clip_buffer (GstTheoraDec * dec, GstBuffer * buf)
-{
- gboolean res = TRUE;
- GstClockTime in_ts, in_dur, stop;
- gint64 cstart, cstop;
-
- in_ts = GST_BUFFER_TIMESTAMP (buf);
- in_dur = GST_BUFFER_DURATION (buf);
-
- GST_LOG_OBJECT (dec,
- "timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT,
- GST_TIME_ARGS (in_ts), GST_TIME_ARGS (in_dur));
-
- /* can't clip without TIME segment */
- if (dec->segment.format != GST_FORMAT_TIME)
- goto beach;
-
- /* we need a start time */
- if (!GST_CLOCK_TIME_IS_VALID (in_ts))
- goto beach;
-
- /* generate valid stop, if duration unknown, we have unknown stop */
- stop =
- GST_CLOCK_TIME_IS_VALID (in_dur) ? (in_ts + in_dur) : GST_CLOCK_TIME_NONE;
-
- /* now clip */
- if (!(res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME,
- in_ts, stop, &cstart, &cstop)))
- goto beach;
-
- /* update timestamp and possibly duration if the clipped stop time is
- * valid */
- GST_BUFFER_TIMESTAMP (buf) = cstart;
- if (GST_CLOCK_TIME_IS_VALID (cstop))
- GST_BUFFER_DURATION (buf) = cstop - cstart;
-
-beach:
- GST_LOG_OBJECT (dec, "%sdropping", (res ? "not " : ""));
- return res;
-}
-
-static GstFlowReturn
-theora_dec_push_forward (GstTheoraDec * dec, GstBuffer * buf)
-{
- GstFlowReturn result = GST_FLOW_OK;
-
- if (clip_buffer (dec, buf)) {
- if (dec->discont) {
- GST_LOG_OBJECT (dec, "setting DISCONT");
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
- dec->discont = FALSE;
- }
- result = gst_pad_push (dec->srcpad, buf);
- } else {
- gst_buffer_unref (buf);
- }
-
- return result;
-}
-
-static GstFlowReturn
-theora_dec_push_reverse (GstTheoraDec * dec, GstBuffer * buf)
-{
- GstFlowReturn result = GST_FLOW_OK;
-
- dec->queued = g_list_prepend (dec->queued, buf);
-
- return result;
-}
-
-/* Allocate buffer and copy image data into Y444 format */
-static GstFlowReturn
-theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf, GstBuffer ** out)
-{
- gint width, height, stride;
- GstFlowReturn result;
- int i, plane;
- GstVideoFormat format;
- guint8 *dest, *src;
-
- switch (dec->info.pixel_fmt) {
- case TH_PF_444:
- format = GST_VIDEO_FORMAT_Y444;
- break;
- case TH_PF_420:
- format = GST_VIDEO_FORMAT_I420;
- break;
- case TH_PF_422:
- format = GST_VIDEO_FORMAT_Y42B;
- break;
- default:
- g_assert_not_reached ();
- }
-
- result =
- gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
- gst_video_format_get_size (format, dec->width, dec->height),
- GST_PAD_CAPS (dec->srcpad), out);
- if (G_UNLIKELY (result != GST_FLOW_OK)) {
- GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
- gst_flow_get_name (result));
- return result;
- }
-
- for (plane = 0; plane < 3; plane++) {
- width = gst_video_format_get_component_width (format, plane, dec->width);
- height = gst_video_format_get_component_height (format, plane, dec->height);
- stride = gst_video_format_get_row_stride (format, plane, dec->width);
-
- dest =
- GST_BUFFER_DATA (*out) + gst_video_format_get_component_offset (format,
- plane, dec->width, dec->height);
- src = buf[plane].data;
- src += ((height == dec->height) ? dec->offset_y : dec->offset_y / 2)
- * buf[plane].stride;
- src += (width == dec->width) ? dec->offset_x : dec->offset_x / 2;
-
- for (i = 0; i < height; i++) {
- memcpy (dest, src, width);
-
- dest += stride;
- src += buf[plane].stride;
- }
- }
-
- return GST_FLOW_OK;
-}
-
-static GstFlowReturn
-theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet,
- GstClockTime outtime, GstClockTime outdur)
-{
- /* normal data packet */
- th_ycbcr_buffer buf;
- GstBuffer *out;
- gboolean keyframe;
- GstFlowReturn result;
- ogg_int64_t gp;
-
- if (G_UNLIKELY (!dec->have_header))
- goto not_initialized;
-
- /* get timestamp and durations */
- if (outtime == -1)
- outtime = dec->last_timestamp;
- if (outdur == -1)
- outdur = gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator,
- dec->info.fps_numerator);
-
- /* calculate expected next timestamp */
- if (outtime != -1 && outdur != -1)
- dec->last_timestamp = outtime + outdur;
-
- /* the second most significant bit of the first data byte is cleared
- * for keyframes. We can only check it if it's not a zero-length packet. */
- keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0);
- if (G_UNLIKELY (keyframe)) {
- GST_DEBUG_OBJECT (dec, "we have a keyframe");
- dec->need_keyframe = FALSE;
- } else if (G_UNLIKELY (dec->need_keyframe)) {
- goto dropping;
- }
-
- GST_DEBUG_OBJECT (dec, "parsing data packet");
-
- /* this does the decoding */
- if (G_UNLIKELY (th_decode_packetin (dec->decoder, packet, &gp) < 0))
- goto decode_error;
-
- if (outtime != -1) {
- gboolean need_skip;
- GstClockTime qostime;
-
- /* qos needs to be done on running time */
- qostime = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME,
- outtime);
-
- GST_OBJECT_LOCK (dec);
- /* check for QoS, don't perform the last steps of getting and
- * pushing the buffers that are known to be late. */
- need_skip = dec->earliest_time != -1 && qostime <= dec->earliest_time;
- GST_OBJECT_UNLOCK (dec);
-
- if (need_skip)
- goto dropping_qos;
- }
-
- /* this does postprocessing and set up the decoded frame
- * pointers in our yuv variable */
- if (G_UNLIKELY (th_decode_ycbcr_out (dec->decoder, buf) < 0))
- goto no_yuv;
-
- if (G_UNLIKELY ((buf[0].width != dec->info.frame_width)
- || (buf[0].height != dec->info.frame_height)))
- goto wrong_dimensions;
-
- result = theora_handle_image (dec, buf, &out);
- if (result != GST_FLOW_OK)
- return result;
-
- GST_BUFFER_OFFSET (out) = dec->frame_nr;
- if (dec->frame_nr != -1)
- dec->frame_nr++;
- GST_BUFFER_OFFSET_END (out) = dec->frame_nr;
-
- GST_BUFFER_TIMESTAMP (out) = outtime;
- GST_BUFFER_DURATION (out) = outdur;
-
- if (dec->segment.rate >= 0.0)
- result = theora_dec_push_forward (dec, out);
- else
- result = theora_dec_push_reverse (dec, out);
-
- return result;
-
- /* ERRORS */
-not_initialized:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
- (NULL), ("no header sent yet"));
- return GST_FLOW_ERROR;
- }
-dropping:
- {
- GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe");
- dec->discont = TRUE;
- return GST_FLOW_OK;
- }
-dropping_qos:
- {
- if (dec->frame_nr != -1)
- dec->frame_nr++;
- dec->discont = TRUE;
- GST_WARNING_OBJECT (dec, "dropping frame because of QoS");
- return GST_FLOW_OK;
- }
-decode_error:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
- (NULL), ("theora decoder did not decode data packet"));
- return GST_FLOW_ERROR;
- }
-no_yuv:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE,
- (NULL), ("couldn't read out YUV image"));
- return GST_FLOW_ERROR;
- }
-wrong_dimensions:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT,
- (NULL), ("dimensions of image do not match header"));
- return GST_FLOW_ERROR;
- }
-}
-
-static GstFlowReturn
-theora_dec_decode_buffer (GstTheoraDec * dec, GstBuffer * buf)
-{
- ogg_packet packet;
- GstFlowReturn result = GST_FLOW_OK;
- GstClockTime timestamp, duration;
-
- /* make ogg_packet out of the buffer */
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
- packet.granulepos = -1;
- packet.packetno = 0; /* we don't really care */
- packet.b_o_s = dec->have_header ? 0 : 1;
- /* EOS does not matter for the decoder */
- packet.e_o_s = 0;
-
- GST_LOG_OBJECT (dec, "decode buffer of size %ld", packet.bytes);
-
- /* save last seem timestamp for interpolating the next timestamps using the
- * framerate when we need to */
- timestamp = GST_BUFFER_TIMESTAMP (buf);
- duration = GST_BUFFER_DURATION (buf);
-
- GST_DEBUG_OBJECT (dec, "header=%02x, outtime=%" GST_TIME_FORMAT,
- packet.bytes ? packet.packet[0] : -1, GST_TIME_ARGS (timestamp));
-
- /* switch depending on packet type. A zero byte packet is always a data
- * packet; we don't dereference it in that case. */
- if (packet.bytes && packet.packet[0] & 0x80) {
- if (dec->have_header) {
- GST_WARNING_OBJECT (GST_OBJECT (dec), "Ignoring header");
- goto done;
- }
- result = theora_handle_header_packet (dec, &packet);
- } else {
- result = theora_handle_data_packet (dec, &packet, timestamp, duration);
- }
-
-done:
- return result;
-}
-
-/* For reverse playback we use a technique that can be used for
- * any keyframe based video codec.
- *
- * Input:
- * Buffer decoding order: 7 8 9 4 5 6 1 2 3 EOS
- * Keyframe flag: K K
- * Discont flag: D D D
- *
- * - Each Discont marks a discont in the decoding order.
- * - The keyframes mark where we can start decoding.
- *
- * First we prepend incomming buffers to the gather queue, whenever we receive
- * a discont, we flush out the gather queue.
- *
- * The above data will be accumulated in the gather queue like this:
- *
- * gather queue: 9 8 7
- * D
- *
- * Whe buffer 4 is received (with a DISCONT), we flush the gather queue like
- * this:
- *
- * while (gather)
- * take head of queue and prepend to decode queue.
- * if we copied a keyframe, decode the decode queue.
- *
- * After we flushed the gather queue, we add 4 to the (now empty) gather queue.
- * We get the following situation:
- *
- * gather queue: 4
- * decode queue: 7 8 9
- *
- * After we received 5 (Keyframe) and 6:
- *
- * gather queue: 6 5 4
- * decode queue: 7 8 9
- *
- * When we receive 1 (DISCONT) which triggers a flush of the gather queue:
- *
- * Copy head of the gather queue (6) to decode queue:
- *
- * gather queue: 5 4
- * decode queue: 6 7 8 9
- *
- * Copy head of the gather queue (5) to decode queue. This is a keyframe so we
- * can start decoding.
- *
- * gather queue: 4
- * decode queue: 5 6 7 8 9
- *
- * Decode frames in decode queue, store raw decoded data in output queue, we
- * can take the head of the decode queue and prepend the decoded result in the
- * output queue:
- *
- * gather queue: 4
- * decode queue:
- * output queue: 9 8 7 6 5
- *
- * Now output all the frames in the output queue, picking a frame from the
- * head of the queue.
- *
- * Copy head of the gather queue (4) to decode queue, we flushed the gather
- * queue and can now store input buffer in the gather queue:
- *
- * gather queue: 1
- * decode queue: 4
- *
- * When we receive EOS, the queue looks like:
- *
- * gather queue: 3 2 1
- * decode queue: 4
- *
- * Fill decode queue, first keyframe we copy is 2:
- *
- * gather queue: 1
- * decode queue: 2 3 4
- *
- * Decoded output:
- *
- * gather queue: 1
- * decode queue:
- * output queue: 4 3 2
- *
- * Leftover buffer 1 cannot be decoded and must be discarded.
- */
-static GstFlowReturn
-theora_dec_flush_decode (GstTheoraDec * dec)
-{
- GstFlowReturn res = GST_FLOW_OK;
-
- while (dec->decode) {
- GstBuffer *buf = GST_BUFFER_CAST (dec->decode->data);
-
- GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT,
- buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
-
- /* decode buffer, prepend to output queue */
- res = theora_dec_decode_buffer (dec, buf);
-
- /* don't need it anymore now */
- gst_buffer_unref (buf);
-
- dec->decode = g_list_delete_link (dec->decode, dec->decode);
- }
- while (dec->queued) {
- GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data);
-
- /* iterate ouput queue an push downstream */
- res = gst_pad_push (dec->srcpad, buf);
-
- dec->queued = g_list_delete_link (dec->queued, dec->queued);
- }
-
- return res;
-}
-
-static GstFlowReturn
-theora_dec_chain_reverse (GstTheoraDec * dec, gboolean discont, GstBuffer * buf)
-{
- GstFlowReturn res = GST_FLOW_OK;
-
- /* if we have a discont, move buffers to the decode list */
- if (G_UNLIKELY (discont)) {
- GST_DEBUG_OBJECT (dec, "received discont,gathering buffers");
- while (dec->gather) {
- GstBuffer *gbuf;
- guint8 *data;
-
- gbuf = GST_BUFFER_CAST (dec->gather->data);
- /* remove from the gather list */
- dec->gather = g_list_delete_link (dec->gather, dec->gather);
- /* copy to decode queue */
- dec->decode = g_list_prepend (dec->decode, gbuf);
-
- /* if we copied a keyframe, flush and decode the decode queue */
- data = GST_BUFFER_DATA (gbuf);
- if ((data[0] & 0x40) == 0) {
- GST_DEBUG_OBJECT (dec, "copied keyframe");
- res = theora_dec_flush_decode (dec);
- }
- }
- }
-
- /* add buffer to gather queue */
- GST_DEBUG_OBJECT (dec, "gathering buffer %p, size %u", buf,
- GST_BUFFER_SIZE (buf));
- dec->gather = g_list_prepend (dec->gather, buf);
-
- return res;
-}
-
-static GstFlowReturn
-theora_dec_chain_forward (GstTheoraDec * dec, gboolean discont,
- GstBuffer * buffer)
-{
- GstFlowReturn result;
-
- result = theora_dec_decode_buffer (dec, buffer);
-
- gst_buffer_unref (buffer);
-
- return result;
-}
-
-static GstFlowReturn
-theora_dec_chain (GstPad * pad, GstBuffer * buf)
-{
- GstTheoraDec *dec;
- GstFlowReturn res;
- gboolean discont;
-
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
-
- /* peel of DISCONT flag */
- discont = GST_BUFFER_IS_DISCONT (buf);
-
- /* resync on DISCONT */
- if (G_UNLIKELY (discont)) {
- GST_DEBUG_OBJECT (dec, "received DISCONT buffer");
- dec->need_keyframe = TRUE;
- dec->last_timestamp = -1;
- dec->discont = TRUE;
- }
-
- if (dec->segment.rate > 0.0)
- res = theora_dec_chain_forward (dec, discont, buf);
- else
- res = theora_dec_chain_reverse (dec, discont, buf);
-
- gst_object_unref (dec);
-
- return res;
-}
-
-static GstStateChangeReturn
-theora_dec_change_state (GstElement * element, GstStateChange transition)
-{
- GstTheoraDec *dec = GST_THEORA_DEC (element);
- GstStateChangeReturn ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- th_info_clear (&dec->info);
- th_comment_clear (&dec->comment);
- GST_DEBUG_OBJECT (dec, "Setting have_header to FALSE in READY->PAUSED");
- dec->have_header = FALSE;
- dec->have_par = FALSE;
- gst_theora_dec_reset (dec);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- ret = parent_class->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- th_info_clear (&dec->info);
- th_comment_clear (&dec->comment);
- th_setup_free (dec->setup);
- dec->setup = NULL;
- th_decode_free (dec->decoder);
- dec->decoder = NULL;
- gst_theora_dec_reset (dec);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static void
-theora_dec_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstTheoraDec *dec = GST_THEORA_DEC (object);
-
- switch (prop_id) {
- case ARG_CROP:
- dec->crop = g_value_get_boolean (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-theora_dec_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstTheoraDec *dec = GST_THEORA_DEC (object);
-
- switch (prop_id) {
- case ARG_CROP:
- g_value_set_boolean (value, dec->crop);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
diff --git a/ext/theora/gsttheoradec.h b/ext/theora/gsttheoradec.h
deleted file mode 100644
index 14f806cd..00000000
--- a/ext/theora/gsttheoradec.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 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_THEORADEC_H__
-#define __GST_THEORADEC_H__
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <gst/gst.h>
-#include <theora/theoradec.h>
-#include <string.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_THEORA_DEC \
- (gst_theora_dec_get_type())
-#define GST_THEORA_DEC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_DEC,GstTheoraDec))
-#define GST_THEORA_DEC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_DEC,GstTheoraDecClass))
-#define GST_IS_THEORA_DEC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_DEC))
-#define GST_IS_THEORA_DEC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_DEC))
-
-typedef struct _GstTheoraDec GstTheoraDec;
-typedef struct _GstTheoraDecClass GstTheoraDecClass;
-
-/**
- * GstTheoraDec:
- *
- * Opaque object data structure.
- */
-struct _GstTheoraDec
-{
- GstElement element;
-
- /* Pads */
- GstPad *sinkpad;
- GstPad *srcpad;
-
- /* theora decoder state */
- th_dec_ctx *decoder;
- //theora_state state;
- th_setup_info *setup;
- th_info info;
- th_comment comment;
-
- gboolean have_header;
-
- GstClockTime last_timestamp;
- guint64 frame_nr; /* unused */
- gboolean need_keyframe;
- gint width, height;
- gint offset_x, offset_y;
- gint output_bpp;
-
- gboolean crop;
-
- /* list of buffers that need timestamps */
- GList *queued;
- /* list of raw output buffers */
- GList *output;
- /* gather/decode queues for reverse playback */
- GList *gather;
- GList *decode;
- GList *pendingevents;
-
- GstTagList *tags;
-
- /* segment info */ /* with STREAM_LOCK */
- GstSegment segment;
- gboolean discont;
- guint32 seqnum;
-
- /* QoS stuff */ /* with LOCK*/
- gdouble proportion;
- GstClockTime earliest_time;
-
- gboolean have_par;
- gint par_num;
- gint par_den;
-};
-
-struct _GstTheoraDecClass
-{
- GstElementClass parent_class;
-};
-
-G_END_DECLS
-
-#endif /* __GST_THEORADEC_H__ */
diff --git a/ext/theora/gsttheoraenc.c b/ext/theora/gsttheoraenc.c
deleted file mode 100644
index 121d3820..00000000
--- a/ext/theora/gsttheoraenc.c
+++ /dev/null
@@ -1,1256 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-theoraenc
- * @see_also: theoradec, oggmux
- *
- * This element encodes raw video into a Theora stream.
- * <ulink url="http://www.theora.org/">Theora</ulink> is a royalty-free
- * video codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
- * Foundation</ulink>, based on the VP3 codec.
- *
- * The theora codec internally only supports encoding of images that are a
- * multiple of 16 pixels in both X and Y direction. It is however perfectly
- * possible to encode images with other dimensions because an arbitrary
- * rectangular cropping region can be set up. This element will automatically
- * set up a correct cropping region if the dimensions are not multiples of 16
- * pixels.
- *
- * To control the quality of the encoding, the #GstTheoraEnc::bitrate and
- * #GstTheoraEnc::quality properties can be used. These two properties are
- * mutualy exclusive. Setting the bitrate property will produce a constant
- * bitrate (CBR) stream while setting the quality property will produce a
- * variable bitrate (VBR) stream.
- *
- * <refsect2>
- * <title>Example pipeline</title>
- * |[
- * gst-launch -v videotestsrc num-buffers=1000 ! theoraenc ! oggmux ! filesink location=videotestsrc.ogg
- * ]| This example pipeline will encode a test video source to theora muxed in an
- * ogg container. Refer to the theoradec documentation to decode the create
- * stream.
- * </refsect2>
- *
- * Last reviewed on 2006-03-01 (0.10.4)
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gsttheoraenc.h"
-
-#include <string.h>
-#include <stdlib.h> /* free */
-
-#include <gst/tag/tag.h>
-#include <gst/video/video.h>
-
-#define GST_CAT_DEFAULT theoraenc_debug
-GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
-
-#define GST_TYPE_BORDER_MODE (gst_border_mode_get_type())
-static GType
-gst_border_mode_get_type (void)
-{
- static GType border_mode_type = 0;
- static const GEnumValue border_mode[] = {
- {BORDER_NONE, "No Border", "none"},
- {BORDER_BLACK, "Black Border", "black"},
- {BORDER_MIRROR, "Mirror image in borders", "mirror"},
- {0, NULL, NULL},
- };
-
- if (!border_mode_type) {
- border_mode_type =
- g_enum_register_static ("GstTheoraEncBorderMode", border_mode);
- }
- return border_mode_type;
-}
-
-/* taken from theora/lib/toplevel.c */
-static int
-_ilog (unsigned int v)
-{
- int ret = 0;
-
- while (v) {
- ret++;
- v >>= 1;
- }
- return (ret);
-}
-
-#define THEORA_DEF_BITRATE 0
-#define THEORA_DEF_QUALITY 48
-#define THEORA_DEF_KEYFRAME_AUTO TRUE
-#define THEORA_DEF_KEYFRAME_FREQ 64
-#define THEORA_DEF_KEYFRAME_FREQ_FORCE 64
-#define THEORA_DEF_SPEEDLEVEL 1
-#define THEORA_DEF_VP3_COMPATIBLE FALSE
-#define THEORA_DEF_DROP_FRAMES TRUE
-#define THEORA_DEF_CAP_OVERFLOW TRUE
-#define THEORA_DEF_CAP_UNDERFLOW FALSE
-#define THEORA_DEF_RATE_BUFFER 0
-enum
-{
- ARG_0,
- ARG_CENTER,
- ARG_BORDER,
- ARG_BITRATE,
- ARG_QUALITY,
- ARG_QUICK,
- ARG_KEYFRAME_AUTO,
- ARG_KEYFRAME_FREQ,
- ARG_KEYFRAME_FREQ_FORCE,
- ARG_KEYFRAME_THRESHOLD,
- ARG_KEYFRAME_MINDISTANCE,
- ARG_NOISE_SENSITIVITY,
- ARG_SHARPNESS,
- ARG_SPEEDLEVEL,
- ARG_VP3_COMPATIBLE,
- ARG_DROP_FRAMES,
- ARG_CAP_OVERFLOW,
- ARG_CAP_UNDERFLOW,
- ARG_RATE_BUFFER,
- /* FILL ME */
-};
-
-/* this function does a straight granulepos -> timestamp conversion */
-static GstClockTime
-granulepos_to_timestamp (GstTheoraEnc * theoraenc, ogg_int64_t granulepos)
-{
- guint64 iframe, pframe;
- int shift = theoraenc->info.keyframe_granule_shift;
-
- if (granulepos < 0)
- return GST_CLOCK_TIME_NONE;
-
- iframe = granulepos >> shift;
- pframe = granulepos - (iframe << shift);
-
- /* num and den are 32 bit, so we can safely multiply with GST_SECOND */
- return gst_util_uint64_scale ((guint64) (iframe + pframe),
- GST_SECOND * theoraenc->info.fps_denominator,
- theoraenc->info.fps_numerator);
-}
-
-static const GstElementDetails theora_enc_details =
-GST_ELEMENT_DETAILS ("Theora video encoder",
- "Codec/Encoder/Video",
- "encode raw YUV video to a theora stream",
- "Wim Taymans <wim@fluendo.com>");
-
-static GstStaticPadTemplate theora_enc_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-raw-yuv, "
- "format = (fourcc) { I420, Y42B, Y444 }, "
- "framerate = (fraction) [0/1, MAX], "
- "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]")
- );
-
-static GstStaticPadTemplate theora_enc_src_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-theora")
- );
-
-static void
-_do_init (GType object_type)
-{
- const GInterfaceInfo preset_interface_info = {
- NULL, /* interface_init */
- NULL, /* interface_finalize */
- NULL /* interface_data */
- };
-
- g_type_add_interface_static (object_type, GST_TYPE_PRESET,
- &preset_interface_info);
-}
-
-GST_BOILERPLATE_FULL (GstTheoraEnc, gst_theora_enc, GstElement,
- GST_TYPE_ELEMENT, _do_init);
-
-static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
-static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
-static GstStateChangeReturn theora_enc_change_state (GstElement * element,
- GstStateChange transition);
-static GstCaps *theora_enc_sink_getcaps (GstPad * pad);
-static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
-static void theora_enc_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void theora_enc_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void theora_enc_finalize (GObject * object);
-
-static void
-gst_theora_enc_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_enc_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_enc_sink_factory));
- gst_element_class_set_details (element_class, &theora_enc_details);
-}
-
-static void
-gst_theora_enc_class_init (GstTheoraEncClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gobject_class->set_property = theora_enc_set_property;
- gobject_class->get_property = theora_enc_get_property;
- gobject_class->finalize = theora_enc_finalize;
-
- g_object_class_install_property (gobject_class, ARG_CENTER,
- g_param_spec_boolean ("center", "Center",
- "ignored and kept for API compat only", TRUE,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_BORDER,
- g_param_spec_enum ("border", "Border",
- "ignored and kept for API compat only",
- GST_TYPE_BORDER_MODE, BORDER_BLACK,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /* general encoding stream options */
- g_object_class_install_property (gobject_class, ARG_BITRATE,
- g_param_spec_int ("bitrate", "Bitrate", "Compressed video bitrate (kbps)",
- 0, (1 << 24) - 1, THEORA_DEF_BITRATE,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_QUALITY,
- g_param_spec_int ("quality", "Quality", "Video quality", 0, 63,
- THEORA_DEF_QUALITY,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_QUICK,
- g_param_spec_boolean ("quick", "Quick",
- "ignored and kept for API compat only", TRUE,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_KEYFRAME_AUTO,
- g_param_spec_boolean ("keyframe-auto", "Keyframe Auto",
- "Automatic keyframe detection", THEORA_DEF_KEYFRAME_AUTO,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ,
- g_param_spec_int ("keyframe-freq", "Keyframe frequency",
- "Keyframe frequency", 1, 32768, THEORA_DEF_KEYFRAME_FREQ,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_KEYFRAME_FREQ_FORCE,
- g_param_spec_int ("keyframe-force", "Keyframe force",
- "Force keyframe every N frames", 1, 32768,
- THEORA_DEF_KEYFRAME_FREQ_FORCE,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_KEYFRAME_THRESHOLD,
- g_param_spec_int ("keyframe-threshold", "Keyframe threshold",
- "ignored and kept for API compat only", 0, 32768, 80,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_KEYFRAME_MINDISTANCE,
- g_param_spec_int ("keyframe-mindistance", "Keyframe mindistance",
- "ignored and kept for API compat only", 1, 32768, 8,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_NOISE_SENSITIVITY,
- g_param_spec_int ("noise-sensitivity", "Noise sensitivity",
- "ignored and kept for API compat only", 0, 32768, 1,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_SHARPNESS,
- g_param_spec_int ("sharpness", "Sharpness",
- "ignored and kept for API compat only", 0, 2, 0,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_SPEEDLEVEL,
- g_param_spec_int ("speed-level", "Speed level",
- "Controls the amount of motion vector searching done while "
- "encoding. This property requires libtheora version >= 1.0",
- 0, 2, THEORA_DEF_SPEEDLEVEL,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_VP3_COMPATIBLE,
- g_param_spec_boolean ("vp3-compatible", "VP3 Compatible",
- "Disables non-VP3 compatible features."
- " This property requires libtheora version >= 1.1",
- THEORA_DEF_VP3_COMPATIBLE,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_DROP_FRAMES,
- g_param_spec_boolean ("drop-frames", "VP3 Compatible",
- "Allow or disallow frame dropping."
- " This property requires libtheora version >= 1.1",
- THEORA_DEF_DROP_FRAMES,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_CAP_OVERFLOW,
- g_param_spec_boolean ("cap-overflow", "VP3 Compatible",
- "Enable capping of bit reservoir overflows."
- " This property requires libtheora version >= 1.1",
- THEORA_DEF_CAP_OVERFLOW,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_CAP_UNDERFLOW,
- g_param_spec_boolean ("cap-underflow", "VP3 Compatible",
- "Enable capping of bit reservoir underflows."
- " This property requires libtheora version >= 1.1",
- THEORA_DEF_CAP_UNDERFLOW,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_RATE_BUFFER,
- g_param_spec_int ("rate-buffer", "Rate Control Buffer",
- "Sets the size of the rate control buffer, in units of frames. "
- "The default value of 0 instructs the encoder to automatically "
- "select an appropriate value."
- " This property requires libtheora version >= 1.1",
- 0, 1000, THEORA_DEF_RATE_BUFFER,
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state = theora_enc_change_state;
- GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
-}
-
-static void
-gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
-{
- enc->sinkpad =
- gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
- gst_pad_set_chain_function (enc->sinkpad, theora_enc_chain);
- gst_pad_set_event_function (enc->sinkpad, theora_enc_sink_event);
- gst_pad_set_getcaps_function (enc->sinkpad, theora_enc_sink_getcaps);
- gst_pad_set_setcaps_function (enc->sinkpad, theora_enc_sink_setcaps);
- gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad);
-
- enc->srcpad =
- gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
- gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
- gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
-
- gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
-
- enc->video_bitrate = THEORA_DEF_BITRATE;
- enc->video_quality = THEORA_DEF_QUALITY;
- enc->keyframe_auto = THEORA_DEF_KEYFRAME_AUTO;
- enc->keyframe_freq = THEORA_DEF_KEYFRAME_FREQ;
- enc->keyframe_force = THEORA_DEF_KEYFRAME_FREQ_FORCE;
-
- enc->expected_ts = GST_CLOCK_TIME_NONE;
-
- enc->speed_level = THEORA_DEF_SPEEDLEVEL;
- enc->vp3_compatible = THEORA_DEF_VP3_COMPATIBLE;
- enc->drop_frames = THEORA_DEF_DROP_FRAMES;
- enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
- enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
- enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
-}
-
-static void
-theora_enc_finalize (GObject * object)
-{
- GstTheoraEnc *enc = GST_THEORA_ENC (object);
-
- GST_DEBUG_OBJECT (enc, "Finalizing");
- if (enc->encoder)
- th_encode_free (enc->encoder);
- th_comment_clear (&enc->comment);
- th_info_clear (&enc->info);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-theora_enc_reset (GstTheoraEnc * enc)
-{
- ogg_uint32_t keyframe_force;
- int rate_flags;
-
- if (enc->encoder)
- th_encode_free (enc->encoder);
- enc->encoder = th_encode_alloc (&enc->info);
- /* We ensure this function cannot fail. */
- g_assert (enc->encoder != NULL);
-#ifdef TH_ENCCTL_SET_SPLEVEL
- th_encode_ctl (enc->encoder, TH_ENCCTL_SET_SPLEVEL, &enc->speed_level,
- sizeof (enc->speed_level));
-#endif
-#ifdef TH_ENCCTL_SET_VP3_COMPATIBLE
- th_encode_ctl (enc->encoder, TH_ENCCTL_SET_VP3_COMPATIBLE,
- &enc->vp3_compatible, sizeof (enc->vp3_compatible));
-#endif
-
- rate_flags = 0;
-#ifdef TH_ENCCTL_SET_RATE_FLAGS
- if (enc->drop_frames)
- rate_flags |= TH_RATECTL_DROP_FRAMES;
- if (enc->drop_frames)
- rate_flags |= TH_RATECTL_CAP_OVERFLOW;
- if (enc->drop_frames)
- rate_flags |= TH_RATECTL_CAP_UNDERFLOW;
- th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_FLAGS,
- &rate_flags, sizeof (rate_flags));
-#endif
-
-#ifdef TH_ENCCTL_SET_RATE_BUFFER
- if (enc->rate_buffer) {
- th_encode_ctl (enc->encoder, TH_ENCCTL_SET_RATE_BUFFER,
- &enc->rate_buffer, sizeof (enc->rate_buffer));
- } else {
- /* FIXME */
- }
-#endif
-
- keyframe_force = enc->keyframe_auto ?
- enc->keyframe_force : enc->keyframe_freq;
- th_encode_ctl (enc->encoder, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
- &keyframe_force, sizeof (keyframe_force));
-}
-
-static void
-theora_enc_clear (GstTheoraEnc * enc)
-{
- enc->packetno = 0;
- enc->bytes_out = 0;
- enc->granulepos_offset = 0;
- enc->timestamp_offset = 0;
-
- enc->next_ts = GST_CLOCK_TIME_NONE;
- enc->next_discont = FALSE;
- enc->expected_ts = GST_CLOCK_TIME_NONE;
-}
-
-static char *
-theora_enc_get_supported_formats (void)
-{
- th_enc_ctx *encoder;
- th_info info;
- struct
- {
- th_pixel_fmt pixelformat;
- char *fourcc;
- } formats[] = {
- {
- TH_PF_420, "I420"}, {
- TH_PF_422, "Y42B"}, {
- TH_PF_444, "Y444"}
- };
- GString *string = NULL;
- guint i;
-
- th_info_init (&info);
- info.frame_width = 16;
- info.frame_height = 16;
- info.fps_numerator = 25;
- info.fps_denominator = 1;
- for (i = 0; i < G_N_ELEMENTS (formats); i++) {
- info.pixel_fmt = formats[i].pixelformat;
-
- encoder = th_encode_alloc (&info);
- if (encoder == NULL)
- continue;
-
- GST_LOG ("format %s is supported", formats[i].fourcc);
- th_encode_free (encoder);
-
- if (string == NULL) {
- string = g_string_new (formats[i].fourcc);
- } else {
- g_string_append (string, ", ");
- g_string_append (string, formats[i].fourcc);
- }
- }
- th_info_clear (&info);
-
- return string == NULL ? NULL : g_string_free (string, FALSE);
-}
-
-static GstCaps *
-theora_enc_sink_getcaps (GstPad * pad)
-{
- GstCaps *caps;
- char *supported_formats, *caps_string;
-
- supported_formats = theora_enc_get_supported_formats ();
- if (!supported_formats) {
- GST_WARNING ("no supported formats found. Encoder disabled?");
- return gst_caps_new_empty ();
- }
-
- caps_string = g_strdup_printf ("video/x-raw-yuv, "
- "format = (fourcc) { %s }, "
- "framerate = (fraction) [0/1, MAX], "
- "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]",
- supported_formats);
- caps = gst_caps_from_string (caps_string);
- g_free (caps_string);
- g_free (supported_formats);
- GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps);
-
- return caps;
-}
-
-static gboolean
-theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstStructure *structure = gst_caps_get_structure (caps, 0);
- GstTheoraEnc *enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
- guint32 fourcc;
- const GValue *par;
- gint fps_n, fps_d;
-
- gst_structure_get_fourcc (structure, "format", &fourcc);
- gst_structure_get_int (structure, "width", &enc->width);
- gst_structure_get_int (structure, "height", &enc->height);
- gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d);
- par = gst_structure_get_value (structure, "pixel-aspect-ratio");
-
- th_info_clear (&enc->info);
- th_info_init (&enc->info);
- /* Theora has a divisible-by-sixteen restriction for the encoded video size but
- * we can define a picture area using pic_width/pic_height */
- enc->info.frame_width = GST_ROUND_UP_16 (enc->width);
- enc->info.frame_height = GST_ROUND_UP_16 (enc->height);
- enc->info.pic_width = enc->width;
- enc->info.pic_height = enc->height;
- switch (fourcc) {
- case GST_MAKE_FOURCC ('I', '4', '2', '0'):
- enc->info.pixel_fmt = TH_PF_420;
- break;
- case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
- enc->info.pixel_fmt = TH_PF_422;
- break;
- case GST_MAKE_FOURCC ('Y', '4', '4', '4'):
- enc->info.pixel_fmt = TH_PF_444;
- break;
- default:
- g_assert_not_reached ();
- }
-
- enc->info.fps_numerator = enc->fps_n = fps_n;
- enc->info.fps_denominator = enc->fps_d = fps_d;
- if (par) {
- enc->info.aspect_numerator = gst_value_get_fraction_numerator (par);
- enc->info.aspect_denominator = gst_value_get_fraction_denominator (par);
- } else {
- /* setting them to 0 indicates that the decoder can chose a good aspect
- * ratio, defaulting to 1/1 */
- enc->info.aspect_numerator = 0;
- enc->info.aspect_denominator = 0;
- }
-
- enc->info.colorspace = TH_CS_UNSPECIFIED;
- enc->info.target_bitrate = enc->video_bitrate;
- enc->info.quality = enc->video_quality;
-
- /* as done in theora */
- enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1);
- GST_DEBUG_OBJECT (enc,
- "keyframe_frequency_force is %d, granule shift is %d",
- enc->keyframe_force, enc->info.keyframe_granule_shift);
-
- theora_enc_reset (enc);
- enc->initialised = TRUE;
-
- gst_object_unref (enc);
-
- return TRUE;
-}
-
-static guint64
-granulepos_add (guint64 granulepos, guint64 addend, gint shift)
-{
- guint64 iframe, pframe;
-
- iframe = granulepos >> shift;
- pframe = granulepos - (iframe << shift);
- iframe += addend;
-
- return (iframe << shift) + pframe;
-}
-
-/* prepare a buffer for transmission by passing data through libtheora */
-static GstFlowReturn
-theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
- GstClockTime timestamp, GstClockTime running_time,
- GstClockTime duration, GstBuffer ** buffer)
-{
- GstBuffer *buf;
- GstFlowReturn ret = GST_FLOW_OK;
-
- buf = gst_buffer_new_and_alloc (packet->bytes);
- if (!buf) {
- GST_WARNING_OBJECT (enc, "Could not allocate buffer");
- ret = GST_FLOW_ERROR;
- goto done;
- }
-
- memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
- gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
- /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
- * time representation */
- GST_BUFFER_OFFSET_END (buf) =
- granulepos_add (packet->granulepos, enc->granulepos_offset,
- enc->info.keyframe_granule_shift);
- GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc,
- GST_BUFFER_OFFSET_END (buf));
-
- GST_BUFFER_TIMESTAMP (buf) = timestamp;
- GST_BUFFER_DURATION (buf) = duration;
-
- if (enc->next_discont) {
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
- enc->next_discont = FALSE;
- }
-
- /* the second most significant bit of the first data byte is cleared
- * for keyframes */
- if ((packet->packet[0] & 0x40) == 0) {
- GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
- } else {
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
- }
- enc->packetno++;
-
-done:
- *buffer = buf;
- return ret;
-}
-
-/* push out the buffer and do internal bookkeeping */
-static GstFlowReturn
-theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer)
-{
- GstFlowReturn ret;
-
- enc->bytes_out += GST_BUFFER_SIZE (buffer);
-
- ret = gst_pad_push (enc->srcpad, buffer);
-
- return ret;
-}
-
-static GstFlowReturn
-theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet,
- GstClockTime timestamp, GstClockTime running_time, GstClockTime duration)
-{
- GstBuffer *buf;
- GstFlowReturn ret;
-
- ret =
- theora_buffer_from_packet (enc, packet, timestamp, running_time, duration,
- &buf);
- if (ret == GST_FLOW_OK)
- ret = theora_push_buffer (enc, buf);
-
- return ret;
-}
-
-static GstCaps *
-theora_set_header_on_caps (GstCaps * caps, GSList * buffers)
-{
- GstStructure *structure;
- GValue array = { 0 };
- GValue value = { 0 };
- GstBuffer *buffer;
- GSList *walk;
-
- caps = gst_caps_make_writable (caps);
- structure = gst_caps_get_structure (caps, 0);
-
- /* put copies of the buffers in a fixed list */
- g_value_init (&array, GST_TYPE_ARRAY);
-
- for (walk = buffers; walk; walk = walk->next) {
- buffer = walk->data;
-
- /* mark buffer */
- GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
-
- /* Copy buffer, because we can't use the original -
- * it creates a circular refcount with the caps<->buffers */
- buffer = gst_buffer_copy (buffer);
-
- g_value_init (&value, GST_TYPE_BUFFER);
- gst_value_set_buffer (&value, buffer);
- gst_value_array_append_value (&array, &value);
- g_value_unset (&value);
-
- /* Unref our copy */
- gst_buffer_unref (buffer);
- }
-
- gst_structure_set_value (structure, "streamheader", &array);
- g_value_unset (&array);
-
- return caps;
-}
-
-static void
-theora_enc_force_keyframe (GstTheoraEnc * enc)
-{
- GstClockTime next_ts;
-
- /* make sure timestamps increment after resetting the decoder */
- next_ts = enc->next_ts + enc->timestamp_offset;
-
- theora_enc_reset (enc);
- enc->granulepos_offset =
- gst_util_uint64_scale (next_ts, enc->fps_n, GST_SECOND * enc->fps_d);
- enc->timestamp_offset = next_ts;
- enc->next_ts = 0;
-}
-
-static gboolean
-theora_enc_sink_event (GstPad * pad, GstEvent * event)
-{
- GstTheoraEnc *enc;
- ogg_packet op;
- gboolean res;
-
- enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
- {
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, time;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &time);
-
- gst_segment_set_newsegment_full (&enc->segment, update, rate,
- applied_rate, format, start, stop, time);
-
- res = gst_pad_push_event (enc->srcpad, event);
- break;
- }
- case GST_EVENT_EOS:
- if (enc->initialised) {
- /* push last packet with eos flag, should not be called */
- while (th_encode_packetout (enc->encoder, 1, &op)) {
- GstClockTime next_time =
- th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
-
- theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts,
- next_time - enc->next_ts);
- enc->next_ts = next_time;
- }
- }
- res = gst_pad_push_event (enc->srcpad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
- res = gst_pad_push_event (enc->srcpad, event);
- break;
- case GST_EVENT_CUSTOM_DOWNSTREAM:
- {
- const GstStructure *s;
-
- s = gst_event_get_structure (event);
-
- if (gst_structure_has_name (s, "GstForceKeyUnit"))
- theora_enc_force_keyframe (enc);
- res = gst_pad_push_event (enc->srcpad, event);
- break;
- }
- default:
- res = gst_pad_push_event (enc->srcpad, event);
- break;
- }
- return res;
-}
-
-static gboolean
-theora_enc_src_event (GstPad * pad, GstEvent * event)
-{
- GstTheoraEnc *enc;
- gboolean res = TRUE;
-
- enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_CUSTOM_UPSTREAM:
- {
- const GstStructure *s;
-
- s = gst_event_get_structure (event);
-
- if (gst_structure_has_name (s, "GstForceKeyUnit")) {
- GST_OBJECT_LOCK (enc);
- enc->force_keyframe = TRUE;
- GST_OBJECT_UNLOCK (enc);
- /* consume the event */
- res = TRUE;
- gst_event_unref (event);
- } else {
- res = gst_pad_push_event (enc->sinkpad, event);
- }
- break;
- }
- default:
- res = gst_pad_push_event (enc->sinkpad, event);
- break;
- }
-
- return res;
-}
-
-static gboolean
-theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
- GstClockTime duration)
-{
- GstClockTimeDiff max_diff;
- gboolean ret = FALSE;
-
- /* Allow 3/4 a frame off */
- max_diff = (enc->info.fps_denominator * GST_SECOND * 3) /
- (enc->info.fps_numerator * 4);
-
- if (timestamp != GST_CLOCK_TIME_NONE
- && enc->expected_ts != GST_CLOCK_TIME_NONE) {
- if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) {
- GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT
- " exceeds expected value %" GST_TIME_FORMAT
- " by too much, marking discontinuity",
- GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts));
- ret = TRUE;
- }
- }
-
- if (GST_CLOCK_TIME_IS_VALID (duration))
- enc->expected_ts = timestamp + duration;
- else
- enc->expected_ts = GST_CLOCK_TIME_NONE;
-
- return ret;
-}
-
-static void
-theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
-{
- GstVideoFormat format;
- guint i;
-
- switch (info->pixel_fmt) {
- case TH_PF_444:
- format = GST_VIDEO_FORMAT_Y444;
- break;
- case TH_PF_420:
- format = GST_VIDEO_FORMAT_I420;
- break;
- case TH_PF_422:
- format = GST_VIDEO_FORMAT_Y42B;
- break;
- default:
- g_assert_not_reached ();
- }
-
- /* According to Theora developer Timothy Terriberry, the Theora
- * encoder will not use memory outside of pic_width/height, even when
- * the frame size is bigger. The values outside this region will be encoded
- * to default values.
- * Due to this, setting the frame's width/height as the buffer width/height
- * is perfectly ok, even though it does not strictly look ok.
- */
- for (i = 0; i < 3; i++) {
- buf[i].width =
- gst_video_format_get_component_width (format, i, info->frame_width);
- buf[i].height =
- gst_video_format_get_component_height (format, i, info->frame_height);
-
- buf[i].data =
- data + gst_video_format_get_component_offset (format, i,
- info->pic_width, info->pic_height);
- buf[i].stride =
- gst_video_format_get_row_stride (format, i, info->pic_width);
- }
-}
-
-static GstFlowReturn
-theora_enc_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstTheoraEnc *enc;
- ogg_packet op;
- GstClockTime timestamp, duration, running_time;
- GstFlowReturn ret;
- gboolean force_keyframe;
-
- enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
-
- /* we keep track of two timelines.
- * - The timestamps from the incomming buffers, which we copy to the outgoing
- * encoded buffers as-is. We need to do this as we simply forward the
- * newsegment events.
- * - The running_time of the buffers, which we use to construct the granulepos
- * in the packets.
- */
- timestamp = GST_BUFFER_TIMESTAMP (buffer);
- duration = GST_BUFFER_DURATION (buffer);
-
- running_time =
- gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
- if ((gint64) running_time < 0) {
- GST_DEBUG_OBJECT (enc, "Dropping buffer, timestamp: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
- }
-
- /* see if we need to schedule a keyframe */
- GST_OBJECT_LOCK (enc);
- force_keyframe = enc->force_keyframe;
- enc->force_keyframe = FALSE;
- GST_OBJECT_UNLOCK (enc);
-
- if (force_keyframe) {
- GstClockTime stream_time;
- GstStructure *s;
-
- stream_time = gst_segment_to_stream_time (&enc->segment,
- GST_FORMAT_TIME, timestamp);
-
- s = gst_structure_new ("GstForceKeyUnit",
- "timestamp", G_TYPE_UINT64, timestamp,
- "stream-time", G_TYPE_UINT64, stream_time,
- "running-time", G_TYPE_UINT64, running_time, NULL);
-
- theora_enc_force_keyframe (enc);
-
- gst_pad_push_event (enc->srcpad,
- gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
- }
-
- /* make sure we copy the discont flag to the next outgoing buffer when it's
- * set on the incomming buffer */
- if (GST_BUFFER_IS_DISCONT (buffer)) {
- enc->next_discont = TRUE;
- }
-
- if (enc->packetno == 0) {
- /* no packets written yet, setup headers */
- GstCaps *caps;
- GstBuffer *buf;
- GSList *buffers = NULL;
- int result;
-
- enc->granulepos_offset = 0;
- enc->timestamp_offset = 0;
-
- GST_DEBUG_OBJECT (enc, "output headers");
- /* Theora 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 libtheora one at a time;
- libtheora handles the additional Ogg bitstream constraints */
-
- /* create the remaining theora headers */
- th_comment_clear (&enc->comment);
- th_comment_init (&enc->comment);
-
- while ((result =
- th_encode_flushheader (enc->encoder, &enc->comment, &op)) > 0) {
- ret =
- theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE,
- GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf);
- if (ret != GST_FLOW_OK) {
- goto header_buffer_alloc;
- }
- buffers = g_slist_prepend (buffers, buf);
- }
- if (result < 0) {
- g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
- g_slist_free (buffers);
- goto encoder_disabled;
- }
-
- buffers = g_slist_reverse (buffers);
-
- /* mark buffers and put on caps */
- caps = gst_pad_get_caps (enc->srcpad);
- caps = theora_set_header_on_caps (caps, buffers);
- GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
- gst_pad_set_caps (enc->srcpad, caps);
-
- g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);
-
- gst_caps_unref (caps);
-
- /* push out the header buffers */
- while (buffers) {
- buf = buffers->data;
- buffers = g_slist_delete_link (buffers, buffers);
- if ((ret = theora_push_buffer (enc, buf)) != GST_FLOW_OK) {
- g_slist_foreach (buffers, (GFunc) gst_buffer_unref, NULL);
- g_slist_free (buffers);
- goto header_push;
- }
- }
-
- enc->granulepos_offset =
- gst_util_uint64_scale (running_time, enc->fps_n,
- GST_SECOND * enc->fps_d);
- enc->timestamp_offset = running_time;
- enc->next_ts = 0;
- }
-
- {
- th_ycbcr_buffer ycbcr;
- gint res;
-
- theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));
-
- if (theora_enc_is_discontinuous (enc, running_time, duration)) {
- theora_enc_reset (enc);
- enc->granulepos_offset =
- gst_util_uint64_scale (running_time, enc->fps_n,
- GST_SECOND * enc->fps_d);
- enc->timestamp_offset = running_time;
- enc->next_ts = 0;
- enc->next_discont = TRUE;
- }
-
- res = th_encode_ycbcr_in (enc->encoder, ycbcr);
- /* none of the failure cases can happen here */
- g_assert (res == 0);
-
- ret = GST_FLOW_OK;
- while (th_encode_packetout (enc->encoder, 0, &op)) {
- GstClockTime next_time;
-
- next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
-
- ret =
- theora_push_packet (enc, &op, timestamp, enc->next_ts,
- next_time - enc->next_ts);
-
- enc->next_ts = next_time;
- if (ret != GST_FLOW_OK)
- goto data_push;
- }
- gst_buffer_unref (buffer);
- }
-
- return ret;
-
- /* ERRORS */
-header_buffer_alloc:
- {
- gst_buffer_unref (buffer);
- return ret;
- }
-header_push:
- {
- gst_buffer_unref (buffer);
- return ret;
- }
-data_push:
- {
- gst_buffer_unref (buffer);
- return ret;
- }
-encoder_disabled:
- {
- GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
- ("libtheora has been compiled with the encoder disabled"));
- gst_buffer_unref (buffer);
- return GST_FLOW_ERROR;
- }
-}
-
-static GstStateChangeReturn
-theora_enc_change_state (GstElement * element, GstStateChange transition)
-{
- GstTheoraEnc *enc;
- GstStateChangeReturn ret;
-
- enc = GST_THEORA_ENC (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- GST_DEBUG_OBJECT (enc, "READY->PAUSED Initing theora state");
- th_info_init (&enc->info);
- th_comment_init (&enc->comment);
- enc->packetno = 0;
- enc->force_keyframe = FALSE;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- ret = parent_class->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_DEBUG_OBJECT (enc, "PAUSED->READY Clearing theora state");
- if (enc->encoder) {
- th_encode_free (enc->encoder);
- enc->encoder = NULL;
- }
- th_comment_clear (&enc->comment);
- th_info_clear (&enc->info);
-
- theora_enc_clear (enc);
- enc->initialised = FALSE;
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static void
-theora_enc_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstTheoraEnc *enc = GST_THEORA_ENC (object);
-
- switch (prop_id) {
- case ARG_CENTER:
- case ARG_BORDER:
- case ARG_QUICK:
- case ARG_KEYFRAME_THRESHOLD:
- case ARG_KEYFRAME_MINDISTANCE:
- case ARG_NOISE_SENSITIVITY:
- case ARG_SHARPNESS:
- /* kept for API compat, but ignored */
- break;
- case ARG_BITRATE:
- enc->video_bitrate = g_value_get_int (value) * 1000;
- enc->video_quality = 0;
- break;
- case ARG_QUALITY:
- enc->video_quality = g_value_get_int (value);
- enc->video_bitrate = 0;
- break;
- case ARG_KEYFRAME_AUTO:
- enc->keyframe_auto = g_value_get_boolean (value);
- break;
- case ARG_KEYFRAME_FREQ:
- enc->keyframe_freq = g_value_get_int (value);
- break;
- case ARG_KEYFRAME_FREQ_FORCE:
- enc->keyframe_force = g_value_get_int (value);
- break;
- case ARG_SPEEDLEVEL:
-#ifdef TH_ENCCTL_SET_SPLEVEL
- enc->speed_level = g_value_get_int (value);
-#endif
- break;
- case ARG_VP3_COMPATIBLE:
-#ifdef TH_ENCCTL_SET_VP3_COMPATIBLE
- enc->vp3_compatible = g_value_get_boolean (value);
-#endif
- break;
- case ARG_DROP_FRAMES:
-#ifdef TH_ENCCTL_SET_RATE_FLAGS
- enc->drop_frames = g_value_get_boolean (value);
-#endif
- break;
- case ARG_CAP_OVERFLOW:
-#ifdef TH_ENCCTL_SET_RATE_FLAGS
- enc->cap_overflow = g_value_get_boolean (value);
-#endif
- break;
- case ARG_CAP_UNDERFLOW:
-#ifdef TH_ENCCTL_SET_RATE_FLAGS
- enc->cap_underflow = g_value_get_boolean (value);
-#endif
- break;
- case ARG_RATE_BUFFER:
-#ifdef TH_ENCCTL_SET_RATE_BUFFER
- enc->rate_buffer = g_value_get_int (value);
-#endif
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-theora_enc_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstTheoraEnc *enc = GST_THEORA_ENC (object);
-
- switch (prop_id) {
- case ARG_CENTER:
- g_value_set_boolean (value, TRUE);
- break;
- case ARG_BORDER:
- g_value_set_enum (value, BORDER_BLACK);
- break;
- case ARG_BITRATE:
- g_value_set_int (value, enc->video_bitrate / 1000);
- break;
- case ARG_QUALITY:
- g_value_set_int (value, enc->video_quality);
- break;
- case ARG_QUICK:
- g_value_set_boolean (value, TRUE);
- break;
- case ARG_KEYFRAME_AUTO:
- g_value_set_boolean (value, enc->keyframe_auto);
- break;
- case ARG_KEYFRAME_FREQ:
- g_value_set_int (value, enc->keyframe_freq);
- break;
- case ARG_KEYFRAME_FREQ_FORCE:
- g_value_set_int (value, enc->keyframe_force);
- break;
- case ARG_KEYFRAME_THRESHOLD:
- g_value_set_int (value, 80);
- break;
- case ARG_KEYFRAME_MINDISTANCE:
- g_value_set_int (value, 8);
- break;
- case ARG_NOISE_SENSITIVITY:
- g_value_set_int (value, 1);
- break;
- case ARG_SHARPNESS:
- g_value_set_int (value, 0);
- break;
- case ARG_SPEEDLEVEL:
- g_value_set_int (value, enc->speed_level);
- break;
- case ARG_VP3_COMPATIBLE:
- g_value_set_boolean (value, enc->vp3_compatible);
- break;
- case ARG_DROP_FRAMES:
- g_value_set_boolean (value, enc->drop_frames);
- break;
- case ARG_CAP_OVERFLOW:
- g_value_set_boolean (value, enc->cap_overflow);
- break;
- case ARG_CAP_UNDERFLOW:
- g_value_set_boolean (value, enc->cap_underflow);
- break;
- case ARG_RATE_BUFFER:
- g_value_set_int (value, enc->rate_buffer);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
diff --git a/ext/theora/gsttheoraenc.h b/ext/theora/gsttheoraenc.h
deleted file mode 100644
index 3efdab20..00000000
--- a/ext/theora/gsttheoraenc.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_THEORAENC_H__
-#define __GST_THEORAENC_H__
-
-#include <gst/gst.h>
-#include <theora/theoraenc.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_THEORA_ENC \
- (gst_theora_enc_get_type())
-#define GST_THEORA_ENC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_ENC,GstTheoraEnc))
-#define GST_THEORA_ENC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_ENC,GstTheoraEncClass))
-#define GST_IS_THEORA_ENC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_ENC))
-#define GST_IS_THEORA_ENC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_ENC))
-
-typedef struct _GstTheoraEnc GstTheoraEnc;
-typedef struct _GstTheoraEncClass GstTheoraEncClass;
-
-/**
- * GstTheoraEncBorderMode:
- * @BORDER_NONE: no border
- * @BORDER_BLACK: black border
- * @BORDER_MIRROR: Mirror image in border
- *
- * Border color to add when sizes not multiple of 16.
- */
-typedef enum
-{
- BORDER_NONE,
- BORDER_BLACK,
- BORDER_MIRROR
-}
-GstTheoraEncBorderMode;
-
-/**
- * GstTheoraEnc:
- *
- * Opaque data structure.
- */
-struct _GstTheoraEnc
-{
- GstElement element;
-
- GstPad *sinkpad;
- GstPad *srcpad;
-
- GstSegment segment;
-
- ogg_stream_state to;
-
- th_enc_ctx *encoder;
- th_info info;
- th_comment comment;
- gboolean initialised;
-
- gint video_bitrate; /* bitrate target for Theora video */
- gint video_quality; /* Theora quality selector 0 = low, 63 = high */
- gboolean keyframe_auto;
- gint keyframe_freq;
- gint keyframe_force;
-
- gint info_width, info_height;
- gint width, height;
- gint fps_n, fps_d;
- GstClockTime next_ts;
-
- GstClockTime expected_ts;
- gboolean next_discont;
-
- gboolean force_keyframe;
-
- guint packetno;
- guint64 bytes_out;
- guint64 granulepos_offset;
- guint64 timestamp_offset;
-
- gint speed_level;
- gboolean vp3_compatible;
- gboolean drop_frames;
- gboolean cap_overflow;
- gboolean cap_underflow;
- int rate_buffer;
-};
-
-struct _GstTheoraEncClass
-{
- GstElementClass parent_class;
-};
-
-G_END_DECLS
-
-#endif /* __GST_THEORAENC_H__ */
-
diff --git a/ext/theora/gsttheoraparse.c b/ext/theora/gsttheoraparse.c
deleted file mode 100644
index 79c90072..00000000
--- a/ext/theora/gsttheoraparse.c
+++ /dev/null
@@ -1,941 +0,0 @@
-/* GStreamer
- * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
- * Copyright (C) 2006 Andy Wingo <wingo@pobox.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-theoraparse
- * @see_also: theoradec, oggdemux, vorbisparse
- *
- * The theoraparse element will parse the header packets of the Theora
- * stream and put them as the streamheader in the caps. This is used in the
- * multifdsink case where you want to stream live theora streams to multiple
- * clients, each client has to receive the streamheaders first before they can
- * consume the theora packets.
- *
- * This element also makes sure that the buffers that it pushes out are properly
- * timestamped and that their offset and offset_end are set. The buffers that
- * theoraparse outputs have all of the metadata that oggmux expects to receive,
- * which allows you to (for example) remux an ogg/theora file.
- *
- * In addition, this element allows you to fix badly synchronized streams. You
- * pass in an array of (granule time, buffer time) synchronization points via
- * the synchronization-points GValueArray property, and this element will adjust
- * the granulepos values that it outputs. The adjustment will be made by
- * offsetting all buffers that it outputs by a specified amount, and updating
- * that offset from the value array whenever a keyframe is processed.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v filesrc location=video.ogg ! oggdemux ! theoraparse ! fakesink
- * ]| This pipeline shows that the streamheader is set in the caps, and that each
- * buffer has the timestamp, duration, offset, and offset_end set.
- * |[
- * gst-launch filesrc location=video.ogg ! oggdemux ! theoraparse \
- * ! oggmux ! filesink location=video-remuxed.ogg
- * ]| This pipeline shows remuxing. video-remuxed.ogg might not be exactly the same
- * as video.ogg, but they should produce exactly the same decoded data.
- * </refsect2>
- *
- * Last reviewed on 2008-05-28 (0.10.20)
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gsttheoraparse.h"
-
-#define GST_CAT_DEFAULT theoraparse_debug
-GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
-
-static GstElementDetails theora_parse_details = {
- "Theora video parser",
- "Codec/Parser/Video",
- "parse raw theora streams",
- "Andy Wingo <wingo@pobox.com>"
-};
-
-static GstStaticPadTemplate theora_parse_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-theora")
- );
-
-static GstStaticPadTemplate theora_parse_src_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-theora")
- );
-
-enum
-{
- PROP_0,
- PROP_SYNCHRONIZATION_POINTS
-};
-
-GST_BOILERPLATE (GstTheoraParse, gst_theora_parse, GstElement,
- GST_TYPE_ELEMENT);
-
-static void theora_parse_dispose (GObject * object);
-static void theora_parse_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void theora_parse_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-
-static gboolean theora_parse_src_query (GstPad * pad, GstQuery * query);
-static GstFlowReturn theora_parse_chain (GstPad * pad, GstBuffer * buffer);
-static GstStateChangeReturn theora_parse_change_state (GstElement * element,
- GstStateChange transition);
-static gboolean theora_parse_sink_event (GstPad * pad, GstEvent * event);
-static gboolean theora_parse_src_query (GstPad * pad, GstQuery * query);
-
-static void
-gst_theora_parse_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_parse_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_parse_sink_factory));
- gst_element_class_set_details (element_class, &theora_parse_details);
-}
-
-static void
-gst_theora_parse_class_init (GstTheoraParseClass * klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gobject_class->dispose = theora_parse_dispose;
- gobject_class->get_property = theora_parse_get_property;
- gobject_class->set_property = theora_parse_set_property;
-
- /**
- * GstTheoraParse:sychronization-points
- *
- * An array of (granuletime, buffertime) pairs
- *
- * Since: 0.10.10
- */
- g_object_class_install_property (gobject_class, PROP_SYNCHRONIZATION_POINTS,
- g_param_spec_value_array ("synchronization-points",
- "Synchronization points",
- "An array of (granuletime, buffertime) pairs",
- g_param_spec_uint64 ("time", "Time",
- "Time (either granuletime or buffertime)", 0, G_MAXUINT64, 0,
- G_PARAM_READWRITE),
- (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state = theora_parse_change_state;
-
- GST_DEBUG_CATEGORY_INIT (theoraparse_debug, "theoraparse", 0,
- "Theora parser");
-}
-
-static void
-gst_theora_parse_init (GstTheoraParse * parse, GstTheoraParseClass * g_class)
-{
- parse->sinkpad =
- gst_pad_new_from_static_template (&theora_parse_sink_factory, "sink");
- gst_pad_set_chain_function (parse->sinkpad, theora_parse_chain);
- gst_pad_set_event_function (parse->sinkpad, theora_parse_sink_event);
- gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
-
- parse->srcpad =
- gst_pad_new_from_static_template (&theora_parse_src_factory, "src");
- gst_pad_set_query_function (parse->srcpad, theora_parse_src_query);
- gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
-}
-
-static void
-theora_parse_dispose (GObject * object)
-{
- GstTheoraParse *parse = GST_THEORA_PARSE (object);
-
- g_free (parse->times);
- parse->times = NULL;
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-theora_parse_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstTheoraParse *parse = GST_THEORA_PARSE (object);
-
- switch (prop_id) {
- case PROP_SYNCHRONIZATION_POINTS:
- {
- GValueArray *array;
- guint i;
-
- array = g_value_get_boxed (value);
-
- if (array) {
- if (array->n_values % 2)
- goto odd_values;
-
- g_free (parse->times);
- parse->times = g_new (GstClockTime, array->n_values);
- parse->npairs = array->n_values / 2;
- for (i = 0; i < array->n_values; i++)
- parse->times[i] = g_value_get_uint64 (&array->values[i]);
- } else {
- g_free (parse->times);
- parse->npairs = 0;
- }
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- return;
-
-odd_values:
- {
- g_critical ("expected an even number of time values for "
- "synchronization-points");
- return;
- }
-}
-
-static void
-theora_parse_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstTheoraParse *parse = GST_THEORA_PARSE (object);
-
- switch (prop_id) {
- case PROP_SYNCHRONIZATION_POINTS:
- {
- GValueArray *array = NULL;
- guint i;
-
- array = g_value_array_new (parse->npairs * 2);
-
- for (i = 0; i < parse->npairs; i++) {
- GValue v = { 0, };
-
- g_value_init (&v, G_TYPE_UINT64);
- g_value_set_uint64 (&v, parse->times[i * 2]);
- g_value_array_append (array, &v);
- g_value_set_uint64 (&v, parse->times[i * 2 + 1]);
- g_value_array_append (array, &v);
- g_value_unset (&v);
- }
-
- g_value_set_boxed (value, array);
- }
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-theora_parse_set_header_on_caps (GstTheoraParse * parse, GstCaps * caps)
-{
- GstBuffer **bufs;
- GstStructure *structure;
- gint i;
- GValue array = { 0 };
- GValue value = { 0 };
-
- bufs = parse->streamheader;
- structure = gst_caps_get_structure (caps, 0);
- g_value_init (&array, GST_TYPE_ARRAY);
-
- for (i = 0; i < 3; i++) {
- if (bufs[i] == NULL)
- continue;
-
- bufs[i] = gst_buffer_make_metadata_writable (bufs[i]);
- GST_BUFFER_FLAG_SET (bufs[i], GST_BUFFER_FLAG_IN_CAPS);
-
- g_value_init (&value, GST_TYPE_BUFFER);
- gst_value_set_buffer (&value, bufs[i]);
- gst_value_array_append_value (&array, &value);
- g_value_unset (&value);
- }
-
- gst_structure_set_value (structure, "streamheader", &array);
- g_value_unset (&array);
-}
-
-/* two tasks to do here: set the streamheader on the caps, and use libtheora to
- parse the headers */
-static void
-theora_parse_set_streamheader (GstTheoraParse * parse)
-{
- GstCaps *caps;
- gint i;
- guint32 bitstream_version;
- th_setup_info *setup = NULL;
-
- g_assert (!parse->streamheader_received);
-
- caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad));
- theora_parse_set_header_on_caps (parse, caps);
- GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps);
- gst_pad_set_caps (parse->srcpad, caps);
- gst_caps_unref (caps);
-
- for (i = 0; i < 3; i++) {
- ogg_packet packet;
- GstBuffer *buf;
- int ret;
-
- buf = parse->streamheader[i];
- if (buf == NULL)
- continue;
-
- gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
-
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
- packet.granulepos = GST_BUFFER_OFFSET_END (buf);
- packet.packetno = i + 1;
- packet.e_o_s = 0;
- packet.b_o_s = (i == 0);
- ret = th_decode_headerin (&parse->info, &parse->comment, &setup, &packet);
- if (ret < 0) {
- GST_WARNING_OBJECT (parse, "Failed to decode Theora header %d: %d\n",
- i + 1, ret);
- }
- }
- if (setup) {
- th_setup_free (setup);
- }
-
- parse->fps_n = parse->info.fps_numerator;
- parse->fps_d = parse->info.fps_denominator;
- parse->shift = parse->info.keyframe_granule_shift;
-
- /* With libtheora-1.0beta1 the granulepos scheme was changed:
- * where earlier the granulepos refered to the index/beginning
- * of a frame, it now refers to the end, which matches the use
- * in vorbis/speex. We check the bitstream version from the header so
- * we know which way to interpret the incoming granuepos
- */
- bitstream_version = (parse->info.version_major << 16) |
- (parse->info.version_minor << 8) | parse->info.version_subminor;
- parse->is_old_bitstream = (bitstream_version <= 0x00030200);
-
- parse->streamheader_received = TRUE;
-}
-
-static void
-theora_parse_drain_event_queue (GstTheoraParse * parse)
-{
- while (parse->event_queue->length) {
- GstEvent *event;
-
- event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
- gst_pad_event_default (parse->sinkpad, event);
- }
-}
-
-static void
-theora_parse_push_headers (GstTheoraParse * parse)
-{
- gint i;
-
- theora_parse_drain_event_queue (parse);
-
- if (!parse->streamheader_received)
- theora_parse_set_streamheader (parse);
-
- /* ignore return values, we pass along the result of pushing data packets only
- */
- for (i = 0; i < 3; i++) {
- GstBuffer *buf;
-
- if ((buf = parse->streamheader[i]))
- gst_pad_push (parse->srcpad, gst_buffer_ref (buf));
- }
-}
-
-static void
-theora_parse_clear_queue (GstTheoraParse * parse)
-{
- while (parse->buffer_queue->length) {
- GstBuffer *buf;
-
- buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
- gst_buffer_unref (buf);
- }
- while (parse->event_queue->length) {
- GstEvent *event;
-
- event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
- gst_event_unref (event);
- }
-}
-
-static gint64
-make_granulepos (GstTheoraParse * parse, gint64 keyframe, gint64 frame)
-{
- gint64 iframe;
-
- if (keyframe == -1)
- keyframe = 0;
- /* If using newer theora, offset the granulepos by +1, see comment in
- * theora_parse_set_streamheader.
- *
- * We don't increment keyframe directly, as internally we always index frames
- * starting from 0 and we do some sanity checking below. */
- if (!parse->is_old_bitstream)
- iframe = keyframe + 1;
- else
- iframe = keyframe;
-
- g_return_val_if_fail (frame >= keyframe, -1);
- g_return_val_if_fail (frame - keyframe < 1 << parse->shift, -1);
-
- return (iframe << parse->shift) + (frame - keyframe);
-}
-
-static void
-parse_granulepos (GstTheoraParse * parse, gint64 granulepos,
- gint64 * keyframe, gint64 * frame)
-{
- gint64 kf;
-
- kf = granulepos >> parse->shift;
- /* If using newer theora, offset the granulepos by -1, see comment
- * in theora_parse_set_streamheader */
- if (!parse->is_old_bitstream)
- kf -= 1;
- if (keyframe)
- *keyframe = kf;
- if (frame)
- *frame = kf + (granulepos & ((1 << parse->shift) - 1));
-}
-
-static gboolean
-is_keyframe (GstBuffer * buf)
-{
- if (!GST_BUFFER_DATA (buf))
- return FALSE;
- if (!GST_BUFFER_SIZE (buf))
- return FALSE;
- return ((GST_BUFFER_DATA (buf)[0] & 0x40) == 0);
-}
-
-static void
-theora_parse_munge_granulepos (GstTheoraParse * parse, GstBuffer * buf,
- gint64 keyframe, gint64 frame)
-{
- gint64 frames_diff;
- GstClockTimeDiff time_diff;
-
- if (keyframe == frame) {
- gint i;
-
- /* update granule_offset */
- for (i = 0; i < parse->npairs; i++) {
- if (parse->times[i * 2] >= GST_BUFFER_OFFSET (buf))
- break;
- }
- if (i > 0) {
- /* time_diff gets reset below */
- time_diff = parse->times[i * 2 - 1] - parse->times[i * 2 - 2];
- parse->granule_offset = gst_util_uint64_scale (time_diff,
- parse->fps_n, parse->fps_d * GST_SECOND);
- parse->granule_offset <<= parse->shift;
- }
- }
-
- frames_diff = parse->granule_offset >> parse->shift;
- time_diff = gst_util_uint64_scale_int (GST_SECOND * frames_diff,
- parse->fps_d, parse->fps_n);
-
- GST_DEBUG_OBJECT (parse, "offsetting theora stream by %" G_GINT64_FORMAT
- " frames (%" GST_TIME_FORMAT ")", frames_diff, GST_TIME_ARGS (time_diff));
-
- GST_BUFFER_OFFSET_END (buf) += parse->granule_offset;
- GST_BUFFER_OFFSET (buf) += time_diff;
- GST_BUFFER_TIMESTAMP (buf) += time_diff;
-}
-
-static GstFlowReturn
-theora_parse_push_buffer (GstTheoraParse * parse, GstBuffer * buf,
- gint64 keyframe, gint64 frame)
-{
-
- GstClockTime this_time, next_time;
-
- this_time = gst_util_uint64_scale_int (GST_SECOND * frame,
- parse->fps_d, parse->fps_n);
-
- next_time = gst_util_uint64_scale_int (GST_SECOND * (frame + 1),
- parse->fps_d, parse->fps_n);
-
- GST_BUFFER_OFFSET_END (buf) = make_granulepos (parse, keyframe, frame);
- GST_BUFFER_OFFSET (buf) = this_time;
- GST_BUFFER_TIMESTAMP (buf) = this_time;
- GST_BUFFER_DURATION (buf) = next_time - this_time;
-
- gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
-
- if (parse->times)
- theora_parse_munge_granulepos (parse, buf, keyframe, frame);
-
- GST_DEBUG_OBJECT (parse, "pushing buffer with granulepos %" G_GINT64_FORMAT
- "|%" G_GINT64_FORMAT, keyframe, frame - keyframe);
-
- return gst_pad_push (parse->srcpad, buf);
-}
-
-static GstFlowReturn
-theora_parse_drain_queue_prematurely (GstTheoraParse * parse)
-{
- GstFlowReturn ret = GST_FLOW_OK;
-
- /* got an EOS event, make sure to push out any buffers that were in the queue
- * -- won't normally be the case, but this catches the
- * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous
- * stream. */
-
- GST_DEBUG_OBJECT (parse, "got EOS, draining queue");
-
- /* if we get an eos before pushing the streamheaders, drain our events before
- * eos */
- theora_parse_drain_event_queue (parse);
-
- while (!g_queue_is_empty (parse->buffer_queue)) {
- GstBuffer *buf;
-
- buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
-
- parse->prev_frame++;
-
- if (is_keyframe (buf))
- /* we have a keyframe */
- parse->prev_keyframe = parse->prev_frame;
- else
- GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT;
-
- if (parse->prev_keyframe < 0) {
- if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
- parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf),
- &parse->prev_keyframe, NULL);
- } else {
- /* No previous keyframe known; can't extract one from this frame. That
- * means we can't do any valid output for this frame, just continue to
- * the next frame.
- */
- gst_buffer_unref (buf);
- continue;
- }
- }
-
- ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe,
- parse->prev_frame);
-
- if (ret != GST_FLOW_OK)
- goto done;
- }
-
-done:
- return ret;
-}
-
-static GstFlowReturn
-theora_parse_drain_queue (GstTheoraParse * parse, gint64 granulepos)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- gint64 keyframe, prev_frame, frame;
-
- parse_granulepos (parse, granulepos, &keyframe, &frame);
-
- GST_DEBUG ("draining queue of length %d",
- g_queue_get_length (parse->buffer_queue));
-
- GST_LOG_OBJECT (parse, "gp %" G_GINT64_FORMAT ", kf %" G_GINT64_FORMAT
- ", frame %" G_GINT64_FORMAT, granulepos, keyframe, frame);
-
- prev_frame = frame - g_queue_get_length (parse->buffer_queue);
-
- GST_LOG_OBJECT (parse,
- "new prev %" G_GINT64_FORMAT ", prev %" G_GINT64_FORMAT, prev_frame,
- parse->prev_frame);
-
- if (prev_frame < parse->prev_frame) {
- GST_WARNING ("jumped %" G_GINT64_FORMAT
- " frames backwards! not sure what to do here",
- parse->prev_frame - prev_frame);
- ret = GST_FLOW_ERROR;
- goto done;
- } else if (prev_frame > parse->prev_frame) {
- GST_INFO ("discontinuity detected (%" G_GINT64_FORMAT
- " frames)", prev_frame - parse->prev_frame);
- if (keyframe <= prev_frame && keyframe > parse->prev_keyframe)
- parse->prev_keyframe = keyframe;
- parse->prev_frame = prev_frame;
- }
-
- while (!g_queue_is_empty (parse->buffer_queue)) {
- GstBuffer *buf;
-
- parse->prev_frame++;
- g_assert (parse->prev_frame >= 0);
-
- buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
-
- if (is_keyframe (buf))
- /* we have a keyframe */
- parse->prev_keyframe = parse->prev_frame;
- else
- GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT;
-
- ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe,
- parse->prev_frame);
-
- if (ret != GST_FLOW_OK)
- goto done;
- }
-
-done:
- return ret;
-}
-
-static GstFlowReturn
-theora_parse_queue_buffer (GstTheoraParse * parse, GstBuffer * buf)
-{
- GstFlowReturn ret = GST_FLOW_OK;
-
- buf = gst_buffer_make_metadata_writable (buf);
-
- g_queue_push_tail (parse->buffer_queue, buf);
-
- if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
- if (parse->prev_keyframe < 0) {
- parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf),
- &parse->prev_keyframe, NULL);
- }
- ret = theora_parse_drain_queue (parse, GST_BUFFER_OFFSET_END (buf));
- }
-
- return ret;
-}
-
-static GstFlowReturn
-theora_parse_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstFlowReturn ret;
- GstTheoraParse *parse;
- guint8 *data;
- guint size;
- gboolean have_header;
-
- parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
-
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
-
- have_header = FALSE;
- if (size >= 1) {
- if (data[0] & 0x80)
- have_header = TRUE;
- }
-
- if (have_header) {
- if (parse->send_streamheader) {
- /* we need to collect the headers still */
- /* so put it on the streamheader list and return */
- if (data[0] >= 0x80 && data[0] <= 0x82)
- parse->streamheader[data[0] - 0x80] = buffer;
- }
- ret = GST_FLOW_OK;
- } else {
- /* data packet, push the headers we collected before */
- if (parse->send_streamheader) {
- theora_parse_push_headers (parse);
- parse->send_streamheader = FALSE;
- }
-
- ret = theora_parse_queue_buffer (parse, buffer);
- }
-
- gst_object_unref (parse);
-
- return ret;
-}
-
-static gboolean
-theora_parse_queue_event (GstTheoraParse * parse, GstEvent * event)
-{
- g_queue_push_tail (parse->event_queue, event);
- return TRUE;
-}
-
-static gboolean
-theora_parse_sink_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret;
- GstTheoraParse *parse;
-
- parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_STOP:
- theora_parse_clear_queue (parse);
- parse->prev_keyframe = -1;
- parse->prev_frame = -1;
- ret = gst_pad_event_default (pad, event);
- break;
- case GST_EVENT_EOS:
- theora_parse_drain_queue_prematurely (parse);
- ret = gst_pad_event_default (pad, event);
- break;
- default:
- if (parse->send_streamheader && GST_EVENT_IS_SERIALIZED (event))
- ret = theora_parse_queue_event (parse, event);
- else
- ret = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (parse);
-
- return ret;
-}
-
-static gboolean
-theora_parse_src_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = TRUE;
- GstTheoraParse *parse;
- guint64 scale = 1;
-
- if (src_format == *dest_format) {
- *dest_value = src_value;
- return TRUE;
- }
-
- parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
-
- /* we need the info part before we can done something */
- if (!parse->streamheader_received)
- goto no_header;
-
- switch (src_format) {
- case GST_FORMAT_BYTES:
- switch (*dest_format) {
- case GST_FORMAT_DEFAULT:
- *dest_value = gst_util_uint64_scale_int (src_value, 2,
- parse->info.pic_height * parse->info.pic_width * 3);
- break;
- case GST_FORMAT_TIME:
- /* seems like a rather silly conversion, implement me if you like */
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- scale = 3 * (parse->info.pic_width * parse->info.pic_height) / 2;
- case GST_FORMAT_DEFAULT:
- *dest_value = scale * gst_util_uint64_scale (src_value,
- parse->info.fps_numerator,
- parse->info.fps_denominator * GST_SECOND);
- break;
- default:
- GST_DEBUG_OBJECT (parse, "cannot convert to format %s",
- gst_format_get_name (*dest_format));
- res = FALSE;
- }
- break;
- case GST_FORMAT_DEFAULT:
- switch (*dest_format) {
- case GST_FORMAT_TIME:
- *dest_value = gst_util_uint64_scale (src_value,
- GST_SECOND * parse->info.fps_denominator,
- parse->info.fps_numerator);
- break;
- case GST_FORMAT_BYTES:
- *dest_value = gst_util_uint64_scale_int (src_value,
- 3 * parse->info.pic_width * parse->info.pic_height, 2);
- break;
- default:
- res = FALSE;
- }
- break;
- default:
- res = FALSE;
- }
-done:
- gst_object_unref (parse);
- return res;
-
- /* ERRORS */
-no_header:
- {
- GST_DEBUG_OBJECT (parse, "no header yet, cannot convert");
- res = FALSE;
- goto done;
- }
-}
-
-static gboolean
-theora_parse_src_query (GstPad * pad, GstQuery * query)
-{
- GstTheoraParse *parse;
-
- gboolean res = FALSE;
-
- parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- {
- gint64 frame, value;
- GstFormat my_format, format;
- gint64 time;
-
- frame = parse->prev_frame;
-
- GST_LOG_OBJECT (parse,
- "query %p: we have current frame: %" G_GINT64_FORMAT, query, frame);
-
- /* parse format */
- gst_query_parse_position (query, &format, NULL);
-
- /* and convert to the final format in two steps with time as the
- * intermediate step */
- my_format = GST_FORMAT_TIME;
- if (!(res =
- theora_parse_src_convert (parse->sinkpad, GST_FORMAT_DEFAULT,
- frame, &my_format, &time)))
- goto error;
-
- /* fixme: handle segments
- time = (time - parse->segment.start) + parse->segment.time;
- */
-
- GST_LOG_OBJECT (parse,
- "query %p: our time: %" GST_TIME_FORMAT " (conv to %s)",
- query, GST_TIME_ARGS (time), gst_format_get_name (format));
-
- if (!(res =
- theora_parse_src_convert (pad, my_format, time, &format, &value)))
- goto error;
-
- gst_query_set_position (query, format, value);
-
- GST_LOG_OBJECT (parse,
- "query %p: we return %" G_GINT64_FORMAT " (format %u)", query, value,
- format);
-
- break;
- }
- case GST_QUERY_DURATION:
- /* forward to peer for total */
- if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query)))
- goto error;
- break;
- case GST_QUERY_CONVERT:
- {
- GstFormat src_fmt, dest_fmt;
- gint64 src_val, dest_val;
-
- gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
- if (!(res =
- theora_parse_src_convert (pad, src_fmt, src_val, &dest_fmt,
- &dest_val)))
- goto error;
-
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-done:
- gst_object_unref (parse);
-
- return res;
-
- /* ERRORS */
-error:
- {
- GST_DEBUG_OBJECT (parse, "query failed");
- goto done;
- }
-}
-
-static GstStateChangeReturn
-theora_parse_change_state (GstElement * element, GstStateChange transition)
-{
- GstTheoraParse *parse = GST_THEORA_PARSE (element);
- GstStateChangeReturn ret;
- gint i;
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- th_info_init (&parse->info);
- th_comment_init (&parse->comment);
- parse->send_streamheader = TRUE;
- parse->buffer_queue = g_queue_new ();
- parse->event_queue = g_queue_new ();
- parse->prev_keyframe = -1;
- parse->prev_frame = -1;
- parse->granule_offset = 0;
- break;
- default:
- break;
- }
-
- ret = parent_class->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- th_info_clear (&parse->info);
- th_comment_clear (&parse->comment);
- theora_parse_clear_queue (parse);
- g_queue_free (parse->buffer_queue);
- g_queue_free (parse->event_queue);
- parse->buffer_queue = NULL;
- for (i = 0; i < 3; i++) {
- if (parse->streamheader[i]) {
- gst_buffer_unref (parse->streamheader[i]);
- parse->streamheader[i] = NULL;
- }
- }
- parse->streamheader_received = FALSE;
- break;
- default:
- break;
- }
-
- return ret;
-}
diff --git a/ext/theora/gsttheoraparse.h b/ext/theora/gsttheoraparse.h
deleted file mode 100644
index 83142879..00000000
--- a/ext/theora/gsttheoraparse.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- c-basic-offset: 2 -*-
- * GStreamer
- * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
- * Copyright (C) 2006 Andy Wingo <wingo@pobox.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_THEORA_PARSE_H__
-#define __GST_THEORA_PARSE_H__
-
-
-#include <gst/gst.h>
-#include <theora/theoradec.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_THEORA_PARSE \
- (gst_theora_parse_get_type())
-#define GST_THEORA_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THEORA_PARSE,GstTheoraParse))
-#define GST_THEORA_PARSE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THEORA_PARSE,GstTheoraParseClass))
-#define GST_IS_THEORA_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THEORA_PARSE))
-#define GST_IS_THEORA_PARSE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THEORA_PARSE))
-
-typedef struct _GstTheoraParse GstTheoraParse;
-typedef struct _GstTheoraParseClass GstTheoraParseClass;
-
-/**
- * GstTheoraParse:
- *
- * Opaque data structure.
- */
-struct _GstTheoraParse {
- GstElement element;
-
- GstPad * sinkpad;
- GstPad * srcpad;
-
- gboolean send_streamheader;
- gboolean streamheader_received;
- gboolean is_old_bitstream;
- GstBuffer * streamheader[3];
-
- GQueue * event_queue;
- GQueue * buffer_queue;
-
- th_info info;
- th_comment comment;
-
- gint64 prev_frame;
- gint64 prev_keyframe;
- guint32 fps_n;
- guint32 fps_d;
- gint shift;
- gint64 granule_offset;
-
- GstClockTime *times;
- gint npairs;
-};
-
-struct _GstTheoraParseClass {
- GstElementClass parent_class;
-};
-
-GType gst_theora_parse_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_THEORA_PARSE_H__ */
diff --git a/ext/vorbis/Makefile.am b/ext/vorbis/Makefile.am
deleted file mode 100644
index fc285a8d..00000000
--- a/ext/vorbis/Makefile.am
+++ /dev/null
@@ -1,46 +0,0 @@
-plugin_LTLIBRARIES =
-
-if USE_VORBIS
-plugin_LTLIBRARIES += libgstvorbis.la
-
-libgstvorbis_la_SOURCES = gstvorbis.c \
- gstvorbisdec.c \
- gstvorbisdeclib.c \
- gstvorbisenc.c \
- gstvorbisparse.c \
- gstvorbistag.c \
- gstvorbiscommon.c
-
-libgstvorbis_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(VORBIS_CFLAGS)
-## AM_PATH_VORBIS also sets VORBISENC_LIBS
-libgstvorbis_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/tag/libgsttag-@GST_MAJORMINOR@.la \
- $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \
- $(GST_LIBS) \
- $(VORBIS_LIBS) $(VORBISENC_LIBS)
-libgstvorbis_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstvorbis_la_LIBTOOLFLAGS = --tag=disable-static
-endif
-
-if USE_IVORBIS
-plugin_LTLIBRARIES += libgstivorbisdec.la
-
-libgstivorbisdec_la_SOURCES = gstivorbisdec.c \
- gstvorbisdec.c gstvorbisdeclib.c gstvorbiscommon.c
-libgstivorbisdec_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
- -DTREMOR $(IVORBIS_CFLAGS)
-libgstivorbisdec_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/tag/libgsttag-@GST_MAJORMINOR@.la \
- $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \
- $(GST_LIBS) $(IVORBIS_LIBS)
-libgstivorbisdec_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgstivorbisdec_la_LIBTOOLFLAGS = --tag=disable-static
-endif
-
-noinst_HEADERS = gstvorbisenc.h \
- gstvorbisdec.h \
- gstvorbisdeclib.h \
- gstvorbisparse.h \
- gstvorbistag.h \
- gstvorbiscommon.h
-
diff --git a/ext/vorbis/README b/ext/vorbis/README
deleted file mode 100644
index 6b315101..00000000
--- a/ext/vorbis/README
+++ /dev/null
@@ -1,16 +0,0 @@
-oggvorbisenc : encodes to vorbis inside an ogg stream. This is not the
- GStreamer way of doing things and should be removed for
- 0.9. It is still called "vorbisenc" for backward compatibility
- reasons. It also takes integer audio as input.
-vorbisenc : Encodes to a raw vorbis stream and should be used together
- with an ogg muxer such as "oggmux" it is called "rawvorbisenc".
- It also takes raw float samples as input.
-
-TODO for 0.9:
-
-- remove oggvorbisenc.c and oggvorbisenc.h
-- remove references to oggvorbisenc.[ch] in the Makefile and in vorbis.c
-- remove the element vorbisenc.
-- rename the element rawvorbisenc to vorbisenc.
-
-
diff --git a/ext/vorbis/gstivorbisdec.c b/ext/vorbis/gstivorbisdec.c
deleted file mode 100644
index d938238d..00000000
--- a/ext/vorbis/gstivorbisdec.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * 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 "gstvorbisdec.h"
-
-GST_DEBUG_CATEGORY (vorbisdec_debug);
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
-
- /* if tremor is around, there is probably good reason for it, so preferred */
- if (!gst_element_register (plugin, "ivorbisdec", GST_RANK_SECONDARY,
- gst_vorbis_dec_get_type ()))
- return FALSE;
-
- GST_DEBUG_CATEGORY_INIT (vorbisdec_debug, "ivorbisdec", 0,
- "vorbis decoding element (integer decoder)");
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "ivorbisdec",
- "Vorbis Tremor decoder",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/vorbis/gstvorbis.c b/ext/vorbis/gstvorbis.c
deleted file mode 100644
index f710aaa3..00000000
--- a/ext/vorbis/gstvorbis.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * 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/tag/tag.h"
-
-#include "gstvorbisenc.h"
-#include "gstvorbisdec.h"
-#include "gstvorbisparse.h"
-#include "gstvorbistag.h"
-
-GST_DEBUG_CATEGORY (vorbisenc_debug);
-GST_DEBUG_CATEGORY (vorbisdec_debug);
-GST_DEBUG_CATEGORY (vorbisparse_debug);
-GST_DEBUG_CATEGORY (vorbistag_debug);
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- if (!gst_element_register (plugin, "vorbisenc", GST_RANK_PRIMARY,
- GST_TYPE_VORBISENC))
- return FALSE;
-
- if (!gst_element_register (plugin, "vorbisdec", GST_RANK_PRIMARY,
- gst_vorbis_dec_get_type ()))
- return FALSE;
-
- if (!gst_element_register (plugin, "vorbisparse", GST_RANK_NONE,
- gst_vorbis_parse_get_type ()))
- return FALSE;
-
- if (!gst_element_register (plugin, "vorbistag", GST_RANK_NONE,
- gst_vorbis_tag_get_type ()))
- return FALSE;
-
- GST_DEBUG_CATEGORY_INIT (vorbisenc_debug, "vorbisenc", 0,
- "vorbis encoding element");
- GST_DEBUG_CATEGORY_INIT (vorbisdec_debug, "vorbisdec", 0,
- "vorbis decoding element");
- GST_DEBUG_CATEGORY_INIT (vorbisparse_debug, "vorbisparse", 0,
- "vorbis parsing element");
- GST_DEBUG_CATEGORY_INIT (vorbistag_debug, "vorbistag", 0,
- "vorbis tagging element");
-
- gst_tag_register_musicbrainz_tags ();
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "vorbis",
- "Vorbis plugin library",
- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/vorbis/gstvorbiscommon.c b/ext/vorbis/gstvorbiscommon.c
deleted file mode 100644
index c4dd408d..00000000
--- a/ext/vorbis/gstvorbiscommon.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* GStreamer
- * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * 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 "gstvorbiscommon.h"
-
-/* http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 */
-const GstAudioChannelPosition gst_vorbis_channel_positions[][8] = {
- { /* Mono */
- GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
- { /* Stereo */
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
- { /* Stereo + Centre */
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
- { /* Quadraphonic */
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
- GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
- },
- { /* Stereo + Centre + rear stereo */
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
- GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
- },
- { /* Full 5.1 Surround */
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
- GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_LFE,
- },
- { /* 6.1 Surround, in Vorbis spec since 2010-01-13 */
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
- GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
- GST_AUDIO_CHANNEL_POSITION_LFE},
- { /* 7.1 Surround, in Vorbis spec since 2010-01-13 */
- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
- GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
- GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
- GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
- GST_AUDIO_CHANNEL_POSITION_LFE},
-};
diff --git a/ext/vorbis/gstvorbiscommon.h b/ext/vorbis/gstvorbiscommon.h
deleted file mode 100644
index 563b8f71..00000000
--- a/ext/vorbis/gstvorbiscommon.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* GStreamer
- * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
- *
- * 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_VORBIS_COMMON_H__
-#define __GST_VORBIS_COMMON_H__
-
-#include <gst/gst.h>
-#include <gst/audio/multichannel.h>
-
-extern const GstAudioChannelPosition gst_vorbis_channel_positions[][8];
-
-#endif /* __GST_VORBIS_COMMON_H__ */
diff --git a/ext/vorbis/gstvorbisdec.c b/ext/vorbis/gstvorbisdec.c
deleted file mode 100644
index 85f36d09..00000000
--- a/ext/vorbis/gstvorbisdec.c
+++ /dev/null
@@ -1,1228 +0,0 @@
-/* GStreamer
- * Copyright (C) 2004 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.
- */
-
-/**
- * SECTION:element-vorbisdec
- * @see_also: vorbisenc, oggdemux
- *
- * This element decodes a Vorbis stream to raw float audio.
- * <ulink url="http://www.vorbis.com/">Vorbis</ulink> is a royalty-free
- * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
- * Foundation</ulink>.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! alsasink
- * ]| Decode an Ogg/Vorbis. To create an Ogg/Vorbis file refer to the documentation of vorbisenc.
- * </refsect2>
- *
- * Last reviewed on 2006-03-01 (0.10.4)
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gstvorbisdec.h"
-#include <string.h>
-#include <gst/audio/audio.h>
-#include <gst/tag/tag.h>
-#include <gst/audio/multichannel.h>
-
-#include "gstvorbiscommon.h"
-
-GST_DEBUG_CATEGORY_EXTERN (vorbisdec_debug);
-#define GST_CAT_DEFAULT vorbisdec_debug
-
-static const GstElementDetails vorbis_dec_details =
- GST_VORBIS_DEC_ELEMENT_DETAILS;
-
-static GstStaticPadTemplate vorbis_dec_src_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_VORBIS_DEC_SRC_CAPS);
-
-static GstStaticPadTemplate vorbis_dec_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-vorbis")
- );
-
-GST_BOILERPLATE (GST_VORBIS_DEC_GLIB_TYPE_NAME, gst_vorbis_dec, GstElement,
- GST_TYPE_ELEMENT);
-
-static void vorbis_dec_finalize (GObject * object);
-static gboolean vorbis_dec_sink_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn vorbis_dec_chain (GstPad * pad, GstBuffer * buffer);
-static GstFlowReturn vorbis_dec_chain_forward (GstVorbisDec * vd,
- gboolean discont, GstBuffer * buffer);
-static GstStateChangeReturn vorbis_dec_change_state (GstElement * element,
- GstStateChange transition);
-
-static gboolean vorbis_dec_src_event (GstPad * pad, GstEvent * event);
-static gboolean vorbis_dec_src_query (GstPad * pad, GstQuery * query);
-static gboolean vorbis_dec_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value);
-
-static gboolean vorbis_dec_sink_query (GstPad * pad, GstQuery * query);
-
-static void
-gst_vorbis_dec_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- GstPadTemplate *src_template, *sink_template;
-
- src_template = gst_static_pad_template_get (&vorbis_dec_src_factory);
- gst_element_class_add_pad_template (element_class, src_template);
-
- sink_template = gst_static_pad_template_get (&vorbis_dec_sink_factory);
- gst_element_class_add_pad_template (element_class, sink_template);
-
- gst_element_class_set_details (element_class, &vorbis_dec_details);
-}
-
-static void
-gst_vorbis_dec_class_init (GstVorbisDecClass * klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gobject_class->finalize = vorbis_dec_finalize;
-
- gstelement_class->change_state = GST_DEBUG_FUNCPTR (vorbis_dec_change_state);
-}
-
-static const GstQueryType *
-vorbis_get_query_types (GstPad * pad)
-{
- static const GstQueryType vorbis_dec_src_query_types[] = {
- GST_QUERY_POSITION,
- GST_QUERY_DURATION,
- GST_QUERY_CONVERT,
- 0
- };
-
- return vorbis_dec_src_query_types;
-}
-
-static void
-gst_vorbis_dec_init (GstVorbisDec * dec, GstVorbisDecClass * g_class)
-{
- dec->sinkpad = gst_pad_new_from_static_template (&vorbis_dec_sink_factory,
- "sink");
-
- gst_pad_set_event_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (vorbis_dec_sink_event));
- gst_pad_set_chain_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (vorbis_dec_chain));
- gst_pad_set_query_function (dec->sinkpad,
- GST_DEBUG_FUNCPTR (vorbis_dec_sink_query));
- gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
-
- dec->srcpad = gst_pad_new_from_static_template (&vorbis_dec_src_factory,
- "src");
-
- gst_pad_set_event_function (dec->srcpad,
- GST_DEBUG_FUNCPTR (vorbis_dec_src_event));
- gst_pad_set_query_type_function (dec->srcpad,
- GST_DEBUG_FUNCPTR (vorbis_get_query_types));
- gst_pad_set_query_function (dec->srcpad,
- GST_DEBUG_FUNCPTR (vorbis_dec_src_query));
- gst_pad_use_fixed_caps (dec->srcpad);
- gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
-
- dec->queued = NULL;
- dec->pendingevents = NULL;
- dec->taglist = NULL;
-}
-
-static void
-vorbis_dec_finalize (GObject * object)
-{
- /* Release any possibly allocated libvorbis data.
- * _clear functions can safely be called multiple times
- */
- GstVorbisDec *vd = GST_VORBIS_DEC (object);
-
- vorbis_block_clear (&vd->vb);
- vorbis_dsp_clear (&vd->vd);
- vorbis_comment_clear (&vd->vc);
- vorbis_info_clear (&vd->vi);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_vorbis_dec_reset (GstVorbisDec * dec)
-{
- dec->last_timestamp = GST_CLOCK_TIME_NONE;
- dec->discont = TRUE;
- dec->seqnum = gst_util_seqnum_next ();
- gst_segment_init (&dec->segment, GST_FORMAT_TIME);
-
- g_list_foreach (dec->queued, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (dec->queued);
- dec->queued = NULL;
- g_list_foreach (dec->gather, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (dec->gather);
- dec->gather = NULL;
- g_list_foreach (dec->decode, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (dec->decode);
- dec->decode = NULL;
- g_list_foreach (dec->pendingevents, (GFunc) gst_mini_object_unref, NULL);
- g_list_free (dec->pendingevents);
- dec->pendingevents = NULL;
-
- if (dec->taglist)
- gst_tag_list_free (dec->taglist);
- dec->taglist = NULL;
-}
-
-
-static gboolean
-vorbis_dec_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = TRUE;
- GstVorbisDec *dec;
- guint64 scale = 1;
-
- if (src_format == *dest_format) {
- *dest_value = src_value;
- return TRUE;
- }
-
- dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
-
- if (!dec->initialized)
- goto no_header;
-
- if (dec->sinkpad == pad &&
- (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
- goto no_format;
-
- switch (src_format) {
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- scale = dec->width * dec->vi.channels;
- case GST_FORMAT_DEFAULT:
- *dest_value =
- scale * gst_util_uint64_scale_int (src_value, dec->vi.rate,
- GST_SECOND);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_DEFAULT:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- *dest_value = src_value * dec->width * dec->vi.channels;
- break;
- case GST_FORMAT_TIME:
- *dest_value =
- gst_util_uint64_scale_int (src_value, GST_SECOND, dec->vi.rate);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_BYTES:
- switch (*dest_format) {
- case GST_FORMAT_DEFAULT:
- *dest_value = src_value / (dec->width * dec->vi.channels);
- break;
- case GST_FORMAT_TIME:
- *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
- dec->vi.rate * dec->width * dec->vi.channels);
- break;
- default:
- res = FALSE;
- }
- break;
- default:
- res = FALSE;
- }
-done:
- gst_object_unref (dec);
-
- return res;
-
- /* ERRORS */
-no_header:
- {
- GST_DEBUG_OBJECT (dec, "no header packets received");
- res = FALSE;
- goto done;
- }
-no_format:
- {
- GST_DEBUG_OBJECT (dec, "formats unsupported");
- res = FALSE;
- goto done;
- }
-}
-
-static gboolean
-vorbis_dec_src_query (GstPad * pad, GstQuery * query)
-{
- GstVorbisDec *dec;
- gboolean res = FALSE;
-
- dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- {
- gint64 value;
- GstFormat format;
- gint64 time;
-
- gst_query_parse_position (query, &format, NULL);
-
- /* we start from the last seen time */
- time = dec->last_timestamp;
- /* correct for the segment values */
- time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, time);
-
- GST_LOG_OBJECT (dec,
- "query %p: our time: %" GST_TIME_FORMAT, query, GST_TIME_ARGS (time));
-
- /* and convert to the final format */
- if (!(res =
- vorbis_dec_convert (pad, GST_FORMAT_TIME, time, &format, &value)))
- goto error;
-
- gst_query_set_position (query, format, value);
-
- GST_LOG_OBJECT (dec,
- "query %p: we return %" G_GINT64_FORMAT " (format %u)", query, value,
- format);
-
- break;
- }
- case GST_QUERY_DURATION:
- {
- res = gst_pad_peer_query (dec->sinkpad, query);
- if (!res)
- goto error;
-
- break;
- }
- case GST_QUERY_CONVERT:
- {
- GstFormat src_fmt, dest_fmt;
- gint64 src_val, dest_val;
-
- gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
- if (!(res =
- vorbis_dec_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val)))
- goto error;
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-done:
- gst_object_unref (dec);
-
- return res;
-
- /* ERRORS */
-error:
- {
- GST_WARNING_OBJECT (dec, "error handling query");
- goto done;
- }
-}
-
-static gboolean
-vorbis_dec_sink_query (GstPad * pad, GstQuery * query)
-{
- GstVorbisDec *dec;
- gboolean res;
-
- dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_CONVERT:
- {
- GstFormat src_fmt, dest_fmt;
- gint64 src_val, dest_val;
-
- gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
- if (!(res =
- vorbis_dec_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val)))
- goto error;
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-
-done:
- gst_object_unref (dec);
-
- return res;
-
- /* ERRORS */
-error:
- {
- GST_DEBUG_OBJECT (dec, "error converting value");
- goto done;
- }
-}
-
-static gboolean
-vorbis_dec_src_event (GstPad * pad, GstEvent * event)
-{
- gboolean res = TRUE;
- GstVorbisDec *dec;
-
- dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- {
- GstFormat format, tformat;
- gdouble rate;
- GstEvent *real_seek;
- GstSeekFlags flags;
- GstSeekType cur_type, stop_type;
- gint64 cur, stop;
- gint64 tcur, tstop;
- guint32 seqnum;
-
- gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
- &stop_type, &stop);
- seqnum = gst_event_get_seqnum (event);
- gst_event_unref (event);
-
- /* First bring the requested format to time */
- tformat = GST_FORMAT_TIME;
- if (!(res = vorbis_dec_convert (pad, format, cur, &tformat, &tcur)))
- goto convert_error;
- if (!(res = vorbis_dec_convert (pad, format, stop, &tformat, &tstop)))
- goto convert_error;
-
- /* then seek with time on the peer */
- real_seek = gst_event_new_seek (rate, GST_FORMAT_TIME,
- flags, cur_type, tcur, stop_type, tstop);
- gst_event_set_seqnum (real_seek, seqnum);
-
- res = gst_pad_push_event (dec->sinkpad, real_seek);
- break;
- }
- default:
- res = gst_pad_push_event (dec->sinkpad, event);
- break;
- }
-done:
- gst_object_unref (dec);
-
- return res;
-
- /* ERRORS */
-convert_error:
- {
- GST_DEBUG_OBJECT (dec, "cannot convert start/stop for seek");
- goto done;
- }
-}
-
-static gboolean
-vorbis_dec_sink_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret = FALSE;
- GstVorbisDec *dec;
-
- dec = GST_VORBIS_DEC (gst_pad_get_parent (pad));
-
- GST_LOG_OBJECT (dec, "handling event");
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- ret = gst_pad_push_event (dec->srcpad, event);
- break;
- case GST_EVENT_FLUSH_START:
- ret = gst_pad_push_event (dec->srcpad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- /* here we must clean any state in the decoder */
-#ifdef HAVE_VORBIS_SYNTHESIS_RESTART
- vorbis_synthesis_restart (&dec->vd);
-#endif
- gst_vorbis_dec_reset (dec);
- ret = gst_pad_push_event (dec->srcpad, event);
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
- gboolean update;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
-
- /* we need time for now */
- if (format != GST_FORMAT_TIME)
- goto newseg_wrong_format;
-
- GST_DEBUG_OBJECT (dec,
- "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
- ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
- update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
- GST_TIME_ARGS (time));
-
- /* now configure the values */
- gst_segment_set_newsegment_full (&dec->segment, update,
- rate, arate, format, start, stop, time);
- dec->seqnum = gst_event_get_seqnum (event);
-
- if (dec->initialized)
- /* and forward */
- ret = gst_pad_push_event (dec->srcpad, event);
- else {
- /* store it to send once we're initialized */
- dec->pendingevents = g_list_append (dec->pendingevents, event);
- ret = TRUE;
- }
- break;
- }
- case GST_EVENT_TAG:
- {
- if (dec->initialized)
- /* and forward */
- ret = gst_pad_push_event (dec->srcpad, event);
- else {
- /* store it to send once we're initialized */
- dec->pendingevents = g_list_append (dec->pendingevents, event);
- ret = TRUE;
- }
- break;
- }
- default:
- ret = gst_pad_push_event (dec->srcpad, event);
- break;
- }
-done:
- gst_object_unref (dec);
-
- return ret;
-
- /* ERRORS */
-newseg_wrong_format:
- {
- GST_DEBUG_OBJECT (dec, "received non TIME newsegment");
- goto done;
- }
-}
-
-static GstFlowReturn
-vorbis_handle_identification_packet (GstVorbisDec * vd)
-{
- GstCaps *caps;
- const GstAudioChannelPosition *pos = NULL;
- gint width = GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH;
-
- switch (vd->vi.channels) {
- case 1:
- case 2:
- /* nothing */
- break;
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- pos = gst_vorbis_channel_positions[vd->vi.channels - 1];
- break;
- default:{
- gint i;
- GstAudioChannelPosition *posn =
- g_new (GstAudioChannelPosition, vd->vi.channels);
-
- GST_ELEMENT_WARNING (GST_ELEMENT (vd), STREAM, DECODE,
- (NULL), ("Using NONE channel layout for more than 8 channels"));
-
- for (i = 0; i < vd->vi.channels; i++)
- posn[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
-
- pos = posn;
- }
- }
-
- /* negotiate width with downstream */
- caps = gst_pad_get_allowed_caps (vd->srcpad);
- if (caps) {
- if (!gst_caps_is_empty (caps)) {
- GstStructure *s;
-
- s = gst_caps_get_structure (caps, 0);
- /* template ensures 16 or 32 */
- gst_structure_get_int (s, "width", &width);
- }
- gst_caps_unref (caps);
- }
- vd->width = width >> 3;
-
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (vd->srcpad));
- gst_caps_set_simple (caps, "rate", G_TYPE_INT, vd->vi.rate,
- "channels", G_TYPE_INT, vd->vi.channels,
- "width", G_TYPE_INT, width, NULL);
-
- if (pos) {
- gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos);
- }
-
- if (vd->vi.channels > 8) {
- g_free ((GstAudioChannelPosition *) pos);
- }
-
- gst_pad_set_caps (vd->srcpad, caps);
- gst_caps_unref (caps);
-
- return GST_FLOW_OK;
-}
-
-static GstFlowReturn
-vorbis_handle_comment_packet (GstVorbisDec * vd, ogg_packet * packet)
-{
- guint bitrate = 0;
- gchar *encoder = NULL;
- GstTagList *list, *old_list;
- GstBuffer *buf;
-
- GST_DEBUG_OBJECT (vd, "parsing comment packet");
-
- buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = gst_ogg_packet_data (packet);
- GST_BUFFER_SIZE (buf) = gst_ogg_packet_size (packet);
-
- list =
- gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\003vorbis", 7,
- &encoder);
-
- old_list = vd->taglist;
- vd->taglist = gst_tag_list_merge (vd->taglist, list, GST_TAG_MERGE_REPLACE);
-
- if (old_list)
- gst_tag_list_free (old_list);
- gst_tag_list_free (list);
- gst_buffer_unref (buf);
-
- if (!vd->taglist) {
- GST_ERROR_OBJECT (vd, "couldn't decode comments");
- vd->taglist = gst_tag_list_new ();
- }
- if (encoder) {
- if (encoder[0])
- gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_ENCODER, encoder, NULL);
- g_free (encoder);
- }
- gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_ENCODER_VERSION, vd->vi.version,
- GST_TAG_AUDIO_CODEC, "Vorbis", NULL);
- if (vd->vi.bitrate_nominal > 0 && vd->vi.bitrate_nominal <= 0x7FFFFFFF) {
- gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_NOMINAL_BITRATE, (guint) vd->vi.bitrate_nominal, NULL);
- bitrate = vd->vi.bitrate_nominal;
- }
- if (vd->vi.bitrate_upper > 0 && vd->vi.bitrate_upper <= 0x7FFFFFFF) {
- gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_MAXIMUM_BITRATE, (guint) vd->vi.bitrate_upper, NULL);
- if (!bitrate)
- bitrate = vd->vi.bitrate_upper;
- }
- if (vd->vi.bitrate_lower > 0 && vd->vi.bitrate_lower <= 0x7FFFFFFF) {
- gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_MINIMUM_BITRATE, (guint) vd->vi.bitrate_lower, NULL);
- if (!bitrate)
- bitrate = vd->vi.bitrate_lower;
- }
- if (bitrate) {
- gst_tag_list_add (vd->taglist, GST_TAG_MERGE_REPLACE,
- GST_TAG_BITRATE, (guint) bitrate, NULL);
- }
-
- if (vd->initialized) {
- gst_element_found_tags_for_pad (GST_ELEMENT_CAST (vd), vd->srcpad,
- vd->taglist);
- vd->taglist = NULL;
- } else {
- /* Only post them as messages for the time being. *
- * They will be pushed on the pad once the decoder is initialized */
- gst_element_post_message (GST_ELEMENT_CAST (vd),
- gst_message_new_tag (GST_OBJECT (vd), gst_tag_list_copy (vd->taglist)));
- }
-
- return GST_FLOW_OK;
-}
-
-static GstFlowReturn
-vorbis_handle_type_packet (GstVorbisDec * vd)
-{
- GList *walk;
- gint res;
-
- g_assert (vd->initialized == FALSE);
-
- if (G_UNLIKELY ((res = vorbis_synthesis_init (&vd->vd, &vd->vi))))
- goto synthesis_init_error;
-
- if (G_UNLIKELY ((res = vorbis_block_init (&vd->vd, &vd->vb))))
- goto block_init_error;
-
- vd->initialized = TRUE;
-
- if (vd->pendingevents) {
- for (walk = vd->pendingevents; walk; walk = g_list_next (walk))
- gst_pad_push_event (vd->srcpad, GST_EVENT_CAST (walk->data));
- g_list_free (vd->pendingevents);
- vd->pendingevents = NULL;
- }
-
- if (vd->taglist) {
- /* The tags have already been sent on the bus as messages. */
- gst_pad_push_event (vd->srcpad, gst_event_new_tag (vd->taglist));
- vd->taglist = NULL;
- }
- return GST_FLOW_OK;
-
- /* ERRORS */
-synthesis_init_error:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
- (NULL), ("couldn't initialize synthesis (%d)", res));
- return GST_FLOW_ERROR;
- }
-block_init_error:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
- (NULL), ("couldn't initialize block (%d)", res));
- return GST_FLOW_ERROR;
- }
-}
-
-static GstFlowReturn
-vorbis_handle_header_packet (GstVorbisDec * vd, ogg_packet * packet)
-{
- GstFlowReturn res;
- gint ret;
-
- GST_DEBUG_OBJECT (vd, "parsing header packet");
-
- /* Packetno = 0 if the first byte is exactly 0x01 */
- packet->b_o_s = ((gst_ogg_packet_data (packet))[0] == 0x1) ? 1 : 0;
-
- if ((ret = vorbis_synthesis_headerin (&vd->vi, &vd->vc, packet)))
- goto header_read_error;
-
- switch ((gst_ogg_packet_data (packet))[0]) {
- case 0x01:
- res = vorbis_handle_identification_packet (vd);
- break;
- case 0x03:
- res = vorbis_handle_comment_packet (vd, packet);
- break;
- case 0x05:
- res = vorbis_handle_type_packet (vd);
- break;
- default:
- /* ignore */
- g_warning ("unknown vorbis header packet found");
- res = GST_FLOW_OK;
- break;
- }
- return res;
-
- /* ERRORS */
-header_read_error:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
- (NULL), ("couldn't read header packet (%d)", ret));
- return GST_FLOW_ERROR;
- }
-}
-
-static GstFlowReturn
-vorbis_dec_push_forward (GstVorbisDec * dec, GstBuffer * buf)
-{
- GstFlowReturn result;
-
- /* clip */
- if (!(buf = gst_audio_buffer_clip (buf, &dec->segment, dec->vi.rate,
- dec->vi.channels * dec->width))) {
- GST_LOG_OBJECT (dec, "clipped buffer");
- return GST_FLOW_OK;
- }
-
- if (dec->discont) {
- GST_LOG_OBJECT (dec, "setting DISCONT");
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
- dec->discont = FALSE;
- }
-
- GST_DEBUG_OBJECT (dec,
- "pushing time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
- GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
-
- result = gst_pad_push (dec->srcpad, buf);
-
- return result;
-}
-
-static GstFlowReturn
-vorbis_dec_push_reverse (GstVorbisDec * dec, GstBuffer * buf)
-{
- GstFlowReturn result = GST_FLOW_OK;
-
- dec->queued = g_list_prepend (dec->queued, buf);
-
- return result;
-}
-
-static void
-vorbis_do_timestamps (GstVorbisDec * vd, GstBuffer * buf, gboolean reverse,
- GstClockTime timestamp, GstClockTime duration)
-{
- /* interpolate reverse */
- if (vd->last_timestamp != -1 && reverse)
- vd->last_timestamp -= duration;
-
- /* take buffer timestamp, use interpolated timestamp otherwise */
- if (timestamp != -1)
- vd->last_timestamp = timestamp;
- else
- timestamp = vd->last_timestamp;
-
- /* interpolate forwards */
- if (vd->last_timestamp != -1 && !reverse)
- vd->last_timestamp += duration;
-
- GST_BUFFER_TIMESTAMP (buf) = timestamp;
- GST_BUFFER_DURATION (buf) = duration;
-}
-
-static GstFlowReturn
-vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
- GstClockTime timestamp, GstClockTime duration)
-{
- vorbis_sample_t **pcm;
- guint sample_count;
- GstBuffer *out;
- GstFlowReturn result;
- gint size;
-
- if (G_UNLIKELY (!vd->initialized))
- goto not_initialized;
-
- /* normal data packet */
- /* FIXME, we can skip decoding if the packet is outside of the
- * segment, this is however not very trivial as we need a previous
- * packet to decode the current one so we must be carefull not to
- * throw away too much. For now we decode everything and clip right
- * before pushing data. */
- if (G_UNLIKELY (vorbis_synthesis (&vd->vb, packet)))
- goto could_not_read;
-
- if (G_UNLIKELY (vorbis_synthesis_blockin (&vd->vd, &vd->vb) < 0))
- goto not_accepted;
-
- /* assume all goes well here */
- result = GST_FLOW_OK;
-
- /* count samples ready for reading */
- if ((sample_count = vorbis_synthesis_pcmout (&vd->vd, NULL)) == 0)
- goto done;
-
- size = sample_count * vd->vi.channels * vd->width;
- GST_LOG_OBJECT (vd, "%d samples ready for reading, size %d", sample_count,
- size);
-
- /* alloc buffer for it */
- result =
- gst_pad_alloc_buffer_and_set_caps (vd->srcpad, GST_BUFFER_OFFSET_NONE,
- size, GST_PAD_CAPS (vd->srcpad), &out);
- if (G_UNLIKELY (result != GST_FLOW_OK))
- goto done;
-
- /* get samples ready for reading now, should be sample_count */
- if (G_UNLIKELY ((vorbis_synthesis_pcmout (&vd->vd, &pcm)) != sample_count))
- goto wrong_samples;
-
- /* copy samples in buffer */
- copy_samples ((vorbis_sample_t *) GST_BUFFER_DATA (out), pcm, sample_count,
- vd->vi.channels, vd->width);
-
- GST_LOG_OBJECT (vd, "setting output size to %d", size);
- GST_BUFFER_SIZE (out) = size;
-
- /* this should not overflow */
- if (duration == -1)
- duration = sample_count * GST_SECOND / vd->vi.rate;
-
- vorbis_do_timestamps (vd, out, FALSE, timestamp, duration);
-
- if (vd->segment.rate >= 0.0)
- result = vorbis_dec_push_forward (vd, out);
- else
- result = vorbis_dec_push_reverse (vd, out);
-
-done:
- vorbis_synthesis_read (&vd->vd, sample_count);
-
- return result;
-
- /* ERRORS */
-not_initialized:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
- (NULL), ("no header sent yet"));
- return GST_FLOW_ERROR;
- }
-could_not_read:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
- (NULL), ("couldn't read data packet"));
- return GST_FLOW_ERROR;
- }
-not_accepted:
- {
- GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
- (NULL), ("vorbis decoder did not accept data packet"));
- return GST_FLOW_ERROR;
- }
-wrong_samples:
- {
- gst_buffer_unref (out);
- GST_ELEMENT_ERROR (GST_ELEMENT (vd), STREAM, DECODE,
- (NULL), ("vorbis decoder reported wrong number of samples"));
- return GST_FLOW_ERROR;
- }
-}
-
-static GstFlowReturn
-vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer)
-{
- ogg_packet *packet;
- ogg_packet_wrapper packet_wrapper;
- GstFlowReturn result = GST_FLOW_OK;
-
- /* make ogg_packet out of the buffer */
- gst_ogg_packet_wrapper_from_buffer (&packet_wrapper, buffer);
- packet = gst_ogg_packet_from_wrapper (&packet_wrapper);
- /* set some more stuff */
- packet->granulepos = -1;
- packet->packetno = 0; /* we don't care */
- /* EOS does not matter, it is used in vorbis to implement clipping the last
- * block of samples based on the granulepos. We clip based on segments. */
- packet->e_o_s = 0;
-
- GST_LOG_OBJECT (vd, "decode buffer of size %ld", packet->bytes);
-
- /* error out on empty header packets, but just skip empty data packets */
- if (G_UNLIKELY (packet->bytes == 0)) {
- if (vd->initialized)
- goto empty_buffer;
- else
- goto empty_header;
- }
-
- /* switch depending on packet type */
- if ((gst_ogg_packet_data (packet))[0] & 1) {
- if (vd->initialized) {
- GST_WARNING_OBJECT (vd, "Already initialized, so ignoring header packet");
- goto done;
- }
- result = vorbis_handle_header_packet (vd, packet);
- } else {
- GstClockTime timestamp, duration;
-
- timestamp = GST_BUFFER_TIMESTAMP (buffer);
- duration = GST_BUFFER_DURATION (buffer);
-
- result = vorbis_handle_data_packet (vd, packet, timestamp, duration);
- }
-
-done:
- return result;
-
-empty_buffer:
- {
- /* don't error out here, just ignore the buffer, it's invalid for vorbis
- * but not fatal. */
- GST_WARNING_OBJECT (vd, "empty buffer received, ignoring");
- result = GST_FLOW_OK;
- goto done;
- }
-
-/* ERRORS */
-empty_header:
- {
- GST_ELEMENT_ERROR (vd, STREAM, DECODE, (NULL), ("empty header received"));
- result = GST_FLOW_ERROR;
- vd->discont = TRUE;
- goto done;
- }
-}
-
-/*
- * Input:
- * Buffer decoding order: 7 8 9 4 5 6 3 1 2 EOS
- * Discont flag: D D D D
- *
- * - Each Discont marks a discont in the decoding order.
- *
- * for vorbis, each buffer is a keyframe when we have the previous
- * buffer. This means that to decode buffer 7, we need buffer 6, which
- * arrives out of order.
- *
- * we first gather buffers in the gather queue until we get a DISCONT. We
- * prepend each incomming buffer so that they are in reversed order.
- *
- * gather queue: 9 8 7
- * decode queue:
- * output queue:
- *
- * When a DISCONT is received (buffer 4), we move the gather queue to the
- * decode queue. This is simply done be taking the head of the gather queue
- * and prepending it to the decode queue. This yields:
- *
- * gather queue:
- * decode queue: 7 8 9
- * output queue:
- *
- * Then we decode each buffer in the decode queue in order and put the output
- * buffer in the output queue. The first buffer (7) will not produce any output
- * because it needs the previous buffer (6) which did not arrive yet. This
- * yields:
- *
- * gather queue:
- * decode queue: 7 8 9
- * output queue: 9 8
- *
- * Then we remove the consumed buffers from the decode queue. Buffer 7 is not
- * completely consumed, we need to keep it around for when we receive buffer
- * 6. This yields:
- *
- * gather queue:
- * decode queue: 7
- * output queue: 9 8
- *
- * Then we accumulate more buffers:
- *
- * gather queue: 6 5 4
- * decode queue: 7
- * output queue:
- *
- * prepending to the decode queue on DISCONT yields:
- *
- * gather queue:
- * decode queue: 4 5 6 7
- * output queue:
- *
- * after decoding and keeping buffer 4:
- *
- * gather queue:
- * decode queue: 4
- * output queue: 7 6 5
- *
- * Etc..
- */
-static GstFlowReturn
-vorbis_dec_flush_decode (GstVorbisDec * dec)
-{
- GstFlowReturn res = GST_FLOW_OK;
- GList *walk;
-
- walk = dec->decode;
-
- GST_DEBUG_OBJECT (dec, "flushing buffers to decoder");
-
- while (walk) {
- GList *next;
- GstBuffer *buf = GST_BUFFER_CAST (walk->data);
-
- GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT,
- buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
-
- next = g_list_next (walk);
-
- /* decode buffer, prepend to output queue */
- res = vorbis_dec_decode_buffer (dec, buf);
-
- /* if we generated output, we can discard the buffer, else we
- * keep it in the queue */
- if (dec->queued) {
- GST_DEBUG_OBJECT (dec, "decoded buffer to %p", dec->queued->data);
- dec->decode = g_list_delete_link (dec->decode, walk);
- gst_buffer_unref (buf);
- } else {
- GST_DEBUG_OBJECT (dec, "buffer did not decode, keeping");
- }
- walk = next;
- }
- while (dec->queued) {
- GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data);
- GstClockTime timestamp, duration;
-
- timestamp = GST_BUFFER_TIMESTAMP (buf);
- duration = GST_BUFFER_DURATION (buf);
-
- vorbis_do_timestamps (dec, buf, TRUE, timestamp, duration);
- res = vorbis_dec_push_forward (dec, buf);
-
- dec->queued = g_list_delete_link (dec->queued, dec->queued);
- }
- return res;
-}
-
-static GstFlowReturn
-vorbis_dec_chain_reverse (GstVorbisDec * vd, gboolean discont, GstBuffer * buf)
-{
- GstFlowReturn result = GST_FLOW_OK;
-
- /* if we have a discont, move buffers to the decode list */
- if (G_UNLIKELY (discont)) {
- GST_DEBUG_OBJECT (vd, "received discont");
- while (vd->gather) {
- GstBuffer *gbuf;
-
- gbuf = GST_BUFFER_CAST (vd->gather->data);
- /* remove from the gather list */
- vd->gather = g_list_delete_link (vd->gather, vd->gather);
- /* copy to decode queue */
- vd->decode = g_list_prepend (vd->decode, gbuf);
- }
- /* flush and decode the decode queue */
- result = vorbis_dec_flush_decode (vd);
- }
-
- GST_DEBUG_OBJECT (vd, "gathering buffer %p of size %u, time %" GST_TIME_FORMAT
- ", dur %" GST_TIME_FORMAT, buf, GST_BUFFER_SIZE (buf),
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
- GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
-
- /* add buffer to gather queue */
- vd->gather = g_list_prepend (vd->gather, buf);
-
- return result;
-}
-
-static GstFlowReturn
-vorbis_dec_chain_forward (GstVorbisDec * vd, gboolean discont,
- GstBuffer * buffer)
-{
- GstFlowReturn result;
-
- result = vorbis_dec_decode_buffer (vd, buffer);
-
- gst_buffer_unref (buffer);
-
- return result;
-}
-
-static GstFlowReturn
-vorbis_dec_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstVorbisDec *vd;
- GstFlowReturn result = GST_FLOW_OK;
- gboolean discont;
-
- vd = GST_VORBIS_DEC (gst_pad_get_parent (pad));
-
- discont = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT);
-
- /* resync on DISCONT */
- if (G_UNLIKELY (discont)) {
- GST_DEBUG_OBJECT (vd, "received DISCONT buffer");
- vd->last_timestamp = GST_CLOCK_TIME_NONE;
-#ifdef HAVE_VORBIS_SYNTHESIS_RESTART
- vorbis_synthesis_restart (&vd->vd);
-#endif
- vd->discont = TRUE;
- }
-
- if (vd->segment.rate >= 0.0)
- result = vorbis_dec_chain_forward (vd, discont, buffer);
- else
- result = vorbis_dec_chain_reverse (vd, discont, buffer);
-
- gst_object_unref (vd);
-
- return result;
-}
-
-static GstStateChangeReturn
-vorbis_dec_change_state (GstElement * element, GstStateChange transition)
-{
- GstVorbisDec *vd = GST_VORBIS_DEC (element);
- GstStateChangeReturn res;
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- vorbis_info_init (&vd->vi);
- vorbis_comment_init (&vd->vc);
- vd->initialized = FALSE;
- gst_vorbis_dec_reset (vd);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- res = parent_class->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_DEBUG_OBJECT (vd, "PAUSED -> READY, clearing vorbis structures");
- vd->initialized = FALSE;
- vorbis_block_clear (&vd->vb);
- vorbis_dsp_clear (&vd->vd);
- vorbis_comment_clear (&vd->vc);
- vorbis_info_clear (&vd->vi);
- gst_vorbis_dec_reset (vd);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
-
- return res;
-}
diff --git a/ext/vorbis/gstvorbisdec.h b/ext/vorbis/gstvorbisdec.h
deleted file mode 100644
index 1c3ddad3..00000000
--- a/ext/vorbis/gstvorbisdec.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*- c-basic-offset: 2 -*-
- * GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * 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_VORBIS_DEC_H__
-#define __GST_VORBIS_DEC_H__
-
-
-#include <gst/gst.h>
-#include "gstvorbisdeclib.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_VORBIS_DEC \
- (gst_vorbis_dec_get_type())
-#define GST_VORBIS_DEC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBIS_DEC,GstVorbisDec))
-#define GST_VORBIS_DEC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBIS_DEC,GstVorbisDecClass))
-#define GST_IS_VORBIS_DEC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBIS_DEC))
-#define GST_IS_VORBIS_DEC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBIS_DEC))
-
-typedef struct _GstVorbisDec GstVorbisDec;
-typedef struct _GstVorbisDecClass GstVorbisDecClass;
-
-/**
- * GstVorbisDec:
- *
- * Opaque data structure.
- */
-struct _GstVorbisDec {
- GstElement element;
-
- GstPad *sinkpad;
- GstPad *srcpad;
-
- vorbis_dsp_state vd;
- vorbis_info vi;
- vorbis_comment vc;
- vorbis_block vb;
-
- gboolean initialized;
- guint width;
-
- /* list of buffers that need timestamps */
- GList *queued;
- /* list of raw output buffers */
- GList *output;
- /* gather/decode queues for reverse playback */
- GList *gather;
- GList *decode;
-
- GstSegment segment;
- gboolean discont;
- guint32 seqnum;
-
- GstClockTime last_timestamp;
-
- GList *pendingevents;
- GstTagList *taglist;
-};
-
-struct _GstVorbisDecClass {
- GstElementClass parent_class;
-};
-
-GType gst_vorbis_dec_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_VORBIS_DEC_H__ */
diff --git a/ext/vorbis/gstvorbisdeclib.c b/ext/vorbis/gstvorbisdeclib.c
deleted file mode 100644
index 9f3331c3..00000000
--- a/ext/vorbis/gstvorbisdeclib.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* GStreamer
- * Copyright (C) 2010 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
- * Copyright (C) 2010 Nokia Corporation. All rights reserved.
- * Contact: Stefan Kost <stefan.kost@nokia.com>
- *
- * Tremor modifications <2006>:
- * Chris Lord, OpenedHand Ltd. <chris@openedhand.com>, http://www.o-hand.com/
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstvorbisdeclib.h"
-
-#ifndef TREMOR
-/* These samples can be outside of the float -1.0 -- 1.0 range, this
- * is allowed, downstream elements are supposed to clip */
-void
-copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
- gint channels, gint width)
-{
- gint i, j;
-
- g_assert (width == 4);
-
-#ifdef GST_VORBIS_DEC_SEQUENTIAL
- for (i = 0; i < channels; i++) {
- memcpy (out, in[i], samples * sizeof (float));
- out += samples;
- }
-#else
- for (j = 0; j < samples; j++) {
- for (i = 0; i < channels; i++) {
- *out++ = in[i][j];
- }
- }
-#endif
-}
-
-#else
-
-/* Taken from Tremor, misc.h */
-#ifdef _ARM_ASSEM_
-static inline ogg_int32_t
-CLIP_TO_15 (ogg_int32_t x)
-{
- int tmp;
- asm volatile ("subs %1, %0, #32768\n\t"
- "movpl %0, #0x7f00\n\t"
- "orrpl %0, %0, #0xff\n"
- "adds %1, %0, #32768\n\t"
- "movmi %0, #0x8000":"+r" (x), "=r" (tmp)
- ::"cc");
-
- return (x);
-}
-#else
-static inline ogg_int32_t
-CLIP_TO_15 (ogg_int32_t x)
-{
- int ret = x;
-
- ret -= ((x <= 32767) - 1) & (x - 32767);
- ret -= ((x >= -32768) - 1) & (x + 32768);
- return (ret);
-}
-#endif
-
-static void
-copy_samples_32 (gint32 * out, ogg_int32_t ** in, guint samples, gint channels)
-{
- gint i, j;
-
- for (j = 0; j < samples; j++) {
- for (i = 0; i < channels; i++) {
- *out++ = CLIP_TO_15 (in[i][j] >> 9);
- }
- }
-}
-
-static void
-copy_samples_16 (gint16 * out, ogg_int32_t ** in, guint samples, gint channels)
-{
- gint i, j;
-
- for (j = 0; j < samples; j++) {
- for (i = 0; i < channels; i++) {
- *out++ = CLIP_TO_15 (in[i][j] >> 9);
- }
- }
-}
-
-void
-copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
- gint channels, gint width)
-{
- if (width == 4) {
- copy_samples_32 ((gint32 *) out, in, samples, channels);
- } else if (width == 2) {
- copy_samples_16 ((gint16 *) out, in, samples, channels);
- } else {
- g_assert_not_reached ();
- }
-}
-
-#endif
diff --git a/ext/vorbis/gstvorbisdeclib.h b/ext/vorbis/gstvorbisdeclib.h
deleted file mode 100644
index a438fa85..00000000
--- a/ext/vorbis/gstvorbisdeclib.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/* GStreamer
- * Copyright (C) 2010 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
- * Copyright (C) 2010 Nokia Corporation. All rights reserved.
- * Contact: Stefan Kost <stefan.kost@nokia.com>
- *
- * Tremor modifications <2006>:
- * Chris Lord, OpenedHand Ltd. <chris@openedhand.com>, http://www.o-hand.com/
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_VORBIS_DEC_LIB_H__
-#define __GST_VORBIS_DEC_LIB_H__
-
-#include <gst/gst.h>
-
-#ifndef TREMOR
-
-#include <vorbis/codec.h>
-
-typedef float vorbis_sample_t;
-typedef ogg_packet ogg_packet_wrapper;
-
-#define GST_VORBIS_DEC_ELEMENT_DETAILS \
-GST_ELEMENT_DETAILS ("Vorbis audio decoder", \
- "Codec/Decoder/Audio", \
- "decode raw vorbis streams to float audio", \
- "Benjamin Otte <in7y118@public.uni-hamburg.de>")
-
-#define GST_VORBIS_DEC_SRC_CAPS \
- GST_STATIC_CAPS ("audio/x-raw-float, " "rate = (int) [ 1, MAX ], " \
- "channels = (int) [ 1, 256 ], " "endianness = (int) BYTE_ORDER, " \
- "width = (int) 32")
-
-#define GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH (32)
-
-#define GST_VORBIS_DEC_GLIB_TYPE_NAME GstVorbisDec
-
-static inline guint8 *
-gst_ogg_packet_data (ogg_packet * p)
-{
- return (guint8 *) p->packet;
-}
-
-static inline gint
-gst_ogg_packet_size (ogg_packet * p)
-{
- return p->bytes;
-}
-
-static inline void
-gst_ogg_packet_wrapper_from_buffer (ogg_packet * packet, GstBuffer * buffer)
-{
- packet->packet = GST_BUFFER_DATA (buffer);
- packet->bytes = GST_BUFFER_SIZE (buffer);
-}
-
-static inline ogg_packet *
-gst_ogg_packet_from_wrapper (ogg_packet_wrapper * packet)
-{
- return packet;
-}
-
-#else
-
-#include <tremor/ivorbiscodec.h>
-
-typedef ogg_int32_t vorbis_sample_t;
-typedef struct _ogg_packet_wrapper ogg_packet_wrapper;
-
-struct _ogg_packet_wrapper {
- ogg_packet packet;
- ogg_reference ref;
- ogg_buffer buf;
-};
-
-#define GST_VORBIS_DEC_ELEMENT_DETAILS \
-GST_ELEMENT_DETAILS ("Vorbis audio decoder", \
- "Codec/Decoder/Audio", \
- "decode raw vorbis streams to integer audio", \
- "Benjamin Otte <in7y118@public.uni-hamburg.de>\n" \
- "Chris Lord <chris@openedhand.com>")
-
-#define GST_VORBIS_DEC_SRC_CAPS \
- GST_STATIC_CAPS ("audio/x-raw-int, " \
- "rate = (int) [ 1, MAX ], " \
- "channels = (int) [ 1, 6 ], " \
- "endianness = (int) BYTE_ORDER, " \
- "width = (int) { 16, 32 }, " \
- "depth = (int) 16, " "signed = (boolean) true")
-
-#define GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH (16)
-
-/* we need a different type name here */
-#define GST_VORBIS_DEC_GLIB_TYPE_NAME GstIVorbisDec
-
-/* and still have it compile */
-typedef struct _GstVorbisDec GstIVorbisDec;
-typedef struct _GstVorbisDecClass GstIVorbisDecClass;
-
-/* compensate minor variation */
-#define vorbis_synthesis(a, b) vorbis_synthesis (a, b, 1)
-
-static inline guint8 *
-gst_ogg_packet_data (ogg_packet * p)
-{
- return (guint8 *) p->packet->buffer->data;
-}
-
-static inline gint
-gst_ogg_packet_size (ogg_packet * p)
-{
- return p->packet->buffer->size;
-}
-
-static inline void
-gst_ogg_packet_wrapper_from_buffer (ogg_packet_wrapper * packet,
- GstBuffer * buffer)
-{
- ogg_reference *ref = &packet->ref;
- ogg_buffer *buf = &packet->buf;
-
- buf->data = GST_BUFFER_DATA (buffer);
- buf->size = GST_BUFFER_SIZE (buffer);
- buf->refcount = 1;
- buf->ptr.owner = NULL;
- buf->ptr.next = NULL;
-
- ref->buffer = buf;
- ref->begin = 0;
- ref->length = buf->size;
- ref->next = NULL;
-
- packet->packet.packet = ref;
- packet->packet.bytes = ref->length;
-}
-
-static inline ogg_packet *
-gst_ogg_packet_from_wrapper (ogg_packet_wrapper * packet)
-{
- return &(packet->packet);
-}
-
-#endif
-
-void copy_samples (vorbis_sample_t *out, vorbis_sample_t **in,
- guint samples, gint channels, gint width);
-
-
-#endif /* __GST_VORBIS_DEC_LIB_H__ */
diff --git a/ext/vorbis/gstvorbisenc.c b/ext/vorbis/gstvorbisenc.c
deleted file mode 100644
index b09723b2..00000000
--- a/ext/vorbis/gstvorbisenc.c
+++ /dev/null
@@ -1,1432 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-vorbisenc
- * @see_also: vorbisdec, oggmux
- *
- * This element encodes raw float audio into a Vorbis stream.
- * <ulink url="http://www.vorbis.com/">Vorbis</ulink> is a royalty-free
- * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
- * Foundation</ulink>.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! vorbisenc ! oggmux ! filesink location=sine.ogg
- * ]| Encode a test sine signal to Ogg/Vorbis. Note that the resulting file
- * will be really small because a sine signal compresses very well.
- * |[
- * gst-launch -v alsasrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
- * ]| Record from a sound card using ALSA and encode to Ogg/Vorbis.
- * </refsect2>
- *
- * Last reviewed on 2006-03-01 (0.10.4)
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <vorbis/vorbisenc.h>
-
-#include <gst/gsttagsetter.h>
-#include <gst/tag/tag.h>
-#include <gst/audio/multichannel.h>
-#include <gst/audio/audio.h>
-#include "gstvorbisenc.h"
-
-#include "gstvorbiscommon.h"
-
-GST_DEBUG_CATEGORY_EXTERN (vorbisenc_debug);
-#define GST_CAT_DEFAULT vorbisenc_debug
-
-static GstStaticPadTemplate vorbis_enc_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-raw-float, "
- "rate = (int) [ 1, 200000 ], "
- "channels = (int) [ 1, 256 ], " "endianness = (int) BYTE_ORDER, "
- "width = (int) 32")
- );
-
-static GstStaticPadTemplate vorbis_enc_src_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-vorbis")
- );
-
-
-/* elementfactory information */
-static const GstElementDetails vorbisenc_details =
-GST_ELEMENT_DETAILS ("Vorbis audio encoder",
- "Codec/Encoder/Audio",
- "Encodes audio in Vorbis format",
- "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>");
-
-enum
-{
- ARG_0,
- ARG_MAX_BITRATE,
- ARG_BITRATE,
- ARG_MIN_BITRATE,
- ARG_QUALITY,
- ARG_MANAGED,
- ARG_LAST_MESSAGE
-};
-
-static GstFlowReturn gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc);
-
-/* this function takes into account the granulepos_offset and the subgranule
- * time offset */
-static GstClockTime
-granulepos_to_timestamp_offset (GstVorbisEnc * vorbisenc,
- ogg_int64_t granulepos)
-{
- if (granulepos >= 0)
- return gst_util_uint64_scale ((guint64) granulepos
- + vorbisenc->granulepos_offset, GST_SECOND, vorbisenc->frequency)
- + vorbisenc->subgranule_offset;
- return GST_CLOCK_TIME_NONE;
-}
-
-/* this function does a straight granulepos -> timestamp conversion */
-static GstClockTime
-granulepos_to_timestamp (GstVorbisEnc * vorbisenc, ogg_int64_t granulepos)
-{
- if (granulepos >= 0)
- return gst_util_uint64_scale ((guint64) granulepos,
- GST_SECOND, vorbisenc->frequency);
- return GST_CLOCK_TIME_NONE;
-}
-
-#define MAX_BITRATE_DEFAULT -1
-#define BITRATE_DEFAULT -1
-#define MIN_BITRATE_DEFAULT -1
-#define QUALITY_DEFAULT 0.3
-#define LOWEST_BITRATE 6000 /* lowest allowed for a 8 kHz stream */
-#define HIGHEST_BITRATE 250001 /* highest allowed for a 44 kHz stream */
-
-static gboolean gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer);
-static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc);
-
-static void gst_vorbis_enc_dispose (GObject * object);
-static void gst_vorbis_enc_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void gst_vorbis_enc_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static GstStateChangeReturn gst_vorbis_enc_change_state (GstElement * element,
- GstStateChange transition);
-static void gst_vorbis_enc_add_interfaces (GType vorbisenc_type);
-
-GST_BOILERPLATE_FULL (GstVorbisEnc, gst_vorbis_enc, GstElement,
- GST_TYPE_ELEMENT, gst_vorbis_enc_add_interfaces);
-
-static void
-gst_vorbis_enc_add_interfaces (GType vorbisenc_type)
-{
- static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
- static const GInterfaceInfo preset_info = { NULL, NULL, NULL };
-
- g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER,
- &tag_setter_info);
- g_type_add_interface_static (vorbisenc_type, GST_TYPE_PRESET, &preset_info);
-}
-
-static void
-gst_vorbis_enc_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- GstPadTemplate *src_template, *sink_template;
-
-
- src_template = gst_static_pad_template_get (&vorbis_enc_src_factory);
- gst_element_class_add_pad_template (element_class, src_template);
-
- sink_template = gst_static_pad_template_get (&vorbis_enc_sink_factory);
- gst_element_class_add_pad_template (element_class, sink_template);
- gst_element_class_set_details (element_class, &vorbisenc_details);
-}
-
-static void
-gst_vorbis_enc_class_init (GstVorbisEncClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- gobject_class->set_property = gst_vorbis_enc_set_property;
- gobject_class->get_property = gst_vorbis_enc_get_property;
- gobject_class->dispose = gst_vorbis_enc_dispose;
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE,
- g_param_spec_int ("max-bitrate", "Maximum Bitrate",
- "Specify a maximum bitrate (in bps). Useful for streaming "
- "applications. (-1 == disabled)",
- -1, HIGHEST_BITRATE, MAX_BITRATE_DEFAULT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
- g_param_spec_int ("bitrate", "Target Bitrate",
- "Attempt to encode at a bitrate averaging this (in bps). "
- "This uses the bitrate management engine, and is not recommended for most users. "
- "Quality is a better alternative. (-1 == disabled)", -1,
- HIGHEST_BITRATE, BITRATE_DEFAULT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_BITRATE,
- g_param_spec_int ("min-bitrate", "Minimum Bitrate",
- "Specify a minimum bitrate (in bps). Useful for encoding for a "
- "fixed-size channel. (-1 == disabled)", -1, HIGHEST_BITRATE,
- MIN_BITRATE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
- g_param_spec_float ("quality", "Quality",
- "Specify quality instead of specifying a particular bitrate.", -0.1,
- 1.0, QUALITY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED,
- g_param_spec_boolean ("managed", "Managed",
- "Enable bitrate management engine", FALSE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
- g_param_spec_string ("last-message", "last-message",
- "The last status message", NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_vorbis_enc_change_state);
-}
-
-static void
-gst_vorbis_enc_dispose (GObject * object)
-{
- GstVorbisEnc *vorbisenc = GST_VORBISENC (object);
-
- if (vorbisenc->sinkcaps) {
- gst_caps_unref (vorbisenc->sinkcaps);
- vorbisenc->sinkcaps = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static GstCaps *
-gst_vorbis_enc_generate_sink_caps (void)
-{
- GstCaps *caps = gst_caps_new_empty ();
- int i, c;
-
- gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float",
- "rate", GST_TYPE_INT_RANGE, 1, 200000,
- "channels", G_TYPE_INT, 1,
- "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32,
- NULL));
-
- gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float",
- "rate", GST_TYPE_INT_RANGE, 1, 200000,
- "channels", G_TYPE_INT, 2,
- "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32,
- NULL));
-
- for (i = 3; i <= 8; i++) {
- GValue chanpos = { 0 };
- GValue pos = { 0 };
- GstStructure *structure;
-
- g_value_init (&chanpos, GST_TYPE_ARRAY);
- g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
-
- for (c = 0; c < i; c++) {
- g_value_set_enum (&pos, gst_vorbis_channel_positions[i - 1][c]);
- gst_value_array_append_value (&chanpos, &pos);
- }
- g_value_unset (&pos);
-
- structure = gst_structure_new ("audio/x-raw-float",
- "rate", GST_TYPE_INT_RANGE, 1, 200000,
- "channels", G_TYPE_INT, i,
- "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL);
- gst_structure_set_value (structure, "channel-positions", &chanpos);
- g_value_unset (&chanpos);
-
- gst_caps_append_structure (caps, structure);
- }
-
- gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float",
- "rate", GST_TYPE_INT_RANGE, 1, 200000,
- "channels", GST_TYPE_INT_RANGE, 9, 256,
- "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32,
- NULL));
-
- return caps;
-}
-
-static GstCaps *
-gst_vorbis_enc_sink_getcaps (GstPad * pad)
-{
- GstVorbisEnc *vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
-
- if (vorbisenc->sinkcaps == NULL)
- vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps ();
-
- return gst_caps_ref (vorbisenc->sinkcaps);
-}
-
-static gboolean
-gst_vorbis_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstVorbisEnc *vorbisenc;
- GstStructure *structure;
-
- vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
- vorbisenc->setup = FALSE;
-
- structure = gst_caps_get_structure (caps, 0);
- gst_structure_get_int (structure, "channels", &vorbisenc->channels);
- gst_structure_get_int (structure, "rate", &vorbisenc->frequency);
-
- gst_vorbis_enc_setup (vorbisenc);
-
- if (vorbisenc->setup)
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean
-gst_vorbis_enc_convert_src (GstPad * pad, GstFormat src_format,
- gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = TRUE;
- GstVorbisEnc *vorbisenc;
- gint64 avg;
-
- vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
-
- if (vorbisenc->samples_in == 0 ||
- vorbisenc->bytes_out == 0 || vorbisenc->frequency == 0) {
- gst_object_unref (vorbisenc);
- return FALSE;
- }
-
- avg = (vorbisenc->bytes_out * vorbisenc->frequency) / (vorbisenc->samples_in);
-
- switch (src_format) {
- case GST_FORMAT_BYTES:
- switch (*dest_format) {
- case GST_FORMAT_TIME:
- *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, avg);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- *dest_value = gst_util_uint64_scale_int (src_value, avg, GST_SECOND);
- break;
- default:
- res = FALSE;
- }
- break;
- default:
- res = FALSE;
- }
- gst_object_unref (vorbisenc);
- return res;
-}
-
-static gboolean
-gst_vorbis_enc_convert_sink (GstPad * pad, GstFormat src_format,
- gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = TRUE;
- guint scale = 1;
- gint bytes_per_sample;
- GstVorbisEnc *vorbisenc;
-
- vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
-
- bytes_per_sample = vorbisenc->channels * 2;
-
- switch (src_format) {
- case GST_FORMAT_BYTES:
- switch (*dest_format) {
- case GST_FORMAT_DEFAULT:
- if (bytes_per_sample == 0)
- return FALSE;
- *dest_value = src_value / bytes_per_sample;
- break;
- case GST_FORMAT_TIME:
- {
- gint byterate = bytes_per_sample * vorbisenc->frequency;
-
- if (byterate == 0)
- return FALSE;
- *dest_value =
- gst_util_uint64_scale_int (src_value, GST_SECOND, byterate);
- break;
- }
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_DEFAULT:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- *dest_value = src_value * bytes_per_sample;
- break;
- case GST_FORMAT_TIME:
- if (vorbisenc->frequency == 0)
- return FALSE;
- *dest_value =
- gst_util_uint64_scale_int (src_value, GST_SECOND,
- vorbisenc->frequency);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- scale = bytes_per_sample;
- /* fallthrough */
- case GST_FORMAT_DEFAULT:
- *dest_value =
- gst_util_uint64_scale_int (src_value,
- scale * vorbisenc->frequency, GST_SECOND);
- break;
- default:
- res = FALSE;
- }
- break;
- default:
- res = FALSE;
- }
- gst_object_unref (vorbisenc);
- return res;
-}
-
-static gint64
-gst_vorbis_enc_get_latency (GstVorbisEnc * vorbisenc)
-{
- /* FIXME, this probably depends on the bitrate and other setting but for now
- * we return this value, which was obtained by totally unscientific
- * measurements */
- return 58 * GST_MSECOND;
-}
-
-static const GstQueryType *
-gst_vorbis_enc_get_query_types (GstPad * pad)
-{
- static const GstQueryType gst_vorbis_enc_src_query_types[] = {
- GST_QUERY_POSITION,
- GST_QUERY_DURATION,
- GST_QUERY_CONVERT,
- 0
- };
-
- return gst_vorbis_enc_src_query_types;
-}
-
-static gboolean
-gst_vorbis_enc_src_query (GstPad * pad, GstQuery * query)
-{
- gboolean res = TRUE;
- GstVorbisEnc *vorbisenc;
- GstPad *peerpad;
-
- vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
- peerpad = gst_pad_get_peer (GST_PAD (vorbisenc->sinkpad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- {
- GstFormat fmt, req_fmt;
- gint64 pos, val;
-
- gst_query_parse_position (query, &req_fmt, NULL);
- if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
- gst_query_set_position (query, req_fmt, val);
- break;
- }
-
- fmt = GST_FORMAT_TIME;
- if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
- break;
-
- if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val))) {
- gst_query_set_position (query, req_fmt, val);
- }
- break;
- }
- case GST_QUERY_DURATION:
- {
- GstFormat fmt, req_fmt;
- gint64 dur, val;
-
- gst_query_parse_duration (query, &req_fmt, NULL);
- if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
- gst_query_set_duration (query, req_fmt, val);
- break;
- }
-
- fmt = GST_FORMAT_TIME;
- if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
- break;
-
- if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
- gst_query_set_duration (query, req_fmt, val);
- }
- break;
- }
- case GST_QUERY_CONVERT:
- {
- GstFormat src_fmt, dest_fmt;
- gint64 src_val, dest_val;
-
- gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
- if (!(res =
- gst_vorbis_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
- &dest_val)))
- goto error;
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- break;
- }
- case GST_QUERY_LATENCY:
- {
- gboolean live;
- GstClockTime min_latency, max_latency;
- gint64 latency;
-
- if ((res = gst_pad_query (peerpad, query))) {
- gst_query_parse_latency (query, &live, &min_latency, &max_latency);
-
- latency = gst_vorbis_enc_get_latency (vorbisenc);
-
- /* add our latency */
- min_latency += latency;
- if (max_latency != -1)
- max_latency += latency;
-
- gst_query_set_latency (query, live, min_latency, max_latency);
- }
- break;
- }
- default:
- res = gst_pad_query (peerpad, query);
- break;
- }
-
-error:
- gst_object_unref (peerpad);
- gst_object_unref (vorbisenc);
- return res;
-}
-
-static gboolean
-gst_vorbis_enc_sink_query (GstPad * pad, GstQuery * query)
-{
- gboolean res = TRUE;
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_CONVERT:
- {
- GstFormat src_fmt, dest_fmt;
- gint64 src_val, dest_val;
-
- gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
- if (!(res =
- gst_vorbis_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
- &dest_val)))
- goto error;
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-
-error:
- return res;
-}
-
-static void
-gst_vorbis_enc_init (GstVorbisEnc * vorbisenc, GstVorbisEncClass * klass)
-{
- vorbisenc->sinkpad =
- gst_pad_new_from_static_template (&vorbis_enc_sink_factory, "sink");
- gst_pad_set_event_function (vorbisenc->sinkpad,
- GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_event));
- gst_pad_set_chain_function (vorbisenc->sinkpad,
- GST_DEBUG_FUNCPTR (gst_vorbis_enc_chain));
- gst_pad_set_setcaps_function (vorbisenc->sinkpad,
- GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_setcaps));
- gst_pad_set_getcaps_function (vorbisenc->sinkpad,
- GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_getcaps));
- gst_pad_set_query_function (vorbisenc->sinkpad,
- GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_query));
- gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad);
-
- vorbisenc->srcpad =
- gst_pad_new_from_static_template (&vorbis_enc_src_factory, "src");
- gst_pad_set_query_function (vorbisenc->srcpad,
- GST_DEBUG_FUNCPTR (gst_vorbis_enc_src_query));
- gst_pad_set_query_type_function (vorbisenc->srcpad,
- GST_DEBUG_FUNCPTR (gst_vorbis_enc_get_query_types));
- gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->srcpad);
-
- vorbisenc->channels = -1;
- vorbisenc->frequency = -1;
-
- vorbisenc->managed = FALSE;
- vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT;
- vorbisenc->bitrate = BITRATE_DEFAULT;
- vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT;
- vorbisenc->quality = QUALITY_DEFAULT;
- vorbisenc->quality_set = FALSE;
- vorbisenc->last_message = NULL;
-}
-
-static void
-gst_vorbis_enc_metadata_set1 (const GstTagList * list, const gchar * tag,
- gpointer vorbisenc)
-{
- GstVorbisEnc *enc = GST_VORBISENC (vorbisenc);
- GList *vc_list, *l;
-
- vc_list = gst_tag_to_vorbis_comments (list, tag);
-
- for (l = vc_list; l != NULL; l = l->next) {
- const gchar *vc_string = (const gchar *) l->data;
- gchar *key = NULL, *val = NULL;
-
- GST_LOG_OBJECT (vorbisenc, "vorbis comment: %s", vc_string);
- if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) {
- vorbis_comment_add_tag (&enc->vc, key, val);
- g_free (key);
- g_free (val);
- }
- }
-
- g_list_foreach (vc_list, (GFunc) g_free, NULL);
- g_list_free (vc_list);
-}
-
-static void
-gst_vorbis_enc_set_metadata (GstVorbisEnc * enc)
-{
- GstTagList *merged_tags;
- const GstTagList *user_tags;
-
- vorbis_comment_init (&enc->vc);
-
- user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
-
- GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
- GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
-
- /* gst_tag_list_merge() will handle NULL for either or both lists fine */
- merged_tags = gst_tag_list_merge (user_tags, enc->tags,
- gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
-
- if (merged_tags) {
- GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
- gst_tag_list_foreach (merged_tags, gst_vorbis_enc_metadata_set1, enc);
- gst_tag_list_free (merged_tags);
- }
-}
-
-static gchar *
-get_constraints_string (GstVorbisEnc * vorbisenc)
-{
- gint min = vorbisenc->min_bitrate;
- gint max = vorbisenc->max_bitrate;
- gchar *result;
-
- if (min > 0 && max > 0)
- result = g_strdup_printf ("(min %d bps, max %d bps)", min, max);
- else if (min > 0)
- result = g_strdup_printf ("(min %d bps, no max)", min);
- else if (max > 0)
- result = g_strdup_printf ("(no min, max %d bps)", max);
- else
- result = g_strdup_printf ("(no min or max)");
-
- return result;
-}
-
-static void
-update_start_message (GstVorbisEnc * vorbisenc)
-{
- gchar *constraints;
-
- g_free (vorbisenc->last_message);
-
- if (vorbisenc->bitrate > 0) {
- if (vorbisenc->managed) {
- constraints = get_constraints_string (vorbisenc);
- vorbisenc->last_message =
- g_strdup_printf ("encoding at average bitrate %d bps %s",
- vorbisenc->bitrate, constraints);
- g_free (constraints);
- } else {
- vorbisenc->last_message =
- g_strdup_printf
- ("encoding at approximate bitrate %d bps (VBR encoding enabled)",
- vorbisenc->bitrate);
- }
- } else {
- if (vorbisenc->quality_set) {
- if (vorbisenc->managed) {
- constraints = get_constraints_string (vorbisenc);
- vorbisenc->last_message =
- g_strdup_printf
- ("encoding at quality level %2.2f using constrained VBR %s",
- vorbisenc->quality, constraints);
- g_free (constraints);
- } else {
- vorbisenc->last_message =
- g_strdup_printf ("encoding at quality level %2.2f",
- vorbisenc->quality);
- }
- } else {
- constraints = get_constraints_string (vorbisenc);
- vorbisenc->last_message =
- g_strdup_printf ("encoding using bitrate management %s", constraints);
- g_free (constraints);
- }
- }
-
- g_object_notify (G_OBJECT (vorbisenc), "last_message");
-}
-
-static gboolean
-gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc)
-{
- vorbisenc->setup = FALSE;
-
- if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0
- && vorbisenc->max_bitrate < 0) {
- vorbisenc->quality_set = TRUE;
- }
-
- update_start_message (vorbisenc);
-
- /* choose an encoding mode */
- /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
- vorbis_info_init (&vorbisenc->vi);
-
- if (vorbisenc->quality_set) {
- if (vorbis_encode_setup_vbr (&vorbisenc->vi,
- vorbisenc->channels, vorbisenc->frequency,
- vorbisenc->quality) != 0) {
- GST_ERROR_OBJECT (vorbisenc,
- "vorbisenc: initialisation failed: invalid parameters for quality");
- vorbis_info_clear (&vorbisenc->vi);
- return FALSE;
- }
-
- /* do we have optional hard quality restrictions? */
- if (vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0) {
- struct ovectl_ratemanage_arg ai;
-
- vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai);
-
- ai.bitrate_hard_min = vorbisenc->min_bitrate;
- ai.bitrate_hard_max = vorbisenc->max_bitrate;
- ai.management_active = 1;
-
- vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai);
- }
- } else {
- long min_bitrate, max_bitrate;
-
- min_bitrate = vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1;
- max_bitrate = vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1;
-
- if (vorbis_encode_setup_managed (&vorbisenc->vi,
- vorbisenc->channels,
- vorbisenc->frequency,
- max_bitrate, vorbisenc->bitrate, min_bitrate) != 0) {
- GST_ERROR_OBJECT (vorbisenc,
- "vorbis_encode_setup_managed "
- "(c %d, rate %d, max br %ld, br %d, min br %ld) failed",
- vorbisenc->channels, vorbisenc->frequency, max_bitrate,
- vorbisenc->bitrate, min_bitrate);
- vorbis_info_clear (&vorbisenc->vi);
- return FALSE;
- }
- }
-
- if (vorbisenc->managed && vorbisenc->bitrate < 0) {
- vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL);
- } else if (!vorbisenc->managed) {
- /* Turn off management entirely (if it was turned on). */
- vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL);
- }
- vorbis_encode_setup_init (&vorbisenc->vi);
-
- /* set up the analysis state and auxiliary encoding storage */
- vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
- vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
-
- vorbisenc->next_ts = 0;
-
- vorbisenc->setup = TRUE;
-
- return TRUE;
-}
-
-static GstFlowReturn
-gst_vorbis_enc_clear (GstVorbisEnc * vorbisenc)
-{
- GstFlowReturn ret = GST_FLOW_OK;
-
- if (vorbisenc->setup) {
- vorbis_analysis_wrote (&vorbisenc->vd, 0);
- ret = gst_vorbis_enc_output_buffers (vorbisenc);
-
- vorbisenc->setup = FALSE;
- }
-
- /* clean up and exit. vorbis_info_clear() must be called last */
- vorbis_block_clear (&vorbisenc->vb);
- vorbis_dsp_clear (&vorbisenc->vd);
- vorbis_info_clear (&vorbisenc->vi);
-
- vorbisenc->header_sent = FALSE;
-
- return ret;
-}
-
-/* prepare a buffer for transmission by passing data through libvorbis */
-static GstBuffer *
-gst_vorbis_enc_buffer_from_packet (GstVorbisEnc * vorbisenc,
- ogg_packet * packet)
-{
- GstBuffer *outbuf;
-
- outbuf = gst_buffer_new_and_alloc (packet->bytes);
- memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
- /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
- * time representation */
- GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos +
- vorbisenc->granulepos_offset;
- GST_BUFFER_OFFSET (outbuf) = granulepos_to_timestamp (vorbisenc,
- GST_BUFFER_OFFSET_END (outbuf));
- GST_BUFFER_TIMESTAMP (outbuf) = vorbisenc->next_ts;
-
- /* update the next timestamp, taking granulepos_offset and subgranule offset
- * into account */
- vorbisenc->next_ts =
- granulepos_to_timestamp_offset (vorbisenc, packet->granulepos) +
- vorbisenc->initial_ts;
- GST_BUFFER_DURATION (outbuf) =
- vorbisenc->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
-
- if (vorbisenc->next_discont) {
- GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
- vorbisenc->next_discont = FALSE;
- }
-
- gst_buffer_set_caps (outbuf, vorbisenc->srccaps);
-
- GST_LOG_OBJECT (vorbisenc, "encoded buffer of %d bytes",
- GST_BUFFER_SIZE (outbuf));
- return outbuf;
-}
-
-/* the same as above, but different logic for setting timestamp and granulepos
- * */
-static GstBuffer *
-gst_vorbis_enc_buffer_from_header_packet (GstVorbisEnc * vorbisenc,
- ogg_packet * packet)
-{
- GstBuffer *outbuf;
-
- outbuf = gst_buffer_new_and_alloc (packet->bytes);
- memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
- GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
- GST_BUFFER_OFFSET_END (outbuf) = 0;
- GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
- GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
-
- gst_buffer_set_caps (outbuf, vorbisenc->srccaps);
-
- GST_DEBUG ("created header packet buffer, %d bytes",
- GST_BUFFER_SIZE (outbuf));
- return outbuf;
-}
-
-/* push out the buffer and do internal bookkeeping */
-static GstFlowReturn
-gst_vorbis_enc_push_buffer (GstVorbisEnc * vorbisenc, GstBuffer * buffer)
-{
- vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer);
-
- GST_DEBUG_OBJECT (vorbisenc,
- "Pushing buffer with GP %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT,
- GST_BUFFER_OFFSET_END (buffer),
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
- return gst_pad_push (vorbisenc->srcpad, buffer);
-}
-
-static GstFlowReturn
-gst_vorbis_enc_push_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet)
-{
- GstBuffer *outbuf;
-
- outbuf = gst_vorbis_enc_buffer_from_packet (vorbisenc, packet);
- return gst_vorbis_enc_push_buffer (vorbisenc, outbuf);
-}
-
-/* Set a copy of these buffers as 'streamheader' on the caps.
- * We need a copy to avoid these buffers ending up with (indirect) refs on
- * themselves
- */
-static GstCaps *
-gst_vorbis_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
- GstBuffer * buf2, GstBuffer * buf3)
-{
- GstBuffer *buf;
- GstStructure *structure;
- GValue array = { 0 };
- GValue value = { 0 };
-
- caps = gst_caps_make_writable (caps);
- structure = gst_caps_get_structure (caps, 0);
-
- /* mark buffers */
- GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
- GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
- GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS);
-
- /* put buffers in a fixed list */
- g_value_init (&array, GST_TYPE_ARRAY);
- g_value_init (&value, GST_TYPE_BUFFER);
- buf = gst_buffer_copy (buf1);
- gst_value_set_buffer (&value, buf);
- gst_buffer_unref (buf);
- gst_value_array_append_value (&array, &value);
- g_value_unset (&value);
- g_value_init (&value, GST_TYPE_BUFFER);
- buf = gst_buffer_copy (buf2);
- gst_value_set_buffer (&value, buf);
- gst_buffer_unref (buf);
- gst_value_array_append_value (&array, &value);
- g_value_unset (&value);
- g_value_init (&value, GST_TYPE_BUFFER);
- buf = gst_buffer_copy (buf3);
- gst_value_set_buffer (&value, buf);
- gst_buffer_unref (buf);
- gst_value_array_append_value (&array, &value);
- gst_structure_set_value (structure, "streamheader", &array);
- g_value_unset (&value);
- g_value_unset (&array);
-
- return caps;
-}
-
-static gboolean
-gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event)
-{
- gboolean res = TRUE;
- GstVorbisEnc *vorbisenc;
-
- vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- /* Tell the library we're at end of stream so that it can handle
- * the last frame and mark end of stream in the output properly */
- GST_DEBUG_OBJECT (vorbisenc, "EOS, clearing state and sending event on");
- gst_vorbis_enc_clear (vorbisenc);
-
- res = gst_pad_push_event (vorbisenc->srcpad, event);
- break;
- case GST_EVENT_TAG:
- if (vorbisenc->tags) {
- GstTagList *list;
-
- gst_event_parse_tag (event, &list);
- gst_tag_list_insert (vorbisenc->tags, list,
- gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc)));
- } else {
- g_assert_not_reached ();
- }
- res = gst_pad_push_event (vorbisenc->srcpad, event);
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, position;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
- if (format == GST_FORMAT_TIME) {
- gst_segment_set_newsegment (&vorbisenc->segment, update, rate, format,
- start, stop, position);
- if (vorbisenc->initial_ts == GST_CLOCK_TIME_NONE) {
- GST_DEBUG_OBJECT (vorbisenc, "Initial segment %" GST_SEGMENT_FORMAT,
- &vorbisenc->segment);
- vorbisenc->initial_ts = start;
- }
- }
- }
- /* fall through */
- default:
- res = gst_pad_push_event (vorbisenc->srcpad, event);
- break;
- }
- return res;
-}
-
-static gboolean
-gst_vorbis_enc_buffer_check_discontinuous (GstVorbisEnc * vorbisenc,
- GstClockTime timestamp, GstClockTime duration)
-{
- gboolean ret = FALSE;
-
- if (timestamp != GST_CLOCK_TIME_NONE &&
- vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
- timestamp + duration != vorbisenc->expected_ts) {
- /* It turns out that a lot of elements don't generate perfect streams due
- * to rounding errors. So, we permit small errors (< 1/2 a sample) without
- * causing a discont.
- */
- int halfsample = GST_SECOND / vorbisenc->frequency / 2;
-
- if ((GstClockTimeDiff) (timestamp - vorbisenc->expected_ts) > halfsample) {
- GST_DEBUG_OBJECT (vorbisenc, "Expected TS %" GST_TIME_FORMAT
- ", buffer TS %" GST_TIME_FORMAT,
- GST_TIME_ARGS (vorbisenc->expected_ts), GST_TIME_ARGS (timestamp));
- ret = TRUE;
- }
- }
-
- if (timestamp != GST_CLOCK_TIME_NONE && duration != GST_CLOCK_TIME_NONE) {
- vorbisenc->expected_ts = timestamp + duration;
- } else
- vorbisenc->expected_ts = GST_CLOCK_TIME_NONE;
-
- return ret;
-}
-
-static GstFlowReturn
-gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstVorbisEnc *vorbisenc;
- GstFlowReturn ret = GST_FLOW_OK;
- gfloat *data;
- gulong size;
- gulong i, j;
- float **vorbis_buffer;
- GstBuffer *buf1, *buf2, *buf3;
- gboolean first = FALSE;
- GstClockTime timestamp = GST_CLOCK_TIME_NONE;
- GstClockTime running_time = GST_CLOCK_TIME_NONE;
-
- vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
-
- if (!vorbisenc->setup)
- goto not_setup;
-
- buffer = gst_audio_buffer_clip (buffer, &vorbisenc->segment,
- vorbisenc->frequency, 4 * vorbisenc->channels);
- if (buffer == NULL) {
- GST_DEBUG_OBJECT (vorbisenc, "Dropping buffer, out of segment");
- return GST_FLOW_OK;
- }
- running_time =
- gst_segment_to_running_time (&vorbisenc->segment, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (buffer));
- timestamp = running_time + vorbisenc->initial_ts;
- GST_DEBUG_OBJECT (vorbisenc, "Initial ts is %" GST_TIME_FORMAT,
- GST_TIME_ARGS (vorbisenc->initial_ts));
- if (!vorbisenc->header_sent) {
- /* 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;
- GstCaps *caps;
-
- /* first, make sure header buffers get timestamp == 0 */
- vorbisenc->next_ts = 0;
- vorbisenc->granulepos_offset = 0;
- vorbisenc->subgranule_offset = 0;
-
- GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
- gst_vorbis_enc_set_metadata (vorbisenc);
- vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
- &header_comm, &header_code);
- vorbis_comment_clear (&vorbisenc->vc);
-
- /* create header buffers */
- buf1 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header);
- buf2 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_comm);
- buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code);
-
- /* mark and put on caps */
- vorbisenc->srccaps = gst_caps_new_simple ("audio/x-vorbis", NULL);
- caps = vorbisenc->srccaps;
- caps = gst_vorbis_enc_set_header_on_caps (caps, buf1, buf2, buf3);
-
- /* negotiate with these caps */
- GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
- gst_pad_set_caps (vorbisenc->srcpad, caps);
-
- gst_buffer_set_caps (buf1, caps);
- gst_buffer_set_caps (buf2, caps);
- gst_buffer_set_caps (buf3, caps);
-
- /* push out buffers */
- /* push_buffer takes the reference even for failure */
- if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf1)) != GST_FLOW_OK)
- goto failed_header_push;
- if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf2)) != GST_FLOW_OK) {
- buf2 = NULL;
- goto failed_header_push;
- }
- if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf3)) != GST_FLOW_OK) {
- buf3 = NULL;
- goto failed_header_push;
- }
-
- /* now adjust starting granulepos accordingly if the buffer's timestamp is
- nonzero */
- vorbisenc->next_ts = timestamp;
- vorbisenc->expected_ts = timestamp;
- vorbisenc->granulepos_offset = gst_util_uint64_scale
- (running_time, vorbisenc->frequency, GST_SECOND);
- vorbisenc->subgranule_offset = 0;
- vorbisenc->subgranule_offset =
- (vorbisenc->next_ts - vorbisenc->initial_ts) -
- granulepos_to_timestamp_offset (vorbisenc, 0);
-
- vorbisenc->header_sent = TRUE;
- first = TRUE;
- }
-
- if (vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
- timestamp < vorbisenc->expected_ts) {
- guint64 diff = vorbisenc->expected_ts - timestamp;
- guint64 diff_bytes;
-
- GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous "
- "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
- "), cannot handle. Clipping buffer.",
- GST_TIME_ARGS (timestamp), GST_TIME_ARGS (vorbisenc->expected_ts));
-
- diff_bytes =
- GST_CLOCK_TIME_TO_FRAMES (diff,
- vorbisenc->frequency) * vorbisenc->channels * sizeof (gfloat);
- if (diff_bytes >= GST_BUFFER_SIZE (buffer)) {
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
- }
- buffer = gst_buffer_make_metadata_writable (buffer);
- GST_BUFFER_DATA (buffer) += diff_bytes;
- GST_BUFFER_SIZE (buffer) -= diff_bytes;
-
- GST_BUFFER_TIMESTAMP (buffer) += diff;
- if (GST_BUFFER_DURATION_IS_VALID (buffer))
- GST_BUFFER_DURATION (buffer) -= diff;
- }
-
- if (gst_vorbis_enc_buffer_check_discontinuous (vorbisenc, timestamp,
- GST_BUFFER_DURATION (buffer)) && !first) {
- GST_WARNING_OBJECT (vorbisenc,
- "Buffer is discontinuous, flushing encoder "
- "and restarting (Discont from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT
- ")", GST_TIME_ARGS (vorbisenc->next_ts), GST_TIME_ARGS (timestamp));
- /* Re-initialise encoder (there's unfortunately no API to flush it) */
- if ((ret = gst_vorbis_enc_clear (vorbisenc)) != GST_FLOW_OK)
- return ret;
- if (!gst_vorbis_enc_setup (vorbisenc))
- return GST_FLOW_ERROR; /* Should be impossible, we can only get here if
- we successfully initialised earlier */
-
- /* Now, set our granulepos offset appropriately. */
- vorbisenc->next_ts = timestamp;
- /* We need to round to the nearest whole number of samples, not just do
- * a truncating division here */
- vorbisenc->granulepos_offset = gst_util_uint64_scale
- (running_time + GST_SECOND / vorbisenc->frequency / 2
- - vorbisenc->subgranule_offset, vorbisenc->frequency, GST_SECOND);
-
- vorbisenc->header_sent = TRUE;
-
- /* And our next output buffer must have DISCONT set on it */
- vorbisenc->next_discont = TRUE;
- }
-
- /* Sending zero samples to libvorbis marks EOS, so we mustn't do that */
- if (GST_BUFFER_SIZE (buffer) == 0) {
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
- }
-
- /* data to encode */
- data = (gfloat *) GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer) / (vorbisenc->channels * sizeof (float));
-
- /* expose the buffer to submit data */
- vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
-
- /* deinterleave samples, write the buffer data */
- for (i = 0; i < size; i++) {
- for (j = 0; j < vorbisenc->channels; j++) {
- vorbis_buffer[j][i] = *data++;
- }
- }
-
- /* tell the library how much we actually submitted */
- vorbis_analysis_wrote (&vorbisenc->vd, size);
-
- GST_LOG_OBJECT (vorbisenc, "wrote %lu samples to vorbis", size);
-
- vorbisenc->samples_in += size;
-
- gst_buffer_unref (buffer);
-
- ret = gst_vorbis_enc_output_buffers (vorbisenc);
-
- return ret;
-
- /* error cases */
-not_setup:
- {
- gst_buffer_unref (buffer);
- GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL),
- ("encoder not initialized (input is not audio?)"));
- return GST_FLOW_UNEXPECTED;
- }
-failed_header_push:
- {
- GST_WARNING_OBJECT (vorbisenc, "Failed to push headers");
- /* buf1 is always already unreffed */
- if (buf2)
- gst_buffer_unref (buf2);
- if (buf3)
- gst_buffer_unref (buf3);
- gst_buffer_unref (buffer);
- return ret;
- }
-}
-
-static GstFlowReturn
-gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc)
-{
- GstFlowReturn ret;
-
- /* vorbis does some data preanalysis, then divides up blocks for
- more involved (potentially parallel) processing. Get a single
- block for encoding now */
- while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) {
- ogg_packet op;
-
- GST_LOG_OBJECT (vorbisenc, "analysed to a block");
-
- /* analysis */
- vorbis_analysis (&vorbisenc->vb, NULL);
- vorbis_bitrate_addblock (&vorbisenc->vb);
-
- while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) {
- GST_LOG_OBJECT (vorbisenc, "pushing out a data packet");
- ret = gst_vorbis_enc_push_packet (vorbisenc, &op);
-
- if (ret != GST_FLOW_OK)
- return ret;
- }
- }
-
- return GST_FLOW_OK;
-}
-
-static void
-gst_vorbis_enc_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstVorbisEnc *vorbisenc;
-
- g_return_if_fail (GST_IS_VORBISENC (object));
-
- vorbisenc = GST_VORBISENC (object);
-
- switch (prop_id) {
- case ARG_MAX_BITRATE:
- g_value_set_int (value, vorbisenc->max_bitrate);
- break;
- case ARG_BITRATE:
- g_value_set_int (value, vorbisenc->bitrate);
- break;
- case ARG_MIN_BITRATE:
- g_value_set_int (value, vorbisenc->min_bitrate);
- break;
- case ARG_QUALITY:
- g_value_set_float (value, vorbisenc->quality);
- break;
- case ARG_MANAGED:
- g_value_set_boolean (value, vorbisenc->managed);
- break;
- case ARG_LAST_MESSAGE:
- g_value_set_string (value, vorbisenc->last_message);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_vorbis_enc_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstVorbisEnc *vorbisenc;
-
- g_return_if_fail (GST_IS_VORBISENC (object));
-
- vorbisenc = GST_VORBISENC (object);
-
- switch (prop_id) {
- case ARG_MAX_BITRATE:
- {
- gboolean old_value = vorbisenc->managed;
-
- vorbisenc->max_bitrate = g_value_get_int (value);
- if (vorbisenc->max_bitrate >= 0
- && vorbisenc->max_bitrate < LOWEST_BITRATE) {
- g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
- vorbisenc->max_bitrate = LOWEST_BITRATE;
- }
- if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
- vorbisenc->managed = TRUE;
- else
- vorbisenc->managed = FALSE;
-
- if (old_value != vorbisenc->managed)
- g_object_notify (object, "managed");
- break;
- }
- case ARG_BITRATE:
- vorbisenc->bitrate = g_value_get_int (value);
- if (vorbisenc->bitrate >= 0 && vorbisenc->bitrate < LOWEST_BITRATE) {
- g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
- vorbisenc->bitrate = LOWEST_BITRATE;
- }
- break;
- case ARG_MIN_BITRATE:
- {
- gboolean old_value = vorbisenc->managed;
-
- vorbisenc->min_bitrate = g_value_get_int (value);
- if (vorbisenc->min_bitrate >= 0
- && vorbisenc->min_bitrate < LOWEST_BITRATE) {
- g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
- vorbisenc->min_bitrate = LOWEST_BITRATE;
- }
- if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
- vorbisenc->managed = TRUE;
- else
- vorbisenc->managed = FALSE;
-
- if (old_value != vorbisenc->managed)
- g_object_notify (object, "managed");
- break;
- }
- case ARG_QUALITY:
- vorbisenc->quality = g_value_get_float (value);
- if (vorbisenc->quality >= 0.0)
- vorbisenc->quality_set = TRUE;
- else
- vorbisenc->quality_set = FALSE;
- break;
- case ARG_MANAGED:
- vorbisenc->managed = g_value_get_boolean (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GstStateChangeReturn
-gst_vorbis_enc_change_state (GstElement * element, GstStateChange transition)
-{
- GstVorbisEnc *vorbisenc = GST_VORBISENC (element);
- GstStateChangeReturn res;
-
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- vorbisenc->tags = gst_tag_list_new ();
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- vorbisenc->setup = FALSE;
- vorbisenc->next_discont = FALSE;
- vorbisenc->header_sent = FALSE;
- gst_segment_init (&vorbisenc->segment, GST_FORMAT_TIME);
- vorbisenc->initial_ts = GST_CLOCK_TIME_NONE;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- vorbis_block_clear (&vorbisenc->vb);
- vorbis_dsp_clear (&vorbisenc->vd);
- vorbis_info_clear (&vorbisenc->vi);
- g_free (vorbisenc->last_message);
- vorbisenc->last_message = NULL;
- if (vorbisenc->srccaps) {
- gst_caps_unref (vorbisenc->srccaps);
- vorbisenc->srccaps = NULL;
- }
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- gst_tag_list_free (vorbisenc->tags);
- vorbisenc->tags = NULL;
- default:
- break;
- }
-
- return res;
-}
diff --git a/ext/vorbis/gstvorbisenc.h b/ext/vorbis/gstvorbisenc.h
deleted file mode 100644
index 9375a16c..00000000
--- a/ext/vorbis/gstvorbisenc.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
- *
- * 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_VORBIS_ENC_H__
-#define __GST_VORBIS_ENC_H__
-
-
-#include <gst/gst.h>
-
-#include <vorbis/codec.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_VORBISENC \
- (gst_vorbis_enc_get_type())
-#define GST_VORBISENC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBISENC,GstVorbisEnc))
-#define GST_VORBISENC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBISENC,GstVorbisEncClass))
-#define GST_IS_VORBISENC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBISENC))
-#define GST_IS_VORBISENC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBISENC))
-
-typedef struct _GstVorbisEnc GstVorbisEnc;
-typedef struct _GstVorbisEncClass GstVorbisEncClass;
-
-/**
- * GstVorbisEnc:
- *
- * Opaque data structure.
- */
-struct _GstVorbisEnc {
- GstElement element;
-
- GstPad *sinkpad;
- GstPad *srcpad;
-
- GstCaps *srccaps;
- GstCaps *sinkcaps;
-
- vorbis_info vi; /* struct that stores all the static vorbis bitstream
- settings */
- vorbis_comment vc; /* struct that stores all the user comments */
-
- vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
- vorbis_block vb; /* local working space for packet->PCM decode */
-
- gboolean managed;
- gint bitrate;
- gint min_bitrate;
- gint max_bitrate;
- gfloat quality;
- gboolean quality_set;
-
- gint channels;
- gint frequency;
-
- guint64 samples_in;
- guint64 bytes_out;
- GstClockTime next_ts;
- GstClockTime expected_ts;
- gboolean next_discont;
- guint64 granulepos_offset;
- gint64 subgranule_offset;
- GstSegment segment;
- GstClockTime initial_ts;
-
- GstTagList * tags;
-
- gboolean setup;
- gboolean header_sent;
- gchar *last_message;
-};
-
-struct _GstVorbisEncClass {
- GstElementClass parent_class;
-};
-
-GType gst_vorbis_enc_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_VORBIS_ENC_H__ */
diff --git a/ext/vorbis/gstvorbisparse.c b/ext/vorbis/gstvorbisparse.c
deleted file mode 100644
index 5e3c12d9..00000000
--- a/ext/vorbis/gstvorbisparse.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/* GStreamer
- * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
- * Copyright (C) 2006 Andy Wingo <wingo@pobox.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-vorbisparse
- * @see_also: vorbisdec, oggdemux, theoraparse
- *
- * The vorbisparse element will parse the header packets of the Vorbis
- * stream and put them as the streamheader in the caps. This is used in the
- * multifdsink case where you want to stream live vorbis streams to multiple
- * clients, each client has to receive the streamheaders first before they can
- * consume the vorbis packets.
- *
- * This element also makes sure that the buffers that it pushes out are properly
- * timestamped and that their offset and offset_end are set. The buffers that
- * vorbisparse outputs have all of the metadata that oggmux expects to receive,
- * which allows you to (for example) remux an ogg/vorbis file.
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisparse ! fakesink
- * ]| This pipeline shows that the streamheader is set in the caps, and that each
- * buffer has the timestamp, duration, offset, and offset_end set.
- * |[
- * gst-launch filesrc location=sine.ogg ! oggdemux ! vorbisparse \
- * ! oggmux ! filesink location=sine-remuxed.ogg
- * ]| This pipeline shows remuxing. sine-remuxed.ogg might not be exactly the same
- * as sine.ogg, but they should produce exactly the same decoded data.
- * </refsect2>
- *
- * Last reviewed on 2006-04-01 (0.10.4.1)
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gstvorbisparse.h"
-
-GST_DEBUG_CATEGORY_EXTERN (vorbisparse_debug);
-#define GST_CAT_DEFAULT vorbisparse_debug
-
-static const GstElementDetails vorbis_parse_details = {
- "VorbisParse",
- "Codec/Parser/Audio",
- "parse raw vorbis streams",
- "Thomas Vander Stichele <thomas at apestaart dot org>"
-};
-
-static GstStaticPadTemplate vorbis_parse_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-vorbis")
- );
-
-static GstStaticPadTemplate vorbis_parse_src_factory =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-vorbis")
- );
-
-GST_BOILERPLATE (GstVorbisParse, gst_vorbis_parse, GstElement,
- GST_TYPE_ELEMENT);
-
-static GstFlowReturn vorbis_parse_chain (GstPad * pad, GstBuffer * buffer);
-static GstStateChangeReturn vorbis_parse_change_state (GstElement * element,
- GstStateChange transition);
-static gboolean vorbis_parse_sink_event (GstPad * pad, GstEvent * event);
-static gboolean vorbis_parse_src_query (GstPad * pad, GstQuery * query);
-static gboolean vorbis_parse_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value);
-static GstFlowReturn vorbis_parse_parse_packet (GstVorbisParse * parse,
- GstBuffer * buf);
-
-static void
-gst_vorbis_parse_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&vorbis_parse_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&vorbis_parse_sink_factory));
- gst_element_class_set_details (element_class, &vorbis_parse_details);
-}
-
-static void
-gst_vorbis_parse_class_init (GstVorbisParseClass * klass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gstelement_class->change_state = vorbis_parse_change_state;
-
- klass->parse_packet = GST_DEBUG_FUNCPTR (vorbis_parse_parse_packet);
-}
-
-static void
-gst_vorbis_parse_init (GstVorbisParse * parse, GstVorbisParseClass * g_class)
-{
- parse->sinkpad =
- gst_pad_new_from_static_template (&vorbis_parse_sink_factory, "sink");
- gst_pad_set_chain_function (parse->sinkpad,
- GST_DEBUG_FUNCPTR (vorbis_parse_chain));
- gst_pad_set_event_function (parse->sinkpad,
- GST_DEBUG_FUNCPTR (vorbis_parse_sink_event));
- gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
-
- parse->srcpad =
- gst_pad_new_from_static_template (&vorbis_parse_src_factory, "src");
- gst_pad_set_query_function (parse->srcpad,
- GST_DEBUG_FUNCPTR (vorbis_parse_src_query));
- gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad);
-}
-
-static void
-vorbis_parse_set_header_on_caps (GstVorbisParse * parse, GstCaps * caps)
-{
- GstBuffer *buf1, *buf2, *buf3;
- GstStructure *structure;
- GValue array = { 0 };
- GValue value = { 0 };
-
- g_assert (parse);
- g_assert (parse->streamheader);
- g_assert (parse->streamheader->next);
- g_assert (parse->streamheader->next->next);
- buf1 = parse->streamheader->data;
- g_assert (buf1);
- buf2 = parse->streamheader->next->data;
- g_assert (buf2);
- buf3 = parse->streamheader->next->next->data;
- g_assert (buf3);
-
- structure = gst_caps_get_structure (caps, 0);
-
- /* mark buffers */
- GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
- GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
- GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS);
-
- /* put buffers in a fixed list */
- g_value_init (&array, GST_TYPE_ARRAY);
- g_value_init (&value, GST_TYPE_BUFFER);
- gst_value_set_buffer (&value, buf1);
- gst_value_array_append_value (&array, &value);
- g_value_unset (&value);
- g_value_init (&value, GST_TYPE_BUFFER);
- gst_value_set_buffer (&value, buf2);
- gst_value_array_append_value (&array, &value);
- g_value_unset (&value);
- g_value_init (&value, GST_TYPE_BUFFER);
- gst_value_set_buffer (&value, buf3);
- gst_value_array_append_value (&array, &value);
- gst_structure_set_value (structure, "streamheader", &array);
- g_value_unset (&value);
- g_value_unset (&array);
-}
-
-static void
-vorbis_parse_drain_event_queue (GstVorbisParse * parse)
-{
- while (parse->event_queue->length) {
- GstEvent *event;
-
- event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
- gst_pad_event_default (parse->sinkpad, event);
- }
-}
-
-static void
-vorbis_parse_push_headers (GstVorbisParse * parse)
-{
- /* mark and put on caps */
- GstCaps *caps;
- GstBuffer *outbuf, *outbuf1, *outbuf2, *outbuf3;
- ogg_packet packet;
-
- /* get the headers into the caps, passing them to vorbis as we go */
- caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad));
- vorbis_parse_set_header_on_caps (parse, caps);
- GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps);
- gst_pad_set_caps (parse->srcpad, caps);
- gst_caps_unref (caps);
-
- outbuf = GST_BUFFER_CAST (parse->streamheader->data);
- packet.packet = GST_BUFFER_DATA (outbuf);
- packet.bytes = GST_BUFFER_SIZE (outbuf);
- packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
- packet.packetno = 1;
- packet.e_o_s = 0;
- packet.b_o_s = 1;
- vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
- parse->sample_rate = parse->vi.rate;
- outbuf1 = outbuf;
-
- outbuf = GST_BUFFER_CAST (parse->streamheader->next->data);
- packet.packet = GST_BUFFER_DATA (outbuf);
- packet.bytes = GST_BUFFER_SIZE (outbuf);
- packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
- packet.packetno = 2;
- packet.e_o_s = 0;
- packet.b_o_s = 0;
- vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
- outbuf2 = outbuf;
-
- outbuf = GST_BUFFER_CAST (parse->streamheader->next->next->data);
- packet.packet = GST_BUFFER_DATA (outbuf);
- packet.bytes = GST_BUFFER_SIZE (outbuf);
- packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
- packet.packetno = 3;
- packet.e_o_s = 0;
- packet.b_o_s = 0;
- vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
- outbuf3 = outbuf;
-
- /* first process queued events */
- vorbis_parse_drain_event_queue (parse);
-
- /* push out buffers, ignoring return value... */
- gst_buffer_set_caps (outbuf1, GST_PAD_CAPS (parse->srcpad));
- gst_pad_push (parse->srcpad, outbuf1);
- gst_buffer_set_caps (outbuf2, GST_PAD_CAPS (parse->srcpad));
- gst_pad_push (parse->srcpad, outbuf2);
- gst_buffer_set_caps (outbuf3, GST_PAD_CAPS (parse->srcpad));
- gst_pad_push (parse->srcpad, outbuf3);
-
- g_list_free (parse->streamheader);
- parse->streamheader = NULL;
-}
-
-static void
-vorbis_parse_clear_queue (GstVorbisParse * parse)
-{
- while (parse->buffer_queue->length) {
- GstBuffer *buf;
-
- buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
- gst_buffer_unref (buf);
- }
- while (parse->event_queue->length) {
- GstEvent *event;
-
- event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
- gst_event_unref (event);
- }
-}
-
-static GstFlowReturn
-vorbis_parse_push_buffer (GstVorbisParse * parse, GstBuffer * buf,
- gint64 granulepos)
-{
- guint64 samples;
-
- /* our hack as noted below */
- samples = GST_BUFFER_OFFSET (buf);
-
- GST_BUFFER_OFFSET_END (buf) = granulepos;
- GST_BUFFER_DURATION (buf) = samples * GST_SECOND / parse->sample_rate;
- GST_BUFFER_OFFSET (buf) = granulepos * GST_SECOND / parse->sample_rate;
- GST_BUFFER_TIMESTAMP (buf) =
- GST_BUFFER_OFFSET (buf) - GST_BUFFER_DURATION (buf);
-
- gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
-
- return gst_pad_push (parse->srcpad, buf);
-}
-
-static GstFlowReturn
-vorbis_parse_drain_queue_prematurely (GstVorbisParse * parse)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- gint64 granulepos = MAX (parse->prev_granulepos, 0);
-
- /* got an EOS event, make sure to push out any buffers that were in the queue
- * -- won't normally be the case, but this catches the
- * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous
- * stream. */
-
- /* if we got EOS before any buffers came, go ahead and push the other events
- * first */
- vorbis_parse_drain_event_queue (parse);
-
- while (!g_queue_is_empty (parse->buffer_queue)) {
- GstBuffer *buf;
-
- buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
-
- granulepos += GST_BUFFER_OFFSET (buf);
- ret = vorbis_parse_push_buffer (parse, buf, granulepos);
-
- if (ret != GST_FLOW_OK)
- goto done;
- }
-
- parse->prev_granulepos = granulepos;
-
-done:
- return ret;
-}
-
-static GstFlowReturn
-vorbis_parse_drain_queue (GstVorbisParse * parse, gint64 granulepos)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- GList *walk;
- gint64 cur = granulepos;
- gint64 gp;
-
- for (walk = parse->buffer_queue->head; walk; walk = walk->next)
- cur -= GST_BUFFER_OFFSET (walk->data);
-
- if (parse->prev_granulepos != -1)
- cur = MAX (cur, parse->prev_granulepos);
-
- while (!g_queue_is_empty (parse->buffer_queue)) {
- GstBuffer *buf;
-
- buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
-
- cur += GST_BUFFER_OFFSET (buf);
- gp = CLAMP (cur, 0, granulepos);
-
- ret = vorbis_parse_push_buffer (parse, buf, gp);
-
- if (ret != GST_FLOW_OK)
- goto done;
- }
-
- parse->prev_granulepos = granulepos;
-
-done:
- return ret;
-}
-
-static GstFlowReturn
-vorbis_parse_queue_buffer (GstVorbisParse * parse, GstBuffer * buf)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- long blocksize;
- ogg_packet packet;
-
- buf = gst_buffer_make_metadata_writable (buf);
-
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
- packet.granulepos = GST_BUFFER_OFFSET_END (buf);
- packet.packetno = parse->packetno + parse->buffer_queue->length;
- packet.e_o_s = 0;
-
- blocksize = vorbis_packet_blocksize (&parse->vi, &packet);
-
- /* temporarily store the sample count in OFFSET -- we overwrite this later */
-
- if (parse->prev_blocksize < 0)
- GST_BUFFER_OFFSET (buf) = 0;
- else
- GST_BUFFER_OFFSET (buf) = (blocksize + parse->prev_blocksize) / 4;
-
- parse->prev_blocksize = blocksize;
-
- g_queue_push_tail (parse->buffer_queue, buf);
-
- if (GST_BUFFER_OFFSET_END_IS_VALID (buf))
- ret = vorbis_parse_drain_queue (parse, GST_BUFFER_OFFSET_END (buf));
-
- return ret;
-}
-
-static GstFlowReturn
-vorbis_parse_parse_packet (GstVorbisParse * parse, GstBuffer * buf)
-{
- GstFlowReturn ret;
- guint8 *data;
- guint size;
- gboolean have_header;
-
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
-
- parse->packetno++;
-
- have_header = FALSE;
- if (size >= 1) {
- if (data[0] >= 0x01 && data[0] <= 0x05)
- have_header = TRUE;
- }
-
- if (have_header) {
- if (!parse->streamheader_sent) {
- /* we need to collect the headers still */
- /* so put it on the streamheader list and return */
- parse->streamheader = g_list_append (parse->streamheader, buf);
- }
- ret = GST_FLOW_OK;
- } else {
- /* data packet, push the headers we collected before */
- if (!parse->streamheader_sent) {
- vorbis_parse_push_headers (parse);
- parse->streamheader_sent = TRUE;
- }
- ret = vorbis_parse_queue_buffer (parse, buf);
- }
-
- return ret;
-}
-
-static GstFlowReturn
-vorbis_parse_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstVorbisParseClass *klass;
- GstVorbisParse *parse;
-
- parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad));
- klass = GST_VORBIS_PARSE_CLASS (G_OBJECT_GET_CLASS (parse));
-
- g_assert (klass->parse_packet != NULL);
-
- return klass->parse_packet (parse, buffer);
-}
-
-static gboolean
-vorbis_parse_queue_event (GstVorbisParse * parse, GstEvent * event)
-{
- GstFlowReturn ret = TRUE;
-
- g_queue_push_tail (parse->event_queue, event);
-
- return ret;
-}
-
-static gboolean
-vorbis_parse_sink_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret;
- GstVorbisParse *parse;
-
- parse = GST_VORBIS_PARSE (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- vorbis_parse_clear_queue (parse);
- parse->prev_granulepos = -1;
- parse->prev_blocksize = -1;
- ret = gst_pad_event_default (pad, event);
- break;
- case GST_EVENT_EOS:
- vorbis_parse_drain_queue_prematurely (parse);
- ret = gst_pad_event_default (pad, event);
- break;
- default:
- if (!parse->streamheader_sent && GST_EVENT_IS_SERIALIZED (event))
- ret = vorbis_parse_queue_event (parse, event);
- else
- ret = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (parse);
-
- return ret;
-}
-
-static gboolean
-vorbis_parse_convert (GstPad * pad,
- GstFormat src_format, gint64 src_value,
- GstFormat * dest_format, gint64 * dest_value)
-{
- gboolean res = TRUE;
- GstVorbisParse *parse;
- guint64 scale = 1;
-
- parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad));
-
- /* fixme: assumes atomic access to lots of instance variables modified from
- * the streaming thread, including 64-bit variables */
-
- if (parse->packetno < 4)
- return FALSE;
-
- if (src_format == *dest_format) {
- *dest_value = src_value;
- return TRUE;
- }
-
- if (parse->sinkpad == pad &&
- (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
- return FALSE;
-
- switch (src_format) {
- case GST_FORMAT_TIME:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- scale = sizeof (float) * parse->vi.channels;
- case GST_FORMAT_DEFAULT:
- *dest_value =
- scale * gst_util_uint64_scale_int (src_value, parse->vi.rate,
- GST_SECOND);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_DEFAULT:
- switch (*dest_format) {
- case GST_FORMAT_BYTES:
- *dest_value = src_value * sizeof (float) * parse->vi.channels;
- break;
- case GST_FORMAT_TIME:
- *dest_value =
- gst_util_uint64_scale_int (src_value, GST_SECOND, parse->vi.rate);
- break;
- default:
- res = FALSE;
- }
- break;
- case GST_FORMAT_BYTES:
- switch (*dest_format) {
- case GST_FORMAT_DEFAULT:
- *dest_value = src_value / (sizeof (float) * parse->vi.channels);
- break;
- case GST_FORMAT_TIME:
- *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
- parse->vi.rate * sizeof (float) * parse->vi.channels);
- break;
- default:
- res = FALSE;
- }
- break;
- default:
- res = FALSE;
- }
-
- return res;
-}
-
-static gboolean
-vorbis_parse_src_query (GstPad * pad, GstQuery * query)
-{
- gint64 granulepos;
- GstVorbisParse *parse;
- gboolean res = FALSE;
-
- parse = GST_VORBIS_PARSE (GST_PAD_PARENT (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- {
- GstFormat format;
- gint64 value;
-
- granulepos = parse->prev_granulepos;
-
- gst_query_parse_position (query, &format, NULL);
-
- /* and convert to the final format */
- if (!(res =
- vorbis_parse_convert (pad, GST_FORMAT_DEFAULT, granulepos,
- &format, &value)))
- goto error;
-
- /* fixme: support segments
- value = (value - parse->segment_start) + parse->segment_time;
- */
-
- gst_query_set_position (query, format, value);
-
- GST_LOG_OBJECT (parse, "query %p: peer returned granulepos: %"
- G_GUINT64_FORMAT " - we return %" G_GUINT64_FORMAT " (format %u)",
- query, granulepos, value, format);
-
- break;
- }
- case GST_QUERY_DURATION:
- {
- /* fixme: not threadsafe */
- /* query peer for total length */
- if (!gst_pad_is_linked (parse->sinkpad)) {
- GST_WARNING_OBJECT (parse, "sink pad %" GST_PTR_FORMAT " is not linked",
- parse->sinkpad);
- goto error;
- }
- if (!(res = gst_pad_query (GST_PAD_PEER (parse->sinkpad), query)))
- goto error;
- break;
- }
- case GST_QUERY_CONVERT:
- {
- GstFormat src_fmt, dest_fmt;
- gint64 src_val, dest_val;
-
- gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
- if (!(res =
- vorbis_parse_convert (pad, src_fmt, src_val, &dest_fmt,
- &dest_val)))
- goto error;
- gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
- break;
- }
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
- return res;
-
-error:
- {
- GST_WARNING_OBJECT (parse, "error handling query");
- return res;
- }
-}
-
-static GstStateChangeReturn
-vorbis_parse_change_state (GstElement * element, GstStateChange transition)
-{
- GstVorbisParse *parse = GST_VORBIS_PARSE (element);
- GstStateChangeReturn ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- vorbis_info_init (&parse->vi);
- vorbis_comment_init (&parse->vc);
- parse->prev_granulepos = -1;
- parse->prev_blocksize = -1;
- parse->packetno = 0;
- parse->streamheader_sent = FALSE;
- parse->buffer_queue = g_queue_new ();
- parse->event_queue = g_queue_new ();
- break;
- default:
- break;
- }
-
- ret = parent_class->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- vorbis_info_clear (&parse->vi);
- vorbis_comment_clear (&parse->vc);
- vorbis_parse_clear_queue (parse);
- g_queue_free (parse->buffer_queue);
- parse->buffer_queue = NULL;
- g_queue_free (parse->event_queue);
- parse->event_queue = NULL;
- break;
- default:
- break;
- }
-
- return ret;
-}
diff --git a/ext/vorbis/gstvorbisparse.h b/ext/vorbis/gstvorbisparse.h
deleted file mode 100644
index 65389497..00000000
--- a/ext/vorbis/gstvorbisparse.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- c-basic-offset: 2 -*-
- * GStreamer
- * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_VORBIS_PARSE_H__
-#define __GST_VORBIS_PARSE_H__
-
-
-#include <gst/gst.h>
-#include <vorbis/codec.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_VORBIS_PARSE \
- (gst_vorbis_parse_get_type())
-#define GST_VORBIS_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VORBIS_PARSE,GstVorbisParse))
-#define GST_VORBIS_PARSE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VORBIS_PARSE,GstVorbisParseClass))
-#define GST_IS_VORBIS_PARSE(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBIS_PARSE))
-#define GST_IS_VORBIS_PARSE_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBIS_PARSE))
-
-typedef struct _GstVorbisParse GstVorbisParse;
-typedef struct _GstVorbisParseClass GstVorbisParseClass;
-
-/**
- * GstVorbisParse:
- *
- * Opaque data structure.
- */
-struct _GstVorbisParse {
- GstElement element;
-
- GstPad * sinkpad;
- GstPad * srcpad;
-
- guint packetno;
- gboolean streamheader_sent;
- GList * streamheader;
-
- GQueue * event_queue;
- GQueue * buffer_queue;
-
- vorbis_info vi;
- vorbis_comment vc;
-
- gint64 prev_granulepos;
- gint32 prev_blocksize;
- guint32 sample_rate;
-};
-
-struct _GstVorbisParseClass {
- GstElementClass parent_class;
-
- /* virtual functions */
- GstFlowReturn (*parse_packet) (GstVorbisParse * parse, GstBuffer * buf);
-};
-
-GType gst_vorbis_parse_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_VORBIS_PARSE_H__ */
diff --git a/ext/vorbis/gstvorbistag.c b/ext/vorbis/gstvorbistag.c
deleted file mode 100644
index 67a931d1..00000000
--- a/ext/vorbis/gstvorbistag.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2006 James Livingston <doclivingston@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:element-vorbistag
- * @see_also: #oggdemux, #oggmux, #vorbisparse, #GstTagSetter
- *
- * The vorbistags element can change the tag contained within a raw
- * vorbis stream. Specifically, it modifies the comments header packet
- * of the vorbis stream.
- *
- * The element will also process the stream as the #vorbisparse element does
- * so it can be used when remuxing an Ogg Vorbis stream, without additional
- * elements.
- *
- * Applications can set the tags to write using the #GstTagSetter interface.
- * Tags contained withing the vorbis bitstream will be picked up
- * automatically (and merged according to the merge mode set via the tag
- * setter interface).
- *
- * <refsect2>
- * <title>Example pipelines</title>
- * |[
- * gst-launch -v filesrc location=foo.ogg ! oggdemux ! vorbistag ! oggmux ! filesink location=bar.ogg
- * ]| This element is not useful with gst-launch, because it does not support
- * setting the tags on a #GstTagSetter interface. Conceptually, the element
- * will usually be used in this order though.
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <glib.h>
-#include <gst/tag/tag.h>
-#include <gst/gsttagsetter.h>
-
-#include <vorbis/codec.h>
-
-#include "gstvorbistag.h"
-
-
-GST_DEBUG_CATEGORY_EXTERN (vorbisparse_debug);
-#define GST_CAT_DEFAULT vorbisparse_debug
-
-static void gst_vorbis_tag_base_init (gpointer g_class);
-static void gst_vorbis_tag_class_init (GstVorbisTagClass * klass);
-static void gst_vorbis_tag_init (GstVorbisTag * tagger,
- GstVorbisTagClass * g_class);
-static GstFlowReturn gst_vorbis_tag_parse_packet (GstVorbisParse * parse,
- GstBuffer * buffer);
-
-#define _do_init(type) \
- G_STMT_START{ \
- static const GInterfaceInfo tag_setter_info = { \
- NULL, \
- NULL, \
- NULL \
- }; \
- g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \
- &tag_setter_info); \
- }G_STMT_END
-
-GST_BOILERPLATE_FULL (GstVorbisTag, gst_vorbis_tag, GstVorbisParse,
- GST_TYPE_VORBIS_PARSE, _do_init);
-
-static GstElementDetails vorbis_tag_details = {
- "VorbisTag",
- "Formatter/Metadata",
- "Retags vorbis streams",
- "James Livingston <doclivingston@gmail.com>"
-};
-
-
-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, &vorbis_tag_details);
-}
-
-static void
-gst_vorbis_tag_class_init (GstVorbisTagClass * klass)
-{
- GstVorbisParseClass *vorbisparse_class = GST_VORBIS_PARSE_CLASS (klass);
-
- vorbisparse_class->parse_packet = gst_vorbis_tag_parse_packet;
-}
-
-static void
-gst_vorbis_tag_init (GstVorbisTag * tagger, GstVorbisTagClass * g_class)
-{
- /* nothing to do */
-}
-
-
-static GstFlowReturn
-gst_vorbis_tag_parse_packet (GstVorbisParse * parse, GstBuffer * buffer)
-{
- GstTagList *old_tags, *new_tags;
- const GstTagList *user_tags;
- GstVorbisTag *tagger;
- gchar *encoder = NULL;
- GstBuffer *new_buf;
-
- /* just pass everything except the comments packet */
- if (GST_BUFFER_SIZE (buffer) >= 1 && GST_BUFFER_DATA (buffer)[0] != 0x03) {
- return GST_VORBIS_PARSE_CLASS (parent_class)->parse_packet (parse, buffer);
- }
-
- tagger = GST_VORBIS_TAG (parse);
-
- old_tags =
- gst_tag_list_from_vorbiscomment_buffer (buffer, (guint8 *) "\003vorbis",
- 7, &encoder);
- user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (tagger));
-
- /* build new tag list */
- new_tags = gst_tag_list_merge (user_tags, old_tags,
- gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (tagger)));
- gst_tag_list_free (old_tags);
-
- new_buf =
- gst_tag_list_to_vorbiscomment_buffer (new_tags, (guint8 *) "\003vorbis",
- 7, encoder);
- gst_buffer_copy_metadata (new_buf, buffer, GST_BUFFER_COPY_TIMESTAMPS);
-
- gst_tag_list_free (new_tags);
- g_free (encoder);
- gst_buffer_unref (buffer);
-
- return GST_VORBIS_PARSE_CLASS (parent_class)->parse_packet (parse, new_buf);
-}
diff --git a/ext/vorbis/gstvorbistag.h b/ext/vorbis/gstvorbistag.h
deleted file mode 100644
index 9a443006..00000000
--- a/ext/vorbis/gstvorbistag.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- c-basic-offset: 2 -*-
- * GStreamer
- * Copyright (C) <2006> James Livingston <doclivingston@gmail.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_VORBIS_TAG_H__
-#define __GST_VORBIS_TAG_H__
-
-#include "gstvorbisparse.h"
-
-
-G_BEGIN_DECLS
-
-
-#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,GstVorbisTagClass))
-#define GST_IS_VORBIS_TAG(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VORBIS_TAG))
-#define GST_IS_VORBIS_TAG_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VORBIS_TAG))
-
-
-typedef struct _GstVorbisTag GstVorbisTag;
-typedef struct _GstVorbisTagClass GstVorbisTagClass;
-
-/**
- * GstVorbisTag:
- *
- * Opaque data structure.
- */
-struct _GstVorbisTag {
- GstVorbisParse parse;
-};
-
-struct _GstVorbisTagClass {
- GstVorbisParseClass parent_class;
-};
-
-GType gst_vorbis_tag_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_VORBIS_TAG_H__ */