aiffparse: fix negotiation errors with multi-channel files
authorTim-Philipp Müller <tim@centricular.com>
Thu, 7 Jan 2016 18:26:26 +0000 (18:26 +0000)
committerTim-Philipp Müller <tim@centricular.com>
Sun, 21 Feb 2016 12:20:10 +0000 (12:20 +0000)
Set fallback channel layout on files with more than two
channels. Not clear where to retrieve the real layout from
or what the default layout is for AIFF files, the spec
only seems to specify some layout for up to 6 channels
and the file in question doesn't have a CHAN chunk.

https://bugzilla.gnome.org/show_bug.cgi?id=676425

gst/aiff/aiffparse.c

index 7ca19c6..5600a7e 100644 (file)
@@ -816,11 +816,14 @@ too_small:
 
 }
 
+#define _P(pos) (G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_ ##pos)
+
 static GstCaps *
 gst_aiff_parse_create_caps (GstAiffParse * aiff)
 {
   GstCaps *caps = NULL;
   const gchar *format = NULL;
+  guint64 channel_mask;
 
   if (aiff->floating_point) {
     if (aiff->endianness == G_BIG_ENDIAN) {
@@ -858,6 +861,44 @@ gst_aiff_parse_create_caps (GstAiffParse * aiff)
         "rate", G_TYPE_INT, aiff->rate, NULL);
   }
 
+  if (aiff->channels > 2) {
+    GST_FIXME_OBJECT (aiff, "using fallback channel layout for %d channels",
+        aiff->channels);
+
+    /* based on AIFF-1.3.pdf */
+    switch (aiff->channels) {
+      case 1:
+        channel_mask = 0;
+        break;
+      case 2:
+        channel_mask = _P (FRONT_LEFT) | _P (FRONT_RIGHT);
+        break;
+      case 3:
+        channel_mask = _P (FRONT_LEFT) | _P (FRONT_RIGHT) | _P (FRONT_CENTER);
+        break;
+      case 4:
+        /* lists both this and 'quad' but doesn't say how to distinguish the two */
+        channel_mask =
+            _P (FRONT_LEFT) | _P (FRONT_RIGHT) | _P (REAR_LEFT) |
+            _P (REAR_RIGHT);
+        break;
+      case 6:
+        channel_mask =
+            _P (FRONT_LEFT) | _P (FRONT_LEFT_OF_CENTER) | _P (FRONT_CENTER) |
+            _P (FRONT_RIGHT) | _P (FRONT_RIGHT_OF_CENTER) | _P (LFE1);
+        break;
+      default:
+        channel_mask = gst_audio_channel_get_fallback_mask (aiff->channels);
+        break;
+    }
+
+
+    if (channel_mask != 0) {
+      gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
+          NULL);
+    }
+  }
+
   GST_DEBUG_OBJECT (aiff, "Created caps: %" GST_PTR_FORMAT, caps);
 
   return caps;
@@ -1050,6 +1091,11 @@ gst_aiff_parse_stream_headers (GstAiffParse * aiff)
         }
         break;
       }
+      case GST_MAKE_FOURCC ('C', 'H', 'A', 'N'):{
+        GST_FIXME_OBJECT (aiff, "Handle CHAN chunk with channel layouts");
+        gst_aiff_parse_ignore_chunk (aiff, tag, size);
+        break;
+      }
       default:
         gst_aiff_parse_ignore_chunk (aiff, tag, size);
     }