shithub: aacdec

Download patch

ref: 4d4850f5de853099d2e2883057458ad48ccec477
parent: cc021be2f301154f53385861a13856a33aec05bb
author: menno <menno>
date: Sun Oct 17 16:44:51 EDT 2004

Updated XMMS plugin
Adds song info window

--- a/plugins/xmms/src/libmp4.c
+++ b/plugins/xmms/src/libmp4.c
@@ -32,6 +32,7 @@
 static void	mp4_seek(int);
 static int	mp4_getTime(void);
 static void	mp4_cleanup(void);
+static void	mp4_getSongTitle(char *, char **, int *);
 static void	mp4_getSongInfo(char *);
 static int	mp4_isFile(char *);
 static void*	mp4Decode(void *);
@@ -59,7 +60,7 @@
     0,	// send visualisation data
     0,	// set player window info
     0,	// set song title text
-    0,	// get song title text
+    mp4_getSongTitle,	// get song title text
     mp4_getSongInfo, // info box
     0,	// to output plugin
   };
@@ -77,8 +78,11 @@
 static pthread_mutex_t	mutex = PTHREAD_MUTEX_INITIALIZER;
 static int		seekPosition = -1;
 
-
+// Functions from mp4_utils.c
 extern int getAACTrack(mp4ff_t *infile);
