sbc: Fix sbc negotiation and improves buffer handling by using GstAdapter.

This commit is contained in:
Luiz Augusto von Dentz 2007-11-01 19:45:00 +00:00 committed by Tim-Philipp Müller
parent 5672836c61
commit 6f87580cfa
5 changed files with 128 additions and 69 deletions

View file

@ -116,7 +116,6 @@ 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 ]"));
static GstCaps * static GstCaps *
sbc_enc_generate_srcpad_caps (GstSbcEnc * enc, GstCaps * caps) sbc_enc_generate_srcpad_caps (GstSbcEnc * enc, GstCaps * caps)
{ {
@ -190,25 +189,86 @@ error:
return FALSE; return FALSE;
} }
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")))
return FALSE;
enc->sbc.rate = rate;
enc->sbc.channels = channels;
enc->blocks = blocks;
enc->sbc.subbands = subbands;
enc->sbc.bitpool = bitpool;
enc->mode = gst_sbc_get_mode_int (mode);
enc->allocation = gst_sbc_get_allocation_mode_int (allocation);
return TRUE;
}
static gboolean
gst_sbc_enc_change_caps (GstSbcEnc * enc, GstCaps * caps)
{
GST_INFO_OBJECT (enc, "Changing srcpad caps (renegotiation)");
if (!gst_pad_accept_caps (enc->srcpad, caps)) {
GST_WARNING_OBJECT (enc, "Src pad refused caps");
return FALSE;
}
if (!gst_sbc_enc_fill_sbc_params (enc, caps)) {
GST_ERROR_OBJECT (enc, "couldn't get sbc parameters from caps");
return FALSE;
}
return TRUE;
}
static GstFlowReturn static GstFlowReturn
sbc_enc_chain (GstPad * pad, GstBuffer * buffer) sbc_enc_chain (GstPad * pad, GstBuffer * buffer)
{ {
GstSbcEnc *enc = GST_SBC_ENC (gst_pad_get_parent (pad)); GstSbcEnc *enc = GST_SBC_ENC (gst_pad_get_parent (pad));
GstAdapter *adapter = enc->adapter;
GstFlowReturn res = GST_FLOW_OK; GstFlowReturn res = GST_FLOW_OK;
guint size, offset = 0; gint codesize = enc->sbc.subbands * enc->sbc.blocks * enc->sbc.channels * 2;
guint8 *data;
data = GST_BUFFER_DATA (buffer); gst_adapter_push (adapter, buffer);
size = GST_BUFFER_SIZE (buffer);
while (offset < size) { while (gst_adapter_available (adapter) >= codesize && res == GST_FLOW_OK) {
GstBuffer *output; GstBuffer *output;
GstCaps *caps; GstCaps *caps;
const guint8 *data;
int consumed; int consumed;
consumed = sbc_encode (&enc->sbc, data + offset, size - offset); data = gst_adapter_peek (adapter, codesize);
if (consumed <= 0) consumed = sbc_encode (&enc->sbc, (gpointer) data, codesize);
if (consumed <= 0) {
GST_ERROR ("comsumed < 0, codesize: %d", codesize);
break; break;
}
gst_adapter_flush (adapter, consumed);
caps = GST_PAD_CAPS (enc->srcpad); caps = GST_PAD_CAPS (enc->srcpad);
@ -218,21 +278,25 @@ sbc_enc_chain (GstPad * pad, GstBuffer * buffer)
if (res != GST_FLOW_OK) if (res != GST_FLOW_OK)
goto done; goto done;
if (!gst_caps_is_equal (caps, GST_BUFFER_CAPS (output)))
if (!gst_sbc_enc_change_caps (enc, GST_BUFFER_CAPS (output))) {
res = GST_FLOW_ERROR;
GST_ERROR_OBJECT (enc, "couldn't renegotiate caps");
goto done;
}
memcpy (GST_BUFFER_DATA (output), enc->sbc.data, enc->sbc.len); memcpy (GST_BUFFER_DATA (output), enc->sbc.data, enc->sbc.len);
GST_BUFFER_TIMESTAMP (output) = GST_BUFFER_TIMESTAMP (buffer); GST_BUFFER_TIMESTAMP (output) = GST_BUFFER_TIMESTAMP (buffer);
res = gst_pad_push (enc->srcpad, output); res = gst_pad_push (enc->srcpad, output);
if (res != GST_FLOW_OK) if (res != GST_FLOW_OK) {
GST_ERROR_OBJECT (enc, "pad pushing failed");
goto done; goto done;
}
offset += consumed;
} }
if (offset < size)
res = GST_FLOW_ERROR;
done: done:
gst_buffer_unref (buffer);
gst_object_unref (enc); gst_object_unref (enc);
return res; return res;
@ -261,6 +325,17 @@ sbc_enc_change_state (GstElement * element, GstStateChange transition)
return parent_class->change_state (element, transition); return parent_class->change_state (element, transition);
} }
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 void static void
gst_sbc_enc_base_init (gpointer g_class) gst_sbc_enc_base_init (gpointer g_class)
{ {
@ -339,6 +414,7 @@ gst_sbc_enc_class_init (GstSbcEncClass * klass)
object_class->set_property = GST_DEBUG_FUNCPTR (gst_sbc_enc_set_property); object_class->set_property = GST_DEBUG_FUNCPTR (gst_sbc_enc_set_property);
object_class->get_property = GST_DEBUG_FUNCPTR (gst_sbc_enc_get_property); object_class->get_property = GST_DEBUG_FUNCPTR (gst_sbc_enc_get_property);
object_class->dispose = GST_DEBUG_FUNCPTR (gst_sbc_enc_dispose);
element_class->change_state = GST_DEBUG_FUNCPTR (sbc_enc_change_state); element_class->change_state = GST_DEBUG_FUNCPTR (sbc_enc_change_state);
@ -381,4 +457,6 @@ gst_sbc_enc_init (GstSbcEnc * self, GstSbcEncClass * klass)
self->blocks = SBC_ENC_DEFAULT_BLOCKS; self->blocks = SBC_ENC_DEFAULT_BLOCKS;
self->mode = SBC_ENC_DEFAULT_MODE; self->mode = SBC_ENC_DEFAULT_MODE;
self->allocation = SBC_ENC_DEFAULT_ALLOCATION; self->allocation = SBC_ENC_DEFAULT_ALLOCATION;
self->adapter = gst_adapter_new ();
} }

