/* GStreamer RealMedia utility functions * Copyright (C) 2006 Tim-Philipp Müller * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #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 (); 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_structure_n_fields ((GstStructure *) tags) > 0) return tags; gst_tag_list_free (tags); return NULL; } GstBuffer * gst_rm_utils_descramble_dnet_buffer (GstBuffer * buf) { guint8 *data, *end, tmp; buf = gst_buffer_make_writable (buf); /* dnet = byte-order swapped AC3 */ data = GST_BUFFER_DATA (buf); end = GST_BUFFER_DATA (buf) + GST_BUFFER_SIZE (buf); while ((data + 1) < end) { /* byte-swap */ tmp = data[0]; data[0] = data[1]; data[1] = tmp; data += sizeof (guint16); } return buf; } static void gst_rm_utils_swap_nibbles (guint8 * data, gint idx1, gint idx2, gint len) { guint8 *d1, *d2, tmp1, 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 = tmp1 = tmp1n = *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) { guint8 *data; guint size; gint n, bs; size = GST_BUFFER_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); data = GST_BUFFER_DATA (buf); /* 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 (data, idx1, idx2, bs); } 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 }