shithub: aacdec

Download patch

ref: b402e6771bfad52a2d4170a090e2feaf753daa78
parent: 7390d86a7e1c5e8be663396278c6ec3eef34168c
author: menno <menno>
date: Fri Aug 9 17:48:12 EDT 2002

Minimalistic AAC support for mp4 winamp plugin

--- /dev/null
+++ b/plugins/in_mp4/config.c
@@ -1,0 +1,38 @@
+/*
+** 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: config.c,v 1.1 2002/08/09 21:48:12 menno Exp $
+**/
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "config.h"
+
+char app_name[] = "AudioCoding.com MPEG-4 General Audio player";
+char INI_FILE[MAX_PATH];
+int m_priority = 3;
+int m_resolution = 0;
+int m_show_errors = 1;
+
+void _r_s(char *name,char *data, int mlen)
+{
+	char buf[10];
+	strcpy(buf,data);
+	GetPrivateProfileString(app_name,name,buf,data,mlen,INI_FILE);
+}
+
--- /dev/null
+++ b/plugins/in_mp4/config.h
@@ -1,0 +1,32 @@
+/*
+** 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: config.h,v 1.1 2002/08/09 21:48:12 menno Exp $
+**/
+
+char app_name[];
+char INI_FILE[];
+int m_priority;
+int m_resolution;
+int m_show_errors;
+
+#define RS(x) (_r_s(#x,x,sizeof(x)))
+#define WS(x) (WritePrivateProfileString(app_name,#x,x,INI_FILE))
+
+void _r_s(char *name,char *data, int mlen);
+
--- 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.12 2002/08/07 08:14:31 menno Exp $
+** $Id: in_mp4.c,v 1.13 2002/08/09 21:48:12 menno Exp $
 **/
 
 #define WIN32_LEAN_AND_MEAN
@@ -28,8 +28,9 @@
 
 #include "resource.h"
 #include "in2.h"
+#include "utils.h"
+#include "config.h"
 
-static char app_name[] = "AudioCoding.com MPEG-4 General Audio player";
 static long priority_table[] = {
     0,
     THREAD_PRIORITY_HIGHEST,
@@ -55,11 +56,8 @@
 
 typedef struct state
 {
+    /* general stuff */
     faacDecHandle hDecoder;
-    MP4FileHandle mp4file;
-    int mp4track;
-    MP4SampleId numSamples;
-    MP4SampleId sampleId;
     int samplerate;
     unsigned char channels;
     int decode_pos_ms; // current decoding position, in milliseconds
@@ -66,13 +64,24 @@
     int paused; // are we paused?
     int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.
     char filename[_MAX_PATH];
-} state;
+    int filetype; /* 0: MP4; 1: AAC */
 
-static char INI_FILE[MAX_PATH];
-static int m_priority = 3;
-static int m_resolution = 0;
-static int m_show_errors = 1;
+    /* MP4 stuff */
+    MP4FileHandle mp4file;
+    int mp4track;
+    MP4SampleId numSamples;
+    MP4SampleId sampleId;
 
+    /* AAC stuff */
+    FILE *aacfile;
+    long filesize;
+    long bytes_read;
+    long bytes_into_buffer;
+    long bytes_consumed;
+    unsigned char *buffer;
+    long lengthMs;
+} state;
+
 static state mp4state;
 
 static In_Module module; // the output module (declared near the bottom of this file)
@@ -82,124 +91,19 @@
 HANDLE play_thread_handle = INVALID_HANDLE_VALUE; // the handle to the decode thread
 
 /* Function definitions */
-DWORD WINAPI PlayThread(void *b); // the decode thread procedure
+DWORD WINAPI MP4PlayThread(void *b); // the decode thread procedure
+DWORD WINAPI AACPlayThread(void *b); // the decode thread procedure
 
-void show_error(HWND hwnd, char *message, ...)
+static void show_error(HWND hwnd, char *message, ...)
 {
     if (m_show_errors)
         MessageBox(hwnd, message, "Error", MB_OK);
 }
 
