static GstFlowReturn
gst_dtsdec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buffer)
{
  GstDtsDec *dts;
  gint channels, i, num_blocks;
  gboolean need_renegotiation = FALSE;
  guint8 *data;
  gsize size;
  GstMapInfo map;
  gint chans;
  gint length = 0, flags, sample_rate, bit_rate, frame_length;
  GstFlowReturn result = GST_FLOW_OK;
  GstBuffer *outbuf;

  dts = GST_DTSDEC (bdec);

  /* no fancy draining */
  if (G_UNLIKELY (!buffer))
    return GST_FLOW_OK;

  /* parsed stuff already, so this should work out fine */
  gst_buffer_map (buffer, &map, GST_MAP_READ);
  data = map.data;
  size = map.size;
  g_assert (size >= 7);

  bit_rate = dts->bit_rate;
  sample_rate = dts->sample_rate;
  flags = 0;
  length = dca_syncinfo (dts->state, data, &flags, &sample_rate, &bit_rate,
      &frame_length);
  g_assert (length == size);

  if (flags != dts->prev_flags) {
    dts->prev_flags = flags;
    dts->flag_update = TRUE;
  }

  /* go over stream properties, renegotiate or update streaminfo if needed */
  if (dts->sample_rate != sample_rate) {
    need_renegotiation = TRUE;
    dts->sample_rate = sample_rate;
  }

  if (flags) {
    dts->stream_channels = flags & (DCA_CHANNEL_MASK | DCA_LFE);
  }

  if (bit_rate != dts->bit_rate) {
    dts->bit_rate = bit_rate;
    gst_dtsdec_update_streaminfo (dts);
  }

  /* If we haven't had an explicit number of channels chosen through properties
   * at this point, choose what to downmix to now, based on what the peer will 
   * accept - this allows a52dec to do downmixing in preference to a 
   * downstream element such as audioconvert.
   * FIXME: Add the property back in for forcing output channels.
   */
  if (dts->request_channels != DCA_CHANNEL) {
    flags = dts->request_channels;
  } else if (dts->flag_update) {
    GstCaps *caps;

    dts->flag_update = FALSE;

    caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dts));
    if (caps && gst_caps_get_size (caps) > 0) {
      GstCaps *copy = gst_caps_copy_nth (caps, 0);
      GstStructure *structure = gst_caps_get_structure (copy, 0);
      gint channels;
      const int dts_channels[6] = {
        DCA_MONO,
        DCA_STEREO,
        DCA_STEREO | DCA_LFE,
        DCA_2F2R,
        DCA_2F2R | DCA_LFE,
        DCA_3F2R | DCA_LFE,
      };

      /* Prefer the original number of channels, but fixate to something 
       * preferred (first in the caps) downstream if possible.
       */
      gst_structure_fixate_field_nearest_int (structure, "channels",
          flags ? gst_dtsdec_channels (flags, NULL) : 6);
      gst_structure_get_int (structure, "channels", &channels);
      if (channels <= 6)
        flags = dts_channels[channels - 1];
      else
        flags = dts_channels[5];

      gst_caps_unref (copy);
    } else if (flags) {
      flags = dts->stream_channels;
    } else {
      flags = DCA_3F2R | DCA_LFE;
    }

    if (caps)
      gst_caps_unref (caps);
  } else {
    flags = dts->using_channels;
  }

  /* process */
  flags |= DCA_ADJUST_LEVEL;
  dts->level = 1;
  if (dca_frame (dts->state, data, &flags, &dts->level, dts->bias)) {
    gst_buffer_unmap (buffer, &map);
    GST_AUDIO_DECODER_ERROR (dts, 1, STREAM, DECODE, (NULL),
        ("dts_frame error"), result);
    goto exit;
  }
  gst_buffer_unmap (buffer, &map);

  channels = flags & (DCA_CHANNEL_MASK | DCA_LFE);
  if (dts->using_channels != channels) {
    need_renegotiation = TRUE;
    dts->using_channels = channels;
  }

  /* negotiate if required */
  if (need_renegotiation) {
    GST_DEBUG_OBJECT (dts,
        "dtsdec: sample_rate:%d stream_chans:0x%x using_chans:0x%x",
        dts->sample_rate, dts->stream_channels, dts->using_channels);
    if (!gst_dtsdec_renegotiate (dts))
      goto failed_negotiation;
  }

  if (dts->dynamic_range_compression == FALSE) {
    dca_dynrng (dts->state, NULL, NULL);
  }

  flags &= (DCA_CHANNEL_MASK | DCA_LFE);
  chans = gst_dtsdec_channels (flags, NULL);
  if (!chans)
    goto invalid_flags;

  /* handle decoded data, one block is 256 samples */
  num_blocks = dca_blocks_num (dts->state);
  outbuf =
      gst_buffer_new_and_alloc (256 * chans * (SAMPLE_WIDTH / 8) * num_blocks);

  gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
  data = map.data;
  size = map.size;
  {
    guint8 *ptr = data;
    for (i = 0; i < num_blocks; i++) {
      if (dca_block (dts->state)) {
        /* also marks discont */
        GST_AUDIO_DECODER_ERROR (dts, 1, STREAM, DECODE, (NULL),
            ("error decoding block %d", i), result);
        if (result != GST_FLOW_OK)
          goto exit;
      } else {
        gint n, c;
        gint *reorder_map = dts->channel_reorder_map;

        for (n = 0; n < 256; n++) {
          for (c = 0; c < chans; c++) {
            ((sample_t *) ptr)[n * chans + reorder_map[c]] =
                dts->samples[c * 256 + n];
          }
        }
      }
      ptr += 256 * chans * (SAMPLE_WIDTH / 8);
    }
  }
  gst_buffer_unmap (outbuf, &map);

  result = gst_audio_decoder_finish_frame (bdec, outbuf, 1);

