alaw-decode.c 10.3 KB
Newer Older
1 2
/* GStreamer A-Law to PCM conversion
 * Copyright (C) 2000 by Abramo Bagnara <abramo@alsa-project.org>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
3 4 5 6
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
Benjamin Otte's avatar
Benjamin Otte committed
7
 * version 2.1 of the License, or (at your option) any later version.
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
19 20 21 22 23
/**
 * SECTION:element-alawdec
 *
 * This element decodes alaw audio. Alaw coding is also known as G.711.
 */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
24

25 26 27
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
28

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
29 30
#include "alaw-decode.h"

31 32
extern GstStaticPadTemplate alaw_dec_src_factory;
extern GstStaticPadTemplate alaw_dec_sink_factory;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
33

34 35
GST_DEBUG_CATEGORY_STATIC (alaw_dec_debug);
#define GST_CAT_DEFAULT alaw_dec_debug
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
36

37
static GstStateChangeReturn
38 39
gst_alaw_dec_change_state (GstElement * element, GstStateChange transition);
static GstFlowReturn gst_alaw_dec_chain (GstPad * pad, GstBuffer * buffer);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
40

41
GST_BOILERPLATE (GstALawDec, gst_alaw_dec, GstElement, GST_TYPE_ELEMENT);
Benjamin Otte's avatar
Benjamin Otte committed
42

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
/* some day we might have defines in gstconfig.h that tell us about the
 * desired cpu/memory/binary size trade-offs */
#define GST_ALAW_DEC_USE_TABLE

#ifdef GST_ALAW_DEC_USE_TABLE

static const gint alaw_to_s16_table[256] = {
  -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
  -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
  -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
  -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
  -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
  -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
  -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
  -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
  -344, -328, -376, -360, -280, -264, -312, -296,
  -472, -456, -504, -488, -408, -392, -440, -424,
  -88, -72, -120, -104, -24, -8, -56, -40,
  -216, -200, -248, -232, -152, -136, -184, -168,
  -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
  -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
  -688, -656, -752, -720, -560, -528, -624, -592,
  -944, -912, -1008, -976, -816, -784, -880, -848,
  5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
  7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
  2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
  3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
  22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
  30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
  11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
  15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
  344, 328, 376, 360, 280, 264, 312, 296,
  472, 456, 504, 488, 408, 392, 440, 424,
  88, 72, 120, 104, 24, 8, 56, 40,
  216, 200, 248, 232, 152, 136, 184, 168,
  1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
  1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
  688, 656, 752, 720, 560, 528, 624, 592,
  944, 912, 1008, 976, 816, 784, 880, 848
};

static inline gint
alaw_to_s16 (guint8 a_val)
{
  return alaw_to_s16_table[a_val];
}

#else /* GST_ALAW_DEC_USE_TABLE */

static inline gint
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
93
alaw_to_s16 (guint8 a_val)
Benjamin Otte's avatar
Benjamin Otte committed
94
{
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
95 96 97 98 99 100 101 102 103 104 105 106 107
  gint t;
  gint seg;

  a_val ^= 0x55;
  t = a_val & 0x7f;
  if (t < 16)
    t = (t << 4) + 8;
  else {
    seg = (t >> 4) & 0x07;
    t = ((t & 0x0f) << 4) + 0x108;
    t <<= seg - 1;
  }
  return ((a_val & 0x80) ? t : -t);
Benjamin Otte's avatar
Benjamin Otte committed
108 109
}

110 111
#endif /* GST_ALAW_DEC_USE_TABLE */