+extern mp4ff_callback_t *getMP4FF_cb(FILE *mp4file);
+extern char *getMP4title(mp4ff_t *infile, char *filename);
+extern void getMP4info(char* filename, FILE *mp4file);
 
 InputPlugin *get_iplugin_info(void)
 {
@@ -167,32 +171,77 @@
 {
 }
 
-static void	mp4_getSongInfo(char *filename)
+void mp4_get_file_type(FILE *mp4file)
 {
-  if(mp4cfg.file_type == FILE_MP4)
-    getMP4info(filename);
-  else if(mp4cfg.file_type == FILE_AAC)
-    /*
-     * check the id3tagv2
-    */
-    ;
+  unsigned char header[10] = {0};
+
+  fseek(mp4file, 0, SEEK_SET);
+  fread(header, 1, 8, mp4file);
+  if(header[4]=='f' &&
+     header[5]=='t' &&
+     header[6]=='y' &&
+     header[7]=='p'){
+    mp4cfg.file_type = FILE_MP4;
+  }else{
+    mp4cfg.file_type = FILE_AAC;
+  }
 }
 
-uint32_t read_callback(void *user_data, void *buffer, uint32_t length)
-{
-  return fread(buffer, 1, length, (FILE*)user_data);
+static void	mp4_getSongTitle(char *filename, char **title, int *len) {
+  FILE* mp4file;
+
+  (*title) = NULL;
+  (*len) = -1;
+	
+  if((mp4file = fopen(filename, "rb"))){
+    mp4_get_file_type(mp4file);
+    fseek(mp4file, 0, SEEK_SET);
+    if(mp4cfg.file_type == FILE_MP4){
+      mp4ff_callback_t*	mp4cb;
+      mp4ff_t*		infile;
+      gint		mp4track;
+
+      mp4cb = getMP4FF_cb(mp4file);
+      if ((infile = mp4ff_open_read_metaonly(mp4cb)) &&
+          ((mp4track = getAACTrack(infile)) >= 0)){
+        (*title) = getMP4title(infile, filename);
+
+        double track_duration = mp4ff_get_track_duration(infile, mp4track);
+        unsigned long time_scale = mp4ff_time_scale(infile, mp4track);
+        unsigned long length = (track_duration * 1000 / time_scale);
+        (*len) = length;
+      }
+      if(infile) mp4ff_close(infile);
+      if(mp4cb) g_free(mp4cb);
+    }
+    else{
+      // Check AAC ID3 tag...
+    }
+    fclose(mp4file);
+  }
 }
 
-uint32_t seek_callback(void *user_data, uint64_t position)
+static void	mp4_getSongInfo(char *filename)
 {
-  return fseek((FILE*)user_data, position, SEEK_SET);
+  FILE* mp4file;
+  if((mp4file = fopen(filename, "rb"))){
+    if (mp4cfg.file_type == FILE_UNKNOW)
+      mp4_get_file_type(mp4file);
+    fseek(mp4file, 0, SEEK_SET);
+    if(mp4cfg.file_type == FILE_MP4)
+      getMP4info(filename, mp4file);
+    else if(mp4cfg.file_type == FILE_AAC)
+      /*
+       * check the id3tagv2
+      */
+      ;
+    fclose(mp4file);
+  }
 }
 
-
 static void *mp4Decode(void *args)
 {
   FILE*		mp4file;
-  unsigned char header[10] = {0};
 
   pthread_mutex_lock(&mutex);
   seekPosition = -1;
@@ -206,26 +255,17 @@
     pthread_exit(NULL);
 
   }
-  fread(header, 1, 8, mp4file);
-  if(header[4]=='f' &&
-     header[5]=='t' &&
-     header[6]=='y' &&
-     header[7]=='p'){
-    mp4cfg.file_type = FILE_MP4;
-  }else{
-    mp4cfg.file_type = FILE_AAC;
-  }
-  fseek(mp4file, SEEK_SET, 0);
+  mp4_get_file_type(mp4file);
+  fseek(mp4file, 0, SEEK_SET);
   if(mp4cfg.file_type == FILE_MP4){// We are reading a MP4 file
+    mp4ff_callback_t*	mp4cb;
     mp4ff_t*		infile;
     gint		mp4track;
     
-    mp4ff_callback_t* mp4cb = malloc(sizeof(mp4ff_callback_t));
-    mp4cb->read = read_callback;
-    mp4cb->seek = seek_callback;
-    mp4cb->user_data = mp4file;
+    mp4cb = getMP4FF_cb(mp4file);
     if(!(infile = mp4ff_open_read(mp4cb))){
       g_print("MP4 - Can't open file\n");
+      goto end;
     }
     
     if((mp4track = getAACTrack(infile)) < 0){
@@ -245,7 +285,7 @@
       guint		bufferSize = 0;
       gulong		samplerate;
       guchar		channels;
-      guint		avgBitrate;
+      //guint		avgBitrate;
       //MP4Duration	duration;
       int		msDuration;
       int		numSamples;
@@ -252,6 +292,7 @@
       int		sampleID = 0;
       unsigned int	framesize;
       mp4AudioSpecificConfig mp4ASC;
+      gchar		*xmmstitle;
 
       decoder = NeAACDecOpen();
       mp4ff_get_decoder_config(infile, mp4track, &buffer, &bufferSize);
@@ -287,10 +328,11 @@
 	msDuration = ((float)numSamples*(float)(f-1.0)/
 		      (float)samplerate)*1000;
       }
+      xmmstitle = getMP4title(infile, args);
       mp4_ip.output->open_audio(FMT_S16_NE, samplerate, channels);
       mp4_ip.output->flush(0);
-      mp4_ip.set_info(args, msDuration, -1, samplerate/1000, channels);
-      g_print("MP4 - %d channels @ %d Hz\n", channels, samplerate);
+      mp4_ip.set_info(xmmstitle, msDuration, -1, samplerate/1000, channels);
+      g_print("MP4 - %d channels @ %ld Hz\n", channels, samplerate);
 
       while(bPlaying){
 	void*			sampleBuffer;
@@ -304,9 +346,13 @@
 					       seekPosition*1000,
 					       MP4_MSECS_TIME_SCALE);
 	  sampleID = MP4GetSampleIdFromTime(mp4file, mp4track, duration, 0);
+          */
+          float f = 1024.0;
+	  if(mp4ASC.sbr_present_flag == 1)
+	    f = f * 2.0;
+          sampleID = (float)seekPosition*(float)samplerate/(float)(f-1.0);
 	  mp4_ip.output->flush(seekPosition*1000);
 	  seekPosition = -1;
-	  */
 	}
 	buffer=NULL;
 	bufferSize=0;
@@ -349,7 +395,7 @@
       mp4_ip.output->close_audio();
       g_free(args);
       NeAACDecClose(decoder);
-      mp4ff_close(infile);
+      if(infile) mp4ff_close(infile);
       if(mp4cb) g_free(mp4cb);
       bPlaying = FALSE;
       fclose(mp4file);
--- a/plugins/xmms/src/mp4_utils.c
+++ b/plugins/xmms/src/mp4_utils.c
@@ -5,7 +5,14 @@
 #include "mp4ff.h"
 #include "faad.h"
 
+#include <gtk/gtk.h>
 #include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <xmms/plugin.h>
+#include <xmms/titlestring.h>
+#include <xmms/util.h>
+
 const char *mp4AudioNames[]=
   {
     "MPEG-1 Audio Layers 1,2 or 3",
@@ -35,6 +42,8 @@
     "MPEG-4 Algorithmic Synthesis and Audio FX profile"
   };
 
+static GtkWidget *mp4_info_dialog = NULL;
+
 /*
  * find AAC track
 */
@@ -54,7 +63,7 @@
     mp4ff_get_decoder_config(infile, i, &buff, &buff_size);
     if(buff){
       rc = NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC);
-      free(buff);
+      g_free(buff);
       if(rc < 0)
 	continue;
       return(i);
@@ -63,47 +72,398 @@
   return(-1);
 }
 
+uint32_t read_callback(void *user_data, void *buffer, uint32_t length)
+{
+  return fread(buffer, 1, length, (FILE*)user_data);
+}
 
-void getMP4info(char* file)
+uint32_t seek_callback(void *user_data, uint64_t position)
 {
-  /*
-  MP4FileHandle	mp4file;
-  MP4Duration	trackDuration;
-  int numTracks;
-  int i=0;
+  return fseek((FILE*)user_data, position, SEEK_SET);
+}
 
-  if(!(mp4file = MP4Read(file,0)))
-    return;
-  //MP4Dump(mp4file, 0, 0);
-  numTracks = MP4GetNumberOfTracks(mp4file, NULL, 0);
-  g_print("there are %d track(s)\n", numTracks);
-  for(i=0;i<numTracks;i++){
-    MP4TrackId trackID = MP4FindTrackId(mp4file, i, NULL, 0);
-    const char *trackType = MP4GetTrackType(mp4file, trackID);
-    printf("Track %d, %s", trackID, trackType);
-    if(!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)){//we found audio track !
-      int j=0;
-      u_int8_t audiotype = MP4GetTrackAudioType(mp4file, trackID);
-      while(mp4AudioTypes[j]){ // what kind of audio is ?
-	if(mp4AudioTypes[j] == audiotype){
-	  if(mp4AudioTypes[j] == MP4_MPEG4_AUDIO_TYPE){
-	    audiotype = MP4GetTrackAudioMpeg4Type(mp4file, trackID);
-	    g_print(" %s", mpeg4AudioNames[audiotype]);
-	  }
-	  else{
-	    printf(" %s", mp4AudioNames[j]);
-	  }
-	  g_print(" duration :%d",
-		 MP4ConvertFromTrackDuration(mp4file, trackID,
-					     MP4GetTrackDuration(mp4file,
-								 trackID),
-					     MP4_MSECS_TIME_SCALE));
-	}
-	j++;
-      }
+mp4ff_callback_t *getMP4FF_cb(FILE *mp4file)
+{
+  mp4ff_callback_t* mp4cb = malloc(sizeof(mp4ff_callback_t));
+  mp4cb->read = read_callback;
+  mp4cb->seek = seek_callback;
+  mp4cb->user_data = mp4file;
+  return mp4cb;
+}
+
+/*
+ * Function to display an info box for an mp4 file.
+ * This code is based heavily on fileinfo.c from the xmms mpg123
+ * plugin, and the info box layout mimics that plugin.
+*/
+void create_mp4_info_dialog (char *filename, FILE *mp4file, mp4ff_t *infile, gint mp4track)
+{
+  char *window_title, *value, *value2;
+  static GtkWidget *filename_entry, *title_entry, *artist_entry, *album_entry;
+  static GtkWidget *genre_entry, *year_entry, *track_entry, *comment_entry;
+  static GtkWidget *mp4_info_label;
+
+  if (!mp4_info_dialog)
+  {
+    GtkWidget *dialog_vbox1, *vbox1, *hbox2, *hbox3, *hbox4;
+    GtkWidget *frame2, *frame3, *table1, *dialog_action_area1;
+    GtkWidget *filename_label, *title_label, *artist_label, *album_label;
+    GtkWidget *genre_label, *year_label, *track_label, *comment_label;
+    GtkWidget *close_button;
+
+    mp4_info_dialog = gtk_dialog_new ();
+    gtk_object_set_data (GTK_OBJECT (mp4_info_dialog), "mp4_info_dialog", mp4_info_dialog);
+    gtk_window_set_policy (GTK_WINDOW (mp4_info_dialog), TRUE, TRUE, FALSE);
+    gtk_signal_connect(GTK_OBJECT (mp4_info_dialog), "destroy",
+                                   gtk_widget_destroyed, &mp4_info_dialog);
+
+    dialog_vbox1 = GTK_DIALOG (mp4_info_dialog)->vbox;
+    gtk_object_set_data (GTK_OBJECT (mp4_info_dialog), "dialog_vbox1", dialog_vbox1);
+    gtk_container_set_border_width (GTK_CONTAINER (dialog_vbox1), 3);
+
+    hbox2 = gtk_hbox_new (FALSE, 0);
+    gtk_widget_ref (hbox2);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "hbox2", hbox2,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (dialog_vbox1), hbox2, FALSE, TRUE, 0);
+    gtk_container_set_border_width (GTK_CONTAINER (hbox2), 3);
+
+    filename_label = gtk_label_new ("Filename: ");
+    gtk_widget_ref (filename_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "filename_label", filename_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (hbox2), filename_label, FALSE, FALSE, 0);
+
+    filename_entry = gtk_entry_new ();
+    gtk_widget_ref (filename_entry);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "filename_entry", filename_entry,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (hbox2), filename_entry, TRUE, TRUE, 0);
+    gtk_entry_set_editable (GTK_ENTRY (filename_entry), FALSE);
+
+    hbox3 = gtk_hbox_new (FALSE, 0);
+    gtk_widget_ref (hbox3);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "hbox3", hbox3,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (dialog_vbox1), hbox3, TRUE, TRUE, 0);
+    gtk_container_set_border_width (GTK_CONTAINER (hbox3), 3);
+
+    frame2 = gtk_frame_new ("Tag Info: ");
+    gtk_widget_ref (frame2);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "frame2", frame2,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (hbox3), frame2, TRUE, TRUE, 0);
+
+    table1 = gtk_table_new (6, 2, FALSE);
+    gtk_widget_ref (table1);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "table1", table1,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_container_add (GTK_CONTAINER (frame2), table1);
+    gtk_container_set_border_width (GTK_CONTAINER (table1), 5);
+
+    comment_label = gtk_label_new ("Comment: ");
+    gtk_widget_ref (comment_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "comment_label", comment_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), comment_label, 0, 1, 5, 6,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+    gtk_misc_set_alignment (GTK_MISC (comment_label), 1, 0.5);
+
+    genre_label = gtk_label_new ("Genre: ");
+    gtk_widget_ref (genre_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "genre_label", genre_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), genre_label, 0, 1, 4, 5,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+    gtk_misc_set_alignment (GTK_MISC (genre_label), 1, 0.5);
+
+    album_label = gtk_label_new ("Album: ");
+    gtk_widget_ref (album_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "album_label", album_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), album_label, 0, 1, 2, 3,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+    gtk_misc_set_alignment (GTK_MISC (album_label), 1, 0.5);
+
+    title_label = gtk_label_new ("Title: ");
+    gtk_widget_ref (title_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "title_label", title_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), title_label, 0, 1, 0, 1,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+    gtk_misc_set_alignment (GTK_MISC (title_label), 1, 0.5);
+
+    artist_label = gtk_label_new ("Artist: ");
+    gtk_widget_ref (artist_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "artist_label", artist_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), artist_label, 0, 1, 1, 2,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+    gtk_misc_set_alignment (GTK_MISC (artist_label), 1, 0.5);
+
+    year_label = gtk_label_new ("Year: ");
+    gtk_widget_ref (year_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "year_label", year_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), year_label, 0, 1, 3, 4,
+                      (GtkAttachOptions) (GTK_FILL),
+                      (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+    gtk_misc_set_alignment (GTK_MISC (year_label), 1, 0.5);
+
+    hbox4 = gtk_hbox_new (FALSE, 0);
+    gtk_widget_ref (hbox4);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "hbox4", hbox4,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), hbox4, 1, 2, 3, 4,
+                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                      (GtkAttachOptions) (GTK_FILL), 0, 0);
+
+    year_entry = gtk_entry_new ();
+    gtk_widget_ref (year_entry);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "year_entry", year_entry,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (hbox4), year_entry, FALSE, FALSE, 0);
+    gtk_widget_set_usize (year_entry, 60, -2);
+    gtk_entry_set_editable (GTK_ENTRY (year_entry), FALSE);
+
+    track_label = gtk_label_new ("     Track: ");
+    gtk_widget_ref (track_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "track_label", track_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (hbox4), track_label, FALSE, FALSE, 0);
+    gtk_misc_set_alignment (GTK_MISC (track_label), 1, 0.5);
+
+    track_entry = gtk_entry_new ();
+    gtk_widget_ref (track_entry);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "track_entry", track_entry,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (hbox4), track_entry, FALSE, FALSE, 0);
+    gtk_widget_set_usize (track_entry, 60, -2);
+    gtk_entry_set_editable (GTK_ENTRY (track_entry), FALSE);
+
+    title_entry = gtk_entry_new ();
+    gtk_widget_ref (title_entry);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "title_entry", title_entry,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), title_entry, 1, 2, 0, 1,
+                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                      (GtkAttachOptions) (0), 0, 0);
+    gtk_entry_set_editable (GTK_ENTRY (title_entry), FALSE);
+
+    artist_entry = gtk_entry_new ();
+    gtk_widget_ref (artist_entry);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "artist_entry", artist_entry,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), artist_entry, 1, 2, 1, 2,
+                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                      (GtkAttachOptions) (0), 0, 0);
+    gtk_entry_set_editable (GTK_ENTRY (artist_entry), FALSE);
+
+    album_entry = gtk_entry_new ();
+    gtk_widget_ref (album_entry);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "album_entry", album_entry,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), album_entry, 1, 2, 2, 3,
+                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                      (GtkAttachOptions) (0), 0, 0);
+    gtk_entry_set_editable (GTK_ENTRY (album_entry), FALSE);
+
+    genre_entry = gtk_entry_new ();
+    gtk_widget_ref (genre_entry);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "genre_entry", genre_entry,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), genre_entry, 1, 2, 4, 5,
+                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                      (GtkAttachOptions) (0), 0, 0);
+    gtk_entry_set_editable (GTK_ENTRY (genre_entry), FALSE);
+
+    comment_entry = gtk_entry_new ();
+    gtk_widget_ref (comment_entry);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "comment_entry", comment_entry,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_table_attach (GTK_TABLE (table1), comment_entry, 1, 2, 5, 6,
+                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                      (GtkAttachOptions) (0), 0, 0);
+    gtk_entry_set_editable (GTK_ENTRY (comment_entry), FALSE);
+
+    frame3 = gtk_frame_new ("MP4 Info: ");
+    gtk_widget_ref (frame3);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "frame3", frame3,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (hbox3), frame3, FALSE, TRUE, 0);
+
+    vbox1 = gtk_vbox_new (FALSE, 0);
+    gtk_widget_ref (vbox1);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "vbox1", vbox1,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_container_add (GTK_CONTAINER (frame3), vbox1);
+    gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5);
+
+    mp4_info_label = gtk_label_new ("");
+    gtk_widget_ref (mp4_info_label);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "mp4_info_label", mp4_info_label,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (vbox1), mp4_info_label, TRUE, TRUE, 0);
+    gtk_label_set_justify (GTK_LABEL (mp4_info_label), GTK_JUSTIFY_LEFT);
+    gtk_misc_set_alignment (GTK_MISC (mp4_info_label), 0, 0);
+
+    dialog_action_area1 = GTK_DIALOG (mp4_info_dialog)->action_area;
+    gtk_object_set_data (GTK_OBJECT (mp4_info_dialog), "dialog_action_area1", dialog_action_area1);
+    gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area1), 4);
+
+    close_button = gtk_button_new_with_label ("Close");
+    gtk_widget_ref (close_button);
+    gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "close_button", close_button,
+                              (GtkDestroyNotify) gtk_widget_unref);
+    gtk_box_pack_start (GTK_BOX (dialog_action_area1), close_button, FALSE, FALSE, 0);
+
+    gtk_signal_connect_object (GTK_OBJECT (close_button), "clicked",
+                               GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (mp4_info_dialog));
+
+  }
+
+  window_title = g_strdup_printf("File Info - %s", g_basename(filename));
+  gtk_window_set_title (GTK_WINDOW (mp4_info_dialog), window_title);
+  g_free(window_title);
+
+  gtk_entry_set_text (GTK_ENTRY (filename_entry), filename);
+
+  gtk_entry_set_text (GTK_ENTRY (title_entry), "");
+  gtk_entry_set_text (GTK_ENTRY (artist_entry), "");
+  gtk_entry_set_text (GTK_ENTRY (album_entry), "");
+  gtk_entry_set_text (GTK_ENTRY (year_entry), "");
+  gtk_entry_set_text (GTK_ENTRY (track_entry), "");
+  gtk_entry_set_text (GTK_ENTRY (genre_entry), "");
+  gtk_entry_set_text (GTK_ENTRY (comment_entry), "");
+
+  if ((mp4ff_meta_get_title(infile, &value)) && value != NULL) {
+    gtk_entry_set_text (GTK_ENTRY(title_entry), value);
+    g_free(value);
+  }
+  if ((mp4ff_meta_get_artist(infile, &value)) && value != NULL) {
+    gtk_entry_set_text (GTK_ENTRY(artist_entry), value);
+    g_free(value);
+  }
+  if ((mp4ff_meta_get_album(infile, &value)) && value != NULL) {
+    gtk_entry_set_text (GTK_ENTRY(album_entry), value);
+    g_free(value);
+  }
+  if ((mp4ff_meta_get_date(infile, &value)) && value != NULL) {
+    gtk_entry_set_text (GTK_ENTRY(year_entry), value);
+    g_free(value);
+  }
+  if ((mp4ff_meta_get_track(infile, &value)) && value != NULL) {
+    if ((mp4ff_meta_get_totaltracks(infile, &value2)) && value2 != NULL) {
+      char *tmp = g_strdup_printf("%s of %s", value, value2);
+      g_free(value2);
+      g_free(value);
+      value = tmp;
     }
-    printf("\n");
+    gtk_entry_set_text (GTK_ENTRY(track_entry), value);
+    g_free(value);
   }
