changeset 32623:d90ee6158b89

Add playlist parser for .nsc files. Tested to properly decode .nsc files, but not properly tested since no publically available stream could be found.
author reimar
date Sun, 12 Dec 2010 19:25:43 +0000
parents 563e0a1369a0
children b2ff2f2c7d10
files playtreeparser.c
diffstat 1 files changed, 114 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/playtreeparser.c	Sun Dec 12 17:16:59 2010 +0000
+++ b/playtreeparser.c	Sun Dec 12 19:25:43 2010 +0000
@@ -680,6 +680,116 @@
   return entry;
 }
 
+/**
+ * \brief decode the base64 used in nsc files
+ * \param in input string, 0-terminated
+ * \param buf output buffer, must point to memory suitable for realloc,
+ *            will be NULL on failure.
+ * \return decoded length in bytes
+ */
+static int decode_nsc_base64(char *in, char **buf) {
+  int i, j, n;
+  if (in[0] != '0' || in[1] != '2')
+    goto err_out;
+  in += 2; // skip prefix
+  if (strlen(in) < 16) // error out if nothing to decode
+    goto err_out;
+  in += 12; // skip encoded string length
+  n = strlen(in) / 4;
+  *buf = realloc(*buf, n * 3);
+  for (i = 0; i < n; i++) {
+    uint8_t c[4];
+    for (j = 0; j < 4; j++) {
+      c[j] = in[4 * i + j];
+      if (c[j] >= '0' && c[j] <= '9') c[j] += 0 - '0';
+      else if (c[j] >= 'A' && c[j] <= 'Z') c[j] += 10 - 'A';
+      else if (c[j] >= 'a' && c[j] <= 'z') c[j] += 36 - 'a';
+      else if (c[j] == '{') c[j] = 62;
+      else if (c[j] == '}') c[j] = 63;
+      else {
+        mp_msg(MSGT_PLAYTREE, MSGL_ERR, "Invalid character %c (0x%02"PRIx8")\n", c[j], c[j]);
+        goto err_out;
+      }
+    }
+    (*buf)[3 * i] = (c[0] << 2) | (c[1] >> 4);
+    (*buf)[3 * i + 1] = (c[1] << 4) | (c[2] >> 2);
+    (*buf)[3 * i + 2] = (c[2] << 6) | c[3];
+  }
+  return 3 * n;
+err_out:
+  if (*buf) free(*buf);
+  *buf = NULL;
+  return 0;
+}
+
+/**
+ * \brief "converts" utf16 to ascii by just discarding every second byte
+ * \param buf buffer to convert
+ * \param len lenght of buffer, must be > 0
+ */
+static void utf16_to_ascii(char *buf, int len) {
+  int i;
+  if (len <= 0) return;
+  for (i = 0; i < len / 2; i++)
+    buf[i] = buf[i * 2];
+  buf[i] = 0; // just in case
+}
+
+static play_tree_t *parse_nsc(play_tree_parser_t* p) {
+  char *line, *addr = NULL, *url, *unicast_url = NULL;
+  int port = 0;
+  play_tree_t *entry = NULL;
+
+  mp_msg(MSGT_PLAYTREE,MSGL_V,"Trying nsc playlist...\n");
+  while((line = play_tree_parser_get_line(p)) != NULL) {
+    strstrip(line);
+    if(!line[0]) // Ignore empties
+      continue;
+    if (strncasecmp(line,"[Address]", 9) == 0)
+      break; // nsc header found
+    else
+      return NULL;
+  }
+  mp_msg(MSGT_PLAYTREE,MSGL_V,"Detected nsc playlist format\n");
+  play_tree_parser_stop_keeping(p);
+  while ((line = play_tree_parser_get_line(p)) != NULL) {
+    strstrip(line);
+    if (!line[0])
+      continue;
+    if (strncasecmp(line, "Unicast URL=", 12) == 0) {
+      int len = decode_nsc_base64(&line[12], &unicast_url);
+      if (len <= 0)
+        mp_msg(MSGT_PLAYTREE, MSGL_WARN, "[nsc] Unsupported Unicast URL encoding\n");
+      else
+        utf16_to_ascii(unicast_url, len);
+    } else if (strncasecmp(line, "IP Address=", 11) == 0) {
+      int len = decode_nsc_base64(&line[11], &addr);
+      if (len <= 0)
+        mp_msg(MSGT_PLAYTREE, MSGL_WARN, "[nsc] Unsupported IP Address encoding\n");
+      else
+        utf16_to_ascii(addr, len);
+    } else if (strncasecmp(line, "IP Port=", 8) == 0) {
+      port = strtol(&line[8], NULL, 0);
+    }
+  }
+
+  if (unicast_url)
+    url = strdup(unicast_url);
+  else if (addr && port) {
+    url = malloc(strlen(addr) + 7 + 20 + 1);
+    sprintf(url, "http://%s:%i", addr, port);
+  } else
+   goto out;
+
+  entry = play_tree_new();
+  play_tree_add_file(entry, url);
+  free(url);
+out:
+  if (addr) free(addr);
+  if (unicast_url) free(unicast_url);
+  return entry;
+}
+
 play_tree_t*
 parse_playtree(stream_t *stream, int forced) {
   play_tree_parser_t* p;
@@ -839,6 +949,10 @@
     if(tree) break;
     play_tree_parser_reset(p);
 
+    tree = parse_nsc(p);
+    if(tree) break;
+    play_tree_parser_reset(p);
+
     // Here come the others formats ( textplain must stay the last one )
     if (forced)
     {