112
static gboolean
113
gst_alaw_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
114
{
115
  GstALawDec *alawdec;
David Schleef's avatar
David Schleef committed
116
  GstStructure *structure;
117 118
  int rate, channels;
  gboolean ret;
119
  GstCaps *outcaps;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
120

121
  alawdec = GST_ALAW_DEC (GST_PAD_PARENT (pad));
122

David Schleef's avatar
David Schleef committed
123
  structure = gst_caps_get_structure (caps, 0);
124

125
  ret = gst_structure_get_int (structure, "rate", &rate);
126
  ret &= gst_structure_get_int (structure, "channels", &channels);
127
  if (!ret)
128
    return FALSE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
129

130
  outcaps = gst_caps_new_simple ("audio/x-raw-int",
131 132 133 134 135
      "width", G_TYPE_INT, 16,
      "depth", G_TYPE_INT, 16,
      "endianness", G_TYPE_INT, G_BYTE_ORDER,
      "signed", G_TYPE_BOOLEAN, TRUE,
      "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL);
136

137 138
  ret = gst_pad_set_caps (alawdec->srcpad, outcaps);
  gst_caps_unref (outcaps);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
139

140 141 142 143 144 145
  if (ret) {
    GST_DEBUG_OBJECT (alawdec, "rate=%d, channels=%d", rate, channels);
    alawdec->rate = rate;
    alawdec->channels = channels;
  }
  return ret;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
146 147
}

148 149 150 151 152
static GstCaps *
gst_alaw_dec_getcaps (GstPad * pad)
{
  GstALawDec *alawdec;
  GstPad *otherpad;
Wim Taymans's avatar
Wim Taymans committed
153 154
  GstCaps *othercaps, *result;
  const GstCaps *templ;
155
  const gchar *name;
Wim Taymans's avatar
Wim Taymans committed
156
  gint i;
157 158 159

  alawdec = GST_ALAW_DEC (GST_PAD_PARENT (pad));

Wim Taymans's avatar
Wim Taymans committed
160
  /* figure out the name of the caps we are going to return */
161
  if (pad == alawdec->srcpad) {
Wim Taymans's avatar
Wim Taymans committed
162
    name = "audio/x-raw-int";
163 164
    otherpad = alawdec->sinkpad;
  } else {
Wim Taymans's avatar
Wim Taymans committed
165
    name = "audio/x-alaw";
166 167
    otherpad = alawdec->srcpad;
  }
Wim Taymans's avatar
Wim Taymans committed
168
  /* get caps from the peer, this can return NULL when there is no peer */
169 170
  othercaps = gst_pad_peer_get_caps (otherpad);

Wim Taymans's avatar
Wim Taymans committed
171 172
  /* get the template caps to make sure we return something acceptable */
  templ = gst_pad_get_pad_template_caps (pad);
173

Wim Taymans's avatar
Wim Taymans committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  if (othercaps) {
    /* there was a peer */
    othercaps = gst_caps_make_writable (othercaps);

    /* go through the caps and remove the fields we don't want */
    for (i = 0; i < gst_caps_get_size (othercaps); i++) {
      GstStructure *structure;

      structure = gst_caps_get_structure (othercaps, i);

      /* adjust the name */
      gst_structure_set_name (structure, name);

      if (pad == alawdec->sinkpad) {
        /* remove the fields we don't want */
        gst_structure_remove_fields (structure, "width", "depth", "endianness",
            "signed", NULL);
      } else {
        /* add fixed fields */
        gst_structure_set (structure, "width", G_TYPE_INT, 16,
            "depth", G_TYPE_INT, 16,
            "endianness", G_TYPE_INT, G_BYTE_ORDER,
            "signed", G_TYPE_BOOLEAN, TRUE, NULL);
      }
    }
    /* filter against the allowed caps of the pad to return our result */
    result = gst_caps_intersect (othercaps, templ);
201
    gst_caps_unref (othercaps);
Wim Taymans's avatar
Wim Taymans committed
202 203 204
  } else {
    /* there was no peer, return the template caps */
    result = gst_caps_copy (templ);
205
  }
Wim Taymans's avatar
Wim Taymans committed
206 207

  return result;
208 209
}

Ronald S. Bultje's avatar
......  
Ronald S. Bultje committed
210
static void
211
gst_alaw_dec_base_init (gpointer klass)
Ronald S. Bultje's avatar
......  
Ronald S. Bultje committed
212 213 214
{
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

215 216 217 218
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&alaw_dec_src_factory));
  gst_element_class_add_pad_template (element_class,
      gst_static_pad_template_get (&alaw_dec_sink_factory));
219 220 221 222 223 224

  gst_element_class_set_details_simple (element_class, "A Law audio decoder",
      "Codec/Decoder/Audio", "Convert 8bit A law to 16bit PCM",
      "Zaheer Abbas Merali <zaheerabbas at merali dot org>");

  GST_DEBUG_CATEGORY_INIT (alaw_dec_debug, "alawdec", 0, "A Law audio decoder");
Ronald S. Bultje's avatar
......  
Ronald S. Bultje committed
225 226
}

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
227
static void
228
gst_alaw_dec_class_init (GstALawDecClass * klass)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
229
{
230 231
  GstElementClass *element_class = (GstElementClass *) klass;

232
  element_class->change_state = GST_DEBUG_FUNCPTR (gst_alaw_dec_change_state);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
233 234 235
}

