diff options
Diffstat (limited to 'gst/realmedia/rmutils.c')
-rw-r--r-- | gst/realmedia/rmutils.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/gst/realmedia/rmutils.c b/gst/realmedia/rmutils.c new file mode 100644 index 0000000..c9bc098 --- /dev/null +++ b/gst/realmedia/rmutils.c @@ -0,0 +1,294 @@ +/* GStreamer RealMedia utility functions + * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> + * + * 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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include "rmutils.h" + +gchar * +gst_rm_utils_read_string8 (const guint8 * data, guint datalen, + guint * p_total_len) +{ + gint length; + + if (p_total_len) + *p_total_len = 0; + + if (datalen < 1) + return NULL; + + length = GST_READ_UINT8 (data); + if (datalen < (1 + length)) + return NULL; + + if (p_total_len) + *p_total_len = 1 + length; + + return g_strndup ((gchar *) data + 1, length); +} + +gchar * +gst_rm_utils_read_string16 (const guint8 * data, guint datalen, + guint * p_total_len) +{ + gint length; + + if (p_total_len) + *p_total_len = 0; + + if (datalen < 2) + return NULL; + + length = GST_READ_UINT16_BE (data); + if (datalen < (2 + length)) + return NULL; + + if (p_total_len) + *p_total_len = 2 + length; + + return g_strndup ((gchar *) data + 2, length); +} + +GstTagList * +gst_rm_utils_read_tags (const guint8 * data, guint datalen, + GstRmUtilsStringReadFunc read_string_func) +{ + const gchar *gst_tags[] = { GST_TAG_TITLE, GST_TAG_ARTIST, + GST_TAG_COPYRIGHT, GST_TAG_COMMENT + }; + GstTagList *tags; + guint i; + + g_assert (read_string_func != NULL); + + GST_DEBUG ("File Content : (CONT) len = %d", datalen); + + tags = gst_tag_list_new_empty (); + + for (i = 0; i < G_N_ELEMENTS (gst_tags); ++i) { + gchar *str = NULL; + guint total_length = 0; + + str = read_string_func (data, datalen, &total_length); + data += total_length; + datalen -= total_length; + + if (str != NULL && !g_utf8_validate (str, -1, NULL)) { + const gchar *encoding; + gchar *tmp; + + encoding = g_getenv ("GST_TAG_ENCODING"); + if (encoding == NULL || *encoding == '\0') { + if (g_get_charset (&encoding)) + encoding = "ISO-8859-15"; + } + GST_DEBUG ("converting tag from %s to UTF-8", encoding); + tmp = g_convert_with_fallback (str, -1, "UTF-8", encoding, (gchar *) "*", + NULL, NULL, NULL); + g_free (str); + str = tmp; + } + + GST_DEBUG ("%s = %s", gst_tags[i], GST_STR_NULL (str)); + if (str != NULL && *str != '\0') { + gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, gst_tags[i], str, NULL); + } + g_free (str); + } + + if (gst_tag_list_n_tags (tags) > 0) + return tags; + + gst_tag_list_unref (tags); + return NULL; +} + +GstBuffer * +gst_rm_utils_descramble_dnet_buffer (GstBuffer * buf) +{ + GstMapInfo map; + guint8 *data, *end, tmp; + + buf = gst_buffer_make_writable (buf); + + /* dnet = byte-order swapped AC3 */ + gst_buffer_map (buf, &map, GST_MAP_READWRITE); + data = map.data; + end = data + map.size; + while ((data + 1) < end) { + /* byte-swap */ + tmp = data[0]; + data[0] = data[1]; + data[1] = tmp; + data += sizeof (guint16); + } + gst_buffer_unmap (buf, &map); + return buf; +} + +static void +gst_rm_utils_swap_nibbles (guint8 * data, gint idx1, gint idx2, gint len) +{ + guint8 *d1, *d2, tmp1 = 0, tmp2, tmp1n, tmp2n; + + if ((idx2 & 1) && !(idx1 & 1)) { + /* align destination to a byte by swapping the indexes */ + tmp1 = idx1; + idx1 = idx2; + idx2 = tmp1; + } + d1 = data + (idx1 >> 1); + d2 = data + (idx2 >> 1); + + /* check if we have aligned offsets and we can copy bytes */ + if ((idx1 & 1) == (idx2 & 1)) { + if (idx1 & 1) { + /* swap first nibble */ + tmp1 = *d1; + tmp2 = *d2; + *d1++ = (tmp2 & 0xf0) | (tmp1 & 0x0f); + *d2++ = (tmp1 & 0xf0) | (tmp2 & 0x0f); + len--; + } + for (; len > 1; len -= 2) { + /* swap 2 nibbles */ + tmp1 = *d1; + *d1++ = *d2; + *d2++ = tmp1; + } + if (len) { + /* swap leftover nibble */ + tmp1 = *d1; + tmp2 = *d2; + *d1 = (tmp2 & 0x0f) | (tmp1 & 0xf0); + *d2 = (tmp1 & 0x0f) | (tmp2 & 0xf0); + } + } else { + /* preload nibbles from source */ + tmp2n = *d1; + tmp2 = *d2; + + for (; len > 1; len -= 2) { + /* assemble nibbles */ + *d1++ = (tmp2n & 0x0f) | (tmp2 << 4); + tmp1n = *d1; + *d2++ = (tmp1n << 4) | (tmp1 >> 4); + + tmp1 = tmp1n; + tmp2n = (tmp2 >> 4); + tmp2 = *d2; + } + if (len) { + /* last leftover */ + *d1 = (tmp2 << 4) | (tmp2n & 0x0f); + *d2 = (tmp1 >> 4) | (tmp2 & 0xf0); + } else { + *d1 = (tmp1 & 0xf0) | (tmp2n); + } + } +} + +static const gint sipr_swap_index[38][2] = { + {0, 63}, {1, 22}, {2, 44}, {3, 90}, + {5, 81}, {7, 31}, {8, 86}, {9, 58}, + {10, 36}, {12, 68}, {13, 39}, {14, 73}, + {15, 53}, {16, 69}, {17, 57}, {19, 88}, + {20, 34}, {21, 71}, {24, 46}, {25, 94}, + {26, 54}, {28, 75}, {29, 50}, {32, 70}, + {33, 92}, {35, 74}, {38, 85}, {40, 56}, + {42, 87}, {43, 65}, {45, 59}, {48, 79}, + {49, 93}, {51, 89}, {55, 95}, {61, 76}, + {67, 83}, {77, 80} +}; + +GstBuffer * +gst_rm_utils_descramble_sipr_buffer (GstBuffer * buf) +{ + GstMapInfo map; + gint n, bs; + gsize size; + + size = gst_buffer_get_size (buf); + + /* split the packet in 96 blocks of nibbles */ + bs = size * 2 / 96; + if (bs == 0) + return buf; + + buf = gst_buffer_make_writable (buf); + + gst_buffer_map (buf, &map, GST_MAP_WRITE); + + /* we need to perform 38 swaps on the blocks */ + for (n = 0; n < 38; n++) { + gint idx1, idx2; + + /* get the indexes of the blocks of nibbles that need swapping */ + idx1 = bs * sipr_swap_index[n][0]; + idx2 = bs * sipr_swap_index[n][1]; + + /* swap the blocks */ + gst_rm_utils_swap_nibbles (map.data, idx1, idx2, bs); + } + gst_buffer_unmap (buf, &map); + + return buf; +} + +void +gst_rm_utils_run_tests (void) +{ +#if 0 + guint8 tab1[] = { 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }; + guint8 tab2[8]; + + memcpy (tab2, tab1, 8); + gst_util_dump_mem (tab2, 8); + + gst_rm_utils_swap_nibbles (tab2, 0, 8, 4); + gst_util_dump_mem (tab2, 8); + memcpy (tab2, tab1, 8); + gst_rm_utils_swap_nibbles (tab2, 0, 8, 5); + gst_util_dump_mem (tab2, 8); + + memcpy (tab2, tab1, 8); + gst_rm_utils_swap_nibbles (tab2, 1, 8, 4); + gst_util_dump_mem (tab2, 8); + memcpy (tab2, tab1, 8); + gst_rm_utils_swap_nibbles (tab2, 1, 8, 5); + gst_util_dump_mem (tab2, 8); + + memcpy (tab2, tab1, 8); + gst_rm_utils_swap_nibbles (tab2, 0, 9, 4); + gst_util_dump_mem (tab2, 8); + memcpy (tab2, tab1, 8); + gst_rm_utils_swap_nibbles (tab2, 0, 9, 5); + gst_util_dump_mem (tab2, 8); + + memcpy (tab2, tab1, 8); + gst_rm_utils_swap_nibbles (tab2, 1, 9, 4); + gst_util_dump_mem (tab2, 8); + memcpy (tab2, tab1, 8); + gst_rm_utils_swap_nibbles (tab2, 1, 9, 5); + gst_util_dump_mem (tab2, 8); +#endif +} |