Exemple #1
0
static void gst_sbc_enc_get_property(GObject *object, guint prop_id,
					GValue *value, GParamSpec *pspec)
{
	GstSbcEnc *enc = GST_SBC_ENC(object);

	switch (prop_id) {
	case PROP_MODE:
		g_value_set_enum(value, enc->mode);
		break;
	case PROP_ALLOCATION:
		g_value_set_enum(value, enc->allocation);
		break;
	case PROP_BLOCKS:
		g_value_set_enum(value, enc->blocks);
		break;
	case PROP_SUBBANDS:
		g_value_set_enum(value, enc->subbands);
		break;
	case PROP_BITPOOL:
		g_value_set_int(value, enc->bitpool);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
		break;
	}
}
Exemple #2
0
static gboolean sbc_enc_sink_setcaps(GstPad *pad, GstCaps *caps)
{
	GstSbcEnc *enc;
	GstStructure *structure;
	GstCaps *src_caps;
	gint rate, channels;
	gboolean res;

	enc = GST_SBC_ENC(GST_PAD_PARENT(pad));
	structure = gst_caps_get_structure(caps, 0);

	if (!gst_structure_get_int(structure, "rate", &rate))
		return FALSE;
	if (!gst_structure_get_int(structure, "channels", &channels))
		return FALSE;

	enc->rate = rate;
	enc->channels = channels;

	src_caps = sbc_enc_get_fixed_srcpad_caps(enc);
	if (!src_caps)
		return FALSE;
	res = gst_pad_set_caps(enc->srcpad, src_caps);
	gst_caps_unref(src_caps);

	return res;
}
Exemple #3
0
static void gst_sbc_enc_set_property(GObject *object, guint prop_id,
					const GValue *value, GParamSpec *pspec)
{
	GstSbcEnc *enc = GST_SBC_ENC(object);

	/* changes to those properties will only happen on the next caps
	 * negotiation */

	switch (prop_id) {
	case PROP_MODE:
		enc->mode = g_value_get_enum(value);
		break;
	case PROP_ALLOCATION:
		enc->allocation = g_value_get_enum(value);
		break;
	case PROP_BLOCKS:
		enc->blocks = g_value_get_enum(value);
		break;
	case PROP_SUBBANDS:
		enc->subbands = g_value_get_enum(value);
		break;
	case PROP_BITPOOL:
		enc->bitpool = g_value_get_int(value);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
		break;
	}
}
Exemple #4
0
static gboolean sbc_enc_src_setcaps(GstPad *pad, GstCaps *caps)
{
	GstSbcEnc *enc = GST_SBC_ENC(GST_PAD_PARENT(pad));

	GST_LOG_OBJECT(enc, "setting srcpad caps");

	return gst_sbc_enc_fill_sbc_params(enc, caps);
}
Exemple #5
0
static GstCaps *sbc_enc_src_getcaps(GstPad *pad)
{
	GstSbcEnc *enc;

	enc = GST_SBC_ENC(GST_PAD_PARENT(pad));

	return sbc_enc_generate_srcpad_caps(enc);
}
Exemple #6
0
static void gst_sbc_enc_dispose(GObject *object)
{
	GstSbcEnc *enc = GST_SBC_ENC(object);

	if (enc->adapter != NULL)
		g_object_unref(G_OBJECT(enc->adapter));

	enc->adapter = NULL;
}
static gboolean
gst_sbc_enc_start (GstAudioEncoder * audio_enc)
{
  GstSbcEnc *enc = GST_SBC_ENC (audio_enc);

  GST_INFO_OBJECT (enc, "Setup subband codec");
  sbc_init (&enc->sbc, 0);

  return TRUE;
}
Exemple #8
0
static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer)
{
	GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad));
	GstAdapter *adapter = enc->adapter;
	GstFlowReturn res = GST_FLOW_OK;

	gst_adapter_push(adapter, buffer);

	while (gst_adapter_available(adapter) >= enc->codesize &&
							res == GST_FLOW_OK) {
		GstBuffer *output;
		GstCaps *caps;
		const guint8 *data;
		gint consumed;

		caps = GST_PAD_CAPS(enc->srcpad);
		res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad,
						GST_BUFFER_OFFSET_NONE,
						enc->frame_length, caps,
						&output);
		if (res != GST_FLOW_OK)
			goto done;

		data = gst_adapter_peek(adapter, enc->codesize);

		consumed = sbc_encode(&enc->sbc, (gpointer) data,
					enc->codesize,
					GST_BUFFER_DATA(output),
					GST_BUFFER_SIZE(output), NULL);
		if (consumed <= 0) {
			GST_DEBUG_OBJECT(enc, "comsumed < 0, codesize: %d",
					enc->codesize);
			break;
		}
		gst_adapter_flush(adapter, consumed);

		GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer);
		/* we have only 1 frame */
		GST_BUFFER_DURATION(output) = enc->frame_duration;

		res = gst_pad_push(enc->srcpad, output);

		if (res != GST_FLOW_OK)
			goto done;
	}