-int StringComp(char const *str1, char const *str2, unsigned long len)
-{
-    signed int c1 = 0, c2 = 0;
-
-    while (len--)
-    {
-        c1 = *str1++;
-        c2 = *str2++;
-
-        if (c1 == 0 || c1 != c2)
-            break;
-    }
-
-    return c1 - c2;
-}
-
-int GetAACTrack(MP4FileHandle infile)
-{
-    /* find AAC track */
-    int i, rc;
-	int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
-
-	for (i = 0; i < numTracks; i++)
-    {
-        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
-        const char* trackType = MP4GetTrackType(infile, trackId);
-
-        if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE))
-        {
-            unsigned char *buff = NULL;
-            int buff_size = 0;
-            unsigned char dummy2_8, dummy3_8, dummy4_8, dummy5_8, dummy6_8,
-                dummy7_8, dummy8_8;
-            unsigned int dummy1_32;
-            MP4GetTrackESConfiguration(infile, trackId, &buff, &buff_size);
-
-            if (buff)
-            {
-                rc = AudioSpecificConfig(buff, &dummy1_32, &dummy2_8, &dummy3_8, &dummy4_8,
-                    &dummy5_8, &dummy6_8, &dummy7_8, &dummy8_8);
-                free(buff);
-
-                if (rc < 0)
-                    return -1;
-                return trackId;
-            }
-        }
-    }
-
-    /* can't decode this */
-    return -1;
-}
-
-int GetAudioTrack(MP4FileHandle infile)
-{
-    /* find AAC track */
-    int i;
-	int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
-
-	for (i = 0; i < numTracks; i++)
-    {
-        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
-        const char* trackType = MP4GetTrackType(infile, trackId);
-
-        if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE))
-        {
-            return trackId;
-        }
-    }
-
-    /* can't decode this */
-    return -1;
-}
-
-int GetVideoTrack(MP4FileHandle infile)
-{
-    /* find AAC track */
-    int i;
-	int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
-
-	for (i = 0; i < numTracks; i++)
-    {
-        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
-        const char* trackType = MP4GetTrackType(infile, trackId);
-
-        if (!strcmp(trackType, MP4_VIDEO_TRACK_TYPE))
-        {
-            return trackId;
-        }
-    }
-
-    /* can't decode this */
-    return -1;
-}
-
-static void _r_s(char *name,char *data, int mlen)
-{
-	char buf[10];
-	strcpy(buf,data);
-	GetPrivateProfileString(app_name,name,buf,data,mlen,INI_FILE);
-}
-#define RS(x) (_r_s(#x,x,sizeof(x)))
-#define WS(x) (WritePrivateProfileString(app_name,#x,x,INI_FILE))
-
-
-
 static void config_init()
 {
 	char *p=INI_FILE;
-	GetModuleFileName(NULL,INI_FILE,sizeof(INI_FILE));
+	GetModuleFileName(NULL,INI_FILE,_MAX_PATH);
 	while (*p) p++;
 	while (p >= INI_FILE && *p != '.') p--;
 	strcpy(p+1,"ini");
@@ -250,8 +154,8 @@
 {
 }
 
-BOOL CALLBACK info_dialog_proc(HWND hwndDlg, UINT message,
-                               WPARAM wParam, LPARAM lParam)
+BOOL CALLBACK mp4_info_dialog_proc(HWND hwndDlg, UINT message,
+                                   WPARAM wParam, LPARAM lParam)
 {
     int i, width, height, numFrames;
     unsigned char ch, sf, dummy8;
@@ -466,10 +370,19 @@
 
 int infoDlg(char *fn, HWND hwndParent)
 {
-    lstrcpy(info_fn, fn);
+    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);
+    } else {
+        lstrcpy(info_fn, fn);
 
-    DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
-        hwndParent, info_dialog_proc);
+        DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
+            hwndParent, mp4_info_dialog_proc);
+    }
 
     return 0;
 }
@@ -539,6 +452,10 @@
     {
         return 1;
     }
+    if(StringComp(fn + strlen(fn) - 3, "aac", 3) == 0)
+    {
+        return 1;
+    }
 
     return 0;
 }
