summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorArwed v. Merkatz <v.merkatz@gmx.net>2004-11-26 23:10:28 +0000
committerArwed v. Merkatz <v.merkatz@gmx.net>2004-11-26 23:10:28 +0000
commitaeb09d35abf17934407c8e1c826de3d8fab7193d (patch)
treed0fe82628748857181a06244014a924e4655682f /gst
parent90bf594c667017695e13238ec9b5970501b34dd9 (diff)
downloadgst-plugins-bad-aeb09d35abf17934407c8e1c826de3d8fab7193d.tar.gz
gst-plugins-bad-aeb09d35abf17934407c8e1c826de3d8fab7193d.tar.bz2
gst-plugins-bad-aeb09d35abf17934407c8e1c826de3d8fab7193d.zip
added TTA parser and decoder
Original commit message from CVS: added TTA parser and decoder
Diffstat (limited to 'gst')
-rw-r--r--gst/tta/Makefile.am12
-rw-r--r--gst/tta/crc32.h114
-rw-r--r--gst/tta/filters.h110
-rw-r--r--gst/tta/gsttta.c40
-rw-r--r--gst/tta/gstttadec.c458
-rw-r--r--gst/tta/gstttadec.h84
-rw-r--r--gst/tta/gstttaparse.c418
-rw-r--r--gst/tta/gstttaparse.h82
-rw-r--r--gst/tta/ttadec.h141
9 files changed, 1459 insertions, 0 deletions
diff --git a/gst/tta/Makefile.am b/gst/tta/Makefile.am
new file mode 100644
index 00000000..9634b139
--- /dev/null
+++ b/gst/tta/Makefile.am
@@ -0,0 +1,12 @@
+plugin_LTLIBRARIES = libgsttta.la
+
+libgsttta_la_SOURCES = gsttta.c \
+ gstttaparse.c \
+ gstttadec.c
+
+noinst_HEADERS = gstttaparse.h gstttadec.h \
+ ttadec.h crc32.h filters.h
+
+libgsttta_la_CFLAGS = $(GST_CFLAGS)
+libgsttta_la_LIBADD = $(GST_LIBS)
+libgsttta_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/gst/tta/crc32.h b/gst/tta/crc32.h
new file mode 100644
index 00000000..c4833917
--- /dev/null
+++ b/gst/tta/crc32.h
@@ -0,0 +1,114 @@
+/*
+ * crc32.h
+ *
+ * Description: CRC32 functions
+ * Developed by: Alexander Djourik <sasha@iszf.irk.ru>
+ * Pavel Zhilin <pzh@iszf.irk.ru>
+ *
+ * Copyright (c) 1999-2004 Alexander Djourik. All rights reserved.
+ *
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ *
+ * Please see the file COPYING in this directory for full copyright
+ * information.
+ */
+
+#ifndef CRC32_H
+#define CRC32_H
+
+static const unsigned long crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define UPDATE_CRC32(x, crc) crc = \
+ (((crc>>8) & 0x00FFFFFF) ^ crc32_table[(crc^x) & 0xFF])
+
+static unsigned long
+crc32 (unsigned char *buffer, unsigned long len) {
+ unsigned long i;
+ unsigned long crc = 0xFFFFFFFF;
+
+ for (i = 0; i < len; i++) UPDATE_CRC32(buffer[i], crc);
+
+ return (crc ^ 0xFFFFFFFF);
+}
+
+#endif /* CRC32_H */
diff --git a/gst/tta/filters.h b/gst/tta/filters.h
new file mode 100644
index 00000000..e2c176e1
--- /dev/null
+++ b/gst/tta/filters.h
@@ -0,0 +1,110 @@
+/*
+ * filters.h
+ *
+ * Description: TTAv1 filter functions
+ * Developed by: Alexander Djourik <sasha@iszf.irk.ru>
+ * Pavel Zhilin <pzh@iszf.irk.ru>
+ *
+ * Copyright (c) 1999-2004 Alexander Djourik. All rights reserved.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * aint with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please see the file COPYING in this directory for full copyright
+ * information.
+ */
+
+#ifndef FILTERS_H
+#define FILTERS_H
+
+///////// Filter Settings //////////
+static long flt_set[3] = {10, 9, 10};
+
+static void
+memshl (register long *pA, register long *pB) {
+ *pA++ = *pB++;
+ *pA++ = *pB++;
+ *pA++ = *pB++;
+ *pA++ = *pB++;
+ *pA++ = *pB++;
+ *pA++ = *pB++;
+ *pA++ = *pB++;
+ *pA = *pB;
+}
+
+static void
+hybrid_filter (fltst *fs, long *in) {
+ register long *pA = fs->dl;
+ register long *pB = fs->qm;
+ register long *pM = fs->dx;
+ register long sum = fs->round;
+
+ if (!fs->error) {
+ sum += *pA++ * *pB, pB++;
+ sum += *pA++ * *pB, pB++;
+ sum += *pA++ * *pB, pB++;
+ sum += *pA++ * *pB, pB++;
+ sum += *pA++ * *pB, pB++;
+ sum += *pA++ * *pB, pB++;
+ sum += *pA++ * *pB, pB++;
+ sum += *pA++ * *pB, pB++; pM += 8;
+ } else if (fs->error < 0) {
+ sum += *pA++ * (*pB -= *pM++), pB++;
+ sum += *pA++ * (*pB -= *pM++), pB++;
+ sum += *pA++ * (*pB -= *pM++), pB++;
+ sum += *pA++ * (*pB -= *pM++), pB++;
+ sum += *pA++ * (*pB -= *pM++), pB++;
+ sum += *pA++ * (*pB -= *pM++), pB++;
+ sum += *pA++ * (*pB -= *pM++), pB++;
+ sum += *pA++ * (*pB -= *pM++), pB++;
+ } else {
+ sum += *pA++ * (*pB += *pM++), pB++;
+ sum += *pA++ * (*pB += *pM++), pB++;
+ sum += *pA++ * (*pB += *pM++), pB++;
+ sum += *pA++ * (*pB += *pM++), pB++;
+ sum += *pA++ * (*pB += *pM++), pB++;
+ sum += *pA++ * (*pB += *pM++), pB++;
+ sum += *pA++ * (*pB += *pM++), pB++;
+ sum += *pA++ * (*pB += *pM++), pB++;
+ }
+
+ *(pM-0) = ((*(pA-1) >> 30) | 1) << 2;
+ *(pM-1) = ((*(pA-2) >> 30) | 1) << 1;
+ *(pM-2) = ((*(pA-3) >> 30) | 1) << 1;
+ *(pM-3) = ((*(pA-4) >> 30) | 1);
+
+ fs->error = *in;
+ *in += (sum >> fs->shift);
+ *pA = *in;
+
+ *(pA-1) = *(pA-0) - *(pA-1);
+ *(pA-2) = *(pA-1) - *(pA-2);
+ *(pA-3) = *(pA-2) - *(pA-3);
+
+ memshl (fs->dl, fs->dl + 1);
+ memshl (fs->dx, fs->dx + 1);
+}
+
+static void
+filter_init (fltst *fs, long shift) {
+ memset (fs, 0, sizeof(fltst));
+ fs->shift = shift;
+ fs->round = 1 << (shift - 1);
+}
+
+#endif /* FILTERS_H */
+
diff --git a/gst/tta/gsttta.c b/gst/tta/gsttta.c
new file mode 100644
index 00000000..addc27ab
--- /dev/null
+++ b/gst/tta/gsttta.c
@@ -0,0 +1,40 @@
+/* GStreamer TTA plugin
+ * (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * gsttta.c: plugin loader
+ *
+ * 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 "gstttaparse.h"
+#include "gstttadec.h"
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ return (gst_tta_parse_plugin_init (plugin) &&
+ gst_tta_dec_plugin_init (plugin));
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "tta",
+ "TTA lossless audio format handling",
+ plugin_init, VERSION, "LGPL", "gst-tta", "http://www.true-audio.com")
diff --git a/gst/tta/gstttadec.c b/gst/tta/gstttadec.c
new file mode 100644
index 00000000..00007ae5
--- /dev/null
+++ b/gst/tta/gstttadec.c
@@ -0,0 +1,458 @@
+/* GStreamer TTA plugin
+ * (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * based on ttalib
+ * (c) 1999-2004 Alexander Djourik <sasha@iszf.irk.ru>
+ *
+ * gstttadec.c: raw TTA bitstream decoder
+ *
+ * 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.
+ */
+
+#include <gst/gst.h>
+
+#include <math.h>
+#include <string.h>
+
+#include "gstttadec.h"
+#include "ttadec.h"
+#include "filters.h"
+
+#define TTA_BUFFER_SIZE (1024 * 32 * 8)
+
+/* this is from ttadec.h originally */
+
+static const unsigned long bit_mask[] = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+ 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+ 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+ 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+ 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
+ 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+ 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
+ 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff
+};
+
+static const unsigned long bit_shift[] = {
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x80000000, 0x80000000, 0x80000000, 0x80000000,
+ 0x80000000, 0x80000000, 0x80000000, 0x80000000
+};
+
+static const unsigned long *shift_16 = bit_shift + 4;
+
+/* Filter signals and args */
+enum
+{
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0
+};
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-tta, "
+ "width = (int) { 8, 16, 24 }, "
+ "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]")
+ );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "width = (int) { 8, 16, 24 }, "
+ "depth = (int) { 8, 16, 24 }, "
+ "channels = (int) { 1, 2 }, "
+ "rate = (int) [ 8000, 96000 ], "
+ "endianness = (int) LITTLE_ENDIAN, " "signed = (boolean) true")
+ );
+
+static void gst_tta_dec_class_init (GstTtaDecClass * klass);
+static void gst_tta_dec_base_init (GstTtaDecClass * klass);
+static void gst_tta_dec_init (GstTtaDec * ttadec);
+
+static void gst_tta_dec_chain (GstPad * pad, GstData * in);
+
+static GstElementClass *parent = NULL;
+
+static GstPadLinkReturn
+gst_tta_dec_link (GstPad * pad, const GstCaps * caps)
+{
+ GstTtaDec *ttadec = GST_TTA_DEC (gst_pad_get_parent (pad));
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ GstCaps *srccaps;
+ guint64 outsize;
+ guint bits;
+
+ if (!gst_caps_is_fixed (caps))
+ return GST_PAD_LINK_DELAYED;
+
+ gst_structure_get_int (structure, "rate", &ttadec->samplerate);
+ gst_structure_get_int (structure, "channels", &ttadec->channels);
+ gst_structure_get_int (structure, "width", &bits);
+ ttadec->bytes = bits / 8;
+
+ srccaps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, ttadec->samplerate,
+ "channels", G_TYPE_INT, ttadec->channels,
+ "depth", G_TYPE_INT, bits,
+ "width", G_TYPE_INT, bits,
+ "endianness", G_TYPE_INT, LITTLE_ENDIAN,
+ "signed", G_TYPE_BOOLEAN, TRUE, NULL);
+
+ gst_pad_set_explicit_caps (ttadec->srcpad, srccaps);
+
+ ttadec->frame_length = FRAME_TIME * ttadec->samplerate;
+
+ ttadec->tta = g_malloc (ttadec->channels * sizeof (decoder));
+ ttadec->cache = g_malloc (ttadec->channels * sizeof (long));
+
+ outsize = ttadec->channels * ttadec->frame_length * ttadec->bytes;
+
+ ttadec->decdata =
+ (guchar *) g_malloc (ttadec->channels * ttadec->frame_length *
+ ttadec->bytes * sizeof (guchar));
+
+ return GST_PAD_LINK_OK;
+}
+
+GType
+gst_tta_dec_get_type (void)
+{
+ static GType plugin_type = 0;
+
+ if (!plugin_type) {
+ static const GTypeInfo plugin_info = {
+ sizeof (GstTtaDecClass),
+ (GBaseInitFunc) gst_tta_dec_base_init,
+ NULL,
+ (GClassInitFunc) gst_tta_dec_class_init,
+ NULL,
+ NULL,
+ sizeof (GstTtaDec),
+ 0,
+ (GInstanceInitFunc) gst_tta_dec_init,
+ };
+ plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
+ "GstTtaDec", &plugin_info, 0);
+ }
+ return plugin_type;
+}
+
+static void
+gst_tta_dec_base_init (GstTtaDecClass * klass)
+{
+ static GstElementDetails plugin_details = {
+ "TTA decoder",
+ "Codec/Decoder/Audio",
+ "Decode TTA audio data",
+ "Arwed v. Merkatz <v.merkatz@gmx.net>"
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ 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, &plugin_details);
+}
+
+static void
+gst_tta_dec_dispose (GObject * object)
+{
+ GstTtaDec *ttadec = GST_TTA_DEC (object);
+
+ g_free (ttadec->tta);
+ g_free (ttadec->decdata);
+ g_free (ttadec->tta_buf.buffer);
+
+ G_OBJECT_CLASS (parent)->dispose (object);
+}
+
+static void
+gst_tta_dec_class_init (GstTtaDecClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent = g_type_class_ref (GST_TYPE_ELEMENT);
+
+ gobject_class->dispose = gst_tta_dec_dispose;
+}
+
+static void
+gst_tta_dec_init (GstTtaDec * ttadec)
+{
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (ttadec);
+
+ ttadec->sinkpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+ "sink"), "sink");
+ gst_pad_set_link_function (ttadec->sinkpad, gst_tta_dec_link);
+
+ ttadec->srcpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+ "src"), "src");
+ gst_pad_use_explicit_caps (ttadec->srcpad);
+
+ gst_element_add_pad (GST_ELEMENT (ttadec), ttadec->sinkpad);
+ gst_element_add_pad (GST_ELEMENT (ttadec), ttadec->srcpad);
+ gst_pad_set_chain_function (ttadec->sinkpad, gst_tta_dec_chain);
+ ttadec->tta_buf.buffer = (guchar *) g_malloc (TTA_BUFFER_SIZE + 4);
+ ttadec->tta_buf.buffer_end = ttadec->tta_buf.buffer + TTA_BUFFER_SIZE;
+ GST_FLAG_SET (ttadec, GST_ELEMENT_EVENT_AWARE);
+}
+
+void
+rice_init (adapt * rice, unsigned long k0, unsigned long k1)
+{
+ rice->k0 = k0;
+ rice->k1 = k1;
+ rice->sum0 = shift_16[k0];
+ rice->sum1 = shift_16[k1];
+}
+
+void
+decoder_init (decoder * tta, long nch, long byte_size)
+{
+ long shift = flt_set[byte_size - 1];
+ long i;
+
+ for (i = 0; i < nch; i++) {
+ filter_init (&tta[i].fst, shift);
+ rice_init (&tta[i].rice, 10, 10);
+ tta[i].last = 0;
+ }
+}
+
+void
+get_binary (tta_buffer * tta_buf, guchar * buffer, unsigned long buffersize,
+ unsigned long *value, unsigned long bits)
+{
+ while (tta_buf->bit_count < bits) {
+ if (tta_buf->bitpos == tta_buf->buffer_end) {
+ int max =
+ TTA_BUFFER_SIZE <=
+ buffersize - tta_buf->offset ? TTA_BUFFER_SIZE : buffersize -
+ tta_buf->offset;
+ memcpy (tta_buf->buffer, buffer + tta_buf->offset, max);
+ tta_buf->offset += max;
+ tta_buf->bitpos = tta_buf->buffer;
+ }
+
+ tta_buf->bit_cache |= *tta_buf->bitpos << tta_buf->bit_count;
+ tta_buf->bit_count += 8;
+ tta_buf->bitpos++;
+ }
+
+ *value = tta_buf->bit_cache & bit_mask[bits];
+ tta_buf->bit_cache >>= bits;
+ tta_buf->bit_count -= bits;
+ tta_buf->bit_cache &= bit_mask[tta_buf->bit_count];
+}
+
+void
+get_unary (tta_buffer * tta_buf, guchar * buffer, unsigned long buffersize,
+ unsigned long *value)
+{
+ *value = 0;
+
+ while (!(tta_buf->bit_cache ^ bit_mask[tta_buf->bit_count])) {
+ if (tta_buf->bitpos == tta_buf->buffer_end) {
+ int max =
+ TTA_BUFFER_SIZE <=
+ buffersize - tta_buf->offset ? TTA_BUFFER_SIZE : buffersize -
+ tta_buf->offset;
+ memcpy (tta_buf->buffer, buffer + tta_buf->offset, max);
+ tta_buf->offset += max;
+ tta_buf->bitpos = tta_buf->buffer;
+ }
+
+ *value += tta_buf->bit_count;
+ tta_buf->bit_cache = *tta_buf->bitpos++;
+ tta_buf->bit_count = 8;
+ }
+
+ while (tta_buf->bit_cache & 1) {
+ (*value)++;
+ tta_buf->bit_cache >>= 1;
+ tta_buf->bit_count--;
+ }
+
+ tta_buf->bit_cache >>= 1;
+ tta_buf->bit_count--;
+}
+
+static void
+gst_tta_dec_chain (GstPad * pad, GstData * in)
+{
+ GstTtaDec *ttadec;
+ GstBuffer *outbuf, *buf = GST_BUFFER (in);
+ guchar *data, *p;
+ decoder *dec;
+ unsigned long outsize;
+ unsigned long size;
+ guint32 frame_samples;
+ long res;
+ long *prev;
+
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ ttadec = GST_TTA_DEC (GST_OBJECT_PARENT (pad));
+ g_return_if_fail (GST_IS_TTA_DEC (ttadec));
+
+ if (GST_IS_EVENT (buf)) {
+ gst_pad_event_default (pad, GST_EVENT (buf));
+ return;
+ }
+ data = GST_BUFFER_DATA (buf);
+ size = GST_BUFFER_SIZE (buf);
+
+ ttadec->tta_buf.bit_count = 0;
+ ttadec->tta_buf.bit_cache = 0;
+ ttadec->tta_buf.bitpos = ttadec->tta_buf.buffer_end;
+ ttadec->tta_buf.offset = 0;
+ decoder_init (ttadec->tta, ttadec->channels, ttadec->bytes);
+
+ if (GST_BUFFER_DURATION_IS_VALID (buf)) {
+ frame_samples =
+ ceil ((gdouble) (GST_BUFFER_DURATION (buf) * ttadec->samplerate) /
+ (gdouble) GST_SECOND);
+ } else {
+ frame_samples = ttadec->samplerate * FRAME_TIME;
+ }
+ outsize = ttadec->channels * frame_samples * ttadec->bytes;
+
+ dec = ttadec->tta;
+ p = ttadec->decdata;
+ prev = ttadec->cache;
+ for (res = 0;
+ p < ttadec->decdata + frame_samples * ttadec->channels * ttadec->bytes;) {
+ unsigned long unary, binary, depth, k;
+ long value, temp_value;
+ fltst *fst = &dec->fst;
+ adapt *rice = &dec->rice;
+ long *last = &dec->last;
+
+ // decode Rice unsigned
+ get_unary (&ttadec->tta_buf, data, size, &unary);
+
+ switch (unary) {
+ case 0:
+ depth = 0;
+ k = rice->k0;
+ break;
+ default:
+ depth = 1;
+ k = rice->k1;
+ unary--;
+ }
+
+ if (k) {
+ get_binary (&ttadec->tta_buf, data, size, &binary, k);
+ value = (unary << k) + binary;
+ } else
+ value = unary;
+
+ switch (depth) {
+ case 1:
+ rice->sum1 += value - (rice->sum1 >> 4);
+ if (rice->k1 > 0 && rice->sum1 < shift_16[rice->k1])
+ rice->k1--;
+ else if (rice->sum1 > shift_16[rice->k1 + 1])
+ rice->k1++;
+ value += bit_shift[rice->k0];
+ default:
+ rice->sum0 += value - (rice->sum0 >> 4);
+ if (rice->k0 > 0 && rice->sum0 < shift_16[rice->k0])
+ rice->k0--;
+ else if (rice->sum0 > shift_16[rice->k0 + 1])
+ rice->k0++;
+ }
+
+ /* this only uses a temporary variable to silence a gcc warning */
+ temp_value = DEC (value);
+ value = temp_value;
+
+ // decompress stage 1: adaptive hybrid filter
+ hybrid_filter (fst, &value);
+
+ // decompress stage 2: fixed order 1 prediction
+ switch (ttadec->bytes) {
+ case 1:
+ value += PREDICTOR1 (*last, 4);
+ break; // bps 8
+ case 2:
+ value += PREDICTOR1 (*last, 5);
+ break; // bps 16
+ case 3:
+ value += PREDICTOR1 (*last, 5);
+ break; // bps 24
+ case 4:
+ value += *last;
+ break; // bps 32
+ }
+ *last = value;
+
+ if (dec < ttadec->tta + ttadec->channels - 1) {
+ *prev++ = value;
+ dec++;
+ } else {
+ *prev = value;
+ if (ttadec->channels > 1) {
+ long *r = prev - 1;
+
+ for (*prev += *r / 2; r >= ttadec->cache; r--)
+ *r = *(r + 1) - *r;
+ for (r = ttadec->cache; r < prev; r++)
+ WRITE_BUFFER (r, ttadec->bytes, p);
+ }
+ WRITE_BUFFER (prev, ttadec->bytes, p);
+ prev = ttadec->cache;
+ res++;
+ dec = ttadec->tta;
+ }
+ }
+
+ outbuf = gst_buffer_new_and_alloc (outsize);
+ memcpy (GST_BUFFER_DATA (outbuf), ttadec->decdata, outsize);
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
+ GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
+ gst_pad_push (ttadec->srcpad, GST_DATA (outbuf));
+}
+
+gboolean
+gst_tta_dec_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "ttadec",
+ GST_RANK_PRIMARY, GST_TYPE_TTA_DEC);
+}
diff --git a/gst/tta/gstttadec.h b/gst/tta/gstttadec.h
new file mode 100644
index 00000000..3bdfdcf1
--- /dev/null
+++ b/gst/tta/gstttadec.h
@@ -0,0 +1,84 @@
+/* GStreamer TTA plugin
+ * (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * gstttadec.h: raw TTA bitstream decoder
+ *
+ * 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_TTA_DEC_H__
+#define __GST_TTA_DEC_H__
+
+#include <gst/gst.h>
+
+#include "ttadec.h"
+
+G_BEGIN_DECLS
+
+/* #define's don't like whitespacey bits */
+#define GST_TYPE_TTA_DEC \
+ (gst_tta_dec_get_type())
+#define GST_TTA_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TTA_DEC,GstTtaDec))
+#define GST_TTA_DEC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TTA_DEC,GstTtaDec))
+#define GST_IS_TTA_DEC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TTA_DEC))
+#define GST_IS_TTA_DEC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TTA_DEC))
+
+typedef struct _GstTtaDec GstTtaDec;
+typedef struct _GstTtaDecClass GstTtaDecClass;
+
+typedef struct _tta_buffer
+{
+ guchar *buffer;
+ guchar *buffer_end;
+ gulong bit_count;
+ gulong bit_cache;
+ guchar *bitpos;
+ gulong offset;
+} tta_buffer;
+
+struct _GstTtaDec
+{
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ guint32 samplerate;
+ guint channels;
+ guint bytes;
+ long frame_length;
+
+ decoder *tta;
+ guchar *decdata;
+ tta_buffer tta_buf;
+ long *cache;
+};
+
+struct _GstTtaDecClass
+{
+ GstElementClass parent;
+};
+
+GType gst_tta_dec_get_type (void);
+
+gboolean gst_tta_dec_plugin_init (GstPlugin *plugin);
+
+G_END_DECLS
+
+#endif /* __GST_TTA_DEC_H__ */
diff --git a/gst/tta/gstttaparse.c b/gst/tta/gstttaparse.c
new file mode 100644
index 00000000..3c480d9c
--- /dev/null
+++ b/gst/tta/gstttaparse.c
@@ -0,0 +1,418 @@
+/* GStreamer TTA plugin
+ * (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * gstttaparse.c: TTA file 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.
+ */
+
+#include <gst/gst.h>
+
+#include <math.h>
+
+#include "gstttaparse.h"
+#include "ttadec.h"
+#include "crc32.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_tta_parse_debug);
+#define GST_CAT_DEFAULT gst_tta_parse_debug
+
+/* Filter signals and args */
+enum
+{
+ LAST_SIGNAL
+};
+
+enum
+{
+ ARG_0
+};
+
+static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-ttafile")
+ );
+
+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-tta, "
+ "width = (int) { 8, 16, 24 }, "
+ "channels = (int) { 1, 2 }, " "rate = (int) [ 8000, 96000 ]")
+ );
+
+static void gst_tta_parse_class_init (GstTtaParseClass * klass);
+static void gst_tta_parse_base_init (GstTtaParseClass * klass);
+static void gst_tta_parse_init (GstTtaParse * ttaparse);
+
+static void gst_tta_parse_chain (GstPad * pad, GstData * in);
+
+static GstElementClass *parent = NULL;
+
+GType
+gst_tta_parse_get_type (void)
+{
+ static GType plugin_type = 0;
+
+ if (!plugin_type) {
+ static const GTypeInfo plugin_info = {
+ sizeof (GstTtaParseClass),
+ (GBaseInitFunc) gst_tta_parse_base_init,
+ NULL,
+ (GClassInitFunc) gst_tta_parse_class_init,
+ NULL,
+ NULL,
+ sizeof (GstTtaParse),
+ 0,
+ (GInstanceInitFunc) gst_tta_parse_init,
+ };
+ plugin_type = g_type_register_static (GST_TYPE_ELEMENT,
+ "GstTtaParse", &plugin_info, 0);
+ }
+ return plugin_type;
+}
+
+static void
+gst_tta_parse_base_init (GstTtaParseClass * klass)
+{
+ static GstElementDetails plugin_details = {
+ "TTA file parser",
+ "Codec/Demuxer/Audio",
+ "Parses TTA files",
+ "Arwed v. Merkatz <v.merkatz@gmx.net>"
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ 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, &plugin_details);
+}
+
+static void
+gst_tta_parse_dispose (GObject * object)
+{
+ GstTtaParse *ttaparse = GST_TTA_PARSE (object);
+
+ g_free (ttaparse->index);
+
+ G_OBJECT_CLASS (parent)->dispose (object);
+}
+
+static void
+gst_tta_parse_class_init (GstTtaParseClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent = g_type_class_ref (GST_TYPE_ELEMENT);
+
+ gobject_class->dispose = gst_tta_parse_dispose;
+}
+
+static gboolean
+gst_tta_src_query (GstPad * pad, GstQueryType type,
+ GstFormat * format, gint64 * value)
+{
+ GstTtaParse *ttaparse = GST_TTA_PARSE (gst_pad_get_parent (pad));
+
+ if (type == GST_QUERY_TOTAL) {
+ if (*format == GST_FORMAT_TIME) {
+ if ((ttaparse->data_length == 0) || (ttaparse->samplerate == 0)) {
+ *value = 0;
+ return FALSE;
+ }
+ *value =
+ ((gdouble) ttaparse->data_length / (gdouble) ttaparse->samplerate) *
+ GST_SECOND;
+ GST_DEBUG_OBJECT (ttaparse, "got queried for time, returned %lli",
+ *value);
+ return TRUE;
+ }
+ } else {
+ return gst_pad_query_default (pad, type, format, value);
+ }
+ return FALSE;
+}
+
+static gboolean
+gst_tta_src_event (GstPad * pad, GstEvent * event)
+{
+ GstTtaParse *ttaparse = GST_TTA_PARSE (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ {
+ if (GST_EVENT_SEEK_FORMAT (event) == GST_FORMAT_TIME) {
+ GST_DEBUG_OBJECT (ttaparse, "got seek event");
+ GstEvent *seek_event;
+ guint64 time = GST_EVENT_SEEK_OFFSET (event);
+ guint64 seek_frame = time / (FRAME_TIME * 1000000000);
+ guint64 seekpos = ttaparse->index[seek_frame].pos;
+
+ GST_DEBUG_OBJECT (ttaparse, "seeking to %u", (guint) seekpos);
+ seek_event =
+ gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET |
+ GST_SEEK_FLAG_ACCURATE, seekpos);
+ gst_event_unref (event);
+ if (gst_pad_send_event (GST_PAD_PEER (ttaparse->sinkpad), seek_event)) {
+ gst_pad_event_default (ttaparse->srcpad,
+ gst_event_new (GST_EVENT_FLUSH));
+ return TRUE;
+ } else {
+ GST_LOG_OBJECT (ttaparse, "seek failed");
+ return FALSE;
+ }
+ } else {
+ return gst_pad_send_event (pad, event);
+ }
+ break;
+ }
+ default:
+ return gst_pad_send_event (pad, event);
+ break;
+ }
+}
+
+static void
+gst_tta_parse_init (GstTtaParse * ttaparse)
+{
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (ttaparse);
+
+ ttaparse->sinkpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+ "sink"), "sink");
+
+ ttaparse->srcpad =
+ gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
+ "src"), "src");
+ gst_pad_use_explicit_caps (ttaparse->srcpad);
+ gst_pad_set_query_function (ttaparse->srcpad, gst_tta_src_query);
+ gst_pad_set_event_function (ttaparse->srcpad, gst_tta_src_event);
+
+ gst_element_add_pad (GST_ELEMENT (ttaparse), ttaparse->sinkpad);
+ gst_element_add_pad (GST_ELEMENT (ttaparse), ttaparse->srcpad);
+ gst_pad_set_chain_function (ttaparse->sinkpad, gst_tta_parse_chain);
+
+ ttaparse->silent = FALSE;
+ ttaparse->header_parsed = FALSE;
+ ttaparse->partialbuf = NULL;
+ ttaparse->seek_ok = FALSE;
+ ttaparse->current_frame = 0;
+ ttaparse->data_length = 0;
+ ttaparse->samplerate = 0;
+
+ GST_FLAG_SET (ttaparse, GST_ELEMENT_EVENT_AWARE);
+}
+
+static void
+gst_tta_handle_event (GstPad * pad, GstBuffer * buffer)
+{
+ GstEvent *event = GST_EVENT (buffer);
+ GstTtaParse *ttaparse = GST_TTA_PARSE (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (ttaparse, "got some event");
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_DISCONTINUOUS:
+ {
+ GstEvent *discont;
+ guint64 offset = GST_EVENT_DISCONT_OFFSET (event, 0).value;
+ int i;
+
+ GST_DEBUG_OBJECT (ttaparse, "discont with offset: %u", offset);
+ for (i = 0; i < ttaparse->num_frames; i++) {
+ if (offset == ttaparse->index[i].pos) {
+ GST_DEBUG_OBJECT (ttaparse, "setting current frame to %i", i);
+ discont = gst_event_new_discontinuous (FALSE,
+ GST_FORMAT_TIME, ttaparse->index[i].time, NULL);
+ gst_event_unref (event);
+ gst_buffer_unref (ttaparse->partialbuf);
+ ttaparse->partialbuf = NULL;
+ ttaparse->current_frame = i;
+ gst_pad_event_default (pad, gst_event_new (GST_EVENT_FLUSH));
+ gst_pad_event_default (pad, discont);
+ GST_DEBUG_OBJECT (ttaparse, "sent discont event");
+ return;
+ }
+ }
+ break;
+ }
+ default:
+ gst_pad_event_default (pad, event);
+ break;
+ }
+}
+
+static void
+gst_tta_parse_chain (GstPad * pad, GstData * in)
+{
+ GstTtaParse *ttaparse;
+ GstBuffer *outbuf, *buf = GST_BUFFER (in);
+ guchar *data;
+ gint i;
+ guint64 size, offset = 0;
+ GstCaps *caps;
+
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ ttaparse = GST_TTA_PARSE (GST_OBJECT_PARENT (pad));
+ g_return_if_fail (GST_IS_TTA_PARSE (ttaparse));
+
+ if (GST_IS_EVENT (buf)) {
+ gst_tta_handle_event (pad, buf);
+ return;
+ }
+
+ if (ttaparse->partialbuf) {
+ GstBuffer *newbuf;
+
+ newbuf = gst_buffer_merge (ttaparse->partialbuf, buf);
+ gst_buffer_unref (buf);
+ gst_buffer_unref (ttaparse->partialbuf);
+ ttaparse->partialbuf = newbuf;
+ } else {
+ ttaparse->partialbuf = buf;
+ }
+
+ size = GST_BUFFER_SIZE (ttaparse->partialbuf);
+ data = GST_BUFFER_DATA (ttaparse->partialbuf);
+ if (!ttaparse->header_parsed) {
+ if ((*data == 'T') && (*(data + 1) == 'T') && (*(data + 2) == 'A')) {
+ double frame_length;
+ int num_frames;
+ guint32 datasize = 0;
+ guint32 crc;
+
+ offset = offset + 4;
+ offset = offset + 2;
+ ttaparse->channels = GST_READ_UINT16_LE (data + offset);
+ offset = offset + 2;
+ ttaparse->bits = GST_READ_UINT16_LE (data + offset);
+ offset += 2;
+ ttaparse->samplerate = GST_READ_UINT32_LE (data + offset);
+ frame_length = FRAME_TIME * ttaparse->samplerate;
+ offset += 4;
+ ttaparse->data_length = GST_READ_UINT32_LE (data + offset);
+ offset += 4;
+ num_frames = (ttaparse->data_length / frame_length) + 1;
+ crc = crc32 (data, 18);
+ if (crc != GST_READ_UINT32_LE (data + offset)) {
+ GST_WARNING_OBJECT (ttaparse, "Header CRC wrong!");
+ }
+ offset += 4;
+ GST_INFO_OBJECT (ttaparse,
+ "channels: %u, bits: %u, samplerate: %u, data_length: %u, num_frames: %u",
+ ttaparse->channels, ttaparse->bits, ttaparse->samplerate,
+ ttaparse->data_length, num_frames);
+ ttaparse->index =
+ (GstTtaIndex *) g_malloc (num_frames * sizeof (GstTtaIndex));
+ ttaparse->num_frames = num_frames;
+ for (i = 0; i < num_frames; i++) {
+ ttaparse->index[i].size = GST_READ_UINT32_LE (data + offset);
+ ttaparse->index[i].pos = GST_BUFFER_OFFSET (ttaparse->partialbuf) + (num_frames) * 4 + 4 + datasize + 22; // 22 == header size, +4 for the TTA1
+ ttaparse->index[i].time = i * FRAME_TIME * 1000000000;
+ offset += 4;
+ datasize += ttaparse->index[i].size;
+ }
+ GST_DEBUG_OBJECT (ttaparse, "Datasize: %u", datasize);
+ crc = crc32 (data + 22, num_frames * 4);
+ if (crc != GST_READ_UINT32_LE (data + offset)) {
+ GST_WARNING_OBJECT (ttaparse, "Seek table CRC wrong!");
+ } else {
+ ttaparse->seek_ok = TRUE;
+ /*
+ g_print("allowing seeking!\n");
+ g_print("dumping index:\n");
+ for (i = 0; i < ttaparse->num_frames; i++) {
+ g_print("frame %u: offset = %llu, time=%llu, size=%u\n",
+ i,
+ ttaparse->index[i].pos,
+ ttaparse->index[i].time,
+ ttaparse->index[i].size);
+ }
+ */
+ }
+ offset += 4;
+ ttaparse->header_parsed = TRUE;
+ caps = gst_caps_new_simple ("audio/x-tta",
+ "width", G_TYPE_INT, ttaparse->bits,
+ "channels", G_TYPE_INT, ttaparse->channels,
+ "rate", G_TYPE_INT, ttaparse->samplerate, NULL);
+ gst_pad_set_explicit_caps (ttaparse->srcpad, caps);
+ }
+ }
+
+ i = ttaparse->current_frame;
+ while (size - offset >= ttaparse->index[i].size) {
+ guint32 crc;
+
+ crc = crc32 (data + offset, ttaparse->index[i].size - 4);
+ if (crc != GST_READ_UINT32_LE (data + offset + ttaparse->index[i].size - 4)) {
+ GST_WARNING_OBJECT (ttaparse, "Frame %u corrupted :(", i);
+ GST_WARNING_OBJECT (ttaparse, "calculated crc: %u, got crc: %u", crc,
+ GST_READ_UINT32_LE (data + offset + ttaparse->index[i].size - 4));
+ }
+ outbuf =
+ gst_buffer_create_sub (ttaparse->partialbuf, offset,
+ ttaparse->index[i].size - 4);
+ GST_BUFFER_TIMESTAMP (outbuf) = ttaparse->index[i].time;
+ if (ttaparse->current_frame + 1 == ttaparse->num_frames) {
+ guint32 samples =
+ ttaparse->data_length % (gint64) (ttaparse->samplerate * FRAME_TIME);
+ gdouble frametime = (gdouble) samples / (gdouble) ttaparse->samplerate;
+
+ GST_BUFFER_DURATION (outbuf) = (guint64) (frametime * GST_SECOND);
+ } else {
+ GST_BUFFER_DURATION (outbuf) = FRAME_TIME * 1000000000;
+ }
+ gst_pad_push (ttaparse->srcpad, GST_DATA (outbuf));
+ offset += ttaparse->index[i].size;
+ ttaparse->current_frame++;
+ i = ttaparse->current_frame;
+ }
+
+ if (size - offset > 0) {
+ glong remainder = size - offset;
+
+ outbuf = gst_buffer_create_sub (ttaparse->partialbuf, offset, remainder);
+ gst_buffer_unref (ttaparse->partialbuf);
+ ttaparse->partialbuf = outbuf;
+ } else {
+ gst_buffer_unref (ttaparse->partialbuf);
+ ttaparse->partialbuf = NULL;
+ }
+
+}
+
+gboolean
+gst_tta_parse_plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "ttaparse",
+ GST_RANK_PRIMARY, GST_TYPE_TTA_PARSE)) {
+ return FALSE;
+ }
+
+ GST_DEBUG_CATEGORY_INIT (gst_tta_parse_debug, "ttaparse", 0,
+ "tta file parser");
+
+ return TRUE;
+}
diff --git a/gst/tta/gstttaparse.h b/gst/tta/gstttaparse.h
new file mode 100644
index 00000000..10ea31ab
--- /dev/null
+++ b/gst/tta/gstttaparse.h
@@ -0,0 +1,82 @@
+/* GStreamer TTA plugin
+ * (c) 2004 Arwed v. Merkatz <v.merkatz@gmx.net>
+ *
+ * gstttaparse.h: TTA file 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.
+ */
+
+#ifndef __GST_TTA_PARSE_H__
+#define __GST_TTA_PARSE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+/* #define's don't like whitespacey bits */
+#define GST_TYPE_TTA_PARSE \
+ (gst_tta_parse_get_type())
+#define GST_TTA_PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TTA_PARSE,GstTtaParse))
+#define GST_TTA_PARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TTA_PARSE,GstTtaParse))
+#define GST_IS_TTA_PARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TTA_PARSE))
+#define GST_IS_TTA_PARSE_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TTA_PARSE))
+
+typedef struct _GstTtaParse GstTtaParse;
+typedef struct _GstTtaParseClass GstTtaParseClass;
+
+typedef struct _GstTtaIndex {
+ guint32 frameno;
+ guint32 size; /* size of frame frameno */
+ guint64 pos; /* start of the frame */
+ guint64 time; /* in nanoseconds */
+} GstTtaIndex;
+
+struct _GstTtaParse
+{
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ gboolean silent;
+ gboolean header_parsed;
+ GstBuffer *partialbuf;
+ guint32 samplerate;
+ guint16 channels;
+ guint16 bits;
+ guint32 data_length;
+ GstTtaIndex *index;
+ guint num_frames;
+ gboolean seek_ok;
+
+ guint32 current_frame;
+};
+
+struct _GstTtaParseClass
+{
+ GstElementClass parent;
+};
+
+GType gst_tta_parse_get_type (void);
+
+gboolean gst_tta_parse_plugin_init (GstPlugin *plugin);
+
+G_END_DECLS
+
+#endif /* __GST_TTA_PARSE_H__ */
diff --git a/gst/tta/ttadec.h b/gst/tta/ttadec.h
new file mode 100644
index 00000000..7a4a8a25
--- /dev/null
+++ b/gst/tta/ttadec.h
@@ -0,0 +1,141 @@
+/*
+ * ttadec.h
+ *
+ * Description: TTAv1 decoder definitions and prototypes
+ * Developed by: Alexander Djourik <sasha@iszf.irk.ru>
+ * Pavel Zhilin <pzh@iszf.irk.ru>
+ *
+ * Copyright (c) 1999-2004 Alexander Djourik. All rights reserved.
+ *
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ *
+ * Please see the file COPYING in this directory for full copyright
+ * information.
+ */
+
+#ifndef TTADEC_H_
+#define TTADEC_H_
+
+#ifdef _WIN32
+#pragma pack(1)
+#define __ATTRIBUTE_PACKED__
+#else
+#define __ATTRIBUTE_PACKED__ __attribute__((packed))
+#endif
+
+#define TTA1_SIGN 0x31415454
+#define FRAME_TIME 1.04489795918367346939
+#define MAX_ORDER 8
+
+#ifndef WAVE_FORMAT_PCM
+#define WAVE_FORMAT_PCM 1
+#endif
+
+#ifdef _WIN32
+ typedef unsigned __int64 uint64;
+#else
+ typedef unsigned long long uint64;
+#endif
+
+/**
+ * moved to gstttadec.c to silence gcc warnings
+ */
+/*
+static const unsigned long bit_mask[] = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+ 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+ 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+ 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+ 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
+ 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+ 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
+ 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff
+};
+
+static const unsigned long bit_shift[] = {
+ 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x80000000, 0x80000000, 0x80000000, 0x80000000,
+ 0x80000000, 0x80000000, 0x80000000, 0x80000000
+};
+
+static const unsigned long *shift_16 = bit_shift + 4;
+*/
+
+typedef unsigned char byte;
+
+#ifdef _BIG_ENDIAN
+#define ENDSWAP_INT16(x) (((((x)>>8)&0xFF)|(((x)&0xFF)<<8)))
+#define ENDSWAP_INT32(x) (((((x)>>24)&0xFF)|(((x)>>8)&0xFF00)|(((x)&0xFF00)<<8)|(((x)&0xFF)<<24)))
+#define WRITE_BUFFER(x, bsize, out) { \
+ if (bsize > 2) *out++ = (byte)(*x >> 16); \
+ if (bsize > 1) *out++ = (byte)(*x >> 8); \
+ *out++ = (byte) *x; }
+#else
+#define ENDSWAP_INT16(x) (x)
+#define ENDSWAP_INT32(x) (x)
+#define WRITE_BUFFER(x, bsize, out) { \
+ *out++ = (byte) *x; \
+ if (bsize > 1) *out++ = (byte)(*x >> 8); \
+ if (bsize > 2) *out++ = (byte)(*x >> 16); }
+#endif
+
+#define PREDICTOR1(x, k) ((long)((((uint64)x << k) - x) >> k))
+#define DEC(x) (((x)&1)?(++(x)>>1):(-(x)>>1))
+
+typedef struct {
+ unsigned long TTAid;
+ unsigned short AudioFormat;
+ unsigned short NumChannels;
+ unsigned short BitsPerSample;
+ unsigned long SampleRate;
+ unsigned long DataLength;
+ unsigned long CRC32;
+} __ATTRIBUTE_PACKED__ tta_hdr;
+
+typedef struct {
+ unsigned long k0;
+ unsigned long k1;
+ unsigned long sum0;
+ unsigned long sum1;
+} adapt;
+
+typedef struct {
+ long shift;
+ long round;
+ long error;
+ long mutex;
+ long qm[MAX_ORDER+1];
+ long dx[MAX_ORDER+1];
+ long dl[MAX_ORDER+1];
+} fltst;
+
+typedef struct {
+ fltst fst;
+ adapt rice;
+ long last;
+} decoder;
+
+#endif /* TTADEC_H_ */