shithub: aacdec

Download patch

ref: 3192dd937a71f737af84273806d91b306526cece
parent: c6050d407a25bfa81573cff01bdadb65ef6cfb5f
author: menno <menno>
date: Wed Aug 14 13:55:49 EDT 2002

New info box for mp4 plugin
mp4 plugin now supports seeking in aac files and info for aac files
(seems a bit buggy)

--- /dev/null
+++ b/plugins/in_mp4/aacinfo.c
@@ -1,0 +1,242 @@
+/*
+** FAAD - Freeware Advanced Audio Decoder
+** Copyright (C) 2002 M. Bakker
+**  
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+** 
+** This program 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 General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software 
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** $Id: aacinfo.c,v 1.1 2002/08/14 17:55:49 menno Exp $
+**/
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "aacinfo.h"
+#include "utils.h"
+
+#define ADIF_MAX_SIZE 30 /* Should be enough */
+#define ADTS_MAX_SIZE 10 /* Should be enough */
+
+static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000};
+
+static int read_ADIF_header(FILE *file, faadAACInfo *info)
+{
+    int bitstream;
+    unsigned char buffer[ADIF_MAX_SIZE];
+    int skip_size = 0;
+    int sf_idx;
+
+    /* Get ADIF header data */
+    info->headertype = 1;
+
+    if (fread(buffer, 1, ADIF_MAX_SIZE, file) != ADIF_MAX_SIZE)
+        return -1;
+
+    /* copyright string */
+    if(buffer[0] & 0x80)
+        skip_size += 9; /* skip 9 bytes */
+
+    bitstream = buffer[0 + skip_size] & 0x10;
+    info->bitrate = ((unsigned int)(buffer[0 + skip_size] & 0x0F)<<19)|
+        ((unsigned int)buffer[1 + skip_size]<<11)|
+        ((unsigned int)buffer[2 + skip_size]<<3)|
+        ((unsigned int)buffer[3 + skip_size] & 0xE0);
+
+    if (bitstream == 0)
+    {
+        info->object_type =  ((buffer[6 + skip_size]&0x01)<<1)|((buffer[7 + skip_size]&0x80)>>7);
+        sf_idx = (buffer[7 + skip_size]&0x78)>>3;
+    } else {
+        info->object_type = (buffer[4 + skip_size] & 0x18)>>3;
+        sf_idx = ((buffer[4 + skip_size] & 0x07)<<1)|((buffer[5 + skip_size] & 0x80)>>7);
+    }
+    info->sampling_rate = sample_rates[sf_idx];
+
+    return 0;
+}
+
+static int read_ADTS_header(FILE *file, faadAACInfo *info, unsigned long **seek_table,
+                            int *seek_table_len, int use_seek_table)
+{
+    /* Get ADTS header data */
+    unsigned char buffer[ADTS_MAX_SIZE];
+    int frames, framesinsec=0, t_framelength = 0, frame_length, sr_idx = 0, ID;
+    int second = 0, pos;
+    float frames_per_sec = 0;
+    unsigned long bytes;
+    unsigned long *tmp_seek_table = NULL;
+
+    info->headertype = 2;
+
+    /* Read all frames to ensure correct time and bitrate */
+    for (frames = 0; /* */; frames++, framesinsec++)
+    {
+        bytes = fread(buffer, 1, ADTS_MAX_SIZE, file);
+
+        if (bytes != ADTS_MAX_SIZE)
+            break;
+
+        /* check syncword */
+        if (!((buffer[0] == 0xFF)&&((buffer[1] & 0xF6) == 0xF0)))
+            break;
+
+        if (!frames)
+        {
+            /* fixed ADTS header is the same for every frame, so we read it only once */
+            /* Syncword found, proceed to read in the fixed ADTS header */
+            ID = buffer[1] & 0x08;
+            info->object_type = (buffer[2]&0xC0)>>6;
+            sr_idx = (buffer[2]&0x3C)>>2;
+            info->channels = ((buffer[2]&0x01)<<2)|((buffer[3]&0xC0)>>6);
+
+            frames_per_sec = sample_rates[sr_idx] / 1024.f;
+        }
+
+        /* ...and the variable ADTS header */
+        if (ID == 0)
+        {
+            info->version = 4;
+            frame_length = (((unsigned int)buffer[4]) << 5) |
+                ((unsigned int)buffer[5] >> 3);
+        } else { /* MPEG-2 */
+            info->version = 2;
+            frame_length = ((((unsigned int)buffer[3] & 0x3)) << 11)
+                | (((unsigned int)buffer[4]) << 3) | (buffer[5] >> 5);
+        }
+
+        t_framelength += frame_length;
+
+        if (framesinsec > 43)
+            framesinsec = 0;
+
+        pos = ftell(file) - ADTS_MAX_SIZE;
+
+        if (framesinsec == 0 && use_seek_table)
+        {
+            tmp_seek_table = (unsigned long*)realloc(tmp_seek_table, (second+1) * sizeof(unsigned long));
+            tmp_seek_table[second] = pos;
+        }
+        if (framesinsec == 0)
+            second++;
+
+        fseek(file, frame_length - ADTS_MAX_SIZE, SEEK_CUR);
+    }
+
+	if(seek_table_len)
+	{
+		*seek_table_len = second;
+		*seek_table = tmp_seek_table;
+	}
+
+    if (frames > 0)
+    {
+        info->sampling_rate = sample_rates[sr_idx];
+        info->bitrate = (int)(((t_framelength / frames) * (info->sampling_rate/1024.0)) +0.5)*8;
+        info->length = (int)((float)(frames/frames_per_sec))*1000;
+    } else {
+        info->sampling_rate = 4;
+        info->bitrate = 128000;
+        info->length = 0;
+        info->channels = 0;
+    }
+
+    return 0;
+}
+
+int get_AAC_format(char *filename, faadAACInfo *info,
+                   unsigned long **seek_table, int *seek_table_len,
+                   int use_seek_table)
+{
+    unsigned long tagsize;
+    FILE *file;
+	char buffer[10];
+    unsigned long file_len;
+    unsigned char adxx_id[5];
+    unsigned long tmp;
+
+    memset(info, 0, sizeof(faadAACInfo));
+
+    file = fopen(filename, "rb");
+
+    if(file == NULL)
+        return -1;
+
+    fseek(file, 0, SEEK_END);
+    file_len = ftell(file);
+    fseek(file, 0, SEEK_SET);
+
+    /* Skip the tag, if it's there */
+    tmp = fread(buffer, 10, 1, file);
+
+    if (StringComp(buffer, "ID3", 3) == 0)
+	{
+        /* high bit is not used */
+        tagsize = (buffer[6] << 21) | (buffer[7] << 14) |
+            (buffer[8] <<  7) | (buffer[9] <<  0);
+
+        fseek(file, tagsize, SEEK_CUR);
+        tagsize += 10;
+    } else {
+        tagsize = 0;
+        fseek(file, 0, SEEK_SET);
+    }
+
+    if (file_len)
+        file_len -= tagsize;
+
+    tmp = fread(adxx_id, 2, 1, file);
+    adxx_id[5-1] = 0;
+    info->length = 0;
+
+    /* Determine the header type of the file, check the first two bytes */
+    if (StringComp(adxx_id, "AD", 2) == 0)
+    {
+        /* We think its an ADIF header, but check the rest just to make sure */
+		tmp = fread(adxx_id + 2, 2, 1, file);
+
+        if (StringComp(adxx_id, "ADIF", 4) == 0)
+        {
+            read_ADIF_header(file, info);
+
+            info->length = (int)((float)file_len*8000.0/((float)info->bitrate));
+        }
+    } else {
+        /* No ADIF, check for ADTS header */
+        if ((adxx_id[0] == 0xFF)&&((adxx_id[1] & 0xF6) == 0xF0))
+        {
+            /* ADTS  header located */
+            fseek(file, tagsize, SEEK_SET);
+
+            read_ADTS_header(file, info, seek_table, seek_table_len,
+                use_seek_table);
+        } else {
+            /* Unknown/headerless AAC file, assume format: */
+            info->version = 2;
+            info->bitrate = 128000;
+            info->sampling_rate = 44100;
+            info->channels = 2;
+            info->headertype = 0;
+            info->object_type = 1;
+        }
+    }
+
+    fclose(file);
+
+    return 0;
+}
+
--- /dev/null
+++ b/plugins/in_mp4/aacinfo.h
@@ -1,0 +1,44 @@
+/*
+** FAAD - Freeware Advanced Audio Decoder
+** Copyright (C) 2002 M. Bakker
+**  
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+** 
+** This program 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 General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software 
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** $Id: aacinfo.h,v 1.1 2002/08/14 17:55:49 menno Exp $
+**/
+
+#ifndef AACINFO_INCLUDED
+#define AACINFO_INCLUDED
+
+typedef struct {
+    int version;
+    int channels;
+    int sampling_rate;
+    int bitrate;
+    int length;
+    int object_type;
+    int headertype;
+} faadAACInfo;
+
+int get_AAC_format(char *filename, faadAACInfo *info,
+                   unsigned long **seek_table, int *seek_table_len,
+                   int use_seek_table);
+
+static int read_ADIF_header(FILE *file, faadAACInfo *info);
+static int read_ADTS_header(FILE *file, faadAACInfo *info,
+                            unsigned long **seek_table, int *seek_table_len,
+                            int use_seek_table);
+
+#endif
--- a/plugins/in_mp4/in_mp4.c
+++ b/plugins/in_mp4/in_mp4.c
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: in_mp4.c,v 1.13 2002/08/09 21:48:12 menno Exp $
+** $Id: in_mp4.c,v 1.14 2002/08/14 17:55:20 menno Exp $
 **/
 
 #define WIN32_LEAN_AND_MEAN