View file

@ -22,6 +22,7 @@
*/ */
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "sbc.h" #include "sbc.h"
#include "ipc.h" #include "ipc.h"
@ -48,6 +49,7 @@ struct _GstSbcEnc {
GstPad *sinkpad; GstPad *sinkpad;
GstPad *srcpad; GstPad *srcpad;
GstAdapter *adapter;
gint mode; gint mode;
gint blocks; gint blocks;

View file

@ -79,8 +79,6 @@ sbc_parse_select_caps (GstSbcParse * parse, GstCaps * caps)
value = gst_structure_get_value (structure, "rate"); value = gst_structure_get_value (structure, "rate");
if (GST_VALUE_HOLDS_LIST (value)) { if (GST_VALUE_HOLDS_LIST (value)) {
temp = gst_sbc_select_rate_from_list (value); temp = gst_sbc_select_rate_from_list (value);
} else if (GST_VALUE_HOLDS_INT_RANGE (value)) {
temp = gst_sbc_select_rate_from_range (value);
} else { } else {
temp = g_value_get_int (value); temp = g_value_get_int (value);
} }
@ -93,9 +91,7 @@ sbc_parse_select_caps (GstSbcParse * parse, GstCaps * caps)
goto error; goto error;
} else { } else {
value = gst_structure_get_value (structure, "channels"); value = gst_structure_get_value (structure, "channels");
if (GST_VALUE_HOLDS_LIST (value)) { if (GST_VALUE_HOLDS_INT_RANGE (value)) {
temp = gst_sbc_select_channels_from_list (value);
} else if (GST_VALUE_HOLDS_INT_RANGE (value)) {
temp = gst_sbc_select_channels_from_range (value); temp = gst_sbc_select_channels_from_range (value);
} else { } else {
temp = g_value_get_int (value); temp = g_value_get_int (value);
@ -111,8 +107,6 @@ sbc_parse_select_caps (GstSbcParse * parse, GstCaps * caps)
value = gst_structure_get_value (structure, "blocks"); value = gst_structure_get_value (structure, "blocks");
if (GST_VALUE_HOLDS_LIST (value)) { if (GST_VALUE_HOLDS_LIST (value)) {
temp = gst_sbc_select_blocks_from_list (value); temp = gst_sbc_select_blocks_from_list (value);
} else if (GST_VALUE_HOLDS_INT_RANGE (value)) {
temp = gst_sbc_select_blocks_from_range (value);
} else { } else {
temp = g_value_get_int (value); temp = g_value_get_int (value);
} }
@ -127,8 +121,6 @@ sbc_parse_select_caps (GstSbcParse * parse, GstCaps * caps)
value = gst_structure_get_value (structure, "subbands"); value = gst_structure_get_value (structure, "subbands");
if (GST_VALUE_HOLDS_LIST (value)) { if (GST_VALUE_HOLDS_LIST (value)) {
temp = gst_sbc_select_subbands_from_list (value); temp = gst_sbc_select_subbands_from_list (value);
} else if (GST_VALUE_HOLDS_INT_RANGE (value)) {
temp = gst_sbc_select_subbands_from_range (value);
} else { } else {
temp = g_value_get_int (value); temp = g_value_get_int (value);
} }

View file

@ -39,27 +39,6 @@ gst_sbc_select_rate_from_list (const GValue * value)
return g_value_get_int (gst_value_list_get_value (value, size - 1)); return g_value_get_int (gst_value_list_get_value (value, size - 1));
} }
/*
* Selects one rate from a range of possible rates
* TODO - use a better approach to this (it is selecting the maximum value)
*/
gint
gst_sbc_select_rate_from_range (const GValue * value)
{
return gst_value_get_int_range_max (value);
}
/*
* Selects one number of channels from a list of possible numbers
* TODO - use a better approach to this (it is selecting the last element)
*/
gint
gst_sbc_select_channels_from_list (const GValue * value)
{
guint size = gst_value_list_get_size (value);
return g_value_get_int (gst_value_list_get_value (value, size - 1));
}
/* /*
* Selects one number of channels option from a range of possible numbers * Selects one number of channels option from a range of possible numbers
* TODO - use a better approach to this (it is selecting the maximum value) * TODO - use a better approach to this (it is selecting the maximum value)
@ -81,16 +60,6 @@ gst_sbc_select_blocks_from_list (const GValue * value)
return g_value_get_int (gst_value_list_get_value (value, size - 1)); return g_value_get_int (gst_value_list_get_value (value, size - 1));
} }
/*
* Selects one blocks option from a range of possible blocks
* TODO - use a better approach to this (it is selecting the maximum value)
*/
gint
gst_sbc_select_blocks_from_range (const GValue * value)
{
return gst_value_get_int_range_max (value);
}
/* /*
* Selects one number of subbands from a list * Selects one number of subbands from a list
* TODO - use a better approach to this (it is selecting the last element) * TODO - use a better approach to this (it is selecting the last element)
@ -102,16 +71,6 @@ gst_sbc_select_subbands_from_list (const GValue * value)
return g_value_get_int (gst_value_list_get_value (value, size - 1)); return g_value_get_int (gst_value_list_get_value (value, size - 1));
} }
/*
* Selects one subbands option from a range
* TODO - use a better approach to this (it is selecting the maximum value)
*/
gint
gst_sbc_select_subbands_from_range (const GValue * value)
{
return gst_value_get_int_range_max (value);
}
/* /*
* Selects one bitpool option from a range * Selects one bitpool option from a range
* TODO - use a better approach to this (it is selecting the maximum value) * TODO - use a better approach to this (it is selecting the maximum value)
@ -202,8 +161,31 @@ gst_sbc_get_allocation_string (int alloc)
case CFG_ALLOCATION_SNR: case CFG_ALLOCATION_SNR:
return "snr"; return "snr";
case CFG_ALLOCATION_AUTO: case CFG_ALLOCATION_AUTO:
return NULL; /* TODO what should be selected here? */ return "loudness"; /* TODO what should be selected here? */
default: default:
return NULL; return NULL;
} }
} }
GstCaps *
gst_sbc_caps_from_sbc (struct ipc_data_cfg * cfg,
struct ipc_codec_sbc * sbc, gint channels)
{
GstCaps *caps;
const gchar *mode_str;
const gchar *allocation_str;
mode_str = gst_sbc_get_mode_string (cfg->mode);
allocation_str = gst_sbc_get_allocation_string (sbc->allocation);
caps = gst_caps_new_simple ("audio/x-sbc",
"rate", G_TYPE_INT, cfg->rate,
"channels", G_TYPE_INT, channels,
"mode", G_TYPE_STRING, mode_str,
"subbands", G_TYPE_INT, sbc->subbands,
"blocks", G_TYPE_INT, sbc->blocks,
"allocation", G_TYPE_STRING, allocation_str,
"bitpool", G_TYPE_INT, sbc->bitpool, NULL);
return caps;
}