@@ -556,45 +473,121 @@
 
     mp4state.channels = 0;
     mp4state.samplerate = 0;
+    mp4state.filetype = 0;
 
     strcpy(mp4state.filename, fn);
 
-    mp4state.mp4file = MP4Read(fn, 0);
-    if (!mp4state.mp4file)
+    if(StringComp(fn + strlen(fn) - 3, "aac", 3) == 0)
+        mp4state.filetype = 1;
+
+    mp4state.hDecoder = faacDecOpen();
+    if (!mp4state.hDecoder)
     {
-        show_error(module.hMainWindow, "Unable to open file.");
+        show_error(module.hMainWindow, "Unable to open decoder library.");
         return -1;
     }
 
-    if ((mp4state.mp4track = GetAACTrack(mp4state.mp4file)) < 0)
+    if (mp4state.filetype)
     {
-        show_error(module.hMainWindow, "Unsupported Audio track type.");
-        MP4Close(mp4state.mp4file);
-        return -1;
-    }
+        long pos, tmp, read;
 
-    mp4state.hDecoder = faacDecOpen();
+        mp4state.aacfile = fopen(fn, "rb");
+        if (!mp4state.aacfile)
+        {
+            show_error(module.hMainWindow, "Unable to open file.");
+            faacDecClose(mp4state.hDecoder);
+            return -1;
+        }
 
-    buffer = NULL;
-    buffer_size = 0;
-    MP4GetTrackESConfiguration(mp4state.mp4file, mp4state.mp4track,
-        &buffer, &buffer_size);
-    if (!buffer)
-    {
-        faacDecClose(mp4state.hDecoder);
-        MP4Close(mp4state.mp4file);
-        return -1;
-    }
+        pos = ftell(mp4state.aacfile);
+        fseek(mp4state.aacfile, 0, SEEK_END);
+        mp4state.filesize = ftell(mp4state.aacfile);
+        fseek(mp4state.aacfile, pos, SEEK_SET);
 
-    if(faacDecInit2(mp4state.hDecoder, buffer, buffer_size,
-                    &mp4state.samplerate, &mp4state.channels) < 0)
-    {
-        /* If some error initializing occured, skip the file */
-        faacDecClose(mp4state.hDecoder);
-        MP4Close(mp4state.mp4file);
-        return -1;
+        if(!(mp4state.buffer=(unsigned char*)malloc(768*48)))
+        {
+            show_error(module.hMainWindow, "Memory allocation error.");
+            faacDecClose(mp4state.hDecoder);
+            fclose(mp4state.aacfile);
+            return -1;
+        }
+        memset(mp4state.buffer, 0, 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)
+        {
+            mp4state.bytes_read = read;
+            mp4state.bytes_into_buffer = read;
+        } else {
+            show_error(module.hMainWindow, "Error reading from file.");
+            faacDecClose(mp4state.hDecoder);
+            fclose(mp4state.aacfile);
+            return -1;
+        }
+
+        if((mp4state.bytes_consumed=faacDecInit(mp4state.hDecoder,
+            mp4state.buffer, &mp4state.samplerate, &mp4state.channels)) < 0)
+        {
+            show_error(module.hMainWindow, "Can't initialize library.");
+            faacDecClose(mp4state.hDecoder);
+            fclose(mp4state.aacfile);
+            return -1;
+        }
+        mp4state.bytes_into_buffer -= mp4state.bytes_consumed;
+
+        avg_bitrate = 0;
+
+        module.is_seekable = 0;
+    } else {
+        mp4state.mp4file = MP4Read(fn, 0);
+        if (!mp4state.mp4file)
+        {
+            show_error(module.hMainWindow, "Unable to open file.");
+            faacDecClose(mp4state.hDecoder);
+            return -1;
+        }
+
+        if ((mp4state.mp4track = GetAACTrack(mp4state.mp4file)) < 0)
+        {
+            show_error(module.hMainWindow, "Unsupported Audio track type.");
+            faacDecClose(mp4state.hDecoder);
+            MP4Close(mp4state.mp4file);
+            return -1;
+        }
+
+        buffer = NULL;
+        buffer_size = 0;
+        MP4GetTrackESConfiguration(mp4state.mp4file, mp4state.mp4track,
+            &buffer, &buffer_size);
+        if (!buffer)
+        {
+            faacDecClose(mp4state.hDecoder);
+            MP4Close(mp4state.mp4file);
+            return -1;
+        }
+
+        if(faacDecInit2(mp4state.hDecoder, buffer, buffer_size,
+            &mp4state.samplerate, &mp4state.channels) < 0)
+        {
+            /* If some error initializing occured, skip the file */
+            faacDecClose(mp4state.hDecoder);
+            MP4Close(mp4state.mp4file);
+            return -1;
+        }
+        free(buffer);
+
+        avg_bitrate = MP4GetTrackIntegerProperty(mp4state.mp4file, mp4state.mp4track,
+            "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.avgBitrate");
+
+        mp4state.numSamples = MP4GetTrackNumberOfSamples(mp4state.mp4file, mp4state.mp4track);
+        mp4state.sampleId = 1;
+
+        module.is_seekable = 1;
     }
