• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer audio helper functions for IEC 61937 payloading
2  * (c) 2011 Intel Corporation
3  *     2011 Collabora Multimedia
4  *     2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 /**
23  * SECTION:gstaudioiec61937
24  * @title: GstAudio IEC61937
25  * @short_description: Utility functions for IEC 61937 payloading
26  *
27  * This module contains some helper functions for encapsulating various
28  * audio formats in IEC 61937 headers and padding.
29  *
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #include <string.h>
37 
38 #include <gst/audio/audio.h>
39 #include "gstaudioiec61937.h"
40 
41 #define IEC61937_HEADER_SIZE      8
42 #define IEC61937_PAYLOAD_SIZE_AC3 (1536 * 4)
43 #define IEC61937_PAYLOAD_SIZE_EAC3 (6144 * 4)
44 #define IEC61937_PAYLOAD_SIZE_AAC (1024 * 4)
45 
46 static gint
caps_get_int_field(const GstCaps * caps,const gchar * field)47 caps_get_int_field (const GstCaps * caps, const gchar * field)
48 {
49   const GstStructure *st;
50   gint ret = 0;
51 
52   st = gst_caps_get_structure (caps, 0);
53   gst_structure_get_int (st, field, &ret);
54 
55   return ret;
56 }
57 
58 static const gchar *
caps_get_string_field(const GstCaps * caps,const gchar * field)59 caps_get_string_field (const GstCaps * caps, const gchar * field)
60 {
61   const GstStructure *st = gst_caps_get_structure (caps, 0);
62   return gst_structure_get_string (st, field);
63 }
64 
65 /**
66  * gst_audio_iec61937_frame_size:
67  * @spec: the ringbufer spec
68  *
69  * Calculated the size of the buffer expected by gst_audio_iec61937_payload() for
70  * payloading type from @spec.
71  *
72  * Returns: the size or 0 if the given @type is not supported or cannot be
73  * payloaded.
74  */
75 guint
gst_audio_iec61937_frame_size(const GstAudioRingBufferSpec * spec)76 gst_audio_iec61937_frame_size (const GstAudioRingBufferSpec * spec)
77 {
78   switch (spec->type) {
79     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
80       return IEC61937_PAYLOAD_SIZE_AC3;
81 
82     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
83       /* Check that the parser supports /some/ alignment. Need to be less
84        * strict about this at checking time since the alignment is dynamically
85        * set at the moment. */
86       if (caps_get_string_field (spec->caps, "alignment"))
87         return IEC61937_PAYLOAD_SIZE_EAC3;
88       else
89         return 0;
90 
91     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
92     {
93       gint dts_frame_size = caps_get_int_field (spec->caps, "frame-size");
94       gint iec_frame_size = caps_get_int_field (spec->caps, "block-size") * 4;
95 
96       /* Note: this will also (correctly) fail if either field is missing */
97       if (iec_frame_size >= (dts_frame_size + IEC61937_HEADER_SIZE))
98         return iec_frame_size;
99       else
100         return 0;
101     }
102 
103     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
104     {
105       int version, layer, channels, frames;
106 
107       version = caps_get_int_field (spec->caps, "mpegaudioversion");
108       layer = caps_get_int_field (spec->caps, "layer");
109       channels = caps_get_int_field (spec->caps, "channels");
110 
111       /* Bail out if we can't figure out either, if it's MPEG 2.5, or if it's
112        * MP3 with multichannel audio */
113       if (!version || !layer || version == 3 || channels > 2)
114         return 0;
115 
116       if (version == 1 && layer == 1)
117         frames = 384;
118       else if (version == 2 && layer == 1 && spec->info.rate <= 12000)
119         frames = 768;
120       else if (version == 2 && layer == 2 && spec->info.rate <= 12000)
121         frames = 2304;
122       else {
123         /* MPEG-1 layer 2,3, MPEG-2 with or without extension,
124          * MPEG-2 layer 3 low sample freq. */
125         frames = 1152;
126       }
127 
128       return frames * 4;
129     }
130 
131     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC:
132     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC:
133     {
134       return IEC61937_PAYLOAD_SIZE_AAC;
135     }
136 
137     default:
138       return 0;
139   }
140 }
141 
142 /**
143  * gst_audio_iec61937_payload:
144  * @src: (array length=src_n): a buffer containing the data to payload
145  * @src_n: size of @src in bytes
146  * @dst: (array length=dst_n): the destination buffer to store the
147  *       payloaded contents in. Should not overlap with @src
148  * @dst_n: size of @dst in bytes
149  * @spec: the ringbufer spec for @src
150  * @endianness: the expected byte order of the payloaded data
151  *
152  * Payloads @src in the form specified by IEC 61937 for the type from @spec and
153  * stores the result in @dst. @src must contain exactly one frame of data and
154  * the frame is not checked for errors.
155  *
156  * Returns: transfer-full: %TRUE if the payloading was successful, %FALSE
157  * otherwise.
158  */
159 gboolean
gst_audio_iec61937_payload(const guint8 * src,guint src_n,guint8 * dst,guint dst_n,const GstAudioRingBufferSpec * spec,gint endianness)160 gst_audio_iec61937_payload (const guint8 * src, guint src_n, guint8 * dst,
161     guint dst_n, const GstAudioRingBufferSpec * spec, gint endianness)
162 {
163   guint i, tmp;
164 #if G_BYTE_ORDER == G_BIG_ENDIAN
165   guint8 zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, six = 6,
166       seven = 7;
167 #else
168   /* We need to send the data byte-swapped */
169   guint8 zero = 1, one = 0, two = 3, three = 2, four = 5, five = 4, six = 7,
170       seven = 6;
171 #endif
172 
173   g_return_val_if_fail (src != NULL, FALSE);
174   g_return_val_if_fail (dst != NULL, FALSE);
175   g_return_val_if_fail (src != dst, FALSE);
176   g_return_val_if_fail (dst_n >= gst_audio_iec61937_frame_size (spec), FALSE);
177 
178   if (dst_n < src_n + IEC61937_HEADER_SIZE)
179     return FALSE;
180 
181   /* Pa, Pb */
182   dst[zero] = 0xF8;
183   dst[one] = 0x72;
184   dst[two] = 0x4E;
185   dst[three] = 0x1F;
186 
187   switch (spec->type) {
188     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3:
189     {
190       g_return_val_if_fail (src_n >= 6, FALSE);
191 
192       /* Pc: bit 13-15 - stream number (0)
193        *     bit 11-12 - reserved (0)
194        *     bit  8-10 - bsmod from AC3 frame */
195       dst[four] = src[5] & 0x7;
196       /* Pc: bit    7  - error bit (0)
197        *     bit  5-6  - subdata type (0)
198        *     bit  0-4  - data type (1) */
199       dst[five] = 1;
200       /* Pd: bit 15-0  - frame size in bits */
201       tmp = src_n * 8;
202       dst[six] = (guint8) (tmp >> 8);
203       dst[seven] = (guint8) (tmp & 0xff);
204 
205       break;
206     }
207 
208     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3:
209     {
210       if (g_str_equal (caps_get_string_field (spec->caps, "alignment"),
211               "iec61937"))
212         return FALSE;
213 
214       /* Pc: bit 13-15 - stream number (0)
215        *     bit 11-12 - reserved (0)
216        *     bit  8-10 - bsmod from E-AC3 frame if present */
217       /* FIXME: this works, but nicer if we can put in the actual bsmod */
218       dst[four] = 0;
219       /* Pc: bit    7  - error bit (0)
220        *     bit  5-6  - subdata type (0)
221        *     bit  0-4  - data type (21) */
222       dst[five] = 21;
223       /* Pd: bit 15-0  - frame size in bytes */
224       dst[six] = ((guint16) src_n) >> 8;
225       dst[seven] = ((guint16) src_n) & 0xff;
226 
227       break;
228     }
229 
230     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS:
231     {
232       int blocksize = caps_get_int_field (spec->caps, "block-size");
233 
234       g_return_val_if_fail (src_n != 0, FALSE);
235 
236       if (blocksize == 0)
237         return FALSE;
238 
239       /* Pc: bit 13-15 - stream number (0)
240        *     bit 11-12 - reserved (0)
241        *     bit  8-10 - for DTS type I-III (0) */
242       dst[four] = 0;
243       /* Pc: bit    7  - error bit (0)
244        *     bit  5-6  - reserved (0)
245        *     bit  0-4  - data type (11 = type I, 12 = type II,
246        *                            13 = type III) */
247       dst[five] = 11 + (blocksize / 1024);
248       /* Pd: bit 15-0  - frame size, in bits (for type I-III) */
249       tmp = src_n * 8;
250       dst[six] = ((guint16) tmp) >> 8;
251       dst[seven] = ((guint16) tmp) & 0xff;
252       break;
253     }
254 
255     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG:
256     {
257       int version, layer;
258 
259       version = caps_get_int_field (spec->caps, "mpegaudioversion");
260       layer = caps_get_int_field (spec->caps, "layer");
261 
262       g_return_val_if_fail (version > 0 && layer > 0, FALSE);
263 
264       /* NOTE: multichannel audio (MPEG-2) is not supported */
265 
266       /* Pc: bit 13-15 - stream number (0)
267        *     bit 11-12 - reserved (0)
268        *     bit  9-10 - 0 - no dynamic range control
269        *               - 2 - dynamic range control exists
270        *               - 1,3 - reserved
271        *     bit    8  - Normal (0) or Karaoke (1) mode */
272       dst[four] = 0;
273       /* Pc: bit    7  - error bit (0)
274        *     bit  5-6  - reserved (0)
275        *     bit  0-4  - data type (04 = MPEG 1, Layer 1
276        *                            05 = MPEG 1, Layer 2, 3 / MPEG 2, w/o ext.
277        *                            06 = MPEG 2, with extension
278        *                            08 - MPEG 2 LSF, Layer 1
279        *                            09 - MPEG 2 LSF, Layer 2
280        *                            10 - MPEG 2 LSF, Layer 3
281        *                 FIXME: we don't handle type 06 at the moment */
282       if (version == 1 && layer == 1)
283         dst[five] = 0x04;
284       else if ((version == 1 && (layer == 2 || layer == 3)) ||
285           (version == 2 && spec->info.rate >= 12000))
286         dst[five] = 0x05;
287       else if (version == 2 && layer == 1 && spec->info.rate < 12000)
288         dst[five] = 0x08;
289       else if (version == 2 && layer == 2 && spec->info.rate < 12000)
290         dst[five] = 0x09;
291       else if (version == 2 && layer == 3 && spec->info.rate < 12000)
292         dst[five] = 0x0A;
293       else
294         g_return_val_if_reached (FALSE);
295       /* Pd: bit 15-0  - frame size in bits */
296       dst[six] = ((guint16) src_n * 8) >> 8;
297       dst[seven] = ((guint16) src_n * 8) & 0xff;
298 
299       break;
300     }
301 
302     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC:
303       /* HACK. disguising MPEG4 AAC as MPEG2 AAC seems to work. */
304       /* TODO: set the right Pc,Pd for MPEG4 in accordance with IEC61937-6 */
305     case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC:
306     {
307       int num_rd_blks;
308 
309       g_return_val_if_fail (src_n >= 7, FALSE);
310       num_rd_blks = (src[6] & 0x03) + 1;
311 
312       /* Pc: bit 13-15 - stream number (0)
313        *     bit 11-12 - reserved (0)
314        *     bit  8-10 - reserved? (0) */
315       dst[four] = 0;
316       /* Pc: bit    7  - error bit (0)
317        *     bit  5-6  - reserved (0)
318        *     bit  0-4  - data type (07 = MPEG2 AAC ADTS
319        *                            19 = MPEG2 AAC ADTS half-rate LSF
320        *                            51 = MPEG2 AAC ADTS quater-rate LSF */
321       if (num_rd_blks == 1)
322         dst[five] = 0x07;
323       else if (num_rd_blks == 2)
324         dst[five] = 0x13;
325       else if (num_rd_blks == 4)
326         dst[five] = 0x33;
327       else
328         g_return_val_if_reached (FALSE);
329 
330       /* Pd: bit 15-0  - frame size in bits */
331       tmp = GST_ROUND_UP_2 (src_n) * 8;
332       dst[six] = (guint8) (tmp >> 8);
333       dst[seven] = (guint8) (tmp & 0xff);
334       break;
335     }
336 
337     default:
338       return FALSE;
339   }
340 
341   /* Copy the payload */
342   i = 8;
343 
344   if (G_BYTE_ORDER == endianness) {
345     memcpy (dst + i, src, src_n);
346   } else {
347     /* Byte-swapped again */
348     /* FIXME: orc-ify this */
349     for (tmp = 1; tmp < src_n; tmp += 2) {
350       dst[i + tmp - 1] = src[tmp];
351       dst[i + tmp] = src[tmp - 1];
352     }
353     /* Do we have 1 byte remaining? */
354     if (src_n % 2) {
355       dst[i + src_n - 1] = 0;
356       dst[i + src_n] = src[src_n - 1];
357       i++;
358     }
359   }
360 
361   i += src_n;
362 
363   /* Zero the rest */
364   memset (dst + i, 0, dst_n - i);
365 
366   return TRUE;
367 }
368