-  MP4Close(mp4file);
-  */
+  if ((mp4ff_meta_get_genre(infile, &value)) && value != NULL) {
+    gtk_entry_set_text (GTK_ENTRY(genre_entry), value);
+    g_free(value);
+  }
+  if ((mp4ff_meta_get_comment(infile, &value)) && value != NULL) {
+    gtk_entry_set_text (GTK_ENTRY(comment_entry), value);
+    g_free(value);
+  }
+
+  // Get the length of the track.
+  double track_duration = mp4ff_get_track_duration(infile, mp4track);
+  unsigned long time_scale = mp4ff_time_scale(infile, mp4track);
+  unsigned long length = (track_duration / time_scale);
+  int min = length / 60;
+  int sec = length % 60;
+
+  // Get other info about the track.
+  unsigned long bitrate = mp4ff_get_avg_bitrate(infile, mp4track) / 1000;
+  unsigned long samplerate = mp4ff_get_sample_rate(infile, mp4track);
+  unsigned long channels = mp4ff_get_channel_count(infile, mp4track);
+  unsigned long audio_type = mp4ff_get_audio_type(infile, mp4track);
+  fseek(mp4file, 0, SEEK_END);
+  int filesize = ftell(mp4file) / 1024;
+
+  value = g_strdup_printf("Length: %d:%d\nAvg. Bitrate: %ld kbps\nSample Rate: %ld Hz\nChannels: %ld\nAudio Type: %ld\nFile Size: %d KB", min, sec, bitrate, samplerate, channels, audio_type, filesize);
+  gtk_label_set_text (GTK_LABEL(mp4_info_label), value);
+  g_free(value);
+
+  gtk_widget_show_all(mp4_info_dialog);
+}
+
+
+void getMP4info(char* filename, FILE* mp4file)
+{
+  mp4ff_callback_t*	mp4cb;
+  mp4ff_t*		infile;
+  gint			mp4track;
+
+  mp4cb = getMP4FF_cb(mp4file);
+  if ((infile = mp4ff_open_read_metaonly(mp4cb)) &&
+      ((mp4track = getAACTrack(infile)) >= 0)){
+    create_mp4_info_dialog (filename, mp4file, infile, mp4track);
+  }
+  if(infile) mp4ff_close(infile);
+  if(mp4cb) g_free(mp4cb);
+}
+
+/* Get the xmms titlestring for the file based on metadata.
+The following code was adapted from the gtkpod project, specifically
+mp4file.c (C) Jorg Schuler, but written to use the mp4ff library.  The
+mpg123 input plugin for xmms was used as a guide for this function.
+	--Jason Arroyo, 2004 */
+char *getMP4title(mp4ff_t *infile, char *filename) {
+	char *ret=NULL;
+	gchar *value, *path, *temp;
+
+	TitleInput *input;
+	XMMS_NEW_TITLEINPUT(input);
+
+	// Fill in the TitleInput with the relevant data
+	// from the mp4 file that can be used to display the title.
+	mp4ff_meta_get_title(infile, &input->track_name);
+        mp4ff_meta_get_artist(infile, &input->performer);
+	mp4ff_meta_get_album(infile, &input->album_name);
+	if (mp4ff_meta_get_track(infile, &value) && value != NULL) {
+		input->track_number = atoi(value);
+		g_free(value);
+	}
+	if (mp4ff_meta_get_date(infile, &value) && value != NULL) {
+		input->year = atoi(value);
+		g_free(value);
+	}
+	mp4ff_meta_get_genre(infile, &input->genre);
+	mp4ff_meta_get_comment(infile, &input->comment);
+	input->file_name = g_strdup(g_basename(filename));
+	path = g_strdup(filename);
+	temp = strrchr(path, '.');
+	if (temp != NULL) {++temp;}
+	input->file_ext = g_strdup_printf("%s", temp);
+	temp = strrchr(path, '/');
+	if (temp) {*temp = '\0';}
+	input->file_path = g_strdup_printf("%s/", path);
+
+	// Use the default xmms title format to format the
+	// title from the above info.
+	ret = xmms_get_titlestring(xmms_get_gentitle_format(), input);
+
+        g_free(input->track_name);
+        g_free(input->performer);
+        g_free(input->album_name);
+        g_free(input->genre);
+        g_free(input->comment);
+        g_free(input->file_name);
+        g_free(input->file_ext);
+        g_free(input->file_path);
+	g_free(input);
+	g_free(path);
+
+	return ret;
 }