-    free(buffer);
 
     config = faacDecGetCurrentConfiguration(mp4state.hDecoder);
     config->outputFormat = m_resolution + 1;
@@ -604,7 +597,10 @@
     {
         show_error(module.hMainWindow, "Number of channels not supported for playback.");
         faacDecClose(mp4state.hDecoder);
-        MP4Close(mp4state.mp4file);
+        if (mp4state.filetype)
+            fclose(mp4state.aacfile);
+        else
+            MP4Close(mp4state.mp4file);
         return -1;
     }
 
@@ -613,22 +609,17 @@
     if (maxlatency < 0) // error opening device
     {
         faacDecClose(mp4state.hDecoder);
-        MP4Close(mp4state.mp4file);
+        if (mp4state.filetype)
+            fclose(mp4state.aacfile);
+        else
+            MP4Close(mp4state.mp4file);
         return -1;
     }
 
-    avg_bitrate = MP4GetTrackIntegerProperty(mp4state.mp4file, mp4state.mp4track,
-        "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.avgBitrate");
-
-    mp4state.numSamples = MP4GetTrackNumberOfSamples(mp4state.mp4file, mp4state.mp4track);
-    mp4state.sampleId = 1;
-
     mp4state.paused        =  0;
     mp4state.decode_pos_ms =  0;
     mp4state.seek_needed   = -1;
 
-    module.is_seekable = 1;
-
     // initialize vis stuff
     module.SAVSAInit(maxlatency, mp4state.samplerate);
     module.VSASetInfo(mp4state.samplerate, mp4state.channels);
@@ -639,12 +630,25 @@
 
     killPlayThread = 0;
 
-    if((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlayThread, (void *)&killPlayThread, 0, &thread_id)) == NULL)
+    if (mp4state.filetype)
     {
-        show_error(module.hMainWindow, "Cannot create playback thread");
-        faacDecClose(mp4state.hDecoder);
-        MP4Close(mp4state.mp4file);
-        return -1;
+        if((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AACPlayThread,
+            (void *)&killPlayThread, 0, &thread_id)) == NULL)
+        {
+            show_error(module.hMainWindow, "Cannot create playback thread");
+            faacDecClose(mp4state.hDecoder);
+            fclose(mp4state.aacfile);
+            return -1;
+        }
+    } else {
+        if((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MP4PlayThread,
+            (void *)&killPlayThread, 0, &thread_id)) == NULL)
+        {
+            show_error(module.hMainWindow, "Cannot create playback thread");
+            faacDecClose(mp4state.hDecoder);
+            MP4Close(mp4state.mp4file);
+            return -1;
+        }
     }
 
     if (m_priority != 3)
@@ -693,7 +697,10 @@
     }
 
     faacDecClose(mp4state.hDecoder);
-    MP4Close(mp4state.mp4file);
+    if (mp4state.filetype)
+        fclose(mp4state.aacfile);
+    else
+        MP4Close(mp4state.mp4file);
     module.outMod->Close();
     module.SAVSADeInit();
 }