View file

@ -22,18 +22,20 @@
*/ */
#include <gst/gst.h> #include <gst/gst.h>
#include "sbc.h"
struct ipc_data_cfg; /* FIXME can't include ipc.h */
struct ipc_codec_sbc;
gint gst_sbc_select_rate_from_list(const GValue *value); gint gst_sbc_select_rate_from_list(const GValue *value);
gint gst_sbc_select_rate_from_range(const GValue *value);
gint gst_sbc_select_channels_from_list(const GValue *value);
gint gst_sbc_select_channels_from_range(const GValue *value); gint gst_sbc_select_channels_from_range(const GValue *value);
gint gst_sbc_select_blocks_from_list(const GValue *value); gint gst_sbc_select_blocks_from_list(const GValue *value);
gint gst_sbc_select_blocks_from_range(const GValue *value);
gint gst_sbc_select_subbands_from_list(const GValue *value); gint gst_sbc_select_subbands_from_list(const GValue *value);
gint gst_sbc_select_subbands_from_range(const GValue *value);
gint gst_sbc_select_bitpool_from_range(const GValue *value);
gint gst_sbc_select_bitpool_from_range(const GValue *value); gint gst_sbc_select_bitpool_from_range(const GValue *value);
@ -44,3 +46,6 @@ const gchar *gst_sbc_get_allocation_string(int alloc);
const gchar *gst_sbc_get_mode_from_list(const GValue *value); const gchar *gst_sbc_get_mode_from_list(const GValue *value);
gint gst_sbc_get_mode_int(const gchar *mode); gint gst_sbc_get_mode_int(const gchar *mode);
const gchar *gst_sbc_get_mode_string(int joint); const gchar *gst_sbc_get_mode_string(int joint);
GstCaps* gst_sbc_caps_from_sbc(struct ipc_data_cfg *cfg, struct ipc_codec_sbc *sbc,
gint channels);