Esempio n. 1
0
static gboolean
gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps)
{
  GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad));
  GstStructure *structure = gst_caps_get_structure (caps, 0);
  GstAudioChannelPosition *pos;

  if (!gst_structure_get_int (structure, "channels", &enc->channels) ||
      !gst_structure_get_int (structure, "rate", &enc->samplerate) ||
      !gst_structure_get_int (structure, "depth", &enc->depth)) {
    GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
        ("got invalid caps: %" GST_PTR_FORMAT, caps));
    gst_object_unref (enc);
    return FALSE;
  }

  pos = gst_audio_get_channel_positions (structure);
  /* If one channel is NONE they'll be all undefined */
  if (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
    g_free (pos);
    pos = NULL;
  }

  if (pos == NULL) {
    GST_ELEMENT_ERROR (enc, STREAM, FORMAT, (NULL),
        ("input has no valid channel layout"));

    gst_object_unref (enc);
    return FALSE;
  }

  enc->channel_mask =
      gst_wavpack_get_channel_mask_from_positions (pos, enc->channels);
  enc->need_channel_remap =
      gst_wavpack_set_channel_mapping (pos, enc->channels,
      enc->channel_mapping);
  g_free (pos);

  /* set fixed src pad caps now that we know what we will get */
  caps = gst_caps_new_simple ("audio/x-wavpack",
      "channels", G_TYPE_INT, enc->channels,
      "rate", G_TYPE_INT, enc->samplerate,
      "width", G_TYPE_INT, enc->depth, "framed", G_TYPE_BOOLEAN, TRUE, NULL);

  if (!gst_wavpack_set_channel_layout (caps, enc->channel_mask))
    GST_WARNING_OBJECT (enc, "setting channel layout failed");

  if (!gst_pad_set_caps (enc->srcpad, caps)) {
    GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL),
        ("setting caps failed: %" GST_PTR_FORMAT, caps));
    gst_caps_unref (caps);
    gst_object_unref (enc);
    return FALSE;
  }
  gst_pad_use_fixed_caps (enc->srcpad);

  gst_caps_unref (caps);
  gst_object_unref (enc);
  return TRUE;
}
Esempio n. 2
0
static GstFlowReturn
gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf)
{
    GstWavpackDec *dec;
    GstBuffer *outbuf;
    GstFlowReturn ret = GST_FLOW_OK;
    WavpackHeader wph;
    int32_t decoded, unpacked_size;
    gboolean format_changed;

    dec = GST_WAVPACK_DEC (GST_PAD_PARENT (pad));

    /* check input, we only accept framed input with complete chunks */
    if (GST_BUFFER_SIZE (buf) < sizeof (WavpackHeader))
        goto input_not_framed;

    if (!gst_wavpack_read_header (&wph, GST_BUFFER_DATA (buf)))
        goto invalid_header;

    if (GST_BUFFER_SIZE (buf) < wph.ckSize + 4 * 1 + 4)
        goto input_not_framed;

    if (!(wph.flags & INITIAL_BLOCK))
        goto input_not_framed;

    dec->wv_id.buffer = GST_BUFFER_DATA (buf);
    dec->wv_id.length = GST_BUFFER_SIZE (buf);
    dec->wv_id.position = 0;

    /* create a new wavpack context if there is none yet but if there
     * was already one (i.e. caps were set on the srcpad) check whether
     * the new one has the same caps */
    if (!dec->context) {
        gchar error_msg[80];

        dec->context = WavpackOpenFileInputEx (dec->stream_reader,
                                               &dec->wv_id, NULL, error_msg, OPEN_STREAMING, 0);

        if (!dec->context) {
            GST_WARNING ("Couldn't decode buffer: %s", error_msg);
            dec->error_count++;
            if (dec->error_count <= WAVPACK_DEC_MAX_ERRORS) {
                goto out;               /* just return OK for now */
            } else {
                goto decode_error;
            }
        }
    }

    g_assert (dec->context != NULL);

    dec->error_count = 0;

    format_changed =
        (dec->sample_rate != WavpackGetSampleRate (dec->context)) ||
        (dec->channels != WavpackGetNumChannels (dec->context)) ||
        (dec->depth != WavpackGetBitsPerSample (dec->context)) ||
#ifdef WAVPACK_OLD_API
        (dec->channel_mask != dec->context->config.channel_mask);
#else
        (dec->channel_mask != WavpackGetChannelMask (dec->context));
#endif

    if (!GST_PAD_CAPS (dec->srcpad) || format_changed) {
        GstCaps *caps;
        gint channel_mask;

        dec->sample_rate = WavpackGetSampleRate (dec->context);
        dec->channels = WavpackGetNumChannels (dec->context);
        dec->depth = WavpackGetBitsPerSample (dec->context);

        caps = gst_caps_new_simple ("audio/x-raw-int",
                                    "rate", G_TYPE_INT, dec->sample_rate,
                                    "channels", G_TYPE_INT, dec->channels,
                                    "depth", G_TYPE_INT, dec->depth,
                                    "width", G_TYPE_INT, 32,
                                    "endianness", G_TYPE_INT, G_BYTE_ORDER,
                                    "signed", G_TYPE_BOOLEAN, TRUE, NULL);

#ifdef WAVPACK_OLD_API
        channel_mask = dec->context->config.channel_mask;
#else
        channel_mask = WavpackGetChannelMask (dec->context);
#endif
        if (channel_mask == 0)
            channel_mask = gst_wavpack_get_default_channel_mask (dec->channels);

        dec->channel_mask = channel_mask;

        /* Only set the channel layout for more than two channels
         * otherwise things break unfortunately */
        if (channel_mask != 0 && dec->channels > 2)
            if (!gst_wavpack_set_channel_layout (caps, channel_mask))
                GST_WARNING_OBJECT (dec, "Failed to set channel layout");

        GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps);

        /* should always succeed */
        gst_pad_set_caps (dec->srcpad, caps);
        gst_caps_unref (caps);

        /* send GST_TAG_AUDIO_CODEC and GST_TAG_BITRATE tags before something
         * is decoded or after the format has changed */
        gst_wavpack_dec_post_tags (dec);
    }

    /* alloc output buffer */
    unpacked_size = 4 * wph.block_samples * dec->channels;
    ret = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET (buf),
                                unpacked_size, GST_PAD_CAPS (dec->srcpad), &outbuf);

    if (ret != GST_FLOW_OK)
        goto out;

    gst_buffer_copy_metadata (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS);

    /* If we got a DISCONT buffer forward the flag. Nothing else
     * has to be done as libwavpack doesn't store state between
     * Wavpack blocks */
    if (GST_BUFFER_IS_DISCONT (buf) || dec->next_block_index != wph.block_index)
        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);

    dec->next_block_index = wph.block_index + wph.block_samples;

    /* decode */
    decoded = WavpackUnpackSamples (dec->context,
                                    (int32_t *) GST_BUFFER_DATA (outbuf), wph.block_samples);
    if (decoded != wph.block_samples)
        goto decode_error;

    if ((outbuf = gst_audio_buffer_clip (outbuf, &dec->segment,
                                         dec->sample_rate, 4 * dec->channels))) {
        GST_LOG_OBJECT (dec, "pushing buffer with time %" GST_TIME_FORMAT,
                        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
        ret = gst_pad_push (dec->srcpad, outbuf);
    }

out:

    if (G_UNLIKELY (ret != GST_FLOW_OK)) {
        GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (ret));
    }

    gst_buffer_unref (buf);

    return ret;

    /* ERRORS */