@@ -30,6 +30,7 @@
 #include "in2.h"
 #include "utils.h"
 #include "config.h"
+#include "aacinfo.h"
 
 static long priority_table[] = {
     0,
@@ -42,12 +43,16 @@
 static int res_id_table[] = {
     IDC_16BITS,
     IDC_24BITS,
-    IDC_32BITS
+    IDC_32BITS,
+    0,
+    IDC_16BITS_DITHERED
 };
 static int res_table[] = {
     16,
     24,
-    32
+    32,
+    0,
+    16
 };
 static char info_fn[_MAX_PATH];
 
@@ -65,6 +70,7 @@
     int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.
     char filename[_MAX_PATH];
     int filetype; /* 0: MP4; 1: AAC */
+    int last_frame;
 
     /* MP4 stuff */
     MP4FileHandle mp4file;
@@ -79,7 +85,10 @@
     long bytes_into_buffer;
     long bytes_consumed;
     unsigned char *buffer;
-    long lengthMs;
+    long seconds;
+    unsigned long *seek_table;
+    int seek_table_len;
+    faadAACInfo aacInfo;
 } state;
 
 static state mp4state;
@@ -157,204 +166,87 @@
 BOOL CALLBACK mp4_info_dialog_proc(HWND hwndDlg, UINT message,
                                    WPARAM wParam, LPARAM lParam)
 {
-    int i, width, height, numFrames;
-    unsigned char ch, sf, dummy8;
-    float fps;
     MP4FileHandle file;
-    int track;
-    char info[256];
+    int tracks, i;
 
-    static const char* mpeg4AudioNames[] = {
-        "MPEG-4 Null (Raw PCM)",
-        "MPEG-4 AAC Main",
-        "MPEG-4 AAC LC",
-        "MPEG-4 AAC SSR",
-        "MPEG-4 AAC LTP",
-        "Reserved",
-        "MPEG-4 AAC Scalable",
-        "MPEG-4 TwinVQ",
-        "MPEG-4 CELP",
-        "MPEG-4 HVXC",
-        "Reserved",
-        "Reserved",
-        "MPEG-4 TTSI",
-        "MPEG-4 Main synthetic",
-        "MPEG-4 Wavetable synthesis",
-        "MPEG-4 General MIDI",
-        "MPEG-4 Algorithmic Synthesis and Audio FX",
-        /* defined in MPEG-4 version 2 */
-        "MPEG-4 ER AAC LC",
-        "Reserved",
-        "MPEG-4 ER AAC LTP",
-        "MPEG-4 ER AAC Scalable",
-        "MPEG-4 ER TwinVQ",
-        "MPEG-4 ER BSAC",
-        "MPEG-4 ER AAC LD",
-        "MPEG-4 ER CELP",
-        "MPEG-4 ER HVXC",
-        "MPEG-4 ER HILN",
-        "MPEG-4 ER Parametric",
-        "Reserved",
-        "Reserved",
-        "Reserved",
-        "Reserved"
-    };
-    static int numMpeg4AudioTypes = 
-        sizeof(mpeg4AudioNames)/sizeof(char*);
-
-	static const char* mpeg4VideoNames[] = {
-		"MPEG-4 Simple @ L3",
-		"MPEG-4 Simple @ L2",
-		"MPEG-4 Simple @ L1",
-		"MPEG-4 Simple Scalable @ L2",
-		"MPEG-4 Simple Scalable @ L1",
-		"MPEG-4 Core @ L2",
-		"MPEG-4 Core @ L1",
-		"MPEG-4 Main @ L4",
-		"MPEG-4 Main @ L3",
-		"MPEG-4 Main @ L2",
-		"MPEG-4 Main @ L1",
-		"MPEG-4 N-Bit @ L2",
-		"MPEG-4 Hybrid @ L2",
-		"MPEG-4 Hybrid @ L1",
-		"MPEG-4 Hybrid @ L1"
-	};
-	static int numMpeg4VideoTypes = 
-		sizeof(mpeg4VideoNames) / sizeof(char*);
-
-	static int mpegVideoTypes[] = {
-		MP4_MPEG2_SIMPLE_VIDEO_TYPE,	// 0x60
-		MP4_MPEG2_MAIN_VIDEO_TYPE,		// 0x61
-		MP4_MPEG2_SNR_VIDEO_TYPE,		// 0x62
-		MP4_MPEG2_SPATIAL_VIDEO_TYPE,	// 0x63
-		MP4_MPEG2_HIGH_VIDEO_TYPE,		// 0x64
-		MP4_MPEG2_442_VIDEO_TYPE,		// 0x65
-		MP4_MPEG1_VIDEO_TYPE,			// 0x6A
-		MP4_JPEG_VIDEO_TYPE 			// 0x6C
-	};
-	static const char* mpegVideoNames[] = {
-		"MPEG-2 Simple",
-		"MPEG-2 Main",
-		"MPEG-2 SNR",
-		"MPEG-2 Spatial",
-		"MPEG-2 High",
-		"MPEG-2 4:2:2",
-		"MPEG-1",
-		"JPEG"
-	};
-	static int numMpegVideoTypes = 
-		sizeof(mpegVideoTypes) / sizeof(u_int8_t);
-
-    unsigned long msDuration;
-    MP4Duration trackDuration;
-    unsigned int timeScale, avgBitRate;
-    unsigned char type;
-    const char* typeName;
-
     switch (message) {
     case WM_INITDIALOG:
         file = MP4Read(info_fn, 0);
+
         if (!file)
             return FALSE;
 
-        if ((track = GetAudioTrack(file)) >= 0)
+        tracks = MP4GetNumberOfTracks(file, NULL, 0);
+
+        if (tracks == 0)
         {
-            unsigned char *buff = NULL;
-            int buff_size = 0;
-            MP4GetTrackESConfiguration(file, track, &buff, &buff_size);
+            SetDlgItemText(hwndDlg, IDC_INFOTEXT, "No tracks found");
+        } else {
+            char *file_info;
+            char *info_text = malloc(1024*sizeof(char));
+            info_text[0] = '\0';
 
-            if (buff)
+            for (i = 0; i < tracks; i++)
             {
-                AudioSpecificConfig(buff, &timeScale, &ch, &sf, &type,
-                    &dummy8, &dummy8, &dummy8, &dummy8);
-                typeName = mpeg4AudioNames[type];
-                free(buff);
-
-                sprintf(info, "%d", ch);
-                SetDlgItemText(hwndDlg, IDC_CHANNELS, info);
-
-                sprintf(info, "%d Hz", timeScale);
-                SetDlgItemText(hwndDlg, IDC_SAMPLERATE, info);
-            } else {
-                typeName = "Unknown";
-                SetDlgItemText(hwndDlg, IDC_CHANNELS, "n/a");
-                SetDlgItemText(hwndDlg, IDC_SAMPLERATE, "n/a");
+                file_info = MP4Info(file, i+1);
+                lstrcat(info_text, file_info);
             }
-            trackDuration = MP4GetTrackDuration(file, track);
+            SetDlgItemText(hwndDlg, IDC_INFOTEXT, info_text);
+            free(info_text);
+        }
 
-            msDuration = MP4ConvertFromTrackDuration(file, track,
-                trackDuration, MP4_MSECS_TIME_SCALE);
+        MP4Close(file);
 
-            avgBitRate = MP4GetTrackIntegerProperty(file, track,
-                "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.avgBitrate");
+        return TRUE;
 
-            SetDlgItemText(hwndDlg, IDC_TYPE, typeName);
-
-            sprintf(info, "%.3f secs", (float)msDuration/1000.0);
-            SetDlgItemText(hwndDlg, IDC_DURATION, info);
-
-            sprintf(info, "%u Kbps", (avgBitRate+500)/1000);
-            SetDlgItemText(hwndDlg, IDC_BITRATE, info);
+    case WM_COMMAND:
+        switch (LOWORD(wParam)) {
+        case IDCANCEL:
+        case IDOK:
+            EndDialog(hwndDlg, wParam);
+            return TRUE;
         }
-
-        if ((track = GetVideoTrack(file)) >= 0)
-        {
-            type = MP4GetTrackVideoType(file, track);
-            typeName = "Unknown";
-
-            if (type == MP4_MPEG4_VIDEO_TYPE) {
-                type = MP4GetVideoProfileLevel(file);
-                if (type > 0 && type <= numMpeg4VideoTypes) {
-                    typeName = mpeg4VideoNames[type - 1];
-                } else {
-                    typeName = "MPEG-4";
-                }
-            } else {
-                for (i = 0; i < numMpegVideoTypes; i++) {
-                    if (type == mpegVideoTypes[i]) {
-                        typeName = mpegVideoNames[i];
-                        break;
-                    }
-                }
-            }
+    }
+    return FALSE;
+}
+
+/* returns the name of the object type */
+char *get_ot_string(int ot)
+{
+    switch (ot)
+    {
+    case 0:
+        return "Main";
+    case 1:
+        return "LC";
+    case 2:
+        return "SSR";
+    case 3:
+        return "LTP";
+    }
+    return NULL;
+}
 
-            trackDuration = MP4GetTrackDuration(file, track);
-            msDuration = MP4ConvertFromTrackDuration(file, track,
-                trackDuration, MP4_MSECS_TIME_SCALE);
+BOOL CALLBACK aac_info_dialog_proc(HWND hwndDlg, UINT message,
+                                   WPARAM wParam, LPARAM lParam)
+{
+    faadAACInfo aacInfo;
+    char *info_text;
 
-            avgBitRate = MP4GetTrackIntegerProperty(file, track,
-                "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.avgBitrate");
+    switch (message) {
+    case WM_INITDIALOG:
+        info_text = malloc(1024*sizeof(char));
 
-            // Note not all mp4 implementations set width and height correctly
-            // The real answer can be buried inside the ES configuration info
-            width = MP4GetTrackIntegerProperty(file, track,
-                "mdia.minf.stbl.stsd.mp4v.width");
+        get_AAC_format(info_fn, &aacInfo, NULL, NULL, 0);
 
-            height = MP4GetTrackIntegerProperty(file, track,
-                "mdia.minf.stbl.stsd.mp4v.height");
+        sprintf(info_text, "%s AAC %s, %d sec, %d kbps, %d Hz",
+            (aacInfo.version==2)?"MPEG-2":"MPEG-4", get_ot_string(aacInfo.object_type),
+            aacInfo.length/1000, (int)(aacInfo.bitrate/1000.0+0.5), aacInfo.sampling_rate);
 
-            // Note if variable rate video is being used the fps is an average 
-            numFrames = MP4GetTrackNumberOfSamples(file, track);
+        SetDlgItemText(hwndDlg, IDC_INFOTEXT, info_text);
 
-            fps = ((float)numFrames/(float)msDuration) * 1000;
+        free(info_text);
 
-            SetDlgItemText(hwndDlg, IDC_VTYPE, typeName);
-
-            sprintf(info, "%.3f secs", (float)msDuration/1000.0);
-            SetDlgItemText(hwndDlg, IDC_VDURATION, info);
-
-            sprintf(info, "%u Kbps", (avgBitRate+500)/1000);
-            SetDlgItemText(hwndDlg, IDC_VBITRATE, info);
-
-            sprintf(info, "%dx%d", width, height);
-            SetDlgItemText(hwndDlg, IDC_VSIZE, info);
-
-            sprintf(info, "%.2f", fps);
-            SetDlgItemText(hwndDlg, IDC_VFPS, info);
-        }
-
-        MP4Close(file);
-
         return TRUE;
 
     case WM_COMMAND:
@@ -372,11 +264,10 @@
 {
     if(StringComp(fn + strlen(fn) - 3, "aac", 3) == 0)
     {
-        MessageBox(hwndParent,
-            "Sorry, no support for AAC info.\n"
-            "AudioCoding.com MPEG-4 General Audio player.",
-            "About",
-            MB_OK);
+        lstrcpy(info_fn, fn);
+
+        DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
+            hwndParent, aac_info_dialog_proc);
     } else {
         lstrcpy(info_fn, fn);
 
@@ -465,16 +356,21 @@
     int maxlatency;
     int thread_id;
     int avg_bitrate;
-    void *sample_buffer;
     unsigned char *buffer;
     int buffer_size;
-    faacDecFrameInfo frameInfo;
     faacDecConfigurationPtr config;
 
     mp4state.channels = 0;
     mp4state.samplerate = 0;
     mp4state.filetype = 0;
+    mp4state.seek_table_len = 0;
 
+    if (mp4state.seek_table)
+    {
+        free(mp4state.seek_table);
+        mp4state.seek_table = NULL;
+    }
+
     strcpy(mp4state.filename, fn);
 
     if(StringComp(fn + strlen(fn) - 3, "aac", 3) == 0)
@@ -491,7 +387,10 @@
     {
         long pos, tmp, read;
 
-        mp4state.aacfile = fopen(fn, "rb");
+        get_AAC_format(mp4state.filename, &mp4state.aacInfo,
+            &mp4state.seek_table, &mp4state.seek_table_len, 1);
+
+        mp4state.aacfile = fopen(mp4state.filename, "rb");
         if (!mp4state.aacfile)
         {
             show_error(module.hMainWindow, "Unable to open file.");
@@ -504,7 +403,7 @@
         mp4state.filesize = ftell(mp4state.aacfile);
         fseek(mp4state.aacfile, pos, SEEK_SET);
 
-        if(!(mp4state.buffer=(unsigned char*)malloc(768*48)))
+        if (!(mp4state.buffer=(unsigned char*)malloc(768*48)))
         {
             show_error(module.hMainWindow, "Memory allocation error.");
             faacDecClose(mp4state.hDecoder);
@@ -513,12 +412,12 @@
         }
         memset(mp4state.buffer, 0, 768*48);
 
-        if(mp4state.filesize < 768*48)
+        if (mp4state.filesize < 768*48)
             tmp = mp4state.filesize;
         else
             tmp = 768*48;
         read = fread(mp4state.buffer, 1, tmp, mp4state.aacfile);
-        if(read == tmp)
+        if (read == tmp)
         {
             mp4state.bytes_read = read;
             mp4state.bytes_into_buffer = read;
@@ -529,7 +428,7 @@
             return -1;
         }
 
-        if((mp4state.bytes_consumed=faacDecInit(mp4state.hDecoder,
+        if ((mp4state.bytes_consumed=faacDecInit(mp4state.hDecoder,
             mp4state.buffer, &mp4state.samplerate, &mp4state.channels)) < 0)
         {
             show_error(module.hMainWindow, "Can't initialize library.");
@@ -539,11 +438,14 @@
         }
         mp4state.bytes_into_buffer -= mp4state.bytes_consumed;
 
-        avg_bitrate = 0;
+        avg_bitrate = mp4state.aacInfo.bitrate;
 
-        module.is_seekable = 0;
+        if (mp4state.aacInfo.headertype == 2)
+            module.is_seekable = 1;
+        else
+            module.is_seekable = 0;
     } else {
-        mp4state.mp4file = MP4Read(fn, 0);
+        mp4state.mp4file = MP4Read(mp4state.filename, 0);
         if (!mp4state.mp4file)
         {
             show_error(module.hMainWindow, "Unable to open file.");
@@ -701,6 +603,14 @@
         fclose(mp4state.aacfile);
     else
         MP4Close(mp4state.mp4file);
+
+    if (mp4state.seek_table)
+    {
+        free(mp4state.seek_table);
+        mp4state.seek_table = NULL;
+        mp4state.seek_table_len = 0;
+    }
+
     module.outMod->Close();
     module.SAVSADeInit();
 }
@@ -731,9 +641,14 @@
             length, MP4_MSECS_TIME_SCALE);
 
         MP4Close(file);
-    }
 
-    return msDuration;
+        return msDuration;
+    } else {
+        faadAACInfo aacInfo;
+        get_AAC_format(fn, &aacInfo, NULL, NULL, 0);
+
+        return aacInfo.length;
+    }
 }
 
 int getlength()
@@ -755,6 +670,8 @@
             length, MP4_MSECS_TIME_SCALE);
 
         return msDuration;
+    } else {
+        return mp4state.aacInfo.length;
     }
     return 0;
 }
@@ -781,9 +698,7 @@
             char *tmp = PathFindFileName(mp4state.filename);
             strcpy(title, tmp);
         }
