changeset 79:722fd456ae1a trunk

[svn] - parse metadata on ALAC files... seems to work, but the method is inefficient
author nenolod
date Mon, 02 Oct 2006 20:54:57 -0700
parents 096db10ce25f
children c312e5c852ac
files ChangeLog src/alac/demux.c src/alac/demux.h src/alac/plugin.c
diffstat 4 files changed, 171 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Oct 02 19:55:45 2006 -0700
+++ b/ChangeLog	Mon Oct 02 20:54:57 2006 -0700
@@ -1,3 +1,13 @@
+2006-10-03 02:55:45 +0000  William Pitcock <nenolod@nenolod.net>
+  revision [156]
+  - a few concurrency fixes
+  
+  trunk/src/alac/demux.c  |   30 +++++++++++++++++++++++++++++-
+  trunk/src/alac/demux.h  |    6 +++---
+  trunk/src/alac/plugin.c |    8 ++++----
+  3 files changed, 36 insertions(+), 8 deletions(-)
+
+
 2006-10-03 01:14:15 +0000  William Pitcock <nenolod@nenolod.net>
   revision [154]
   - thread safety
--- a/src/alac/demux.c	Mon Oct 02 19:55:45 2006 -0700
+++ b/src/alac/demux.c	Mon Oct 02 20:54:57 2006 -0700
@@ -475,39 +475,92 @@
     stream_skip(qtmovie->stream, size_remaining);
 }
 
-/* 'udta' user data.. contains tag info */
-static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
+enum
+{
+	UDTA_NIL = 0,
+	UDTA_NAM,
+	UDTA_ART,
+	UDTA_ALB,
+	UDTA_GEN,
+	UDTA_DAY
+};
+
+/* 'udta' user data.. contains tag info. this routine is utterly fucked because Apple's
+ * lovely container format is utterly fucked itself...
+ */
+void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len)
 {
     /* don't need anything from here atm, skip */
     size_t size_remaining = chunk_len - 8; /* FIXME WRONG */
+    char *buf = g_malloc0(chunk_len);
+    char *bptr;
+    fourcc_t sub_chunk_id;   /* bptr[4] << 24 | bptr[3] << 16 | bptr[2] << 8 | bptr[1] */
+    int udta_tgt = UDTA_NIL;
 
-    stream_skip(qtmovie->stream, size_remaining);
-#if 0
-    while (size_remaining)
+    /* read the stream in for scanning -nenolod */
+    stream_read(qtmovie->stream, size_remaining, buf);
+
+    /* this is (bptr + 3) to account for the MAKEFOURCC() macro. -nenolod */
+    for (bptr = buf; (bptr + 3) - buf < size_remaining; bptr++)
     {
-        size_t sub_chunk_len;
-        fourcc_t sub_chunk_id;
-
-        sub_chunk_len = stream_read_uint32(qtmovie->stream);
-        if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining)
-            return;
-
-        sub_chunk_id = stream_read_uint32(qtmovie->stream);
+        sub_chunk_id = MAKEFOURCC(*bptr, *(bptr + 1), *(bptr + 2), *(bptr + 3));
 
         switch (sub_chunk_id)
         {
         case MAKEFOURCC('m','e','t','a'):
-            stream_skip(qtmovie->stream, sub_chunk_len);
-            break;
+             bptr += 4; /* skip meta */
+             break;
+        case MAKEFOURCC(0xA9,'n','a','m'):
+             udta_tgt = UDTA_NAM;
+	     bptr += 4;
+             break;
+        case MAKEFOURCC(0xA9,'A','R','T'):
+             udta_tgt = UDTA_ART;
+	     bptr += 4;
+             break;
+        case MAKEFOURCC(0xA9,'a','l','b'):
+             udta_tgt = UDTA_ALB;
+	     bptr += 4;
+             break;
+        case MAKEFOURCC(0xA9,'g','e','n'):
+             udta_tgt = UDTA_GEN;
+	     bptr += 4;
+             break;
+        case MAKEFOURCC(0xA9,'d','a','y'):
+             udta_tgt = UDTA_DAY;
+	     bptr += 4;
+             break;
+        case MAKEFOURCC('d','a','t','a'):
+             switch(udta_tgt)
+             {
+             case UDTA_NAM:
+                 qtmovie->res->tuple.nam = g_strdup(bptr + 12);
+                 break;
+             case UDTA_ART:
+                 qtmovie->res->tuple.art = g_strdup(bptr + 12);
+                 break;
+             case UDTA_ALB:
+                 qtmovie->res->tuple.alb = g_strdup(bptr + 12);
+                 break;
+             case UDTA_DAY:
+                 qtmovie->res->tuple.day = g_strdup(bptr + 12);
+                 break;
+             case UDTA_GEN:
+                 qtmovie->res->tuple.gen = g_strdup(bptr + 12);
+                 break;
+             default:
+	         break;
+             }
+
+             bptr += 12;
+	     bptr += strlen(bptr);
+             break;
         default:
-            fprintf(stderr, "read_chunk_udta(%p, %lu): unknown chunk: %c%c%c%c\n",
-	            qtmovie, chunk_len, SPLITFOURCC(sub_chunk_id));
-	    return;
+             break;
         }
+    }
 
