mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-21 15:56:42 +00:00
sbc: Fix sbc negotiation and improves buffer handling by using GstAdapter.
This commit is contained in:
parent
5672836c61
commit
6f87580cfa
5 changed files with 128 additions and 69 deletions
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue