Пример #1
0
static void
gst_flac_dec_error_cb (const FLAC__StreamDecoder * d,
    FLAC__StreamDecoderErrorStatus status, void *client_data)
{
  const gchar *error;
  GstFlacDec *dec;

  dec = GST_FLAC_DEC (client_data);

  switch (status) {
    case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
      /* Ignore this error and keep processing */
      return;
    case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
      error = "bad header";
      break;
    case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
      error = "CRC mismatch";
      break;
    default:
      error = "unknown error";
      break;
  }

  if (gst_flac_dec_handle_decoder_error (dec, FALSE))
    GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status));
}
Пример #2
0
static FLAC__StreamDecoderWriteStatus
gst_flac_dec_write_stream (const FLAC__StreamDecoder * decoder,
    const FLAC__Frame * frame,
    const FLAC__int32 * const buffer[], void *client_data)
{
  return gst_flac_dec_write (GST_FLAC_DEC (client_data), frame, buffer);
}
Пример #3
0
static gboolean
gst_flac_dec_start (GstAudioDecoder * audio_dec)
{
  FLAC__StreamDecoderInitStatus s;
  GstFlacDec *dec;

  dec = GST_FLAC_DEC (audio_dec);

  dec->adapter = gst_adapter_new ();

  dec->decoder = FLAC__stream_decoder_new ();

  gst_audio_info_init (&dec->info);
  dec->depth = 0;

  /* no point calculating MD5 since it's never checked here */
  FLAC__stream_decoder_set_md5_checking (dec->decoder, false);

  GST_DEBUG_OBJECT (dec, "initializing decoder");
  s = FLAC__stream_decoder_init_stream (dec->decoder,
      gst_flac_dec_read_stream, NULL, NULL, NULL, NULL,
      gst_flac_dec_write_stream, gst_flac_dec_metadata_cb,
      gst_flac_dec_error_cb, dec);

  if (s != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), LIBRARY, INIT, (NULL), (NULL));
    return FALSE;
  }

  dec->got_headers = FALSE;

  return TRUE;
}
Пример #4
0
static void
gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * decoder,
    const FLAC__StreamMetadata * metadata, void *client_data)
{
  GstFlacDec *flacdec = GST_FLAC_DEC (client_data);

  GST_LOG_OBJECT (flacdec, "metadata type: %d", metadata->type);

  switch (metadata->type) {
    case FLAC__METADATA_TYPE_STREAMINFO:{
      gint64 samples;
      guint depth, width, gdepth;

      samples = metadata->data.stream_info.total_samples;

      flacdec->min_blocksize = metadata->data.stream_info.min_blocksize;
      flacdec->max_blocksize = metadata->data.stream_info.max_blocksize;
      flacdec->depth = depth = metadata->data.stream_info.bits_per_sample;

      if (depth < 9) {
        gdepth = width = 8;
      } else if (depth < 17) {
        gdepth = width = 16;
      } else if (depth < 25) {
        gdepth = 24;
        width = 32;
      } else {
        gdepth = width = 32;
      }

      gst_audio_info_set_format (&flacdec->info,
          gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, width, gdepth),
          metadata->data.stream_info.sample_rate,
          metadata->data.stream_info.channels, NULL);

      memcpy (flacdec->info.position,
          channel_positions[flacdec->info.channels - 1],
          sizeof (GstAudioChannelPosition) * flacdec->info.channels);
      gst_audio_channel_positions_to_valid_order (flacdec->info.position,
          flacdec->info.channels);
      /* Note: we create the inverse reordering map here */
      gst_audio_get_channel_reorder_map (flacdec->info.channels,
          flacdec->info.position, channel_positions[flacdec->info.channels - 1],
          flacdec->channel_reorder_map);

      GST_DEBUG_OBJECT (flacdec, "blocksize: min=%u, max=%u",
          flacdec->min_blocksize, flacdec->max_blocksize);
      GST_DEBUG_OBJECT (flacdec, "sample rate: %u, channels: %u",
          flacdec->info.rate, flacdec->info.channels);
      GST_DEBUG_OBJECT (flacdec, "depth: %u, width: %u", flacdec->depth,
          flacdec->info.finfo->width);

      GST_DEBUG_OBJECT (flacdec, "total samples = %" G_GINT64_FORMAT, samples);
      break;
    }
    default:
      break;
  }
}
Пример #5
0
static gboolean
gst_flac_dec_set_format (GstAudioDecoder * dec, GstCaps * caps)
{
  const GValue *headers;
  GstFlacDec *flacdec;
  GstStructure *s;
  guint i, num;

  flacdec = GST_FLAC_DEC (dec);

  GST_LOG_OBJECT (dec, "sink caps: %" GST_PTR_FORMAT, caps);

  s = gst_caps_get_structure (caps, 0);
  headers = gst_structure_get_value (s, "streamheader");
  if (headers == NULL || !GST_VALUE_HOLDS_ARRAY (headers)) {
    GST_WARNING_OBJECT (dec, "no 'streamheader' field in input caps, try "
        "adding a flacparse element upstream");
    return FALSE;
  }

  if (gst_adapter_available (flacdec->adapter) > 0) {
    GST_WARNING_OBJECT (dec, "unexpected data left in adapter");
    gst_adapter_clear (flacdec->adapter);
  }

  num = gst_value_array_get_size (headers);
  for (i = 0; i < num; ++i) {
    const GValue *header_val;
    GstBuffer *header_buf;

    header_val = gst_value_array_get_value (headers, i);
    if (header_val == NULL || !GST_VALUE_HOLDS_BUFFER (header_val))
      return FALSE;

    header_buf = g_value_dup_boxed (header_val);
    GST_INFO_OBJECT (dec, "pushing header buffer of %" G_GSIZE_FORMAT " bytes "
        "into adapter", gst_buffer_get_size (header_buf));
    gst_adapter_push (flacdec->adapter, header_buf);
  }

  GST_DEBUG_OBJECT (dec, "Processing headers and metadata");
  if (!FLAC__stream_decoder_process_until_end_of_metadata (flacdec->decoder)) {
    GST_WARNING_OBJECT (dec, "process_until_end_of_metadata failed");
    if (FLAC__stream_decoder_get_state (flacdec->decoder) ==
        FLAC__STREAM_DECODER_ABORTED) {
      GST_WARNING_OBJECT (flacdec, "Read callback caused internal abort");
      /* allow recovery */
      gst_adapter_clear (flacdec->adapter);
      FLAC__stream_decoder_flush (flacdec->decoder);
      gst_flac_dec_handle_decoder_error (flacdec, TRUE);
    }
  }
  GST_INFO_OBJECT (dec, "headers and metadata are now processed");
  return TRUE;
}
Пример #6
0
static GstFlowReturn
gst_flac_dec_handle_frame (GstAudioDecoder * audio_dec, GstBuffer * buf)
{
  GstFlacDec *dec;

  dec = GST_FLAC_DEC (audio_dec);

  /* drain remaining data? */
  if (G_UNLIKELY (buf == NULL)) {
    gst_flac_dec_flush (audio_dec, FALSE);
    return GST_FLOW_OK;
  }

  GST_LOG_OBJECT (dec, "frame: ts %" GST_TIME_FORMAT ", flags 0x%04x, "
      "%" G_GSIZE_FORMAT " bytes", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
      GST_BUFFER_FLAGS (buf), gst_buffer_get_size (buf));

  /* drop any in-stream headers, we've processed those in set_format already */
  if (G_UNLIKELY (!dec->got_headers)) {
    gboolean got_audio_frame;
    GstMapInfo map;

    /* check if this is a flac audio frame (rather than a header or junk) */
    gst_buffer_map (buf, &map, GST_MAP_READ);
    got_audio_frame =
        gst_flac_dec_scan_got_frame (dec, map.data, map.size, NULL);
    gst_buffer_unmap (buf, &map);

    if (!got_audio_frame) {
      GST_INFO_OBJECT (dec, "dropping in-stream header, %" G_GSIZE_FORMAT " "
          "bytes", map.size);
      gst_audio_decoder_finish_frame (audio_dec, NULL, 1);
      return GST_FLOW_OK;
    }

    GST_INFO_OBJECT (dec, "first audio frame, got all in-stream headers now");
    dec->got_headers = TRUE;
  }

  gst_adapter_push (dec->adapter, gst_buffer_ref (buf));
  buf = NULL;

  dec->last_flow = GST_FLOW_OK;

  /* framed - there should always be enough data to decode something */
  GST_LOG_OBJECT (dec, "%" G_GSIZE_FORMAT " bytes available",
      gst_adapter_available (dec->adapter));

  if (!FLAC__stream_decoder_process_single (dec->decoder)) {
    GST_INFO_OBJECT (dec, "process_single failed");
  }

  return dec->last_flow;
}
Пример #7
0
static void
gst_flac_dec_flush (GstAudioDecoder * audio_dec, gboolean hard)
{
  GstFlacDec *dec = GST_FLAC_DEC (audio_dec);

  if (!hard) {
    guint available = gst_adapter_available (dec->adapter);

    if (available > 0) {
      GST_INFO_OBJECT (dec, "draining, %u bytes left in adapter", available);
      FLAC__stream_decoder_process_until_end_of_stream (dec->decoder);
    }
  }

  FLAC__stream_decoder_flush (dec->decoder);
  gst_adapter_clear (dec->adapter);
}
Пример #8
0
static gboolean
gst_flac_dec_stop (GstAudioDecoder * dec)
{
  GstFlacDec *flacdec = GST_FLAC_DEC (dec);

  if (flacdec->decoder) {
    FLAC__stream_decoder_delete (flacdec->decoder);
    flacdec->decoder = NULL;
  }

  if (flacdec->adapter) {
    gst_adapter_clear (flacdec->adapter);
    g_object_unref (flacdec->adapter);
    flacdec->adapter = NULL;
  }

  return TRUE;
}
Пример #9
0
static FLAC__StreamDecoderReadStatus
gst_flac_dec_read_stream (const FLAC__StreamDecoder * decoder,
    FLAC__byte buffer[], size_t * bytes, void *client_data)
{
  GstFlacDec *dec = GST_FLAC_DEC (client_data);
  guint len;

  len = MIN (gst_adapter_available (dec->adapter), *bytes);

  if (len == 0) {
    GST_LOG_OBJECT (dec, "0 bytes available at the moment");
    return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
  }

  GST_LOG_OBJECT (dec, "feeding %u bytes to decoder "
      "(available=%" G_GSIZE_FORMAT ", bytes=%u)",
      len, gst_adapter_available (dec->adapter), (guint) * bytes);
  gst_adapter_copy (dec->adapter, buffer, 0, len);
  *bytes = len;

  gst_adapter_flush (dec->adapter, len);

  return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}