sbc: Make a2dpsink to act like a bin and split the payloader.
This commit is contained in:
parent
6a34433dd8
commit
76c77b1c60
@ -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");
|
self->srcpad = gst_pad_new_from_static_template (&sbc_dec_src_factory, "src");
|
||||||
gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
|
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);
|
||||||
|
}
|
||||||
|
@ -58,4 +58,6 @@ struct _GstSbcDecClass {
|
|||||||
|
|
||||||
GType gst_sbc_dec_get_type(void);
|
GType gst_sbc_dec_get_type(void);
|
||||||
|
|
||||||
|
gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -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);
|
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 *
|
static GstCaps *
|
||||||
sbc_enc_generate_srcpad_caps (GstSbcEnc * enc)
|
sbc_enc_generate_srcpad_caps (GstSbcEnc * enc)
|
||||||
{
|
{
|
||||||
@ -155,41 +129,48 @@ sbc_enc_generate_srcpad_caps (GstSbcEnc * enc)
|
|||||||
GEnumValue *enum_value;
|
GEnumValue *enum_value;
|
||||||
GEnumClass *enum_class;
|
GEnumClass *enum_class;
|
||||||
gchar *temp;
|
gchar *temp;
|
||||||
|
GValue *value;
|
||||||
|
|
||||||
src_caps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad));
|
src_caps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad));
|
||||||
structure = gst_caps_get_structure (src_caps, 0);
|
structure = gst_caps_get_structure (src_caps, 0);
|
||||||
|
|
||||||
|
value = g_new0 (GValue, 1);
|
||||||
|
|
||||||
if (enc->rate != 0)
|
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)
|
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)
|
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)
|
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) {
|
if (enc->mode != BT_A2DP_CHANNEL_MODE_AUTO) {
|
||||||
enum_class = g_type_class_ref (GST_TYPE_SBC_MODE);
|
enum_class = g_type_class_ref (GST_TYPE_SBC_MODE);
|
||||||
enum_value = g_enum_get_value (enum_class, enc->mode);
|
enum_value = g_enum_get_value (enum_class, enc->mode);
|
||||||
sbc_enc_set_structure_string_param (enc, structure, "mode",
|
gst_sbc_util_set_structure_string_param (structure, "mode",
|
||||||
enum_value->value_nick);
|
enum_value->value_nick, value);
|
||||||
g_type_class_unref (enum_class);
|
g_type_class_unref (enum_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enc->allocation != BT_A2DP_ALLOCATION_AUTO) {
|
if (enc->allocation != BT_A2DP_ALLOCATION_AUTO) {
|
||||||
enum_class = g_type_class_ref (GST_TYPE_SBC_ALLOCATION);
|
enum_class = g_type_class_ref (GST_TYPE_SBC_ALLOCATION);
|
||||||
enum_value = g_enum_get_value (enum_class, enc->allocation);
|
enum_value = g_enum_get_value (enum_class, enc->allocation);
|
||||||
sbc_enc_set_structure_string_param (enc, structure, "allocation",
|
gst_sbc_util_set_structure_string_param (structure, "allocation",
|
||||||
enum_value->value_nick);
|
enum_value->value_nick, value);
|
||||||
g_type_class_unref (enum_class);
|
g_type_class_unref (enum_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
temp = gst_caps_to_string (src_caps);
|
temp = gst_caps_to_string (src_caps);
|
||||||
GST_DEBUG_OBJECT (enc, "Srcpad caps: %s", temp);
|
GST_DEBUG_OBJECT (enc, "Srcpad caps: %s", temp);
|
||||||
g_free (temp);
|
g_free (temp);
|
||||||
|
g_free (value);
|
||||||
|
|
||||||
return src_caps;
|
return src_caps;
|
||||||
}
|
}
|
||||||
@ -207,23 +188,10 @@ sbc_enc_src_getcaps (GstPad * pad)
|
|||||||
static gboolean
|
static gboolean
|
||||||
sbc_enc_src_setcaps (GstPad * pad, GstCaps * caps)
|
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));
|
GstSbcEnc *enc = GST_SBC_ENC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
GST_LOG_OBJECT (enc, "setting srcpad caps");
|
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);
|
return gst_sbc_enc_fill_sbc_params (enc, caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,39 +285,16 @@ error:
|
|||||||
gboolean
|
gboolean
|
||||||
gst_sbc_enc_fill_sbc_params (GstSbcEnc * enc, GstCaps * caps)
|
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));
|
if (!gst_sbc_util_fill_sbc_params (&enc->sbc, 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;
|
return FALSE;
|
||||||
|
|
||||||
if (!(mode = gst_structure_get_string (structure, "mode")))
|
enc->rate = enc->sbc.rate;
|
||||||
return FALSE;
|
enc->channels = enc->sbc.channels;
|
||||||
if (!(allocation = gst_structure_get_string (structure, "allocation")))
|
enc->blocks = enc->sbc.blocks;
|
||||||
return FALSE;
|
enc->subbands = enc->sbc.subbands;
|
||||||
|
enc->mode = enc->sbc.joint;
|
||||||
enc->rate = enc->sbc.rate = rate;
|
enc->allocation = enc->sbc.allocation;
|
||||||
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->codesize = sbc_get_codesize (&enc->sbc);
|
enc->codesize = sbc_get_codesize (&enc->sbc);
|
||||||
enc->frame_length = sbc_get_frame_length (&enc->sbc);
|
enc->frame_length = sbc_get_frame_length (&enc->sbc);
|
||||||
enc->frame_duration = sbc_get_frame_duration (&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_adapter_flush (adapter, consumed);
|
||||||
|
|
||||||
GST_BUFFER_TIMESTAMP (output) = GST_BUFFER_TIMESTAMP (buffer);
|
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);
|
res = gst_pad_push (enc->srcpad, output);
|
||||||
if (res != GST_FLOW_OK)
|
if (res != GST_FLOW_OK)
|
||||||
@ -587,5 +534,15 @@ gst_sbc_enc_init (GstSbcEnc * self, GstSbcEncClass * klass)
|
|||||||
self->rate = SBC_ENC_DEFAULT_RATE;
|
self->rate = SBC_ENC_DEFAULT_RATE;
|
||||||
self->channels = SBC_ENC_DEFAULT_CHANNELS;
|
self->channels = SBC_ENC_DEFAULT_CHANNELS;
|
||||||
|
|
||||||
|
self->frame_length = 0;
|
||||||
|
self->frame_duration = 0;
|
||||||
|
|
||||||
self->adapter = gst_adapter_new ();
|
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);
|
||||||
|
}
|
||||||
|
@ -68,4 +68,6 @@ struct _GstSbcEncClass {
|
|||||||
|
|
||||||
GType gst_sbc_enc_get_type(void);
|
GType gst_sbc_enc_get_type(void);
|
||||||
|
|
||||||
|
gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -56,171 +56,86 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
|
|||||||
"allocation = (string) { snr, loudness },"
|
"allocation = (string) { snr, loudness },"
|
||||||
"bitpool = (int) [ 2, 64 ]"));
|
"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
|
static gboolean
|
||||||
sbc_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
|
sbc_parse_sink_setcaps (GstPad * pad, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstSbcParse *parse;
|
GstSbcParse *parse;
|
||||||
GstCaps *inter, *other, *srccaps;
|
GstStructure *structure;
|
||||||
|
gint rate, channels;
|
||||||
|
|
||||||
parse = GST_SBC_PARSE (GST_PAD_PARENT (pad));
|
parse = GST_SBC_PARSE (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
other = gst_pad_peer_get_caps (parse->srcpad);
|
structure = gst_caps_get_structure (caps, 0);
|
||||||
if (other == NULL)
|
|
||||||
other = gst_caps_new_any ();
|
|
||||||
|
|
||||||
inter = gst_caps_intersect (caps, other);
|
if (!gst_structure_get_int (structure, "rate", &rate))
|
||||||
if (gst_caps_is_empty (inter)) {
|
|
||||||
gst_caps_unref (inter);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
srccaps = sbc_parse_select_caps (parse, inter);
|
if (!gst_structure_get_int (structure, "channels", &channels))
|
||||||
if (srccaps == NULL) {
|
|
||||||
gst_caps_unref (inter);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
gst_pad_set_caps (parse->srcpad, srccaps);
|
if (!(parse->rate == 0 || rate == parse->rate))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
gst_caps_unref (inter);
|
if (!(parse->channels == 0 || channels == parse->channels))
|
||||||
gst_caps_unref (other);
|
return FALSE;
|
||||||
gst_caps_unref (srccaps);
|
|
||||||
|
|
||||||
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
|
static GstFlowReturn
|
||||||
@ -235,11 +150,13 @@ sbc_parse_chain (GstPad * pad, GstBuffer * buffer)
|
|||||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
|
|
||||||
if (parse->buffer) {
|
if (parse->buffer) {
|
||||||
GstBuffer *temp = buffer;
|
GstBuffer *temp;
|
||||||
|
temp = buffer;
|
||||||
buffer = gst_buffer_span (parse->buffer, 0, buffer,
|
buffer = gst_buffer_span (parse->buffer, 0, buffer,
|
||||||
GST_BUFFER_SIZE (parse->buffer) + GST_BUFFER_SIZE (buffer));
|
GST_BUFFER_SIZE (parse->buffer)
|
||||||
gst_buffer_unref (temp);
|
+ GST_BUFFER_SIZE (buffer));
|
||||||
gst_buffer_unref (parse->buffer);
|
gst_buffer_unref (parse->buffer);
|
||||||
|
gst_buffer_unref (temp);
|
||||||
parse->buffer = NULL;
|
parse->buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,11 +216,13 @@ sbc_parse_change_state (GstElement * element, GstStateChange transition)
|
|||||||
|
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
GST_DEBUG ("Finish subband codec");
|
GST_DEBUG ("Finish subband codec");
|
||||||
|
|
||||||
if (parse->buffer) {
|
if (parse->buffer) {
|
||||||
gst_buffer_unref (parse->buffer);
|
gst_buffer_unref (parse->buffer);
|
||||||
parse->buffer = NULL;
|
parse->buffer = NULL;
|
||||||
}
|
}
|
||||||
sbc_finish (&parse->sbc);
|
sbc_finish (&parse->sbc);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -353,5 +272,17 @@ gst_sbc_parse_init (GstSbcParse * self, GstSbcParseClass * klass)
|
|||||||
|
|
||||||
self->srcpad =
|
self->srcpad =
|
||||||
gst_pad_new_from_static_template (&sbc_parse_src_factory, "src");
|
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);
|
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);
|
||||||
|
}
|
||||||
|
@ -50,6 +50,9 @@ struct _GstSbcParse {
|
|||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
|
|
||||||
sbc_t sbc;
|
sbc_t sbc;
|
||||||
|
|
||||||
|
gint channels;
|
||||||
|
gint rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstSbcParseClass {
|
struct _GstSbcParseClass {
|
||||||
@ -58,4 +61,6 @@ struct _GstSbcParseClass {
|
|||||||
|
|
||||||
GType gst_sbc_parse_get_type(void);
|
GType gst_sbc_parse_get_type(void);
|
||||||
|
|
||||||
|
gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
|
#include <math.h>
|
||||||
#include "gstsbcutil.h"
|
#include "gstsbcutil.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -316,3 +317,105 @@ error:
|
|||||||
|
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
@ -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_caps_from_sbc(sbc_capabilities_t *sbc, gint channels);
|
||||||
|
|
||||||
GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message);
|
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user