-        size_remaining -= sub_chunk_len;
-    }
-#endif
+    g_free(buf);
 }
 
 /* 'moov' movie atom - contains other atoms */
--- a/src/alac/demux.h	Mon Oct 02 19:55:45 2006 -0700
+++ b/src/alac/demux.h	Mon Oct 02 20:54:57 2006 -0700
@@ -19,6 +19,16 @@
     void *buf;
 
     struct {
+        char *art;
+        char *nam;
+        char *alb;
+        char *day;
+        char *cmt;
+        char *des;
+        char *gen;
+    } tuple;
+
+    struct {
         uint32_t sample_count;
         uint32_t sample_duration;
     } *time_to_sample;
--- a/src/alac/plugin.c	Mon Oct 02 19:55:45 2006 -0700
+++ b/src/alac/plugin.c	Mon Oct 02 20:54:57 2006 -0700
@@ -52,6 +52,17 @@
 
 extern void set_endian();
 
+static gchar *
+extname(const char *filename)
+{
+    gchar *ext = strrchr(filename, '.');
+
+    if (ext != NULL)
+        ++ext;
+
+    return ext;  
+}
+
 static void alac_about(void)
 {
 	static GtkWidget *aboutbox;
@@ -106,6 +117,63 @@
     return TRUE;
 }
 
+TitleInput *build_tuple_from_demux(demux_res_t *demux_res, char *path)
+{
+    TitleInput *ti = bmp_title_input_new();
+
+    if (demux_res->tuple.art != NULL)
+        ti->performer = g_strdup(demux_res->tuple.art);
+    if (demux_res->tuple.nam != NULL)
+        ti->track_name = g_strdup(demux_res->tuple.nam);
+    if (demux_res->tuple.alb != NULL)
+        ti->album_name = g_strdup(demux_res->tuple.alb);
+    if (demux_res->tuple.gen != NULL)
+        ti->genre = g_strdup(demux_res->tuple.gen);
+    if (demux_res->tuple.cmt != NULL)
+        ti->comment = g_strdup(demux_res->tuple.cmt);
+    if (demux_res->tuple.day != NULL)
+        ti->year = atoi(demux_res->tuple.day);
+
+    ti->file_name = g_path_get_basename(path);
+    ti->file_path = g_path_get_dirname(path);
+    ti->file_ext = extname(path);
+
+    return ti;
+}
+
+TitleInput *build_tuple(char *filename)
+{
+    demux_res_t demux_res;
+    VFSFile *input_file;
+    stream_t *input_stream;
+    TitleInput *ti;
+
+    input_file = vfs_fopen(filename, "rb");
+    input_stream = stream_create_file(input_file, 1);
+
+    set_endian();
+
+    if (!input_stream)
+    {
+	vfs_fclose(input_file);
+        return NULL;
+    }
+        
+    /* if qtmovie_read returns successfully, the stream is up to
+     * the movie data, which can be used directly by the decoder */
+    if (!qtmovie_read(input_stream, &demux_res))
+    {
+        stream_destroy(input_stream);
+	vfs_fclose(input_file);
+        return NULL;
+    }
+
+    stream_destroy(input_stream);
+    vfs_fclose(input_file);
+
+    return build_tuple_from_demux(&demux_res, filename);
+}
+
 static void play_file(char *filename)
 {
     going = 1;
@@ -156,7 +224,8 @@
     NULL,
     NULL,
     NULL,                       /* file_info_box */
-    NULL
+    NULL,
+    build_tuple
 };
 
 static int get_sample_info(demux_res_t *demux_res, uint32_t samplenum,
@@ -240,6 +309,8 @@
     gint framesize;
     VFSFile *input_file;
     stream_t *input_stream;
+    TitleInput *ti;
+    gchar *title;
 
     memset(&demux_res, '\0', sizeof(demux_res_t));
 
@@ -258,6 +329,10 @@
 
     demux_res.stream = input_stream;
 
+    /* Get the titlestring ready. */
+    ti = build_tuple_from_demux(&demux_res, (char *) args);
+    title = xmms_get_titlestring(xmms_get_gentitle_format(), ti);
+
     /* initialise the sound converter */
     demux_res.alac = create_alac(demux_res.sample_size, demux_res.num_channels);
     alac_set_info(demux_res.alac, demux_res.codecdata);
@@ -267,7 +342,7 @@
 	(float)(demux_res.sample_rate / 251));
 
     alac_ip.output->open_audio(FMT_S16_LE, demux_res.sample_rate, demux_res.num_channels);
-    alac_ip.set_info((char *) args, duration, -1, demux_res.sample_rate, demux_res.num_channels);
+    alac_ip.set_info(title, duration, -1, demux_res.sample_rate, demux_res.num_channels);
 
     /* will convert the entire buffer */
     GetBuffer(&demux_res);