mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
gst/audioconvert/gstaudioconvert.c: Patch from #341562: give more specific audio caps in get_caps, so that basetransf...
Original commit message from CVS: * gst/audioconvert/gstaudioconvert.c: (make_lossless_changes), (append_with_other_format), (set_structure_widths), (gst_audio_convert_transform_caps): Patch from #341562: give more specific audio caps in get_caps, so that basetransform can make better decisions on what caps to negotiate.
This commit is contained in:
parent
e4dbbc2048
commit
8e09be1bd9
2 changed files with 214 additions and 20 deletions
|
@ -1,3 +1,12 @@
|
|||
2006-05-29 Michael Smith <msmith@fluendo.com>
|
||||
|
||||
* gst/audioconvert/gstaudioconvert.c: (make_lossless_changes),
|
||||
(append_with_other_format), (set_structure_widths),
|
||||
(gst_audio_convert_transform_caps):
|
||||
Patch from #341562: give more specific audio caps in get_caps, so
|
||||
that basetransform can make better decisions on what caps to
|
||||
negotiate.
|
||||
|
||||
2006-05-28 Stefan Kost <ensonic@users.sf.net>
|
||||
|
||||
* tests/check/elements/volume.c:
|
||||
|
|
|
@ -156,8 +156,6 @@ GST_STATIC_CAPS ( \
|
|||
|
||||
static GstAudioChannelPosition *supported_positions;
|
||||
|
||||
static GstStaticCaps gst_audio_convert_static_caps = STATIC_CAPS;
|
||||
|
||||
static GstStaticPadTemplate gst_audio_convert_src_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
|
@ -318,37 +316,224 @@ parse_error:
|
|||
}
|
||||
}
|
||||
|
||||
/* audioconvert can convert anything except sample rate; so return template
|
||||
* caps with rate fixed */
|
||||
/* FIXME:
|
||||
* it would be smart here to return the caps with the same width as the first
|
||||
/* Modify the structure so that things that must always have a single
|
||||
* value (for float), or can always be losslessly converted (for int), have
|
||||
* appropriate values.
|
||||
*/
|
||||
static GstStructure *
|
||||
make_lossless_changes (GstStructure * s, gboolean isfloat)
|
||||
{
|
||||
if (isfloat) {
|
||||
/* float doesn't have depth, and only supports width 32, and native-endian
|
||||
*/
|
||||
gst_structure_remove_field (s, "depth");
|
||||
gst_structure_set (s, "width", G_TYPE_INT, 32, NULL);
|
||||
gst_structure_set (s, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
|
||||
} else {
|
||||
/* int supports either endian, and signed or unsigned. GValues are a pain */
|
||||
GValue list = { 0 };
|
||||
GValue val = { 0 };
|
||||
int i;
|
||||
gint endian[] = { G_LITTLE_ENDIAN, G_BIG_ENDIAN };
|
||||
gboolean booleans[] = { TRUE, FALSE };
|
||||
|
||||
g_value_init (&list, GST_TYPE_LIST);
|
||||
g_value_init (&val, G_TYPE_INT);
|
||||
for (i = 0; i < 2; i++) {
|
||||
g_value_set_int (&val, endian[i]);
|
||||
gst_value_list_append_value (&list, &val);
|
||||
}
|
||||
gst_structure_set_value (s, "endianness", &list);
|
||||
g_value_unset (&val);
|
||||
g_value_unset (&list);
|
||||
|
||||
g_value_init (&list, GST_TYPE_LIST);
|
||||
g_value_init (&val, G_TYPE_BOOLEAN);
|
||||
for (i = 0; i < 2; i++) {
|
||||
g_value_set_boolean (&val, booleans[i]);
|
||||
gst_value_list_append_value (&list, &val);
|
||||
}
|
||||
gst_structure_set_value (s, "signed", &list);
|
||||
g_value_unset (&val);
|
||||
g_value_unset (&list);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Little utility function to create a related structure for float/int */
|
||||
static void
|
||||
append_with_other_format (GstCaps * caps, GstStructure * s, gboolean isfloat)
|
||||
{
|
||||
GstStructure *s2;
|
||||
|
||||
if (isfloat) {
|
||||
s2 = gst_structure_copy (s);
|
||||
gst_structure_set_name (s2, "audio/x-raw-int");
|
||||
s = make_lossless_changes (s2, FALSE);
|
||||
gst_caps_append_structure (caps, s2);
|
||||
} else {
|
||||
s2 = gst_structure_copy (s);
|
||||
gst_structure_set_name (s2, "audio/x-raw-float");
|
||||
s = make_lossless_changes (s2, TRUE);
|
||||
gst_caps_append_structure (caps, s2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set widths (a list); multiples of 8 between min and max */
|
||||
static void
|
||||
set_structure_widths (GstStructure * s, int min, int max)
|
||||
{
|
||||
GValue list = { 0 };
|
||||
GValue val = { 0 };
|
||||
int width;
|
||||
|
||||
if (min == max) {
|
||||
gst_structure_set (s, "width", G_TYPE_INT, min, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
g_value_init (&list, GST_TYPE_LIST);
|
||||
g_value_init (&val, G_TYPE_INT);
|
||||
for (width = min; width <= max; width += 8) {
|
||||
g_value_set_int (&val, width);
|
||||
gst_value_list_append_value (&list, &val);
|
||||
GST_DEBUG ("Appended width %d to widths available", width);
|
||||
}
|
||||
gst_structure_set_value (s, "width", &list);
|
||||
g_value_unset (&val);
|
||||
g_value_unset (&list);
|
||||
}
|
||||
|
||||
/* Audioconvert can perform all conversions on audio except for resampling.
|
||||
* However, there are some conversions we _prefer_ not to do. For example, it's
|
||||
* better to convert format (float<->int, endianness, etc) than the number of
|
||||
* channels, as the latter conversion is not lossless.
|
||||
*
|
||||
* So, we return, in order (assuming input caps have only one structure;
|
||||
* is this right?):
|
||||
* - input caps with a different format (lossless conversions).
|
||||
* - input caps with a different format (slightly lossy conversions).
|
||||
* - input caps with a different number of channels (very lossy!)
|
||||
*/
|
||||
static GstCaps *
|
||||
gst_audio_convert_transform_caps (GstBaseTransform * base,
|
||||
GstPadDirection direction, GstCaps * caps)
|
||||
{
|
||||
int i;
|
||||
const GValue *rate;
|
||||
GstCaps *ret;
|
||||
GstStructure *structure;
|
||||
GstStructure *s, *structure;
|
||||
gboolean isfloat;
|
||||
gint width, depth, channels;
|
||||
gchar *fields_used[] = { "width", "depth", "rate", "channels", "endianness",
|
||||
"signed"
|
||||
};
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), NULL);
|
||||
|
||||
structure = gst_caps_get_structure (caps, 0);
|
||||
|
||||
ret = gst_static_caps_get (&gst_audio_convert_static_caps);
|
||||
isfloat = strcmp (gst_structure_get_name (structure),
|
||||
"audio/x-raw-float") == 0;
|
||||
|
||||
/* if rate not set, we return the template */
|
||||
if (!(rate = gst_structure_get_value (structure, "rate")))
|
||||
return ret;
|
||||
|
||||
/* else, write rate in the template caps */
|
||||
ret = gst_caps_make_writable (ret);
|
||||
|
||||
for (i = 0; i < gst_caps_get_size (ret); ++i) {
|
||||
structure = gst_caps_get_structure (ret, i);
|
||||
gst_structure_set_value (structure, "rate", rate);
|
||||
/* We operate on a version of the original structure with any additional
|
||||
* fields absent */
|
||||
s = gst_structure_empty_new (gst_structure_get_name (structure));
|
||||
for (i = 0; i < sizeof (fields_used) / sizeof (*fields_used); i++) {
|
||||
if (gst_structure_has_field (structure, fields_used[i]))
|
||||
gst_structure_set_value (s, fields_used[i],
|
||||
gst_structure_get_value (structure, fields_used[i]));
|
||||
}
|
||||
|
||||
if (!isfloat) {
|
||||
/* Commonly, depth is left out: set it equal to width if we have a fixed
|
||||
* width, if so */
|
||||
if (!gst_structure_has_field (s, "depth") &&
|
||||
gst_structure_get_int (s, "width", &width))
|
||||
gst_structure_set (s, "depth", G_TYPE_INT, width, NULL);
|
||||
}
|
||||
|
||||
ret = gst_caps_new_empty ();
|
||||
|
||||
/* All lossless conversions */
|
||||
s = make_lossless_changes (s, isfloat);
|
||||
gst_caps_append_structure (ret, s);
|
||||
|
||||
/* Same, plus a float<->int conversion */
|
||||
append_with_other_format (ret, s, isfloat);
|
||||
|
||||
/* We don't mind increasing width/depth/channels, but reducing them is
|
||||
* Very Bad. Only available if width, depth, channels are already fixed. */
|
||||
s = gst_structure_copy (s);
|
||||
if (!isfloat) {
|
||||
if (gst_structure_get_int (structure, "width", &width))
|
||||
set_structure_widths (s, width, 32);
|
||||
if (gst_structure_get_int (structure, "depth", &depth)) {
|
||||
if (depth == 32)
|
||||
gst_structure_set (s, "depth", G_TYPE_INT, 32, NULL);
|
||||
else
|
||||
gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, depth, 32, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (gst_structure_get_int (structure, "channels", &channels)) {
|
||||
if (channels == 8)
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, 8, NULL);
|
||||
else
|
||||
gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, channels, 8, NULL);
|
||||
}
|
||||
gst_caps_append_structure (ret, s);
|
||||
|
||||
/* Same, plus a float<->int conversion */
|
||||
append_with_other_format (ret, s, isfloat);
|
||||
|
||||
/* We'll reduce depth if we must... only for integer, since we can't do this
|
||||
* for float. We reduce as low as 16 bits; reducing to less than this is
|
||||
* even worse than dropping channels. We only do this if we haven't already
|
||||
* done the equivalent above. */
|
||||
if (!gst_structure_get_int (structure, "width", &width) || width > 16) {
|
||||
if (isfloat) {
|
||||
/* These are invalid widths/depths for float, but we don't actually use
|
||||
* them - we just pass it to append_with_other_format, which makes them
|
||||
* valid
|
||||
*/
|
||||
GstStructure *s2 = gst_structure_copy (s);
|
||||
|
||||
set_structure_widths (s2, 16, 32);
|
||||
gst_structure_set (s2, "depth", GST_TYPE_INT_RANGE, 16, 32, NULL);
|
||||
append_with_other_format (ret, s2, TRUE);
|
||||
gst_structure_free (s2);
|
||||
} else {
|
||||
s = gst_structure_copy (s);
|
||||
set_structure_widths (s, 16, 32);
|
||||
gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, 16, 32, NULL);
|
||||
gst_caps_append_structure (ret, s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Channel conversions to fewer channels is only done if needed - generally
|
||||
* it's very bad to drop channels entirely.
|
||||
*/
|
||||
s = gst_structure_copy (s);
|
||||
gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 8, NULL);
|
||||
gst_caps_append_structure (ret, s);
|
||||
|
||||
/* Same, plus a float<->int conversion */
|
||||
append_with_other_format (ret, s, isfloat);
|
||||
|
||||
/* And, finally, for integer only, we allow conversion to any width/depth we
|
||||
* support: this should be equivalent to our (non-float) template caps. (the
|
||||
* floating point case should be being handled just above) */
|
||||
s = gst_structure_copy (s);
|
||||
set_structure_widths (s, 8, 32);
|
||||
gst_structure_set (s, "depth", GST_TYPE_INT_RANGE, 1, 32, NULL);
|
||||
|
||||
if (isfloat) {
|
||||
append_with_other_format (ret, s, TRUE);
|
||||
gst_structure_free (s);
|
||||
} else
|
||||
gst_caps_append_structure (ret, s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue