audioconvert: Prefer output formats with the same depth or at least a higher depth

Enhance current code to prefer an exact match on sample depth if
possible. Also ignore GST_AUDIO_FORMAT_FLAG_UNPACK when checking
equality on the flags.
This commit is contained in:
Rasmus Rohde 2012-10-31 20:01:05 +01:00 committed by Sebastian Dröge
parent 5f44303925
commit c286f8ffa2
2 changed files with 84 additions and 8 deletions

View file

@ -442,6 +442,7 @@ gst_audio_convert_fixate_format (GstBaseTransform * base, GstStructure * ins,
const gchar *in_format;
const GValue *format;
const GstAudioFormatInfo *in_info, *out_info = NULL;
GstAudioFormatFlags in_flags, out_flags;
in_format = gst_structure_get_string (ins, "format");
if (!in_format)
@ -457,6 +458,9 @@ gst_audio_convert_fixate_format (GstBaseTransform * base, GstStructure * ins,
if (!in_info)
return;
in_flags = GST_AUDIO_FORMAT_INFO_FLAGS (in_info);
in_flags &= ~(GST_AUDIO_FORMAT_FLAG_UNPACK);
if (GST_VALUE_HOLDS_LIST (format)) {
gint i, len;
@ -467,22 +471,32 @@ gst_audio_convert_fixate_format (GstBaseTransform * base, GstStructure * ins,
val = gst_value_list_get_value (format, i);
if (G_VALUE_HOLDS_STRING (val)) {
const GstAudioFormatInfo *t_info;
fname = g_value_get_string (val);
out_info =
t_info =
gst_audio_format_get_info (gst_audio_format_from_string (fname));
if (!out_info)
if (!t_info)
continue;
/* accept input format */
if (strcmp (fname, in_format) == 0)
break;
out_flags = GST_AUDIO_FORMAT_INFO_FLAGS (t_info);
out_flags &= ~(GST_AUDIO_FORMAT_FLAG_UNPACK);
/* or another format without losing precision */
if ((GST_AUDIO_FORMAT_INFO_FLAGS (out_info) ==
GST_AUDIO_FORMAT_INFO_FLAGS (in_info)) &&
(GST_AUDIO_FORMAT_INFO_DEPTH (out_info) >=
GST_AUDIO_FORMAT_INFO_DEPTH (in_info)))
break;
if (in_flags == out_flags) {
if (GST_AUDIO_FORMAT_INFO_DEPTH (t_info) ==
GST_AUDIO_FORMAT_INFO_DEPTH (in_info)) {
/* exact match. We are done */
out_info = t_info;
break;
} else if ((GST_AUDIO_FORMAT_INFO_DEPTH (t_info) >=
GST_AUDIO_FORMAT_INFO_DEPTH (in_info))) {
/* match where we do not lose precision. This could
be ok, but keep searching for an exact match */
out_info = t_info;
}
}
}
out_info = NULL;
}
if (out_info)
gst_structure_set (outs, "format", G_TYPE_STRING,

View file

@ -1441,6 +1441,67 @@ GST_START_TEST (test_convert_undefined_multichannel)
GST_END_TEST;
#define SIMPLE_CAPS_TEMPLATE_STRING \
"audio/x-raw, " \
"format = (string) {S8, S16LE, S24LE, S32LE}, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, MAX ]"
static GstStaticPadTemplate simple_sinktemplate =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (SIMPLE_CAPS_TEMPLATE_STRING)
);
GST_START_TEST (test_preserve_width)
{
static const struct _test_formats
{
int width;
const gchar *outf;
} test_formats[] = { {
8, "S8"}, {
16, "S16LE"}, {
24, "S24LE"}, {
32, "S32LE"}, {
0, NULL}};
gint i;
GstStructure *structure;
GstElement *audioconvert;
GstCaps *incaps, *convert_outcaps;
audioconvert = gst_check_setup_element ("audioconvert");
mysrcpad = gst_check_setup_src_pad (audioconvert, &srctemplate);
mysinkpad = gst_check_setup_sink_pad (audioconvert, &simple_sinktemplate);
gst_pad_set_active (mysrcpad, TRUE);
gst_pad_set_active (mysinkpad, TRUE);
fail_unless (gst_element_set_state (audioconvert,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
for (i = 0; test_formats[i].width; i++) {
gint width = test_formats[i].width;
incaps = get_int_caps (1, G_BIG_ENDIAN, width, width, TRUE);
gst_pad_set_caps (mysrcpad, incaps);
convert_outcaps = gst_pad_get_current_caps (mysinkpad);
structure = gst_caps_get_structure (convert_outcaps, 0);
fail_unless_equals_string (gst_structure_get_string (structure, "format"),
test_formats[i].outf);
gst_caps_unref (convert_outcaps);
gst_caps_unref (incaps);
}
cleanup_audioconvert (audioconvert);
}
GST_END_TEST;
static Suite *
audioconvert_suite (void)
{
@ -1455,6 +1516,7 @@ audioconvert_suite (void)
tcase_add_test (tc_chain, test_multichannel_conversion);
tcase_add_test (tc_chain, test_caps_negotiation);
tcase_add_test (tc_chain, test_convert_undefined_multichannel);
tcase_add_test (tc_chain, test_preserve_width);
return s;
}