self->srcpad = gst_pad_new_from_static_template (&sbc_dec_src_factory, "src");
gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
}
+
+gboolean
+gst_sbc_dec_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "sbcdec",
+ GST_RANK_PRIMARY, GST_TYPE_SBC_DEC);
+}
GType gst_sbc_dec_get_type(void);
+gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin);
+
G_END_DECLS
gboolean gst_sbc_enc_fill_sbc_params (GstSbcEnc * enc, GstCaps * caps);
-static void
-sbc_enc_set_structure_int_param (GstSbcEnc * enc,
- GstStructure * structure, const gchar * field, gint field_value)
-{
- GValue *value;
-
- value = g_new0 (GValue, 1);
- value = g_value_init (value, G_TYPE_INT);
- g_value_set_int (value, field_value);
- gst_structure_set_value (structure, field, value);
- g_free (value);
-}
-
-static void
-sbc_enc_set_structure_string_param (GstSbcEnc * enc,
- GstStructure * structure, const gchar * field, const gchar * field_value)
-{
- GValue *value;
-
- value = g_new0 (GValue, 1);
- value = g_value_init (value, G_TYPE_STRING);
- g_value_set_string (value, field_value);
- gst_structure_set_value (structure, field, value);
- g_free (value);
-}
-
static GstCaps *
sbc_enc_generate_srcpad_caps (GstSbcEnc * enc)
{
GEnumValue *enum_value;
GEnumClass *enum_class;
gchar *temp;
+ GValue *value;
src_caps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad));
structure = gst_caps_get_structure (src_caps, 0);
+ value = g_new0 (GValue, 1);
+
if (enc->rate != 0)
- sbc_enc_set_structure_int_param (enc, structure, "rate", enc->rate);
+ gst_sbc_util_set_structure_int_param (structure, "rate", enc->rate, value);
if (enc->channels != 0)
- sbc_enc_set_structure_int_param (enc, structure, "channels", enc->channels);
+ gst_sbc_util_set_structure_int_param (structure, "channels",
+ enc->channels, value);
if (enc->subbands != 0)
- sbc_enc_set_structure_int_param (enc, structure, "subbands", enc->subbands);
+ gst_sbc_util_set_structure_int_param (structure, "subbands",
+ enc->subbands, value);
if (enc->blocks != 0)
- sbc_enc_set_structure_int_param (enc, structure, "blocks", enc->blocks);
+ gst_sbc_util_set_structure_int_param (structure, "blocks",
+ enc->blocks, value);
if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) {
enum_class = g_type_class_ref (GST_TYPE_SBC_MODE);
enum_value = g_enum_get_value (enum_class, enc->mode);
- sbc_enc_set_structure_string_param (enc, structure, "mode",
- enum_value->value_nick);
+ gst_sbc_util_set_structure_string_param (structure, "mode",
+ enum_value->value_nick, value);
g_type_class_unref (enum_class);
}
if (enc->allocation != BT_A2DP_ALLOCATION_AUTO) {
enum_class = g_type_class_ref (GST_TYPE_SBC_ALLOCATION);
enum_value = g_enum_get_value (enum_class, enc->allocation);
- sbc_enc_set_structure_string_param (enc, structure, "allocation",
- enum_value->value_nick);
+ gst_sbc_util_set_structure_string_param (structure, "allocation",
+ enum_value->value_nick, value);
g_type_class_unref (enum_class);
}
temp = gst_caps_to_string (src_caps);
GST_DEBUG_OBJECT (enc, "Srcpad caps: %s", temp);
g_free (temp);
+ g_free (value);
return src_caps;
}
static gboolean
sbc_enc_src_setcaps (GstPad * pad, GstCaps * caps)
{
- GstCaps *srcpad_caps;
- GstCaps *temp_caps;
- gboolean res = TRUE;
GstSbcEnc *enc = GST_SBC_ENC (GST_PAD_PARENT (pad));
GST_LOG_OBJECT (enc, "setting srcpad caps");
- srcpad_caps = sbc_enc_generate_srcpad_caps (enc);
- temp_caps = gst_caps_intersect (srcpad_caps, caps);
- if (temp_caps == GST_CAPS_NONE)
- res = FALSE;
-
- gst_caps_unref (temp_caps);
- gst_caps_unref (srcpad_caps);
-
- g_return_val_if_fail (res, FALSE);
-
return gst_sbc_enc_fill_sbc_params (enc, caps);
}
gboolean
gst_sbc_enc_fill_sbc_params (GstSbcEnc * enc, GstCaps * caps)
{
- GstStructure *structure;
- gint rate, channels, subbands, blocks, bitpool;
- const gchar *mode;
- const gchar *allocation;
-
- g_assert (gst_caps_is_fixed (caps));
- 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;
- if (!gst_structure_get_int (structure, "subbands", &subbands))
- return FALSE;
- if (!gst_structure_get_int (structure, "blocks", &blocks))
- return FALSE;
- if (!gst_structure_get_int (structure, "bitpool", &bitpool))
- return FALSE;
-
- if (!(mode = gst_structure_get_string (structure, "mode")))
- return FALSE;
- if (!(allocation = gst_structure_get_string (structure, "allocation")))
+ if (!gst_sbc_util_fill_sbc_params (&enc->sbc, caps))
return FALSE;
- enc->rate = enc->sbc.rate = rate;
- enc->channels = enc->sbc.channels = channels;
- enc->blocks = enc->sbc.blocks = blocks;
- enc->subbands = enc->sbc.subbands = subbands;
- enc->sbc.bitpool = bitpool;
- enc->mode = enc->sbc.joint = gst_sbc_get_mode_int (mode);
- enc->allocation = enc->sbc.allocation =
- gst_sbc_get_allocation_mode_int (allocation);
+ enc->rate = enc->sbc.rate;
+ enc->channels = enc->sbc.channels;
+ enc->blocks = enc->sbc.blocks;
+ enc->subbands = enc->sbc.subbands;
+ enc->mode = enc->sbc.joint;
+ enc->allocation = enc->sbc.allocation;
enc->codesize = sbc_get_codesize (&enc->sbc);
enc->frame_length = sbc_get_frame_length (&enc->sbc);
enc->frame_duration = sbc_get_frame_duration (&enc->sbc);
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)
self->rate = SBC_ENC_DEFAULT_RATE;
self->channels = SBC_ENC_DEFAULT_CHANNELS;
+ self->frame_length = 0;
+ self->frame_duration = 0;
+
self->adapter = gst_adapter_new ();
}
+
+gboolean
+gst_sbc_enc_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "sbcenc",
+ GST_RANK_NONE, GST_TYPE_SBC_ENC);
+}
GType gst_sbc_enc_get_type(void);
+gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin);
+
G_END_DECLS
"allocation = (string) { snr, loudness },"
"bitpool = (int) [ 2, 64 ]"));
-/* Creates a fixed caps from the caps given. */
-/* FIXME use gstsbcutil caps fixating function */
-static GstCaps *
-sbc_parse_select_caps (GstSbcParse * parse, GstCaps * caps)
+static gboolean
+sbc_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
{
- GstCaps *result;
+ GstSbcParse *parse;
GstStructure *structure;
- const GValue *value;
- gboolean error = FALSE;
- gint temp, rate, channels, blocks, subbands, bitpool;
- const gchar *allocation = NULL;
- const gchar *mode = NULL;
- const gchar *error_message = NULL;
- gchar *str;
-
- str = gst_caps_to_string (caps);
- GST_DEBUG_OBJECT (parse, "Parsing caps: %s", str);
- g_free (str);
+ gint rate, channels;
+
+ parse = GST_SBC_PARSE (GST_PAD_PARENT (pad));
structure = gst_caps_get_structure (caps, 0);
- if (!gst_structure_has_field (structure, "rate")) {
- error = TRUE;
- error_message = "no rate.";
- goto error;
- } else {
- value = gst_structure_get_value (structure, "rate");
- if (GST_VALUE_HOLDS_LIST (value))
- temp = gst_sbc_select_rate_from_list (value);
- else
- temp = g_value_get_int (value);
- rate = temp;
- }
+ if (!gst_structure_get_int (structure, "rate", &rate))
+ return FALSE;
- if (!gst_structure_has_field (structure, "channels")) {
- error = TRUE;
- error_message = "no channels.";
- goto error;
- } else {
- value = gst_structure_get_value (structure, "channels");
- if (GST_VALUE_HOLDS_INT_RANGE (value))
- temp = gst_sbc_select_channels_from_range (value);
- else
- temp = g_value_get_int (value);
- channels = temp;
- }
+ if (!gst_structure_get_int (structure, "channels", &channels))
+ return FALSE;
- if (!gst_structure_has_field (structure, "blocks")) {
- error = TRUE;
- error_message = "no blocks.";
- goto error;
- } else {
- value = gst_structure_get_value (structure, "blocks");
- if (GST_VALUE_HOLDS_LIST (value))
- temp = gst_sbc_select_blocks_from_list (value);
- else
- temp = g_value_get_int (value);
- blocks = temp;
- }
+ if (!(parse->rate == 0 || rate == parse->rate))
+ return FALSE;
- if (!gst_structure_has_field (structure, "subbands")) {
- error = TRUE;
- error_message = "no subbands.";
- goto error;
- } else {
- value = gst_structure_get_value (structure, "subbands");
- if (GST_VALUE_HOLDS_LIST (value))
- temp = gst_sbc_select_subbands_from_list (value);
- else
- temp = g_value_get_int (value);
- subbands = temp;
- }
+ if (!(parse->channels == 0 || channels == parse->channels))
+ return FALSE;
- if (!gst_structure_has_field (structure, "bitpool")) {
- error = TRUE;
- error_message = "no bitpool";
- goto error;
- } else {
- value = gst_structure_get_value (structure, "bitpool");
- if (GST_VALUE_HOLDS_INT_RANGE (value))
- temp = gst_sbc_select_bitpool_from_range (value);
- else
- temp = g_value_get_int (value);
- bitpool = temp;
- }
+ parse->rate = rate;
+ parse->channels = channels;
- if (!gst_structure_has_field (structure, "allocation")) {
- error = TRUE;
- error_message = "no allocation.";
- goto error;
- } else {
- value = gst_structure_get_value (structure, "allocation");
- if (GST_VALUE_HOLDS_LIST (value))
- allocation = gst_sbc_get_allocation_from_list (value);
- else
- allocation = g_value_get_string (value);
- }
+ return gst_sbc_util_fill_sbc_params (&parse->sbc, caps);
+}
- if (!gst_structure_has_field (structure, "mode")) {
- error = TRUE;
- error_message = "no mode.";
- goto error;
- } else {
- value = gst_structure_get_value (structure, "mode");
- if (GST_VALUE_HOLDS_LIST (value))
- mode = gst_sbc_get_mode_from_list (value);
- else
- mode = g_value_get_string (value);
- }
+static GstCaps *
+sbc_parse_src_getcaps (GstPad * pad)
+{
+ GstCaps *caps;
+ const GstCaps *allowed_caps;
+ GstStructure *structure;
+ GValue *value;
+ GstSbcParse *parse = GST_SBC_PARSE (GST_PAD_PARENT (pad));
-error:
- if (error) {
- GST_ERROR_OBJECT (parse, "Invalid input caps: %s", error_message);
- return NULL;
- }
+ allowed_caps = gst_pad_get_allowed_caps (pad);
+ if (allowed_caps == NULL)
+ allowed_caps = gst_pad_get_pad_template_caps (pad);
+ caps = gst_caps_copy (allowed_caps);
+
+ value = g_new0 (GValue, 1);
+
+ structure = gst_caps_get_structure (caps, 0);
- result = gst_caps_new_simple ("audio/x-sbc",
- "rate", G_TYPE_INT, rate,
- "channels", G_TYPE_INT, channels,
- "mode", G_TYPE_STRING, mode,
- "blocks", G_TYPE_INT, blocks,
- "subbands", G_TYPE_INT, subbands,
- "allocation", G_TYPE_STRING, allocation,
- "bitpool", G_TYPE_INT, bitpool, NULL);
- parse->sbc.rate = rate;
- parse->sbc.channels = channels;
- parse->sbc.blocks = blocks;
- parse->sbc.subbands = subbands;
- parse->sbc.bitpool = bitpool;
- parse->sbc.joint = gst_sbc_get_mode_int (mode);
- parse->sbc.allocation = gst_sbc_get_allocation_mode_int (allocation);
-
- return result;
+ if (parse->rate != 0)
+ gst_sbc_util_set_structure_int_param (structure, "rate",
+ parse->rate, value);
+ if (parse->channels != 0)
+ gst_sbc_util_set_structure_int_param (structure, "channels",
+ parse->channels, value);
+
+ g_free (value);
+
+ return caps;
}
static gboolean
-sbc_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
+sbc_parse_src_acceptcaps (GstPad * pad, GstCaps * caps)
{
+ GstStructure *structure;
GstSbcParse *parse;
- GstCaps *inter, *other, *srccaps;
+ gint rate, channels;
parse = GST_SBC_PARSE (GST_PAD_PARENT (pad));
- other = gst_pad_peer_get_caps (parse->srcpad);
- if (other == NULL)
- other = gst_caps_new_any ();
+ structure = gst_caps_get_structure (caps, 0);
- inter = gst_caps_intersect (caps, other);
- if (gst_caps_is_empty (inter)) {
- gst_caps_unref (inter);
+ if (!gst_structure_get_int (structure, "rate", &rate))
return FALSE;
- }
- srccaps = sbc_parse_select_caps (parse, inter);
- if (srccaps == NULL) {
- gst_caps_unref (inter);
+ if (!gst_structure_get_int (structure, "channels", &channels))
return FALSE;
- }
-
- gst_pad_set_caps (parse->srcpad, srccaps);
- gst_caps_unref (inter);
- gst_caps_unref (other);
- gst_caps_unref (srccaps);
+ if ((parse->rate == 0 || parse->rate == rate)
+ && (parse->channels == 0 || parse->channels == channels))
+ return TRUE;
- return TRUE;
+ return FALSE;
}
static GstFlowReturn
timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (parse->buffer) {
- GstBuffer *temp = buffer;
+ GstBuffer *temp;
+ temp = buffer;
buffer = gst_buffer_span (parse->buffer, 0, buffer,
- GST_BUFFER_SIZE (parse->buffer) + GST_BUFFER_SIZE (buffer));
- gst_buffer_unref (temp);
+ GST_BUFFER_SIZE (parse->buffer)
+ + GST_BUFFER_SIZE (buffer));
gst_buffer_unref (parse->buffer);
+ gst_buffer_unref (temp);
parse->buffer = NULL;
}
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_DEBUG ("Finish subband codec");
+
if (parse->buffer) {
gst_buffer_unref (parse->buffer);
parse->buffer = NULL;
}
sbc_finish (&parse->sbc);
+
break;
default:
self->srcpad =
gst_pad_new_from_static_template (&sbc_parse_src_factory, "src");
+ gst_pad_set_getcaps_function (self->srcpad,
+ GST_DEBUG_FUNCPTR (sbc_parse_src_getcaps));
+ gst_pad_set_acceptcaps_function (self->srcpad,
+ GST_DEBUG_FUNCPTR (sbc_parse_src_acceptcaps));
+ /* FIXME get encoding parameters on set caps */
gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
}
+
+gboolean
+gst_sbc_parse_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "sbcparse",
+ GST_RANK_NONE, GST_TYPE_SBC_PARSE);
+}
GstBuffer *buffer;
sbc_t sbc;
+
+ gint channels;
+ gint rate;
};
struct _GstSbcParseClass {
GType gst_sbc_parse_get_type(void);
+gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin);
+
G_END_DECLS
#endif
#include "ipc.h"
+#include <math.h>
#include "gstsbcutil.h"
/*
return result;
}
+
+/**
+ * Sets the int field_value to the param "field" on the structure.
+ * value is used to do the operation, it must be a uninitialized (zero-filled)
+ * GValue, it will be left unitialized at the end of the function.
+ */
+void
+gst_sbc_util_set_structure_int_param (GstStructure * structure,
+ const gchar * field, gint field_value, GValue * value)
+{
+ value = g_value_init (value, G_TYPE_INT);
+ g_value_set_int (value, field_value);
+ gst_structure_set_value (structure, field, value);
+ g_value_unset (value);
+}
+
+/**
+ * Sets the string field_value to the param "field" on the structure.
+ * value is used to do the operation, it must be a uninitialized (zero-filled)
+ * GValue, it will be left unitialized at the end of the function.
+ */
+void
+gst_sbc_util_set_structure_string_param (GstStructure * structure,
+ const gchar * field, const gchar * field_value, GValue * value)
+{
+ value = g_value_init (value, G_TYPE_STRING);
+ g_value_set_string (value, field_value);
+ gst_structure_set_value (structure, field, value);
+ g_value_unset (value);
+}
+
+gboolean
+gst_sbc_util_fill_sbc_params (sbc_t * sbc, GstCaps * caps)
+{
+ GstStructure *structure;
+ gint rate, channels, subbands, blocks, bitpool;
+ const gchar *mode;
+ const gchar *allocation;
+
+ g_assert (gst_caps_is_fixed (caps));
+
+ 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;
+ if (!gst_structure_get_int (structure, "subbands", &subbands))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "blocks", &blocks))
+ return FALSE;
+ if (!gst_structure_get_int (structure, "bitpool", &bitpool))
+ return FALSE;
+
+ if (!(mode = gst_structure_get_string (structure, "mode")))
+ return FALSE;
+ if (!(allocation = gst_structure_get_string (structure, "allocation")))
+ return FALSE;
+
+ sbc->rate = rate;
+ sbc->channels = channels;
+ sbc->blocks = blocks;
+ sbc->subbands = subbands;
+ sbc->bitpool = bitpool;
+ sbc->joint = gst_sbc_get_mode_int (mode);
+ sbc->allocation = gst_sbc_get_allocation_mode_int (allocation);
+
+ return TRUE;
+}
+
+gint
+gst_sbc_util_calc_frame_len (gint subbands, gint channels,
+ gint blocks, gint bitpool, gint channel_mode)
+{
+ gint len;
+ gint join;
+ len = 4 + (4 * subbands * channels) / 8;
+
+ if (channel_mode == BT_A2DP_CHANNEL_MODE_MONO ||
+ channel_mode == BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
+ len += ((blocks * channels * bitpool) + 7) / 8;
+ else {
+ join = channel_mode == BT_A2DP_CHANNEL_MODE_JOINT_STEREO ? 1 : 0;
+ len += ((join * subbands + blocks * bitpool) + 7) / 8;
+ }
+
+ return len;
+}
+
+gint
+gst_sbc_util_calc_bitrate (gint frame_len, gint rate, gint subbands,
+ gint blocks)
+{
+ return (((frame_len * 8 * rate / subbands) / blocks) / 1000);
+}
+
+gint64
+gst_sbc_util_calc_frame_duration (gint rate, gint blocks, gint subbands)
+{
+ gint64 res = 1000000;
+ return res * blocks * subbands / rate;
+}
GstCaps* gst_sbc_caps_from_sbc(sbc_capabilities_t *sbc, gint channels);
GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message);
+
+void gst_sbc_util_set_structure_int_param(GstStructure *structure,
+ const gchar* field, gint field_value,
+ GValue *value);
+
+void gst_sbc_util_set_structure_string_param(GstStructure *structure,
+ const gchar* field, const gchar* field_value,
+ GValue *value);
+
+gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps);
+
+gint gst_sbc_util_calc_frame_len(gint subbands, gint channels,
+ gint blocks, gint bitpool, gint channel_mode);
+
+gint gst_sbc_util_calc_bitrate(gint frame_len, gint rate, gint subbands,
+ gint blocks);
+
+gint64 gst_sbc_util_calc_frame_duration(gint rate, gint blocks, gint subbands);