LCOV - code coverage report
Current view: top level - ext/wavpack - gstwavpackparse.c (source / functions) Hit Total Coverage
Test: GStreamer Good Plug-ins 0.10.28.1 Lines: 244 591 41.3 %
Date: 2011-03-25 Functions: 17 32 53.1 %
Branches: 76 383 19.8 %

           Branch data     Line data    Source code
       1                 :            : /* GStreamer wavpack plugin
       2                 :            :  * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
       3                 :            :  * Copyright (c) 2006 Tim-Philipp Müller <tim centricular net>
       4                 :            :  * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
       5                 :            :  *
       6                 :            :  * gstwavpackparse.c: wavpack file parser
       7                 :            :  *
       8                 :            :  * This library is free software; you can redistribute it and/or
       9                 :            :  * modify it under the terms of the GNU Library General Public
      10                 :            :  * License as published by the Free Software Foundation; either
      11                 :            :  * version 2 of the License, or (at your option) any later version.
      12                 :            :  *
      13                 :            :  * This library is distributed in the hope that it will be useful,
      14                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16                 :            :  * Library General Public License for more details.
      17                 :            :  *
      18                 :            :  * You should have received a copy of the GNU Library General Public
      19                 :            :  * License along with this library; if not, write to the
      20                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      21                 :            :  * Boston, MA 02111-1307, USA.
      22                 :            :  */
      23                 :            : 
      24                 :            : /**
      25                 :            :  * SECTION:element-wavpackparse
      26                 :            :  *
      27                 :            :  * WavpackParse takes raw, unframed Wavpack streams and splits them into
      28                 :            :  * single Wavpack chunks with information like bit depth and the position
      29                 :            :  * in the stream.
      30                 :            :  * <ulink url="http://www.wavpack.com/">Wavpack</ulink> is an open-source
      31                 :            :  * audio codec that features both lossless and lossy encoding.
      32                 :            :  *
      33                 :            :  * <refsect2>
      34                 :            :  * <title>Example launch line</title>
      35                 :            :  * |[
      36                 :            :  * gst-launch filesrc location=test.wv ! wavpackparse ! wavpackdec ! fakesink
      37                 :            :  * ]| This pipeline decodes the Wavpack file test.wv into raw audio buffers.
      38                 :            :  * </refsect2>
      39                 :            :  */
      40                 :            : 
      41                 :            : #ifdef HAVE_CONFIG_H
      42                 :            : #include "config.h"
      43                 :            : #endif
      44                 :            : #include <gst/gst.h>
      45                 :            : #include <gst/gst-i18n-plugin.h>
      46                 :            : 
      47                 :            : #include <math.h>
      48                 :            : #include <string.h>
      49                 :            : 
      50                 :            : #include <wavpack/wavpack.h>
      51                 :            : #include "gstwavpackparse.h"
      52                 :            : #include "gstwavpackstreamreader.h"
      53                 :            : #include "gstwavpackcommon.h"
      54                 :            : 
      55                 :            : GST_DEBUG_CATEGORY_STATIC (gst_wavpack_parse_debug);
      56                 :            : #define GST_CAT_DEFAULT gst_wavpack_parse_debug
      57                 :            : 
      58                 :            : static inline GstWavpackParseIndexEntry *
      59                 :          0 : gst_wavpack_parse_index_entry_new (void)
      60                 :            : {
      61                 :          0 :   return g_slice_new (GstWavpackParseIndexEntry);
      62                 :            : }
      63                 :            : 
      64                 :            : static inline void
      65                 :          0 : gst_wavpack_parse_index_entry_free (GstWavpackParseIndexEntry * entry)
      66                 :            : {
      67                 :          0 :   g_slice_free (GstWavpackParseIndexEntry, entry);
      68                 :          0 : }
      69                 :            : 
      70                 :            : static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
      71                 :            :     GST_PAD_SINK,
      72                 :            :     GST_PAD_ALWAYS,
      73                 :            :     GST_STATIC_CAPS ("audio/x-wavpack, "
      74                 :            :         "framed = (boolean) false; "
      75                 :            :         "audio/x-wavpack-correction, " "framed = (boolean) false")
      76                 :            :     );
      77                 :            : 
      78                 :            : static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
      79                 :            :     GST_PAD_SRC,
      80                 :            :     GST_PAD_SOMETIMES,
      81                 :            :     GST_STATIC_CAPS ("audio/x-wavpack, "
      82                 :            :         "width = (int) [ 1, 32 ], "
      83                 :            :         "channels = (int) [ 1, 8 ], "
      84                 :            :         "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true")
      85                 :            :     );
      86                 :            : 
      87                 :            : static GstStaticPadTemplate wvc_src_factory = GST_STATIC_PAD_TEMPLATE ("wvcsrc",
      88                 :            :     GST_PAD_SRC,
      89                 :            :     GST_PAD_SOMETIMES,
      90                 :            :     GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true")
      91                 :            :     );
      92                 :            : 
      93                 :            : static gboolean gst_wavpack_parse_sink_activate (GstPad * sinkpad);
      94                 :            : 
      95                 :            : static gboolean
      96                 :            : gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active);
      97                 :            : 
      98                 :            : static void gst_wavpack_parse_loop (GstElement * element);
      99                 :            : 
     100                 :            : static GstStateChangeReturn gst_wavpack_parse_change_state (GstElement *
     101                 :            :     element, GstStateChange transition);
     102                 :            : static void gst_wavpack_parse_reset (GstWavpackParse * parse);
     103                 :            : 
     104                 :            : static gint64 gst_wavpack_parse_get_upstream_length (GstWavpackParse * wvparse);
     105                 :            : 
     106                 :            : static GstBuffer *gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse,
     107                 :            :     gint64 offset, guint size, GstFlowReturn * flow);
     108                 :            : static GstFlowReturn gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf);
     109                 :            : 
     110         [ +  + ]:         72 : GST_BOILERPLATE (GstWavpackParse, gst_wavpack_parse, GstElement,
     111                 :         72 :     GST_TYPE_ELEMENT);
     112                 :            : 
     113                 :            : static void
     114                 :          6 : gst_wavpack_parse_base_init (gpointer klass)
     115                 :            : {
     116                 :          6 :   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
     117                 :            : 
     118                 :          6 :   gst_element_class_add_pad_template (element_class,
     119                 :            :       gst_static_pad_template_get (&src_factory));
     120                 :          6 :   gst_element_class_add_pad_template (element_class,
     121                 :            :       gst_static_pad_template_get (&wvc_src_factory));
     122                 :          6 :   gst_element_class_add_pad_template (element_class,
     123                 :            :       gst_static_pad_template_get (&sink_factory));
     124                 :            : 
     125                 :          6 :   gst_element_class_set_details_simple (element_class, "Wavpack parser",
     126                 :            :       "Codec/Demuxer/Audio",
     127                 :            :       "Parses Wavpack files",
     128                 :            :       "Arwed v. Merkatz <v.merkatz@gmx.net>, "
     129                 :            :       "Sebastian Dröge <slomo@circular-chaos.org>");
     130                 :          6 : }
     131                 :            : 
     132                 :            : static void
     133                 :          5 : gst_wavpack_parse_finalize (GObject * object)
     134                 :            : {
     135                 :          5 :   gst_wavpack_parse_reset (GST_WAVPACK_PARSE (object));
     136                 :            : 
     137                 :          5 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     138                 :          5 : }
     139                 :            : 
     140                 :            : static void
     141                 :          6 : gst_wavpack_parse_class_init (GstWavpackParseClass * klass)
     142                 :            : {
     143                 :            :   GObjectClass *gobject_class;
     144                 :            : 
     145                 :            :   GstElementClass *gstelement_class;
     146                 :            : 
     147                 :          6 :   gobject_class = (GObjectClass *) klass;
     148                 :          6 :   gstelement_class = (GstElementClass *) klass;
     149                 :            : 
     150                 :          6 :   gobject_class->finalize = gst_wavpack_parse_finalize;
     151                 :          6 :   gstelement_class->change_state =
     152                 :          6 :       GST_DEBUG_FUNCPTR (gst_wavpack_parse_change_state);
     153                 :          6 : }
     154                 :            : 
     155                 :            : static GstWavpackParseIndexEntry *
     156                 :          0 : gst_wavpack_parse_index_get_last_entry (GstWavpackParse * wvparse)
     157                 :            : {
     158         [ #  # ]:          0 :   g_assert (wvparse->entries != NULL);
     159                 :            : 
     160                 :          0 :   return wvparse->entries->data;
     161                 :            : }
     162                 :            : 
     163                 :            : static GstWavpackParseIndexEntry *
     164                 :          0 : gst_wavpack_parse_index_get_entry_from_sample (GstWavpackParse * wvparse,
     165                 :            :     gint64 sample_offset)
     166                 :            : {
     167                 :            :   gint i;
     168                 :            : 
     169                 :            :   GSList *node;
     170                 :            : 
     171         [ #  # ]:          0 :   if (wvparse->entries == NULL)
     172                 :          0 :     return NULL;
     173                 :            : 
     174         [ #  # ]:          0 :   for (node = wvparse->entries, i = 0; node; node = node->next, i++) {
     175                 :            :     GstWavpackParseIndexEntry *entry;
     176                 :            : 
     177                 :          0 :     entry = node->data;
     178                 :            : 
     179         [ #  # ]:          0 :     GST_LOG_OBJECT (wvparse, "Index entry %03u: sample %" G_GINT64_FORMAT " @"
     180                 :            :         " byte %" G_GINT64_FORMAT, i, entry->sample_offset, entry->byte_offset);
     181                 :            : 
     182 [ #  # ][ #  # ]:          0 :     if (entry->sample_offset <= sample_offset &&
     183                 :          0 :         sample_offset < entry->sample_offset_end) {
     184         [ #  # ]:          0 :       GST_LOG_OBJECT (wvparse, "found match");
     185                 :          0 :       return entry;
     186                 :            :     }
     187                 :            : 
     188                 :            :     /* as the list is sorted and we first look at the latest entry
     189                 :            :      * we can abort searching for an entry if the sample we want is
     190                 :            :      * after the latest one */
     191         [ #  # ]:          0 :     if (sample_offset >= entry->sample_offset_end)
     192                 :          0 :       break;
     193                 :            :   }
     194         [ #  # ]:          0 :   GST_LOG_OBJECT (wvparse, "no match in index");
     195                 :          0 :   return NULL;
     196                 :            : }
     197                 :            : 
     198                 :            : static void
     199                 :          0 : gst_wavpack_parse_index_append_entry (GstWavpackParse * wvparse,
     200                 :            :     gint64 byte_offset, gint64 sample_offset, gint64 num_samples)
     201                 :            : {
     202                 :            :   GstWavpackParseIndexEntry *entry;
     203                 :            : 
     204                 :            :   /* do we have this one already? */
     205         [ #  # ]:          0 :   if (wvparse->entries) {
     206                 :          0 :     entry = gst_wavpack_parse_index_get_last_entry (wvparse);
     207         [ #  # ]:          0 :     if (entry->byte_offset >= byte_offset
     208         [ #  # ]:          0 :         || entry->sample_offset >= sample_offset)
     209                 :          0 :       return;
     210                 :            :   }
     211                 :            : 
     212 [ #  # ][ #  # ]:          0 :   GST_LOG_OBJECT (wvparse, "Adding index entry %8" G_GINT64_FORMAT " - %"
         [ #  # ][ #  # ]
                 [ #  # ]
     213                 :            :       GST_TIME_FORMAT " @ offset 0x%08" G_GINT64_MODIFIER "x", sample_offset,
     214                 :            :       GST_TIME_ARGS (gst_util_uint64_scale_int (sample_offset,
     215                 :            :               GST_SECOND, wvparse->samplerate)), byte_offset);
     216                 :            : 
     217                 :          0 :   entry = gst_wavpack_parse_index_entry_new ();
     218                 :          0 :   entry->byte_offset = byte_offset;
     219                 :          0 :   entry->sample_offset = sample_offset;
     220                 :          0 :   entry->sample_offset_end = sample_offset + num_samples;
     221                 :          0 :   wvparse->entries = g_slist_prepend (wvparse->entries, entry);
     222                 :            : }
     223                 :            : 
     224                 :            : static void
     225                 :         19 : gst_wavpack_parse_reset (GstWavpackParse * parse)
     226                 :            : {
     227                 :         19 :   parse->total_samples = G_GINT64_CONSTANT (-1);
     228                 :         19 :   parse->samplerate = 0;
     229                 :         19 :   parse->channels = 0;
     230                 :            : 
     231                 :         19 :   gst_segment_init (&parse->segment, GST_FORMAT_UNDEFINED);
     232                 :         19 :   parse->next_block_index = 0;
     233                 :            : 
     234                 :         19 :   parse->current_offset = 0;
     235                 :         19 :   parse->need_newsegment = TRUE;
     236                 :         19 :   parse->discont = TRUE;
     237                 :         19 :   parse->upstream_length = -1;
     238                 :            : 
     239         [ -  + ]:         19 :   if (parse->entries) {
     240                 :          0 :     g_slist_foreach (parse->entries, (GFunc) gst_wavpack_parse_index_entry_free,
     241                 :            :         NULL);
     242                 :          0 :     g_slist_free (parse->entries);
     243                 :          0 :     parse->entries = NULL;
     244                 :            :   }
     245                 :            : 
     246         [ +  + ]:         19 :   if (parse->adapter) {
     247                 :          2 :     gst_adapter_clear (parse->adapter);
     248                 :          2 :     g_object_unref (parse->adapter);
     249                 :          2 :     parse->adapter = NULL;
     250                 :            :   }
     251                 :            : 
     252         [ +  + ]:         19 :   if (parse->srcpad != NULL) {
     253                 :            :     gboolean res;
     254                 :            : 
     255         [ -  + ]:          2 :     GST_DEBUG_OBJECT (parse, "Removing src pad");
     256                 :          2 :     res = gst_element_remove_pad (GST_ELEMENT (parse), parse->srcpad);
     257         [ -  + ]:         21 :     g_return_if_fail (res != FALSE);
     258                 :          2 :     gst_object_unref (parse->srcpad);
     259                 :          2 :     parse->srcpad = NULL;
     260                 :            :   }
     261                 :            : 
     262                 :         19 :   g_list_foreach (parse->queued_events, (GFunc) gst_mini_object_unref, NULL);
     263                 :         19 :   g_list_free (parse->queued_events);
     264                 :         19 :   parse->queued_events = NULL;
     265                 :            : 
     266         [ -  + ]:         19 :   if (parse->pending_buffer)
     267                 :          0 :     gst_buffer_unref (parse->pending_buffer);
     268                 :            : 
     269                 :         19 :   parse->pending_buffer = NULL;
     270                 :            : }
     271                 :            : 
     272                 :            : static const GstQueryType *
     273                 :          0 : gst_wavpack_parse_get_src_query_types (GstPad * pad)
     274                 :            : {
     275                 :            :   static const GstQueryType types[] = {
     276                 :            :     GST_QUERY_POSITION,
     277                 :            :     GST_QUERY_DURATION,
     278                 :            :     GST_QUERY_SEEKING,
     279                 :            :     0
     280                 :            :   };
     281                 :            : 
     282                 :          0 :   return types;
     283                 :            : }
     284                 :            : 
     285                 :            : static gboolean
     286                 :          2 : gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query)
     287                 :            : {
     288                 :          2 :   GstWavpackParse *parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
     289                 :            : 
     290                 :            :   GstFormat format;
     291                 :            : 
     292                 :          2 :   gboolean ret = FALSE;
     293                 :            : 
     294   [ +  +  -  - ]:          2 :   switch (GST_QUERY_TYPE (query)) {
     295                 :            :     case GST_QUERY_POSITION:{
     296                 :            :       gint64 cur;
     297                 :            : 
     298                 :            :       guint rate;
     299                 :            : 
     300                 :          1 :       GST_OBJECT_LOCK (parse);
     301                 :          1 :       cur = parse->segment.last_stop;
     302                 :          1 :       rate = parse->samplerate;
     303                 :          1 :       GST_OBJECT_UNLOCK (parse);
     304                 :            : 
     305         [ -  + ]:          1 :       if (rate == 0) {
     306         [ #  # ]:          0 :         GST_DEBUG_OBJECT (parse, "haven't read header yet");
     307                 :          0 :         break;
     308                 :            :       }
     309                 :            : 
     310                 :          1 :       gst_query_parse_position (query, &format, NULL);
     311                 :            : 
     312      [ -  +  - ]:          1 :       switch (format) {
     313                 :            :         case GST_FORMAT_TIME:
     314                 :          0 :           cur = gst_util_uint64_scale_int (cur, GST_SECOND, rate);
     315                 :          0 :           gst_query_set_position (query, GST_FORMAT_TIME, cur);
     316                 :          0 :           ret = TRUE;
     317                 :          0 :           break;
     318                 :            :         case GST_FORMAT_DEFAULT:
     319                 :          1 :           gst_query_set_position (query, GST_FORMAT_DEFAULT, cur);
     320                 :          1 :           ret = TRUE;
     321                 :          1 :           break;
     322                 :            :         default:
     323         [ #  # ]:          0 :           GST_DEBUG_OBJECT (parse, "cannot handle position query in "
     324                 :            :               "%s format. Forwarding upstream.", gst_format_get_name (format));
     325                 :          0 :           ret = gst_pad_query_default (pad, query);
     326                 :          0 :           break;
     327                 :            :       }
     328                 :          1 :       break;
     329                 :            :     }
     330                 :            :     case GST_QUERY_DURATION:{
     331                 :            :       gint64 len;
     332                 :            : 
     333                 :            :       guint rate;
     334                 :            : 
     335                 :          1 :       GST_OBJECT_LOCK (parse);
     336                 :          1 :       rate = parse->samplerate;
     337                 :          1 :       len = parse->total_samples;
     338                 :          1 :       GST_OBJECT_UNLOCK (parse);
     339                 :            : 
     340         [ -  + ]:          1 :       if (rate == 0) {
     341         [ #  # ]:          0 :         GST_DEBUG_OBJECT (parse, "haven't read header yet");
     342                 :          0 :         break;
     343                 :            :       }
     344                 :            : 
     345                 :          1 :       gst_query_parse_duration (query, &format, NULL);
     346                 :            : 
     347      [ -  +  - ]:          1 :       switch (format) {
     348                 :            :         case GST_FORMAT_TIME:
     349         [ #  # ]:          0 :           if (len != G_GINT64_CONSTANT (-1))
     350                 :          0 :             len = gst_util_uint64_scale_int (len, GST_SECOND, rate);
     351                 :          0 :           gst_query_set_duration (query, GST_FORMAT_TIME, len);
     352                 :          0 :           ret = TRUE;
     353                 :          0 :           break;
     354                 :            :         case GST_FORMAT_DEFAULT:
     355                 :          1 :           gst_query_set_duration (query, GST_FORMAT_DEFAULT, len);
     356                 :          1 :           ret = TRUE;
     357                 :          1 :           break;
     358                 :            :         default:
     359         [ #  # ]:          0 :           GST_DEBUG_OBJECT (parse, "cannot handle duration query in "
     360                 :            :               "%s format. Forwarding upstream.", gst_format_get_name (format));
     361                 :          0 :           ret = gst_pad_query_default (pad, query);
     362                 :          0 :           break;
     363                 :            :       }
     364                 :          1 :       break;
     365                 :            :     }
     366                 :            :     case GST_QUERY_SEEKING:{
     367                 :          0 :       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
     368 [ #  # ][ #  # ]:          0 :       if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) {
     369                 :            :         gboolean seekable;
     370                 :            : 
     371                 :          0 :         gint64 duration = -1;
     372                 :            : 
     373                 :            :         /* only fails if we didn't read the headers yet and can't say
     374                 :            :          * anything about our seeking capabilities */
     375         [ #  # ]:          0 :         if (!gst_pad_query_duration (pad, &format, &duration))
     376                 :          0 :           break;
     377                 :            : 
     378                 :            :         /* can't seek in streaming mode yet */
     379                 :          0 :         GST_OBJECT_LOCK (parse);
     380                 :          0 :         seekable = (parse->adapter == NULL);
     381                 :          0 :         GST_OBJECT_UNLOCK (parse);
     382                 :            : 
     383                 :          0 :         gst_query_set_seeking (query, format, seekable, 0, duration);
     384                 :          0 :         ret = TRUE;
     385                 :            :       }
     386                 :          0 :       break;
     387                 :            :     }
     388                 :            :     default:{
     389                 :          0 :       ret = gst_pad_query_default (pad, query);
     390                 :          0 :       break;
     391                 :            :     }
     392                 :            :   }
     393                 :            : 
     394                 :          2 :   gst_object_unref (parse);
     395                 :          2 :   return ret;
     396                 :            : 
     397                 :            : }
     398                 :            : 
     399                 :            : /* returns TRUE on success, with byte_offset set to the offset of the
     400                 :            :  * wavpack chunk containing the sample requested. start_sample will be
     401                 :            :  * set to the first sample in the chunk starting at byte_offset.
     402                 :            :  * Scanning from the last known header offset to the wanted position
     403                 :            :  * when seeking forward isn't very clever, but seems fast enough in
     404                 :            :  * practice and has the nice side effect of populating our index
     405                 :            :  * table */
     406                 :            : static gboolean
     407                 :          0 : gst_wavpack_parse_scan_to_find_sample (GstWavpackParse * parse,
     408                 :            :     gint64 sample, gint64 * byte_offset, gint64 * start_sample)
     409                 :            : {
     410                 :            :   GstWavpackParseIndexEntry *entry;
     411                 :            : 
     412                 :            :   GstFlowReturn ret;
     413                 :            : 
     414                 :          0 :   gint64 off = 0;
     415                 :            : 
     416                 :            :   /* first, check if we have to scan at all */
     417                 :          0 :   entry = gst_wavpack_parse_index_get_entry_from_sample (parse, sample);
     418         [ #  # ]:          0 :   if (entry) {
     419                 :          0 :     *byte_offset = entry->byte_offset;
     420                 :          0 :     *start_sample = entry->sample_offset;
     421         [ #  # ]:          0 :     GST_LOG_OBJECT (parse, "Found index entry: sample %" G_GINT64_FORMAT
     422                 :            :         " @ offset %" G_GINT64_FORMAT, entry->sample_offset,
     423                 :            :         entry->byte_offset);
     424                 :          0 :     return TRUE;
     425                 :            :   }
     426                 :            : 
     427         [ #  # ]:          0 :   GST_LOG_OBJECT (parse, "No matching entry in index, scanning file ...");
     428                 :            : 
     429                 :            :   /* if we have an index, we can start scanning from the last known offset
     430                 :            :    * in there, after all we know our wanted sample is not in the index */
     431         [ #  # ]:          0 :   if (parse->entries) {
     432                 :            :     GstWavpackParseIndexEntry *entry;
     433                 :            : 
     434                 :          0 :     entry = gst_wavpack_parse_index_get_last_entry (parse);
     435                 :          0 :     off = entry->byte_offset;
     436                 :            :   }
     437                 :            : 
     438                 :            :   /* now scan forward until we find the chunk we're looking for or hit EOS */
     439                 :            :   do {
     440                 :            :     WavpackHeader header;
     441                 :            : 
     442                 :            :     GstBuffer *buf;
     443                 :            : 
     444                 :          0 :     buf = gst_wavpack_parse_pull_buffer (parse, off, sizeof (WavpackHeader),
     445                 :            :         &ret);
     446                 :            : 
     447         [ #  # ]:          0 :     if (buf == NULL)
     448                 :          0 :       break;
     449                 :            : 
     450                 :          0 :     gst_wavpack_read_header (&header, GST_BUFFER_DATA (buf));
     451                 :          0 :     gst_buffer_unref (buf);
     452                 :            : 
     453         [ #  # ]:          0 :     if (header.flags & INITIAL_BLOCK)
     454                 :          0 :       gst_wavpack_parse_index_append_entry (parse, off, header.block_index,
     455                 :          0 :           header.block_samples);
     456                 :            :     else
     457                 :          0 :       continue;
     458                 :            : 
     459 [ #  # ][ #  # ]:          0 :     if (header.block_index <= sample &&
     460                 :          0 :         sample < (header.block_index + header.block_samples)) {
     461                 :          0 :       *byte_offset = off;
     462                 :          0 :       *start_sample = header.block_index;
     463                 :          0 :       return TRUE;
     464                 :            :     }
     465                 :            : 
     466                 :          0 :     off += header.ckSize + 8;
     467                 :          0 :   } while (1);
     468                 :            : 
     469         [ #  # ]:          0 :   GST_DEBUG_OBJECT (parse, "scan failed: %s (off=0x%08" G_GINT64_MODIFIER "x)",
     470                 :            :       gst_flow_get_name (ret), off);
     471                 :            : 
     472                 :          0 :   return FALSE;
     473                 :            : }
     474                 :            : 
     475                 :            : static gboolean
     476                 :          2 : gst_wavpack_parse_send_newsegment (GstWavpackParse * wvparse, gboolean update)
     477                 :            : {
     478                 :          2 :   GstSegment *s = &wvparse->segment;
     479                 :            : 
     480                 :            :   gboolean ret;
     481                 :            : 
     482                 :          2 :   gint64 stop_time = -1;
     483                 :            : 
     484                 :          2 :   gint64 start_time = 0;
     485                 :            : 
     486                 :            :   gint64 cur_pos_time;
     487                 :            : 
     488                 :            :   gint64 diff;
     489                 :            : 
     490                 :            :   /* segment is in DEFAULT format, but we want to send a TIME newsegment */
     491                 :          2 :   start_time = gst_util_uint64_scale_int (s->start, GST_SECOND,
     492                 :          2 :       wvparse->samplerate);
     493                 :            : 
     494         [ -  + ]:          2 :   if (s->stop != -1) {
     495                 :          0 :     stop_time = gst_util_uint64_scale_int (s->stop, GST_SECOND,
     496                 :          0 :         wvparse->samplerate);
     497                 :            :   }
     498                 :            : 
     499 [ -  + ][ #  # ]:          2 :   GST_DEBUG_OBJECT (wvparse, "sending newsegment from %" GST_TIME_FORMAT
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     500                 :            :       " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start_time),
     501                 :            :       GST_TIME_ARGS (stop_time));
     502                 :            : 
     503                 :            :   /* after a seek, s->last_stop will point to a chunk boundary, ie. from
     504                 :            :    * which sample we will start sending data again, while s->start will
     505                 :            :    * point to the sample we actually want to seek to and want to start
     506                 :            :    * playing right after the seek. Adjust clock-time for the difference
     507                 :            :    * so we start playing from start_time */
     508                 :          2 :   cur_pos_time = gst_util_uint64_scale_int (s->last_stop, GST_SECOND,
     509                 :          2 :       wvparse->samplerate);
     510                 :          2 :   diff = start_time - cur_pos_time;
     511                 :            : 
     512                 :          2 :   ret = gst_pad_push_event (wvparse->srcpad,
     513                 :            :       gst_event_new_new_segment (update, s->rate, GST_FORMAT_TIME,
     514                 :            :           start_time, stop_time, start_time - diff));
     515                 :            : 
     516                 :          2 :   return ret;
     517                 :            : }
     518                 :            : 
     519                 :            : static gboolean
     520                 :          0 : gst_wavpack_parse_handle_seek_event (GstWavpackParse * wvparse,
     521                 :            :     GstEvent * event)
     522                 :            : {
     523                 :            :   GstSeekFlags seek_flags;
     524                 :            : 
     525                 :            :   GstSeekType start_type;
     526                 :            : 
     527                 :            :   GstSeekType stop_type;
     528                 :            : 
     529                 :            :   GstSegment segment;
     530                 :            : 
     531                 :            :   GstFormat format;
     532                 :            : 
     533                 :            :   gboolean only_update;
     534                 :            : 
     535                 :            :   gboolean flush, ret;
     536                 :            : 
     537                 :            :   gdouble speed;
     538                 :            : 
     539                 :            :   gint64 stop;
     540                 :            : 
     541                 :            :   gint64 start;                 /* sample we want to seek to                  */
     542                 :            : 
     543                 :            :   gint64 byte_offset;           /* byte offset the chunk we seek to starts at */
     544                 :            : 
     545                 :            :   gint64 chunk_start;           /* first sample in chunk we seek to           */
     546                 :            : 
     547                 :            :   guint rate;
     548                 :            : 
     549                 :            :   gint64 last_stop;
     550                 :            : 
     551         [ #  # ]:          0 :   if (wvparse->adapter) {
     552         [ #  # ]:          0 :     GST_DEBUG_OBJECT (wvparse, "seeking in streaming mode not implemented yet");
     553                 :          0 :     return FALSE;
     554                 :            :   }
     555                 :            : 
     556                 :          0 :   gst_event_parse_seek (event, &speed, &format, &seek_flags, &start_type,
     557                 :            :       &start, &stop_type, &stop);
     558                 :            : 
     559 [ #  # ][ #  # ]:          0 :   if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME) {
     560         [ #  # ]:          0 :     GST_DEBUG ("seeking is only supported in TIME or DEFAULT format");
     561                 :          0 :     return FALSE;
     562                 :            :   }
     563                 :            : 
     564         [ #  # ]:          0 :   if (speed < 0.0) {
     565         [ #  # ]:          0 :     GST_DEBUG ("only forward playback supported, rate %f not allowed", speed);
     566                 :          0 :     return FALSE;
     567                 :            :   }
     568                 :            : 
     569                 :          0 :   GST_OBJECT_LOCK (wvparse);
     570                 :            : 
     571                 :          0 :   rate = wvparse->samplerate;
     572         [ #  # ]:          0 :   if (rate == 0) {
     573                 :          0 :     GST_OBJECT_UNLOCK (wvparse);
     574         [ #  # ]:          0 :     GST_DEBUG ("haven't read header yet");
     575                 :          0 :     return FALSE;
     576                 :            :   }
     577                 :            : 
     578                 :            :   /* figure out the last position we need to play. If it's configured (stop !=
     579                 :            :    * -1), use that, else we play until the total duration of the file */
     580         [ #  # ]:          0 :   if (stop == -1)
     581                 :          0 :     stop = wvparse->segment.duration;
     582                 :            : 
     583                 :            :   /* convert from time to samples if necessary */
     584         [ #  # ]:          0 :   if (format == GST_FORMAT_TIME) {
     585         [ #  # ]:          0 :     if (start_type != GST_SEEK_TYPE_NONE)
     586                 :          0 :       start = gst_util_uint64_scale_int (start, rate, GST_SECOND);
     587         [ #  # ]:          0 :     if (stop_type != GST_SEEK_TYPE_NONE)
     588                 :          0 :       stop = gst_util_uint64_scale_int (stop, rate, GST_SECOND);
     589                 :            :   }
     590                 :            : 
     591         [ #  # ]:          0 :   if (start < 0) {
     592                 :          0 :     GST_OBJECT_UNLOCK (wvparse);
     593         [ #  # ]:          0 :     GST_DEBUG_OBJECT (wvparse, "Invalid start sample %" G_GINT64_FORMAT, start);
     594                 :          0 :     return FALSE;
     595                 :            :   }
     596                 :            : 
     597                 :          0 :   flush = ((seek_flags & GST_SEEK_FLAG_FLUSH) != 0);
     598                 :            : 
     599                 :            :   /* operate on segment copy until we know the seek worked */
     600                 :          0 :   segment = wvparse->segment;
     601                 :            : 
     602                 :          0 :   gst_segment_set_seek (&segment, speed, GST_FORMAT_DEFAULT,
     603                 :            :       seek_flags, start_type, start, stop_type, stop, &only_update);
     604                 :            : 
     605                 :            : #if 0
     606                 :            :   if (only_update) {
     607                 :            :     wvparse->segment = segment;
     608                 :            :     gst_wavpack_parse_send_newsegment (wvparse, TRUE);
     609                 :            :     goto done;
     610                 :            :   }
     611                 :            : #endif
     612                 :            : 
     613                 :          0 :   gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_start ());
     614                 :            : 
     615         [ #  # ]:          0 :   if (flush) {
     616                 :          0 :     gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_start ());
     617                 :            :   } else {
     618                 :          0 :     gst_pad_pause_task (wvparse->sinkpad);
     619                 :            :   }
     620                 :            : 
     621                 :          0 :   GST_PAD_STREAM_LOCK (wvparse->sinkpad);
     622                 :            : 
     623                 :            :   /* Save current position */
     624                 :          0 :   last_stop = wvparse->segment.last_stop;
     625                 :            : 
     626                 :          0 :   gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_stop ());
     627                 :            : 
     628         [ #  # ]:          0 :   if (flush) {
     629                 :          0 :     gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_stop ());
     630                 :            :   }
     631                 :            : 
     632 [ #  # ][ #  # ]:          0 :   GST_DEBUG_OBJECT (wvparse, "Performing seek to %" GST_TIME_FORMAT " sample %"
         [ #  # ][ #  # ]
                 [ #  # ]
     633                 :            :       G_GINT64_FORMAT, GST_TIME_ARGS (segment.start * GST_SECOND / rate),
     634                 :            :       start);
     635                 :            : 
     636                 :          0 :   ret = gst_wavpack_parse_scan_to_find_sample (wvparse, segment.start,
     637                 :            :       &byte_offset, &chunk_start);
     638                 :            : 
     639         [ #  # ]:          0 :   if (ret) {
     640         [ #  # ]:          0 :     GST_DEBUG_OBJECT (wvparse, "new offset: %" G_GINT64_FORMAT, byte_offset);
     641                 :          0 :     wvparse->current_offset = byte_offset;
     642                 :            :     /* we want to send a newsegment event with the actual seek position
     643                 :            :      * as start, even though our first buffer might start before the
     644                 :            :      * configured segment. We leave it up to the decoder or sink to crop
     645                 :            :      * the output buffers accordingly */
     646                 :          0 :     wvparse->segment = segment;
     647                 :          0 :     wvparse->segment.last_stop = chunk_start;
     648                 :          0 :     wvparse->need_newsegment = TRUE;
     649                 :          0 :     wvparse->discont = (last_stop != chunk_start) ? TRUE : FALSE;
     650                 :            : 
     651                 :            :     /* if we're doing a segment seek, post a SEGMENT_START message */
     652         [ #  # ]:          0 :     if (wvparse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
     653                 :          0 :       gst_element_post_message (GST_ELEMENT_CAST (wvparse),
     654                 :            :           gst_message_new_segment_start (GST_OBJECT_CAST (wvparse),
     655                 :            :               wvparse->segment.format, wvparse->segment.last_stop));
     656                 :            :     }
     657                 :            :   } else {
     658         [ #  # ]:          0 :     GST_DEBUG_OBJECT (wvparse, "seek failed: don't know where to seek to");
     659                 :            :   }
     660                 :            : 
     661                 :          0 :   GST_PAD_STREAM_UNLOCK (wvparse->sinkpad);
     662                 :          0 :   GST_OBJECT_UNLOCK (wvparse);
     663                 :            : 
     664                 :          0 :   gst_pad_start_task (wvparse->sinkpad,
     665                 :            :       (GstTaskFunction) gst_wavpack_parse_loop, wvparse);
     666                 :            : 
     667                 :          0 :   return ret;
     668                 :            : }
     669                 :            : 
     670                 :            : static gboolean
     671                 :          0 : gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event)
     672                 :            : {
     673                 :            :   GstWavpackParse *parse;
     674                 :            : 
     675                 :          0 :   gboolean ret = TRUE;
     676                 :            : 
     677                 :          0 :   parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
     678                 :            : 
     679   [ #  #  #  # ]:          0 :   switch (GST_EVENT_TYPE (event)) {
     680                 :            :     case GST_EVENT_FLUSH_STOP:{
     681         [ #  # ]:          0 :       if (parse->adapter) {
     682                 :          0 :         gst_adapter_clear (parse->adapter);
     683                 :            :       }
     684         [ #  # ]:          0 :       if (parse->pending_buffer) {
     685                 :          0 :         gst_buffer_unref (parse->pending_buffer);
     686                 :          0 :         parse->pending_buffer = NULL;
     687                 :          0 :         parse->pending_offset = 0;
     688                 :            :       }
     689                 :          0 :       ret = gst_pad_push_event (parse->srcpad, event);
     690                 :          0 :       break;
     691                 :            :     }
     692                 :            :     case GST_EVENT_NEWSEGMENT:{
     693                 :          0 :       parse->need_newsegment = TRUE;
     694                 :          0 :       gst_event_unref (event);
     695                 :          0 :       ret = TRUE;
     696                 :          0 :       break;
     697                 :            :     }
     698                 :            :     case GST_EVENT_EOS:{
     699         [ #  # ]:          0 :       if (parse->adapter) {
     700                 :            :         /* remove all bytes that are left in the adapter after EOS. They can't
     701                 :            :          * be a complete Wavpack block and we can't do anything with them */
     702                 :          0 :         gst_adapter_clear (parse->adapter);
     703                 :            :       }
     704         [ #  # ]:          0 :       if (parse->pending_buffer) {
     705                 :          0 :         gst_buffer_unref (parse->pending_buffer);
     706                 :          0 :         parse->pending_buffer = NULL;
     707                 :          0 :         parse->pending_offset = 0;
     708                 :            :       }
     709                 :          0 :       ret = gst_pad_push_event (parse->srcpad, event);
     710                 :          0 :       break;
     711                 :            :     }
     712                 :            :     default:{
     713                 :            :       /* stream lock is recursive, should be fine for all events */
     714                 :          0 :       GST_PAD_STREAM_LOCK (pad);
     715         [ #  # ]:          0 :       if (parse->srcpad == NULL) {
     716                 :          0 :         parse->queued_events = g_list_append (parse->queued_events, event);
     717                 :            :       } else {
     718                 :          0 :         ret = gst_pad_push_event (parse->srcpad, event);
     719                 :            :       }
     720                 :          0 :       GST_PAD_STREAM_UNLOCK (pad);
     721                 :            :     }
     722                 :            :   }
     723                 :            : 
     724                 :            : 
     725                 :          0 :   gst_object_unref (parse);
     726                 :          0 :   return ret;
     727                 :            : }
     728                 :            : 
     729                 :            : static gboolean
     730                 :          0 : gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event)
     731                 :            : {
     732                 :            :   GstWavpackParse *parse;
     733                 :            : 
     734                 :            :   gboolean ret;
     735                 :            : 
     736                 :          0 :   parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad));
     737                 :            : 
     738         [ #  # ]:          0 :   switch (GST_EVENT_TYPE (event)) {
     739                 :            :     case GST_EVENT_SEEK:
     740                 :          0 :       ret = gst_wavpack_parse_handle_seek_event (parse, event);
     741                 :          0 :       break;
     742                 :            :     default:
     743                 :          0 :       ret = gst_pad_event_default (pad, event);
     744                 :          0 :       break;
     745                 :            :   }
     746                 :            : 
     747                 :          0 :   gst_object_unref (parse);
     748                 :          0 :   return ret;
     749                 :            : }
     750                 :            : 
     751                 :            : static void
     752                 :          5 : gst_wavpack_parse_init (GstWavpackParse * parse, GstWavpackParseClass * gclass)
     753                 :            : {
     754                 :          5 :   GstElementClass *klass = GST_ELEMENT_GET_CLASS (parse);
     755                 :            : 
     756                 :            :   GstPadTemplate *tmpl;
     757                 :            : 
     758                 :          5 :   tmpl = gst_element_class_get_pad_template (klass, "sink");
     759                 :          5 :   parse->sinkpad = gst_pad_new_from_template (tmpl, "sink");
     760                 :            : 
     761                 :          5 :   gst_pad_set_activate_function (parse->sinkpad,
     762                 :          5 :       GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate));
     763                 :          5 :   gst_pad_set_activatepull_function (parse->sinkpad,
     764                 :          5 :       GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate_pull));
     765                 :          5 :   gst_pad_set_event_function (parse->sinkpad,
     766                 :          5 :       GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_event));
     767                 :          5 :   gst_pad_set_chain_function (parse->sinkpad,
     768                 :          5 :       GST_DEBUG_FUNCPTR (gst_wavpack_parse_chain));
     769                 :            : 
     770                 :          5 :   gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad);
     771                 :            : 
     772                 :          5 :   parse->srcpad = NULL;
     773                 :          5 :   gst_wavpack_parse_reset (parse);
     774                 :          5 : }
     775                 :            : 
     776                 :            : static gint64
     777                 :          0 : gst_wavpack_parse_get_upstream_length (GstWavpackParse * parse)
     778                 :            : {
     779                 :          0 :   gint64 length = -1;
     780                 :            : 
     781                 :          0 :   GstFormat format = GST_FORMAT_BYTES;
     782                 :            : 
     783         [ #  # ]:          0 :   if (!gst_pad_query_peer_duration (parse->sinkpad, &format, &length)) {
     784                 :          0 :     length = -1;
     785                 :            :   } else {
     786         [ #  # ]:          0 :     GST_DEBUG ("upstream length: %" G_GINT64_FORMAT, length);
     787                 :            :   }
     788                 :          0 :   return length;
     789                 :            : }
     790                 :            : 
     791                 :            : static GstBuffer *
     792                 :          0 : gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse, gint64 offset,
     793                 :            :     guint size, GstFlowReturn * flow)
     794                 :            : {
     795                 :            :   GstFlowReturn flow_ret;
     796                 :            : 
     797                 :          0 :   GstBuffer *buf = NULL;
     798                 :            : 
     799         [ #  # ]:          0 :   if (offset + size > wvparse->upstream_length) {
     800                 :          0 :     wvparse->upstream_length = gst_wavpack_parse_get_upstream_length (wvparse);
     801         [ #  # ]:          0 :     if (offset + size > wvparse->upstream_length) {
     802         [ #  # ]:          0 :       GST_DEBUG_OBJECT (wvparse, "EOS: %" G_GINT64_FORMAT " + %u > %"
     803                 :            :           G_GINT64_FORMAT, offset, size, wvparse->upstream_length);
     804                 :          0 :       flow_ret = GST_FLOW_UNEXPECTED;
     805                 :          0 :       goto done;
     806                 :            :     }
     807                 :            :   }
     808                 :            : 
     809                 :          0 :   flow_ret = gst_pad_pull_range (wvparse->sinkpad, offset, size, &buf);
     810                 :            : 
     811         [ #  # ]:          0 :   if (flow_ret != GST_FLOW_OK) {
     812         [ #  # ]:          0 :     GST_DEBUG_OBJECT (wvparse, "pull_range (%" G_GINT64_FORMAT ", %u) "
     813                 :            :         "failed, flow: %s", offset, size, gst_flow_get_name (flow_ret));
     814                 :          0 :     buf = NULL;
     815                 :          0 :     goto done;
     816                 :            :   }
     817                 :            : 
     818         [ #  # ]:          0 :   if (GST_BUFFER_SIZE (buf) < size) {
     819         [ #  # ]:          0 :     GST_DEBUG_OBJECT (wvparse, "Short read at offset %" G_GINT64_FORMAT
     820                 :            :         ", got only %u of %u bytes", offset, GST_BUFFER_SIZE (buf), size);
     821                 :          0 :     gst_buffer_unref (buf);
     822                 :          0 :     buf = NULL;
     823                 :          0 :     flow_ret = GST_FLOW_UNEXPECTED;
     824                 :            :   }
     825                 :            : 
     826                 :            : done:
     827         [ #  # ]:          0 :   if (flow)
     828                 :          0 :     *flow = flow_ret;
     829                 :          0 :   return buf;
     830                 :            : }
     831                 :            : 
     832                 :            : static gboolean
     833                 :          2 : gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
     834                 :            :     WavpackHeader * header)
     835                 :            : {
     836                 :            :   GstWavpackMetadata meta;
     837                 :            : 
     838                 :          2 :   GstCaps *caps = NULL;
     839                 :            : 
     840                 :            :   guchar *bufptr;
     841                 :            : 
     842         [ -  + ]:          2 :   g_assert (wvparse->srcpad == NULL);
     843                 :            : 
     844                 :          2 :   bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader);
     845                 :            : 
     846         [ +  - ]:         12 :   while (gst_wavpack_read_metadata (&meta, GST_BUFFER_DATA (buf), &bufptr)) {
     847      [ -  +  + ]:         12 :     switch (meta.id) {
     848                 :            :       case ID_WVC_BITSTREAM:{
     849                 :          0 :         caps = gst_caps_new_simple ("audio/x-wavpack-correction",
     850                 :            :             "framed", G_TYPE_BOOLEAN, TRUE, NULL);
     851                 :          0 :         wvparse->srcpad =
     852                 :          0 :             gst_pad_new_from_template (gst_element_class_get_pad_template
     853                 :          0 :             (GST_ELEMENT_GET_CLASS (wvparse), "wvcsrc"), "wvcsrc");
     854                 :          0 :         break;
     855                 :            :       }
     856                 :            :       case ID_WV_BITSTREAM:
     857                 :            :       case ID_WVX_BITSTREAM:{
     858                 :          2 :         WavpackStreamReader *stream_reader = gst_wavpack_stream_reader_new ();
     859                 :            : 
     860                 :            :         WavpackContext *wpc;
     861                 :            : 
     862                 :            :         gchar error_msg[80];
     863                 :            : 
     864                 :            :         read_id rid;
     865                 :            : 
     866                 :            :         gint channel_mask;
     867                 :            : 
     868                 :          2 :         rid.buffer = GST_BUFFER_DATA (buf);
     869                 :          2 :         rid.length = GST_BUFFER_SIZE (buf);
     870                 :          2 :         rid.position = 0;
     871                 :            : 
     872                 :          2 :         wpc =
     873                 :            :             WavpackOpenFileInputEx (stream_reader, &rid, NULL, error_msg, 0, 0);
     874                 :            : 
     875         [ -  + ]:          2 :         if (!wpc)
     876                 :          0 :           return FALSE;
     877                 :            : 
     878                 :          2 :         wvparse->samplerate = WavpackGetSampleRate (wpc);
     879                 :          2 :         wvparse->channels = WavpackGetNumChannels (wpc);
     880                 :          2 :         wvparse->total_samples =
     881                 :          2 :             (header->total_samples ==
     882         [ +  + ]:          2 :             0xffffffff) ? G_GINT64_CONSTANT (-1) : header->total_samples;
     883                 :            : 
     884                 :          2 :         caps = gst_caps_new_simple ("audio/x-wavpack",
     885                 :            :             "width", G_TYPE_INT, WavpackGetBitsPerSample (wpc),
     886                 :            :             "channels", G_TYPE_INT, wvparse->channels,
     887                 :            :             "rate", G_TYPE_INT, wvparse->samplerate,
     888                 :            :             "framed", G_TYPE_BOOLEAN, TRUE, NULL);
     889                 :            : #ifdef WAVPACK_OLD_API
     890                 :            :         channel_mask = wpc->config.channel_mask;
     891                 :            : #else
     892                 :          2 :         channel_mask = WavpackGetChannelMask (wpc);
     893                 :            : #endif
     894         [ -  + ]:          2 :         if (channel_mask == 0)
     895                 :          0 :           channel_mask =
     896                 :          0 :               gst_wavpack_get_default_channel_mask (wvparse->channels);
     897                 :            : 
     898         [ +  - ]:          2 :         if (channel_mask != 0) {
     899         [ -  + ]:          2 :           if (!gst_wavpack_set_channel_layout (caps, channel_mask)) {
     900         [ #  # ]:          0 :             GST_WARNING_OBJECT (wvparse, "Failed to set channel layout");
     901                 :          0 :             gst_caps_unref (caps);
     902                 :          0 :             caps = NULL;
     903                 :          0 :             WavpackCloseFile (wpc);
     904                 :          0 :             g_free (stream_reader);
     905                 :          0 :             break;
     906                 :            :           }
     907                 :            :         }
     908                 :            : 
     909                 :          2 :         wvparse->srcpad =
     910                 :          2 :             gst_pad_new_from_template (gst_element_class_get_pad_template
     911                 :          2 :             (GST_ELEMENT_GET_CLASS (wvparse), "src"), "src");
     912                 :          2 :         WavpackCloseFile (wpc);
     913                 :          2 :         g_free (stream_reader);
     914                 :          2 :         break;
     915                 :            :       }
     916                 :            :       default:{
     917         [ -  + ]:         10 :         GST_LOG_OBJECT (wvparse, "unhandled ID: 0x%02x", meta.id);
     918                 :         10 :         break;
     919                 :            :       }
     920                 :            :     }
     921         [ +  + ]:         12 :     if (caps != NULL)
     922                 :          2 :       break;
     923                 :            :   }
     924                 :            : 
     925 [ +  - ][ -  + ]:          2 :   if (caps == NULL || wvparse->srcpad == NULL)
     926                 :          0 :     return FALSE;
     927                 :            : 
     928         [ -  + ]:          2 :   GST_DEBUG_OBJECT (wvparse, "Added src pad with caps %" GST_PTR_FORMAT, caps);
     929                 :            : 
     930                 :          2 :   gst_pad_set_query_function (wvparse->srcpad,
     931                 :          2 :       GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query));
     932                 :          2 :   gst_pad_set_query_type_function (wvparse->srcpad,
     933                 :          2 :       GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_src_query_types));
     934                 :          2 :   gst_pad_set_event_function (wvparse->srcpad,
     935                 :          2 :       GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event));
     936                 :            : 
     937                 :          2 :   gst_pad_set_caps (wvparse->srcpad, caps);
     938                 :          2 :   gst_caps_unref (caps);
     939                 :          2 :   gst_pad_use_fixed_caps (wvparse->srcpad);
     940                 :            : 
     941                 :          2 :   gst_object_ref (wvparse->srcpad);
     942                 :          2 :   gst_pad_set_active (wvparse->srcpad, TRUE);
     943                 :          2 :   gst_element_add_pad (GST_ELEMENT (wvparse), wvparse->srcpad);
     944                 :          2 :   gst_element_no_more_pads (GST_ELEMENT (wvparse));
     945                 :            : 
     946                 :          2 :   return TRUE;
     947                 :            : }
     948                 :            : 
     949                 :            : static GstFlowReturn
     950                 :          3 : gst_wavpack_parse_push_buffer (GstWavpackParse * wvparse, GstBuffer * buf,
     951                 :            :     WavpackHeader * header)
     952                 :            : {
     953                 :            :   GstFlowReturn ret;
     954                 :          3 :   wvparse->current_offset += header->ckSize + 8;
     955                 :            : 
     956                 :          3 :   wvparse->segment.last_stop = header->block_index;
     957                 :            : 
     958         [ +  + ]:          3 :   if (wvparse->need_newsegment) {
     959         [ +  - ]:          2 :     if (gst_wavpack_parse_send_newsegment (wvparse, FALSE))
     960                 :          2 :       wvparse->need_newsegment = FALSE;
     961                 :            :   }
     962                 :            : 
     963                 :            :   /* send any queued events */
     964         [ -  + ]:          3 :   if (wvparse->queued_events) {
     965                 :            :     GList *l;
     966                 :            : 
     967         [ #  # ]:          0 :     for (l = wvparse->queued_events; l != NULL; l = l->next) {
     968                 :          0 :       gst_pad_push_event (wvparse->srcpad, GST_EVENT (l->data));
     969                 :            :     }
     970                 :          0 :     g_list_free (wvparse->queued_events);
     971                 :          0 :     wvparse->queued_events = NULL;
     972                 :            :   }
     973                 :            : 
     974         [ +  - ]:          3 :   if (wvparse->pending_buffer == NULL) {
     975                 :          3 :     wvparse->pending_buffer = buf;
     976                 :          3 :     wvparse->pending_offset = header->block_index;
     977         [ #  # ]:          0 :   } else if (wvparse->pending_offset == header->block_index) {
     978                 :          0 :     wvparse->pending_buffer = gst_buffer_join (wvparse->pending_buffer, buf);
     979                 :            :   } else {
     980         [ #  # ]:          0 :     GST_ERROR ("Got incomplete block, dropping");
     981                 :          0 :     gst_buffer_unref (wvparse->pending_buffer);
     982                 :          0 :     wvparse->pending_buffer = buf;
     983                 :          0 :     wvparse->pending_offset = header->block_index;
     984                 :            :   }
     985                 :            : 
     986         [ -  + ]:          3 :   if (!(header->flags & FINAL_BLOCK))
     987                 :          0 :     return GST_FLOW_OK;
     988                 :            : 
     989                 :          3 :   buf = wvparse->pending_buffer;
     990                 :          3 :   wvparse->pending_buffer = NULL;
     991                 :            : 
     992                 :          3 :   GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (header->block_index,
     993                 :          3 :       GST_SECOND, wvparse->samplerate);
     994                 :          3 :   GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (header->block_samples,
     995                 :          3 :       GST_SECOND, wvparse->samplerate);
     996                 :          3 :   GST_BUFFER_OFFSET (buf) = header->block_index;
     997                 :          3 :   GST_BUFFER_OFFSET_END (buf) = header->block_index + header->block_samples;
     998                 :            : 
     999 [ +  + ][ -  + ]:          3 :   if (wvparse->discont || wvparse->next_block_index != header->block_index) {
    1000                 :          2 :     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
    1001                 :          2 :     wvparse->discont = FALSE;
    1002                 :            :   }
    1003                 :            : 
    1004                 :          3 :   wvparse->next_block_index = header->block_index + header->block_samples;
    1005                 :            : 
    1006                 :          3 :   gst_buffer_set_caps (buf, GST_PAD_CAPS (wvparse->srcpad));
    1007                 :            : 
    1008 [ -  + ][ #  # ]:          3 :   GST_LOG_OBJECT (wvparse, "Pushing buffer with time %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
    1009                 :            :       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
    1010                 :            : 
    1011                 :          3 :   ret = gst_pad_push (wvparse->srcpad, buf);
    1012                 :            : 
    1013                 :          3 :   wvparse->segment.last_stop = wvparse->next_block_index;
    1014                 :            : 
    1015                 :          3 :   return ret;
    1016                 :            : }
    1017                 :            : 
    1018                 :            : static guint8 *
    1019                 :          1 : gst_wavpack_parse_find_marker (guint8 * buf, guint size)
    1020                 :            : {
    1021                 :            :   int i;
    1022                 :            : 
    1023                 :          1 :   guint8 *ret = NULL;
    1024                 :            : 
    1025         [ -  + ]:          1 :   if (G_UNLIKELY (size < 4))
    1026                 :          0 :     return NULL;
    1027                 :            : 
    1028         [ +  - ]:        107 :   for (i = 0; i < size - 4; i++) {
    1029         [ +  + ]:        107 :     if (memcmp (buf + i, "wvpk", 4) == 0) {
    1030                 :          1 :       ret = buf + i;
    1031                 :          1 :       break;
    1032                 :            :     }
    1033                 :            :   }
    1034                 :          1 :   return ret;
    1035                 :            : }
    1036                 :            : 
    1037                 :            : static GstFlowReturn
    1038                 :          0 : gst_wavpack_parse_resync_loop (GstWavpackParse * parse, WavpackHeader * header)
    1039                 :            : {
    1040                 :          0 :   GstFlowReturn flow_ret = GST_FLOW_UNEXPECTED;
    1041                 :            : 
    1042                 :          0 :   GstBuffer *buf = NULL;
    1043                 :            : 
    1044                 :            :   /* loop until we have a frame header or reach the end of the stream */
    1045                 :            :   while (1) {
    1046                 :            :     guint8 *data, *marker;
    1047                 :            : 
    1048                 :            :     guint len, size;
    1049                 :            : 
    1050         [ #  # ]:          0 :     if (buf) {
    1051                 :          0 :       gst_buffer_unref (buf);
    1052                 :          0 :       buf = NULL;
    1053                 :            :     }
    1054                 :            : 
    1055 [ #  # ][ #  # ]:          0 :     if (parse->upstream_length == 0 ||
    1056                 :          0 :         parse->upstream_length <= parse->current_offset) {
    1057                 :          0 :       parse->upstream_length = gst_wavpack_parse_get_upstream_length (parse);
    1058 [ #  # ][ #  # ]:          0 :       if (parse->upstream_length == 0 ||
    1059                 :          0 :           parse->upstream_length <= parse->current_offset) {
    1060                 :            :         break;
    1061                 :            :       }
    1062                 :            :     }
    1063                 :            : 
    1064                 :          0 :     len = MIN (parse->upstream_length - parse->current_offset, 2048);
    1065                 :            : 
    1066         [ #  # ]:          0 :     GST_LOG_OBJECT (parse, "offset: %" G_GINT64_FORMAT, parse->current_offset);
    1067                 :            : 
    1068                 :          0 :     buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset,
    1069                 :            :         len, &flow_ret);
    1070                 :            : 
    1071                 :            :     /* whatever the problem is, there's nothing more for us to do for now */
    1072         [ #  # ]:          0 :     if (flow_ret != GST_FLOW_OK)
    1073                 :          0 :       break;
    1074                 :            : 
    1075                 :          0 :     data = GST_BUFFER_DATA (buf);
    1076                 :          0 :     size = GST_BUFFER_SIZE (buf);
    1077                 :            : 
    1078                 :            :     /* not enough data for a header? */
    1079         [ #  # ]:          0 :     if (size < sizeof (WavpackHeader))
    1080                 :          0 :       break;
    1081                 :            : 
    1082                 :            :     /* got a header right where we are at now? */
    1083         [ #  # ]:          0 :     if (gst_wavpack_read_header (header, data))
    1084                 :          0 :       break;
    1085                 :            : 
    1086                 :            :     /* nope, let's see if we can find one */
    1087                 :          0 :     marker = gst_wavpack_parse_find_marker (data + 1, size - 1);
    1088                 :            : 
    1089         [ #  # ]:          0 :     if (marker) {
    1090                 :          0 :       parse->current_offset += marker - data;
    1091                 :            :       /* do one more loop iteration to make sure we pull enough
    1092                 :            :        * data for a full header, we'll bail out then */
    1093                 :            :     } else {
    1094                 :          0 :       parse->current_offset += len - 4;
    1095                 :            :     }
    1096                 :          0 :   }
    1097                 :            : 
    1098         [ #  # ]:          0 :   if (buf)
    1099                 :          0 :     gst_buffer_unref (buf);
    1100                 :            : 
    1101                 :          0 :   return flow_ret;
    1102                 :            : }
    1103                 :            : 
    1104                 :            : static void
    1105                 :          0 : gst_wavpack_parse_loop (GstElement * element)
    1106                 :            : {
    1107                 :          0 :   GstWavpackParse *parse = GST_WAVPACK_PARSE (element);
    1108                 :            : 
    1109                 :            :   GstFlowReturn flow_ret;
    1110                 :          0 :   WavpackHeader header = { {0,}, 0, };
    1111                 :          0 :   GstBuffer *buf = NULL;
    1112                 :            : 
    1113                 :          0 :   flow_ret = gst_wavpack_parse_resync_loop (parse, &header);
    1114                 :            : 
    1115         [ #  # ]:          0 :   if (flow_ret != GST_FLOW_OK)
    1116                 :          0 :     goto pause;
    1117                 :            : 
    1118         [ #  # ]:          0 :   GST_LOG_OBJECT (parse, "Read header at offset %" G_GINT64_FORMAT
    1119                 :            :       ": chunk size = %u+8", parse->current_offset, header.ckSize);
    1120                 :            : 
    1121                 :          0 :   buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset,
    1122                 :          0 :       header.ckSize + 8, &flow_ret);
    1123                 :            : 
    1124         [ #  # ]:          0 :   if (flow_ret != GST_FLOW_OK)
    1125                 :          0 :     goto pause;
    1126                 :            : 
    1127         [ #  # ]:          0 :   if (parse->srcpad == NULL) {
    1128         [ #  # ]:          0 :     if (!gst_wavpack_parse_create_src_pad (parse, buf, &header)) {
    1129         [ #  # ]:          0 :       GST_ERROR_OBJECT (parse, "Failed to create src pad");
    1130                 :          0 :       flow_ret = GST_FLOW_ERROR;
    1131                 :          0 :       goto pause;
    1132                 :            :     }
    1133                 :            :   }
    1134         [ #  # ]:          0 :   if (header.flags & INITIAL_BLOCK)
    1135                 :          0 :     gst_wavpack_parse_index_append_entry (parse, parse->current_offset,
    1136                 :          0 :         header.block_index, header.block_samples);
    1137                 :            : 
    1138                 :          0 :   flow_ret = gst_wavpack_parse_push_buffer (parse, buf, &header);
    1139         [ #  # ]:          0 :   if (flow_ret != GST_FLOW_OK)
    1140                 :          0 :     goto pause;
    1141                 :            : 
    1142                 :          0 :   return;
    1143                 :            : 
    1144                 :            : pause:
    1145                 :            :   {
    1146                 :          0 :     const gchar *reason = gst_flow_get_name (flow_ret);
    1147                 :            : 
    1148         [ #  # ]:          0 :     GST_LOG_OBJECT (parse, "pausing task, reason %s", reason);
    1149                 :          0 :     gst_pad_pause_task (parse->sinkpad);
    1150                 :            : 
    1151 [ #  # ][ #  # ]:          0 :     if (flow_ret == GST_FLOW_UNEXPECTED && parse->srcpad) {
    1152         [ #  # ]:          0 :       if (parse->segment.flags & GST_SEEK_FLAG_SEGMENT) {
    1153                 :            :         GstClockTime stop;
    1154                 :            : 
    1155         [ #  # ]:          0 :         GST_LOG_OBJECT (parse, "Sending segment done");
    1156                 :            : 
    1157         [ #  # ]:          0 :         if ((stop = parse->segment.stop) == -1)
    1158                 :          0 :           stop = parse->segment.duration;
    1159                 :            : 
    1160                 :          0 :         gst_element_post_message (GST_ELEMENT_CAST (parse),
    1161                 :            :             gst_message_new_segment_done (GST_OBJECT_CAST (parse),
    1162                 :            :                 parse->segment.format, stop));
    1163                 :            :       } else {
    1164         [ #  # ]:          0 :         GST_LOG_OBJECT (parse, "Sending EOS, at end of stream");
    1165                 :          0 :         gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
    1166                 :            :       }
    1167         [ #  # ]:          0 :     } else if (flow_ret == GST_FLOW_NOT_LINKED
    1168         [ #  # ]:          0 :         || flow_ret < GST_FLOW_UNEXPECTED) {
    1169 [ #  # ][ #  # ]:          0 :       GST_ELEMENT_ERROR (parse, STREAM, FAILED,
         [ #  # ][ #  # ]
    1170                 :            :           (_("Internal data stream error.")), ("stream stopped, reason %s",
    1171                 :            :               reason));
    1172         [ #  # ]:          0 :       if (parse->srcpad)
    1173                 :          0 :         gst_pad_push_event (parse->srcpad, gst_event_new_eos ());
    1174                 :            :     }
    1175                 :          0 :     return;
    1176                 :            :   }
    1177                 :            : }
    1178                 :            : 
    1179                 :            : static gboolean
    1180                 :          3 : gst_wavpack_parse_resync_adapter (GstAdapter * adapter)
    1181                 :            : {
    1182                 :            :   const guint8 *buf, *marker;
    1183                 :            : 
    1184                 :          3 :   guint avail = gst_adapter_available (adapter);
    1185                 :            : 
    1186         [ -  + ]:          3 :   if (avail < 4)
    1187                 :          0 :     return FALSE;
    1188                 :            : 
    1189                 :            :   /* if the marker is at the beginning don't do the expensive search */
    1190                 :          3 :   buf = gst_adapter_peek (adapter, 4);
    1191         [ +  + ]:          3 :   if (memcmp (buf, "wvpk", 4) == 0)
    1192                 :          2 :     return TRUE;
    1193                 :            : 
    1194         [ -  + ]:          1 :   if (avail == 4)
    1195                 :          0 :     return FALSE;
    1196                 :            : 
    1197                 :            :   /* search for the marker in the complete content of the adapter */
    1198                 :          1 :   buf = gst_adapter_peek (adapter, avail);
    1199 [ +  - ][ +  - ]:          1 :   if (buf && (marker = gst_wavpack_parse_find_marker ((guint8 *) buf, avail))) {
    1200                 :          1 :     gst_adapter_flush (adapter, marker - buf);
    1201                 :          1 :     return TRUE;
    1202                 :            :   }
    1203                 :            : 
    1204                 :            :   /* flush everything except the last 4 bytes. they could contain
    1205                 :            :    * the start of a new marker */
    1206                 :          0 :   gst_adapter_flush (adapter, avail - 4);
    1207                 :            : 
    1208                 :          3 :   return FALSE;
    1209                 :            : }
    1210                 :            : 
    1211                 :            : static GstFlowReturn
    1212                 :          2 : gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf)
    1213                 :            : {
    1214                 :          2 :   GstWavpackParse *wvparse = GST_WAVPACK_PARSE (GST_PAD_PARENT (pad));
    1215                 :            : 
    1216                 :          2 :   GstFlowReturn ret = GST_FLOW_OK;
    1217                 :            : 
    1218                 :            :   WavpackHeader wph;
    1219                 :            : 
    1220                 :            :   const guint8 *tmp_buf;
    1221                 :            : 
    1222         [ +  - ]:          2 :   if (!wvparse->adapter) {
    1223                 :          2 :     wvparse->adapter = gst_adapter_new ();
    1224                 :            :   }
    1225                 :            : 
    1226         [ -  + ]:          2 :   if (GST_BUFFER_IS_DISCONT (buf)) {
    1227                 :          0 :     gst_adapter_clear (wvparse->adapter);
    1228                 :          0 :     wvparse->discont = TRUE;
    1229                 :            :   }
    1230                 :            : 
    1231                 :          2 :   gst_adapter_push (wvparse->adapter, buf);
    1232                 :            : 
    1233         [ -  + ]:          2 :   if (gst_adapter_available (wvparse->adapter) < sizeof (WavpackHeader))
    1234                 :          0 :     return ret;
    1235                 :            : 
    1236         [ -  + ]:          2 :   if (!gst_wavpack_parse_resync_adapter (wvparse->adapter))
    1237                 :          0 :     return ret;
    1238                 :            : 
    1239                 :          2 :   tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader));
    1240                 :          2 :   gst_wavpack_read_header (&wph, (guint8 *) tmp_buf);
    1241                 :            : 
    1242         [ +  + ]:          5 :   while (gst_adapter_available (wvparse->adapter) >= wph.ckSize + 4 * 1 + 4) {
    1243                 :          3 :     GstBuffer *outbuf =
    1244                 :          3 :         gst_adapter_take_buffer (wvparse->adapter, wph.ckSize + 4 * 1 + 4);
    1245                 :            : 
    1246         [ -  + ]:          3 :     if (!outbuf)
    1247                 :          0 :       return GST_FLOW_ERROR;
    1248                 :            : 
    1249         [ +  + ]:          3 :     if (wvparse->srcpad == NULL) {
    1250         [ -  + ]:          2 :       if (!gst_wavpack_parse_create_src_pad (wvparse, outbuf, &wph)) {
    1251         [ #  # ]:          0 :         GST_ERROR_OBJECT (wvparse, "Failed to create src pad");
    1252                 :          0 :         ret = GST_FLOW_ERROR;
    1253                 :          0 :         break;
    1254                 :            :       }
    1255                 :            :     }
    1256                 :            : 
    1257                 :          3 :     ret = gst_wavpack_parse_push_buffer (wvparse, outbuf, &wph);
    1258                 :            : 
    1259         [ -  + ]:          3 :     if (ret != GST_FLOW_OK)
    1260                 :          0 :       break;
    1261                 :            : 
    1262         [ +  + ]:          3 :     if (gst_adapter_available (wvparse->adapter) >= sizeof (WavpackHeader)) {
    1263                 :          1 :       tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader));
    1264                 :            : 
    1265         [ -  + ]:          1 :       if (!gst_wavpack_parse_resync_adapter (wvparse->adapter))
    1266                 :          0 :         break;
    1267                 :            : 
    1268                 :          1 :       gst_wavpack_read_header (&wph, (guint8 *) tmp_buf);
    1269                 :            :     }
    1270                 :            :   }
    1271                 :            : 
    1272                 :          2 :   return ret;
    1273                 :            : }
    1274                 :            : 
    1275                 :            : static GstStateChangeReturn
    1276                 :         46 : gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition)
    1277                 :            : {
    1278                 :         46 :   GstWavpackParse *wvparse = GST_WAVPACK_PARSE (element);
    1279                 :            : 
    1280                 :         46 :   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
    1281                 :            : 
    1282         [ +  + ]:         46 :   switch (transition) {
    1283                 :            :     case GST_STATE_CHANGE_READY_TO_PAUSED:
    1284                 :          9 :       gst_segment_init (&wvparse->segment, GST_FORMAT_DEFAULT);
    1285                 :          9 :       wvparse->segment.last_stop = 0;
    1286                 :            :     default:
    1287                 :         46 :       break;
    1288                 :            :   }
    1289                 :            : 
    1290         [ +  - ]:         46 :   if (GST_ELEMENT_CLASS (parent_class)->change_state)
    1291                 :         46 :     ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
    1292                 :            : 
    1293         [ +  + ]:         46 :   switch (transition) {
    1294                 :            :     case GST_STATE_CHANGE_PAUSED_TO_READY:
    1295                 :          9 :       gst_wavpack_parse_reset (wvparse);
    1296                 :          9 :       break;
    1297                 :            :     default:
    1298                 :         37 :       break;
    1299                 :            :   }
    1300                 :            : 
    1301                 :         46 :   return ret;
    1302                 :            : }
    1303                 :            : 
    1304                 :            : static gboolean
    1305                 :          9 : gst_wavpack_parse_sink_activate (GstPad * sinkpad)
    1306                 :            : {
    1307         [ -  + ]:          9 :   if (gst_pad_check_pull_range (sinkpad)) {
    1308                 :          0 :     return gst_pad_activate_pull (sinkpad, TRUE);
    1309                 :            :   } else {
    1310                 :          9 :     return gst_pad_activate_push (sinkpad, TRUE);
    1311                 :            :   }
    1312                 :            : }
    1313                 :            : 
    1314                 :            : static gboolean
    1315                 :          0 : gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active)
    1316                 :            : {
    1317                 :            :   gboolean result;
    1318                 :            : 
    1319         [ #  # ]:          0 :   if (active) {
    1320                 :          0 :     result = gst_pad_start_task (sinkpad,
    1321                 :          0 :         (GstTaskFunction) gst_wavpack_parse_loop, GST_PAD_PARENT (sinkpad));
    1322                 :            :   } else {
    1323                 :          0 :     result = gst_pad_stop_task (sinkpad);
    1324                 :            :   }
    1325                 :            : 
    1326                 :          0 :   return result;
    1327                 :            : }
    1328                 :            : 
    1329                 :            : gboolean
    1330                 :         11 : gst_wavpack_parse_plugin_init (GstPlugin * plugin)
    1331                 :            : {
    1332         [ -  + ]:         11 :   if (!gst_element_register (plugin, "wavpackparse",
    1333                 :            :           GST_RANK_PRIMARY, GST_TYPE_WAVPACK_PARSE)) {
    1334                 :          0 :     return FALSE;
    1335                 :            :   }
    1336                 :            : 
    1337         [ +  - ]:         11 :   GST_DEBUG_CATEGORY_INIT (gst_wavpack_parse_debug, "wavpack_parse", 0,
    1338                 :            :       "Wavpack file parser");
    1339                 :            : 
    1340                 :         11 :   return TRUE;
    1341                 :            : }

Generated by: LCOV version 1.9