Blame gst-libs/gst/audio/gstaudioiec61937.c

Packit 971217
/* GStreamer audio helper functions for IEC 61937 payloading
Packit 971217
 * (c) 2011 Intel Corporation
Packit 971217
 *     2011 Collabora Multimedia
Packit 971217
 *     2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:gstaudioiec61937
Packit 971217
 * @title: GstAudio IEC61937
Packit 971217
 * @short_description: Utility functions for IEC 61937 payloading
Packit 971217
 *
Packit 971217
 * This module contains some helper functions for encapsulating various
Packit 971217
 * audio formats in IEC 61937 headers and padding.
Packit 971217
 *
Packit 971217
 */
Packit 971217
Packit 971217
#ifdef HAVE_CONFIG_H
Packit 971217
#include "config.h"
Packit 971217
#endif
Packit 971217
Packit 971217
#include <string.h>
Packit 971217
Packit 971217
#include <gst/audio/audio.h>
Packit 971217
#include "gstaudioiec61937.h"
Packit 971217
Packit 971217
#define IEC61937_HEADER_SIZE      8
Packit 971217
#define IEC61937_PAYLOAD_SIZE_AC3 (1536 * 4)
Packit 971217
#define IEC61937_PAYLOAD_SIZE_EAC3 (6144 * 4)
Packit 971217
#define IEC61937_PAYLOAD_SIZE_AAC (1024 * 4)
Packit 971217
Packit 971217
static gint
Packit 971217
caps_get_int_field (const GstCaps * caps, const gchar * field)
Packit 971217
{
Packit 971217
  const GstStructure *st;
Packit 971217
  gint ret = 0;
Packit 971217
Packit 971217
  st = gst_caps_get_structure (caps, 0);
Packit 971217
  gst_structure_get_int (st, field, &ret;;
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static const gchar *
Packit 971217
caps_get_string_field (const GstCaps * caps, const gchar * field)
Packit 971217
{
Packit 971217
  const GstStructure *st = gst_caps_get_structure (caps, 0);
Packit 971217
  return gst_structure_get_string (st, field);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_audio_iec61937_frame_size:
Packit 971217
 * @spec: the ringbufer spec
Packit 971217
 *
Packit 971217
 * Calculated the size of the buffer expected by gst_audio_iec61937_payload() for
Packit 971217
 * payloading type from @spec.
Packit 971217
 *
Packit 971217
 * Returns: the size or 0 if the given @type is not supported or cannot be
Packit 971217
 * payloaded.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_audio_iec61937_frame_size (const GstAudioRingBufferSpec * spec)
Packit 971217
{
Packit 971217
  switch (spec->type) {
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
Packit 971217
      return IEC61937_PAYLOAD_SIZE_AC3;
Packit 971217
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
Packit 971217
      /* Check that the parser supports /some/ alignment. Need to be less
Packit 971217
       * strict about this at checking time since the alignment is dynamically
Packit 971217
       * set at the moment. */
Packit 971217
      if (caps_get_string_field (spec->caps, "alignment"))
Packit 971217
        return IEC61937_PAYLOAD_SIZE_EAC3;
Packit 971217
      else
Packit 971217
        return 0;
Packit 971217
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
Packit 971217
    {
Packit 971217
      gint dts_frame_size = caps_get_int_field (spec->caps, "frame-size");
Packit 971217
      gint iec_frame_size = caps_get_int_field (spec->caps, "block-size") * 4;
Packit 971217
Packit 971217
      /* Note: this will also (correctly) fail if either field is missing */
Packit 971217
      if (iec_frame_size >= (dts_frame_size + IEC61937_HEADER_SIZE))
Packit 971217
        return iec_frame_size;
Packit 971217
      else
Packit 971217
        return 0;
Packit 971217
    }
Packit 971217
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
Packit 971217
    {
Packit 971217
      int version, layer, channels, frames;
Packit 971217
Packit 971217
      version = caps_get_int_field (spec->caps, "mpegaudioversion");
Packit 971217
      layer = caps_get_int_field (spec->caps, "layer");
Packit 971217
      channels = caps_get_int_field (spec->caps, "channels");
Packit 971217
Packit 971217
      /* Bail out if we can't figure out either, if it's MPEG 2.5, or if it's
Packit 971217
       * MP3 with multichannel audio */
Packit 971217
      if (!version || !layer || version == 3 || channels > 2)
Packit 971217
        return 0;
Packit 971217
Packit 971217
      if (version == 1 && layer == 1)
Packit 971217
        frames = 384;
Packit 971217
      else if (version == 2 && layer == 1 && spec->info.rate <= 12000)
Packit 971217
        frames = 768;
Packit 971217
      else if (version == 2 && layer == 2 && spec->info.rate <= 12000)
Packit 971217
        frames = 2304;
Packit 971217
      else {
Packit 971217
        /* MPEG-1 layer 2,3, MPEG-2 with or without extension,
Packit 971217
         * MPEG-2 layer 3 low sample freq. */
Packit 971217
        frames = 1152;
Packit 971217
      }
Packit 971217
Packit 971217
      return frames * 4;
Packit 971217
    }
Packit 971217
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC:
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC:
Packit 971217
    {
Packit 971217
      return IEC61937_PAYLOAD_SIZE_AAC;
Packit 971217
    }
Packit 971217
Packit 971217
    default:
Packit 971217
      return 0;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_audio_iec61937_payload:
Packit 971217
 * @src: (array length=src_n): a buffer containing the data to payload
Packit 971217
 * @src_n: size of @src in bytes
Packit 971217
 * @dst: (array length=dst_n): the destination buffer to store the
Packit 971217
 *       payloaded contents in. Should not overlap with @src
Packit 971217
 * @dst_n: size of @dst in bytes
Packit 971217
 * @spec: the ringbufer spec for @src
Packit 971217
 * @endianness: the expected byte order of the payloaded data
Packit 971217
 *
Packit 971217
 * Payloads @src in the form specified by IEC 61937 for the type from @spec and
Packit 971217
 * stores the result in @dst. @src must contain exactly one frame of data and
Packit 971217
 * the frame is not checked for errors.
Packit 971217
 *
Packit 971217
 * Returns: transfer-full: %TRUE if the payloading was successful, %FALSE
Packit 971217
 * otherwise.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_audio_iec61937_payload (const guint8 * src, guint src_n, guint8 * dst,
Packit 971217
    guint dst_n, const GstAudioRingBufferSpec * spec, gint endianness)
Packit 971217
{
Packit 971217
  guint i, tmp;
Packit 971217
#if G_BYTE_ORDER == G_BIG_ENDIAN
Packit 971217
  guint8 zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, six = 6,
Packit 971217
      seven = 7;
Packit 971217
#else
Packit 971217
  /* We need to send the data byte-swapped */
Packit 971217
  guint8 zero = 1, one = 0, two = 3, three = 2, four = 5, five = 4, six = 7,
Packit 971217
      seven = 6;
Packit 971217
#endif
Packit 971217
Packit 971217
  g_return_val_if_fail (src != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (dst != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (src != dst, FALSE);
Packit 971217
  g_return_val_if_fail (dst_n >= gst_audio_iec61937_frame_size (spec), FALSE);
Packit 971217
Packit 971217
  if (dst_n < src_n + IEC61937_HEADER_SIZE)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  /* Pa, Pb */
Packit 971217
  dst[zero] = 0xF8;
Packit 971217
  dst[one] = 0x72;
Packit 971217
  dst[two] = 0x4E;
Packit 971217
  dst[three] = 0x1F;
Packit 971217
Packit 971217
  switch (spec->type) {
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
Packit 971217
    {
Packit 971217
      g_return_val_if_fail (src_n >= 6, FALSE);
Packit 971217
Packit 971217
      /* Pc: bit 13-15 - stream number (0)
Packit 971217
       *     bit 11-12 - reserved (0)
Packit 971217
       *     bit  8-10 - bsmod from AC3 frame */
Packit 971217
      dst[four] = src[5] & 0x7;
Packit 971217
      /* Pc: bit    7  - error bit (0)
Packit 971217
       *     bit  5-6  - subdata type (0)
Packit 971217
       *     bit  0-4  - data type (1) */
Packit 971217
      dst[five] = 1;
Packit 971217
      /* Pd: bit 15-0  - frame size in bits */
Packit 971217
      tmp = src_n * 8;
Packit 971217
      dst[six] = (guint8) (tmp >> 8);
Packit 971217
      dst[seven] = (guint8) (tmp & 0xff);
Packit 971217
Packit 971217
      break;
Packit 971217
    }
Packit 971217
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
Packit 971217
    {
Packit 971217
      if (g_str_equal (caps_get_string_field (spec->caps, "alignment"),
Packit 971217
              "iec61937"))
Packit 971217
        return FALSE;
Packit 971217
Packit 971217
      /* Pc: bit 13-15 - stream number (0)
Packit 971217
       *     bit 11-12 - reserved (0)
Packit 971217
       *     bit  8-10 - bsmod from E-AC3 frame if present */
Packit 971217
      /* FIXME: this works, but nicer if we can put in the actual bsmod */
Packit 971217
      dst[four] = 0;
Packit 971217
      /* Pc: bit    7  - error bit (0)
Packit 971217
       *     bit  5-6  - subdata type (0)
Packit 971217
       *     bit  0-4  - data type (21) */
Packit 971217
      dst[five] = 21;
Packit 971217
      /* Pd: bit 15-0  - frame size in bytes */
Packit 971217
      dst[six] = ((guint16) src_n) >> 8;
Packit 971217
      dst[seven] = ((guint16) src_n) & 0xff;
Packit 971217
Packit 971217
      break;
Packit 971217
    }
Packit 971217
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
Packit 971217
    {
Packit 971217
      int blocksize = caps_get_int_field (spec->caps, "block-size");
Packit 971217
Packit 971217
      g_return_val_if_fail (src_n != 0, FALSE);
Packit 971217
Packit 971217
      if (blocksize == 0)
Packit 971217
        return FALSE;
Packit 971217
Packit 971217
      /* Pc: bit 13-15 - stream number (0)
Packit 971217
       *     bit 11-12 - reserved (0)
Packit 971217
       *     bit  8-10 - for DTS type I-III (0) */
Packit 971217
      dst[four] = 0;
Packit 971217
      /* Pc: bit    7  - error bit (0)
Packit 971217
       *     bit  5-6  - reserved (0)
Packit 971217
       *     bit  0-4  - data type (11 = type I, 12 = type II,
Packit 971217
       *                            13 = type III) */
Packit 971217
      dst[five] = 11 + (blocksize / 1024);
Packit 971217
      /* Pd: bit 15-0  - frame size, in bits (for type I-III) */
Packit 971217
      tmp = src_n * 8;
Packit 971217
      dst[six] = ((guint16) tmp) >> 8;
Packit 971217
      dst[seven] = ((guint16) tmp) & 0xff;
Packit 971217
      break;
Packit 971217
    }
Packit 971217
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
Packit 971217
    {
Packit 971217
      int version, layer;
Packit 971217
Packit 971217
      version = caps_get_int_field (spec->caps, "mpegaudioversion");
Packit 971217
      layer = caps_get_int_field (spec->caps, "layer");
Packit 971217
Packit 971217
      g_return_val_if_fail (version > 0 && layer > 0, FALSE);
Packit 971217
Packit 971217
      /* NOTE: multichannel audio (MPEG-2) is not supported */
Packit 971217
Packit 971217
      /* Pc: bit 13-15 - stream number (0)
Packit 971217
       *     bit 11-12 - reserved (0)
Packit 971217
       *     bit  9-10 - 0 - no dynamic range control
Packit 971217
       *               - 2 - dynamic range control exists
Packit 971217
       *               - 1,3 - reserved
Packit 971217
       *     bit    8  - Normal (0) or Karaoke (1) mode */
Packit 971217
      dst[four] = 0;
Packit 971217
      /* Pc: bit    7  - error bit (0)
Packit 971217
       *     bit  5-6  - reserved (0)
Packit 971217
       *     bit  0-4  - data type (04 = MPEG 1, Layer 1
Packit 971217
       *                            05 = MPEG 1, Layer 2, 3 / MPEG 2, w/o ext.
Packit 971217
       *                            06 = MPEG 2, with extension
Packit 971217
       *                            08 - MPEG 2 LSF, Layer 1
Packit 971217
       *                            09 - MPEG 2 LSF, Layer 2
Packit 971217
       *                            10 - MPEG 2 LSF, Layer 3
Packit 971217
       *                 FIXME: we don't handle type 06 at the moment */
Packit 971217
      if (version == 1 && layer == 1)
Packit 971217
        dst[five] = 0x04;
Packit 971217
      else if ((version == 1 && (layer == 2 || layer == 3)) ||
Packit 971217
          (version == 2 && spec->info.rate >= 12000))
Packit 971217
        dst[five] = 0x05;
Packit 971217
      else if (version == 2 && layer == 1 && spec->info.rate < 12000)
Packit 971217
        dst[five] = 0x08;
Packit 971217
      else if (version == 2 && layer == 2 && spec->info.rate < 12000)
Packit 971217
        dst[five] = 0x09;
Packit 971217
      else if (version == 2 && layer == 3 && spec->info.rate < 12000)
Packit 971217
        dst[five] = 0x0A;
Packit 971217
      else
Packit 971217
        g_return_val_if_reached (FALSE);
Packit 971217
      /* Pd: bit 15-0  - frame size in bits */
Packit 971217
      dst[six] = ((guint16) src_n * 8) >> 8;
Packit 971217
      dst[seven] = ((guint16) src_n * 8) & 0xff;
Packit 971217
Packit 971217
      break;
Packit 971217
    }
Packit 971217
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC:
Packit 971217
      /* HACK. disguising MPEG4 AAC as MPEG2 AAC seems to work. */
Packit 971217
      /* TODO: set the right Pc,Pd for MPEG4 in accordance with IEC61937-6 */
Packit 971217
    case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC:
Packit 971217
    {
Packit 971217
      int num_rd_blks;
Packit 971217
Packit 971217
      g_return_val_if_fail (src_n >= 7, FALSE);
Packit 971217
      num_rd_blks = (src[6] & 0x03) + 1;
Packit 971217
Packit 971217
      /* Pc: bit 13-15 - stream number (0)
Packit 971217
       *     bit 11-12 - reserved (0)
Packit 971217
       *     bit  8-10 - reserved? (0) */
Packit 971217
      dst[four] = 0;
Packit 971217
      /* Pc: bit    7  - error bit (0)
Packit 971217
       *     bit  5-6  - reserved (0)
Packit 971217
       *     bit  0-4  - data type (07 = MPEG2 AAC ADTS
Packit 971217
       *                            19 = MPEG2 AAC ADTS half-rate LSF
Packit 971217
       *                            51 = MPEG2 AAC ADTS quater-rate LSF */
Packit 971217
      if (num_rd_blks == 1)
Packit 971217
        dst[five] = 0x07;
Packit 971217
      else if (num_rd_blks == 2)
Packit 971217
        dst[five] = 0x13;
Packit 971217
      else if (num_rd_blks == 4)
Packit 971217
        dst[five] = 0x33;
Packit 971217
      else
Packit 971217
        g_return_val_if_reached (FALSE);
Packit 971217
Packit 971217
      /* Pd: bit 15-0  - frame size in bits */
Packit 971217
      tmp = GST_ROUND_UP_2 (src_n) * 8;
Packit 971217
      dst[six] = (guint8) (tmp >> 8);
Packit 971217
      dst[seven] = (guint8) (tmp & 0xff);
Packit 971217
      break;
Packit 971217
    }
Packit 971217
Packit 971217
    default:
Packit 971217
      return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Copy the payload */
Packit 971217
  i = 8;
Packit 971217
Packit 971217
  if (G_BYTE_ORDER == endianness) {
Packit 971217
    memcpy (dst + i, src, src_n);
Packit 971217
  } else {
Packit 971217
    /* Byte-swapped again */
Packit 971217
    /* FIXME: orc-ify this */
Packit 971217
    for (tmp = 1; tmp < src_n; tmp += 2) {
Packit 971217
      dst[i + tmp - 1] = src[tmp];
Packit 971217
      dst[i + tmp] = src[tmp - 1];
Packit 971217
    }
Packit 971217
    /* Do we have 1 byte remaining? */
Packit 971217
    if (src_n % 2) {
Packit 971217
      dst[i + src_n - 1] = 0;
Packit 971217
      dst[i + src_n] = src[src_n - 1];
Packit 971217
      i++;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  i += src_n;
Packit 971217
Packit 971217
  /* Zero the rest */
Packit 971217
  memset (dst + i, 0, dst_n - i);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}