@@ -700,48 +707,56 @@
 
 int getsonglength(char *fn)
 {
-    int track;
-    long msDuration;
-	MP4Duration length;
-    MP4FileHandle file;
+    long msDuration = 0;
 
-    file = MP4Read(fn, 0);
-    if (!file)
-        return 0;
-
-    if ((track = GetAACTrack(file)) < 0)
+    if(StringComp(fn + strlen(fn) - 3, "mp4", 3) == 0)
     {
-        MP4Close(file);
-        return -1;
-    }
+        int track;
+        MP4Duration length;
+        MP4FileHandle file;
 
-    length = MP4GetTrackDuration(file, track);
+        file = MP4Read(fn, 0);
+        if (!file)
+            return 0;
 
-	msDuration = MP4ConvertFromTrackDuration(file, track,
-        length, MP4_MSECS_TIME_SCALE);
+        if ((track = GetAACTrack(file)) < 0)
+        {
+            MP4Close(file);
+            return -1;
+        }
 
-    MP4Close(file);
+        length = MP4GetTrackDuration(file, track);
 
+        msDuration = MP4ConvertFromTrackDuration(file, track,
+            length, MP4_MSECS_TIME_SCALE);
+
+        MP4Close(file);
+    }
+
     return msDuration;
 }
 
 int getlength()
 {
-    int track;
-    long msDuration;
-	MP4Duration length;
-
-    if ((track = GetAACTrack(mp4state.mp4file)) < 0)
+    if (!mp4state.filetype)
     {
-        return -1;
-    }
+        int track;
+        long msDuration;
+        MP4Duration length;
 
-    length = MP4GetTrackDuration(mp4state.mp4file, track);
+        if ((track = GetAACTrack(mp4state.mp4file)) < 0)
+        {
+            return -1;
+        }
 
-	msDuration = MP4ConvertFromTrackDuration(mp4state.mp4file, track,
-        length, MP4_MSECS_TIME_SCALE);
+        length = MP4GetTrackDuration(mp4state.mp4file, track);
 
-    return msDuration;
+        msDuration = MP4ConvertFromTrackDuration(mp4state.mp4file, track,
+            length, MP4_MSECS_TIME_SCALE);
+
+        return msDuration;
+    }
+    return 0;
 }
 
 int getoutputtime()
@@ -754,18 +769,6 @@
     mp4state.seek_needed = time_in_ms;
 }
 
-LPTSTR PathFindFileName(LPCTSTR pPath)
-{
-    LPCTSTR pT;
-
-    for (pT = pPath; *pPath; pPath = CharNext(pPath)) {
-        if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':')) && pPath[1] && (pPath[1] != TEXT('\\')))
-            pT = pPath + 1;
-    }
-
-    return (LPTSTR)pT;   // const -> non const
-}
-
 void getfileinfo(char *filename, char *title, int *length_in_ms)
 {
     if (!filename || !*filename)  /* currently playing file */
@@ -779,7 +782,7 @@
             strcpy(title, tmp);
         }
     }
-    else // some other file
+    else /* some other file */
     {
         if (length_in_ms)
             *length_in_ms = getsonglength(filename);
@@ -798,14 +801,10 @@
 
 int last_frame;
 
-DWORD WINAPI PlayThread(void *b)
+DWORD WINAPI MP4PlayThread(void *b)
 {
     int done = 0;
     int l;
-	int decoded_frames=0;
-	int br_calc_frames=0;
-	int br_bytes_consumed=0;
-    unsigned long bytesconsumed;
 
     void *sample_buffer;
     unsigned char *buffer;
@@ -900,13 +899,128 @@
                     module.outMod->Write(sample_buffer, l);
                 }
             }
+        } else {
+            Sleep(10);
         }
