Olivier Naudan | 2556a70 | 2012-04-16 08:57:32 -0400 | [diff] [blame] | 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 |
Sebastian Dröge | 6bf128e | 2013-07-14 12:07:04 +0200 | [diff] [blame] | 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| 17 | * Boston, MA 02110-1301, USA. |
Olivier Naudan | 2556a70 | 2012-04-16 08:57:32 -0400 | [diff] [blame] | 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 | |
Sebastian Dröge | 1e844f1 | 2012-06-08 13:25:41 +0200 | [diff] [blame] | 118 | if (gst_tag_list_n_tags (tags) > 0) |
Olivier Naudan | 2556a70 | 2012-04-16 08:57:32 -0400 | [diff] [blame] | 119 | return tags; |
| 120 | |
Sebastian Dröge | c167d67 | 2012-08-09 11:25:39 +0200 | [diff] [blame] | 121 | gst_tag_list_unref (tags); |
Olivier Naudan | 2556a70 | 2012-04-16 08:57:32 -0400 | [diff] [blame] | 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 | } |