diff options
author | Arwed v. Merkatz <v.merkatz@gmx.net> | 2004-11-26 23:10:28 +0000 |
---|---|---|
committer | Arwed v. Merkatz <v.merkatz@gmx.net> | 2004-11-26 23:10:28 +0000 |
commit | aeb09d35abf17934407c8e1c826de3d8fab7193d (patch) | |
tree | d0fe82628748857181a06244014a924e4655682f /gst | |
parent | 90bf594c667017695e13238ec9b5970501b34dd9 (diff) | |
download | gst-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.am | 12 | ||||
-rw-r--r-- | gst/tta/crc32.h | 114 | ||||
-rw-r--r-- | gst/tta/filters.h | 110 | ||||
-rw-r--r-- | gst/tta/gsttta.c | 40 | ||||
-rw-r--r-- | gst/tta/gstttadec.c | 458 | ||||
-rw-r--r-- | gst/tta/gstttadec.h | 84 | ||||
-rw-r--r-- | gst/tta/gstttaparse.c | 418 | ||||
-rw-r--r-- | gst/tta/gstttaparse.h | 82 | ||||
-rw-r--r-- | gst/tta/ttadec.h | 141 |
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_ */ |