-        else
+    }
+
+	PlayThreadAlive = 0;
+	
+    return 0;
+}
+
+DWORD WINAPI AACPlayThread(void *b)
+{
+    int done = 0;
+    int l;
+
+    void *sample_buffer;
+    faacDecFrameInfo frameInfo;
+
+    PlayThreadAlive = 1;
+    last_frame = 0;
+
+    while (!*((int *)b))
+    {
+        if (done)
         {
+            module.outMod->CanWrite();
+
+            if (!module.outMod->IsPlaying())
+            {
+                PostMessage(module.hMainWindow, WM_WA_AAC_EOF, 0, 0);
+                PlayThreadAlive = 0;
+                return 0;
+            }
+
             Sleep(10);
         }
-    }
+        else if (module.outMod->CanWrite() >=
+            ((1024*mp4state.channels*sizeof(short))<<(module.dsp_isactive()?1:0)))
+        {
+            if(last_frame)
+            {
+                done = 1;
+            } else {
+                long tmp, read;
+                unsigned char *buffer = mp4state.buffer;
+
+                do
+                {
+                    if (mp4state.bytes_consumed>0)
+                    {
+                        if (mp4state.bytes_into_buffer)
+                        {
+                            memcpy(buffer, buffer+mp4state.bytes_consumed,
+                                mp4state.bytes_into_buffer);
+                        }
+
+                        if (mp4state.bytes_read < mp4state.filesize)
+                        {
+                            if (mp4state.bytes_read + mp4state.bytes_consumed < mp4state.filesize)
+                                tmp = mp4state.bytes_consumed;
+                            else
+                                tmp = mp4state.filesize - mp4state.bytes_read;
+                            read = fread(buffer + mp4state.bytes_into_buffer, 1, tmp, mp4state.aacfile);
+                            if (read == tmp)
+                            {
+                                mp4state.bytes_read += read;
+                                mp4state.bytes_into_buffer += read;
+                            }
+                        } else {
+                            if (mp4state.bytes_into_buffer)
+                            {
+                                memset(buffer + mp4state.bytes_into_buffer, 0,
+                                    mp4state.bytes_consumed);
+                            }
+                        }
+
+                        mp4state.bytes_consumed = 0;
+                    }
 
+                    if (mp4state.bytes_into_buffer < 1)
+                    {
+                        if (mp4state.bytes_read < mp4state.filesize)
+                        {
+                            show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
+                            last_frame = 1;
+                        } else {
+                            last_frame = 1;
+                        }
+                    }
+
+                    sample_buffer = faacDecDecode(mp4state.hDecoder, &frameInfo, buffer);
+
+                    mp4state.bytes_consumed += frameInfo.bytesconsumed;
+                    mp4state.bytes_into_buffer -= mp4state.bytes_consumed;
+                } while (!frameInfo.samples && !frameInfo.error);
+
+                if (!killPlayThread && (frameInfo.samples > 0))
+                {
+                    module.SAAddPCMData(sample_buffer, mp4state.channels, res_table[m_resolution],
+                        mp4state.decode_pos_ms);
+                    module.VSAAddPCMData(sample_buffer, mp4state.channels, res_table[m_resolution],
+                        mp4state.decode_pos_ms);
+                    mp4state.decode_pos_ms += (1024*1000)/mp4state.samplerate;
+
+                    if (module.dsp_isactive())
+                    {
+                        l = module.dsp_dosamples((short*)sample_buffer,
+                            frameInfo.samples*sizeof(short)/mp4state.channels/(res_table[m_resolution]/8),
+                            res_table[m_resolution],
+                            mp4state.channels,mp4state.samplerate)*(mp4state.channels*(res_table[m_resolution]/8));
+                    } else {
+                        l = frameInfo.samples*(res_table[m_resolution]/8);
+                    }
+
+                    module.outMod->Write(sample_buffer, l);
+                }
+            }
+        } else {
+            Sleep(10);
+        }
+    }
+
 	PlayThreadAlive = 0;
 	
     return 0;
@@ -918,7 +1032,7 @@
     "AudioCoding.com MPEG-4 General Audio player: " __DATE__,
     0,  // hMainWindow
     0,  // hDllInstance
-    "MP4\0MPEG-4 Files (*.MP4)\0"
+    "MP4\0MPEG-4 Files (*.MP4)\0AAC\0AAC Files (*.AAC)\0"
     ,
     1, // is_seekable
     1, // uses output
