audioconvert: Prefer output formats with the same depth or at least a higher depth
authorRasmus Rohde <rohde@duff.dk>
Wed, 31 Oct 2012 19:01:05 +0000 (20:01 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 1 Nov 2012 13:29:43 +0000 (14:29 +0100)
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.

gst/audioconvert/gstaudioconvert.c
tests/check/elements/audioconvert.c

index e7a1f1d..67ee317 100644 (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,
index 4e28c0d..47ffb0b 100644 (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;
 }