Merging gst-plugins-ugly
[platform/upstream/gstreamer.git] / gst / realmedia / rmutils.c
1 /* GStreamer RealMedia utility functions
2  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <string.h>
25 #include "rmutils.h"
26
27 gchar *
28 gst_rm_utils_read_string8 (const guint8 * data, guint datalen,
29     guint * p_total_len)
30 {
31   gint length;
32
33   if (p_total_len)
34     *p_total_len = 0;
35
36   if (datalen < 1)
37     return NULL;
38
39   length = GST_READ_UINT8 (data);
40   if (datalen < (1 + length))
41     return NULL;
42
43   if (p_total_len)
44     *p_total_len = 1 + length;
45
46   return g_strndup ((gchar *) data + 1, length);
47 }
48
49 gchar *
50 gst_rm_utils_read_string16 (const guint8 * data, guint datalen,
51     guint * p_total_len)
52 {
53   gint length;
54
55   if (p_total_len)
56     *p_total_len = 0;
57
58   if (datalen < 2)
59     return NULL;
60
61   length = GST_READ_UINT16_BE (data);
62   if (datalen < (2 + length))
63     return NULL;
64
65   if (p_total_len)
66     *p_total_len = 2 + length;
67
68   return g_strndup ((gchar *) data + 2, length);
69 }
70
71 GstTagList *
72 gst_rm_utils_read_tags (const guint8 * data, guint datalen,
73     GstRmUtilsStringReadFunc read_string_func)
74 {
75   const gchar *gst_tags[] = { GST_TAG_TITLE, GST_TAG_ARTIST,
76     GST_TAG_COPYRIGHT, GST_TAG_COMMENT
77   };
78   GstTagList *tags;
79   guint i;
80
81   g_assert (read_string_func != NULL);
82
83   GST_DEBUG ("File Content : (CONT) len = %d", datalen);
84
85   tags = gst_tag_list_new_empty ();
86
87   for (i = 0; i < G_N_ELEMENTS (gst_tags); ++i) {
88     gchar *str = NULL;
89     guint total_length = 0;
90
91     str = read_string_func (data, datalen, &total_length);
92     data += total_length;
93     datalen -= total_length;
94
95     if (str != NULL && !g_utf8_validate (str, -1, NULL)) {
96       const gchar *encoding;
97       gchar *tmp;
98
99       encoding = g_getenv ("GST_TAG_ENCODING");
100       if (encoding == NULL || *encoding == '\0') {
101         if (g_get_charset (&encoding))
102           encoding = "ISO-8859-15";
103       }
104       GST_DEBUG ("converting tag from %s to UTF-8", encoding);
105       tmp = g_convert_with_fallback (str, -1, "UTF-8", encoding, (gchar *) "*",
106           NULL, NULL, NULL);
107       g_free (str);
108       str = tmp;
109     }
110
111     GST_DEBUG ("%s = %s", gst_tags[i], GST_STR_NULL (str));
112     if (str != NULL && *str != '\0') {
113       gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, gst_tags[i], str, NULL);
114     }
115     g_free (str);
116   }
117
118   if (gst_tag_list_n_tags (tags) > 0)
119     return tags;
120
121   gst_tag_list_unref (tags);
122   return NULL;
123 }
124
125 GstBuffer *
126 gst_rm_utils_descramble_dnet_buffer (GstBuffer * buf)
127 {
128   GstMapInfo map;
129   guint8 *data, *end, tmp;
130
131   buf = gst_buffer_make_writable (buf);
132
133   /* dnet = byte-order swapped AC3 */
134   gst_buffer_map (buf, &map, GST_MAP_READWRITE);
135   data = map.data;
136   end = data + map.size;
137   while ((data + 1) < end) {
138     /* byte-swap */
139     tmp = data[0];
140     data[0] = data[1];
141     data[1] = tmp;
142     data += sizeof (guint16);
143   }
144   gst_buffer_unmap (buf, &map);
145   return buf;
146 }
147
148 static void
149 gst_rm_utils_swap_nibbles (guint8 * data, gint idx1, gint idx2, gint len)
150 {
151   guint8 *d1, *d2, tmp1 = 0, tmp2, tmp1n, tmp2n;
152
153   if ((idx2 & 1) && !(idx1 & 1)) {
154     /* align destination to a byte by swapping the indexes */
155     tmp1 = idx1;
156     idx1 = idx2;
157     idx2 = tmp1;
158   }
159   d1 = data + (idx1 >> 1);
160   d2 = data + (idx2 >> 1);
161
162   /* check if we have aligned offsets and we can copy bytes */
163   if ((idx1 & 1) == (idx2 & 1)) {
164     if (idx1 & 1) {
165       /* swap first nibble */
166       tmp1 = *d1;
167       tmp2 = *d2;
168       *d1++ = (tmp2 & 0xf0) | (tmp1 & 0x0f);
169       *d2++ = (tmp1 & 0xf0) | (tmp2 & 0x0f);
170       len--;
171     }
172     for (; len > 1; len -= 2) {
173       /* swap 2 nibbles */
174       tmp1 = *d1;
175       *d1++ = *d2;
176       *d2++ = tmp1;
177     }
178     if (len) {
179       /* swap leftover nibble */
180       tmp1 = *d1;
181       tmp2 = *d2;
182       *d1 = (tmp2 & 0x0f) | (tmp1 & 0xf0);
183       *d2 = (tmp1 & 0x0f) | (tmp2 & 0xf0);
184     }
185   } else {
186     /* preload nibbles from source */
187     tmp2n = *d1;
188     tmp2 = *d2;
189
190     for (; len > 1; len -= 2) {
191       /* assemble nibbles */
192       *d1++ = (tmp2n & 0x0f) | (tmp2 << 4);
193       tmp1n = *d1;
194       *d2++ = (tmp1n << 4) | (tmp1 >> 4);
195
196       tmp1 = tmp1n;
197       tmp2n = (tmp2 >> 4);
198       tmp2 = *d2;
199     }
200     if (len) {
201       /* last leftover */
202       *d1 = (tmp2 << 4) | (tmp2n & 0x0f);
203       *d2 = (tmp1 >> 4) | (tmp2 & 0xf0);
204     } else {
205       *d1 = (tmp1 & 0xf0) | (tmp2n);
206     }
207   }
208 }
209
210 static const gint sipr_swap_index[38][2] = {
211   {0, 63}, {1, 22}, {2, 44}, {3, 90},
212   {5, 81}, {7, 31}, {8, 86}, {9, 58},
213   {10, 36}, {12, 68}, {13, 39}, {14, 73},
214   {15, 53}, {16, 69}, {17, 57}, {19, 88},
215   {20, 34}, {21, 71}, {24, 46}, {25, 94},
216   {26, 54}, {28, 75}, {29, 50}, {32, 70},
217   {33, 92}, {35, 74}, {38, 85}, {40, 56},
218   {42, 87}, {43, 65}, {45, 59}, {48, 79},
219   {49, 93}, {51, 89}, {55, 95}, {61, 76},
220   {67, 83}, {77, 80}
221 };
222
223 GstBuffer *
224 gst_rm_utils_descramble_sipr_buffer (GstBuffer * buf)
225 {
226   GstMapInfo map;
227   gint n, bs;
228   gsize size;
229
230   size = gst_buffer_get_size (buf);
231
232   /* split the packet in 96 blocks of nibbles */
233   bs = size * 2 / 96;
234   if (bs == 0)
235     return buf;
236
237   buf = gst_buffer_make_writable (buf);
238
239   gst_buffer_map (buf, &map, GST_MAP_WRITE);
240
241   /* we need to perform 38 swaps on the blocks */
242   for (n = 0; n < 38; n++) {
243     gint idx1, idx2;
244
245     /* get the indexes of the blocks of nibbles that need swapping */
246     idx1 = bs * sipr_swap_index[n][0];
247     idx2 = bs * sipr_swap_index[n][1];
248
249     /* swap the blocks */
250     gst_rm_utils_swap_nibbles (map.data, idx1, idx2, bs);
251   }
252   gst_buffer_unmap (buf, &map);
253
254   return buf;
255 }
256
257 void
258 gst_rm_utils_run_tests (void)
259 {
260 #if 0
261   guint8 tab1[] = { 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe };
262   guint8 tab2[8];
263
264   memcpy (tab2, tab1, 8);
265   gst_util_dump_mem (tab2, 8);
266
267   gst_rm_utils_swap_nibbles (tab2, 0, 8, 4);
268   gst_util_dump_mem (tab2, 8);
269   memcpy (tab2, tab1, 8);
270   gst_rm_utils_swap_nibbles (tab2, 0, 8, 5);
271   gst_util_dump_mem (tab2, 8);
272
273   memcpy (tab2, tab1, 8);
274   gst_rm_utils_swap_nibbles (tab2, 1, 8, 4);
275   gst_util_dump_mem (tab2, 8);
276   memcpy (tab2, tab1, 8);
277   gst_rm_utils_swap_nibbles (tab2, 1, 8, 5);
278   gst_util_dump_mem (tab2, 8);
279
280   memcpy (tab2, tab1, 8);
281   gst_rm_utils_swap_nibbles (tab2, 0, 9, 4);
282   gst_util_dump_mem (tab2, 8);
283   memcpy (tab2, tab1, 8);
284   gst_rm_utils_swap_nibbles (tab2, 0, 9, 5);
285   gst_util_dump_mem (tab2, 8);
286
287   memcpy (tab2, tab1, 8);
288   gst_rm_utils_swap_nibbles (tab2, 1, 9, 4);
289   gst_util_dump_mem (tab2, 8);
290   memcpy (tab2, tab1, 8);
291   gst_rm_utils_swap_nibbles (tab2, 1, 9, 5);
292   gst_util_dump_mem (tab2, 8);
293 #endif
294 }