--- a/plugins/in_mp4/in_mp4.dsp
+++ b/plugins/in_mp4/in_mp4.dsp
@@ -92,8 +92,16 @@
 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
 # Begin Source File
 
+SOURCE=.\config.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\in_mp4.c
 # End Source File
+# Begin Source File
+
+SOURCE=.\utils.c
+# End Source File
 # End Group
 # Begin Group "Header Files"
 
@@ -100,6 +108,10 @@
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
+SOURCE=.\config.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\include\faad.h
 # End Source File
 # Begin Source File
@@ -109,6 +121,10 @@
 # Begin Source File
 
 SOURCE=.\out.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\utils.h
 # End Source File
 # End Group
 # Begin Group "Resource Files"
--- /dev/null
+++ b/plugins/in_mp4/utils.c
@@ -1,0 +1,133 @@
+/*
+** 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: utils.c,v 1.1 2002/08/09 21:48:12 menno Exp $
+**/
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mp4.h>
+#include <faad.h>
+#include "utils.h"
+
+int StringComp(char const *str1, char const *str2, unsigned long len)
+{
+    signed int c1 = 0, c2 = 0;
+
+    while (len--)
+    {
+        c1 = *str1++;
+        c2 = *str2++;
+
+        if (c1 == 0 || c1 != c2)
+            break;
+    }
+
+    return c1 - c2;
+}
+
+int GetAACTrack(MP4FileHandle infile)
+{
+    /* find AAC track */
+    int i, rc;
+	int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
+
+	for (i = 0; i < numTracks; i++)
+    {
+        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
+        const char* trackType = MP4GetTrackType(infile, trackId);
+
+        if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE))
+        {
+            unsigned char *buff = NULL;
+            int buff_size = 0;
+            unsigned char dummy2_8, dummy3_8, dummy4_8, dummy5_8, dummy6_8,
+                dummy7_8, dummy8_8;
+            unsigned int dummy1_32;
+            MP4GetTrackESConfiguration(infile, trackId, &buff, &buff_size);
+
+            if (buff)
+            {
+                rc = AudioSpecificConfig(buff, &dummy1_32, &dummy2_8, &dummy3_8, &dummy4_8,
+                    &dummy5_8, &dummy6_8, &dummy7_8, &dummy8_8);
+                free(buff);
+
+                if (rc < 0)
+                    return -1;
+                return trackId;
+            }
+        }
+    }
+
+    /* can't decode this */
+    return -1;
+}
+
+int GetAudioTrack(MP4FileHandle infile)
+{
+    /* find AAC track */
+    int i;
+	int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
+
+	for (i = 0; i < numTracks; i++)
+    {
+        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
+        const char* trackType = MP4GetTrackType(infile, trackId);
+
+        if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE))
+        {
+            return trackId;
+        }
+    }
+
+    /* can't decode this */
+    return -1;
+}
+
+int GetVideoTrack(MP4FileHandle infile)
+{
+    /* find AAC track */
+    int i;
+	int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
+
+	for (i = 0; i < numTracks; i++)
+    {
+        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
+        const char* trackType = MP4GetTrackType(infile, trackId);
+
+        if (!strcmp(trackType, MP4_VIDEO_TRACK_TYPE))
+        {
+            return trackId;
+        }
+    }
+
+    /* can't decode this */
+    return -1;
+}
+
+LPTSTR PathFindFileName(LPCTSTR pPath)
+{
+    LPCTSTR pT;
+
+    for (pT = pPath; *pPath; pPath = CharNext(pPath)) {
+        if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':')) && pPath[1] && (pPath[1] != TEXT('\\')))
+            pT = pPath + 1;
+    }
+
+    return (LPTSTR)pT;   // const -> non const
+}
--- /dev/null
+++ b/plugins/in_mp4/utils.h
@@ -1,0 +1,26 @@
+/*
+** 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: utils.h,v 1.1 2002/08/09 21:48:12 menno Exp $
+**/
+
+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);