~ft/aacdec

4d4850f5de853099d2e2883057458ad48ccec477 — menno 16 years ago cc021be
Updated XMMS plugin
Adds song info window
2 files changed, 482 insertions(+), 76 deletions(-)

M plugins/xmms/src/libmp4.c
M plugins/xmms/src/mp4_utils.c
M plugins/xmms/src/libmp4.c => plugins/xmms/src/libmp4.c +82 -36
@@ 32,6 32,7 @@ static void	mp4_pause(short);
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 @@ InputPlugin mp4_ip =
    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_t	decodeThread;
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_cleanup(void)
{
}

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 @@ static void *mp4Decode(void *args)
    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,13 285,14 @@ static void *mp4Decode(void *args)
      guint		bufferSize = 0;
      gulong		samplerate;
      guchar		channels;
      guint		avgBitrate;
      //guint		avgBitrate;
      //MP4Duration	duration;
      int		msDuration;
      int		numSamples;
      int		sampleID = 0;
      unsigned int	framesize;
      mp4AudioSpecificConfig mp4ASC;
      gchar		*xmmstitle;

      decoder = NeAACDecOpen();
      mp4ff_get_decoder_config(infile, mp4track, &buffer, &bufferSize);


@@ 287,10 328,11 @@ static void *mp4Decode(void *args)
	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 @@ static void *mp4Decode(void *args)
					       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 @@ end:
      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);

M plugins/xmms/src/mp4_utils.c => plugins/xmms/src/mp4_utils.c +400 -40
@@ 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 @@ const char *mpeg4AudioNames[]=
    "MPEG-4 Algorithmic Synthesis and Audio FX profile"
  };

static GtkWidget *mp4_info_dialog = NULL;

/*
 * find AAC track
*/


@@ 54,7 63,7 @@ int getAACTrack(mp4ff_t *infile)
    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 @@ int getAACTrack(mp4ff_t *infile)
  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;

  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++;
      }
  return fseek((FILE*)user_data, position, SEEK_SET);
}

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);
  }
  if ((mp4ff_meta_get_genre(infile, &value)) && value != NULL) {
    gtk_entry_set_text (GTK_ENTRY(genre_entry), value);
    g_free(value);
  }
  MP4Close(mp4file);
  */
  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;
}