diff --git a/ext/sbc/gstsbcdec.c b/ext/sbc/gstsbcdec.c index 27386dd9e2..b3378580c6 100644 --- a/ext/sbc/gstsbcdec.c +++ b/ext/sbc/gstsbcdec.c @@ -192,3 +192,10 @@ gst_sbc_dec_init (GstSbcDec * self, GstSbcDecClass * klass) 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); +} diff --git a/ext/sbc/gstsbcdec.h b/ext/sbc/gstsbcdec.h index 4a6922a090..0bb0b57e2d 100644 --- a/ext/sbc/gstsbcdec.h +++ b/ext/sbc/gstsbcdec.h @@ -58,4 +58,6 @@ struct _GstSbcDecClass { GType gst_sbc_dec_get_type(void); +gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin); + G_END_DECLS diff --git a/ext/sbc/gstsbcenc.c b/ext/sbc/gstsbcenc.c index 5d7a804506..325a956943 100644 --- a/ext/sbc/gstsbcenc.c +++ b/ext/sbc/gstsbcenc.c @@ -121,32 +121,6 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, 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) { @@ -155,41 +129,48 @@ 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; } @@ -207,23 +188,10 @@ sbc_enc_src_getcaps (GstPad * pad) 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); } @@ -317,39 +285,16 @@ error: 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)) + if (!gst_sbc_util_fill_sbc_params (&enc->sbc, caps)) return FALSE; - if (!(mode = gst_structure_get_string (structure, "mode"))) - return FALSE; - if (!(allocation = gst_structure_get_string (structure, "allocation"))) - 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); @@ -391,6 +336,8 @@ sbc_enc_chain (GstPad * pad, GstBuffer * buffer) 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) @@ -587,5 +534,15 @@ gst_sbc_enc_init (GstSbcEnc * self, GstSbcEncClass * klass) 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); +} diff --git a/ext/sbc/gstsbcenc.h b/ext/sbc/gstsbcenc.h index d81428c914..c7b216385f 100644 --- a/ext/sbc/gstsbcenc.h +++ b/ext/sbc/gstsbcenc.h @@ -68,4 +68,6 @@ struct _GstSbcEncClass { GType gst_sbc_enc_get_type(void); +gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin); + G_END_DECLS diff --git a/ext/sbc/gstsbcparse.c b/ext/sbc/gstsbcparse.c index 93bae3aeee..acc002c9d5 100644 --- a/ext/sbc/gstsbcparse.c +++ b/ext/sbc/gstsbcparse.c @@ -56,171 +56,86 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, "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) -{ - GstCaps *result; - 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); - - 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_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_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 (!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 (!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; - } - - 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); - } - - 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); - } - -error: - if (error) { - GST_ERROR_OBJECT (parse, "Invalid input caps: %s", error_message); - return NULL; - } - - 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; -} - static gboolean sbc_parse_sink_setcaps (GstPad * pad, GstCaps * caps) { GstSbcParse *parse; - GstCaps *inter, *other, *srccaps; + GstStructure *structure; + 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); + if (!(parse->rate == 0 || rate == parse->rate)) + return FALSE; - gst_caps_unref (inter); - gst_caps_unref (other); - gst_caps_unref (srccaps); + if (!(parse->channels == 0 || channels == parse->channels)) + return FALSE; - return TRUE; + parse->rate = rate; + parse->channels = channels; + + return gst_sbc_util_fill_sbc_params (&parse->sbc, caps); +} + +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)); + + 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); + + 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_src_acceptcaps (GstPad * pad, GstCaps * caps) +{ + GstStructure *structure; + GstSbcParse *parse; + gint rate, channels; + + parse = GST_SBC_PARSE (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; + + if ((parse->rate == 0 || parse->rate == rate) + && (parse->channels == 0 || parse->channels == channels)) + return TRUE; + + return FALSE; } static GstFlowReturn @@ -235,11 +150,13 @@ sbc_parse_chain (GstPad * pad, GstBuffer * buffer) 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; } @@ -299,11 +216,13 @@ sbc_parse_change_state (GstElement * element, GstStateChange transition) 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: @@ -353,5 +272,17 @@ gst_sbc_parse_init (GstSbcParse * self, GstSbcParseClass * klass) 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); +} diff --git a/ext/sbc/gstsbcparse.h b/ext/sbc/gstsbcparse.h index ceaf21977f..eb9ca4418f 100644 --- a/ext/sbc/gstsbcparse.h +++ b/ext/sbc/gstsbcparse.h @@ -50,6 +50,9 @@ struct _GstSbcParse { GstBuffer *buffer; sbc_t sbc; + + gint channels; + gint rate; }; struct _GstSbcParseClass { @@ -58,4 +61,6 @@ struct _GstSbcParseClass { GType gst_sbc_parse_get_type(void); +gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin); + G_END_DECLS diff --git a/ext/sbc/gstsbcutil.c b/ext/sbc/gstsbcutil.c index b66a63be62..a63fe9ded3 100644 --- a/ext/sbc/gstsbcutil.c +++ b/ext/sbc/gstsbcutil.c @@ -26,6 +26,7 @@ #endif #include "ipc.h" +#include #include "gstsbcutil.h" /* @@ -316,3 +317,105 @@ error: 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; +} diff --git a/ext/sbc/gstsbcutil.h b/ext/sbc/gstsbcutil.h index 4581abf720..40b9eae73e 100644 --- a/ext/sbc/gstsbcutil.h +++ b/ext/sbc/gstsbcutil.h @@ -49,3 +49,21 @@ const gchar *gst_sbc_get_mode_string(int joint); 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);