shithub: aacdec

Download patch

ref: 3501993184b7b711ab99d442ac651a6fb1310b6f
parent: 58fc702265e87f43f286f958ca79cc1a47e926ce
author: menno <menno>
date: Sun Jan 20 11:59:26 EST 2002

MPEG-4 AAC Winamp input plugin!!

diff: cannot open b/plugins/in_mp4//null: file does not exist: 'b/plugins/in_mp4//null' diff: cannot open b/plugins//null: file does not exist: 'b/plugins//null'
--- /dev/null
+++ b/plugins/in_mp4/in2.h
@@ -1,0 +1,104 @@
+#include "out.h"
+
+// note: exported symbol is now winampGetInModule2.
+
+#define IN_VER 0x100
+
+typedef struct
+{
+    int version;                // module type (IN_VER)
+    char *description;          // description of module, with version string
+
+    HWND hMainWindow;           // winamp's main window (filled in by winamp)
+    HINSTANCE hDllInstance;     // DLL instance handle (Also filled in by winamp)
+
+    char *FileExtensions;       // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
+                                // May be altered from Config, so the user can select what they want
+
+    int is_seekable;            // is this stream seekable?
+    int UsesOutputPlug;         // does this plug-in use the output plug-ins? (musn't ever change, ever :)
+
+    void (*Config)(HWND hwndParent); // configuration dialog
+    void (*About)(HWND hwndParent);  // about dialog
+
+    void (*Init)();             // called at program init
+    void (*Quit)();             // called at program quit
+
+    void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used
+    int (*InfoBox)(char *file, HWND hwndParent);
+
+    int (*IsOurFile)(char *fn); // called before extension checks, to allow detection of mms://, etc
+    // playback stuff
+    int (*Play)(char *fn);      // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error
+    void (*Pause)();            // pause stream
+    void (*UnPause)();          // unpause stream
+    int (*IsPaused)();          // ispaused? return 1 if paused, 0 if not
+    void (*Stop)();             // stop (unload) stream
+
+    // time stuff
+    int (*GetLength)();         // get length in ms
+    int (*GetOutputTime)();     // returns current output time in ms. (usually returns outMod->GetOutputTime()
+    void (*SetOutputTime)(int time_in_ms);  // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush()..
+
+    // volume stuff
+    void (*SetVolume)(int volume);  // from 0 to 255.. usually just call outMod->SetVolume
+    void (*SetPan)(int pan);    // from -127 to 127.. usually just call outMod->SetPan
+
+    // in-window builtin vis stuff
+
+    void (*SAVSAInit)(int maxlatency_in_ms, int srate);     // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
+    // call after opening audio device with max latency in ms and samplerate
+    void (*SAVSADeInit)();  // call in Stop()
+
+
+    // simple vis supplying mode
+    void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp);
+                                            // sets the spec data directly from PCM data
+                                            // quick and easy way to get vis working :)
+                                            // needs at least 576 samples :)
+
+    // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
+    int (*SAGetMode)();     // gets csa (the current type (4=ws,2=osc,1=spec))
+                            // use when calling SAAdd()
+    void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp
+
+
+    // vis stuff (plug-in)
+    // simple vis supplying mode
+    void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
+                                            // quick and easy way to get vis working :)
+                                            // needs at least 576 samples :)
+
+    // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
+    int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd
+    void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in
+
+
+    // call this in Play() to tell the vis plug-ins the current output params.
+    void (*VSASetInfo)(int nch, int srate);
+
+
+    // dsp plug-in processing:
+    // (filled in by winamp, called by input plug)
+
+    // returns 1 if active (which means that the number of samples returned by dsp_dosamples
+    // could be greater than went in.. Use it to estimate if you'll have enough room in the
+    // output buffer
+    int (*dsp_isactive)();
+
+    // returns number of samples to output. This can be as much as twice numsamples.
+    // be sure to allocate enough buffer for samples, then.
+    int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate);
+
+
+    // eq stuff
+    void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
+
+    // info setting (filled in by winamp)
+    void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
+
+    Out_Module *outMod; // filled in by winamp, optionally used :)
+} In_Module;
+
+
+
--- /dev/null
+++ b/plugins/in_mp4/in_mp4.c
@@ -1,0 +1,918 @@
+/*
+** 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: in_mp4.c,v 1.1 2002/01/20 16:59:26 menno Exp $
+**/
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <commctrl.h>
+#include <stdlib.h>
+#include <faad.h>
+#include <mp4.h>
+
+#include "resource.h"
+#include "in2.h"
+
+static char app_name[] = "AudioCoding.com MPEG-4 General Audio player";
+static long priority_table[] = {
+    0,
+    THREAD_PRIORITY_HIGHEST,
+    THREAD_PRIORITY_ABOVE_NORMAL,
+    THREAD_PRIORITY_NORMAL,
+    THREAD_PRIORITY_BELOW_NORMAL,
+    THREAD_PRIORITY_LOWEST
+};
+static int res_id_table[] = {
+    IDC_16BITS,
+    IDC_24BITS,
+    IDC_32BITS
+};
+static int res_table[] = {
+    16,
+    24,
+    32
+};
+static char info_fn[_MAX_PATH];
+
+// post this to the main window at end of file (after playback has stopped)
+#define WM_WA_AAC_EOF WM_USER+2
+
+typedef struct state
+{
+    faacDecHandle hDecoder;
+    MP4FileHandle *mp4file;
+    int mp4track;
+    MP4SampleId numSamples;
+    MP4SampleId sampleId;
+    int samplerate;
+    int channels;
+    int decode_pos_ms; // current decoding position, in milliseconds
+    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;
+
+static char INI_FILE[MAX_PATH];
+static int m_priority = 3;
+static int m_resolution = 0;
+static int m_show_errors = 1;
+
+static state mp4state;
+
+static In_Module module; // the output module (declared near the bottom of this file)
+
+static int killPlayThread;
+static int PlayThreadAlive = 0; // 1=play thread still running
+HANDLE play_thread_handle = INVALID_HANDLE_VALUE; // the handle to the decode thread
+
+/* Function definitions */
+DWORD WINAPI PlayThread(void *b); // the decode thread procedure
+
+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);
+
+	for (i = 0; i < numTracks; i++)
+    {
+        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL);
+        const char* trackType = MP4GetTrackType(infile, trackId);
+
+        if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE))
+        {
+            unsigned char *buff = NULL;
+            int buff_size = 0, dummy;
+            MP4GetTrackESConfiguration(infile, trackId, &buff, &buff_size);
+
+            if (buff)
+            {
+                rc = AudioSpecificConfig(buff, &dummy, &dummy, &dummy, &dummy);
+                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);
+
+	for (i = 0; i < numTracks; i++)
+    {
+        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL);
+        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);
+
+	for (i = 0; i < numTracks; i++)
+    {
+        MP4TrackId trackId = MP4FindTrackId(infile, i, NULL);
+        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));
+	while (*p) p++;
+	while (p >= INI_FILE && *p != '.') p--;
+	strcpy(p+1,"ini");
+}
+
+void config_read()
+{
+    char priority[10];
+    char resolution[10];
+    char show_errors[10];
+
+	config_init();
+
+    RS(priority);
+	RS(resolution);
+	RS(show_errors);
+
+    m_priority = atoi(priority);
+    m_resolution = atoi(resolution);
+    m_show_errors = atoi(show_errors);
+}
+
+void config_write()
+{
+    char priority[10];
+    char resolution[10];
+    char show_errors[10];
+
+    itoa(m_priority, priority, 10);
+    itoa(m_resolution, resolution, 10);
+    itoa(m_show_errors, show_errors, 10);
+
+    WS(priority);
+	WS(resolution);
+	WS(show_errors);
+}
+
+void init()
+{
+    config_read();
+}
+
+void quit()
+{
+}
+
+BOOL CALLBACK info_dialog_proc(HWND hwndDlg, UINT message,
+                               WPARAM wParam, LPARAM lParam)
+{
+    int i, width, height, numFrames, ch, sf;
+    float fps;
+    MP4FileHandle file;
+    int track;
+    char info[256];
+
+    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 Wavetable synthesis",
+        "MPEG-4 General MIDI",
+        "MPEG-4 Algorithmic Synthesis and Audio FX",
+        "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 long msDuration;
+    MP4Duration trackDuration;
+    unsigned int timeScale, avgBitRate;
+    int type;
+    const char* typeName;
+
+    switch (message) {
+    case WM_INITDIALOG:
+        file = MP4Read(info_fn, 0);
+        if (!file)
+            return FALSE;
+
+        if ((track = GetAudioTrack(file)) >= 0)
+        {
+            unsigned char *buff = NULL;
+            int buff_size = 0;
+            MP4GetTrackESConfiguration(file, track, &buff, &buff_size);
+
+            if (buff)
+            {
+                AudioSpecificConfig(buff, &timeScale, &ch, &sf, &type);
+                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");
+            }
+            trackDuration = MP4GetTrackDuration(file, track);
+
+            msDuration = MP4ConvertFromTrackDuration(file, track,
+                trackDuration, MP4_MSECS_TIME_SCALE);
+
+            avgBitRate = MP4GetTrackIntegerProperty(file, track,
+                "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.avgBitrate");
+
+            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);
+        }
+
+        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;
+                    }
+                }
+            }
+
+            trackDuration = MP4GetTrackDuration(file, track);
+            msDuration = MP4ConvertFromTrackDuration(file, track,
+                trackDuration, MP4_MSECS_TIME_SCALE);
+
+            avgBitRate = MP4GetTrackIntegerProperty(file, track,
+                "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.avgBitrate");
+
+            // 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");
+
+            height = MP4GetTrackIntegerProperty(file, track,
+                "mdia.minf.stbl.stsd.mp4v.height");
+
+            // Note if variable rate video is being used the fps is an average 
+            numFrames = MP4GetTrackNumberOfSamples(file, track);
+
+            fps = ((float)numFrames/(float)msDuration) * 1000;
+
+            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:
+        switch (LOWORD(wParam)) {
+        case IDCANCEL:
+        case IDOK:
+            EndDialog(hwndDlg, wParam);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+int infoDlg(char *fn, HWND hwndParent)
+{
+    lstrcpy(info_fn, fn);
+
+    DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
+        hwndParent, info_dialog_proc);
+
+    return 0;
+}
+
+BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message,
+                                 WPARAM wParam, LPARAM lParam)
+{
+    int i;
+
+    switch (message) {
+    case WM_INITDIALOG:
+		SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETRANGE, TRUE, MAKELONG(1,5)); 
+		SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETPOS, TRUE, m_priority);
+        SendMessage(GetDlgItem(hwndDlg, res_id_table[m_resolution]), BM_SETCHECK, BST_CHECKED, 0);
+        if (m_show_errors)
+            SendMessage(GetDlgItem(hwndDlg, IDC_ERROR), BM_SETCHECK, BST_CHECKED, 0);
+        return TRUE;
+
+    case WM_COMMAND:
+        switch (LOWORD(wParam)) {
+        case IDCANCEL:
+            EndDialog(hwndDlg, wParam);
+            return TRUE;
+        case IDOK:
+            m_show_errors = SendMessage(GetDlgItem(hwndDlg, IDC_ERROR), BM_GETCHECK, 0, 0);
+            m_priority = SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_GETPOS, 0, 0);
+            for (i = 0; i < 3; i++)
+            {
+                int set = SendMessage(GetDlgItem(hwndDlg, res_id_table[i]), BM_GETCHECK, 0, 0);
+                if (set)
+                {
+                    m_resolution = i;
+                    break;
+                }
+            }
+
+            /* save config */
+            config_write();
+            EndDialog(hwndDlg, wParam);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+void config(HWND hwndParent)
+{
+    DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG),
+        hwndParent, config_dialog_proc);
+
+    return;
+}
+
+void about(HWND hwndParent)
+{
+    MessageBox(hwndParent,
+        "AudioCoding.com MPEG-4 General Audio player.\n"
+        "Visit the website for more info.\n"
+        "Copyright 2002 AudioCoding.com",
+        "About",
+        MB_OK);
+}
+
+int isourfile(char *fn)
+{
+    if(StringComp(fn + strlen(fn) - 3, "mp4", 3) == 0)
+    {
+        return 1;
+    }
+
+    return 0;
+}
+
+int play(char *fn)
+{
+    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;
+
+    strcpy(mp4state.filename, fn);
+
+    mp4state.mp4file = MP4Read(fn, 0);
+    if (!mp4state.mp4file)
+    {
+        show_error(module.hMainWindow, "Unable to open file.");
+        return -1;
+    }
+
+    if ((mp4state.mp4track = GetAACTrack(mp4state.mp4file)) < 0)
+    {
+        show_error(module.hMainWindow, "Unsupported Audio track type.");
+        MP4Close(mp4state.mp4file);
+        return -1;
+    }
+
+    mp4state.hDecoder = faacDecOpen();
+
+    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);
+
+    config = faacDecGetCurrentConfiguration(mp4state.hDecoder);
+    config->outputFormat = m_resolution + 1;
+    faacDecSetConfiguration(mp4state.hDecoder, config);
+
+    if (mp4state.channels == 0)
+    {
+        show_error(module.hMainWindow, "Number of channels not supported for playback.");
+        faacDecClose(mp4state.hDecoder);
+        MP4Close(mp4state.mp4file);
+        return -1;
+    }
+
+    maxlatency = module.outMod->Open(mp4state.samplerate, mp4state.channels,
+        res_table[m_resolution], -1,-1);
+    if (maxlatency < 0) // error opening device
+    {
+        faacDecClose(mp4state.hDecoder);
+        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);
+
+    module.SetInfo((avg_bitrate + 500)/1000, mp4state.samplerate/1000, mp4state.channels, 1);
+
+    module.outMod->SetVolume(-666); // set the output plug-ins default volume
+
+    killPlayThread = 0;
+
+    if((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlayThread, (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)
+	    SetThreadPriority(play_thread_handle, priority_table[m_priority]);
+
+    return 0;
+}
+
+void pause()
+{
+    mp4state.paused = 1;
+    module.outMod->Pause(1);
+}
+
+void unpause()
+{
+    mp4state.paused = 0;
+    module.outMod->Pause(0);
+}
+
+int ispaused()
+{
+    return mp4state.paused;
+}
+
+void setvolume(int volume)
+{
+    module.outMod->SetVolume(volume);
+}
+
+void setpan(int pan)
+{
+    module.outMod->SetPan(pan);
+}
+
+void stop()
+{
+    killPlayThread = 1;
+
+    if (play_thread_handle != INVALID_HANDLE_VALUE)
+    {
+        if (WaitForSingleObject(play_thread_handle, INFINITE) == WAIT_TIMEOUT)
+            TerminateThread(play_thread_handle,0);
+        CloseHandle(play_thread_handle);
+        play_thread_handle = INVALID_HANDLE_VALUE;
+    }
+
+    faacDecClose(mp4state.hDecoder);
+    MP4Close(mp4state.mp4file);
+    module.outMod->Close();
+    module.SAVSADeInit();
+}
+
+int getsonglength(char *fn)
+{
+    int track;
+    long long msDuration;
+	MP4Duration length;
+    MP4FileHandle file;
+
+    file = MP4Read(fn, 0);
+    if (!file)
+        return 0;
+
+    if ((track = GetAACTrack(file)) < 0)
+    {
+        MP4Close(file);
+        return -1;
+    }
+
+    length = MP4GetTrackDuration(file, track);
+
+	msDuration = MP4ConvertFromTrackDuration(file, track,
+        length, MP4_MSECS_TIME_SCALE);
+
+    MP4Close(file);
+
+    return msDuration;
+}
+
+int getlength()
+{
+    return getsonglength(mp4state.filename);
+}
+
+int getoutputtime()
+{
+    return mp4state.decode_pos_ms+(module.outMod->GetOutputTime()-module.outMod->GetWrittenTime());
+}
+
+void setoutputtime(int time_in_ms)
+{
+    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 */
+    {
+        if (length_in_ms)
+            *length_in_ms = getlength();
+
+        if (title)
+        {
+            char *tmp = PathFindFileName(mp4state.filename);
+            strcpy(title, tmp);
+        }
+    }
+    else // some other file
+    {
+        if (length_in_ms)
+            *length_in_ms = getsonglength(filename);
+
+        if (title)
+        {
+            char *tmp = PathFindFileName(filename);
+            strcpy(title, tmp);
+        }
+    }
+}
+
+void eq_set(int on, char data[10], int preamp)
+{
+}
+
+int last_frame;
+
+DWORD WINAPI PlayThread(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;
+    int buffer_size;
+    faacDecFrameInfo frameInfo;
+
+	PlayThreadAlive = 1;
+    last_frame = 0;
+
+    while (!*((int *)b))
+    {
+        /* seeking */
+        if (mp4state.seek_needed != -1)
+        {
+            MP4Duration duration;
+
+            module.outMod->Flush(mp4state.decode_pos_ms);
+            duration = MP4ConvertToTrackDuration(mp4state.mp4file,
+                mp4state.mp4track, mp4state.seek_needed, MP4_MSECS_TIME_SCALE);
+            mp4state.sampleId = MP4GetSampleIdFromTime(mp4state.mp4file,
+                mp4state.mp4track, duration, 0);
+
+            mp4state.decode_pos_ms = mp4state.seek_needed;
+			mp4state.seek_needed = -1;
+        }
+
+        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 {
+                int rc;
+
+                /* get acces unit from MP4 file */
+                buffer = NULL;
+                buffer_size = 0;
+
+                rc = MP4ReadSample(mp4state.mp4file, mp4state.mp4track,
+                    mp4state.sampleId++, &buffer, &buffer_size,
+                    NULL, NULL, NULL, NULL);
+                if (rc == 0)
+                {
+                    last_frame = 1;
+                } else {
+                    sample_buffer = faacDecDecode(mp4state.hDecoder, &frameInfo, buffer);
+                }
+                if (frameInfo.error > 0)
+                {
+                    show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
+                    last_frame = 1;
+                }
+                if (mp4state.sampleId >= mp4state.numSamples)
+                    last_frame = 1;
+
+                if (buffer) free(buffer);
+
+                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;
+}
+
+static In_Module module =
+{
+    IN_VER,
+    "AudioCoding.com MPEG-4 General Audio player: " __DATE__,
+    0,  // hMainWindow
+    0,  // hDllInstance
+    "MP4\0MPEG-4 Files (*.MP4)\0"
+    ,
+    1, // is_seekable
+    1, // uses output
+    config,
+    about,
+    init,
+    quit,
+    getfileinfo,
+    infoDlg,
+    isourfile,
+    play,
+    pause,
+    unpause,
+    ispaused,
+    stop,
+
+    getlength,
+    getoutputtime,
+    setoutputtime,
+
+    setvolume,
+    setpan,
+
+    0,0,0,0,0,0,0,0,0, // vis stuff
+
+
+    0,0, // dsp
+
+    eq_set,
+
+    NULL,       // setinfo
+
+    0 // out_mod
+};
+
+__declspec(dllexport) In_Module* winampGetInModule2()
+{
+    return &module;
+}
--- /dev/null
+++ b/plugins/in_mp4/in_mp4.dsp
@@ -1,0 +1,123 @@
+# Microsoft Developer Studio Project File - Name="in_mp4" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=in_mp4 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "in_mp4.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "in_mp4.mak" CFG="in_mp4 - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "in_mp4 - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "in_mp4 - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=xicl6.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "in_mp4 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "..\..\include" /I "..\..\common\mp4v2" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x413 /d "NDEBUG"
+# ADD RSC /l 0x413 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=xilink6.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+
+!ELSEIF  "$(CFG)" == "in_mp4 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\include" /I "..\..\common\mp4v2" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x413 /d "_DEBUG"
+# ADD RSC /l 0x413 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=xilink6.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+
+!ENDIF 
+
+# Begin Target
+
+# Name "in_mp4 - Win32 Release"
+# Name "in_mp4 - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\in_mp4.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=..\..\include\faad.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\in2.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\out.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\in_mp4.rc
+# End Source File
+# End Group
+# End Target
+# End Project
--- /dev/null
+++ b/plugins/in_mp4/in_mp4.dsw
@@ -1,0 +1,59 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "in_mp4"=.\in_mp4.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name libfaad
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libmp4v2_st
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libfaad"=..\..\libfaad\libfaad.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libmp4v2_st"=..\..\common\mp4v2\libmp4v2_st60.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
--- /dev/null
+++ b/plugins/in_mp4/in_mp4.rc
@@ -1,0 +1,150 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Dutch (Netherlands) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NLD)
+#ifdef _WIN32
+LANGUAGE LANG_DUTCH, SUBLANG_DUTCH
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_INFO DIALOG DISCARDABLE  0, 0, 191, 207
+STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "MPEG-4 File Info"
+FONT 8, "MS Sans Serif"
+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
+END
+
+IDD_CONFIG DIALOG DISCARDABLE  0, 0, 125, 95
+STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Configuration"
+FONT 8, "MS Sans Serif"
+BEGIN
+    CONTROL         "Slider1",IDC_PRIORITY,"msctls_trackbar32",TBS_VERT | 
+                    TBS_NOTICKS | WS_TABSTOP,13,15,18,39
+    CONTROL         "16 bits",IDC_16BITS,"Button",BS_AUTORADIOBUTTON,77,18,
+                    37,10
+    CONTROL         "24 bits",IDC_24BITS,"Button",BS_AUTORADIOBUTTON,77,30,
+                    37,10
+    CONTROL         "32 bits",IDC_32BITS,"Button",BS_AUTORADIOBUTTON,77,42,
+                    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
+    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
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    IDD_INFO, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 184
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 200
+    END
+
+    IDD_CONFIG, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 118
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 88
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+#endif    // Dutch (Netherlands) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
--- /dev/null
+++ b/plugins/in_mp4/out.h
@@ -1,0 +1,52 @@
+#define OUT_VER 0x10
+
+typedef struct
+{
+    int version;                // module version (OUT_VER)
+    char *description;          // description of module, with version string
+    int id;                     // module id. each input module gets its own. non-nullsoft modules should
+                                // be >= 65536.
+
+    HWND hMainWindow;           // winamp's main window (filled in by winamp)
+    HINSTANCE hDllInstance;     // DLL instance handle (filled in by winamp)
+
+    void (*Config)(HWND hwndParent); // configuration dialog
+    void (*About)(HWND hwndParent);  // about dialog
+
+    void (*Init)();             // called when loaded
+    void (*Quit)();             // called when unloaded
+
+    int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
+                    // returns >=0 on success, <0 on failure
+                    // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
+                    //    ... so don't expect the max latency returned to be what you asked for.
+                    // returns max latency in ms (0 for diskwriters, etc)
+                    // bufferlenms and prebufferms must be in ms. 0 to use defaults.
+                    // prebufferms must be <= bufferlenms
+
+    void (*Close)();    // close the ol' output device.
+
+    int (*Write)(char *buf, int len);
+                    // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
+                    // 1 returns not able to write (yet). Non-blocking, always.
+
+    int (*CanWrite)();  // returns number of bytes possible to write at a given time.
+                        // Never will decrease unless you call Write (or Close, heh)
+
+    int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
+                        // written (i.e. closing while IsPlaying() returns 1 would truncate the song
+
+    int (*Pause)(int pause); // returns previous pause state
+
+    void (*SetVolume)(int volume); // volume is 0-255
+    void (*SetPan)(int pan); // pan is -128 to 128
+
+    void (*Flush)(int t);   // flushes buffers and restarts output at time t (in ms)
+                            // (used for seeking)
+
+    int (*GetOutputTime)(); // returns played time in MS
+    int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)
+
+} Out_Module;
+
+
--- /dev/null
+++ b/plugins/in_mp4/resource.h
@@ -1,0 +1,32 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by in_mp4.rc
+//
+#define IDD_INFO                        101
+#define IDD_CONFIG                      102
+#define IDC_TYPE                        1000
+#define IDC_DURATION                    1001
+#define IDC_BITRATE                     1002
+#define IDC_SAMPLERATE                  1003
+#define IDC_VTYPE                       1004
+#define IDC_PRIORITY                    1004
+#define IDC_VBITRATE                    1005
+#define IDC_ERROR                       1005
+#define IDC_VDURATION                   1006
+#define IDC_16BITS                      1006
+#define IDC_VSIZE                       1007
+#define IDC_24BITS                      1007
+#define IDC_VFPS                        1008
+#define IDC_32BITS                      1008
+#define IDC_CHANNELS                    1009
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        103
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1007
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif