mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 06:46:38 +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 },"
|
"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 ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue