vorbisdec: also support ivorbis tremor decoder

... which only needs a bit of refactoring and extracting to support
the minor difference in (i)vorbis interface.

Fixes #609063.
This commit is contained in:
Mark Nauwelaerts 2010-02-15 12:09:53 +01:00
parent 5e06eaa517
commit 32dff24552
8 changed files with 428 additions and 60 deletions

View file

@ -584,6 +584,29 @@ AG_GST_CHECK_FEATURE(GNOME_VFS, [GNOME VFS], gnomevfs, [
)
])
dnl *** ivorbis ***
dnl AM_PATH_IVORBIS only takes two options
translit(dnm, m, l) AM_CONDITIONAL(USE_IVORBIS, true)
AG_GST_CHECK_FEATURE(IVORBIS, [integer vorbis plug-in], ivorbisdec, [
AG_GST_PKG_CHECK_MODULES(IVORBIS, vorbisidec)
if test $HAVE_IVORBIS = no
then
IVORBIS_LIBS=
IVORBIS_CFLAGS=
AC_CHECK_LIB(vorbisidec, vorbis_block_init,
[IVORBIS_LIBS=-lvorbisidec
HAVE_IVORBIS=yes
case $host in
arm-*-*)
IVORBIS_CFLAGS="-D_ARM_ASSEM_ $IVORBIS_CFLAGS"
esac
],
HAVE_IVORBIS=no)
AC_SUBST(IVORBIS_LIBS)
AC_SUBST(IVORBIS_CFLAGS)
fi
])
dnl *** libgio ***
translit(dnm, m, l) AM_CONDITIONAL(USE_GIO, true)
AG_GST_CHECK_FEATURE(GIO, [GIO library], gio, [

View file

@ -42,9 +42,17 @@ endif
if USE_VORBIS
VORBIS_DIR=vorbis
else
endif
if USE_IVORBIS
VORBIS_DIR=vorbis
endif
if !USE_VORBIS
if !USE_IVORBIS
VORBIS_DIR=
endif
endif
if USE_THEORA
THEORA_DIR=theora

View file

@ -1,13 +1,17 @@
plugin_LTLIBRARIES = libgstvorbis.la
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)
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 \
@ -16,9 +20,26 @@ libgstvorbis_la_LIBADD = \
$(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

View file

@ -0,0 +1,47 @@
/* 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_PRIMARY + 1,
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)

View file

@ -52,25 +52,13 @@ GST_DEBUG_CATEGORY_EXTERN (vorbisdec_debug);
#define GST_CAT_DEFAULT vorbisdec_debug
static const GstElementDetails vorbis_dec_details =
GST_ELEMENT_DETAILS ("Vorbis audio decoder",
"Codec/Decoder/Audio",
"decode raw vorbis streams to float audio",
"Benjamin Otte <in7y118@public.uni-hamburg.de>");
GST_VORBIS_DEC_ELEMENT_DETAILS;
static GstStaticPadTemplate vorbis_dec_src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-float, "
"rate = (int) [ 1, MAX ], "
"channels = (int) [ 1, 256 ], " "endianness = (int) BYTE_ORDER, "
/* no ifdef in macros, please
#ifdef GST_VORBIS_DEC_SEQUENTIAL
"layout = \"sequential\", "
#endif
*/
"width = (int) 32")
);
GST_VORBIS_DEC_SRC_CAPS);
static GstStaticPadTemplate vorbis_dec_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
@ -79,7 +67,8 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_STATIC_CAPS ("audio/x-vorbis")
);
GST_BOILERPLATE (GstVorbisDec, gst_vorbis_dec, GstElement, GST_TYPE_ELEMENT);
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);
@ -560,6 +549,7 @@ 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:
@ -589,11 +579,24 @@ vorbis_handle_identification_packet (GstVorbisDec * vd)
}
}
vd->width = 4;
/* 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);
"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);
@ -620,8 +623,8 @@ vorbis_handle_comment_packet (GstVorbisDec * vd, ogg_packet * packet)
GST_DEBUG_OBJECT (vd, "parsing comment packet");
buf = gst_buffer_new ();
GST_BUFFER_DATA (buf) = packet->packet;
GST_BUFFER_SIZE (buf) = packet->bytes;
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,
@ -738,12 +741,12 @@ vorbis_handle_header_packet (GstVorbisDec * vd, ogg_packet * packet)
GST_DEBUG_OBJECT (vd, "parsing header packet");
/* Packetno = 0 if the first byte is exactly 0x01 */
packet->b_o_s = (packet->packet[0] == 0x1) ? 1 : 0;
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 (packet->packet[0]) {
switch ((gst_ogg_packet_data (packet))[0]) {
case 0x01:
res = vorbis_handle_identification_packet (vd);
break;
@ -770,27 +773,6 @@ header_read_error:
}
}
/* These samples can be outside of the float -1.0 -- 1.0 range, this
* is allowed, downstream elements are supposed to clip */
static void
copy_samples (float *out, float **in, guint samples, gint channels)
{
gint i, j;
#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
}
static GstFlowReturn
vorbis_dec_push_forward (GstVorbisDec * dec, GstBuffer * buf)
{
@ -855,7 +837,7 @@ static GstFlowReturn
vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
GstClockTime timestamp, GstClockTime duration)
{
float **pcm;
vorbis_sample_t **pcm;
guint sample_count;
GstBuffer *out;
GstFlowReturn result;
@ -899,8 +881,8 @@ vorbis_handle_data_packet (GstVorbisDec * vd, ogg_packet * packet,
goto wrong_samples;
/* copy samples in buffer */
copy_samples ((float *) GST_BUFFER_DATA (out), pcm, sample_count,
vd->vi.channels);
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;
@ -952,22 +934,24 @@ wrong_samples:
static GstFlowReturn
vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer)
{
ogg_packet packet;
ogg_packet *packet;
ogg_packet_wrapper packet_wrapper;
GstFlowReturn result = GST_FLOW_OK;
/* make ogg_packet out of the buffer */
packet.packet = GST_BUFFER_DATA (buffer);
packet.bytes = GST_BUFFER_SIZE (buffer);
packet.granulepos = -1;
packet.packetno = 0; /* we don't care */
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;
packet->e_o_s = 0;
GST_LOG_OBJECT (vd, "decode buffer of size %ld", packet.bytes);
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 (G_UNLIKELY (packet->bytes == 0)) {
if (vd->initialized)
goto empty_buffer;
else
@ -975,19 +959,19 @@ vorbis_dec_decode_buffer (GstVorbisDec * vd, GstBuffer * buffer)
}
/* switch depending on packet type */
if (packet.packet[0] & 1) {
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);
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);
result = vorbis_handle_data_packet (vd, packet, timestamp, duration);
}
done:

View file

@ -24,7 +24,7 @@
#include <gst/gst.h>
#include <vorbis/codec.h>
#include "gstvorbisdeclib.h"
G_BEGIN_DECLS

View file

@ -0,0 +1,122 @@
/* 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

View file

@ -0,0 +1,163 @@
/* 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__ */