-    }
-    else /* some other file */
-    {
+    } else {
         if (length_in_ms)
             *length_in_ms = getsonglength(filename);
 
@@ -799,8 +714,6 @@
 {
 }
 
-int last_frame;
-
 DWORD WINAPI MP4PlayThread(void *b)
 {
     int done = 0;
@@ -812,7 +725,7 @@
     faacDecFrameInfo frameInfo;
 
 	PlayThreadAlive = 1;
-    last_frame = 0;
+    mp4state.last_frame = 0;
 
     while (!*((int *)b))
     {
@@ -843,11 +756,10 @@
             }
 
             Sleep(10);
-        }
-        else if (module.outMod->CanWrite() >=
+        } else if (module.outMod->CanWrite() >=
             ((1024*mp4state.channels*sizeof(short))<<(module.dsp_isactive()?1:0)))
         {
-            if(last_frame)
+            if (mp4state.last_frame)
             {
                 done = 1;
             } else {
@@ -862,7 +774,7 @@
                     NULL, NULL, NULL, NULL);
                 if (rc == 0 || buffer == NULL)
                 {
-                    last_frame = 1;
+                    mp4state.last_frame = 1;
                     sample_buffer = NULL;
                     frameInfo.samples = 0;
                 } else {
@@ -871,15 +783,23 @@
                 if (frameInfo.error > 0)
                 {
                     show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
-                    last_frame = 1;
+                    mp4state.last_frame = 1;
                 }
                 if (mp4state.sampleId >= mp4state.numSamples)
-                    last_frame = 1;
+                    mp4state.last_frame = 1;
 
                 if (buffer) free(buffer);
 
                 if (!killPlayThread && (frameInfo.samples > 0))
                 {
+                    if (res_table[m_resolution] == 24)
+                    {
+                        /* convert libfaad output (3 bytes packed in 4) */
+                        char *temp_buffer = convert3in4to3in3(sample_buffer, frameInfo.samples);
+                        memcpy((void*)sample_buffer, (void*)temp_buffer, frameInfo.samples*3);
+                        free(temp_buffer);
+                    }
+
                     module.SAAddPCMData(sample_buffer, mp4state.channels, res_table[m_resolution],
                         mp4state.decode_pos_ms);
                     module.VSAAddPCMData(sample_buffer, mp4state.channels, res_table[m_resolution],
@@ -909,6 +829,23 @@
     return 0;
 }
 
+int aac_seek(int pos_ms)
+{
+    int read;
+    int offset_sec = (int)((float)pos_ms / 1000.0 + 0.5);
+
+    fseek(mp4state.aacfile, mp4state.seek_table[offset_sec], SEEK_SET);
+
+    mp4state.bytes_read = mp4state.seek_table[offset_sec];
+    mp4state.bytes_consumed = 0;
+
+    read = fread(mp4state.buffer, 1, 768*48, mp4state.aacfile);
+    mp4state.bytes_read += read;
+    mp4state.bytes_into_buffer = read;
+
+    return 0;
+}
+
 DWORD WINAPI AACPlayThread(void *b)
 {
     int done = 0;
@@ -918,10 +855,23 @@
     faacDecFrameInfo frameInfo;
 
     PlayThreadAlive = 1;
-    last_frame = 0;
+    mp4state.last_frame = 0;
 
     while (!*((int *)b))
     {
+        /* seeking */
+        if (mp4state.seek_needed != -1)
+        {
+            int ms;
+
+            /* Round off to a second */
+            ms = mp4state.seek_needed - (mp4state.seek_needed%1000);
+            module.outMod->Flush(mp4state.decode_pos_ms);
+            aac_seek(ms);
+            mp4state.decode_pos_ms = ms;
+            mp4state.seek_needed = -1;
+        }
+
         if (done)
         {
             module.outMod->CanWrite();
@@ -934,11 +884,10 @@
             }
 
             Sleep(10);
-        }
-        else if (module.outMod->CanWrite() >=
+        } else if (module.outMod->CanWrite() >=
             ((1024*mp4state.channels*sizeof(short))<<(module.dsp_isactive()?1:0)))
         {
-            if(last_frame)
+            if (mp4state.last_frame)
             {
                 done = 1;
             } else {
@@ -947,7 +896,7 @@
 
                 do
                 {
-                    if (mp4state.bytes_consumed>0)
+                    if (mp4state.bytes_consumed > 0)
                     {
                         if (mp4state.bytes_into_buffer)
                         {
@@ -983,9 +932,9 @@
                         if (mp4state.bytes_read < mp4state.filesize)
                         {
                             show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
-                            last_frame = 1;
+                            mp4state.last_frame = 1;
                         } else {
-                            last_frame = 1;
+                            mp4state.last_frame = 1;
                         }
                     }
 
@@ -997,6 +946,14 @@
 
                 if (!killPlayThread && (frameInfo.samples > 0))
                 {
+                    if (res_table[m_resolution] == 24)
+                    {
+                        /* convert libfaad output (3 bytes packed in 4 bytes) */
+                        char *temp_buffer = convert3in4to3in3(sample_buffer, frameInfo.samples);
+                        memcpy((void*)sample_buffer, (void*)temp_buffer, frameInfo.samples*3);
+                        free(temp_buffer);
+                    }
+
                     module.SAAddPCMData(sample_buffer, mp4state.channels, res_table[m_resolution],
                         mp4state.decode_pos_ms);
                     module.VSAAddPCMData(sample_buffer, mp4state.channels, res_table[m_resolution],
@@ -1021,6 +978,13 @@
         }
     }
 
+    if (mp4state.seek_table)
+    {
+        free(mp4state.seek_table);
+        mp4state.seek_table = NULL;
+        mp4state.seek_table_len = 0;
+    }
+
 	PlayThreadAlive = 0;
 	
     return 0;
@@ -1029,7 +993,7 @@
 static In_Module module =
 {
     IN_VER,
-    "AudioCoding.com MPEG-4 General Audio player: " __DATE__,
+    "AudioCoding.com MPEG-4 General Audio player: " FAAD2_VERSION,
     0,  // hMainWindow
     0,  // hDllInstance
     "MP4\0MPEG-4 Files (*.MP4)\0AAC\0AAC Files (*.AAC)\0"
--- a/plugins/in_mp4/in_mp4.dsp
+++ b/plugins/in_mp4/in_mp4.dsp
@@ -92,6 +92,10 @@
 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
 # Begin Source File
 
+SOURCE=.\aacinfo.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\config.c
 # End Source File
 # Begin Source File
@@ -106,6 +110,10 @@
 # Begin Group "Header Files"
 
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\aacinfo.h
+# End Source File
 # Begin Source File
 
 SOURCE=.\config.h
--- a/plugins/in_mp4/in_mp4.rc
+++ b/plugins/in_mp4/in_mp4.rc
@@ -1,4 +1,4 @@
-//Microsoft Developer Studio generated resource script.
+// Microsoft Visual C++ generated resource script.
 //
 #include "resource.h"
 
@@ -27,18 +27,18 @@
 // TEXTINCLUDE
 //
 
-1 TEXTINCLUDE DISCARDABLE 
+1 TEXTINCLUDE 
 BEGIN
     "resource.h\0"
 END
 
-2 TEXTINCLUDE DISCARDABLE 
+2 TEXTINCLUDE 
 BEGIN
     "#include ""afxres.h""\r\n"
     "\0"
 END
 
-3 TEXTINCLUDE DISCARDABLE 
+3 TEXTINCLUDE 
 BEGIN
     "\r\n"
     "\0"
@@ -52,58 +52,43 @@
 // Dialog
 //
 
-IDD_INFO DIALOG DISCARDABLE  0, 0, 191, 207
-STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+IDD_INFO DIALOGEX 0, 0, 303, 207
+STYLE DS_SETFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
 CAPTION "MPEG-4 File Info"
-FONT 8, "MS Sans Serif"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
 BEGIN
-    DEFPUSHBUTTON   "OK",IDOK,134,186,50,14
-    LTEXT           "Type:",IDC_STATIC,14,22,19,8
-    LTEXT           "Average bitrate:",IDC_STATIC,14,48,51,8
-    LTEXT           "Duration:",IDC_STATIC,14,35,30,8
-    LTEXT           "Samplerate:",IDC_STATIC,14,61,38,8
-    GROUPBOX        "MPEG-4 Audio Track",IDC_STATIC,7,7,177,84
-    LTEXT           "n/a",IDC_TYPE,71,22,102,8
-    LTEXT           "n/a",IDC_BITRATE,71,48,102,8
-    LTEXT           "n/a",IDC_DURATION,71,35,102,8
-    LTEXT           "n/a",IDC_SAMPLERATE,71,61,102,8
-    LTEXT           "Type:",IDC_STATIC,14,113,19,8
-    LTEXT           "Average bitrate:",IDC_STATIC,14,139,51,8
-    LTEXT           "Duration:",IDC_STATIC,14,126,30,8
-    LTEXT           "Size:",IDC_STATIC,14,152,16,8
-    GROUPBOX        "MPEG-4 Video Track",IDC_STATIC,7,98,177,84
-    LTEXT           "n/a",IDC_VTYPE,71,113,102,8
-    LTEXT           "n/a",IDC_VBITRATE,71,139,102,8
-    LTEXT           "n/a",IDC_VDURATION,71,126,102,8
-    LTEXT           "n/a",IDC_VSIZE,71,152,102,8
-    LTEXT           "Frames/second:",IDC_STATIC,14,165,52,8
-    LTEXT           "n/a",IDC_VFPS,71,165,102,8
-    LTEXT           "Channels:",IDC_STATIC,14,74,32,8
-    LTEXT           "n/a",IDC_CHANNELS,71,74,102,8
+    DEFPUSHBUTTON   "OK",IDOK,246,186,50,14
+    LTEXT           "Static",IDC_INFOTEXT,14,17,275,47,0,WS_EX_CLIENTEDGE
+    GROUPBOX        "Track info",IDC_STATIC,7,7,289,64
+    GROUPBOX        "User data",IDC_STATIC,7,77,289,104
 END
 
-IDD_CONFIG DIALOG DISCARDABLE  0, 0, 125, 95
-STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+IDD_CONFIG DIALOGEX 0, 0, 151, 108
+STYLE DS_SETFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
 CAPTION "Configuration"
-FONT 8, "MS Sans Serif"
+FONT 8, "MS Sans Serif", 0, 0, 0x0
 BEGIN
     CONTROL         "Slider1",IDC_PRIORITY,"msctls_trackbar32",TBS_VERT | 
-                    TBS_NOTICKS | WS_TABSTOP,13,15,18,39
+                    TBS_NOTICKS | WS_TABSTOP,13,15,18,46
     CONTROL         "16 bits",IDC_16BITS,"Button",BS_AUTORADIOBUTTON,77,18,
                     37,10
-    CONTROL         "24 bits",IDC_24BITS,"Button",BS_AUTORADIOBUTTON | 
-                    WS_DISABLED,77,30,37,10
-    CONTROL         "32 bits",IDC_32BITS,"Button",BS_AUTORADIOBUTTON,77,42,
+    CONTROL         "24 bits",IDC_24BITS,"Button",BS_AUTORADIOBUTTON,77,40,
                     37,10
+    CONTROL         "32 bits",IDC_32BITS,"Button",BS_AUTORADIOBUTTON,77,51,
+                    37,10
     CONTROL         "Show errors",IDC_ERROR,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,7,60,53,10
-    DEFPUSHBUTTON   "OK",IDOK,68,74,50,14
-    PUSHBUTTON      "Cancel",IDCANCEL,7,74,50,14
-    GROUPBOX        "Priority",IDC_STATIC,7,7,57,49
+                    WS_TABSTOP,7,70,53,10
+    DEFPUSHBUTTON   "OK",IDOK,94,87,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,7,87,50,14
+    GROUPBOX        "Priority",IDC_STATIC,7,7,57,58
     LTEXT           "Highest",IDC_STATIC,34,18,25,8
-    LTEXT           "Normal",IDC_STATIC,34,29,23,8
-    LTEXT           "Lowest",IDC_STATIC,34,40,24,8
-    GROUPBOX        "Resolution",IDC_STATIC,71,7,47,49
+    LTEXT           "Normal",IDC_STATIC,34,35,23,8
+    LTEXT           "Lowest",IDC_STATIC,34,52,24,8
+    GROUPBOX        "Resolution",IDC_STATIC,71,7,73,58
+    CONTROL         "16 bits dithered",IDC_16BITS_DITHERED,"Button",
+                    BS_AUTORADIOBUTTON,77,29,64,10
 END
 
 
@@ -113,12 +98,12 @@
 //
 
 #ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO DISCARDABLE 
+GUIDELINES DESIGNINFO 
 BEGIN
     IDD_INFO, DIALOG
     BEGIN
         LEFTMARGIN, 7
-        RIGHTMARGIN, 184
+        RIGHTMARGIN, 296
         TOPMARGIN, 7
         BOTTOMMARGIN, 200
     END
@@ -126,9 +111,9 @@
     IDD_CONFIG, DIALOG
     BEGIN
         LEFTMARGIN, 7
-        RIGHTMARGIN, 118
+        RIGHTMARGIN, 144
         TOPMARGIN, 7
-        BOTTOMMARGIN, 88
+        BOTTOMMARGIN, 101
     END
 END
 #endif    // APSTUDIO_INVOKED
--- a/plugins/in_mp4/in_mp4.vcproj
+++ b/plugins/in_mp4/in_mp4.vcproj
@@ -135,6 +135,9 @@
 			Name="Source Files"
 			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
 			<File
+				RelativePath="aacinfo.c">
+			</File>
+			<File
 				RelativePath=".\config.c">
 			</File>
 			<File
@@ -148,6 +151,9 @@
 			Name="Header Files"
 			Filter="h;hpp;hxx;hm;inl">
 			<File
+				RelativePath="aacinfo.h">
+			</File>
+			<File
 				RelativePath=".\config.h">
 			</File>
 			<File
@@ -158,6 +164,9 @@
 			</File>
 			<File
 				RelativePath=".\out.h">
+			</File>
+			<File
+				RelativePath="resource.h">
 			</File>
 			<File
 				RelativePath=".\utils.h">
--- a/plugins/in_mp4/resource.h
+++ b/plugins/in_mp4/resource.h
@@ -1,10 +1,11 @@
 //{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
+// Microsoft Visual C++ generated include file.
 // Used by in_mp4.rc
 //
 #define IDD_INFO                        101
 #define IDD_CONFIG                      102
 #define IDC_TYPE                        1000
+#define IDC_INFOTEXT                    1000
 #define IDC_DURATION                    1001
 #define IDC_BITRATE                     1002
 #define IDC_SAMPLERATE                  1003
@@ -19,6 +20,8 @@
 #define IDC_VFPS                        1008
 #define IDC_32BITS                      1008
 #define IDC_CHANNELS                    1009
+#define IDC_24BITS2                     1009
+#define IDC_16BITS_DITHERED             1009
 
 // Next default values for new objects
 // 
--- a/plugins/in_mp4/utils.c
+++ b/plugins/in_mp4/utils.c
@@ -16,7 +16,7 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: utils.c,v 1.1 2002/08/09 21:48:12 menno Exp $
+** $Id: utils.c,v 1.2 2002/08/14 17:55:20 menno Exp $
 **/
 
 #define WIN32_LEAN_AND_MEAN
@@ -130,4 +130,20 @@
     }
 
     return (LPTSTR)pT;   // const -> non const
+}
+
+char *convert3in4to3in3(void *sample_buffer, int samples)
+{
+    int i;
+    long *sample_buffer24 = (long*)sample_buffer;
+    char *data = malloc(samples*3*sizeof(char));
+
+    for (i = 0; i < samples; i++)
+    {
+        data[i*3] = sample_buffer24[i] & 0xFF;
+        data[i*3+1] = (sample_buffer24[i] >> 8) & 0xFF;
+        data[i*3+2] = (sample_buffer24[i] >> 16) & 0xFF;
+    }
+
+    return data;
 }
--- a/plugins/in_mp4/utils.h
+++ b/plugins/in_mp4/utils.h
@@ -16,11 +16,19 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: utils.h,v 1.1 2002/08/09 21:48:12 menno Exp $
+** $Id: utils.h,v 1.2 2002/08/14 17:55:20 menno Exp $
 **/
 
+#ifndef UTILS_INCLUDED
+#define UTILS_INCLUDED
+
+#include <mp4.h>
+
 LPTSTR PathFindFileName(LPCTSTR pPath);
 int GetVideoTrack(MP4FileHandle infile);
 int GetAudioTrack(MP4FileHandle infile);
 int GetAACTrack(MP4FileHandle infile);
 int StringComp(char const *str1, char const *str2, unsigned long len);
+char *convert3in4to3in3(void *sample_buffer, int samples);
+
+#endif
\ No newline at end of file