blob: c9bc0982a97cd798717006ad659516c13c480083 [file] [log] [blame]
Olivier Naudan2556a702012-04-16 08:57:32 -04001/* 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
Sebastian Dröge6bf128e2013-07-14 12:07:04 +020016 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
Olivier Naudan2556a702012-04-16 08:57:32 -040018 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <string.h>
25#include "rmutils.h"
26
27gchar *
28gst_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
49gchar *
50gst_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
71GstTagList *
72gst_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
Sebastian Dröge1e844f12012-06-08 13:25:41 +0200118 if (gst_tag_list_n_tags (tags) > 0)
Olivier Naudan2556a702012-04-16 08:57:32 -0400119 return tags;
120
Sebastian Drögec167d672012-08-09 11:25:39 +0200121 gst_tag_list_unref (tags);
Olivier Naudan2556a702012-04-16 08:57:32 -0400122 return NULL;
123}
124
125GstBuffer *
126gst_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
148static void
149gst_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
210static 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
223GstBuffer *
224gst_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
257void
258gst_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}