From: <en...@ke...> - 2008-11-13 13:00:00
|
CVS Root: /cvs/gstreamer Module: gst-plugins-bad Changes by: ensonic Date: Thu Nov 13 2008 12:59:49 UTC Log message: * configure.ac: * gst/aacparse/Makefile.am: * gst/aacparse/gstaacparse.c: * gst/aacparse/gstaacparse.h: * gst/aacparse/gstbaseparse.c: * gst/aacparse/gstbaseparse.h: * gst/amrparse/Makefile.am: * gst/amrparse/gstamrparse.c: * gst/amrparse/gstamrparse.h: * gst/amrparse/gstbaseparse.c: * gst/amrparse/gstbaseparse.h: Add two new baseparse based parsers (aac and amr) from Bug #518857. Modified files: . : ChangeLog configure.ac Added files: gst/aacparse : Makefile.am gstaacparse.c gstaacparse.h gstbaseparse.c gstbaseparse.h gst/amrparse : Makefile.am gstamrparse.c gstamrparse.h gstbaseparse.c gstbaseparse.h Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/ChangeLog.diff?r1=1.3691&r2=1.3692 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/configure.ac.diff?r1=1.907&r2=1.908 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/aacparse/Makefile.am?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/aacparse/gstaacparse.c?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/aacparse/gstaacparse.h?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/aacparse/gstbaseparse.c?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/aacparse/gstbaseparse.h?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/amrparse/Makefile.am?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/amrparse/gstamrparse.c?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/amrparse/gstamrparse.h?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/amrparse/gstbaseparse.c?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-bad/gst/amrparse/gstbaseparse.h?rev=1.1&content-type=text/vnd.viewcvs-markup ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gst-plugins-bad/ChangeLog,v retrieving revision 1.3691 retrieving revision 1.3692 diff -u -d -r1.3691 -r1.3692 --- ChangeLog 12 Nov 2008 10:32:22 -0000 1.3691 +++ ChangeLog 13 Nov 2008 12:59:32 -0000 1.3692 @@ -1,3 +1,18 @@ +2008-11-13 Stefan Kost <en...@us...> + + * configure.ac: + * gst/aacparse/Makefile.am: + * gst/aacparse/gstaacparse.c: + * gst/aacparse/gstaacparse.h: + * gst/aacparse/gstbaseparse.c: + * gst/aacparse/gstbaseparse.h: + * gst/amrparse/Makefile.am: + * gst/amrparse/gstamrparse.c: + * gst/amrparse/gstamrparse.h: + * gst/amrparse/gstbaseparse.c: + * gst/amrparse/gstbaseparse.h: + Add two new baseparse based parsers (aac and amr) from Bug #518857. 2008-11-12 Thijs Vermeir <thi...@gm...> * gst/librfb/rfbdecoder.c: Index: configure.ac RCS file: /cvs/gstreamer/gst-plugins-bad/configure.ac,v retrieving revision 1.907 retrieving revision 1.908 diff -u -d -r1.907 -r1.908 --- configure.ac 8 Nov 2008 02:00:56 -0000 1.907 +++ configure.ac 13 Nov 2008 12:59:33 -0000 1.908 @@ -232,7 +232,9 @@ dnl *** plug-ins to include *** dnl these are all the gst plug-ins, compilable without additional libs +AG_GST_CHECK_PLUGIN(aacparse) AG_GST_CHECK_PLUGIN(aiffparse) +AG_GST_CHECK_PLUGIN(amrparse) AG_GST_CHECK_PLUGIN(app) AG_GST_CHECK_PLUGIN(bayer) AG_GST_CHECK_PLUGIN(cdxaparse) @@ -1385,7 +1387,9 @@ Makefile gst-plugins-bad.spec gst/Makefile +gst/aacparse/Makefile gst/aiffparse/Makefile +gst/amrparse/Makefile gst/app/Makefile gst/bayer/Makefile gst/cdxaparse/Makefile --- NEW FILE: Makefile.am --- plugin_LTLIBRARIES = libgstaacparse.la libgstaacparse_la_SOURCES = \ gstaacparse.c gstbaseparse.c libgstaacparse_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) libgstaacparse_la_LIBADD = $(GST_BASE_LIBS) libgstaacparse_la_LDFLAGS = $(PACKAGE_LIBS) $(GST_PLUGIN_LDFLAGS) libgstaacparse_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = gstaacparse.h gstbaseparse.h --- NEW FILE: gstaacparse.c --- /* GStreamer AAC parser plugin * Copyright (C) 2008 Nokia Corporation. All rights reserved. * * Contact: Stefan Kost <ste...@no...> * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:gstaacparse * @short_description: AAC parser * @see_also: #GstAmrParse * <refsect2> * <para> * This is an AAC parser. It can handle both ADIF and ADTS stream formats. * The parser inherits from #GstBaseParse and therefore in only needs to * implement AAC-specific functionality. * </para> * As ADIF format is not framed, it is not seekable. From the same reason * stream duration cannot be calculated either. Instead, AAC clips that are * in ADTS format can be seeked, and parser also is able to calculate their * playback position and clip duration. * <title>Example launch line</title> * <programlisting> * gst-launch filesrc location=abc.aac ! aacparse ! faad ! audioresample ! audioconvert ! alsasink * </programlisting> * </refsect2> #include <string.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gstaacparse.h" static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/mpeg, " "framed = (boolean) true, " "mpegversion = (int) { 2, 4 };")); static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, "framed = (boolean) false, " "mpegversion = (int) { 2, 4 };")); GST_DEBUG_CATEGORY_STATIC (gst_aacparse_debug); #define GST_CAT_DEFAULT gst_aacparse_debug static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 }; #define ADIF_MAX_SIZE 40 /* Should be enough */ #define ADTS_MAX_SIZE 10 /* Should be enough */ #define AAC_FRAME_DURATION(parse) (GST_SECOND/parse->frames_per_sec) static void gst_aacparse_finalize (GObject * object); gboolean gst_aacparse_start (GstBaseParse * parse); gboolean gst_aacparse_stop (GstBaseParse * parse); static gboolean gst_aacparse_sink_setcaps (GstBaseParse * parse, GstCaps * caps); gboolean gst_aacparse_check_valid_frame (GstBaseParse * parse, GstBuffer * buffer, guint * size, gint * skipsize); GstFlowReturn gst_aacparse_parse_frame (GstBaseParse * parse, GstBuffer * buffer); gboolean gst_aacparse_convert (GstBaseParse * parse, GstFormat src_format, gint64 src_value, GstFormat dest_format, gint64 * dest_value); gboolean gst_aacparse_is_seekable (GstBaseParse * parse); gboolean gst_aacparse_event (GstBaseParse * parse, GstEvent * event); #define _do_init(bla) \ GST_DEBUG_CATEGORY_INIT (gst_aacparse_debug, "aacparse", 0, \ "AAC audio stream parser"); GST_BOILERPLATE_FULL (GstAacParse, gst_aacparse, GstBaseParse, GST_TYPE_BASE_PARSE, _do_init); * gst_aacparse_base_init: * @klass: #GstElementClass. static void gst_aacparse_base_init (gpointer klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstElementDetails details = GST_ELEMENT_DETAILS ("AAC audio stream parser", "Codec/Parser/Audio", "Advanced Audio Coding parser", "Stefan Kost <ste...@no...>"); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&sink_template)); gst_static_pad_template_get (&src_template)); gst_element_class_set_details (element_class, &details); } * gst_aacparse_class_init: * @klass: #GstAacParseClass. gst_aacparse_class_init (GstAacParseClass * klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass); object_class->finalize = gst_aacparse_finalize; parse_class->start = GST_DEBUG_FUNCPTR (gst_aacparse_start); parse_class->stop = GST_DEBUG_FUNCPTR (gst_aacparse_stop); parse_class->event = GST_DEBUG_FUNCPTR (gst_aacparse_event); parse_class->convert = GST_DEBUG_FUNCPTR (gst_aacparse_convert); parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_aacparse_sink_setcaps); parse_class->is_seekable = GST_DEBUG_FUNCPTR (gst_aacparse_is_seekable); parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_aacparse_parse_frame); parse_class->check_valid_frame = GST_DEBUG_FUNCPTR (gst_aacparse_check_valid_frame); * gst_aacparse_init: * @aacparse: #GstAacParse. gst_aacparse_init (GstAacParse * aacparse, GstAacParseClass * klass) /* init rest */ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), 1024); aacparse->ts = 0; GST_DEBUG ("initialized"); * gst_aacparse_finalize: * @object: gst_aacparse_finalize (GObject * object) GstAacParse *aacparse; aacparse = GST_AACPARSE (object); G_OBJECT_CLASS (parent_class)->finalize (object); * gst_aacparse_set_src_caps: * Set source pad caps according to current knowledge about the * audio stream. * Returns: TRUE if caps were successfully set. static gboolean gst_aacparse_set_src_caps (GstAacParse * aacparse) GstCaps *src_caps = NULL; gchar *caps_str = NULL; gboolean res = FALSE; src_caps = gst_caps_new_simple ("audio/mpeg", "framed", G_TYPE_BOOLEAN, TRUE, "mpegversion", G_TYPE_INT, aacparse->mpegversion, NULL); caps_str = gst_caps_to_string (src_caps); GST_DEBUG_OBJECT (aacparse, "setting srcpad caps: %s", caps_str); g_free (caps_str); gst_pad_use_fixed_caps (GST_BASE_PARSE (aacparse)->srcpad); res = gst_pad_set_caps (GST_BASE_PARSE (aacparse)->srcpad, src_caps); gst_pad_fixate_caps (GST_BASE_PARSE (aacparse)->srcpad, src_caps); gst_caps_unref (src_caps); return res; * gst_aacparse_sink_setcaps: * @sinkpad: GstPad * @caps: GstCaps * Implementation of "set_sink_caps" vmethod in #GstBaseParse class. * Returns: TRUE on success. gst_aacparse_sink_setcaps (GstBaseParse * parse, GstCaps * caps) GstStructure *structure; gchar *caps_str; aacparse = GST_AACPARSE (parse); structure = gst_caps_get_structure (caps, 0); caps_str = gst_caps_to_string (caps); GST_DEBUG_OBJECT (aacparse, "setcaps: %s", caps_str); // This is needed at least in case of RTP // Parses the codec_data information to get ObjectType, // number of channels and samplerate if (gst_structure_has_field (structure, "codec_data")) { const GValue *value = gst_structure_get_value (structure, "codec_data"); if (value) { GstBuffer *buf = gst_value_get_buffer (value); const guint8 *buffer = GST_BUFFER_DATA (buf); aacparse->object_type = (buffer[0] & 0xf8) >> 3; aacparse->sample_rate = ((buffer[0] & 0x07) << 1) | ((buffer[1] & 0x80) >> 7); aacparse->channels = (buffer[1] & 0x78) >> 3; aacparse->header_type = DSPAAC_HEADER_NONE; aacparse->mpegversion = 4; } else return FALSE; } return TRUE; * gst_aacparse_update_duration: gst_aacparse_update_duration (GstAacParse * aacparse) GstPad *peer; GstBaseParse *parse; parse = GST_BASE_PARSE (aacparse); /* Cannot estimate duration. No data has been passed to us yet */ if (!aacparse->framecount || !aacparse->frames_per_sec) { return; // info->length = (int)((filelength_filestream(file)/(((info->bitrate*8)/1024)*16))*1000); peer = gst_pad_get_peer (parse->sinkpad); if (peer) { GstFormat pformat = GST_FORMAT_BYTES; guint64 bpf = aacparse->bytecount / aacparse->framecount; gboolean qres = FALSE; gint64 ptot; qres = gst_pad_query_duration (peer, &pformat, &ptot); gst_object_unref (GST_OBJECT (peer)); if (qres && bpf) { gst_base_parse_set_duration (parse, GST_FORMAT_TIME, AAC_FRAME_DURATION (aacparse) * ptot / bpf); } * gst_aacparse_adts_get_frame_len: * @data: block of data containing an ADTS header. * This function calculates ADTS frame length from the given header. * Returns: size of the ADTS frame. static inline guint gst_aacparse_adts_get_frame_len (const guint8 * data) return ((data[3] & 0x03) << 11) | (data[4] << 3) | ((data[5] & 0xe0) >> 5); * gst_aacparse_check_adts_frame: * @data: Data to be checked. * @avail: Amount of data passed. * @framesize: If valid ADTS frame was found, this will be set to tell the * found frame size in bytes. * @needed_data: If frame was not found, this may be set to tell how much * more data is needed in the next round to detect the frame * reliably. This may happen when a frame header candidate * is found but it cannot be guaranteed to be the header without * peeking the following data. * Check if the given data contains contains ADTS frame. The algorithm * will examine ADTS frame header and calculate the frame size. Also, another * consecutive ADTS frame header need to be present after the found frame. * Otherwise the data is not considered as a valid ADTS frame. However, this * "extra check" is omitted when EOS has been received. In this case it is * enough when data[0] contains a valid ADTS header. * This function may set the #needed_data to indicate that a possible frame * candidate has been found, but more data (#needed_data bytes) is needed to * be absolutely sure. When this situation occurs, FALSE will be returned. * When a valid frame is detected, this function will use * gst_base_parse_set_min_frame_size() function from #GstBaseParse class * to set the needed bytes for next frame.This way next data chunk is already * of correct size. * Returns: TRUE if the given data contains a valid ADTS header. gst_aacparse_check_adts_frame (GstAacParse * aacparse, const guint8 * data, const guint avail, guint * framesize, guint * needed_data) if ((data[0] == 0xff) && ((data[1] & 0xf6) == 0xf0)) { *framesize = gst_aacparse_adts_get_frame_len (data); /* In EOS mode this is enough. No need to examine the data further */ if (aacparse->eos) { return TRUE; if (*framesize + ADTS_MAX_SIZE > avail) { /* We have found a possible frame header candidate, but can't be sure since we don't have enough data to check the next frame */ GST_DEBUG ("NEED MORE DATA: we need %d, available %d", *framesize + ADTS_MAX_SIZE, avail); *needed_data = *framesize + ADTS_MAX_SIZE; gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), *framesize + ADTS_MAX_SIZE); if ((data[*framesize] == 0xff) && ((data[*framesize + 1] & 0xf6) == 0xf0)) { guint nextlen = gst_aacparse_adts_get_frame_len (data + (*framesize)); GST_LOG ("ADTS frame found, len: %d bytes", *framesize); nextlen + ADTS_MAX_SIZE); aacparse->sync = FALSE; return FALSE; * gst_aacparse_detect_stream: * @data: A block of data that needs to be examined for stream characteristics. * @avail: Size of the given datablock. * @framesize: If valid stream was found, this will be set to tell the * first frame size in bytes. * @skipsize: If valid stream was found, this will be set to tell the first * audio frame position within the given data. * Examines the given piece of data and try to detect the format of it. It * checks for "ADIF" header (in the beginning of the clip) and ADTS frame * header. If the stream is detected, TRUE will be returned and #framesize * is set to indicate the found frame size. Additionally, #skipsize might * be set to indicate the number of bytes that need to be skipped, a.k.a. the * position of the frame inside given data chunk. gst_aacparse_detect_stream (GstAacParse * aacparse, const guint8 * data, const guint avail, guint * framesize, gint * skipsize) gboolean found = FALSE; guint need_data = 0; guint i = 0; GST_DEBUG_OBJECT (aacparse, "Parsing header data"); /* FIXME: No need to check for ADIF if we are not in the beginning of the stream */ /* Can we even parse the header? */ if (avail < ADTS_MAX_SIZE) return FALSE; for (i = 0; i < avail - 4; i++) { if (((data[i] == 0xff) && ((data[i + 1] & 0xf6) == 0xf0)) || strncmp ((char *) data + i, "ADIF", 4) == 0) { found = TRUE; if (i) { /* Trick: tell the parent class that we didn't find the frame yet, but make it skip 'i' amount of bytes. Next time we arrive here we have full frame in the beginning of the data. */ *skipsize = i; return FALSE; } break; if (!found) { if (i) *skipsize = i; if (gst_aacparse_check_adts_frame (aacparse, data, avail, framesize, &need_data)) { gint sr_idx; GST_INFO ("ADTS ID: %d, framesize: %d", (data[1] & 0x08) >> 3, *framesize); aacparse->header_type = DSPAAC_HEADER_ADTS; sr_idx = (data[2] & 0x3c) >> 2; aacparse->sample_rate = aac_sample_rates[sr_idx]; aacparse->mpegversion = (data[1] & 0x08) ? 2 : 4; aacparse->object_type = (data[2] & 0xc0) >> 6; aacparse->channels = ((data[2] & 0x01) << 2) | ((data[3] & 0xc0) >> 6); aacparse->bitrate = ((data[5] & 0x1f) << 6) | ((data[6] & 0xfc) >> 2); aacparse->frames_per_sec = aac_sample_rates[sr_idx] / 1024.f; GST_DEBUG ("ADTS: samplerate %d, channels %d, bitrate %d, objtype %d, " "fps %f", aacparse->sample_rate, aacparse->channels, aacparse->bitrate, aacparse->object_type, aacparse->frames_per_sec); aacparse->sync = TRUE; return TRUE; } else if (need_data) { /* This tells the parent class not to skip any data */ *skipsize = 0; if (avail < ADIF_MAX_SIZE) if (memcmp (data + i, "ADIF", 4) == 0) { const guint8 *adif; int skip_size = 0; int bitstream_type; int sr_idx; aacparse->header_type = DSPAAC_HEADER_ADIF; aacparse->mpegversion = 4; // Skip the "ADIF" bytes adif = data + i + 4; /* copyright string */ if (adif[0] & 0x80) skip_size += 9; /* skip 9 bytes */ bitstream_type = adif[0 + skip_size] & 0x10; aacparse->bitrate = ((unsigned int) (adif[0 + skip_size] & 0x0f) << 19) | ((unsigned int) adif[1 + skip_size] << 11) | ((unsigned int) adif[2 + skip_size] << 3) | ((unsigned int) adif[3 + skip_size] & 0xe0); /* CBR */ if (bitstream_type == 0) { #if 0 /* Buffer fullness parsing. Currently not needed... */ guint num_elems = 0; guint fullness = 0; num_elems = (adif[3 + skip_size] & 0x1e); GST_INFO ("ADIF num_config_elems: %d", num_elems); fullness = ((unsigned int) (adif[3 + skip_size] & 0x01) << 19) | ((unsigned int) adif[4 + skip_size] << 11) | ((unsigned int) adif[5 + skip_size] << 3) | ((unsigned int) (adif[6 + skip_size] & 0xe0) >> 5); GST_INFO ("ADIF buffer fullness: %d", fullness); aacparse->object_type = ((adif[6 + skip_size] & 0x01) << 1) | ((adif[7 + skip_size] & 0x80) >> 7); sr_idx = (adif[7 + skip_size] & 0x78) >> 3; /* VBR */ else { aacparse->object_type = (adif[4 + skip_size] & 0x18) >> 3; sr_idx = ((adif[4 + skip_size] & 0x07) << 1) | ((adif[5 + skip_size] & 0x80) >> 7); /* FIXME: This gives totally wrong results. Duration calculation cannot be based on this */ GST_INFO ("ADIF fps: %f", aacparse->frames_per_sec); // FIXME: Can we assume this? aacparse->channels = 2; GST_INFO ("ADIF: br=%d, samplerate=%d, objtype=%d", aacparse->bitrate, aacparse->sample_rate, aacparse->object_type); gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), 512); *framesize = avail; /* This should never happen */ * gst_aacparse_check_valid_frame: * @parse: #GstBaseParse. * @buffer: #GstBuffer. * @framesize: If the buffer contains a valid frame, its size will be put here * @skipsize: How much data parent class should skip in order to find the * frame header. * Implementation of "check_valid_frame" vmethod in #GstBaseParse class. * Returns: TRUE if buffer contains a valid frame. gboolean gst_aacparse_check_valid_frame (GstBaseParse * parse, GstBuffer * buffer, guint * framesize, gint * skipsize) const guint8 *data; guint needed_data = 1024; gboolean ret = FALSE; data = GST_BUFFER_DATA (buffer); if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { /* Discontinuous stream -> drop the sync */ aacparse->sync = FALSE; if (aacparse->header_type == DSPAAC_HEADER_ADIF || aacparse->header_type == DSPAAC_HEADER_NONE) { /* There is nothing to parse */ *framesize = GST_BUFFER_SIZE (buffer); ret = TRUE; else if (aacparse->header_type == DSPAAC_HEADER_NOT_PARSED || aacparse->sync == FALSE) { ret = gst_aacparse_detect_stream (aacparse, data, GST_BUFFER_SIZE (buffer), framesize, skipsize); } else if (aacparse->header_type == DSPAAC_HEADER_ADTS) { ret = gst_aacparse_check_adts_frame (aacparse, data, GST_BUFFER_SIZE (buffer), framesize, &needed_data); if (!ret) { /* Increase the block size, we want to find the header by ourselves */ GST_DEBUG ("buffer didn't contain valid frame, skip = %d", *skipsize); gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse), needed_data); return ret; * gst_aacparse_parse_frame: * Implementation of "parse_frame" vmethod in #GstBaseParse class. * Returns: GST_FLOW_OK if frame was successfully parsed and can be pushed * forward. Otherwise appropriate error is returned. GstFlowReturn gst_aacparse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) GstFlowReturn ret = GST_FLOW_OK; gint64 btime; gboolean r = gst_aacparse_convert (parse, GST_FORMAT_BYTES, GST_BUFFER_OFFSET (buffer), GST_FORMAT_TIME, &btime); if (r) { /* FIXME: What to do if the conversion fails? */ aacparse->ts = btime; GST_BUFFER_DURATION (buffer) = AAC_FRAME_DURATION (aacparse); GST_BUFFER_TIMESTAMP (buffer) = aacparse->ts; if (GST_CLOCK_TIME_IS_VALID (aacparse->ts)) aacparse->ts += GST_BUFFER_DURATION (buffer); if (!(++aacparse->framecount % 50)) { gst_aacparse_update_duration (aacparse); aacparse->bytecount += GST_BUFFER_SIZE (buffer); if (!aacparse->src_caps_set) { if (!gst_aacparse_set_src_caps (aacparse)) { /* If linking fails, we need to return appropriate error */ ret = GST_FLOW_NOT_LINKED; aacparse->src_caps_set = TRUE; gst_buffer_set_caps (buffer, GST_PAD_CAPS (parse->srcpad)); * gst_aacparse_start: * Implementation of "start" vmethod in #GstBaseParse class. * Returns: TRUE if startup succeeded. gst_aacparse_start (GstBaseParse * parse) GST_DEBUG ("start"); aacparse->src_caps_set = FALSE; aacparse->framecount = 0; aacparse->bytecount = 0; aacparse->eos = FALSE; * gst_aacparse_stop: * Implementation of "stop" vmethod in #GstBaseParse class. * Returns: TRUE is stopping succeeded. gst_aacparse_stop (GstBaseParse * parse) GST_DEBUG ("stop"); aacparse->ts = -1; * gst_aacparse_event: * @event: #GstEvent. * Implementation of "event" vmethod in #GstBaseParse class. * Returns: TRUE if the event was handled and can be dropped. gst_aacparse_event (GstBaseParse * parse, GstEvent * event) GST_DEBUG ("event"); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: aacparse->eos = TRUE; GST_DEBUG ("EOS event"); default: return parent_class->event (parse, event); * gst_aacparse_convert: * @src_format: #GstFormat describing the source format. * @src_value: Source value to be converted. * @dest_format: #GstFormat defining the converted format. * @dest_value: Pointer where the conversion result will be put. * Implementation of "convert" vmethod in #GstBaseParse class. * Returns: TRUE if conversion was successful. gst_aacparse_convert (GstBaseParse * parse, gint64 src_value, GstFormat dest_format, gint64 * dest_value) gfloat bpf; /* We are not able to do any estimations until some data has been passed */ if (!aacparse->framecount) bpf = (gfloat) aacparse->bytecount / aacparse->framecount; if (src_format == GST_FORMAT_BYTES) { if (dest_format == GST_FORMAT_TIME) { /* BYTES -> TIME conversion */ GST_DEBUG ("converting bytes -> time"); if (aacparse->framecount && aacparse->frames_per_sec) { *dest_value = AAC_FRAME_DURATION (aacparse) * src_value / bpf; GST_DEBUG ("conversion result: %lld ms", *dest_value / GST_MSECOND); ret = TRUE; } else if (dest_format == GST_FORMAT_BYTES) { /* Parent class may ask us to convert from BYTES to BYTES */ *dest_value = src_value; ret = TRUE; } else if (src_format == GST_FORMAT_TIME) { GST_DEBUG ("converting time -> bytes"); if (dest_format == GST_FORMAT_BYTES) { *dest_value = bpf * src_value / AAC_FRAME_DURATION (aacparse); GST_DEBUG ("time %lld ms in bytes = %lld", src_value / GST_MSECOND, *dest_value); } else if (src_format == GST_FORMAT_DEFAULT) { /* DEFAULT == frame-based */ if (dest_format == GST_FORMAT_TIME && aacparse->frames_per_sec) { *dest_value = src_value * AAC_FRAME_DURATION (aacparse); * gst_aacparse_is_seekable: * Implementation of "is_seekable" vmethod in #GstBaseParse class. * Returns: TRUE if the current stream is seekable. gst_aacparse_is_seekable (GstBaseParse * parse) GST_DEBUG_OBJECT (aacparse, "IS_SEEKABLE: %d", aacparse->header_type != DSPAAC_HEADER_ADIF); /* Not seekable if ADIF header is found */ return (aacparse->header_type != DSPAAC_HEADER_ADIF); * plugin_init: * @plugin: GstPlugin plugin_init (GstPlugin * plugin) return gst_element_register (plugin, "aacparse", GST_RANK_PRIMARY + 1, GST_TYPE_AACPARSE); GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "aacparse", "Advanced Audio Coding Parser", plugin_init, VERSION, GST_LICENSE_UNKNOWN, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); --- NEW FILE: gstaacparse.h --- /* GStreamer AAC parser #ifndef __GST_AACPARSE_H__ #define __GST_AACPARSE_H__ #include <gst/gst.h> #include "gstbaseparse.h" G_BEGIN_DECLS #define GST_TYPE_AACPARSE \ (gst_aacparse_get_type()) #define GST_AACPARSE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AACPARSE, GstAacParse)) #define GST_AACPARSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AACPARSE, GstAacParseClass)) #define GST_IS_AACPARSE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AACPARSE)) #define GST_IS_AACPARSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AACPARSE)) * GstAacHeaderType: * @DSPAAC_HEADER_NOT_PARSED: Header not parsed yet. * @DSPAAC_HEADER_UNKNOWN: Unknown (not recognized) header. * @DSPAAC_HEADER_ADIF: ADIF header found. * @DSPAAC_HEADER_ADTS: ADTS header found. * @DSPAAC_HEADER_NONE: Raw stream, no header. * Type header enumeration set in #header_type. typedef enum { DSPAAC_HEADER_NOT_PARSED, DSPAAC_HEADER_UNKNOWN, DSPAAC_HEADER_ADIF, DSPAAC_HEADER_ADTS, DSPAAC_HEADER_NONE } GstAacHeaderType; typedef struct _GstAacParse GstAacParse; typedef struct _GstAacParseClass GstAacParseClass; * GstAacParse: * @element: the parent element. * @object_type: AAC object type of the stream. * @bitrate: Current media bitrate. * @sample_rate: Current media samplerate. * @channels: Current media channel count. * @frames_per_sec: FPS value of the current stream. * @header_type: #GstAacHeaderType indicating the current stream type. * @framecount: The amount of frames that has been processed this far. * @bytecount: The amount of bytes that has been processed this far. * @sync: Tells whether the parser is in sync (a.k.a. not searching for header) * @eos: End-of-Stream indicator. Set when EOS event arrives. * @duration: Duration of the current stream. * @ts: Current stream timestamp. * The opaque GstAacParse data structure. struct _GstAacParse { GstBaseParse element; /* Stream type -related info */ gint object_type; gint bitrate; gint sample_rate; gint channels; gint mpegversion; gfloat frames_per_sec; GstAacHeaderType header_type; guint64 framecount; guint64 bytecount; gboolean src_caps_set; gboolean sync; gboolean eos; GstClockTime duration; GstClockTime ts; * GstAacParseClass: * @parent_class: Element parent class. * The opaque GstAacParseClass data structure. struct _GstAacParseClass { GstBaseParseClass parent_class; GType gst_aacparse_get_type (void); G_END_DECLS #endif /* __GST_AACPARSE_H__ */ --- NEW FILE: gstbaseparse.c --- /* GStreamer * Contact: Stefan Kost <ste...@no...> * Copyright (C) 2008 Sebastian Dröge <seb...@co...>. [...1702 lines suppressed...] GstBaseParseClass *klass; gboolean res = TRUE; gchar *caps_str = gst_caps_to_string (caps); parse = GST_BASE_PARSE (gst_pad_get_parent (pad)); klass = GST_BASE_PARSE_GET_CLASS (parse); GST_DEBUG_OBJECT (parse, "setcaps: %s", caps_str); if (klass->set_sink_caps) res = klass->set_sink_caps (parse, caps); parse->negotiated = res; gst_object_unref (parse); return gst_pad_set_caps (pad, caps); --- NEW FILE: gstbaseparse.h --- #ifndef __GST_BASE_PARSE_H__ #define __GST_BASE_PARSE_H__ #include <gst/base/gstadapter.h> #define GST_TYPE_BASE_PARSE (gst_base_parse_get_type()) #define GST_BASE_PARSE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_PARSE,GstBaseParse)) #define GST_BASE_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_PARSE,GstBaseParseClass)) #define GST_BASE_PARSE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_BASE_PARSE,GstBaseParseClass)) #define GST_IS_BASE_PARSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_PARSE)) #define GST_IS_BASE_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_PARSE)) #define GST_BASE_PARSE_CAST(obj) ((GstBaseParse *)(obj)) * GST_BASE_PARSE_SINK_NAME: * the name of the templates for the sink pad #define GST_BASE_PARSE_SINK_NAME "sink" * GST_BASE_PARSE_SRC_NAME: * the name of the templates for the source pad #define GST_BASE_PARSE_SRC_NAME "src" * GST_BASE_PARSE_SRC_PAD: * @obj: base parse instance * Gives the pointer to the source #GstPad object of the element. * Since: 0.10.x #define GST_BASE_PARSE_SRC_PAD(obj) (GST_BASE_PARSE_CAST (obj)->srcpad) * GST_BASE_PARSE_SINK_PAD: * Gives the pointer to the sink #GstPad object of the element. #define GST_BASE_PARSE_SINK_PAD(obj) (GST_BASE_PARSE_CAST (obj)->sinkpad) * GST_BASE_PARSE_FLOW_DROPPED: * A #GstFlowReturn that can be returned from parse_frame to * indicate that no output buffer was generated. #define GST_BASE_PARSE_FLOW_DROPPED GST_FLOW_CUSTOM_SUCCESS * GST_BASE_PARSE_LOCK: * Obtain a lock to protect the parse function from concurrent access. #define GST_BASE_PARSE_LOCK(obj) g_mutex_lock (GST_BASE_PARSE_CAST (obj)->parse_lock) * GST_BASE_PARSE_UNLOCK: * Release the lock that protects the parse function from concurrent access. #define GST_BASE_PARSE_UNLOCK(obj) g_mutex_unlock (GST_BASE_PARSE_CAST (obj)->parse_lock) typedef struct _GstBaseParse GstBaseParse; typedef struct _GstBaseParseClass GstBaseParseClass; typedef struct _GstBaseParsePrivate GstBaseParsePrivate; typedef struct _GstBaseParseClassPrivate GstBaseParseClassPrivate; * GstBaseParse: * The opaque #GstBaseParse data structure. struct _GstBaseParse { GstElement element; GstAdapter *adapter; /*< protected >*/ /* source and sink pads */ GstPad *sinkpad; GstPad *srcpad; /* MT-protected (with STREAM_LOCK) */ GstSegment segment; /* Newsegment event to be sent after SEEK */ GstEvent *pending_segment; /* Segment event that closes the running segment prior to SEEK */ GstEvent *close_segment; /* Caps nego done already? */ gboolean negotiated; GMutex *parse_lock; /*< private >*/ gpointer _gst_reserved[GST_PADDING_LARGE]; GstBaseParsePrivate *priv; * GstBaseParseClass: * @start: Optional. * Called when the element starts processing. * Allows opening external resources. * @stop: Optional. * Called when the element stops processing. * Allows closing external resources. * @set_sink_caps: allows the subclass to be notified of the actual caps set. * @check_valid_frame: Check if the given piece of data contains a valid * frame. * @parse_frame: Parse the already checked frame. Subclass need to * set the buffer timestamp, duration, caps and possibly * other necessary metadata. This is called with srcpad's * STREAM_LOCK held. * @convert: Optional. * Convert between formats. * @find_frame: Optional. * Finds a frame. Gets a position passed and should return * TRUE and the offset in bytes where this position is. * Will only be called in pull mode and the subclass can pull * whatever it wants from upstream. If not implemented, * the base class will implement it by calling * @check_valid_frame and @parse_frame to find the wanted * frame and build a seek table. * @event: Optional. * Event handler on the sink pad. This function should return * TRUE if the event was handled and can be dropped. * @src_event: Optional. * Event handler on the source pad. Should return TRUE * if the event was handled and can be dropped. * @is_seekable: Optional. * Subclass can override this if it wants to control the * seekability of the stream. Otherwise the element assumes * that stream is always seekable. * Subclasses can override any of the available virtual methods or not, as * needed. At minimum @check_valid_frame and @parse_frame needs to be * overridden. struct _GstBaseParseClass { GstElementClass parent_class; /*< public >*/ /* virtual methods for subclasses */ gboolean (*start) (GstBaseParse *parse); gboolean (*stop) (GstBaseParse *parse); gboolean (*set_sink_caps) (GstBaseParse *parse, GstCaps *caps); gboolean (*check_valid_frame) (GstBaseParse *parse, GstBuffer *buffer, guint *framesize, gint *skipsize); GstFlowReturn (*parse_frame) (GstBaseParse *parse, GstBuffer *buffer); gboolean (*convert) (GstBaseParse * parse, GstFormat src_format, gint64 src_value, GstFormat dest_format, gint64 * dest_value); gboolean (*find_frame) (GstBaseParse *parse, gboolean (*event) (GstBaseParse *parse, GstEvent *event); gboolean (*src_event) (GstBaseParse *parse, gboolean (*is_seekable) (GstBaseParse *parse); gpointer _gst_reserved[GST_PADDING_LARGE]; GstBaseParseClassPrivate *priv; GType gst_base_parse_get_type (void); void gst_base_parse_set_duration (GstBaseParse *parse, GstFormat fmt, gint64 duration); void gst_base_parse_set_min_frame_size (GstBaseParse *parse, guint min_size); #endif /* __GST_BASE_PARSE_H__ */ plugin_LTLIBRARIES = libgstamrparse.la libgstamrparse_la_SOURCES = \ gstamrparse.c gstbaseparse.c libgstamrparse_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) libgstamrparse_la_LIBADD = $(GST_BASE_LIBS) libgstamrparse_la_LDFLAGS = $(PACKAGE_LIBS) $(GST_PLUGIN_LDFLAGS) libgstamrparse_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = gstamrparse.h gstbaseparse.h --- NEW FILE: gstamrparse.c --- /* GStreamer Adaptive Multi-Rate parser plugin * Copyright (C) 2006 Edgard Lima <edg...@in...> * SECTION:gstamrparse * @short_description: AMR parser * @see_also: #GstAmrnbDec, #GstAmrnbEnc * This is an AMR parser capable of handling both narrow-band and wideband * formats. * gst-launch filesrc location=abc.amr ! amrparse ! amrdec ! audioresample ! audioconvert ! alsasink #include "gstamrparse.h" GST_STATIC_CAPS ("audio/AMR, " "rate = (int) 8000, " "channels = (int) 1;" "audio/AMR-WB, " "rate = (int) 16000, " "channels = (int) 1;") ); GST_STATIC_CAPS ("audio/x-amr-nb-sh; audio/x-amr-wb-sh")); GST_DEBUG_CATEGORY_STATIC (gst_amrparse_debug); #define GST_CAT_DEFAULT gst_amrparse_debug static const gint block_size_nb[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 }; static const gint block_size_wb[16] = { 17, 23, 32, 36, 40, 46, 50, 58, 60, 5, 5, 0, 0, 0, 0, 0 }; /* AMR has a "hardcoded" framerate of 50fps */ #define AMR_FRAMES_PER_SECOND 50 #define AMR_FRAME_DURATION (GST_SECOND/AMR_FRAMES_PER_SECOND) #define AMR_MIME_HEADER_SIZE 9 static void gst_amrparse_finalize (GObject * object); gboolean gst_amrparse_start (GstBaseParse * parse); gboolean gst_amrparse_stop (GstBaseParse * parse); static gboolean gst_amrparse_sink_setcaps (GstBaseParse * parse, gboolean gst_amrparse_check_valid_frame (GstBaseParse * parse, GstBuffer * buffer, guint * framesize, gint * skipsize); GstFlowReturn gst_amrparse_parse_frame (GstBaseParse * parse, gboolean gst_amrparse_convert (GstBaseParse * parse, gboolean gst_amrparse_event (GstBaseParse * parse, GstEvent * event); GST_DEBUG_CATEGORY_INIT (gst_amrparse_debug, "amrparse", 0, \ "AMR-NB audio stream parser"); GST_BOILERPLATE_FULL (GstAmrParse, gst_amrparse, GstBaseParse, * gst_amrparse_base_init: gst_amrparse_base_init (gpointer klass) GstElementDetails details = GST_ELEMENT_DETAILS ("AMR audio stream parser", "Adaptive Multi-Rate audio parser", "Ronald Bultje <rb...@ro...>"); * gst_amrparse_class_init: * @klass: GstAmrParseClass. gst_amrparse_class_init (GstAmrParseClass * klass) object_class->finalize = gst_amrparse_finalize; parse_class->start = GST_DEBUG_FUNCPTR (gst_amrparse_start); parse_class->stop = GST_DEBUG_FUNCPTR (gst_amrparse_stop); parse_class->event = GST_DEBUG_FUNCPTR (gst_amrparse_event); parse_class->convert = GST_DEBUG_FUNCPTR (gst_amrparse_convert); parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_amrparse_sink_setcaps); parse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_amrparse_parse_frame); GST_DEBUG_FUNCPTR (gst_amrparse_check_valid_frame); * gst_amrparse_init: * @amrparse: #GstAmrParse * @klass: #GstAmrParseClass. gst_amrparse_init (GstAmrParse * amrparse, GstAmrParseClass * klass) gst_base_parse_set_min_frame_size (GST_BASE_PARSE (amrparse), 62); amrparse->ts = 0; * gst_amrparse_finalize: gst_amrparse_finalize (GObject * object) GstAmrParse *amrparse; amrparse = GST_AMRPARSE (object); * gst_amrparse_set_src_caps: * @amrparse: #GstAmrParse. gst_amrparse_set_src_caps (GstAmrParse * amrparse) if (amrparse->wide) { GST_DEBUG_OBJECT (amrparse, "setting srcpad caps to AMR-WB"); src_caps = gst_caps_new_simple ("audio/AMR-WB", "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 16000, NULL); } else { GST_DEBUG_OBJECT (amrparse, "setting srcpad caps to AMR-NB"); /* Max. size of NB frame is 31 bytes, so we can set the min. frame size to 32 (+1 for next frame header) */ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (amrparse), 32); src_caps = gst_caps_new_simple ("audio/AMR", "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL); gst_pad_use_fixed_caps (GST_BASE_PARSE (amrparse)->srcpad); res = gst_pad_set_caps (GST_BASE_PARSE (amrparse)->srcpad, src_caps); gst_pad_fixate_caps (GST_BASE_PARSE (amrparse)->srcpad, src_caps); * gst_amrparse_sink_setcaps: gst_amrparse_sink_setcaps (GstBaseParse * parse, GstCaps * caps) const gchar *name; amrparse = GST_AMRPARSE (parse); name = gst_structure_get_name (structure); GST_DEBUG_OBJECT (amrparse, "setcaps: %s", name); if (!strncmp (name, "audio/x-amr-wb-sh", 17)) { amrparse->block_size = block_size_wb; amrparse->wide = 1; } else if (!strncmp (name, "audio/x-amr-nb-sh", 17)) { amrparse->block_size = block_size_nb; amrparse->wide = 0; GST_WARNING ("Unknown caps"); amrparse->need_header = FALSE; gst_amrparse_set_src_caps (amrparse); * gst_amrparse_update_duration: * Send duration information to base class. gst_amrparse_update_duration (GstAmrParse * amrparse) parse = GST_BASE_PARSE (amrparse); if (!amrparse->framecount) { guint64 bpf = amrparse->bytecount / amrparse->framecount; AMR_FRAME_DURATION * ptot / bpf); * gst_amrparse_parse_header: * @data: Header data to be parsed. * @skipsize: Output argument where the frame size will be stored. * Check if the given data contains an AMR mime header. gst_amrparse_parse_header (GstAmrParse * amrparse, const guint8 * data, gint * skipsize) GST_DEBUG_OBJECT (amrparse, "Parsing header data"); if (!memcmp (data, "#!AMR-WB\n", 9)) { GST_DEBUG_OBJECT (amrparse, "AMR-WB detected"); amrparse->wide = TRUE; *skipsize = 9; } else if (!memcmp (data, "#!AMR\n", 6)) { GST_DEBUG_OBJECT (amrparse, "AMR-NB detected"); amrparse->wide = FALSE; *skipsize = 6; } else * gst_amrparse_check_valid_frame: * @framesize: Output variable where the found frame size is put. * @skipsize: Output variable which tells how much data needs to be skipped * until a frame header is found. * Returns: TRUE if the given data contains valid frame. gst_amrparse_check_valid_frame (GstBaseParse * parse, gint fsize, mode, dsize; dsize = GST_BUFFER_SIZE (buffer); GST_LOG ("buffer: %d bytes", dsize); amrparse->sync = FALSE; if (amrparse->need_header) { if (dsize >= AMR_MIME_HEADER_SIZE && gst_amrparse_parse_header (amrparse, data, skipsize)) { amrparse->need_header = FALSE; } else { GST_WARNING ("media doesn't look like a AMR format"); /* We return FALSE, so this frame won't get pushed forward. Instead, the "skip" value is set, so next time we will receive a valid frame. */ /* Does this look like a possible frame header candidate? */ if ((data[0] & 0x83) == 0) { /* Yep. Retrieve the frame size */ mode = (data[0] >> 3) & 0x0F; fsize = amrparse->block_size[mode] + 1; /* +1 for the header byte */ /* We recognize this data as a valid frame when: * - We are in sync. There is no need for extra checks then * - We are in EOS. There might not be enough data to check next frame * - Sync is lost, but the following data after this frame seem * to contain a valid header as well (and there is enough data to * perform this check) */ if (amrparse->sync || amrparse->eos || (dsize >= fsize && (data[fsize] & 0x83) == 0)) { amrparse->sync = TRUE; *framesize = fsize; GST_LOG ("sync lost"); amrparse->sync = FALSE; * gst_amrparse_parse_frame: * Implementation of "parse" vmethod in #GstBaseParse class. * Returns: #GstFlowReturn defining the parsing status. gst_amrparse_parse_frame (GstBaseParse * parse, GstBuffer * buffer) gboolean r = gst_amrparse_convert (parse, GST_FORMAT_BYTES, amrparse->ts = btime; GST_BUFFER_DURATION (buffer) = AMR_FRAME_DURATION; GST_BUFFER_TIMESTAMP (buffer) = amrparse->ts; if (GST_CLOCK_TIME_IS_VALID (amrparse->ts)) { amrparse->ts += AMR_FRAME_DURATION; if (!(++amrparse->framecount % 50)) { gst_amrparse_update_duration (amrparse); amrparse->bytecount += GST_BUFFER_SIZE (buffer); return GST_FLOW_OK; * gst_amrparse_start: gst_amrparse_start (GstBaseParse * parse) amrparse->need_header = TRUE; amrparse->sync = TRUE; amrparse->eos = FALSE; amrparse->framecount = 0; amrparse->bytecount = 0; * gst_amrparse_stop: gst_amrparse_stop (GstBaseParse * parse) amrparse->ts = -1; * gst_amrparse_event: gst_amrparse_event (GstBaseParse * parse, GstEvent * event) amrparse->eos = TRUE; * gst_amrparse_convert: gst_amrparse_convert (GstBaseParse * parse, if (!amrparse->framecount) bpf = (gfloat) amrparse->bytecount / amrparse->framecount; if (amrparse->framecount) { *dest_value = AMR_FRAME_DURATION * src_value / bpf; *dest_value = bpf * src_value / AMR_FRAME_DURATION; GST_DEBUG ("time %lld ms in bytes = %lld", src_value / GST_MSECOND, *dest_value); *dest_value = src_value * AMR_FRAME_DURATION; return gst_element_register (plugin, "amrparse", GST_RANK_PRIMARY + 1, GST_TYPE_AMRPARSE); "amrparse", "Adaptive Multi-Rate Parser", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); --- NEW FILE: gstamrparse.h --- /* GStreamer Adaptive Multi-Rate parser * Copyright (C) 2004 Ronald Bultje <rb...@ro...> #ifndef __GST_AMRPARSE_H__ #define __GST_AMRPARSE_H__ #define GST_TYPE_AMRPARSE \ (gst_amrparse_get_type()) #define GST_AMRPARSE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_AMRPARSE, GstAmrParse)) #define GST_AMRPARSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_AMRPARSE, GstAmrParseClass)) #define GST_IS_AMRPARSE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_AMRPARSE)) #define GST_IS_AMRPARSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_AMRPARSE)) typedef struct _GstAmrParse GstAmrParse; typedef struct _GstAmrParseClass GstAmrParseClass; * GstAmrParse: * @block_size: Pointer to frame size lookup table. * @need_header: Tells whether the MIME header should be read in the beginning. * @wide: Wideband mode. * @eos: Indicates the EOS situation. Set when EOS event is received. * @sync: Tells whether the parser is in sync. * @framecount: Total amount of frames handled. * @bytecount: Total amount of bytes handled. * @ts: Timestamp of the current media. struct _GstAmrParse { const gint *block_size; gboolean need_header; gboolean wide; * GstAmrParseClass: * The opaque GstAmrParseClass data structure. struct _GstAmrParseClass { GType gst_amrparse_get_type (void); #endif /* __GST_AMRPARSE_H__ */ |