diff --git a/docs/libs/gst-plugins-base-libs-docs.sgml b/docs/libs/gst-plugins-base-libs-docs.sgml index b7b61a70a7..54df8dba20 100644 --- a/docs/libs/gst-plugins-base-libs-docs.sgml +++ b/docs/libs/gst-plugins-base-libs-docs.sgml @@ -52,6 +52,7 @@ + diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt index 41235a09ef..15bd466856 100644 --- a/docs/libs/gst-plugins-base-libs-sections.txt +++ b/docs/libs/gst-plugins-base-libs-sections.txt @@ -317,6 +317,13 @@ gst_ring_buffer_debug_spec_buff gst_ring_buffer_debug_spec_caps +
+gstaudioiec61937 +gst/audio/gstaudioiec61937.h +gst_audio_iec61937_frame_size +gst_audio_iec61937_payload +
+ # cdda diff --git a/gst-libs/gst/audio/Makefile.am b/gst-libs/gst/audio/Makefile.am index e531e73526..7977f89806 100644 --- a/gst-libs/gst/audio/Makefile.am +++ b/gst-libs/gst/audio/Makefile.am @@ -26,7 +26,8 @@ libgstaudio_@GST_MAJORMINOR@_la_SOURCES = \ gstbaseaudiosrc.c \ gstaudiofilter.c \ gstaudiosink.c \ - gstaudiosrc.c + gstaudiosrc.c \ + gstaudioiec61937.c nodist_libgstaudio_@GST_MAJORMINOR@_la_SOURCES = $(built_sources) $(built_headers) libgstaudio_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/audio @@ -40,7 +41,8 @@ libgstaudio_@GST_MAJORMINOR@include_HEADERS = \ gstaudiosink.h \ gstaudiosrc.h \ mixerutils.h \ - multichannel.h + multichannel.h \ + gstaudioiec61937.h nodist_libgstaudio_@GST_MAJORMINOR@include_HEADERS = \ audio-enumtypes.h diff --git a/gst-libs/gst/audio/gstaudioiec61937.c b/gst-libs/gst/audio/gstaudioiec61937.c new file mode 100644 index 0000000000..caf150d2e8 --- /dev/null +++ b/gst-libs/gst/audio/gstaudioiec61937.c @@ -0,0 +1,319 @@ +/* GStreamer audio helper functions for IEC 61937 payloading + * (c) 2011 Intel Corporation + * 2011 Collabora Multimedia + * 2011 Arun Raghavan + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:gstaudioiec61937 + * @short_description: Utility functions for IEC 61937 payloading + * + * This module contains some helper functions for encapsulating various + * audio formats in IEC 61937 headers and padding. + * + * Since: 0.10.35 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "gstaudioiec61937.h" + +#define IEC61937_HEADER_SIZE 8 +#define IEC61937_PAYLOAD_SIZE_AC3 (1536 * 4) +#define IEC61937_PAYLOAD_SIZE_EAC3 (6144 * 4) + +static gint +caps_get_int_field (const GstCaps * caps, const gchar * field) +{ + const GstStructure *st; + gint ret = 0; + + st = gst_caps_get_structure (caps, 0); + gst_structure_get_int (st, field, &ret); + + return ret; +} + +static const gchar * +caps_get_string_field (const GstCaps * caps, const gchar * field) +{ + const GstStructure *st = gst_caps_get_structure (caps, 0); + return gst_structure_get_string (st, field); +} + +/** + * gst_audio_iec61937_frame_size + * @type: the type of data to be payloaded as a #GstBufferFormatType + * + * Returns 0 if the given @type is not supported or cannot be payloaded, else + * returns the size of the buffer expected by gst_audio_iec61937_payload() for + * payloading @type. + * + * Since: 0.10.35 + */ +guint +gst_audio_iec61937_frame_size (const GstRingBufferSpec * spec) +{ + switch (spec->type) { + case GST_BUFTYPE_AC3: + return IEC61937_PAYLOAD_SIZE_AC3; + + case GST_BUFTYPE_EAC3: + /* Check that the parser supports /some/ alignment. Need to be less + * strict about this at checking time since the alignment is dynamically + * set at the moment. */ + if (caps_get_string_field (spec->caps, "alignment")) + return IEC61937_PAYLOAD_SIZE_EAC3; + else + return 0; + + case GST_BUFTYPE_DTS: + { + gint dts_frame_size = caps_get_int_field (spec->caps, "frame-size"); + gint iec_frame_size = caps_get_int_field (spec->caps, "block-size") * 4; + + /* Note: this will also (correctly) fail if either field is missing */ + if (iec_frame_size >= (dts_frame_size + IEC61937_HEADER_SIZE)) + return iec_frame_size; + else + return 0; + } + + case GST_BUFTYPE_MPEG: + { + int version, layer, channels, frames; + + version = caps_get_int_field (spec->caps, "mpegaudioversion"); + layer = caps_get_int_field (spec->caps, "layer"); + channels = caps_get_int_field (spec->caps, "channels"); + + /* Bail out if we can't figure out either, if it's MPEG 2.5, or if it's + * MP3 with multichannel audio */ + if (!version || !layer || version == 3 || channels > 2) + return 0; + + if (version == 1 && layer == 1) + frames = 384; + else if (version == 2 && layer == 1 && spec->rate < 32000) + frames = 768; + else if (version == 2 && layer == 1 && spec->rate < 32000) + frames = 2304; + else + frames = 1152; + + return frames * 4; + } + + default: + return 0; + } +} + +/** + * gst_audio_iec61937_payload + * @src: a buffer containing the data to payload + * @src_n: size of @src in bytes + * @dst: the destination buffer to store the payloaded contents in. Should not + * overlap with @src + * @dst_n: size of @dst in bytes + * @type: the type of data in @src + * + * Payloads @src in the form specified by IEC 61937 for @type and stores + * the result in @dst. @src must contain exactly one frame of data and the + * frame is not checked for errors. + * + * Returns: transfer-full: #TRUE if the payloading was successful, #FALSE + * otherwise. + * + * Since: 0.10.35 + */ +gboolean +gst_audio_iec61937_payload (const guint8 * src, guint src_n, guint8 * dst, + guint dst_n, const GstRingBufferSpec * spec) +{ + guint i, tmp; +#if G_BYTE_ORDER == G_BIG_ENDIAN + guint8 zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, six = 6, + seven = 7; +#else + /* We need to send the data byte-swapped */ + guint8 zero = 1, one = 0, two = 3, three = 2, four = 5, five = 4, six = 7, + seven = 6; +#endif + + g_return_val_if_fail (src != NULL, FALSE); + g_return_val_if_fail (dst != NULL, FALSE); + g_return_val_if_fail (src != dst, FALSE); + g_return_val_if_fail (dst_n >= gst_audio_iec61937_frame_size (spec), FALSE); + + if (dst_n < src_n + IEC61937_HEADER_SIZE) + return FALSE; + + /* Pa, Pb */ + dst[zero] = 0xF8; + dst[one] = 0x72; + dst[two] = 0x4E; + dst[three] = 0x1F; + + switch (spec->type) { + case GST_BUFTYPE_AC3: + { + g_return_val_if_fail (src_n >= 6, FALSE); + + /* Pc: bit 13-15 - stream number (0) + * bit 11-12 - reserved (0) + * bit 8-10 - bsmod from AC3 frame */ + dst[four] = src[5] & 0x7; + /* Pc: bit 7 - error bit (0) + * bit 5-6 - subdata type (0) + * bit 0-4 - data type (1) */ + dst[five] = 1; + /* Pd: bit 15-0 - frame size in bits */ + tmp = src_n * 8; + dst[six] = (guint8) (tmp >> 8); + dst[seven] = (guint8) (tmp & 0xff); + + break; + } + + case GST_BUFTYPE_EAC3: + { + if (g_str_equal (caps_get_string_field (spec->caps, "alignment"), + "iec61937")) + return FALSE; + + /* Pc: bit 13-15 - stream number (0) + * bit 11-12 - reserved (0) + * bit 8-10 - bsmod from E-AC3 frame if present */ + /* FIXME: this works, but nicer if we can put in the actual bsmod */ + dst[four] = 0; + /* Pc: bit 7 - error bit (0) + * bit 5-6 - subdata type (0) + * bit 0-4 - data type (21) */ + dst[five] = 21; + /* Pd: bit 15-0 - frame size in bytes */ + dst[six] = ((guint16) src_n) >> 8; + dst[seven] = ((guint16) src_n) & 0xff; + + break; + } + + case GST_BUFTYPE_DTS: + { + int blocksize = caps_get_int_field (spec->caps, "block-size"); + + g_return_val_if_fail (src_n != 0, FALSE); + + if (blocksize == 0) + return FALSE; + + /* Pc: bit 13-15 - stream number (0) + * bit 11-12 - reserved (0) + * bit 8-10 - for DTS type I-III (0) */ + dst[four] = 0; + /* Pc: bit 7 - error bit (0) + * bit 5-6 - reserved (0) + * bit 0-4 - data type (11 = type I, 12 = type II, + * 13 = type III) */ + dst[five] = 11 + (blocksize / 1024); + /* Pd: bit 15-0 - frame size in bytes */ + dst[six] = ((guint16) src_n) >> 8; + dst[seven] = ((guint16) src_n) & 0xff; + break; + } + + case GST_BUFTYPE_MPEG: + { + int version, layer; + + version = caps_get_int_field (spec->caps, "mpegaudioversion"); + layer = caps_get_int_field (spec->caps, "layer"); + + g_return_val_if_fail (version > 0 && layer > 0, FALSE); + + /* NOTE: multichannel audio (MPEG-2) is not supported */ + + /* Pc: bit 13-15 - stream number (0) + * bit 11-12 - reserved (0) + * bit 9-10 - 0 - no dynamic range control + * - 2 - dynamic range control exists + * - 1,3 - reserved + * bit 8 - Normal (0) or Karaoke (1) mode */ + dst[four] = 0; + /* Pc: bit 7 - error bit (0) + * bit 5-6 - reserved (0) + * bit 0-4 - data type (04 = MPEG 1, Layer 1 + * 05 = MPEG 1, Layer 2, 3 / MPEG 2, w/o ext. + * 06 = MPEG 2, with extension + * 08 - MPEG 2 LSF, Layer 1 + * 09 - MPEG 2 LSF, Layer 2 + * 10 - MPEG 2 LSF, Layer 3 */ + if (version == 1 && layer == 1) + dst[five] = 0x04; + else if ((version == 1 && (layer == 2 || layer == 3)) || + (version == 2 && spec->rate >= 32000)) + dst[five] = 0x05; + else if (version == 2 && layer == 1 && spec->rate < 32000) + dst[five] = 0x08; + else if (version == 2 && layer == 2 && spec->rate < 32000) + dst[five] = 0x09; + else if (version == 2 && layer == 3 && spec->rate < 32000) + dst[five] = 0x0A; + else + g_return_val_if_reached (FALSE); + /* Pd: bit 15-0 - frame size in bits */ + dst[six] = ((guint16) src_n * 8) >> 8; + dst[seven] = ((guint16) src_n * 8) & 0xff; + + break; + } + + default: + return FALSE; + } + + /* Copy the payload */ + i = 8; + +#if G_BYTE_ORDER == G_BIG_ENDIAN + memcpy (dst + i, src, src_n); +#else + /* Byte-swapped again */ + /* FIXME: orc-ify this */ + for (tmp = 1; tmp < src_n; tmp += 2) { + dst[i + tmp - 1] = src[tmp]; + dst[i + tmp] = src[tmp - 1]; + } + /* Do we have 1 byte remaining? */ + if (src_n % 2) { + dst[i + src_n - 1] = 0; + dst[i + src_n] = src[src_n - 1]; + i++; + } +#endif + + i += src_n; + + /* Zero the rest */ + memset (dst + i, 0, dst_n - i); + + return TRUE; +} diff --git a/gst-libs/gst/audio/gstaudioiec61937.h b/gst-libs/gst/audio/gstaudioiec61937.h new file mode 100644 index 0000000000..52da245870 --- /dev/null +++ b/gst-libs/gst/audio/gstaudioiec61937.h @@ -0,0 +1,38 @@ +/* GStreamer audio helper functions for IEC 61937 payloading + * (c) 2011 Intel Corporation + * 2011 Collabora Multimedia + * 2011 Arun Raghavan + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:gstaudioiec61937 + * @short_description: Utility functions for IEC 61937 payloading + * + * This module contains some helper functions for encapsulating various + * audio formats in IEC 61937 headers and padding. + */ + +#ifndef __GST_AUDIO_IEC61937_H__ +#define __GST_AUDIO_IEC61937_H__ + +#include + +guint gst_audio_iec61937_frame_size (const GstRingBufferSpec * spec); +gboolean gst_audio_iec61937_payload (const guint8 * src, guint src_n, + guint8 * dst, guint dst_n, const GstRingBufferSpec * spec); + +#endif /* __GST_AUDIO_IEC61937_H__ */