done:
	gst_object_unref(enc);

	return res;
}
static gboolean
gst_sbc_enc_stop (GstAudioEncoder * audio_enc)
{
  GstSbcEnc *enc = GST_SBC_ENC (audio_enc);

  GST_INFO_OBJECT (enc, "Finish subband codec");
  sbc_finish (&enc->sbc);

  enc->subbands = 0;
  enc->blocks = 0;
  enc->rate = 0;
  enc->channels = 0;
  enc->bitpool = 0;

  return TRUE;
}
Exemple #10
0
static GstStateChangeReturn sbc_enc_change_state(GstElement *element,
						GstStateChange transition)
{
	GstSbcEnc *enc = GST_SBC_ENC(element);

	switch (transition) {
	case GST_STATE_CHANGE_READY_TO_PAUSED:
		GST_DEBUG("Setup subband codec");
		sbc_init(&enc->sbc, 0);
		break;

	case GST_STATE_CHANGE_PAUSED_TO_READY:
		GST_DEBUG("Finish subband codec");
		sbc_finish(&enc->sbc);
		break;

	default:
		break;
	}

	return parent_class->change_state(element, transition);
}
Exemple #11
0
static gboolean
gst_sbc_enc_set_format (GstAudioEncoder * audio_enc, GstAudioInfo * info)
{
  const gchar *allocation_method, *channel_mode;
  GstSbcEnc *enc = GST_SBC_ENC (audio_enc);
  GstStructure *s;
  GstCaps *caps, *filter_caps;
  GstCaps *output_caps = NULL;
  guint sampleframes_per_frame;

  enc->rate = GST_AUDIO_INFO_RATE (info);
  enc->channels = GST_AUDIO_INFO_CHANNELS (info);

  /* negotiate output format based on downstream caps restrictions */
  caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (enc));
  if (caps == GST_CAPS_NONE || gst_caps_is_empty (caps))
    goto failure;

  if (caps == NULL)
    caps = gst_static_pad_template_get_caps (&sbc_enc_src_factory);

  /* fixate output caps */
  filter_caps = gst_caps_new_simple ("audio/x-sbc", "rate", G_TYPE_INT,
      enc->rate, "channels", G_TYPE_INT, enc->channels, NULL);
  output_caps = gst_caps_intersect (caps, filter_caps);
  gst_caps_unref (filter_caps);

  if (output_caps == NULL || gst_caps_is_empty (output_caps)) {
    GST_WARNING_OBJECT (enc, "Couldn't negotiate output caps with input rate "
        "%d and input channels %d and allowed output caps %" GST_PTR_FORMAT,
        enc->rate, enc->channels, caps);
    goto failure;
  }

  gst_caps_unref (caps);
  caps = NULL;

  GST_DEBUG_OBJECT (enc, "fixating caps %" GST_PTR_FORMAT, output_caps);
  output_caps = gst_caps_truncate (output_caps);
  s = gst_caps_get_structure (output_caps, 0);
  if (enc->channels == 1)
    gst_structure_fixate_field_string (s, "channel-mode", "mono");
  else
    gst_structure_fixate_field_string (s, "channel-mode", "joint");

  gst_structure_fixate_field_nearest_int (s, "bitpool", 64);
  gst_structure_fixate_field_nearest_int (s, "blocks", 16);
  gst_structure_fixate_field_nearest_int (s, "subbands", 8);
  gst_structure_fixate_field_string (s, "allocation-method", "loudness");
  s = NULL;

  /* in case there's anything else left to fixate */
  output_caps = gst_caps_fixate (output_caps);
  gst_caps_set_simple (output_caps, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);

  GST_INFO_OBJECT (enc, "output caps %" GST_PTR_FORMAT, output_caps);

  /* let's see what we fixated to */
  s = gst_caps_get_structure (output_caps, 0);
  gst_structure_get_int (s, "blocks", &enc->blocks);
  gst_structure_get_int (s, "subbands", &enc->subbands);
  gst_structure_get_int (s, "bitpool", &enc->bitpool);
  allocation_method = gst_structure_get_string (s, "allocation-method");
  channel_mode = gst_structure_get_string (s, "channel-mode");

  /* We want channel-mode and channels coherent */
  if (enc->channels == 1) {
    if (g_strcmp0 (channel_mode, "mono") != 0) {
      GST_ERROR_OBJECT (enc, "Can't have channel-mode '%s' for 1 channel",
          channel_mode);
      goto failure;
    }
  } else {
    if (g_strcmp0 (channel_mode, "joint") != 0 &&
        g_strcmp0 (channel_mode, "stereo") != 0 &&
        g_strcmp0 (channel_mode, "dual") != 0) {
      GST_ERROR_OBJECT (enc, "Can't have channel-mode '%s' for 2 channels",
          channel_mode);
      goto failure;
    }
  }

  /* we want to be handed all available samples in handle_frame, but always
   * enough to encode a frame */
  sampleframes_per_frame = enc->blocks * enc->subbands;
  gst_audio_encoder_set_frame_samples_min (audio_enc, sampleframes_per_frame);
  gst_audio_encoder_set_frame_samples_max (audio_enc, sampleframes_per_frame);
  gst_audio_encoder_set_frame_max (audio_enc, 0);

  /* FIXME: what to do with left-over samples at the end? can we encode them? */
  gst_audio_encoder_set_hard_min (audio_enc, TRUE);

  /* and configure encoder based on the output caps we negotiated */
  if (enc->rate == 16000)
    enc->sbc.frequency = SBC_FREQ_16000;
  else if (enc->rate == 32000)
    enc->sbc.frequency = SBC_FREQ_32000;
  else if (enc->rate == 44100)
    enc->sbc.frequency = SBC_FREQ_44100;
  else if (enc->rate == 48000)
    enc->sbc.frequency = SBC_FREQ_48000;
  else
    goto failure;

  if (enc->blocks == 4)
    enc->sbc.blocks = SBC_BLK_4;
  else if (enc->blocks == 8)
    enc->sbc.blocks = SBC_BLK_8;
  else if (enc->blocks == 12)
    enc->sbc.blocks = SBC_BLK_12;
  else if (enc->blocks == 16)
    enc->sbc.blocks = SBC_BLK_16;
  else
    goto failure;

  enc->sbc.subbands = (enc->subbands == 4) ? SBC_SB_4 : SBC_SB_8;
  enc->sbc.bitpool = enc->bitpool;

  if (channel_mode == NULL || allocation_method == NULL)
    goto failure;

  if (strcmp (channel_mode, "joint") == 0)
    enc->sbc.mode = SBC_MODE_JOINT_STEREO;
  else if (strcmp (channel_mode, "stereo") == 0)
    enc->sbc.mode = SBC_MODE_STEREO;
  else if (strcmp (channel_mode, "dual") == 0)
    enc->sbc.mode = SBC_MODE_DUAL_CHANNEL;
  else if (strcmp (channel_mode, "mono") == 0)
    enc->sbc.mode = SBC_MODE_MONO;
  else if (strcmp (channel_mode, "auto") == 0)
    enc->sbc.mode = SBC_MODE_JOINT_STEREO;
  else
    goto failure;

  if (strcmp (allocation_method, "loudness") == 0)
    enc->sbc.allocation = SBC_AM_LOUDNESS;
  else if (strcmp (allocation_method, "snr") == 0)
    enc->sbc.allocation = SBC_AM_SNR;
  else
    goto failure;

  if (!gst_audio_encoder_set_output_format (audio_enc, output_caps))
    goto failure;

  return gst_audio_encoder_negotiate (audio_enc);

