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 },"
"bitpool = (int) [ 2, 64 ]"));
static GstCaps *
sbc_enc_generate_srcpad_caps (GstSbcEnc * enc, GstCaps * caps)
{
@ -190,25 +189,86 @@ error:
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
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;
guint size, offset = 0;
guint8 *data;
gint codesize = enc->sbc.subbands * enc->sbc.blocks * enc->sbc.channels * 2;
data = GST_BUFFER_DATA (buffer);
size = GST_BUFFER_SIZE (buffer);
gst_adapter_push (adapter, buffer);
while (offset < size) {
while (gst_adapter_available (adapter) >= codesize && res == GST_FLOW_OK) {
GstBuffer *output;
GstCaps *caps;
const guint8 *data;
int consumed;
consumed = sbc_encode (&enc->sbc, data + offset, size - offset);
if (consumed <= 0)
data = gst_adapter_peek (adapter, codesize);
consumed = sbc_encode (&enc->sbc, (gpointer) data, codesize);
if (consumed <= 0) {
GST_ERROR ("comsumed < 0, codesize: %d", codesize);
break;
}
gst_adapter_flush (adapter, consumed);
caps = GST_PAD_CAPS (enc->srcpad);
@ -218,21 +278,25 @@ sbc_enc_chain (GstPad * pad, GstBuffer * buffer)
if (res != GST_FLOW_OK)
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);
GST_BUFFER_TIMESTAMP (output) = GST_BUFFER_TIMESTAMP (buffer);
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;
offset += consumed;
}
if (offset < size)
res = GST_FLOW_ERROR;
}
done:
gst_buffer_unref (buffer);
gst_object_unref (enc);
return res;
@ -261,6 +325,17 @@ sbc_enc_change_state (GstElement * element, GstStateChange 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
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->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);
@ -381,4 +457,6 @@ gst_sbc_enc_init (GstSbcEnc * self, GstSbcEncClass * klass)
self->blocks = SBC_ENC_DEFAULT_BLOCKS;
self->mode = SBC_ENC_DEFAULT_MODE;
self->allocation = SBC_ENC_DEFAULT_ALLOCATION;
self->adapter = gst_adapter_new ();
}

View file

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

View file

@ -79,8 +79,6 @@ sbc_parse_select_caps (GstSbcParse * parse, GstCaps * caps)
value = gst_structure_get_value (structure, "rate");
if (GST_VALUE_HOLDS_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 {
temp = g_value_get_int (value);
}
@ -93,9 +91,7 @@ sbc_parse_select_caps (GstSbcParse * parse, GstCaps * caps)
goto error;
} else {
value = gst_structure_get_value (structure, "channels");
if (GST_VALUE_HOLDS_LIST (value)) {
temp = gst_sbc_select_channels_from_list (value);
} else if (GST_VALUE_HOLDS_INT_RANGE (value)) {
if (GST_VALUE_HOLDS_INT_RANGE (value)) {
temp = gst_sbc_select_channels_from_range (value);
} else {
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");
if (GST_VALUE_HOLDS_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 {
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");
if (GST_VALUE_HOLDS_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 {
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));
}
/*
* 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
* 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));
}
/*
* 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
* 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));
}
/*
* 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
* 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:
return "snr";
case CFG_ALLOCATION_AUTO:
return NULL; /* TODO what should be selected here? */
return "loudness"; /* TODO what should be selected here? */
default:
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 "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_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_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_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);
gint gst_sbc_get_mode_int(const gchar *mode);
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);