static void
236
gst_alaw_dec_init (GstALawDec * alawdec, GstALawDecClass * klass)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
237
{
238 239
  alawdec->sinkpad =
      gst_pad_new_from_static_template (&alaw_dec_sink_factory, "sink");
240 241
  gst_pad_set_setcaps_function (alawdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_alaw_dec_sink_setcaps));
242 243
  gst_pad_set_getcaps_function (alawdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_alaw_dec_getcaps));
244 245
  gst_pad_set_chain_function (alawdec->sinkpad,
      GST_DEBUG_FUNCPTR (gst_alaw_dec_chain));
246 247
  gst_element_add_pad (GST_ELEMENT (alawdec), alawdec->sinkpad);

248 249
  alawdec->srcpad =
      gst_pad_new_from_static_template (&alaw_dec_src_factory, "src");
250
  gst_pad_use_fixed_caps (alawdec->srcpad);
251 252
  gst_pad_set_getcaps_function (alawdec->srcpad,
      GST_DEBUG_FUNCPTR (gst_alaw_dec_getcaps));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
253
  gst_element_add_pad (GST_ELEMENT (alawdec), alawdec->srcpad);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
254 255
}

256
static GstFlowReturn
257
gst_alaw_dec_chain (GstPad * pad, GstBuffer * buffer)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
258 259 260 261
{
  GstALawDec *alawdec;
  gint16 *linear_data;
  guint8 *alaw_data;
262
  guint alaw_size;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
263
  GstBuffer *outbuf;
Benjamin Otte's avatar
Benjamin Otte committed
264
  gint i;
265
  GstFlowReturn ret;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
266

267 268
  alawdec = GST_ALAW_DEC (GST_PAD_PARENT (pad));

269
  if (G_UNLIKELY (alawdec->rate == 0))
270 271 272 273
    goto not_negotiated;

  GST_LOG_OBJECT (alawdec, "buffer with ts=%" GST_TIME_FORMAT,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
274 275 276 277

  alaw_data = GST_BUFFER_DATA (buffer);
  alaw_size = GST_BUFFER_SIZE (buffer);

278 279 280 281 282 283 284
  ret =
      gst_pad_alloc_buffer_and_set_caps (alawdec->srcpad,
      GST_BUFFER_OFFSET_NONE, alaw_size * 2, GST_PAD_CAPS (alawdec->srcpad),
      &outbuf);
  if (ret != GST_FLOW_OK)
    goto alloc_failed;

285 286 287 288 289
  linear_data = (gint16 *) GST_BUFFER_DATA (outbuf);

  /* copy discont flag */
  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
290

291 292
  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
  GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer);
293
  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (alawdec->srcpad));
294

295 296
  for (i = 0; i < alaw_size; i++) {
    linear_data[i] = alaw_to_s16 (alaw_data[i]);
Benjamin Otte's avatar
Benjamin Otte committed
297
  }
298
  gst_buffer_unref (buffer);
299 300 301 302

  ret = gst_pad_push (alawdec->srcpad, outbuf);

  return ret;
303 304 305

not_negotiated:
  {
306
    gst_buffer_unref (buffer);
307 308
    GST_WARNING_OBJECT (alawdec, "no input format set: not-negotiated");
    return GST_FLOW_NOT_NEGOTIATED;
309 310 311 312
  }
alloc_failed:
  {
    gst_buffer_unref (buffer);
313
    GST_DEBUG_OBJECT (alawdec, "pad alloc failed, flow: %s",
314
        gst_flow_get_name (ret));
315
    return ret;
316
  }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
317
}
318 319

static GstStateChangeReturn
320
gst_alaw_dec_change_state (GstElement * element, GstStateChange transition)
321 322
{
  GstStateChangeReturn ret;
323
  GstALawDec *dec = GST_ALAW_DEC (element);
324 325 326 327 328 329 330 331 332 333 334 335

  switch (transition) {
    default:
      break;
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  if (ret != GST_STATE_CHANGE_SUCCESS)
    return ret;

  switch (transition) {
    case GST_STATE_CHANGE_PAUSED_TO_READY:
336 337
      dec->rate = 0;
      dec->channels = 0;
338 339 340 341 342 343 344
      break;
    default:
      break;
  }

  return ret;
}