ext/cairo: pack gstcairo plugin in default
[platform/upstream/gst-plugins-good.git] / ext / wavpack / gstwavpackcommon.c
index 61c8add..a17c9b2 100644 (file)
+/* GStreamer Wavpack plugin
+ * Copyright (c) 2005 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (c) 1998 - 2005 Conifer Software
+ * Copyright (c) 2006 Sebastian Dröge <slomo@circular-chaos.org>
+ *
+ * gstwavpackcommon.c: common helper functions
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include "gstwavpackcommon.h"
 #include <string.h>
 
+#include <gst/gst.h>
+
+GST_DEBUG_CATEGORY_EXTERN (wavpack_debug);
+#define GST_CAT_DEFAULT wavpack_debug
+
 gboolean
 gst_wavpack_read_header (WavpackHeader * header, guint8 * buf)
 {
-  g_memmove (header, buf, sizeof (WavpackHeader));
-  little_endian_to_native (header, WavpackHeaderFormat);
+  memmove (header, buf, sizeof (WavpackHeader));
+
+  WavpackLittleEndianToNative (header, (char *) WavpackHeaderFormat);
+
+  return (memcmp (header->ckID, "wvpk", 4) == 0);
+}
+
+/* inspired by the original one in wavpack */
+gboolean
+gst_wavpack_read_metadata (GstWavpackMetadata * wpmd, guint8 * header_data,
+    guint8 ** p_data)
+{
+  WavpackHeader hdr;
+  guint8 *end;
+
+  gst_wavpack_read_header (&hdr, header_data);
+  end = header_data + hdr.ckSize + 8;
 
-  if (strncmp (header->ckID, "wvpk", 4))
+  if (end - *p_data < 2)
     return FALSE;
-  else
+
+  wpmd->id = GST_READ_UINT8 (*p_data);
+  wpmd->byte_length = 2 * (guint) GST_READ_UINT8 (*p_data + 1);
+
+  *p_data += 2;
+
+  if ((wpmd->id & ID_LARGE) == ID_LARGE) {
+    guint extra;
+
+    wpmd->id &= ~ID_LARGE;
+
+    if (end - *p_data < 2)
+      return FALSE;
+
+    extra = GST_READ_UINT16_LE (*p_data);
+    wpmd->byte_length += (extra << 9);
+    *p_data += 2;
+  }
+
+  if ((wpmd->id & ID_ODD_SIZE) == ID_ODD_SIZE) {
+    wpmd->id &= ~ID_ODD_SIZE;
+    --wpmd->byte_length;
+  }
+
+  if (wpmd->byte_length > 0) {
+    if (end - *p_data < wpmd->byte_length + (wpmd->byte_length & 1)) {
+      wpmd->data = NULL;
+      return FALSE;
+    }
+
+    wpmd->data = *p_data;
+    *p_data += wpmd->byte_length + (wpmd->byte_length & 1);
+  } else {
+    wpmd->data = NULL;
+  }
+
+  return TRUE;
+}
+
+gint
+gst_wavpack_get_default_channel_mask (gint nchannels)
+{
+  gint channel_mask = 0;
+
+  /* Set the default channel mask for the given number of channels.
+   * It's the same as for WAVE_FORMAT_EXTENDED:
+   * http://www.microsoft.com/whdc/device/audio/multichaud.mspx
+   */
+  switch (nchannels) {
+    case 11:
+      channel_mask |= 0x00400;
+      channel_mask |= 0x00200;
+    case 9:
+      channel_mask |= 0x00100;
+    case 8:
+      channel_mask |= 0x00080;
+      channel_mask |= 0x00040;
+    case 6:
+      channel_mask |= 0x00020;
+      channel_mask |= 0x00010;
+    case 4:
+      channel_mask |= 0x00008;
+    case 3:
+      channel_mask |= 0x00004;
+    case 2:
+      channel_mask |= 0x00002;
+      channel_mask |= 0x00001;
+      break;
+    case 1:
+      /* For mono use front center */
+      channel_mask |= 0x00004;
+      break;
+  }
+
+  return channel_mask;
+}
+
+static const struct
+{
+  const guint32 ms_mask;
+  const GstAudioChannelPosition gst_pos;
+} layout_mapping[] = {
+  {
+  0x00001, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, {
+  0x00002, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
+  0x00004, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
+  0x00008, GST_AUDIO_CHANNEL_POSITION_LFE1}, {
+  0x00010, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, {
+  0x00020, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
+  0x00040, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
+  0x00080, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
+  0x00100, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
+  0x00200, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, {
+  0x00400, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, {
+  0x00800, GST_AUDIO_CHANNEL_POSITION_TOP_CENTER}, {
+  0x01000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT}, {
+  0x02000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER}, {
+  0x04000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT}, {
+  0x08000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT}, {
+  0x10000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER}, {
+  0x20000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT}
+};
+
+#define MAX_CHANNEL_POSITIONS G_N_ELEMENTS (layout_mapping)
+
+gboolean
+gst_wavpack_get_channel_positions (gint num_channels, gint layout,
+    GstAudioChannelPosition * pos)
+{
+  gint i, p;
+
+  if (num_channels == 1 && layout == 0x00004) {
+    pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
     return TRUE;
+  }
+
+  p = 0;
+  for (i = 0; i < MAX_CHANNEL_POSITIONS; ++i) {
+    if ((layout & layout_mapping[i].ms_mask) != 0) {
+      if (p >= num_channels) {
+        GST_WARNING ("More bits set in the channel layout map than there "
+            "are channels! Broken file");
+        return FALSE;
+      }
+      if (layout_mapping[i].gst_pos == GST_AUDIO_CHANNEL_POSITION_INVALID) {
+        GST_WARNING ("Unsupported channel position (mask 0x%08x) in channel "
+            "layout map - ignoring those channels", layout_mapping[i].ms_mask);
+        /* what to do? just ignore it and let downstream deal with a channel
+         * layout that has INVALID positions in it for now ... */
+      }
+      pos[p] = layout_mapping[i].gst_pos;
+      ++p;
+    }
+  }
+
+  if (p != num_channels) {
+    GST_WARNING ("Only %d bits set in the channel layout map, but there are "
+        "supposed to be %d channels! Broken file", p, num_channels);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GstAudioChannelPosition *
+gst_wavpack_get_default_channel_positions (gint nchannels)
+{
+  GstAudioChannelPosition *pos = g_new (GstAudioChannelPosition, nchannels);
+  gint i;
+
+  if (nchannels == 1) {
+    pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
+    return pos;
+  }
+
+  for (i = 0; i < nchannels; i++)
+    pos[i] = layout_mapping[i].gst_pos;
+
+  return pos;
+}
+
+gint
+gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition * pos,
+    gint nchannels)
+{
+  gint channel_mask = 0;
+  gint i, j;
+
+  if (nchannels == 1 && pos[0] == GST_AUDIO_CHANNEL_POSITION_MONO) {
+    channel_mask = 0x00000004;
+    return channel_mask;
+  }
+
+  /* FIXME: not exactly efficient but otherwise we need an inverse
+   * mapping table too */
+  for (i = 0; i < nchannels; i++) {
+    for (j = 0; j < MAX_CHANNEL_POSITIONS; j++) {
+      if (pos[i] == layout_mapping[j].gst_pos) {
+        channel_mask |= layout_mapping[j].ms_mask;
+        break;
+      }
+    }
+  }
+
+  return channel_mask;
+}
+
+gboolean
+gst_wavpack_set_channel_mapping (GstAudioChannelPosition * pos, gint nchannels,
+    gint8 * channel_mapping)
+{
+  gint i, j;
+  gboolean ret = TRUE;
+
+  for (i = 0; i < nchannels; i++) {
+    for (j = 0; j < MAX_CHANNEL_POSITIONS; j++) {
+      if (pos[i] == layout_mapping[j].gst_pos) {
+        channel_mapping[i] = j;
+        ret &= (i == j);
+        break;
+      }
+    }
+  }
+
+  return !ret;
 }