LCOV - code coverage report
Current view: top level - ext/mad - gstmad.c (source / functions) Hit Total Coverage
Test: GStreamer Ugly Plug-ins 0.10.17.1 Lines: 144 893 16.1 %
Date: 2011-03-25 Functions: 12 33 36.4 %
Branches: 17 710 2.4 %

           Branch data     Line data    Source code
       1                 :            : /* GStreamer
       2                 :            :  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
       3                 :            :  *
       4                 :            :  * This library is free software; you can redistribute it and/or
       5                 :            :  * modify it under the terms of the GNU Library General Public
       6                 :            :  * License as published by the Free Software Foundation; either
       7                 :            :  * version 2 of the License, or (at your option) any later version.
       8                 :            :  *
       9                 :            :  * This library is distributed in the hope that it will be useful,
      10                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12                 :            :  * Library General Public License for more details.
      13                 :            :  *
      14                 :            :  * You should have received a copy of the GNU Library General Public
      15                 :            :  * License along with this library; if not, write to the
      16                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      17                 :            :  * Boston, MA 02111-1307, USA.
      18                 :            :  */
      19                 :            : 
      20                 :            : /**
      21                 :            :  * SECTION:element-mad
      22                 :            :  * @see_also: lame
      23                 :            :  *
      24                 :            :  * MP3 audio decoder.
      25                 :            :  *
      26                 :            :  * <refsect2>
      27                 :            :  * <title>Example pipelines</title>
      28                 :            :  * |[
      29                 :            :  * gst-launch filesrc location=music.mp3 ! mad ! audioconvert ! audioresample ! autoaudiosink
      30                 :            :  * ]| Decode the mp3 file and play
      31                 :            :  * </refsect2>
      32                 :            :  */
      33                 :            : 
      34                 :            : #ifdef HAVE_CONFIG_H
      35                 :            : #include "config.h"
      36                 :            : #endif
      37                 :            : 
      38                 :            : #include <stdlib.h>
      39                 :            : #include <string.h>
      40                 :            : #include "gstmad.h"
      41                 :            : #include <gst/audio/audio.h>
      42                 :            : 
      43                 :            : #ifdef HAVE_ID3TAG
      44                 :            : #include <id3tag.h>
      45                 :            : #endif
      46                 :            : 
      47                 :            : enum
      48                 :            : {
      49                 :            :   ARG_0,
      50                 :            :   ARG_HALF,
      51                 :            :   ARG_IGNORE_CRC
      52                 :            : };
      53                 :            : 
      54                 :            : GST_DEBUG_CATEGORY_STATIC (mad_debug);
      55                 :            : #define GST_CAT_DEFAULT mad_debug
      56                 :            : 
      57                 :            : static GstStaticPadTemplate mad_src_template_factory =
      58                 :            : GST_STATIC_PAD_TEMPLATE ("src",
      59                 :            :     GST_PAD_SRC,
      60                 :            :     GST_PAD_ALWAYS,
      61                 :            :     GST_STATIC_CAPS ("audio/x-raw-int, "
      62                 :            :         "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
      63                 :            :         "signed = (boolean) true, "
      64                 :            :         "width = (int) 32, "
      65                 :            :         "depth = (int) 32, "
      66                 :            :         "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
      67                 :            :         "channels = (int) [ 1, 2 ]")
      68                 :            :     );
      69                 :            : 
      70                 :            : /* FIXME: make three caps, for mpegversion 1, 2 and 2.5 */
      71                 :            : static GstStaticPadTemplate mad_sink_template_factory =
      72                 :            : GST_STATIC_PAD_TEMPLATE ("sink",
      73                 :            :     GST_PAD_SINK,
      74                 :            :     GST_PAD_ALWAYS,
      75                 :            :     GST_STATIC_CAPS ("audio/mpeg, "
      76                 :            :         "mpegversion = (int) 1, "
      77                 :            :         "layer = (int) [ 1, 3 ], "
      78                 :            :         "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
      79                 :            :         "channels = (int) [ 1, 2 ]")
      80                 :            :     );
      81                 :            : 
      82                 :            : static void gst_mad_dispose (GObject * object);
      83                 :            : static void gst_mad_clear_queues (GstMad * mad);
      84                 :            : 
      85                 :            : static void gst_mad_set_property (GObject * object, guint prop_id,
      86                 :            :     const GValue * value, GParamSpec * pspec);
      87                 :            : static void gst_mad_get_property (GObject * object, guint prop_id,
      88                 :            :     GValue * value, GParamSpec * pspec);
      89                 :            : 
      90                 :            : static gboolean gst_mad_src_event (GstPad * pad, GstEvent * event);
      91                 :            : 
      92                 :            : static const GstQueryType *gst_mad_get_query_types (GstPad * pad);
      93                 :            : 
      94                 :            : static gboolean gst_mad_src_query (GstPad * pad, GstQuery * query);
      95                 :            : static gboolean gst_mad_convert_sink (GstPad * pad, GstFormat src_format,
      96                 :            :     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
      97                 :            : static gboolean gst_mad_convert_src (GstPad * pad, GstFormat src_format,
      98                 :            :     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
      99                 :            : 
     100                 :            : static gboolean gst_mad_sink_event (GstPad * pad, GstEvent * event);
     101                 :            : static GstFlowReturn gst_mad_chain (GstPad * pad, GstBuffer * buffer);
     102                 :            : static GstFlowReturn gst_mad_chain_reverse (GstMad * mad, GstBuffer * buf);
     103                 :            : 
     104                 :            : static GstStateChangeReturn gst_mad_change_state (GstElement * element,
     105                 :            :     GstStateChange transition);
     106                 :            : 
     107                 :            : static void gst_mad_set_index (GstElement * element, GstIndex * index);
     108                 :            : static GstIndex *gst_mad_get_index (GstElement * element);
     109                 :            : 
     110                 :            : #ifdef HAVE_ID3TAG
     111                 :            : static GstTagList *gst_mad_id3_to_tag_list (const struct id3_tag *tag);
     112                 :            : #endif
     113                 :            : 
     114         [ +  + ]:         50 : GST_BOILERPLATE (GstMad, gst_mad, GstElement, GST_TYPE_ELEMENT);
     115                 :            : 
     116                 :            : /*
     117                 :            : #define GST_TYPE_MAD_LAYER (gst_mad_layer_get_type())
     118                 :            : static GType
     119                 :            : gst_mad_layer_get_type (void)
     120                 :            : {
     121                 :            :   static GType mad_layer_type = 0;
     122                 :            :   static GEnumValue mad_layer[] = {
     123                 :            :     {0, "Unknown", "unknown"},
     124                 :            :     {MAD_LAYER_I, "Layer I", "1"},
     125                 :            :     {MAD_LAYER_II, "Layer II", "2"},
     126                 :            :     {MAD_LAYER_III, "Layer III", "3"},
     127                 :            :     {0, NULL, NULL},
     128                 :            :   };
     129                 :            : 
     130                 :            :   if (!mad_layer_type) {
     131                 :            :     mad_layer_type = g_enum_register_static ("GstMadLayer", mad_layer);
     132                 :            :   }
     133                 :            :   return mad_layer_type;
     134                 :            : }
     135                 :            : */
     136                 :            : 
     137                 :            : #define GST_TYPE_MAD_MODE (gst_mad_mode_get_type())
     138                 :            : static GType
     139                 :          5 : gst_mad_mode_get_type (void)
     140                 :            : {
     141                 :            :   static GType mad_mode_type = 0;
     142                 :            :   static GEnumValue mad_mode[] = {
     143                 :            :     {-1, "Unknown", "unknown"},
     144                 :            :     {MAD_MODE_SINGLE_CHANNEL, "Mono", "mono"},
     145                 :            :     {MAD_MODE_DUAL_CHANNEL, "Dual Channel", "dual"},
     146                 :            :     {MAD_MODE_JOINT_STEREO, "Joint Stereo", "joint"},
     147                 :            :     {MAD_MODE_STEREO, "Stereo", "stereo"},
     148                 :            :     {0, NULL, NULL},
     149                 :            :   };
     150                 :            : 
     151         [ +  - ]:          5 :   if (!mad_mode_type) {
     152                 :          5 :     mad_mode_type = g_enum_register_static ("GstMadMode", mad_mode);
     153                 :            :   }
     154                 :          5 :   return mad_mode_type;
     155                 :            : }
     156                 :            : 
     157                 :            : #define GST_TYPE_MAD_EMPHASIS (gst_mad_emphasis_get_type())
     158                 :            : static GType
     159                 :          5 : gst_mad_emphasis_get_type (void)
     160                 :            : {
     161                 :            :   static GType mad_emphasis_type = 0;
     162                 :            :   static GEnumValue mad_emphasis[] = {
     163                 :            :     {-1, "Unknown", "unknown"},
     164                 :            :     {MAD_EMPHASIS_NONE, "None", "none"},
     165                 :            :     {MAD_EMPHASIS_50_15_US, "50/15 Microseconds", "50-15"},
     166                 :            :     {MAD_EMPHASIS_CCITT_J_17, "CCITT J.17", "j-17"},
     167                 :            :     {MAD_EMPHASIS_RESERVED, "Reserved", "reserved"},
     168                 :            :     {0, NULL, NULL},
     169                 :            :   };
     170                 :            : 
     171         [ +  - ]:          5 :   if (!mad_emphasis_type) {
     172                 :          5 :     mad_emphasis_type = g_enum_register_static ("GstMadEmphasis", mad_emphasis);
     173                 :            :   }
     174                 :          5 :   return mad_emphasis_type;
     175                 :            : }
     176                 :            : 
     177                 :            : static void
     178                 :          5 : gst_mad_base_init (gpointer g_class)
     179                 :            : {
     180                 :          5 :   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
     181                 :            : 
     182                 :          5 :   gst_element_class_add_pad_template (element_class,
     183                 :            :       gst_static_pad_template_get (&mad_sink_template_factory));
     184                 :          5 :   gst_element_class_add_pad_template (element_class,
     185                 :            :       gst_static_pad_template_get (&mad_src_template_factory));
     186                 :          5 :   gst_element_class_set_details_simple (element_class, "mad mp3 decoder",
     187                 :            :       "Codec/Decoder/Audio",
     188                 :            :       "Uses mad code to decode mp3 streams", "Wim Taymans <wim@fluendo.com>");
     189                 :          5 : }
     190                 :            : 
     191                 :            : static void
     192                 :          5 : gst_mad_class_init (GstMadClass * klass)
     193                 :            : {
     194                 :            :   GObjectClass *gobject_class;
     195                 :            :   GstElementClass *gstelement_class;
     196                 :            : 
     197                 :          5 :   gobject_class = (GObjectClass *) klass;
     198                 :          5 :   gstelement_class = (GstElementClass *) klass;
     199                 :            : 
     200                 :          5 :   parent_class = g_type_class_peek_parent (klass);
     201                 :            : 
     202                 :          5 :   gobject_class->set_property = gst_mad_set_property;
     203                 :          5 :   gobject_class->get_property = gst_mad_get_property;
     204                 :          5 :   gobject_class->dispose = gst_mad_dispose;
     205                 :            : 
     206                 :          5 :   gstelement_class->change_state = gst_mad_change_state;
     207                 :          5 :   gstelement_class->set_index = gst_mad_set_index;
     208                 :          5 :   gstelement_class->get_index = gst_mad_get_index;
     209                 :            : 
     210                 :            :   /* init properties */
     211                 :            :   /* currently, string representations are used, we might want to change that */
     212                 :            :   /* FIXME: descriptions need to be more technical,
     213                 :            :    * default values and ranges need to be selected right */
     214                 :          5 :   g_object_class_install_property (gobject_class, ARG_HALF,
     215                 :            :       g_param_spec_boolean ("half", "Half", "Generate PCM at 1/2 sample rate",
     216                 :            :           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     217                 :          5 :   g_object_class_install_property (gobject_class, ARG_IGNORE_CRC,
     218                 :            :       g_param_spec_boolean ("ignore-crc", "Ignore CRC", "Ignore CRC errors",
     219                 :            :           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     220                 :            : 
     221                 :            :   /* register tags */
     222                 :            : #define GST_TAG_LAYER    "layer"
     223                 :            : #define GST_TAG_MODE     "mode"
     224                 :            : #define GST_TAG_EMPHASIS "emphasis"
     225                 :            : 
     226                 :            :   /* FIXME 0.11: strings!? why? */
     227                 :          5 :   gst_tag_register (GST_TAG_LAYER, GST_TAG_FLAG_ENCODED, G_TYPE_UINT,
     228                 :            :       "layer", "MPEG audio layer", NULL);
     229                 :          5 :   gst_tag_register (GST_TAG_MODE, GST_TAG_FLAG_ENCODED, G_TYPE_STRING,
     230                 :            :       "mode", "MPEG audio channel mode", NULL);
     231                 :          5 :   gst_tag_register (GST_TAG_EMPHASIS, GST_TAG_FLAG_ENCODED, G_TYPE_STRING,
     232                 :            :       "emphasis", "MPEG audio emphasis", NULL);
     233                 :            : 
     234                 :            :   /* ref these here from a thread-safe context (ie. not the streaming thread) */
     235                 :          5 :   g_type_class_ref (GST_TYPE_MAD_MODE);
     236                 :          5 :   g_type_class_ref (GST_TYPE_MAD_EMPHASIS);
     237                 :          5 : }
     238                 :            : 
     239                 :            : static void
     240                 :          3 : gst_mad_init (GstMad * mad, GstMadClass * klass)
     241                 :            : {
     242                 :            :   GstPadTemplate *template;
     243                 :            : 
     244                 :            :   /* create the sink and src pads */
     245                 :          3 :   template = gst_static_pad_template_get (&mad_sink_template_factory);
     246                 :          3 :   mad->sinkpad = gst_pad_new_from_template (template, "sink");
     247                 :          3 :   gst_object_unref (template);
     248                 :          3 :   gst_element_add_pad (GST_ELEMENT (mad), mad->sinkpad);
     249                 :          3 :   gst_pad_set_chain_function (mad->sinkpad, GST_DEBUG_FUNCPTR (gst_mad_chain));
     250                 :          3 :   gst_pad_set_event_function (mad->sinkpad,
     251                 :          3 :       GST_DEBUG_FUNCPTR (gst_mad_sink_event));
     252                 :            : 
     253                 :          3 :   template = gst_static_pad_template_get (&mad_src_template_factory);
     254                 :          3 :   mad->srcpad = gst_pad_new_from_template (template, "src");
     255                 :          3 :   gst_object_unref (template);
     256                 :          3 :   gst_element_add_pad (GST_ELEMENT (mad), mad->srcpad);
     257                 :          3 :   gst_pad_set_event_function (mad->srcpad,
     258                 :          3 :       GST_DEBUG_FUNCPTR (gst_mad_src_event));
     259                 :          3 :   gst_pad_set_query_function (mad->srcpad,
     260                 :          3 :       GST_DEBUG_FUNCPTR (gst_mad_src_query));
     261                 :          3 :   gst_pad_set_query_type_function (mad->srcpad,
     262                 :          3 :       GST_DEBUG_FUNCPTR (gst_mad_get_query_types));
     263                 :          3 :   gst_pad_use_fixed_caps (mad->srcpad);
     264                 :            : 
     265                 :          3 :   mad->tempbuffer = g_malloc (MAD_BUFFER_MDLEN * 3);
     266                 :          3 :   mad->tempsize = 0;
     267                 :          3 :   mad->base_byte_offset = 0;
     268                 :          3 :   mad->bytes_consumed = 0;
     269                 :          3 :   mad->total_samples = 0;
     270                 :          3 :   mad->new_header = TRUE;
     271                 :          3 :   mad->framecount = 0;
     272                 :          3 :   mad->vbr_average = 0;
     273                 :          3 :   mad->vbr_rate = 0;
     274                 :          3 :   mad->restart = TRUE;
     275                 :          3 :   mad->segment_start = 0;
     276                 :          3 :   gst_segment_init (&mad->segment, GST_FORMAT_TIME);
     277                 :          3 :   mad->header.mode = -1;
     278                 :          3 :   mad->header.emphasis = -1;
     279                 :          3 :   mad->tags = NULL;
     280                 :            : 
     281                 :          3 :   mad->half = FALSE;
     282                 :          3 :   mad->ignore_crc = TRUE;
     283                 :          3 :   mad->check_for_xing = TRUE;
     284                 :          3 :   mad->xing_found = FALSE;
     285                 :          3 : }
     286                 :            : 
     287                 :            : static void
     288                 :          3 : gst_mad_dispose (GObject * object)
     289                 :            : {
     290                 :          3 :   GstMad *mad = GST_MAD (object);
     291                 :            : 
     292                 :          3 :   gst_mad_set_index (GST_ELEMENT (object), NULL);
     293                 :            : 
     294                 :          3 :   g_free (mad->tempbuffer);
     295                 :          3 :   mad->tempbuffer = NULL;
     296                 :            : 
     297                 :          3 :   g_list_foreach (mad->pending_events, (GFunc) gst_mini_object_unref, NULL);
     298                 :          3 :   g_list_free (mad->pending_events);
     299                 :          3 :   mad->pending_events = NULL;
     300                 :            : 
     301                 :          3 :   G_OBJECT_CLASS (parent_class)->dispose (object);
     302                 :          3 : }
     303                 :            : 
     304                 :            : static void
     305                 :          3 : gst_mad_set_index (GstElement * element, GstIndex * index)
     306                 :            : {
     307                 :          3 :   GstMad *mad = GST_MAD (element);
     308                 :            : 
     309                 :          3 :   mad->index = index;
     310                 :            : 
     311         [ -  + ]:          3 :   if (index)
     312                 :          0 :     gst_index_get_writer_id (index, GST_OBJECT (element), &mad->index_id);
     313                 :          3 : }
     314                 :            : 
     315                 :            : static GstIndex *
     316                 :          0 : gst_mad_get_index (GstElement * element)
     317                 :            : {
     318                 :          0 :   GstMad *mad = GST_MAD (element);
     319                 :            : 
     320                 :          0 :   return mad->index;
     321                 :            : }
     322                 :            : 
     323                 :            : static gboolean
     324                 :          0 : gst_mad_convert_sink (GstPad * pad, GstFormat src_format, gint64 src_value,
     325                 :            :     GstFormat * dest_format, gint64 * dest_value)
     326                 :            : {
     327                 :          0 :   gboolean res = TRUE;
     328                 :            :   GstMad *mad;
     329                 :            : 
     330         [ #  # ]:          0 :   if (src_format == *dest_format) {
     331                 :          0 :     *dest_value = src_value;
     332                 :          0 :     return TRUE;
     333                 :            :   }
     334                 :            : 
     335                 :            :   /* -1 always maps to -1, and 0 to 0, we don't need any more info for that */
     336 [ #  # ][ #  # ]:          0 :   if (src_value == -1 || src_value == 0) {
     337                 :          0 :     *dest_value = src_value;
     338                 :          0 :     return TRUE;
     339                 :            :   }
     340                 :            : 
     341                 :          0 :   mad = GST_MAD (GST_PAD_PARENT (pad));
     342                 :            : 
     343         [ #  # ]:          0 :   if (mad->vbr_average == 0)
     344                 :          0 :     return FALSE;
     345                 :            : 
     346      [ #  #  # ]:          0 :   switch (src_format) {
     347                 :            :     case GST_FORMAT_BYTES:
     348         [ #  # ]:          0 :       switch (*dest_format) {
     349                 :            :         case GST_FORMAT_TIME:
     350                 :            :           /* multiply by 8 because vbr is in bits/second */
     351                 :          0 :           *dest_value = gst_util_uint64_scale (src_value, 8 * GST_SECOND,
     352                 :          0 :               mad->vbr_average);
     353                 :          0 :           break;
     354                 :            :         default:
     355                 :          0 :           res = FALSE;
     356                 :            :       }
     357                 :          0 :       break;
     358                 :            :     case GST_FORMAT_TIME:
     359         [ #  # ]:          0 :       switch (*dest_format) {
     360                 :            :         case GST_FORMAT_BYTES:
     361                 :            :           /* multiply by 8 because vbr is in bits/second */
     362                 :          0 :           *dest_value = gst_util_uint64_scale (src_value, mad->vbr_average,
     363                 :            :               8 * GST_SECOND);
     364                 :          0 :           break;
     365                 :            :         default:
     366                 :          0 :           res = FALSE;
     367                 :            :       }
     368                 :          0 :       break;
     369                 :            :     default:
     370                 :          0 :       res = FALSE;
     371                 :            :   }
     372                 :          0 :   return res;
     373                 :            : }
     374                 :            : 
     375                 :            : static gboolean
     376                 :          0 : gst_mad_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
     377                 :            :     GstFormat * dest_format, gint64 * dest_value)
     378                 :            : {
     379                 :          0 :   gboolean res = TRUE;
     380                 :          0 :   guint scale = 1;
     381                 :            :   gint bytes_per_sample;
     382                 :            :   GstMad *mad;
     383                 :            : 
     384         [ #  # ]:          0 :   if (src_format == *dest_format) {
     385                 :          0 :     *dest_value = src_value;
     386                 :          0 :     return TRUE;
     387                 :            :   }
     388                 :            : 
     389                 :            :   /* -1 always maps to -1, and 0 to 0, we don't need any more info for that */
     390 [ #  # ][ #  # ]:          0 :   if (src_value == -1 || src_value == 0) {
     391                 :          0 :     *dest_value = src_value;
     392                 :          0 :     return TRUE;
     393                 :            :   }
     394                 :            : 
     395                 :          0 :   mad = GST_MAD (GST_PAD_PARENT (pad));
     396                 :            : 
     397                 :          0 :   bytes_per_sample = mad->channels * 4;
     398                 :            : 
     399   [ #  #  #  # ]:          0 :   switch (src_format) {
     400                 :            :     case GST_FORMAT_BYTES:
     401      [ #  #  # ]:          0 :       switch (*dest_format) {
     402                 :            :         case GST_FORMAT_DEFAULT:
     403         [ #  # ]:          0 :           if (bytes_per_sample == 0)
     404                 :          0 :             return FALSE;
     405                 :          0 :           *dest_value = src_value / bytes_per_sample;
     406                 :          0 :           break;
     407                 :            :         case GST_FORMAT_TIME:
     408                 :            :         {
     409                 :          0 :           gint byterate = bytes_per_sample * mad->rate;
     410                 :            : 
     411         [ #  # ]:          0 :           if (byterate == 0)
     412                 :          0 :             return FALSE;
     413                 :          0 :           *dest_value =
     414                 :          0 :               gst_util_uint64_scale_int (src_value, GST_SECOND, byterate);
     415                 :          0 :           break;
     416                 :            :         }
     417                 :            :         default:
     418                 :          0 :           res = FALSE;
     419                 :            :       }
     420                 :          0 :       break;
     421                 :            :     case GST_FORMAT_DEFAULT:
     422      [ #  #  # ]:          0 :       switch (*dest_format) {
     423                 :            :         case GST_FORMAT_BYTES:
     424                 :          0 :           *dest_value = src_value * bytes_per_sample;
     425                 :          0 :           break;
     426                 :            :         case GST_FORMAT_TIME:
     427         [ #  # ]:          0 :           if (mad->rate == 0)
     428                 :          0 :             return FALSE;
     429                 :          0 :           *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
     430                 :            :               mad->rate);
     431                 :          0 :           break;
     432                 :            :         default:
     433                 :          0 :           res = FALSE;
     434                 :            :       }
     435                 :          0 :       break;
     436                 :            :     case GST_FORMAT_TIME:
     437      [ #  #  # ]:          0 :       switch (*dest_format) {
     438                 :            :         case GST_FORMAT_BYTES:
     439                 :          0 :           scale = bytes_per_sample;
     440                 :            :           /* fallthrough */
     441                 :            :         case GST_FORMAT_DEFAULT:
     442                 :          0 :           *dest_value = gst_util_uint64_scale_int (src_value,
     443                 :          0 :               scale * mad->rate, GST_SECOND);
     444                 :          0 :           break;
     445                 :            :         default:
     446                 :          0 :           res = FALSE;
     447                 :            :       }
     448                 :          0 :       break;
     449                 :            :     default:
     450                 :          0 :       res = FALSE;
     451                 :            :   }
     452                 :          0 :   return res;
     453                 :            : }
     454                 :            : 
     455                 :            : static const GstQueryType *
     456                 :          0 : gst_mad_get_query_types (GstPad * pad)
     457                 :            : {
     458                 :            :   static const GstQueryType gst_mad_src_query_types[] = {
     459                 :            :     GST_QUERY_POSITION,
     460                 :            :     GST_QUERY_DURATION,
     461                 :            :     GST_QUERY_CONVERT,
     462                 :            :     0
     463                 :            :   };
     464                 :            : 
     465                 :          0 :   return gst_mad_src_query_types;
     466                 :            : }
     467                 :            : 
     468                 :            : static gboolean
     469                 :          0 : gst_mad_src_query (GstPad * pad, GstQuery * query)
     470                 :            : {
     471                 :          0 :   gboolean res = TRUE;
     472                 :            :   GstPad *peer;
     473                 :            :   GstMad *mad;
     474                 :            : 
     475                 :          0 :   mad = GST_MAD (GST_PAD_PARENT (pad));
     476                 :            : 
     477                 :          0 :   peer = gst_pad_get_peer (mad->sinkpad);
     478                 :            : 
     479   [ #  #  #  #  :          0 :   switch (GST_QUERY_TYPE (query)) {
                      # ]
     480                 :            :     case GST_QUERY_FORMATS:
     481                 :          0 :       gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT, GST_FORMAT_TIME,
     482                 :            :           GST_FORMAT_BYTES);
     483                 :          0 :       break;
     484                 :            :     case GST_QUERY_POSITION:
     485                 :            :     {
     486                 :            :       GstFormat format;
     487                 :            :       gint64 cur;
     488                 :            : 
     489                 :            :       /* save requested format */
     490                 :          0 :       gst_query_parse_position (query, &format, NULL);
     491                 :            : 
     492                 :            :       /* try any demuxer before us first */
     493 [ #  # ][ #  # ]:          0 :       if (format == GST_FORMAT_TIME && peer && gst_pad_query (peer, query)) {
                 [ #  # ]
     494                 :          0 :         gst_query_parse_position (query, NULL, &cur);
     495 [ #  # ][ #  # ]:          0 :         GST_LOG_OBJECT (mad, "peer returned position %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     496                 :            :             GST_TIME_ARGS (cur));
     497                 :          0 :         break;
     498                 :            :       }
     499                 :            : 
     500                 :            :       /* and convert to the requested format */
     501         [ #  # ]:          0 :       if (format != GST_FORMAT_DEFAULT) {
     502         [ #  # ]:          0 :         if (!gst_mad_convert_src (pad, GST_FORMAT_DEFAULT, mad->total_samples,
     503                 :            :                 &format, &cur))
     504                 :          0 :           goto error;
     505                 :            :       } else {
     506                 :          0 :         cur = mad->total_samples;
     507                 :            :       }
     508                 :            : 
     509                 :          0 :       gst_query_set_position (query, format, cur);
     510                 :            : 
     511         [ #  # ]:          0 :       if (format == GST_FORMAT_TIME) {
     512 [ #  # ][ #  # ]:          0 :         GST_LOG ("position=%" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
         [ #  # ][ #  # ]
                 [ #  # ]
     513                 :            :       } else {
     514         [ #  # ]:          0 :         GST_LOG ("position=%" G_GINT64_FORMAT ", format=%u", cur, format);
     515                 :            :       }
     516                 :          0 :       break;
     517                 :            :     }
     518                 :            :     case GST_QUERY_DURATION:
     519                 :            :     {
     520                 :          0 :       GstFormat bytes_format = GST_FORMAT_BYTES;
     521                 :          0 :       GstFormat time_format = GST_FORMAT_TIME;
     522                 :            :       GstFormat req_format;
     523                 :            :       gint64 total, total_bytes;
     524                 :            : 
     525                 :            :       /* save requested format */
     526                 :          0 :       gst_query_parse_duration (query, &req_format, NULL);
     527                 :            : 
     528         [ #  # ]:          0 :       if (peer == NULL)
     529                 :          0 :         goto error;
     530                 :            : 
     531                 :            :       /* try any demuxer before us first */
     532 [ #  # ][ #  # ]:          0 :       if (req_format == GST_FORMAT_TIME && gst_pad_query (peer, query)) {
     533                 :          0 :         gst_query_parse_duration (query, NULL, &total);
     534 [ #  # ][ #  # ]:          0 :         GST_LOG_OBJECT (mad, "peer returned duration %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     535                 :            :             GST_TIME_ARGS (total));
     536                 :          0 :         break;
     537                 :            :       }
     538                 :            : 
     539                 :            :       /* query peer for total length in bytes */
     540         [ #  # ]:          0 :       if (!gst_pad_query_peer_duration (mad->sinkpad, &bytes_format,
     541         [ #  # ]:          0 :               &total_bytes) || total_bytes <= 0) {
     542         [ #  # ]:          0 :         GST_LOG_OBJECT (mad, "duration query on peer pad failed");
     543                 :          0 :         goto error;
     544                 :            :       }
     545                 :            : 
     546         [ #  # ]:          0 :       GST_LOG_OBJECT (mad, "peer pad returned total=%" G_GINT64_FORMAT
     547                 :            :           " bytes", total_bytes);
     548                 :            : 
     549         [ #  # ]:          0 :       if (!gst_mad_convert_sink (pad, GST_FORMAT_BYTES, total_bytes,
     550                 :            :               &time_format, &total)) {
     551         [ #  # ]:          0 :         GST_DEBUG_OBJECT (mad, "conversion BYTE => TIME failed");
     552                 :          0 :         goto error;
     553                 :            :       }
     554         [ #  # ]:          0 :       if (!gst_mad_convert_src (pad, GST_FORMAT_TIME, total,
     555                 :            :               &req_format, &total)) {
     556         [ #  # ]:          0 :         GST_DEBUG_OBJECT (mad, "conversion TIME => %s failed",
     557                 :            :             gst_format_get_name (req_format));
     558                 :          0 :         goto error;
     559                 :            :       }
     560                 :            : 
     561                 :          0 :       gst_query_set_duration (query, req_format, total);
     562                 :            : 
     563         [ #  # ]:          0 :       if (req_format == GST_FORMAT_TIME) {
     564 [ #  # ][ #  # ]:          0 :         GST_LOG_OBJECT (mad, "duration=%" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     565                 :            :             GST_TIME_ARGS (total));
     566                 :            :       } else {
     567         [ #  # ]:          0 :         GST_LOG_OBJECT (mad, "duration=%" G_GINT64_FORMAT " (%s)",
     568                 :            :             total, gst_format_get_name (req_format));
     569                 :            :       }
     570                 :          0 :       break;
     571                 :            :     }
     572                 :            :     case GST_QUERY_CONVERT:
     573                 :            :     {
     574                 :            :       GstFormat src_fmt, dest_fmt;
     575                 :            :       gint64 src_val, dest_val;
     576                 :            : 
     577                 :          0 :       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
     578         [ #  # ]:          0 :       if (!(res =
     579                 :          0 :               gst_mad_convert_src (pad, src_fmt, src_val, &dest_fmt,
     580                 :            :                   &dest_val)))
     581                 :          0 :         goto error;
     582                 :          0 :       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
     583                 :          0 :       break;
     584                 :            :     }
     585                 :            :     default:
     586                 :          0 :       res = gst_pad_query_default (pad, query);
     587                 :          0 :       break;
     588                 :            :   }
     589                 :            : 
     590         [ #  # ]:          0 :   if (peer)
     591                 :          0 :     gst_object_unref (peer);
     592                 :            : 
     593                 :          0 :   return res;
     594                 :            : 
     595                 :            : error:
     596                 :            : 
     597         [ #  # ]:          0 :   GST_DEBUG ("error handling query");
     598                 :            : 
     599         [ #  # ]:          0 :   if (peer)
     600                 :          0 :     gst_object_unref (peer);
     601                 :            : 
     602                 :          0 :   return FALSE;
     603                 :            : }
     604                 :            : 
     605                 :            : static gboolean
     606                 :          0 : index_seek (GstMad * mad, GstPad * pad, GstEvent * event)
     607                 :            : {
     608                 :            :   gdouble rate;
     609                 :            :   GstFormat format;
     610                 :            :   GstSeekFlags flags;
     611                 :            :   GstSeekType cur_type, stop_type;
     612                 :            :   gint64 cur, stop;
     613                 :          0 :   GstIndexEntry *entry = NULL;
     614                 :            : 
     615                 :            :   /* since we know the exact byteoffset of the frame,
     616                 :            :      make sure to try bytes first */
     617                 :            : 
     618                 :          0 :   const GstFormat try_all_formats[] = {
     619                 :            :     GST_FORMAT_BYTES,
     620                 :            :     GST_FORMAT_TIME,
     621                 :            :     0
     622                 :            :   };
     623                 :          0 :   const GstFormat *try_formats = try_all_formats;
     624                 :            :   const GstFormat *peer_formats;
     625                 :            : 
     626                 :          0 :   gst_event_parse_seek (event, &rate, &format, &flags,
     627                 :            :       &cur_type, &cur, &stop_type, &stop);
     628                 :            : 
     629         [ #  # ]:          0 :   if (rate < 0.0)
     630                 :          0 :     return FALSE;
     631                 :            : 
     632         [ #  # ]:          0 :   if (format == GST_FORMAT_TIME) {
     633                 :          0 :     gst_segment_set_seek (&mad->segment, rate, format, flags, cur_type,
     634                 :            :         cur, stop_type, stop, NULL);
     635                 :            :   } else {
     636                 :          0 :     gst_segment_init (&mad->segment, GST_FORMAT_UNDEFINED);
     637                 :            :   }
     638                 :            : 
     639                 :          0 :   entry = gst_index_get_assoc_entry (mad->index, mad->index_id,
     640                 :            :       GST_INDEX_LOOKUP_BEFORE, 0, format, cur);
     641                 :            : 
     642         [ #  # ]:          0 :   GST_DEBUG ("index seek");
     643                 :            : 
     644         [ #  # ]:          0 :   if (!entry)
     645                 :          0 :     return FALSE;
     646                 :            : 
     647                 :            : #if 0
     648                 :            :   peer_formats = gst_pad_get_formats (GST_PAD_PEER (mad->sinkpad));
     649                 :            : #else
     650                 :          0 :   peer_formats = try_all_formats;       /* FIXME */
     651                 :            : #endif
     652                 :            : 
     653         [ #  # ]:          0 :   while (gst_formats_contains (peer_formats, *try_formats)) {
     654                 :            :     gint64 value;
     655                 :            :     GstEvent *seek_event;
     656                 :            : 
     657         [ #  # ]:          0 :     if (gst_index_entry_assoc_map (entry, *try_formats, &value)) {
     658                 :            :       /* lookup succeeded, create the seek */
     659                 :            : 
     660         [ #  # ]:          0 :       GST_DEBUG ("index %s %" G_GINT64_FORMAT
     661                 :            :           " -> %s %" G_GINT64_FORMAT,
     662                 :            :           gst_format_get_details (format)->nick,
     663                 :            :           cur, gst_format_get_details (*try_formats)->nick, value);
     664                 :            : 
     665                 :          0 :       seek_event = gst_event_new_seek (rate, *try_formats, flags,
     666                 :            :           cur_type, value, stop_type, stop);
     667                 :            : 
     668         [ #  # ]:          0 :       if (gst_pad_send_event (GST_PAD_PEER (mad->sinkpad), seek_event)) {
     669                 :            :         /* seek worked, we're done, loop will exit */
     670                 :          0 :         mad->restart = TRUE;
     671         [ #  # ]:          0 :         g_assert (format == GST_FORMAT_TIME);
     672                 :          0 :         mad->segment_start = cur;
     673                 :          0 :         return TRUE;
     674                 :            :       }
     675                 :            :     }
     676                 :          0 :     try_formats++;
     677                 :            :   }
     678                 :            : 
     679                 :          0 :   return FALSE;
     680                 :            : }
     681                 :            : 
     682                 :            : static gboolean
     683                 :          0 : normal_seek (GstMad * mad, GstPad * pad, GstEvent * event)
     684                 :            : {
     685                 :            :   gdouble rate;
     686                 :            :   GstFormat format, conv;
     687                 :            :   GstSeekFlags flags;
     688                 :            :   GstSeekType cur_type, stop_type;
     689                 :            :   gint64 cur, stop;
     690                 :            :   gint64 time_cur, time_stop;
     691                 :            :   gint64 bytes_cur, bytes_stop;
     692                 :            :   gboolean flush;
     693                 :            : 
     694                 :            :   /* const GstFormat *peer_formats; */
     695                 :            :   gboolean res;
     696                 :            : 
     697         [ #  # ]:          0 :   GST_DEBUG ("normal seek");
     698                 :            : 
     699                 :          0 :   gst_event_parse_seek (event, &rate, &format, &flags,
     700                 :            :       &cur_type, &cur, &stop_type, &stop);
     701                 :            : 
     702         [ #  # ]:          0 :   if (rate < 0.0)
     703                 :          0 :     return FALSE;
     704                 :            : 
     705         [ #  # ]:          0 :   if (format != GST_FORMAT_TIME) {
     706                 :          0 :     conv = GST_FORMAT_TIME;
     707         [ #  # ]:          0 :     if (!gst_mad_convert_src (pad, format, cur, &conv, &time_cur))
     708                 :          0 :       goto convert_error;
     709         [ #  # ]:          0 :     if (!gst_mad_convert_src (pad, format, stop, &conv, &time_stop))
     710                 :          0 :       goto convert_error;
     711                 :            :   } else {
     712                 :          0 :     time_cur = cur;
     713                 :          0 :     time_stop = stop;
     714                 :            :   }
     715                 :            : 
     716                 :          0 :   gst_segment_set_seek (&mad->segment, rate, GST_FORMAT_TIME, flags, cur_type,
     717                 :            :       time_cur, stop_type, time_stop, NULL);
     718                 :            : 
     719 [ #  # ][ #  # ]:          0 :   GST_DEBUG ("seek to time %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     720                 :            :       GST_TIME_ARGS (time_cur), GST_TIME_ARGS (time_stop));
     721                 :            : 
     722                 :            :   /* shave off the flush flag, we'll need it later */
     723                 :          0 :   flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);
     724                 :            : 
     725                 :          0 :   conv = GST_FORMAT_BYTES;
     726         [ #  # ]:          0 :   if (!gst_mad_convert_sink (pad, GST_FORMAT_TIME, time_cur, &conv, &bytes_cur))
     727                 :          0 :     goto convert_error;
     728         [ #  # ]:          0 :   if (!gst_mad_convert_sink (pad, GST_FORMAT_TIME, time_stop, &conv,
     729                 :            :           &bytes_stop))
     730                 :          0 :     goto convert_error;
     731                 :            : 
     732                 :            :   {
     733                 :            :     GstEvent *seek_event;
     734                 :            : 
     735                 :            :     /* conversion succeeded, create the seek */
     736                 :          0 :     seek_event =
     737                 :          0 :         gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
     738                 :            :         bytes_cur, stop_type, bytes_stop);
     739                 :            : 
     740                 :            :     /* do the seek */
     741                 :          0 :     res = gst_pad_push_event (mad->sinkpad, seek_event);
     742                 :            : 
     743         [ #  # ]:          0 :     if (res) {
     744                 :            :       /* we need to break out of the processing loop on flush */
     745                 :          0 :       mad->restart = flush;
     746                 :          0 :       mad->segment_start = time_cur;
     747                 :          0 :       mad->last_ts = time_cur;
     748                 :            :     }
     749                 :            :   }
     750                 :            : #if 0
     751                 :            :   peer_formats = gst_pad_get_formats (GST_PAD_PEER (mad->sinkpad));
     752                 :            :   /* while we did not exhaust our seek formats without result */
     753                 :            :   while (peer_formats && *peer_formats && !res) {
     754                 :            :     gint64 desired_offset;
     755                 :            : 
     756                 :            :     format = *peer_formats;
     757                 :            : 
     758                 :            :     /* try to convert requested format to one we can seek with on the sinkpad */
     759                 :            :     if (gst_pad_convert (mad->sinkpad, GST_FORMAT_TIME, src_offset,
     760                 :            :             &format, &desired_offset)) {
     761                 :            :       GstEvent *seek_event;
     762                 :            : 
     763                 :            :       /* conversion succeeded, create the seek */
     764                 :            :       seek_event =
     765                 :            :           gst_event_new_seek (format | GST_EVENT_SEEK_METHOD (event) | flush,
     766                 :            :           desired_offset);
     767                 :            :       /* do the seek */
     768                 :            :       if (gst_pad_send_event (GST_PAD_PEER (mad->sinkpad), seek_event)) {
     769                 :            :         /* seek worked, we're done, loop will exit */
     770                 :            :         res = TRUE;
     771                 :            :       }
     772                 :            :     }
     773                 :            :     /* at this point, either the seek worked or res == FALSE */
     774                 :            :     if (res)
     775                 :            :       /* we need to break out of the processing loop on flush */
     776                 :            :       mad->restart = flush;
     777                 :            : 
     778                 :            :     peer_formats++;
     779                 :            :   }
     780                 :            : #endif
     781                 :            : 
     782                 :          0 :   return res;
     783                 :            : 
     784                 :            :   /* ERRORS */
     785                 :            : convert_error:
     786                 :            :   {
     787                 :            :     /* probably unsupported seek format */
     788         [ #  # ]:          0 :     GST_DEBUG ("failed to convert format %u into GST_FORMAT_TIME", format);
     789                 :          0 :     return FALSE;
     790                 :            :   }
     791                 :            : }
     792                 :            : 
     793                 :            : static gboolean
     794                 :          0 : gst_mad_src_event (GstPad * pad, GstEvent * event)
     795                 :            : {
     796                 :          0 :   gboolean res = TRUE;
     797                 :            :   GstMad *mad;
     798                 :            : 
     799                 :          0 :   mad = GST_MAD (GST_PAD_PARENT (pad));
     800                 :            : 
     801         [ #  # ]:          0 :   switch (GST_EVENT_TYPE (event)) {
     802                 :            :     case GST_EVENT_SEEK:
     803                 :            :       /* the all-formats seek logic, ref the event, we need it later */
     804                 :          0 :       gst_event_ref (event);
     805         [ #  # ]:          0 :       if (!(res = gst_pad_push_event (mad->sinkpad, event))) {
     806         [ #  # ]:          0 :         if (mad->index)
     807                 :          0 :           res = index_seek (mad, pad, event);
     808                 :            :         else
     809                 :          0 :           res = normal_seek (mad, pad, event);
     810                 :            :       }
     811                 :          0 :       gst_event_unref (event);
     812                 :          0 :       break;
     813                 :            :     default:
     814                 :          0 :       res = gst_pad_push_event (mad->sinkpad, event);
     815                 :          0 :       break;
     816                 :            :   }
     817                 :            : 
     818                 :          0 :   return res;
     819                 :            : }
     820                 :            : 
     821                 :            : static inline gint32
     822                 :          0 : scale (mad_fixed_t sample)
     823                 :            : {
     824                 :            : #if MAD_F_FRACBITS < 28
     825                 :            :   /* round */
     826                 :            :   sample += (1L << (28 - MAD_F_FRACBITS - 1));
     827                 :            : #endif
     828                 :            : 
     829                 :            :   /* clip */
     830         [ #  # ]:          0 :   if (sample >= MAD_F_ONE)
     831                 :          0 :     sample = MAD_F_ONE - 1;
     832         [ #  # ]:          0 :   else if (sample < -MAD_F_ONE)
     833                 :          0 :     sample = -MAD_F_ONE;
     834                 :            : 
     835                 :            : #if MAD_F_FRACBITS < 28
     836                 :            :   /* quantize */
     837                 :            :   sample >>= (28 - MAD_F_FRACBITS);
     838                 :            : #endif
     839                 :            : 
     840                 :            :   /* convert from 29 bits to 32 bits */
     841                 :          0 :   return (gint32) (sample << 3);
     842                 :            : }
     843                 :            : 
     844                 :            : /* do we need this function? */
     845                 :            : static void
     846                 :          0 : gst_mad_set_property (GObject * object, guint prop_id,
     847                 :            :     const GValue * value, GParamSpec * pspec)
     848                 :            : {
     849                 :            :   GstMad *mad;
     850                 :            : 
     851                 :          0 :   mad = GST_MAD (object);
     852                 :            : 
     853      [ #  #  # ]:          0 :   switch (prop_id) {
     854                 :            :     case ARG_HALF:
     855                 :          0 :       mad->half = g_value_get_boolean (value);
     856                 :          0 :       break;
     857                 :            :     case ARG_IGNORE_CRC:
     858                 :          0 :       mad->ignore_crc = g_value_get_boolean (value);
     859                 :          0 :       break;
     860                 :            :     default:
     861                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     862                 :          0 :       break;
     863                 :            :   }
     864                 :          0 : }
     865                 :            : 
     866                 :            : static void
     867                 :          0 : gst_mad_get_property (GObject * object, guint prop_id,
     868                 :            :     GValue * value, GParamSpec * pspec)
     869                 :            : {
     870                 :            :   GstMad *mad;
     871                 :            : 
     872                 :          0 :   mad = GST_MAD (object);
     873                 :            : 
     874      [ #  #  # ]:          0 :   switch (prop_id) {
     875                 :            :     case ARG_HALF:
     876                 :          0 :       g_value_set_boolean (value, mad->half);
     877                 :          0 :       break;
     878                 :            :     case ARG_IGNORE_CRC:
     879                 :          0 :       g_value_set_boolean (value, mad->ignore_crc);
     880                 :          0 :       break;
     881                 :            :     default:
     882                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     883                 :          0 :       break;
     884                 :            :   }
     885                 :          0 : }
     886                 :            : 
     887                 :            : static void
     888                 :          0 : gst_mad_update_info (GstMad * mad)
     889                 :            : {
     890                 :          0 :   struct mad_header *header = &mad->frame.header;
     891                 :          0 :   gboolean changed = FALSE;
     892                 :            : 
     893                 :            : #define CHECK_HEADER(h1,str)                                    \
     894                 :            : G_STMT_START{                                                   \
     895                 :            :   if (mad->header.h1 != header->h1 || mad->new_header) {        \
     896                 :            :     mad->header.h1 = header->h1;                                \
     897                 :            :      changed = TRUE;                                            \
     898                 :            :   };                                                            \
     899                 :            : } G_STMT_END
     900                 :            : 
     901                 :            :   /* update average bitrate */
     902         [ #  # ]:          0 :   if (mad->new_header) {
     903                 :          0 :     mad->framecount = 1;
     904                 :          0 :     mad->vbr_rate = header->bitrate;
     905                 :            :   } else {
     906                 :          0 :     mad->framecount++;
     907                 :          0 :     mad->vbr_rate += header->bitrate;
     908                 :            :   }
     909                 :          0 :   mad->vbr_average = (gint) (mad->vbr_rate / mad->framecount);
     910                 :            : 
     911 [ #  # ][ #  # ]:          0 :   CHECK_HEADER (layer, "layer");
     912 [ #  # ][ #  # ]:          0 :   CHECK_HEADER (mode, "mode");
     913 [ #  # ][ #  # ]:          0 :   CHECK_HEADER (emphasis, "emphasis");
     914                 :          0 :   mad->header.bitrate = header->bitrate;
     915                 :          0 :   mad->new_header = FALSE;
     916                 :            : 
     917         [ #  # ]:          0 :   if (changed) {
     918                 :            :     GstTagList *list;
     919                 :            :     GEnumValue *mode;
     920                 :            :     GEnumValue *emphasis;
     921                 :            : 
     922                 :          0 :     mode =
     923                 :          0 :         g_enum_get_value (g_type_class_peek (GST_TYPE_MAD_MODE),
     924                 :          0 :         mad->header.mode);
     925                 :          0 :     emphasis =
     926                 :          0 :         g_enum_get_value (g_type_class_peek (GST_TYPE_MAD_EMPHASIS),
     927                 :          0 :         mad->header.emphasis);
     928                 :          0 :     list = gst_tag_list_new ();
     929                 :          0 :     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
     930                 :          0 :         GST_TAG_LAYER, mad->header.layer,
     931                 :            :         GST_TAG_MODE, mode->value_nick,
     932                 :            :         GST_TAG_EMPHASIS, emphasis->value_nick, NULL);
     933         [ #  # ]:          0 :     if (!mad->framed) {
     934                 :            :       gchar *str;
     935                 :            : 
     936                 :          0 :       str = g_strdup_printf ("MPEG-1 layer %d", mad->header.layer);
     937                 :          0 :       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
     938                 :            :           GST_TAG_AUDIO_CODEC, str, NULL);
     939                 :          0 :       g_free (str);
     940                 :            :     }
     941         [ #  # ]:          0 :     if (!mad->xing_found) {
     942                 :          0 :       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
     943                 :            :           GST_TAG_BITRATE, mad->header.bitrate, NULL);
     944                 :            :     }
     945                 :          0 :     gst_element_post_message (GST_ELEMENT (mad),
     946                 :          0 :         gst_message_new_tag (GST_OBJECT (mad), list));
     947                 :            :   }
     948                 :            : #undef CHECK_HEADER
     949                 :            : 
     950                 :          0 : }
     951                 :            : 
     952                 :            : static gboolean
     953                 :          0 : gst_mad_sink_event (GstPad * pad, GstEvent * event)
     954                 :            : {
     955                 :          0 :   GstMad *mad = GST_MAD (GST_PAD_PARENT (pad));
     956                 :            :   gboolean result;
     957                 :            : 
     958         [ #  # ]:          0 :   GST_DEBUG ("handling %s event", GST_EVENT_TYPE_NAME (event));
     959                 :            : 
     960   [ #  #  #  #  :          0 :   switch (GST_EVENT_TYPE (event)) {
                      # ]
     961                 :            :     case GST_EVENT_NEWSEGMENT:{
     962                 :            :       GstFormat format;
     963                 :            :       gboolean update;
     964                 :            :       gdouble rate, applied_rate;
     965                 :            :       gint64 start, stop, pos;
     966                 :            : 
     967                 :          0 :       gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
     968                 :            :           &format, &start, &stop, &pos);
     969                 :            : 
     970         [ #  # ]:          0 :       if (format == GST_FORMAT_TIME) {
     971                 :            :         /* FIXME: is this really correct? */
     972                 :          0 :         mad->tempsize = 0;
     973                 :          0 :         result = gst_pad_push_event (mad->srcpad, event);
     974                 :            :         /* we don't need to restart when we get here */
     975                 :          0 :         mad->restart = FALSE;
     976                 :          0 :         mad->framed = TRUE;
     977                 :          0 :         gst_segment_set_newsegment_full (&mad->segment, update, rate,
     978                 :            :             applied_rate, GST_FORMAT_TIME, start, stop, pos);
     979                 :            :       } else {
     980         [ #  # ]:          0 :         GST_DEBUG ("dropping newsegment event in format %s",
     981                 :            :             gst_format_get_name (format));
     982                 :            :         /* on restart the chain function will generate a new
     983                 :            :          * newsegment event, so we can just drop this one */
     984                 :          0 :         mad->restart = TRUE;
     985                 :          0 :         gst_event_unref (event);
     986                 :          0 :         mad->tempsize = 0;
     987                 :          0 :         mad->framed = FALSE;
     988                 :          0 :         result = TRUE;
     989                 :            :       }
     990                 :          0 :       break;
     991                 :            :     }
     992                 :            :     case GST_EVENT_EOS:
     993         [ #  # ]:          0 :       if (mad->segment.rate < 0.0)
     994                 :          0 :         gst_mad_chain_reverse (mad, NULL);
     995                 :          0 :       mad->caps_set = FALSE;    /* could be a new stream */
     996                 :          0 :       result = gst_pad_push_event (mad->srcpad, event);
     997                 :          0 :       break;
     998                 :            :     case GST_EVENT_FLUSH_STOP:
     999                 :            :       /* Clear any stored data, as it won't make sense once
    1000                 :            :        * the new data arrives */
    1001                 :          0 :       mad->tempsize = 0;
    1002                 :          0 :       mad_frame_mute (&mad->frame);
    1003                 :          0 :       mad_synth_mute (&mad->synth);
    1004                 :          0 :       gst_mad_clear_queues (mad);
    1005                 :            :       /* fall-through */
    1006                 :            :     case GST_EVENT_FLUSH_START:
    1007                 :          0 :       result = gst_pad_event_default (pad, event);
    1008                 :          0 :       break;
    1009                 :            :     default:
    1010         [ #  # ]:          0 :       if (mad->restart) {
    1011                 :            :         /* Cache all other events if we still have to send a NEWSEGMENT */
    1012                 :          0 :         mad->pending_events = g_list_append (mad->pending_events, event);
    1013                 :          0 :         result = TRUE;
    1014                 :            :       } else {
    1015                 :          0 :         result = gst_pad_event_default (pad, event);
    1016                 :            :       }
    1017                 :          0 :       break;
    1018                 :            :   }
    1019                 :          0 :   return result;
    1020                 :            : }
    1021                 :            : 
    1022                 :            : static gboolean
    1023                 :          0 : gst_mad_check_restart (GstMad * mad)
    1024                 :            : {
    1025                 :          0 :   gboolean yes = mad->restart;
    1026                 :            : 
    1027         [ #  # ]:          0 :   if (mad->restart) {
    1028                 :          0 :     mad->restart = FALSE;
    1029                 :          0 :     mad->tempsize = 0;
    1030                 :            :   }
    1031                 :          0 :   return yes;
    1032                 :            : }
    1033                 :            : 
    1034                 :            : 
    1035                 :            : /* The following code has been taken from
    1036                 :            :  * rhythmbox/metadata/monkey-media/stream-info-impl/id3-vfs/mp3bitrate.c
    1037                 :            :  * which took it from xine-lib/src/demuxers/demux_mpgaudio.c
    1038                 :            :  * This code has been kindly relicensed to LGPL by Thibaut Mattern and
    1039                 :            :  * Bastien Nocera
    1040                 :            :  */
    1041                 :            : #define BE_32(x) GST_READ_UINT32_BE(x)
    1042                 :            : 
    1043                 :            : #define FOURCC_TAG( ch0, ch1, ch2, ch3 )                \
    1044                 :            :         ( (long)(unsigned char)(ch3) |                  \
    1045                 :            :           ( (long)(unsigned char)(ch2) << 8 ) |         \
    1046                 :            :           ( (long)(unsigned char)(ch1) << 16 ) |        \
    1047                 :            :           ( (long)(unsigned char)(ch0) << 24 ) )
    1048                 :            : 
    1049                 :            : /* Xing header stuff */
    1050                 :            : #define XING_TAG FOURCC_TAG('X', 'i', 'n', 'g')
    1051                 :            : #define XING_FRAMES_FLAG     0x0001
    1052                 :            : #define XING_BYTES_FLAG      0x0002
    1053                 :            : #define XING_TOC_FLAG        0x0004
    1054                 :            : #define XING_VBR_SCALE_FLAG  0x0008
    1055                 :            : #define XING_TOC_LENGTH      100
    1056                 :            : 
    1057                 :            : /* check for valid "Xing" VBR header */
    1058                 :            : static int
    1059                 :          0 : is_xhead (unsigned char *buf)
    1060                 :            : {
    1061                 :          0 :   return (BE_32 (buf) == XING_TAG);
    1062                 :            : }
    1063                 :            : 
    1064                 :            : 
    1065                 :            : #undef LOG
    1066                 :            : /*#define LOG*/
    1067                 :            : #ifdef LOG
    1068                 :            : #ifndef WIN32
    1069                 :            : #define lprintf(x...) g_print(x)
    1070                 :            : #else
    1071                 :            : #define lprintf GST_DEBUG
    1072                 :            : #endif
    1073                 :            : #else
    1074                 :            : #ifndef WIN32
    1075                 :            : #define lprintf(x...)
    1076                 :            : #else
    1077                 :            : #define lprintf GST_DEBUG
    1078                 :            : #endif
    1079                 :            : #endif
    1080                 :            : 
    1081                 :            : static int
    1082                 :          0 : mpg123_parse_xing_header (struct mad_header *header,
    1083                 :            :     const guint8 * buf, int bufsize, int *bitrate, int *time)
    1084                 :            : {
    1085                 :            :   int i;
    1086                 :          0 :   guint8 *ptr = (guint8 *) buf;
    1087                 :            :   double frame_duration;
    1088                 :            :   int xflags, xframes, xbytes;
    1089                 :            :   int abr;
    1090                 :            :   guint8 xtoc[XING_TOC_LENGTH];
    1091                 :          0 :   int lsf_bit = !(header->flags & MAD_FLAG_LSF_EXT);
    1092                 :            : 
    1093                 :          0 :   xframes = xbytes = 0;
    1094                 :            : 
    1095                 :            :   /* offset of the Xing header */
    1096         [ #  # ]:          0 :   if (lsf_bit) {
    1097         [ #  # ]:          0 :     if (header->mode != MAD_MODE_SINGLE_CHANNEL)
    1098                 :          0 :       ptr += (32 + 4);
    1099                 :            :     else
    1100                 :          0 :       ptr += (17 + 4);
    1101                 :            :   } else {
    1102         [ #  # ]:          0 :     if (header->mode != MAD_MODE_SINGLE_CHANNEL)
    1103                 :          0 :       ptr += (17 + 4);
    1104                 :            :     else
    1105                 :          0 :       ptr += (9 + 4);
    1106                 :            :   }
    1107                 :            : 
    1108         [ #  # ]:          0 :   if (ptr >= (buf + bufsize - 4))
    1109                 :          0 :     return 0;
    1110                 :            : 
    1111         [ #  # ]:          0 :   if (is_xhead (ptr)) {
    1112                 :            :     lprintf ("Xing header found\n");
    1113                 :            : 
    1114                 :          0 :     ptr += 4;
    1115         [ #  # ]:          0 :     if (ptr >= (buf + bufsize - 4))
    1116                 :          0 :       return 0;
    1117                 :            : 
    1118                 :          0 :     xflags = BE_32 (ptr);
    1119                 :          0 :     ptr += 4;
    1120                 :            : 
    1121         [ #  # ]:          0 :     if (xflags & XING_FRAMES_FLAG) {
    1122         [ #  # ]:          0 :       if (ptr >= (buf + bufsize - 4))
    1123                 :          0 :         return 0;
    1124                 :          0 :       xframes = BE_32 (ptr);
    1125                 :            :       lprintf ("xframes: %d\n", xframes);
    1126                 :          0 :       ptr += 4;
    1127                 :            :     }
    1128         [ #  # ]:          0 :     if (xflags & XING_BYTES_FLAG) {
    1129         [ #  # ]:          0 :       if (ptr >= (buf + bufsize - 4))
    1130                 :          0 :         return 0;
    1131                 :          0 :       xbytes = BE_32 (ptr);
    1132                 :            :       lprintf ("xbytes: %d\n", xbytes);
    1133                 :          0 :       ptr += 4;
    1134                 :            :     }
    1135         [ #  # ]:          0 :     if (xflags & XING_TOC_FLAG) {
    1136                 :          0 :       guchar old = 0;
    1137                 :            : 
    1138                 :            :       lprintf ("toc found\n");
    1139         [ #  # ]:          0 :       if (ptr >= (buf + bufsize - XING_TOC_LENGTH))
    1140                 :          0 :         return 0;
    1141         [ #  # ]:          0 :       if (*ptr != 0) {
    1142                 :            :         lprintf ("skipping broken Xing TOC\n");
    1143                 :          0 :         goto skip_toc;
    1144                 :            :       }
    1145         [ #  # ]:          0 :       for (i = 0; i < XING_TOC_LENGTH; i++) {
    1146                 :          0 :         xtoc[i] = *(ptr + i);
    1147         [ #  # ]:          0 :         if (old > xtoc[i]) {
    1148                 :            :           lprintf ("skipping broken Xing TOC\n");
    1149                 :          0 :           goto skip_toc;
    1150                 :            :         }
    1151                 :            :         lprintf ("%d ", xtoc[i]);
    1152                 :            :       }
    1153                 :            :       lprintf ("\n");
    1154                 :            :     skip_toc:
    1155                 :          0 :       ptr += XING_TOC_LENGTH;
    1156                 :            :     }
    1157                 :            : 
    1158         [ #  # ]:          0 :     if (xflags & XING_VBR_SCALE_FLAG) {
    1159         [ #  # ]:          0 :       if (ptr >= (buf + bufsize - 4))
    1160                 :          0 :         return 0;
    1161                 :            :       lprintf ("xvbr_scale: %d\n", BE_32 (ptr));
    1162                 :            :     }
    1163                 :            : 
    1164                 :            :     /* 1 kbit = 1000 bits ! (and not 1024 bits) */
    1165         [ #  # ]:          0 :     if (xflags & (XING_FRAMES_FLAG | XING_BYTES_FLAG)) {
    1166         [ #  # ]:          0 :       if (header->layer == MAD_LAYER_I) {
    1167                 :          0 :         frame_duration = 384.0 / (double) header->samplerate;
    1168                 :            :       } else {
    1169                 :            :         int slots_per_frame;
    1170                 :            : 
    1171                 :          0 :         slots_per_frame = ((header->layer == MAD_LAYER_III)
    1172 [ #  # ][ #  # ]:          0 :             && !lsf_bit) ? 72 : 144;
    1173                 :          0 :         frame_duration = slots_per_frame * 8.0 / (double) header->samplerate;
    1174                 :            :       }
    1175                 :          0 :       abr = ((double) xbytes * 8.0) / ((double) xframes * frame_duration);
    1176                 :            :       lprintf ("abr: %d bps\n", abr);
    1177         [ #  # ]:          0 :       if (bitrate != NULL) {
    1178                 :          0 :         *bitrate = abr;
    1179                 :            :       }
    1180         [ #  # ]:          0 :       if (time != NULL) {
    1181                 :          0 :         *time = (double) xframes *frame_duration;
    1182                 :            : 
    1183                 :            :         lprintf ("stream_length: %d s, %d min %d s\n", *time,
    1184                 :            :             *time / 60, *time % 60);
    1185                 :            :       }
    1186                 :            :     } else {
    1187                 :            :       /* it's a stupid Xing header */
    1188                 :            :       lprintf ("not a Xing VBR file\n");
    1189                 :            :     }
    1190                 :          0 :     return 1;
    1191                 :            :   } else {
    1192                 :            :     lprintf ("Xing header not found\n");
    1193                 :          0 :     return 0;
    1194                 :            :   }
    1195                 :            : }
    1196                 :            : 
    1197                 :            : /* End of Xine code */
    1198                 :            : 
    1199                 :            : /* internal function to check if the header has changed and thus the
    1200                 :            :  * caps need to be reset.  Only call during normal mode, not resyncing */
    1201                 :            : static void
    1202                 :          0 : gst_mad_check_caps_reset (GstMad * mad)
    1203                 :            : {
    1204                 :            :   guint nchannels;
    1205                 :          0 :   guint rate, old_rate = mad->rate;
    1206                 :            : 
    1207         [ #  # ]:          0 :   nchannels = MAD_NCHANNELS (&mad->frame.header);
    1208                 :            : 
    1209                 :            : #if MAD_VERSION_MINOR <= 12
    1210                 :            :   rate = mad->header.sfreq;
    1211                 :            : #else
    1212                 :          0 :   rate = mad->frame.header.samplerate;
    1213                 :            : #endif
    1214                 :            : 
    1215                 :            :   /* rate and channels are not supposed to change in a continuous stream,
    1216                 :            :    * so check this first before doing anything */
    1217                 :            : 
    1218                 :            :   /* only set caps if they weren't already set for this continuous stream */
    1219 [ #  # ][ #  # ]:          0 :   if (mad->channels != nchannels || mad->rate != rate) {
    1220         [ #  # ]:          0 :     if (mad->caps_set) {
    1221         [ #  # ]:          0 :       GST_DEBUG
    1222                 :            :           ("Header changed from %d Hz/%d ch to %d Hz/%d ch, failed sync after seek ?",
    1223                 :            :           mad->rate, mad->channels, rate, nchannels);
    1224                 :            :       /* we're conservative on stream changes. However, our *initial* caps
    1225                 :            :        * might have been wrong as well - mad ain't perfect in syncing. So,
    1226                 :            :        * we count caps changes and change if we pass a limit treshold (3). */
    1227 [ #  # ][ #  # ]:          0 :       if (nchannels != mad->pending_channels || rate != mad->pending_rate) {
    1228                 :          0 :         mad->times_pending = 0;
    1229                 :          0 :         mad->pending_channels = nchannels;
    1230                 :          0 :         mad->pending_rate = rate;
    1231                 :            :       }
    1232         [ #  # ]:          0 :       if (++mad->times_pending < 3)
    1233                 :          0 :         return;
    1234                 :            :     }
    1235                 :            :   }
    1236                 :          0 :   gst_mad_update_info (mad);
    1237                 :            : 
    1238 [ #  # ][ #  # ]:          0 :   if (mad->channels != nchannels || mad->rate != rate) {
    1239                 :            :     GstCaps *caps;
    1240                 :            : 
    1241         [ #  # ]:          0 :     if (mad->stream.options & MAD_OPTION_HALFSAMPLERATE)
    1242                 :          0 :       rate >>= 1;
    1243                 :            : 
    1244                 :            :     /* FIXME see if peer can accept the caps */
    1245                 :            : 
    1246                 :            :     /* we set the caps even when the pad is not connected so they
    1247                 :            :      * can be gotten for streaminfo */
    1248                 :          0 :     caps = gst_caps_new_simple ("audio/x-raw-int",
    1249                 :            :         "endianness", G_TYPE_INT, G_BYTE_ORDER,
    1250                 :            :         "signed", G_TYPE_BOOLEAN, TRUE,
    1251                 :            :         "width", G_TYPE_INT, 32,
    1252                 :            :         "depth", G_TYPE_INT, 32,
    1253                 :            :         "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, nchannels, NULL);
    1254                 :            : 
    1255                 :          0 :     gst_pad_set_caps (mad->srcpad, caps);
    1256                 :          0 :     gst_caps_unref (caps);
    1257                 :            : 
    1258                 :          0 :     mad->caps_set = TRUE;       /* set back to FALSE on discont */
    1259                 :          0 :     mad->channels = nchannels;
    1260                 :          0 :     mad->rate = rate;
    1261                 :            : 
    1262                 :            :     /* update sample count so we don't come up with crazy timestamps */
    1263 [ #  # ][ #  # ]:          0 :     if (mad->total_samples && old_rate) {
    1264                 :          0 :       mad->total_samples = mad->total_samples * rate / old_rate;
    1265                 :            :     }
    1266                 :            :   }
    1267                 :            : }
    1268                 :            : 
    1269                 :            : static void
    1270                 :          7 : gst_mad_clear_queues (GstMad * mad)
    1271                 :            : {
    1272                 :          7 :   g_list_foreach (mad->queued, (GFunc) gst_mini_object_unref, NULL);
    1273                 :          7 :   g_list_free (mad->queued);
    1274                 :          7 :   mad->queued = NULL;
    1275                 :          7 :   g_list_foreach (mad->gather, (GFunc) gst_mini_object_unref, NULL);
    1276                 :          7 :   g_list_free (mad->gather);
    1277                 :          7 :   mad->gather = NULL;
    1278                 :          7 :   g_list_foreach (mad->decode, (GFunc) gst_mini_object_unref, NULL);
    1279                 :          7 :   g_list_free (mad->decode);
    1280                 :          7 :   mad->decode = NULL;
    1281                 :          7 : }
    1282                 :            : 
    1283                 :            : static GstFlowReturn
    1284                 :          0 : gst_mad_flush_decode (GstMad * mad)
    1285                 :            : {
    1286                 :          0 :   GstFlowReturn res = GST_FLOW_OK;
    1287                 :            :   GList *walk;
    1288                 :            : 
    1289                 :          0 :   walk = mad->decode;
    1290                 :            : 
    1291         [ #  # ]:          0 :   GST_DEBUG_OBJECT (mad, "flushing buffers to decoder");
    1292                 :            : 
    1293                 :            :   /* clear buffer and decoder state */
    1294                 :          0 :   mad->tempsize = 0;
    1295                 :          0 :   mad_frame_mute (&mad->frame);
    1296                 :          0 :   mad_synth_mute (&mad->synth);
    1297                 :            : 
    1298                 :          0 :   mad->process = TRUE;
    1299         [ #  # ]:          0 :   while (walk) {
    1300                 :            :     GList *next;
    1301                 :          0 :     GstBuffer *buf = GST_BUFFER_CAST (walk->data);
    1302                 :            : 
    1303 [ #  # ][ #  # ]:          0 :     GST_DEBUG_OBJECT (mad, "decoding buffer %p, ts %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
    1304                 :            :         buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
    1305                 :            : 
    1306         [ #  # ]:          0 :     next = g_list_next (walk);
    1307                 :            :     /* decode buffer, resulting data prepended to output queue */
    1308                 :          0 :     gst_buffer_ref (buf);
    1309                 :          0 :     res = gst_mad_chain (mad->sinkpad, buf);
    1310                 :            : 
    1311                 :            :     /* if we generated output, we can discard the buffer, else we
    1312                 :            :      * keep it in the queue */
    1313         [ #  # ]:          0 :     if (mad->queued) {
    1314         [ #  # ]:          0 :       GST_DEBUG_OBJECT (mad, "decoded buffer to %p", mad->queued->data);
    1315                 :          0 :       mad->decode = g_list_delete_link (mad->decode, walk);
    1316                 :          0 :       gst_buffer_unref (buf);
    1317                 :            :     } else {
    1318         [ #  # ]:          0 :       GST_DEBUG_OBJECT (mad, "buffer did not decode, keeping");
    1319                 :            :     }
    1320                 :          0 :     walk = next;
    1321                 :            :   }
    1322                 :          0 :   mad->process = FALSE;
    1323                 :            : 
    1324                 :            :   /* now send queued data downstream */
    1325         [ #  # ]:          0 :   while (mad->queued) {
    1326                 :          0 :     GstBuffer *buf = GST_BUFFER_CAST (mad->queued->data);
    1327                 :            : 
    1328 [ #  # ][ #  # ]:          0 :     GST_DEBUG_OBJECT (mad, "pushing buffer %p of size %u, "
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1329                 :            :         "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
    1330                 :            :         GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
    1331                 :            :         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
    1332                 :          0 :     res = gst_pad_push (mad->srcpad, buf);
    1333                 :            : 
    1334                 :          0 :     mad->queued = g_list_delete_link (mad->queued, mad->queued);
    1335                 :            :   }
    1336                 :            : 
    1337                 :          0 :   return res;
    1338                 :            : }
    1339                 :            : 
    1340                 :            : static GstFlowReturn
    1341                 :          0 : gst_mad_chain_reverse (GstMad * mad, GstBuffer * buf)
    1342                 :            : {
    1343                 :          0 :   GstFlowReturn result = GST_FLOW_OK;
    1344                 :            : 
    1345                 :            :   /* if we have a discont, move buffers to the decode list */
    1346 [ #  # ][ #  # ]:          0 :   if (!buf || GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
    1347         [ #  # ]:          0 :     GST_DEBUG_OBJECT (mad, "received discont");
    1348         [ #  # ]:          0 :     while (mad->gather) {
    1349                 :            :       GstBuffer *gbuf;
    1350                 :            : 
    1351                 :          0 :       gbuf = GST_BUFFER_CAST (mad->gather->data);
    1352                 :            :       /* remove from the gather list */
    1353                 :          0 :       mad->gather = g_list_delete_link (mad->gather, mad->gather);
    1354                 :            :       /* copy to decode queue */
    1355                 :          0 :       mad->decode = g_list_prepend (mad->decode, gbuf);
    1356                 :            :     }
    1357                 :            :     /* decode stuff in the decode queue */
    1358                 :          0 :     gst_mad_flush_decode (mad);
    1359                 :            :   }
    1360                 :            : 
    1361         [ #  # ]:          0 :   if (G_LIKELY (buf)) {
    1362 [ #  # ][ #  # ]:          0 :     GST_DEBUG_OBJECT (mad, "gathering buffer %p of size %u, "
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1363                 :            :         "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
    1364                 :            :         GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
    1365                 :            :         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
    1366                 :            : 
    1367                 :            :     /* add buffer to gather queue */
    1368                 :          0 :     mad->gather = g_list_prepend (mad->gather, buf);
    1369                 :            :   }
    1370                 :            : 
    1371                 :          0 :   return result;
    1372                 :            : }
    1373                 :            : 
    1374                 :            : static GstFlowReturn
    1375                 :          0 : gst_mad_chain (GstPad * pad, GstBuffer * buffer)
    1376                 :            : {
    1377                 :            :   GstMad *mad;
    1378                 :            :   guint8 *data;
    1379                 :            :   glong size, tempsize;
    1380                 :          0 :   gboolean new_pts = FALSE;
    1381                 :            :   gboolean discont;
    1382                 :            :   GstClockTime timestamp;
    1383                 :          0 :   GstFlowReturn result = GST_FLOW_OK;
    1384                 :            : 
    1385                 :          0 :   mad = GST_MAD (GST_PAD_PARENT (pad));
    1386                 :            : 
    1387                 :            :   /* restarts happen on discontinuities, ie. seek, flush, PAUSED to PLAYING */
    1388         [ #  # ]:          0 :   if (gst_mad_check_restart (mad)) {
    1389                 :          0 :     mad->need_newsegment = TRUE;
    1390         [ #  # ]:          0 :     GST_DEBUG ("mad restarted");
    1391                 :            :   }
    1392                 :            : 
    1393         [ #  # ]:          0 :   if (mad->segment.rate < 0.0) {
    1394         [ #  # ]:          0 :     if (!mad->process)
    1395                 :          0 :       return gst_mad_chain_reverse (mad, buffer);
    1396                 :            :     /* no output discont */
    1397                 :          0 :     discont = FALSE;
    1398                 :            :   } else {
    1399                 :            :     /* take discont flag */
    1400                 :          0 :     discont = GST_BUFFER_IS_DISCONT (buffer);
    1401                 :            :   }
    1402                 :            : 
    1403                 :          0 :   timestamp = GST_BUFFER_TIMESTAMP (buffer);
    1404 [ #  # ][ #  # ]:          0 :   GST_DEBUG ("mad in timestamp %" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1405                 :            :       GST_TIME_ARGS (timestamp), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
    1406                 :            : 
    1407                 :            :   /* handle timestamps */
    1408         [ #  # ]:          0 :   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
    1409                 :            :     /* if there is nothing left to process in our temporary buffer,
    1410                 :            :      * we can set this timestamp on the next outgoing buffer */
    1411         [ #  # ]:          0 :     if (mad->tempsize == 0) {
    1412                 :            :       /* we have to save the result here because we can't yet convert
    1413                 :            :        * the timestamp to a sample offset, as the samplerate might not
    1414                 :            :        * be known yet */
    1415                 :          0 :       mad->last_ts = timestamp;
    1416                 :          0 :       mad->base_byte_offset = GST_BUFFER_OFFSET (buffer);
    1417                 :          0 :       mad->bytes_consumed = 0;
    1418                 :            :     }
    1419                 :            :     /* else we need to finish the current partial frame with the old timestamp
    1420                 :            :      * and queue this timestamp for the next frame */
    1421                 :            :     else {
    1422                 :          0 :       new_pts = TRUE;
    1423                 :            :     }
    1424                 :            :   }
    1425 [ #  # ][ #  # ]:          0 :   GST_DEBUG ("last_ts %" GST_TIME_FORMAT, GST_TIME_ARGS (mad->last_ts));
         [ #  # ][ #  # ]
                 [ #  # ]
    1426                 :            : 
    1427                 :            :   /* handle data */
    1428                 :          0 :   data = GST_BUFFER_DATA (buffer);
    1429                 :          0 :   size = GST_BUFFER_SIZE (buffer);
    1430                 :            : 
    1431                 :          0 :   tempsize = mad->tempsize;
    1432                 :            : 
    1433                 :            :   /* process the incoming buffer in chunks of maximum MAD_BUFFER_MDLEN bytes;
    1434                 :            :    * this is the upper limit on processable chunk sizes set by mad */
    1435         [ #  # ]:          0 :   while (size > 0) {
    1436                 :            :     gint tocopy;
    1437                 :            :     guchar *mad_input_buffer;   /* convenience pointer to tempbuffer */
    1438                 :            : 
    1439 [ #  # ][ #  # ]:          0 :     if (mad->tempsize == 0 && discont) {
    1440                 :          0 :       mad->discont = TRUE;
    1441                 :          0 :       discont = FALSE;
    1442                 :            :     }
    1443                 :          0 :     tocopy =
    1444                 :          0 :         MIN (MAD_BUFFER_MDLEN, MIN (size,
    1445                 :            :             MAD_BUFFER_MDLEN * 3 - mad->tempsize));
    1446         [ #  # ]:          0 :     if (tocopy == 0) {
    1447 [ #  # ][ #  # ]:          0 :       GST_ELEMENT_ERROR (mad, STREAM, DECODE, (NULL),
         [ #  # ][ #  # ]
    1448                 :            :           ("mad claims to need more data than %u bytes, we don't have that much",
    1449                 :            :               MAD_BUFFER_MDLEN * 3));
    1450                 :          0 :       result = GST_FLOW_ERROR;
    1451                 :          0 :       goto end;
    1452                 :            :     }
    1453                 :            : 
    1454                 :            :     /* append the chunk to process to our internal temporary buffer */
    1455         [ #  # ]:          0 :     GST_LOG ("tempbuffer size %ld, copying %d bytes from incoming buffer",
    1456                 :            :         mad->tempsize, tocopy);
    1457                 :          0 :     memcpy (mad->tempbuffer + mad->tempsize, data, tocopy);
    1458                 :          0 :     mad->tempsize += tocopy;
    1459                 :            : 
    1460                 :            :     /* update our incoming buffer's parameters to reflect this */
    1461                 :          0 :     size -= tocopy;
    1462                 :          0 :     data += tocopy;
    1463                 :            : 
    1464                 :          0 :     mad_input_buffer = mad->tempbuffer;
    1465                 :            : 
    1466                 :            :     /* while we have data we can consume it */
    1467         [ #  # ]:          0 :     while (mad->tempsize > 0) {
    1468                 :          0 :       gint consumed = 0;
    1469                 :            :       guint nsamples;
    1470                 :          0 :       guint64 time_offset = GST_CLOCK_TIME_NONE;
    1471                 :          0 :       guint64 time_duration = GST_CLOCK_TIME_NONE;
    1472                 :            :       unsigned char const *before_sync, *after_sync;
    1473                 :          0 :       gboolean goto_exit = FALSE;
    1474                 :            : 
    1475                 :          0 :       mad->in_error = FALSE;
    1476                 :            : 
    1477                 :          0 :       mad_stream_buffer (&mad->stream, mad_input_buffer, mad->tempsize);
    1478                 :            : 
    1479                 :            :       /* added separate header decoding to catch errors earlier, also fixes
    1480                 :            :        * some weird decoding errors... */
    1481         [ #  # ]:          0 :       GST_LOG ("decoding the header now");
    1482         [ #  # ]:          0 :       if (mad_header_decode (&mad->frame.header, &mad->stream) == -1) {
    1483         [ #  # ]:          0 :         if (mad->stream.error == MAD_ERROR_BUFLEN) {
    1484         [ #  # ]:          0 :           GST_LOG ("not enough data in tempbuffer (%ld), breaking to get more",
    1485                 :            :               mad->tempsize);
    1486                 :          0 :           break;
    1487                 :            :         } else {
    1488         [ #  # ]:          0 :           GST_WARNING ("mad_header_decode had an error: %s",
    1489                 :            :               mad_stream_errorstr (&mad->stream));
    1490                 :            :         }
    1491                 :            :       }
    1492                 :            : 
    1493         [ #  # ]:          0 :       GST_LOG ("decoding one frame now");
    1494                 :            : 
    1495         [ #  # ]:          0 :       if (mad_frame_decode (&mad->frame, &mad->stream) == -1) {
    1496         [ #  # ]:          0 :         GST_LOG ("got error %d", mad->stream.error);
    1497                 :            : 
    1498                 :            :         /* not enough data, need to wait for next buffer? */
    1499         [ #  # ]:          0 :         if (mad->stream.error == MAD_ERROR_BUFLEN) {
    1500         [ #  # ]:          0 :           if (mad->stream.next_frame == mad_input_buffer) {
    1501         [ #  # ]:          0 :             GST_LOG
    1502                 :            :                 ("not enough data in tempbuffer (%ld), breaking to get more",
    1503                 :            :                 mad->tempsize);
    1504                 :          0 :             break;
    1505                 :            :           } else {
    1506         [ #  # ]:          0 :             GST_LOG ("sync error, flushing unneeded data");
    1507                 :          0 :             goto next_no_samples;
    1508                 :            :           }
    1509         [ #  # ]:          0 :         } else if (mad->stream.error == MAD_ERROR_BADDATAPTR) {
    1510                 :            :           /* Flush data */
    1511                 :          0 :           goto next_no_samples;
    1512                 :            :         }
    1513                 :            :         /* we are in an error state */
    1514                 :          0 :         mad->in_error = TRUE;
    1515         [ #  # ]:          0 :         GST_WARNING ("mad_frame_decode had an error: %s",
    1516                 :            :             mad_stream_errorstr (&mad->stream));
    1517         [ #  # ]:          0 :         if (!MAD_RECOVERABLE (mad->stream.error)) {
    1518 [ #  # ][ #  # ]:          0 :           GST_ELEMENT_ERROR (mad, STREAM, DECODE, (NULL), (NULL));
         [ #  # ][ #  # ]
    1519                 :          0 :           result = GST_FLOW_ERROR;
    1520                 :          0 :           goto end;
    1521         [ #  # ]:          0 :         } else if (mad->stream.error == MAD_ERROR_LOSTSYNC) {
    1522                 :            :           /* lost sync, force a resync */
    1523         [ #  # ]:          0 :           GST_INFO ("recoverable lost sync error");
    1524                 :            : 
    1525                 :            : #ifdef HAVE_ID3TAG
    1526                 :            :           {
    1527                 :            :             signed long tagsize;
    1528                 :            : 
    1529                 :          0 :             tagsize = id3_tag_query (mad->stream.this_frame,
    1530                 :          0 :                 mad->stream.bufend - mad->stream.this_frame);
    1531                 :            : 
    1532         [ #  # ]:          0 :             if (tagsize > mad->tempsize) {
    1533         [ #  # ]:          0 :               GST_INFO ("mad: got partial id3 tag in buffer, skipping");
    1534         [ #  # ]:          0 :             } else if (tagsize > 0) {
    1535                 :            :               struct id3_tag *tag;
    1536                 :            :               id3_byte_t const *data;
    1537                 :            : 
    1538         [ #  # ]:          0 :               GST_INFO ("mad: got ID3 tag size %ld", tagsize);
    1539                 :            : 
    1540                 :          0 :               data = mad->stream.this_frame;
    1541                 :            : 
    1542                 :            :               /* mad has moved the pointer to the next frame over the start of the
    1543                 :            :                * id3 tags, so we need to flush one byte less than the tagsize */
    1544                 :          0 :               mad_stream_skip (&mad->stream, tagsize - 1);
    1545                 :            : 
    1546                 :          0 :               tag = id3_tag_parse (data, tagsize);
    1547         [ #  # ]:          0 :               if (tag) {
    1548                 :            :                 GstTagList *list;
    1549                 :            : 
    1550                 :          0 :                 list = gst_mad_id3_to_tag_list (tag);
    1551                 :          0 :                 id3_tag_delete (tag);
    1552         [ #  # ]:          0 :                 GST_DEBUG ("found tag");
    1553                 :          0 :                 gst_element_post_message (GST_ELEMENT (mad),
    1554                 :          0 :                     gst_message_new_tag (GST_OBJECT (mad),
    1555                 :            :                         gst_tag_list_copy (list)));
    1556         [ #  # ]:          0 :                 if (mad->tags) {
    1557                 :          0 :                   gst_tag_list_insert (mad->tags, list, GST_TAG_MERGE_PREPEND);
    1558                 :            :                 } else {
    1559                 :          0 :                   mad->tags = gst_tag_list_copy (list);
    1560                 :            :                 }
    1561         [ #  # ]:          0 :                 if (mad->need_newsegment)
    1562                 :          0 :                   mad->pending_events =
    1563                 :          0 :                       g_list_append (mad->pending_events,
    1564                 :          0 :                       gst_event_new_tag (list));
    1565                 :            :                 else
    1566                 :          0 :                   gst_pad_push_event (mad->srcpad, gst_event_new_tag (list));
    1567                 :            :               }
    1568                 :            :             }
    1569                 :            :           }
    1570                 :            : #endif /* HAVE_ID3TAG */
    1571                 :            :         }
    1572                 :            : 
    1573                 :          0 :         mad_frame_mute (&mad->frame);
    1574                 :          0 :         mad_synth_mute (&mad->synth);
    1575                 :          0 :         before_sync = mad->stream.ptr.byte;
    1576         [ #  # ]:          0 :         if (mad_stream_sync (&mad->stream) != 0)
    1577         [ #  # ]:          0 :           GST_WARNING ("mad_stream_sync failed");
    1578                 :          0 :         after_sync = mad->stream.ptr.byte;
    1579                 :            :         /* a succesful resync should make us drop bytes as consumed, so
    1580                 :            :            calculate from the byte pointers before and after resync */
    1581                 :          0 :         consumed = after_sync - before_sync;
    1582         [ #  # ]:          0 :         GST_DEBUG ("resynchronization consumes %d bytes", consumed);
    1583         [ #  # ]:          0 :         GST_DEBUG ("synced to data: 0x%0x 0x%0x", *mad->stream.ptr.byte,
    1584                 :            :             *(mad->stream.ptr.byte + 1));
    1585                 :            : 
    1586                 :          0 :         mad_stream_sync (&mad->stream);
    1587                 :            :         /* recoverable errors pass */
    1588                 :          0 :         goto next_no_samples;
    1589                 :            :       }
    1590                 :            : 
    1591         [ #  # ]:          0 :       if (mad->check_for_xing) {
    1592                 :          0 :         int bitrate = 0, time = 0;
    1593                 :            :         GstTagList *list;
    1594                 :          0 :         int frame_len = mad->stream.next_frame - mad->stream.this_frame;
    1595                 :            : 
    1596                 :          0 :         mad->check_for_xing = FALSE;
    1597                 :            : 
    1598                 :            :         /* Assume Xing headers can only be the first frame in a mp3 file */
    1599         [ #  # ]:          0 :         if (mpg123_parse_xing_header (&mad->frame.header,
    1600                 :          0 :                 mad->stream.this_frame, frame_len, &bitrate, &time)) {
    1601                 :          0 :           mad->xing_found = TRUE;
    1602                 :          0 :           list = gst_tag_list_new ();
    1603                 :          0 :           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
    1604                 :          0 :               GST_TAG_DURATION, (gint64) time * 1000 * 1000 * 1000,
    1605                 :            :               GST_TAG_BITRATE, bitrate, NULL);
    1606                 :          0 :           gst_element_post_message (GST_ELEMENT (mad),
    1607                 :          0 :               gst_message_new_tag (GST_OBJECT (mad), gst_tag_list_copy (list)));
    1608                 :            : 
    1609         [ #  # ]:          0 :           if (mad->need_newsegment)
    1610                 :          0 :             mad->pending_events =
    1611                 :          0 :                 g_list_append (mad->pending_events, gst_event_new_tag (list));
    1612                 :            :           else
    1613                 :          0 :             gst_pad_push_event (mad->srcpad, gst_event_new_tag (list));
    1614                 :            : 
    1615                 :          0 :           goto next_no_samples;
    1616                 :            :         }
    1617                 :            :       }
    1618                 :            : 
    1619                 :            :       /* if we're not resyncing/in error, check if caps need to be set again */
    1620         [ #  # ]:          0 :       if (!mad->in_error)
    1621                 :          0 :         gst_mad_check_caps_reset (mad);
    1622 [ #  # ][ #  # ]:          0 :       nsamples = MAD_NSBSAMPLES (&mad->frame.header) *
                 [ #  # ]
    1623         [ #  # ]:          0 :           (mad->stream.options & MAD_OPTION_HALFSAMPLERATE ? 16 : 32);
    1624                 :            : 
    1625         [ #  # ]:          0 :       if (mad->rate == 0) {
    1626                 :          0 :         g_warning ("mad->rate is 0; timestamps cannot be calculated");
    1627                 :            :       } else {
    1628                 :            :         /* if we have a pending timestamp, we can use it now to calculate the sample offset */
    1629         [ #  # ]:          0 :         if (GST_CLOCK_TIME_IS_VALID (mad->last_ts)) {
    1630                 :          0 :           GstFormat format = GST_FORMAT_DEFAULT;
    1631                 :            :           gint64 total;
    1632                 :            : 
    1633                 :            :           /* Convert incoming timestamp to a number of encoded samples */
    1634                 :          0 :           gst_pad_query_convert (mad->srcpad, GST_FORMAT_TIME, mad->last_ts,
    1635                 :            :               &format, &total);
    1636                 :            : 
    1637         [ #  # ]:          0 :           GST_DEBUG_OBJECT (mad, "calculated samples offset from ts is %"
    1638                 :            :               G_GUINT64_FORMAT " accumulated samples offset is %"
    1639                 :            :               G_GUINT64_FORMAT, total, mad->total_samples);
    1640                 :            : 
    1641                 :            :           /* We are using the incoming timestamps to generate the outgoing ones
    1642                 :            :            * if available. However some muxing formats are not precise enough
    1643                 :            :            * to allow us to generate a perfect stream. When converting the
    1644                 :            :            * timestamp to a number of encoded samples so far we are introducing
    1645                 :            :            * a lot of potential error compared to our accumulated number of
    1646                 :            :            * samples encoded. If the difference between those 2 numbers is
    1647                 :            :            * bigger than half a frame we then use the incoming timestamp
    1648                 :            :            * as a reference, otherwise we continue using our accumulated samples
    1649                 :            :            * counter */
    1650         [ #  # ]:          0 :           if (ABS (mad->total_samples - total) > nsamples / 2) {
    1651         [ #  # ]:          0 :             GST_DEBUG_OBJECT (mad, "difference is bigger than half a frame, "
    1652                 :            :                 "using calculated samples offset %" G_GUINT64_FORMAT, total);
    1653                 :            :             /* Override our accumulated samples counter */
    1654                 :          0 :             mad->total_samples = total;
    1655                 :            :             /* We use that timestamp directly */
    1656                 :          0 :             time_offset = mad->last_ts;
    1657                 :            :           }
    1658                 :            : 
    1659                 :          0 :           mad->last_ts = GST_CLOCK_TIME_NONE;
    1660                 :            :         }
    1661                 :            : 
    1662         [ #  # ]:          0 :         if (!GST_CLOCK_TIME_IS_VALID (time_offset)) {
    1663                 :          0 :           time_offset = gst_util_uint64_scale_int (mad->total_samples,
    1664                 :            :               GST_SECOND, mad->rate);
    1665                 :            :         }
    1666                 :            :         /* Duration is next timestamp - this one to generate a continuous
    1667                 :            :          * stream */
    1668                 :          0 :         time_duration =
    1669                 :          0 :             gst_util_uint64_scale_int (mad->total_samples + nsamples,
    1670                 :            :             GST_SECOND, mad->rate) - time_offset;
    1671                 :            :       }
    1672                 :            : 
    1673         [ #  # ]:          0 :       if (mad->index) {
    1674                 :          0 :         guint64 x_bytes = mad->base_byte_offset + mad->bytes_consumed;
    1675                 :            : 
    1676                 :          0 :         gst_index_add_association (mad->index, mad->index_id,
    1677                 :            :             GST_ASSOCIATION_FLAG_DELTA_UNIT,
    1678                 :            :             GST_FORMAT_BYTES, x_bytes, GST_FORMAT_TIME, time_offset, NULL);
    1679                 :            :       }
    1680                 :            : 
    1681         [ #  # ]:          0 :       if (mad->segment_start <= (time_offset ==
    1682         [ #  # ]:          0 :               GST_CLOCK_TIME_NONE ? 0 : time_offset)) {
    1683                 :            : 
    1684                 :            :         /* for sample accurate seeking, calculate how many samples
    1685                 :            :            to skip and send the remaining pcm samples */
    1686                 :            : 
    1687                 :          0 :         GstBuffer *outbuffer = NULL;
    1688                 :            :         gint32 *outdata;
    1689                 :            :         mad_fixed_t const *left_ch, *right_ch;
    1690                 :            : 
    1691         [ #  # ]:          0 :         if (mad->need_newsegment) {
    1692                 :          0 :           gint64 start = time_offset;
    1693                 :            : 
    1694 [ #  # ][ #  # ]:          0 :           GST_DEBUG ("Sending NEWSEGMENT event, start=%" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
    1695                 :            :               GST_TIME_ARGS (start));
    1696                 :            : 
    1697                 :          0 :           gst_segment_set_newsegment (&mad->segment, FALSE, 1.0,
    1698                 :            :               GST_FORMAT_TIME, start, GST_CLOCK_TIME_NONE, start);
    1699                 :            : 
    1700                 :          0 :           gst_pad_push_event (mad->srcpad,
    1701                 :            :               gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
    1702                 :            :                   start, GST_CLOCK_TIME_NONE, start));
    1703                 :          0 :           mad->need_newsegment = FALSE;
    1704                 :            :         }
    1705                 :            : 
    1706         [ #  # ]:          0 :         if (mad->pending_events) {
    1707                 :            :           GList *l;
    1708                 :            : 
    1709         [ #  # ]:          0 :           for (l = mad->pending_events; l != NULL; l = l->next) {
    1710                 :          0 :             gst_pad_push_event (mad->srcpad, GST_EVENT (l->data));
    1711                 :            :           }
    1712                 :          0 :           g_list_free (mad->pending_events);
    1713                 :          0 :           mad->pending_events = NULL;
    1714                 :            :         }
    1715                 :            : 
    1716                 :            :         /* will attach the caps to the buffer */
    1717                 :          0 :         result =
    1718                 :          0 :             gst_pad_alloc_buffer_and_set_caps (mad->srcpad, 0,
    1719                 :          0 :             nsamples * mad->channels * 4, GST_PAD_CAPS (mad->srcpad),
    1720                 :            :             &outbuffer);
    1721         [ #  # ]:          0 :         if (result != GST_FLOW_OK) {
    1722                 :            :           /* Head for the exit, dropping samples as we go */
    1723         [ #  # ]:          0 :           GST_LOG ("Skipping frame synthesis due to pad_alloc return value");
    1724                 :          0 :           goto_exit = TRUE;
    1725                 :          0 :           goto skip_frame;
    1726                 :            :         }
    1727                 :            : 
    1728         [ #  # ]:          0 :         if (GST_BUFFER_SIZE (outbuffer) != nsamples * mad->channels * 4) {
    1729                 :          0 :           gst_buffer_unref (outbuffer);
    1730                 :            : 
    1731                 :          0 :           outbuffer = gst_buffer_new_and_alloc (nsamples * mad->channels * 4);
    1732                 :          0 :           gst_buffer_set_caps (outbuffer, GST_PAD_CAPS (mad->srcpad));
    1733                 :            :         }
    1734                 :            : 
    1735                 :          0 :         mad_synth_frame (&mad->synth, &mad->frame);
    1736                 :          0 :         left_ch = mad->synth.pcm.samples[0];
    1737                 :          0 :         right_ch = mad->synth.pcm.samples[1];
    1738                 :            : 
    1739                 :          0 :         outdata = (gint32 *) GST_BUFFER_DATA (outbuffer);
    1740                 :            : 
    1741 [ #  # ][ #  # ]:          0 :         GST_DEBUG ("mad out timestamp %" GST_TIME_FORMAT " dur: %"
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1742                 :            :             GST_TIME_FORMAT, GST_TIME_ARGS (time_offset),
    1743                 :            :             GST_TIME_ARGS (time_duration));
    1744                 :            : 
    1745                 :          0 :         GST_BUFFER_TIMESTAMP (outbuffer) = time_offset;
    1746                 :          0 :         GST_BUFFER_DURATION (outbuffer) = time_duration;
    1747                 :          0 :         GST_BUFFER_OFFSET (outbuffer) = mad->total_samples;
    1748                 :          0 :         GST_BUFFER_OFFSET_END (outbuffer) = mad->total_samples + nsamples;
    1749                 :            : 
    1750                 :            :         /* output sample(s) in 16-bit signed native-endian PCM */
    1751         [ #  # ]:          0 :         if (mad->channels == 1) {
    1752                 :          0 :           gint count = nsamples;
    1753                 :            : 
    1754         [ #  # ]:          0 :           while (count--) {
    1755                 :          0 :             *outdata++ = scale (*left_ch++) & 0xffffffff;
    1756                 :            :           }
    1757                 :            :         } else {
    1758                 :          0 :           gint count = nsamples;
    1759                 :            : 
    1760         [ #  # ]:          0 :           while (count--) {
    1761                 :          0 :             *outdata++ = scale (*left_ch++) & 0xffffffff;
    1762                 :          0 :             *outdata++ = scale (*right_ch++) & 0xffffffff;
    1763                 :            :           }
    1764                 :            :         }
    1765                 :            : 
    1766         [ #  # ]:          0 :         if ((outbuffer = gst_audio_buffer_clip (outbuffer, &mad->segment,
    1767                 :          0 :                     mad->rate, 4 * mad->channels))) {
    1768 [ #  # ][ #  # ]:          0 :           GST_LOG_OBJECT (mad,
         [ #  # ][ #  # ]
                 [ #  # ]
    1769                 :            :               "pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT,
    1770                 :            :               GST_BUFFER_OFFSET (outbuffer),
    1771                 :            :               GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuffer)));
    1772                 :            : 
    1773                 :            :           /* apply discont */
    1774         [ #  # ]:          0 :           if (mad->discont) {
    1775                 :          0 :             GST_BUFFER_FLAG_SET (outbuffer, GST_BUFFER_FLAG_DISCONT);
    1776                 :          0 :             mad->discont = FALSE;
    1777                 :            :           }
    1778                 :            : 
    1779                 :          0 :           mad->segment.last_stop = GST_BUFFER_TIMESTAMP (outbuffer);
    1780         [ #  # ]:          0 :           if (mad->segment.rate > 0.0) {
    1781                 :          0 :             result = gst_pad_push (mad->srcpad, outbuffer);
    1782                 :            :           } else {
    1783         [ #  # ]:          0 :             GST_LOG_OBJECT (mad, "queued buffer");
    1784                 :          0 :             mad->queued = g_list_prepend (mad->queued, outbuffer);
    1785                 :          0 :             result = GST_FLOW_OK;
    1786                 :            :           }
    1787         [ #  # ]:          0 :           if (result != GST_FLOW_OK) {
    1788                 :            :             /* Head for the exit, dropping samples as we go */
    1789                 :          0 :             goto_exit = TRUE;
    1790                 :            :           }
    1791                 :            :         } else {
    1792         [ #  # ]:          0 :           GST_LOG_OBJECT (mad, "Dropping buffer");
    1793                 :            :         }
    1794                 :            :       }
    1795                 :            : 
    1796                 :            :     skip_frame:
    1797                 :          0 :       mad->total_samples += nsamples;
    1798                 :            : 
    1799                 :            :       /* we have a queued timestamp on the incoming buffer that we should
    1800                 :            :        * use for the next frame */
    1801 [ #  # ][ #  # ]:          0 :       if (new_pts && (mad->stream.next_frame - mad_input_buffer >= tempsize)) {
    1802                 :          0 :         new_pts = FALSE;
    1803                 :          0 :         mad->last_ts = timestamp;
    1804                 :          0 :         mad->base_byte_offset = GST_BUFFER_OFFSET (buffer);
    1805                 :          0 :         mad->bytes_consumed = 0;
    1806                 :            :       }
    1807                 :          0 :       tempsize = 0;
    1808         [ #  # ]:          0 :       if (discont) {
    1809                 :          0 :         mad->discont = TRUE;
    1810                 :          0 :         discont = FALSE;
    1811                 :            :       }
    1812                 :            : 
    1813         [ #  # ]:          0 :       if (gst_mad_check_restart (mad)) {
    1814                 :          0 :         goto end;
    1815                 :            :       }
    1816                 :            : 
    1817                 :            :     next_no_samples:
    1818                 :            :       /* figure out how many bytes mad consumed */
    1819                 :            :       /* if consumed is already set, it's from the resync higher up, so
    1820                 :            :          we need to use that value instead.  Otherwise, recalculate from
    1821                 :            :          mad's consumption */
    1822         [ #  # ]:          0 :       if (consumed == 0)
    1823                 :          0 :         consumed = mad->stream.next_frame - mad_input_buffer;
    1824                 :            : 
    1825         [ #  # ]:          0 :       GST_LOG ("mad consumed %d bytes", consumed);
    1826                 :            :       /* move out pointer to where mad want the next data */
    1827                 :          0 :       mad_input_buffer += consumed;
    1828                 :          0 :       mad->tempsize -= consumed;
    1829                 :          0 :       mad->bytes_consumed += consumed;
    1830         [ #  # ]:          0 :       if (goto_exit == TRUE)
    1831                 :          0 :         goto end;
    1832                 :            :     }
    1833                 :            :     /* we only get here from breaks, tempsize never actually drops below 0 */
    1834                 :          0 :     memmove (mad->tempbuffer, mad_input_buffer, mad->tempsize);
    1835                 :            :   }
    1836                 :          0 :   result = GST_FLOW_OK;
    1837                 :            : 
    1838                 :            : end:
    1839                 :          0 :   gst_buffer_unref (buffer);
    1840                 :            : 
    1841                 :          0 :   return result;
    1842                 :            : }
    1843                 :            : 
    1844                 :            : static GstStateChangeReturn
    1845                 :         34 : gst_mad_change_state (GstElement * element, GstStateChange transition)
    1846                 :            : {
    1847                 :            :   GstMad *mad;
    1848                 :            :   GstStateChangeReturn ret;
    1849                 :            : 
    1850                 :         34 :   mad = GST_MAD (element);
    1851                 :            : 
    1852   [ +  +  +  + ]:         34 :   switch (transition) {
    1853                 :            :     case GST_STATE_CHANGE_NULL_TO_READY:
    1854                 :          4 :       break;
    1855                 :            :     case GST_STATE_CHANGE_READY_TO_PAUSED:
    1856                 :            :     {
    1857                 :          7 :       guint options = 0;
    1858                 :            : 
    1859                 :          7 :       mad_stream_init (&mad->stream);
    1860                 :          7 :       mad_frame_init (&mad->frame);
    1861                 :          7 :       mad_synth_init (&mad->synth);
    1862                 :          7 :       mad->tempsize = 0;
    1863                 :          7 :       mad->discont = TRUE;
    1864                 :          7 :       mad->total_samples = 0;
    1865                 :          7 :       mad->rate = 0;
    1866                 :          7 :       mad->channels = 0;
    1867                 :          7 :       mad->caps_set = FALSE;
    1868                 :          7 :       mad->times_pending = mad->pending_rate = mad->pending_channels = 0;
    1869                 :          7 :       mad->vbr_average = 0;
    1870                 :          7 :       gst_segment_init (&mad->segment, GST_FORMAT_TIME);
    1871                 :          7 :       mad->new_header = TRUE;
    1872                 :          7 :       mad->framed = FALSE;
    1873                 :          7 :       mad->framecount = 0;
    1874                 :          7 :       mad->vbr_rate = 0;
    1875                 :          7 :       mad->frame.header.samplerate = 0;
    1876                 :          7 :       mad->last_ts = GST_CLOCK_TIME_NONE;
    1877         [ +  - ]:          7 :       if (mad->ignore_crc)
    1878                 :          7 :         options |= MAD_OPTION_IGNORECRC;
    1879         [ -  + ]:          7 :       if (mad->half)
    1880                 :          0 :         options |= MAD_OPTION_HALFSAMPLERATE;
    1881                 :          7 :       mad_stream_options (&mad->stream, options);
    1882                 :          7 :       break;
    1883                 :            :     }
    1884                 :            :     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
    1885                 :          6 :       break;
    1886                 :            :     default:
    1887                 :         17 :       break;
    1888                 :            :   }
    1889                 :            : 
    1890                 :         34 :   ret = parent_class->change_state (element, transition);
    1891                 :            : 
    1892   [ +  +  +  + ]:         34 :   switch (transition) {
    1893                 :            :     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
    1894                 :          6 :       break;
    1895                 :            :     case GST_STATE_CHANGE_PAUSED_TO_READY:
    1896                 :            :       mad_synth_finish (&mad->synth);
    1897                 :          7 :       mad_frame_finish (&mad->frame);
    1898                 :          7 :       mad_stream_finish (&mad->stream);
    1899                 :          7 :       mad->restart = TRUE;
    1900                 :          7 :       mad->check_for_xing = TRUE;
    1901         [ -  + ]:          7 :       if (mad->tags) {
    1902                 :          0 :         gst_tag_list_free (mad->tags);
    1903                 :          0 :         mad->tags = NULL;
    1904                 :            :       }
    1905                 :          7 :       gst_mad_clear_queues (mad);
    1906                 :          7 :       break;
    1907                 :            :     case GST_STATE_CHANGE_READY_TO_NULL:
    1908                 :          4 :       break;
    1909                 :            :     default:
    1910                 :         17 :       break;
    1911                 :            :   }
    1912                 :         34 :   return ret;
    1913                 :            : }
    1914                 :            : 
    1915                 :            : #ifdef HAVE_ID3TAG
    1916                 :            : /* id3 tag helper (FIXME: why does mad parse id3 tags at all? It shouldn't) */
    1917                 :            : static GstTagList *
    1918                 :          0 : gst_mad_id3_to_tag_list (const struct id3_tag *tag)
    1919                 :            : {
    1920                 :            :   const struct id3_frame *frame;
    1921                 :            :   const id3_ucs4_t *ucs4;
    1922                 :            :   id3_utf8_t *utf8;
    1923                 :            :   GstTagList *tag_list;
    1924                 :            :   GType tag_type;
    1925                 :          0 :   guint i = 0;
    1926                 :            : 
    1927                 :          0 :   tag_list = gst_tag_list_new ();
    1928                 :            : 
    1929         [ #  # ]:          0 :   while ((frame = id3_tag_findframe (tag, NULL, i++)) != NULL) {
    1930                 :            :     const union id3_field *field;
    1931                 :            :     unsigned int nstrings, j;
    1932                 :            :     const gchar *tag_name;
    1933                 :            : 
    1934                 :            :     /* find me the function to query the frame id */
    1935                 :          0 :     gchar *id = g_strndup (frame->id, 5);
    1936                 :            : 
    1937                 :          0 :     tag_name = gst_tag_from_id3_tag (id);
    1938         [ #  # ]:          0 :     if (tag_name == NULL) {
    1939                 :          0 :       g_free (id);
    1940                 :          0 :       continue;
    1941                 :            :     }
    1942                 :            : 
    1943         [ #  # ]:          0 :     if (strcmp (id, "COMM") == 0) {
    1944         [ #  # ]:          0 :       if (frame->nfields < 4)
    1945                 :          0 :         continue;
    1946                 :            : 
    1947                 :          0 :       ucs4 = id3_field_getfullstring (&frame->fields[3]);
    1948         [ #  # ]:          0 :       g_assert (ucs4);
    1949                 :            : 
    1950                 :          0 :       utf8 = id3_ucs4_utf8duplicate (ucs4);
    1951         [ #  # ]:          0 :       if (utf8 == 0)
    1952                 :          0 :         continue;
    1953                 :            : 
    1954         [ #  # ]:          0 :       if (!g_utf8_validate ((char *) utf8, -1, NULL)) {
    1955         [ #  # ]:          0 :         GST_ERROR ("converted string is not valid utf-8");
    1956                 :          0 :         g_free (utf8);
    1957                 :          0 :         continue;
    1958                 :            :       }
    1959                 :            : 
    1960                 :          0 :       gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
    1961                 :            :           GST_TAG_COMMENT, utf8, NULL);
    1962                 :            : 
    1963                 :          0 :       g_free (utf8);
    1964                 :          0 :       continue;
    1965                 :            :     }
    1966                 :            : 
    1967         [ #  # ]:          0 :     if (frame->nfields < 2)
    1968                 :          0 :       continue;
    1969                 :            : 
    1970                 :          0 :     field = &frame->fields[1];
    1971                 :          0 :     nstrings = id3_field_getnstrings (field);
    1972                 :            : 
    1973         [ #  # ]:          0 :     for (j = 0; j < nstrings; ++j) {
    1974                 :          0 :       ucs4 = id3_field_getstrings (field, j);
    1975         [ #  # ]:          0 :       g_assert (ucs4);
    1976                 :            : 
    1977         [ #  # ]:          0 :       if (strcmp (id, ID3_FRAME_GENRE) == 0)
    1978                 :          0 :         ucs4 = id3_genre_name (ucs4);
    1979                 :            : 
    1980                 :          0 :       utf8 = id3_ucs4_utf8duplicate (ucs4);
    1981         [ #  # ]:          0 :       if (utf8 == 0)
    1982                 :          0 :         continue;
    1983                 :            : 
    1984         [ #  # ]:          0 :       if (!g_utf8_validate ((char *) utf8, -1, NULL)) {
    1985         [ #  # ]:          0 :         GST_ERROR ("converted string is not valid utf-8");
    1986                 :          0 :         free (utf8);
    1987                 :          0 :         continue;
    1988                 :            :       }
    1989                 :            : 
    1990                 :          0 :       tag_type = gst_tag_get_type (tag_name);
    1991                 :            : 
    1992                 :            :       /* be sure to add non-string tags here */
    1993   [ #  #  #  # ]:          0 :       switch (tag_type) {
    1994                 :            :         case G_TYPE_UINT:
    1995                 :            :         {
    1996                 :            :           guint tmp;
    1997                 :            :           gchar *check;
    1998                 :            : 
    1999                 :          0 :           tmp = strtoul ((char *) utf8, &check, 10);
    2000                 :            : 
    2001         [ #  # ]:          0 :           if (strcmp (tag_name, GST_TAG_DATE) == 0) {
    2002                 :            :             GDate *d;
    2003                 :            : 
    2004         [ #  # ]:          0 :             if (*check != '\0')
    2005                 :          0 :               break;
    2006         [ #  # ]:          0 :             if (tmp == 0)
    2007                 :          0 :               break;
    2008                 :          0 :             d = g_date_new_dmy (1, 1, tmp);
    2009                 :          0 :             tmp = g_date_get_julian (d);
    2010                 :          0 :             g_date_free (d);
    2011         [ #  # ]:          0 :           } else if (strcmp (tag_name, GST_TAG_TRACK_NUMBER) == 0) {
    2012         [ #  # ]:          0 :             if (*check == '/') {
    2013                 :            :               guint total;
    2014                 :            : 
    2015                 :          0 :               check++;
    2016                 :          0 :               total = strtoul (check, &check, 10);
    2017         [ #  # ]:          0 :               if (*check != '\0')
    2018                 :          0 :                 break;
    2019                 :            : 
    2020                 :          0 :               gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
    2021                 :            :                   GST_TAG_TRACK_COUNT, total, NULL);
    2022                 :            :             }
    2023         [ #  # ]:          0 :           } else if (strcmp (tag_name, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) {
    2024         [ #  # ]:          0 :             if (*check == '/') {
    2025                 :            :               guint total;
    2026                 :            : 
    2027                 :          0 :               check++;
    2028                 :          0 :               total = strtoul (check, &check, 10);
    2029         [ #  # ]:          0 :               if (*check != '\0')
    2030                 :          0 :                 break;
    2031                 :            : 
    2032                 :          0 :               gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
    2033                 :            :                   GST_TAG_ALBUM_VOLUME_COUNT, total, NULL);
    2034                 :            :             }
    2035                 :            :           }
    2036                 :            : 
    2037         [ #  # ]:          0 :           if (*check != '\0')
    2038                 :          0 :             break;
    2039                 :          0 :           gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, tag_name, tmp,
    2040                 :            :               NULL);
    2041                 :          0 :           break;
    2042                 :            :         }
    2043                 :            :         case G_TYPE_UINT64:
    2044                 :            :         {
    2045                 :            :           guint64 tmp;
    2046                 :            : 
    2047         [ #  # ]:          0 :           g_assert (strcmp (tag_name, GST_TAG_DURATION) == 0);
    2048                 :          0 :           tmp = strtoul ((char *) utf8, NULL, 10);
    2049         [ #  # ]:          0 :           if (tmp == 0) {
    2050                 :          0 :             break;
    2051                 :            :           }
    2052                 :          0 :           gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
    2053                 :            :               GST_TAG_DURATION, tmp * 1000 * 1000, NULL);
    2054                 :          0 :           break;
    2055                 :            :         }
    2056                 :            :         case G_TYPE_STRING:{
    2057                 :          0 :           gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
    2058                 :            :               tag_name, (const gchar *) utf8, NULL);
    2059                 :          0 :           break;
    2060                 :            :         }
    2061                 :            :           /* handles GST_TYPE_DATE and anything else */
    2062                 :            :         default:{
    2063                 :          0 :           GValue src = { 0, };
    2064                 :          0 :           GValue dest = { 0, };
    2065                 :            : 
    2066                 :          0 :           g_value_init (&src, G_TYPE_STRING);
    2067                 :          0 :           g_value_set_string (&src, (const gchar *) utf8);
    2068                 :            : 
    2069                 :          0 :           g_value_init (&dest, tag_type);
    2070         [ #  # ]:          0 :           if (g_value_transform (&src, &dest)) {
    2071                 :          0 :             gst_tag_list_add_values (tag_list, GST_TAG_MERGE_APPEND,
    2072                 :            :                 tag_name, &dest, NULL);
    2073                 :            :           } else {
    2074         [ #  # ]:          0 :             GST_WARNING ("Failed to transform tag from string to type '%s'",
    2075                 :            :                 g_type_name (tag_type));
    2076                 :            :           }
    2077                 :          0 :           g_value_unset (&src);
    2078                 :          0 :           g_value_unset (&dest);
    2079                 :          0 :           break;
    2080                 :            :         }
    2081                 :            :       }
    2082                 :          0 :       free (utf8);
    2083                 :            :     }
    2084                 :          0 :     g_free (id);
    2085                 :            :   }
    2086                 :            : 
    2087                 :          0 :   return tag_list;
    2088                 :            : }
    2089                 :            : #endif /* HAVE_ID3TAG */
    2090                 :            : 
    2091                 :            : /* plugin initialisation */
    2092                 :            : 
    2093                 :            : static gboolean
    2094                 :          5 : plugin_init (GstPlugin * plugin)
    2095                 :            : {
    2096         [ +  - ]:          5 :   GST_DEBUG_CATEGORY_INIT (mad_debug, "mad", 0, "mad mp3 decoding");
    2097                 :            : 
    2098                 :          5 :   return gst_element_register (plugin, "mad", GST_RANK_SECONDARY,
    2099                 :            :       gst_mad_get_type ());
    2100                 :            : }
    2101                 :            : 
    2102                 :            : GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    2103                 :            :     GST_VERSION_MINOR,
    2104                 :            :     "mad",
    2105                 :            :     "mp3 decoding based on the mad library",
    2106                 :            :     plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);

Generated by: LCOV version 1.9