exit:
  return result;

  /* ERRORS */
failed_negotiation:
  {
    GST_ELEMENT_ERROR (dts, CORE, NEGOTIATION, (NULL), (NULL));
    return GST_FLOW_ERROR;
  }
invalid_flags:
  {
    GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL),
        ("Invalid channel flags: %d", flags));
    return GST_FLOW_ERROR;
  }
}
Beispiel #2
0
static GstFlowReturn
gst_dtsdec_handle_frame (GstDtsDec * dts, guint8 * data,
    guint length, gint flags, gint sample_rate, gint bit_rate)
{
  gboolean need_renegotiation = FALSE;
  gint channels, num_blocks;
  GstBuffer *out;
  gint i, s, c, num_c;
  sample_t *samples;
  GstFlowReturn result = GST_FLOW_OK;

  /* go over stream properties, update caps/streaminfo if needed */
  if (dts->sample_rate != sample_rate) {
    need_renegotiation = TRUE;
    dts->sample_rate = sample_rate;
  }

  dts->stream_channels = flags;

  if (bit_rate != dts->bit_rate) {
    dts->bit_rate = bit_rate;
    gst_dtsdec_update_streaminfo (dts);
  }

  if (dts->request_channels == DTS_CHANNEL) {
    GstCaps *caps;

    caps = gst_pad_get_allowed_caps (dts->srcpad);
    if (caps && gst_caps_get_size (caps) > 0) {
      GstCaps *copy = gst_caps_copy_nth (caps, 0);
      GstStructure *structure = gst_caps_get_structure (copy, 0);
      gint channels;
      const int dts_channels[6] = {
        DTS_MONO,
        DTS_STEREO,
        DTS_STEREO | DTS_LFE,
        DTS_2F2R,
        DTS_2F2R | DTS_LFE,
        DTS_3F2R | DTS_LFE,
      };

      /* Prefer the original number of channels, but fixate to something 
       * preferred (first in the caps) downstream if possible.
       */
      gst_structure_fixate_field_nearest_int (structure, "channels",
          flags ? gst_dtsdec_channels (flags, NULL) : 6);
      gst_structure_get_int (structure, "channels", &channels);
      if (channels <= 6)
        dts->request_channels = dts_channels[channels - 1];
      else
        dts->request_channels = dts_channels[5];

      gst_caps_unref (copy);
    } else if (flags) {
      dts->request_channels = dts->stream_channels;
    } else {
      dts->request_channels = DTS_3F2R | DTS_LFE;
    }

    if (caps)
      gst_caps_unref (caps);
  }

  /* process */
  flags = dts->request_channels | DTS_ADJUST_LEVEL;
  dts->level = 1;

  if (dts_frame (dts->state, data, &flags, &dts->level, dts->bias)) {
    GST_WARNING ("dts_frame error");
    return GST_FLOW_OK;
  }

  channels = flags & (DTS_CHANNEL_MASK | DTS_LFE);

  if (dts->using_channels != channels) {
    need_renegotiation = TRUE;
    dts->using_channels = channels;
  }

  if (need_renegotiation == TRUE) {
    GST_DEBUG ("dtsdec: sample_rate:%d stream_chans:0x%x using_chans:0x%x",
        dts->sample_rate, dts->stream_channels, dts->using_channels);
    if (!gst_dtsdec_renegotiate (dts)) {
      GST_ELEMENT_ERROR (dts, CORE, NEGOTIATION, (NULL), (NULL));
      return GST_FLOW_ERROR;
    }
  }

  if (dts->dynamic_range_compression == FALSE) {
    dts_dynrng (dts->state, NULL, NULL);
  }

  /* handle decoded data, one block is 256 samples */
  num_blocks = dts_blocks_num (dts->state);
  for (i = 0; i < num_blocks; i++) {
    if (dts_block (dts->state)) {
      GST_WARNING ("dts_block error %d", i);
      continue;
    }

    samples = dts_samples (dts->state);
    num_c = gst_dtsdec_channels (dts->using_channels, NULL);

    result = gst_pad_alloc_buffer_and_set_caps (dts->srcpad, 0,
        (SAMPLE_WIDTH / 8) * 256 * num_c, GST_PAD_CAPS (dts->srcpad), &out);

    if (result != GST_FLOW_OK)
      break;

    GST_BUFFER_TIMESTAMP (out) = dts->current_ts;
    GST_BUFFER_DURATION (out) = GST_SECOND * 256 / dts->sample_rate;
    dts->current_ts += GST_BUFFER_DURATION (out);

    /* libdts returns buffers in 256-sample-blocks per channel,
     * we want interleaved. And we need to copy anyway... */
    data = GST_BUFFER_DATA (out);
    for (s = 0; s < 256; s++) {
      for (c = 0; c < num_c; c++) {
        *(sample_t *) data = samples[s + c * 256];
        data += (SAMPLE_WIDTH / 8);
      }
    }

    /* push on */
    result = gst_pad_push (dts->srcpad, out);

    if (result != GST_FLOW_OK)
      break;
  }

  return result;
}