summaryrefslogtreecommitdiff
path: root/gst/realmedia/rmutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/realmedia/rmutils.c')
-rw-r--r--gst/realmedia/rmutils.c294
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
+}