From 56675a8221a9eb8f9cee413bbb3745c6cb8eff9d Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Fri, 28 Jan 2005 10:36:12 +0000 Subject: [PATCH] Add support for AMR-NB (mobile phone audio format; #155163, #163286). Original commit message from CVS: * configure.ac: * ext/Makefile.am: * ext/amrnb/Makefile.am: * ext/amrnb/amrnb.c: (plugin_init): * ext/amrnb/amrnbdec.c: (gst_amrnbdec_get_type), (gst_amrnbdec_base_init), (gst_amrnbdec_class_init), (gst_amrnbdec_init), (gst_amrnbdec_link), (gst_amrnbdec_chain), (gst_amrnbdec_state_change): * ext/amrnb/amrnbdec.h: * ext/amrnb/amrnbparse.c: (gst_amrnbparse_get_type), (gst_amrnbparse_base_init), (gst_amrnbparse_class_init), (gst_amrnbparse_init), (gst_amrnbparse_formats), (gst_amrnbparse_querytypes), (gst_amrnbparse_query), (gst_amrnbparse_handle_event), (gst_amrnbparse_reserve), (gst_amrnbparse_loop), (gst_amrnbparse_state_change): * ext/amrnb/amrnbparse.h: Add support for AMR-NB (mobile phone audio format; #155163, #163286). * gst/typefind/gsttypefindfunctions.c: (plugin_init): Add AMR-NB/-WB raw formats. * ext/alsa/gstalsa.c: (gst_alsa_link): Keep valid time when changing format. * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header), (qtdemux_parse_trak): Add some more format-specific options (#140141, #143555, #155163). --- ChangeLog | 27 ++++ configure.ac | 11 ++ ext/Makefile.am | 9 ++ ext/amrnb/Makefile.am | 14 ++ ext/amrnb/amrnb.c | 44 ++++++ ext/amrnb/amrnbdec.c | 222 ++++++++++++++++++++++++++++ ext/amrnb/amrnbdec.h | 64 ++++++++ ext/amrnb/amrnbparse.c | 321 +++++++++++++++++++++++++++++++++++++++++ ext/amrnb/amrnbparse.h | 59 ++++++++ 9 files changed, 771 insertions(+) create mode 100644 ext/amrnb/Makefile.am create mode 100644 ext/amrnb/amrnb.c create mode 100644 ext/amrnb/amrnbdec.c create mode 100644 ext/amrnb/amrnbdec.h create mode 100644 ext/amrnb/amrnbparse.c create mode 100644 ext/amrnb/amrnbparse.h diff --git a/ChangeLog b/ChangeLog index c88908d03b..7fbd78ab80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2005-01-28 Ronald S. Bultje + + * configure.ac: + * ext/Makefile.am: + * ext/amrnb/Makefile.am: + * ext/amrnb/amrnb.c: (plugin_init): + * ext/amrnb/amrnbdec.c: (gst_amrnbdec_get_type), + (gst_amrnbdec_base_init), (gst_amrnbdec_class_init), + (gst_amrnbdec_init), (gst_amrnbdec_link), (gst_amrnbdec_chain), + (gst_amrnbdec_state_change): + * ext/amrnb/amrnbdec.h: + * ext/amrnb/amrnbparse.c: (gst_amrnbparse_get_type), + (gst_amrnbparse_base_init), (gst_amrnbparse_class_init), + (gst_amrnbparse_init), (gst_amrnbparse_formats), + (gst_amrnbparse_querytypes), (gst_amrnbparse_query), + (gst_amrnbparse_handle_event), (gst_amrnbparse_reserve), + (gst_amrnbparse_loop), (gst_amrnbparse_state_change): + * ext/amrnb/amrnbparse.h: + Add support for AMR-NB (mobile phone audio format; #155163, #163286). + * gst/typefind/gsttypefindfunctions.c: (plugin_init): + Add AMR-NB/-WB raw formats. + * ext/alsa/gstalsa.c: (gst_alsa_link): + Keep valid time when changing format. + * gst/qtdemux/qtdemux.c: (gst_qtdemux_loop_header), + (qtdemux_parse_trak): + Add some more format-specific options (#140141, #143555, #155163). + 2005-01-28 Ronald S. Bultje * gst/matroska/matroska-demux.c: diff --git a/configure.ac b/configure.ac index 4fa04b0ad1..c6e164701f 100644 --- a/configure.ac +++ b/configure.ac @@ -778,6 +778,16 @@ GST_CHECK_FEATURE(ALSA, [alsa plug-ins], gstalsa, [ ]) ]) +dnl *** AMR-NB *** +translit(dnm, m, l) AM_CONDITIONAL(USE_AMRNB, true) +GST_CHECK_FEATURE(AMRNB, [AMR-NB], amrnbdec amrnbenc, [ + GST_CHECK_LIBHEADER(AMRNB, amrnb, + Decoder_Interface_init, -lm, + amrnb/interf_dec.h, + AMRNB_LIBS="-lamrnb -lm" + AC_SUBST(AMRNB_LIBS)) +]) + dnl *** arts *** dnl if mcopidl can't be found there's no use in compiling it AC_CHECK_PROG(MCOPIDL, mcopidl, yes, no) @@ -2021,6 +2031,7 @@ ext/Makefile ext/a52dec/Makefile ext/aalib/Makefile ext/alsa/Makefile +ext/amrnb/Makefile ext/arts/Makefile ext/artsd/Makefile ext/audiofile/Makefile diff --git a/ext/Makefile.am b/ext/Makefile.am index 08c61fd16a..a74262f700 100644 --- a/ext/Makefile.am +++ b/ext/Makefile.am @@ -16,6 +16,12 @@ else ALSA_DIR= endif +if USE_AMRNB +AMRNB_DIR=amrnb +else +AMRNB= +endif + if USE_ARTS ARTS_DIR=arts else @@ -398,6 +404,8 @@ SUBDIRS=\ $(A52DEC_DIR) \ $(AALIB_DIR) \ $(ALSA_DIR) \ + $(AMRNB_DIR) \ + $(AMRWB_DIR) \ $(ARTS_DIR) \ $(ARTSC_DIR) \ $(AUDIOFILE_DIR) \ @@ -464,6 +472,7 @@ DIST_SUBDIRS=\ a52dec \ aalib \ alsa \ + amrnb \ arts \ artsd \ audiofile \ diff --git a/ext/amrnb/Makefile.am b/ext/amrnb/Makefile.am new file mode 100644 index 0000000000..0f03af4dd9 --- /dev/null +++ b/ext/amrnb/Makefile.am @@ -0,0 +1,14 @@ +plugin_LTLIBRARIES = libgstamrnb.la + +libgstamrnb_la_SOURCES = \ + amrnb.c \ + amrnbdec.c \ + amrnbparse.c + +libgstamrnb_la_CFLAGS = $(GST_CFLAGS) $(AMRNB_CFLAGS) +libgstamrnb_la_LIBADD = $(AMRNB_LIBS) +libgstamrnb_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = \ + amrnbdec.h \ + amrnbparse.h diff --git a/ext/amrnb/amrnb.c b/ext/amrnb/amrnb.c new file mode 100644 index 0000000000..721fb4897d --- /dev/null +++ b/ext/amrnb/amrnb.c @@ -0,0 +1,44 @@ +/* GStreamer Adaptive Multi-Rate Narrow-Band (AMR-NB) plugin + * Copyright (C) 2004 Ronald Bultje + * + * 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 "amrnbdec.h" +#include "amrnbparse.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_library_load ("gstbytestream")) + return FALSE; + + return gst_element_register (plugin, "amrnbdec", + GST_RANK_PRIMARY, GST_TYPE_AMRNBDEC) && + gst_element_register (plugin, "amrnbparse", + GST_RANK_PRIMARY, GST_TYPE_AMRNBPARSE); +} + + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "amrnb", + "Adaptive Multi-Rate Narrow-Band", + plugin_init, VERSION, GST_LICENSE_UNKNOWN, GST_PACKAGE, GST_ORIGIN); diff --git a/ext/amrnb/amrnbdec.c b/ext/amrnb/amrnbdec.c new file mode 100644 index 0000000000..c28364edc9 --- /dev/null +++ b/ext/amrnb/amrnbdec.c @@ -0,0 +1,222 @@ +/* GStreamer Adaptive Multi-Rate Narrow-Band (AMR-NB) plugin + * Copyright (C) 2004 Ronald Bultje + * + * 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 "amrnbdec.h" + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-amr-nb, " + "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]") + ); + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "width = (int) 16, " + "depth = (int) 16, " + "signed = (boolean) TRUE, " + "endianness = (int) BYTE_ORDER, " + "rate = (int) [ 1000, 96000 ]," "channels = (int) [ 1, 2 ]") + ); + +static void gst_amrnbdec_base_init (GstAmrnbDecClass * klass); +static void gst_amrnbdec_class_init (GstAmrnbDecClass * klass); +static void gst_amrnbdec_init (GstAmrnbDec * amrnbdec); + +static void gst_amrnbdec_chain (GstPad * pad, GstData * data); +static GstPadLinkReturn gst_amrnbdec_link (GstPad * pad, const GstCaps * caps); +static GstElementStateReturn gst_amrnbdec_state_change (GstElement * element); + +static GstElementClass *parent_class = NULL; + +GType +gst_amrnbdec_get_type (void) +{ + static GType amrnbdec_type = 0; + + if (!amrnbdec_type) { + static const GTypeInfo amrnbdec_info = { + sizeof (GstAmrnbDecClass), + (GBaseInitFunc) gst_amrnbdec_base_init, + NULL, + (GClassInitFunc) gst_amrnbdec_class_init, + NULL, + NULL, + sizeof (GstAmrnbDec), + 0, + (GInstanceInitFunc) gst_amrnbdec_init, + }; + + amrnbdec_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstAmrnbDec", &amrnbdec_info, 0); + } + + return amrnbdec_type; +} + +static void +gst_amrnbdec_base_init (GstAmrnbDecClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstElementDetails gst_amrnbdec_details = { + "AMR-NB decoder", + "Codec/Decoder/Audio", + "Adaptive Multi-Rate Narrow-Band audio decoder", + "Ronald Bultje " + }; + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + gst_element_class_set_details (element_class, &gst_amrnbdec_details); +} + +static void +gst_amrnbdec_class_init (GstAmrnbDecClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + element_class->change_state = gst_amrnbdec_state_change; +} + +static void +gst_amrnbdec_init (GstAmrnbDec * amrnbdec) +{ + /* create the sink pad */ + amrnbdec->sinkpad = + gst_pad_new_from_template (gst_static_pad_template_get (&sink_template), + "sink"); + gst_pad_set_link_function (amrnbdec->sinkpad, gst_amrnbdec_link); + gst_pad_set_chain_function (amrnbdec->sinkpad, gst_amrnbdec_chain); + gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->sinkpad); + + /* create the src pad */ + amrnbdec->srcpad = + gst_pad_new_from_template (gst_static_pad_template_get (&src_template), + "src"); + gst_pad_use_explicit_caps (amrnbdec->srcpad); + gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->srcpad); + + /* init rest */ + amrnbdec->handle = NULL; + amrnbdec->channels = 0; + amrnbdec->rate = 0; + amrnbdec->ts = 0; +} + +static GstPadLinkReturn +gst_amrnbdec_link (GstPad * pad, const GstCaps * caps) +{ + GstStructure *structure = gst_caps_get_structure (caps, 0); + GstAmrnbDec *amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad)); + GstCaps *copy; + + /* get channel count */ + gst_structure_get_int (structure, "channels", &amrnbdec->channels); + gst_structure_get_int (structure, "rate", &amrnbdec->rate); + + /* create reverse caps */ + copy = gst_caps_new_simple ("audio/x-raw-int", + "channels", G_TYPE_INT, amrnbdec->channels, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "rate", G_TYPE_INT, amrnbdec->rate, "signed", G_TYPE_BOOLEAN, TRUE, NULL); + if (!gst_pad_set_explicit_caps (amrnbdec->srcpad, copy)) + return GST_PAD_LINK_REFUSED; + + return GST_PAD_LINK_OK; +} + +static void +gst_amrnbdec_chain (GstPad * pad, GstData * in_data) +{ + const gint block_size[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, + 0, 0, 0, 0, 0, 0, 0 + }; + GstAmrnbDec *amrnbdec = GST_AMRNBDEC (GST_OBJECT_PARENT (pad)); + GstBuffer *buf = gst_buffer_copy_on_write (in_data), *out; + guint8 *data = GST_BUFFER_DATA (buf); + gint size = GST_BUFFER_SIZE (buf), block, mode; + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) + amrnbdec->ts = GST_BUFFER_TIMESTAMP (buf); + + while (size >= 1) { + /* get size */ + mode = (data[0] >> 3) & 0x0F; + block = block_size[mode] + 1; + if (size < block) + break; + + /* get output */ + out = gst_buffer_new_and_alloc (160 * 2); + GST_BUFFER_DURATION (out) = GST_SECOND * 160 / + (amrnbdec->rate * amrnbdec->channels); + GST_BUFFER_TIMESTAMP (out) = amrnbdec->ts; + amrnbdec->ts += GST_BUFFER_DURATION (out); + + /* decode */ + Decoder_Interface_Decode (amrnbdec->handle, data, + (short *) GST_BUFFER_DATA (out), 0); + data += block; + size -= block; + + /* play */ + gst_pad_push (amrnbdec->srcpad, GST_DATA (out)); + } + + gst_buffer_unref (buf); +} + +static GstElementStateReturn +gst_amrnbdec_state_change (GstElement * element) +{ + GstAmrnbDec *amrnbdec = GST_AMRNBDEC (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + if (!(amrnbdec->handle = Decoder_Interface_init ())) + return GST_STATE_FAILURE; + break; + case GST_STATE_PAUSED_TO_READY: + amrnbdec->ts = 0; + break; + case GST_STATE_READY_TO_NULL: + Decoder_Interface_exit (amrnbdec->handle); + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} diff --git a/ext/amrnb/amrnbdec.h b/ext/amrnb/amrnbdec.h new file mode 100644 index 0000000000..e1437bff2a --- /dev/null +++ b/ext/amrnb/amrnbdec.h @@ -0,0 +1,64 @@ +/* GStreamer Adaptive Multi-Rate Narrow-Band (AMR-NB) plugin + * Copyright (C) 2004 Ronald Bultje + * + * 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_AMRNBDEC_H__ +#define __GST_AMRNBDEC_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_AMRNBDEC \ + (gst_amrnbdec_get_type()) +#define GST_AMRNBDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AMRNBDEC, GstAmrnbDec)) +#define GST_AMRNBDEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AMRNBDEC, GstAmrnbDec)) +#define GST_IS_AMRNBDEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AMRNBDEC)) +#define GST_IS_AMRNBDEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AMRNBDEC)) + +typedef struct _GstAmrnbDec GstAmrnbDec; +typedef struct _GstAmrnbDecClass GstAmrnbDecClass; + +struct _GstAmrnbDec { + GstElement element; + + /* pads */ + GstPad *sinkpad, *srcpad; + guint64 ts; + + /* library handle */ + void *handle; + + /* output settings */ + gint channels, rate; +}; + +struct _GstAmrnbDecClass { + GstElementClass parent_class; +}; + +GType gst_amrnbdec_get_type (void); + +G_END_DECLS + +#endif /* __GST_AMRNBDEC_H__ */ diff --git a/ext/amrnb/amrnbparse.c b/ext/amrnb/amrnbparse.c new file mode 100644 index 0000000000..27d3a8fc72 --- /dev/null +++ b/ext/amrnb/amrnbparse.c @@ -0,0 +1,321 @@ +/* GStreamer Adaptive Multi-Rate Narrow-Band (AMR-NB) plugin + * Copyright (C) 2004 Ronald Bultje + * + * 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 + +#include "amrnbparse.h" + +GST_DEBUG_CATEGORY_STATIC (amrnbparse_debug); +#define GST_CAT_DEFAULT amrnbparse_debug + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-amr-nb, " + "rate = (int) 8000, " "channels = (int) 1") + ); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-amr-nb-sh") + ); + +static void gst_amrnbparse_base_init (GstAmrnbParseClass * klass); +static void gst_amrnbparse_class_init (GstAmrnbParseClass * klass); +static void gst_amrnbparse_init (GstAmrnbParse * amrnbparse); + +static const GstFormat *gst_amrnbparse_formats (GstPad * pad); +static const GstQueryType *gst_amrnbparse_querytypes (GstPad * pad); +static gboolean gst_amrnbparse_query (GstPad * pad, GstQueryType type, + GstFormat * fmt, gint64 * value); +static void gst_amrnbparse_loop (GstElement * element); +static GstElementStateReturn gst_amrnbparse_state_change (GstElement * element); + +static GstElementClass *parent_class = NULL; + +GType +gst_amrnbparse_get_type (void) +{ + static GType amrnbparse_type = 0; + + if (!amrnbparse_type) { + static const GTypeInfo amrnbparse_info = { + sizeof (GstAmrnbParseClass), + (GBaseInitFunc) gst_amrnbparse_base_init, + NULL, + (GClassInitFunc) gst_amrnbparse_class_init, + NULL, + NULL, + sizeof (GstAmrnbParse), + 0, + (GInstanceInitFunc) gst_amrnbparse_init, + }; + + amrnbparse_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstAmrnbParse", &amrnbparse_info, 0); + } + + return amrnbparse_type; +} + +static void +gst_amrnbparse_base_init (GstAmrnbParseClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstElementDetails gst_amrnbparse_details = { + "AMR-NB parser", + "Codec/Parser/Audio", + "Adaptive Multi-Rate Narrow-Band audio parser", + "Ronald Bultje " + }; + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + gst_element_class_set_details (element_class, &gst_amrnbparse_details); +} + +static void +gst_amrnbparse_class_init (GstAmrnbParseClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + element_class->change_state = gst_amrnbparse_state_change; + + GST_DEBUG_CATEGORY_INIT (amrnbparse_debug, + "amrnbparse", 0, "AMR-NB stream parsing"); +} + +static void +gst_amrnbparse_init (GstAmrnbParse * amrnbparse) +{ + GST_FLAG_SET (amrnbparse, GST_ELEMENT_EVENT_AWARE); + + /* create the sink pad */ + amrnbparse->sinkpad = + gst_pad_new_from_template (gst_static_pad_template_get (&sink_template), + "sink"); + gst_element_add_pad (GST_ELEMENT (amrnbparse), amrnbparse->sinkpad); + + /* create the src pad */ + amrnbparse->srcpad = + gst_pad_new_from_template (gst_static_pad_template_get (&src_template), + "src"); + gst_pad_set_query_function (amrnbparse->srcpad, + GST_DEBUG_FUNCPTR (gst_amrnbparse_query)); + gst_pad_set_query_type_function (amrnbparse->srcpad, + GST_DEBUG_FUNCPTR (gst_amrnbparse_querytypes)); + gst_pad_set_formats_function (amrnbparse->srcpad, + GST_DEBUG_FUNCPTR (gst_amrnbparse_formats)); + gst_element_add_pad (GST_ELEMENT (amrnbparse), amrnbparse->srcpad); + + gst_element_set_loop_function (GST_ELEMENT (amrnbparse), gst_amrnbparse_loop); + + /* init rest */ + amrnbparse->ts = 0; +} + +/* + * Position querying. + */ + +static const GstFormat * +gst_amrnbparse_formats (GstPad * pad) +{ + static const GstFormat list[] = { + GST_FORMAT_TIME, + 0 + }; + + return list; +} + +static const GstQueryType * +gst_amrnbparse_querytypes (GstPad * pad) +{ + static const GstQueryType list[] = { + GST_QUERY_POSITION, + GST_QUERY_TOTAL, + 0 + }; + + return list; +} + +static gboolean +gst_amrnbparse_query (GstPad * pad, GstQueryType type, + GstFormat * fmt, gint64 * value) +{ + GstAmrnbParse *amrnbparse = GST_AMRNBPARSE (gst_pad_get_parent (pad)); + gboolean res = TRUE; + + if (*fmt != GST_FORMAT_TIME) + return FALSE; + + switch (type) { + case GST_QUERY_POSITION: + *value = amrnbparse->ts; + break; + case GST_QUERY_TOTAL:{ + gint64 pos = gst_bytestream_tell (amrnbparse->bs), + tot = gst_bytestream_length (amrnbparse->bs); + + *value = amrnbparse->ts * ((gdouble) tot / pos); + break; + } + default: + res = FALSE; + break; + } + + return res; +} + +/* + * Data reading. + */ + +static gboolean +gst_amrnbparse_handle_event (GstAmrnbParse * amrnbparse, GstEvent * event) +{ + gboolean res; + + if (!event) { + GST_ELEMENT_ERROR (amrnbparse, RESOURCE, READ, (NULL), (NULL)); + return FALSE; + } + + GST_LOG ("handling event %d", GST_EVENT_TYPE (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + case GST_EVENT_INTERRUPT: + res = FALSE; + break; + case GST_EVENT_DISCONTINUOUS: + default: + res = TRUE; + break; + } + + gst_pad_event_default (amrnbparse->sinkpad, event); + + return res; +} + +static guint8 * +gst_amrnbparse_reserve (GstAmrnbParse * amrnbparse, gint size) +{ + gint read; + guint8 *data; + + GST_DEBUG ("Trying to read %d bytes", size); + do { + if ((read = gst_bytestream_peek_bytes (amrnbparse->bs, + &data, size)) != size) { + GstEvent *event; + guint32 avail; + + gst_bytestream_get_status (amrnbparse->bs, &avail, &event); + if (!gst_amrnbparse_handle_event (amrnbparse, event)) + return NULL; + } + } while (read < size); + + GST_DEBUG ("Read %d bytes of data", read); + + return data; +} + +static void +gst_amrnbparse_loop (GstElement * element) +{ + const gint block_size[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, + 0, 0, 0, 0, 0, 0, 0 + }; + GstAmrnbParse *amrnbparse = GST_AMRNBPARSE (element); + GstBuffer *buf; + guint8 *data; + gint block, mode, read; + + if (!(data = gst_amrnbparse_reserve (amrnbparse, 1))) + return; + + /* init */ + if (amrnbparse->ts == 0 && data[0] == '#') { + if (!(data = gst_amrnbparse_reserve (amrnbparse, 6))) + return; + if (!memcmp (data, "#!AMR", 5)) { + GST_LOG ("Found header"); + gst_bytestream_flush_fast (amrnbparse->bs, 5); + data += 5; + } + } + + /* get size */ + mode = (data[0] >> 3) & 0x0F; + block = block_size[mode] + 1; + if (!gst_amrnbparse_reserve (amrnbparse, block)) + return; + read = gst_bytestream_read (amrnbparse->bs, &buf, block); + g_assert (read == block); + + /* output */ + GST_BUFFER_DURATION (buf) = GST_SECOND * 160 / 8000; + GST_BUFFER_TIMESTAMP (buf) = amrnbparse->ts; + amrnbparse->ts += GST_BUFFER_DURATION (buf); + + GST_DEBUG ("Pushing %d bytes of data", block); + gst_pad_push (amrnbparse->srcpad, GST_DATA (buf)); +} + +static GstElementStateReturn +gst_amrnbparse_state_change (GstElement * element) +{ + GstAmrnbParse *amrnbparse = GST_AMRNBPARSE (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + if (!(amrnbparse->bs = gst_bytestream_new (amrnbparse->sinkpad))) + return GST_STATE_FAILURE; + break; + case GST_STATE_PAUSED_TO_READY: + amrnbparse->ts = 0; + break; + case GST_STATE_READY_TO_NULL: + gst_bytestream_destroy (amrnbparse->bs); + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} diff --git a/ext/amrnb/amrnbparse.h b/ext/amrnb/amrnbparse.h new file mode 100644 index 0000000000..c6474d9d4c --- /dev/null +++ b/ext/amrnb/amrnbparse.h @@ -0,0 +1,59 @@ +/* GStreamer Adaptive Multi-Rate Narrow-Band (AMR-NB) plugin + * Copyright (C) 2004 Ronald Bultje + * + * 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_AMRNBPARSE_H__ +#define __GST_AMRNBPARSE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_AMRNBPARSE \ + (gst_amrnbparse_get_type()) +#define GST_AMRNBPARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AMRNBPARSE, GstAmrnbParse)) +#define GST_AMRNBPARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AMRNBPARSE, GstAmrnbParse)) +#define GST_IS_AMRNBPARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AMRNBPARSE)) +#define GST_IS_AMRNBPARSE_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AMRNBPARSE)) + +typedef struct _GstAmrnbParse GstAmrnbParse; +typedef struct _GstAmrnbParseClass GstAmrnbParseClass; + +struct _GstAmrnbParse { + GstElement element; + + /* pads */ + GstPad *sinkpad, *srcpad; + GstByteStream *bs; + guint64 ts; +}; + +struct _GstAmrnbParseClass { + GstElementClass parent_class; +}; + +GType gst_amrnbparse_get_type (void); + +G_END_DECLS + +#endif /* __GST_AMRNBPARSE_H__ */