input_not_framed:
    {
        GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Expected framed input"));
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
invalid_header:
    {
        GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Invalid wavpack header"));
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
decode_error:
    {
        const gchar *reason = "unknown";

        if (dec->context) {
#ifdef WAVPACK_OLD_API
            reason = dec->context->error_message;
#else
            reason = WavpackGetErrorMessage (dec->context);
#endif
        } else {
            reason = "couldn't create decoder context";
        }
        GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL),
                           ("Failed to decode wavpack stream: %s", reason));
        gst_buffer_unref (outbuf);
        gst_buffer_unref (buf);
        return GST_FLOW_ERROR;
    }
}
Esempio n. 3
0
static gboolean
gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf,
    WavpackHeader * header)
{
  GstWavpackMetadata meta;

  GstCaps *caps = NULL;

  guchar *bufptr;

  g_assert (wvparse->srcpad == NULL);

  bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader);

  while (gst_wavpack_read_metadata (&meta, GST_BUFFER_DATA (buf), &bufptr)) {
    switch (meta.id) {
      case ID_WVC_BITSTREAM:{
        caps = gst_caps_new_simple ("audio/x-wavpack-correction",
            "framed", G_TYPE_BOOLEAN, TRUE, NULL);
        wvparse->srcpad =
            gst_pad_new_from_template (gst_element_class_get_pad_template
            (GST_ELEMENT_GET_CLASS (wvparse), "wvcsrc"), "wvcsrc");
        break;
      }
      case ID_WV_BITSTREAM:
      case ID_WVX_BITSTREAM:{
        WavpackStreamReader *stream_reader = gst_wavpack_stream_reader_new ();

        WavpackContext *wpc;

        gchar error_msg[80];

        read_id rid;

        gint channel_mask;

        rid.buffer = GST_BUFFER_DATA (buf);
        rid.length = GST_BUFFER_SIZE (buf);
        rid.position = 0;

        wpc =
            WavpackOpenFileInputEx (stream_reader, &rid, NULL, error_msg, 0, 0);

        if (!wpc)
          return FALSE;

        wvparse->samplerate = WavpackGetSampleRate (wpc);
        wvparse->channels = WavpackGetNumChannels (wpc);
        wvparse->total_samples =
            (header->total_samples ==
            0xffffffff) ? G_GINT64_CONSTANT (-1) : header->total_samples;

        caps = gst_caps_new_simple ("audio/x-wavpack",
            "width", G_TYPE_INT, WavpackGetBitsPerSample (wpc),
            "channels", G_TYPE_INT, wvparse->channels,
            "rate", G_TYPE_INT, wvparse->samplerate,
            "framed", G_TYPE_BOOLEAN, TRUE, NULL);
#ifdef WAVPACK_OLD_API
        channel_mask = wpc->config.channel_mask;
#else
        channel_mask = WavpackGetChannelMask (wpc);
#endif
        if (channel_mask == 0)
          channel_mask =
              gst_wavpack_get_default_channel_mask (wvparse->channels);

        if (channel_mask != 0) {
          if (!gst_wavpack_set_channel_layout (caps, channel_mask)) {
            GST_WARNING_OBJECT (wvparse, "Failed to set channel layout");
            gst_caps_unref (caps);
            caps = NULL;
            WavpackCloseFile (wpc);
            g_free (stream_reader);
            break;
          }
        }

        wvparse->srcpad =
            gst_pad_new_from_template (gst_element_class_get_pad_template
            (GST_ELEMENT_GET_CLASS (wvparse), "src"), "src");
        WavpackCloseFile (wpc);
        g_free (stream_reader);
        break;
      }
      default:{
        GST_LOG_OBJECT (wvparse, "unhandled ID: 0x%02x", meta.id);
        break;
      }
    }
    if (caps != NULL)
      break;
  }

  if (caps == NULL || wvparse->srcpad == NULL)
    return FALSE;

  GST_DEBUG_OBJECT (wvparse, "Added src pad with caps %" GST_PTR_FORMAT, caps);

  gst_pad_set_query_function (wvparse->srcpad,
      GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query));
  gst_pad_set_query_type_function (wvparse->srcpad,
      GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_src_query_types));
  gst_pad_set_event_function (wvparse->srcpad,
      GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event));

  gst_pad_set_caps (wvparse->srcpad, caps);
  gst_caps_unref (caps);
  gst_pad_use_fixed_caps (wvparse->srcpad);

  gst_object_ref (wvparse->srcpad);
  gst_pad_set_active (wvparse->srcpad, TRUE);
  gst_element_add_pad (GST_ELEMENT (wvparse), wvparse->srcpad);
  gst_element_no_more_pads (GST_ELEMENT (wvparse));

  return TRUE;
}