failure:
  if (output_caps)
    gst_caps_unref (output_caps);
  if (caps)
    gst_caps_unref (caps);
  return FALSE;
}
Exemple #12
0
static GstFlowReturn
gst_sbc_enc_handle_frame (GstAudioEncoder * audio_enc, GstBuffer * buffer)
{
  GstSbcEnc *enc = GST_SBC_ENC (audio_enc);
  GstMapInfo in_map, out_map;
  GstBuffer *outbuf = NULL;
  guint samples_per_frame, frames, i = 0;

  /* no fancy draining */
  if (buffer == NULL)
    return GST_FLOW_OK;

  if (G_UNLIKELY (enc->channels == 0 || enc->blocks == 0 || enc->subbands == 0))
    return GST_FLOW_NOT_NEGOTIATED;

  samples_per_frame = enc->channels * enc->blocks * enc->subbands;

  if (!gst_buffer_map (buffer, &in_map, GST_MAP_READ))
    goto map_failed;

  frames = in_map.size / (samples_per_frame * sizeof (gint16));

  GST_LOG_OBJECT (enc,
      "encoding %" G_GSIZE_FORMAT " samples into %u SBC frames",
      in_map.size / (enc->channels * sizeof (gint16)), frames);

  if (frames > 0) {
    gsize frame_len;

    frame_len = sbc_get_frame_length (&enc->sbc);
    outbuf = gst_audio_encoder_allocate_output_buffer (audio_enc,
        frames * frame_len);

    if (outbuf == NULL)
      goto no_buffer;

    gst_buffer_map (outbuf, &out_map, GST_MAP_WRITE);

    for (i = 0; i < frames; ++i) {
      gssize ret, written = 0;

      ret = sbc_encode (&enc->sbc, in_map.data + (i * samples_per_frame * 2),
          samples_per_frame * 2, out_map.data + (i * frame_len), frame_len,
          &written);

      if (ret < 0 || written != frame_len) {
        GST_WARNING_OBJECT (enc, "encoding error, ret = %" G_GSSIZE_FORMAT ", "
            "written = %" G_GSSIZE_FORMAT, ret, written);
        break;
      }
    }

    gst_buffer_unmap (outbuf, &out_map);

    if (i > 0)
      gst_buffer_set_size (outbuf, i * frame_len);
    else
      gst_buffer_replace (&outbuf, NULL);
  }

done:

  gst_buffer_unmap (buffer, &in_map);

  return gst_audio_encoder_finish_frame (audio_enc, outbuf,
      i * (samples_per_frame / enc->channels));

/* ERRORS */
no_buffer:
  {
    GST_ERROR_OBJECT (enc, "could not allocate output buffer");
    goto done;
  }
map_failed:
  {
    GST_ERROR_OBJECT (enc, "could not map input buffer");
    goto done;
  }
}