shithub: aacdec

Download patch

ref: e9b4be45b8eb828ddd32a5a1c0b1e1f7f921c624
parent: 9cb5698f51570f4512fe74471d558a0502b289b4
author: menno <menno>
date: Sun Nov 16 14:52:41 EST 2003

new QCD plugin code by shaohao

--- a/plugins/QCDMp4/AAC2Mp4Enc.c
+++ /dev/null
@@ -1,270 +1,0 @@
-//-----------------------------------------------------------------------------
-//
-// File:	QCDEncodeDLL.cpp
-//
-// About:	See QCDOutputDLL.h
-//
-// Authors:	Written by Paul Quinn
-//
-//	QCD multimedia player application Software Development Kit Release 1.0.
-//
-//	Copyright (C) 1997-2002 Quinnware
-//
-//	This code is free.  If you redistribute it in any form, leave this notice 
-//	here.
-//
-//	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.
-//
-//-----------------------------------------------------------------------------
-
-#include <windows.h>
-#include <shlobj.h>
-#include <mp4.h>
-
-#include "QCDInputDLL.h"
-#include "QCDConvertDLL.h"
-#include "resource.h"
-#include "utils.h"
-#include "config.h"
-#include "aac2mp4.h"
-
-HWND			hwndConfigEnc;
-QCDModInitEnc	*QCDCallbacks_Enc;
-
-BOOL CALLBACK config_convert_proc(HWND hwndDlg, UINT message,
-                                 WPARAM wParam, LPARAM lParam);
-
-static char m_output_folder[MAX_PATH];// our output folder
-
-void config_enc_read()
-{
-	char output_folder[MAX_PATH];
-	output_folder[0] = 0;
-
-    RS(output_folder);
-
-	lstrcpy(m_output_folder, output_folder);
-}
-
-void config_enc_write()
-{
-	char output_folder[MAX_PATH];
-	lstrcpy(output_folder, m_output_folder);
-
-	WS(output_folder);
-}
-
-BOOL isFolder(char *folder)
-{
-	if(lstrlen(folder) > 0 && folder[1] == ':')
-		return TRUE;
-	else
-		return FALSE;
-}
-
-//-----------------------------------------------------------------------------
-
-PLUGIN_API BOOL ENCODEDLL_ENTRY_POINT(QCDModInitEnc *ModInit, QCDModInfo *ModInfo)
-{
-	ModInit->version = PLUGIN_API_VERSION;
-	ModInfo->moduleString = "AAC to Mp4 Converter v1.0";
-
-	ModInit->toModule.ShutDown				= ShutDown_Enc;
-	ModInit->toModule.Open					= Open_Enc;
-	ModInit->toModule.Write					= Write_Enc;
-	ModInit->toModule.Stop					= Stop_Enc;
-	ModInit->toModule.GetCurrentPosition	= GetCurrentPosition_Enc;
-	ModInit->toModule.Configure				= Configure_Enc;
-	ModInit->toModule.About					= About_Enc;
-
-/* encoders can handle these calls if they wish,
- * but they are generally not needed
-
-	ModInit->toModule.Flush				= Flush;
-	ModInit->toModule.Pause				= Pause;
-	ModInit->toModule.Drain				= Drain;
-	ModInit->toModule.SetVolume			= SetVolume;
-	ModInit->toModule.DrainCancel		= DrainCancel;
-
-*/
-
-	QCDCallbacks_Enc = ModInit;
-
-	hwndPlayer = (HWND)QCDCallbacks_Enc->Service(opGetParentWnd, 0, 0, 0);
-
-	QCDCallbacks_Enc->Service(opGetPluginSettingsFile, INI_FILE, MAX_PATH, 0);
-
-	//
-	// TODO: all your plugin initialization here
-	//
-	config_enc_read();
-
-	
-	// return TRUE for successful initialization
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-
-void ShutDown_Enc(int flags)
-{
-	Stop_Enc(STOPFLAG_FORCESTOP);
-}
-
-//-----------------------------------------------------------------------------
-
-BOOL Open_Enc(LPCSTR medianame, WAVEFORMATEX *wf)
-{
-	char mp4FileName[256];
-	
-	if(StringComp(strrchr(medianame, '.'), ".aac", 4))
-	{
-		MessageBox(hwndPlayer, "Only AAC files can be converted into Mp4 Files!", "File Type Error", MB_OK);
-		return FALSE;
-	}
-	else if(!isFolder(m_output_folder) && MessageBox(hwndPlayer, "You should select a output folder!", "Error", MB_OK) == IDOK )
-	{
-		if(!IsWindow(hwndConfigEnc))
-			hwndConfigEnc = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_CONFIG_CONVERT), 
-				hwndPlayer, config_convert_proc);
-		ShowWindow(hwndConfigEnc, SW_SHOW);
-		return FALSE;
-	}
-	else
-	{
-		lstrcpy(mp4FileName, m_output_folder); // copy the folder path
-		lstrcat(mp4FileName, strrchr(medianame, '\\')); //copy the file name
-		lstrcpy(strrchr(mp4FileName, '.'), ".mp4"); // rename the file name to .mp4
-
-		if(covert_aac_to_mp4(medianame, mp4FileName))
-		{
-			MessageBox(hwndPlayer, "An error occured while converting AAC to MP4!", "An error occured!", MB_OK);
-			return FALSE;
-		}
-		else
-		{
-			QCDCallbacks_Enc->Service(opSetStatusMessage, "Converting OK", TEXT_TOOLTIP, 0);
-
-			return TRUE;
-		}
-	}
-}
-
-//-----------------------------------------------------------------------------
-
-BOOL Write_Enc(WriteDataStruct* writeData)
-{
-	//
-	// TODO : Use the raw wave audio data passed from the player.
-	//
-	// Return value - one of the follwing:
-	//
-	// TRUE		- write succeeded
-	// FALSE	- write failed
-	//
-	// Note: this call can block (eg: to wait for available space to write)
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-
-BOOL Stop_Enc(int flags)
-{
-	//
-	// TODO : Stop and close the output.
-	//
-	// Return TRUE for success, FALSE for failure
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-
-BOOL GetCurrentPosition_Enc(UINT *position, int flags)
-{
-	// 
-	// TODO : set position to exact current playing position
-	// returned position needs to be latest marker sent to Write
-	// return TRUE for success
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-
-BOOL CALLBACK config_convert_proc(HWND hwndDlg, UINT message,
-                                 WPARAM wParam, LPARAM lParam)
-{
-	char str_buffer[MAX_PATH];
-
-	switch (message) 
-	{
-    case WM_INITDIALOG:
-		if(isFolder(m_output_folder))// is a driver folder
-			SetDlgItemText(hwndDlg, IDC_OUTPUTFOLDER, m_output_folder);
-		else
-			SetDlgItemText(hwndDlg, IDC_OUTPUTFOLDER, "Select Output Folder");
-        return TRUE;
-
-    case WM_COMMAND:
-        switch (LOWORD(wParam))
-		{
-		case IDC_OUTPUTFOLDER:
-			{
-				char name[MAX_PATH];
-				BROWSEINFO bi;
-				ITEMIDLIST *idlist;
-				bi.hwndOwner = hwndDlg;
-				bi.pidlRoot = 0;
-				bi.pszDisplayName = name;
-				bi.lpszTitle = "Select a directory for saving mp4 files converted from aac files: ";
-				bi.ulFlags = BIF_RETURNONLYFSDIRS /*| BIF_USENEWUI*/;
-				bi.lpfn = NULL;
-				bi.lParam = 0;
-				
-				idlist = SHBrowseForFolder( &bi );
-				if(idlist)
-				{
-					SHGetPathFromIDList( idlist, m_output_folder);
-					SetDlgItemText(hwndDlg, IDC_OUTPUTFOLDER, m_output_folder);
-				}
-				return TRUE;
-			}
-        case IDOK:
-			GetDlgItemText(hwndDlg, IDC_OUTPUTFOLDER, str_buffer, MAX_PATH);
-			if(isFolder(str_buffer)) // is a driver foder
-				lstrcpy(m_output_folder, str_buffer);
-			else
-				m_output_folder[0] = 0;
-
-            /* save config */
-            config_enc_write();
-		default:
-			/* close the dialogbox */
-            DestroyWindow(hwndDlg);
-            return TRUE;
-        }
-    }
-    return FALSE;
-}
-
-void Configure_Enc(int flags)
-{
-	if(!IsWindow(hwndConfigEnc))
-		hwndConfigEnc = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_CONFIG_CONVERT), 
-			hwndPlayer, config_convert_proc);
-	ShowWindow(hwndConfigEnc, SW_SHOWNORMAL);
-}
-
-//-----------------------------------------------------------------------------
-
-void About_Enc(int flags)
-{
-	if(!IsWindow(hwndAbout))
-		hwndAbout = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_ABOUT), 
-			hwndPlayer, about_dialog_proc);
-	ShowWindow(hwndAbout, SW_SHOWNORMAL);
-}
--- a/plugins/QCDMp4/QCDConvertDLL.h
+++ /dev/null
@@ -1,40 +1,0 @@
-//-----------------------------------------------------------------------------
-// 
-// File:	QCDEncodeDLL.h
-//
-// About:	QCD Player Output module DLL interface.  For more documentation, see
-//			QCDModOutput.h.
-//
-// Authors:	Written by Paul Quinn
-//
-//	QCD multimedia player application Software Development Kit Release 1.0.
-//
-//	Copyright (C) 1997-2002 Quinnware
-//
-//	This code is free.  If you redistribute it in any form, leave this notice 
-//	here.
-//
-//	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.
-//
-//-----------------------------------------------------------------------------
-
-#include "QCDModEncode.h"
-
-#ifndef QCDENCODEDLL_H
-#define QCDENCODEDLL_H
-
-extern QCDModInitEnc	*QCDCallbacks_Enc;
-
-// Calls from the Player
-void ShutDown_Enc(int flags);
-BOOL Open_Enc(LPCSTR, WAVEFORMATEX *wf);
-BOOL Write_Enc(WriteDataStruct*);
-BOOL Stop_Enc(int flags);
-BOOL GetCurrentPosition_Enc(UINT *position, int flags);
-
-void Configure_Enc(int flags);
-void About_Enc(int flags);
-
-#endif //QCDOUTPUTDLL_H
\ No newline at end of file
--- a/plugins/QCDMp4/QCDInputDLL.h
+++ b/plugins/QCDMp4/QCDInputDLL.h
@@ -25,10 +25,6 @@
 
 #include "QCDModInput.h"
 
-extern HINSTANCE		hInstance;
-extern HWND				hwndPlayer, hwndAbout;
-extern QCDModInitIn		sQCDCallbacks, *QCDCallbacks;
-
 // Calls from the Player
 int  GetMediaSupported(const char* medianame, MediaInfo *mediaInfo);
 int  GetTrackExtents(const char* medianame, TrackExtents *ext, int flags);
@@ -47,6 +43,4 @@
 void Configure(int flags);
 void About(int flags);
 
-#endif //QCDInputDLL_H
-
-INT_PTR CALLBACK about_dialog_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+#endif //QCDInputDLL_H
\ No newline at end of file
--- a/plugins/QCDMp4/QCDModDefs.h
+++ b/plugins/QCDMp4/QCDModDefs.h
@@ -25,6 +25,7 @@
 #ifndef QCDMODDEFS_H
 #define QCDMODDEFS_H
 
+#include <mmreg.h>
 #include <windows.h>
 
 #ifdef __cplusplus
@@ -34,14 +35,20 @@
 #endif
 
 // Current plugin version
-#define PLUGIN_API_VERSION 250
 
+// use this version for old style API calls (all returned text in native encoding)
+#define PLUGIN_API_VERSION				250		
+
+// use this version for new style API calls (all returned text in UTF8 encoding on WinNT/2K/XP (native encoding on Win9x))
+#define PLUGIN_API_VERSION_WANTUTF8		((PLUGIN_API_WANTUTF8<<16)|PLUGIN_API_VERSION)
+#define PLUGIN_API_WANTUTF8				100
+
 //-----------------------------------------------------------------------------
 
-typedef struct {
+typedef struct 
+{
 	char				*moduleString;
 	char				*moduleExtensions;
-
 } QCDModInfo;
 
 //-----------------------------------------------------------------------------
@@ -60,7 +67,7 @@
 	opGetNextIndex = 12,			// get index of next track to play (0 based), param1 = index start index. -1 for after current
 	opGetTrackNum = 13,				// get track number of index, param1 = index of track in playlist, -1 for current
 									//		- 'track number' is the number of the track in it's respective album, as opposed to playlist number
-									//		- the 'track number' for digital files will be 1, unless they are tagged with the CDDB identifier
+									//		- the 'track number' for digital files will be 1 if the tag is not set or the file is not identified
 
 	opGetTrackLength = 14,			// get track length, param1 = index of track in playlist, -1 for current
 									//                   param2 = 0 for seconds, 1 for milliseconds
@@ -88,7 +95,7 @@
 
 	opGetIndexFromPLNum = 28,		// get index from playlist number, param1 = playlist number
 
-	opGetChildWnd = 30,				// handle to the draggable window extension (only available on some skins) 
+	opGetExtensionWnd = 30,			// handle to the draggable window extension (only available on some skins), param1 = extension number (0 - 9)
 	opGetExtVisWnd = 31,			// handle to the external visual window
 	opGetMusicBrowserWnd = 32,		// handle to the music browser window 
 	opGetSkinPreviewWnd = 33,		// handle to the skin preview window 
@@ -97,10 +104,13 @@
 	opGetAboutWnd = 36,				// handle to the about window 
 	opGetSegmentsWnd = 37,			// handle to the segments window 
 	opGetEQPresetsWnd = 38,			// handle to the EQ presets window 
+	opGetVideoWnd = 39,				// handle to the video window 
 
 	opGetVisDimensions = 50,		// gets the width and height of visual window (param1 = -1 current vis window, 0 internal vis, 1 external vis, 2 full screen)
 									//		returns: HEIGHT in high word, WIDTH in low word 
 
+	opShowVideoWindow = 55,			// Show or Close video window (param1 = 1 for create, 2 for create and show, 0 for close)
+
 	opGetQueriesComplete = 60,		// get status on whether all tracks in playlist have been queryied for their info
 
 									// playlist manipulation
@@ -108,9 +118,9 @@
 	opSelectIndex = 91,				// mark index as selected (param1 = index, param2 = 1 - set, 0 - unset)
 	opBlockIndex = 92,				// mark index as blocked (param1 = index, param2 = 1 - set, 0 - unset)
 
-	opGetMediaInfo = 99,			// get the CddbDisc object for the index specified, param1 = index of track, -1 for current
+	opGetMediaInfo = 99,			// get the ICddbDisc object for the index specified, param1 = index of track, -1 for current
 									//		param2 = pointer to integer that receives track value
-									//		returns: pointer to CddbDisc object. Do not release or deallocate this pointer
+									//		returns: pointer to ICddbDisc object. Do not release or deallocate this pointer
 
 
    									//*** below returns string info in buffer, param1 = size of buffer
@@ -141,6 +151,7 @@
 	opGetSupportedExtensions = 116,	// get file extensions supported by the player, param2 = 0 - get all extensions, 1 - get registered extensions
 									//		- returned extensions will be colon delimited
 
+	opGetPlaylistString = 117,		// get string for index as it appears in playlist, param2 = index
 
    									//*** below buffer points to struct or other object
    									//*** returns 1 on success, 0 on failure
@@ -149,6 +160,8 @@
 	opGetMainMenu = 121,			// Returns copy of HMENU handle to QCD Menu (must use DestroyMenu on handle when complete)
 
 	opShowQuickTrack = 125,			// Display QuickTrack Menu (buffer = POINT* - location to display menu)
+	opGetQuickTrack = 126,			// Returns copy of HMENU handle to QuickTrack menu (must use DestroyMenu on handle when complete)
+									//		To use if QuickTrack item selected: PostMessage(hwndPlayer, WM_COMMAND, menu_id, 0);
 
 	opGetEQVals = 200,				// get current EQ levels/on/off (buffer = EQInfo*)
 	opSetEQVals = 201,				// set EQ levels/on/off (buffer = EQInfo*)
@@ -196,13 +209,17 @@
 	opMovePlaylistTrack = 1012,		// param1 = index of track to move, param2 = destination index (move shifts tracks between param1 and param2)
 	opSwapPlaylistTracks = 1013,	// param1 = index of first track, param2 = index of second track (swap only switches indecies param1 and param2)
 
+	opCreateDiscInfo = 1020,		// returns: pointer to ICddbDisc object. Do not release or deallocate this pointer
+	opSetDiscInfo = 1021,			// buffer = ICddbDisc*, param1 = MediaInfo*, param2 = track number
 
-
 	opSetSeekPosition = 1100,		// seek to position during playback
 									//		buffer = NULL, param1 = position
 									//		param2 = 0 - position is in seconds, 1 - position is in milliseconds, 2 - position is in percent (use (float)param1))
 
 
+	opSetRepeatState = 1110,		// set playlist repeat state, buffer = NULL, param1 = 0 - off, 1 - repeat track, 2 - repeat playlist
+	opSetShuffleState = 1111,		// set playlist shuffle state, buffer = NULL, param1 = 0 - off, 1 - on
+
 									//*** below configures custom plugin menu items for the 'plugin menu'
 									//*** Player will call plugin's configure routine with menu value when menu item selected
 									//*** returns 1 on success, 0 on failure
@@ -213,8 +230,18 @@
 	opSetPluginMenuState = 2001,	// buffer = HINSTANCE of plugin, param1 = item id, param2 = menu flags (same as windows menu flags - eg: MF_CHECKED)
 
 
+									//*** below are services for using the player's filename template editor
+									//*** returns 1 on success, 0 on failure
+
+	opShowTemplateEditor = 2100,	// displays template editor dialog, param1 = (HWND)parent window, param2 = modal flag
+	opLoadTemplate = 2101,			// loads saved templates, buffer = (char*)string buf, param1 = bufsize, param2 = index of template (index < 0 for default formats, index >= 0 for user made formats)
+	opRenderTemplate = 2102,		// create string based on template, buffer = (char*)template, param1 = FormatMetaInfo*, param2 = (char*)string buffer (min 260 bytes)
+
 									//*** other services
 
+	opUTF8toUCS2 = 9000,			// convert UTF8 string to UCS2 (Unicode) string, buffer = null terminated utf8 string, param1 = (WCHAR*)result string buffer, param2 = size of result buffer
+	opUCS2toUTF8 = 9001,			// convert UCS2 (Unicode) string to UTF8 string, buffer = null terminated ucs2 string, param1 = (char*)result string buffer, param2 = size of result buffer
+
 	opSafeWait = 10000				// plugin's can use this to wait on an object without worrying about deadlocking the player.
 									// this should only be called by the thread that enters the plugin, not by any plugin-created threads
 
@@ -225,6 +252,10 @@
 //-----------------------------------------------------------------------------
 typedef long (*PluginServiceFunc)(PluginServiceOp op, void *buffer, long param1, long param2);
 
+// Use to retrieve service func for DSP plugins (or other inproc process that doesn't have access to PluginServiceFunc)
+// Eg: PluginServiceFunc Service = (PluginServiceFunc)SendMessage(hwndPlayer, WM_GETSERVICEFUNC, 0, 0);
+// Set WPARAM = PLUGIN_API_WANTUTF8 for UTF8 string parameters
+#define WM_GETSERVICEFUNC			(WM_USER + 1)
 
 //-----------------------------------------------------------------------------
 typedef struct				// for Output Plugin Write callback
@@ -263,6 +294,7 @@
     long bitrate;		// audio bitrate in bits per second
     long frequency;		// audio freq in Hz
     long mode;			// 0 for stereo, 1 for joint-stereo, 2 for dual-channel, 3 for mono, 4 for multi-channel
+	char text[8];		// up to eight characters to identify format (will override level and layer settings)
 } AudioInfo;
 
 //-----------------------------------------------------------------------------
@@ -316,7 +348,22 @@
 
 } MediaInfo;
 
+//-----------------------------------------------------------------------------
+typedef struct
+{
+	long	struct_size;
+	LPCWSTR	title;
+	LPCWSTR	artalb;
+	LPCWSTR	album;
+	LPCWSTR	genre;
+	LPCWSTR	year;
+	LPCWSTR	tracknum;
+	LPCWSTR	filename;
+	LPCWSTR	arttrk;
+	long	reserved;
 
+} FormatMetaInfo;
+
 //-----------------------------------------------------------------------------
 // When subclassing the parent window, a plugin can watch for these messages
 // to react to events going on between plugins and player
@@ -328,8 +375,8 @@
 #define WM_PN_PLAYSTOPPED		(WM_USER + 102) // playback has stopped by user
 #define WM_PN_PLAYPAUSED		(WM_USER + 103) // playback has been paused
 #define WM_PN_PLAYDONE			(WM_USER + 104) // playback has finished (track completed)
-#define WM_PN_MEDIAEJECTED		(WM_USER + 105) // a CD was ejected (lParam = (LPCSTR)medianame)
-#define WM_PN_MEDIAINSERTED		(WM_USER + 106) // a CD was inserted (lParam = (LPCSTR)medianame)
+#define WM_PN_MEDIAEJECTED		(WM_USER + 105) // a CD was ejected (CDRom drive letter= 'A' + lParam)
+#define WM_PN_MEDIAINSERTED		(WM_USER + 106) // a CD was inserted (CDRom drive letter= 'A' + lParam)
 #define WM_PN_INFOCHANGED		(WM_USER + 107) // track information was updated (lParam = (LPCSTR)medianame)
 #define WM_PN_TRACKCHANGED		(WM_USER + 109)	// current track playing has changed (relevant from CD plugin) (lParam = (LPCSTR)medianame)
 
@@ -340,6 +387,17 @@
 // (so you can get handle, modify, and display your own)
 #define WM_SHOWMAINMENU			(WM_USER + 20)
 
+// For intercepting skinned border window commands
+#define WM_BORDERWINDOW			(WM_USER + 26)
+// WM_BORDERWINDOW	wParam's
+#define BORDERWINDOW_NORMALSIZE			0x100000
+#define BORDERWINDOW_DOUBLESIZE			0x200000
+#define BORDERWINDOW_FULLSCREEN			0x400000
+
+// send to border window to cause resize
+// wParam = LPPOINT lpp; // point x-y is CLIENT area size of window
+#define WM_SIZEBORDERWINDOW		(WM_USER + 1)
+
 //-----------------------------------------------------------------------------
 // To shutdown player, send this command
 #define WM_SHUTDOWN				(WM_USER + 5)
@@ -350,6 +408,6 @@
 #define TEXT_TOOLTIP		0x1		// message acts as tooltip in status window
 #define TEXT_URGENT			0x2		// forces message to appear even if no status window (using msg box)
 #define TEXT_HOLD			0x4		// tooltip message stays up (no fade out)
-
+#define TEXT_UNICODE		0x10	// buffer contains a unicode string (multibyte string otherwise)
 
 #endif //QCDMODDEFS_H
\ No newline at end of file
--- a/plugins/QCDMp4/QCDModEncode.h
+++ /dev/null
@@ -1,76 +1,0 @@
-//-----------------------------------------------------------------------------
-//
-// File:	QCDModEncode.h
-//
-// About:	Encode plugin module interface.  This file is published with the 
-//			Encode plugin SDK.
-//
-// Authors:	Written by Paul Quinn
-//
-// Copyright:
-//
-//	QCD multimedia player application Software Development Kit Release 1.0.
-//
-//	Copyright (C) 1997-2002 Quinnware
-//
-//	This code is free.  If you redistribute it in any form, leave this notice 
-//	here.
-//
-//	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.
-//
-//-----------------------------------------------------------------------------
-
-#ifndef QCDMODENCODE_H
-#define QCDMODENCODE_H
-
-#include "QCDModDefs.h"
-
-// name of the DLL export for encode plugins
-#define ENCODEDLL_ENTRY_POINT	QEncodeModule
-
-// Stop will receive one of these flags
-#define STOPFLAG_FORCESTOP		0
-#define STOPFLAG_PLAYDONE		1
-
-// pause flags
-#define PAUSE_DISABLED			0	// Pause() call is to unpause playback
-#define PAUSE_ENABLED			1	// Pause() call is to pause playback
-
-//-----------------------------------------------------------------------------
-
-typedef struct 
-{
-	UINT				size;			// size of init structure
-	UINT				version;		// plugin structure version (set to PLUGIN_API_VERSION)
-	PluginServiceFunc	Service;		// player supplied services callback
-
-	struct
-	{
-		void *dummy;
-		void (*PositionUpdate)(UINT marker);
-		void *Reserved[2];
-	} toPlayer;
-
-	struct 
-	{
-		BOOL (*Open)(LPCSTR, WAVEFORMATEX *wf);
-		BOOL (*Write)(WriteDataStruct*);
-		BOOL (*Flush)(UINT marker);
-		BOOL (*Stop)(int flags);
-		BOOL (*Pause)(int flags);
-		BOOL (*Drain)(int flags);
-		void (*ShutDown)(int flags);
-
-		void (*Configure)(int flags);
-		void (*About)(int flags);
-
-		BOOL (*SetVolume)(int levelleft, int levelright, int flags);
-		BOOL (*GetCurrentPosition)(UINT *position, int flags);
-		BOOL (*DrainCancel)(int flags);
-		void *Reserved[8];
-	} toModule;
-} QCDModInitEnc;
-
-#endif //QCDMODENCODE_H
\ No newline at end of file
--- /dev/null
+++ b/plugins/QCDMp4/QCDModTagEditor.h
@@ -1,0 +1,84 @@
+//-----------------------------------------------------------------------------
+//
+// File:	QCDModTagEditor
+//
+// About:	Tag Editing plugin module interface.  This file is published with the 
+//			QCD plugin SDK.
+//
+// Authors:	Written by Paul Quinn
+//
+// Copyright:
+//
+//	QCD multimedia player application Software Development Kit Release 1.0.
+//
+//	Copyright (C) 2002 Quinnware
+//
+//	This code is free.  If you redistribute it in any form, leave this notice 
+//	here.
+//
+//	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.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef QCDMODTAGEDITOR_H
+#define QCDMODTAGEDITOR_H
+
+#include "QCDModDefs.h"
+
+// name of the DLL export for output plugins
+#define TAGEDITORDLL_ENTRY_POINT	QTagEditorModule
+
+// Tag field ids
+typedef enum
+{
+	TAGFIELD_FIRSTFIELD = 0,
+
+	TAGFIELD_TITLE = 0,
+	TAGFIELD_ARTIST,
+	TAGFIELD_ALBUM, 
+	TAGFIELD_GENRE,
+	TAGFIELD_YEAR,  
+	TAGFIELD_TRACK, 
+	TAGFIELD_COMMENT,
+
+	TAGFIELD_COMPOSER,
+	TAGFIELD_CONDUCTOR,
+	TAGFIELD_ORCHESTRA,
+	TAGFIELD_YEARCOMPOSED,
+
+	TAGFIELD_ORIGARTIST,
+	TAGFIELD_LABEL, 
+	TAGFIELD_COPYRIGHT,
+	TAGFIELD_ENCODER,
+	TAGFIELD_CDDBTAGID,
+
+	TAGFIELD_FIELDCOUNT
+};
+
+//-----------------------------------------------------------------------------
+
+typedef struct 
+{
+	UINT	size;			// size of init structure
+	UINT	version;		// plugin structure version (set to PLUGIN_API_VERSION)
+
+	LPCSTR	description;
+	LPCSTR	defaultexts;
+
+	bool	(*Read)(LPCSTR filename, void* tagHandle);
+	bool	(*Write)(LPCSTR filename, void* tagHandle);
+	bool	(*Strip)(LPCSTR filename);
+
+	void	(*ShutDown)(int flags);
+
+	void	(*SetFieldA)(void* tagHandle, int fieldId, LPCSTR szNewText);
+	void	(*SetFieldW)(void* tagHandle, int fieldId, LPCWSTR szNewText);
+
+	LPCSTR	(*GetFieldA)(void* tagHandle, int fieldId);
+	LPCWSTR	(*GetFieldW)(void* tagHandle, int fieldId);
+
+} QCDModInitTag;
+
+#endif //QCDMODTAGEDITOR_H
\ No newline at end of file
--- a/plugins/QCDMp4/QCDMp4.c
+++ b/plugins/QCDMp4/QCDMp4.c
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,17 +16,21 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: QCDMp4.c,v 1.2 2003/05/07 18:30:49 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: QCDMp4.c,v 1.3 2003/11/16 19:52:41 menno Exp $
 **/
 
 //#define DEBUG_OUTPUT
-#include "QCDInputDLL.h"
 
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <commctrl.h>
 #include <commdlg.h>
-#include <shellapi.h>
 #include <stdlib.h>
 #include <math.h>
 #include <faad.h>
@@ -33,10 +37,15 @@
 #include <mp4.h>
 
 #include "resource.h"
+#include "QCDInputDLL.h"
 #include "utils.h"
 #include "config.h"
 #include "aacinfo.h"
-
+//#include "aac2mp4.h"
+//
+//const char *long_ext_list = "MP4\0MPEG-4 Files (*.MP4)\0M4A\0MPEG-4 Files (*.M4A)\0AAC\0AAC Files (*.AAC)\0";
+//const char *short_ext_list = "MP4\0MPEG-4 Files (*.MP4)\0M4A\0MPEG-4 Files (*.M4A)\0";
+
 static long priority_table[] = {
     0,
     THREAD_PRIORITY_HIGHEST,
@@ -50,7 +59,8 @@
     IDC_24BITS,
     IDC_32BITS,
     0,
-    IDC_16BITS_DITHERED
+    0,
+    /*IDC_16BITS_DITHERED*/ IDC_16BITS /* temp hack */
 };
 static int res_table[] = {
     16,
@@ -57,9 +67,20 @@
     24,
     32,
     0,
+    0,
     16
 };
+//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
+
+struct seek_list
+{
+    struct seek_list *next;
+    __int64 offset;
+};
+
 typedef struct state
 {
     /* general stuff */
@@ -66,12 +87,13 @@
     faacDecHandle hDecoder;
     int samplerate;
     unsigned char channels;
-    int decode_pos_ms; // current decoding position, in milliseconds
+    double 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];
     int filetype; /* 0: MP4; 1: AAC */
     int last_frame;
+    __int64 last_offset;
 
     /* MP4 stuff */
     MP4FileHandle mp4file;
@@ -81,39 +103,65 @@
 
     /* AAC stuff */
     FILE *aacfile;
-    long filesize;
-    long bytes_read;
-    long bytes_into_buffer;
-    long bytes_consumed;
-    unsigned char *buffer;
-    long seconds;
-//    faadAACInfo aacInfo;
+    long m_aac_bytes_into_buffer;
+    long m_aac_bytes_consumed;
+    __int64 m_file_offset;
+    unsigned char *m_aac_buffer;
+    int m_at_eof;
+    double cur_pos_sec;
+    int m_header_type;
+    struct seek_list *m_head;
+    struct seek_list *m_tail;
+    unsigned long m_length;
+
+    /* for gapless decoding */
+    unsigned int useAacLength;
+    unsigned int framesize;
+    unsigned int initial;
+    unsigned long timescale;
 } state;
 
 static state mp4state;
 
-HINSTANCE		hInstance;
-HWND			hwndPlayer, hwndConfig, hwndAbout;
-QCDModInitIn	sQCDCallbacks, *QCDCallbacks;
-BOOL			oldAPIs = 0;
+//static In_Module module; // the output module (declared near the bottom of this file)
+struct {
+	HINSTANCE		hInstance;
+	HWND			hMainWindow;
+	QCDModInitIn	QCDCallbacks;
+} module;
+AudioInfo		ai;
 
 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 */
+void *decode_aac_frame(state *st, faacDecFrameInfo *frameInfo);
 DWORD WINAPI MP4PlayThread(void *b); // the decode thread procedure
 DWORD WINAPI AACPlayThread(void *b); // the decode thread procedure
 
+
 #ifdef DEBUG_OUTPUT
 void in_mp4_DebugOutput(char *message)
 {
     char s[1024];
 
-    sprintf(s, "%s: %s", mp4state.filename, message);
-    MessageBox(NULL, s, "Debug Message", MB_OK);
+    sprintf(s, "in_mp4: %s: %s", mp4state.filename, message);
+    OutputDebugString(s);
 }
 #endif
 
+int file_length(FILE *f)
+{
+    long end = 0;
+    long cur = ftell(f);
+    fseek(f, 0, SEEK_END);
+    end = ftell(f);
+    fseek(f, cur, SEEK_SET);
+
+    return end;
+}
+
 static void show_error(HWND hwnd, char *message, ...)
 {
     if (m_show_errors)
@@ -120,6 +168,16 @@
         MessageBox(hwnd, message, "Error", MB_OK);
 }
 
+static void config_init()
+{
+    //char *p=INI_FILE;
+    //GetModuleFileName(NULL,INI_FILE,_MAX_PATH);
+    //while (*p) p++;
+    //while (p >= INI_FILE && *p != '.') p--;
+    //strcpy(p+1,"ini");
+	module.QCDCallbacks.Service(opGetPluginSettingsFile, INI_FILE, MAX_PATH, 0);
+}
+
 void config_read()
 {
     char priority[10];
@@ -126,21 +184,33 @@
     char resolution[10];
     char show_errors[10];
     char use_for_aac[10];
+    char downmix[10];
+    char vbr_display[10];
 
+    config_init();
+
     strcpy(show_errors, "1");
     strcpy(priority, "3");
     strcpy(resolution, "0");
     strcpy(use_for_aac, "1");
+    strcpy(downmix, "0");
+    strcpy(vbr_display, "1");
+    //strcpy(titleformat, "%7");
 
     RS(priority);
-	RS(resolution);
-	RS(show_errors);
+    RS(resolution);
+    RS(show_errors);
     RS(use_for_aac);
+    RS(downmix);
+    RS(vbr_display);
+    //RS(titleformat);
 
     m_priority = atoi(priority);
     m_resolution = atoi(resolution);
     m_show_errors = atoi(show_errors);
     m_use_for_aac = atoi(use_for_aac);
+    m_downmix = atoi(downmix);
+    m_vbr_display = atoi(vbr_display);
 }
 
 void config_write()
@@ -149,105 +219,38 @@
     char resolution[10];
     char show_errors[10];
     char use_for_aac[10];
+    char downmix[10];
+    char vbr_display[10];
 
     itoa(m_priority, priority, 10);
     itoa(m_resolution, resolution, 10);
     itoa(m_show_errors, show_errors, 10);
     itoa(m_use_for_aac, use_for_aac, 10);
+    itoa(m_downmix, downmix, 10);
+    itoa(m_vbr_display, vbr_display, 10);
 
     WS(priority);
-	WS(resolution);
-	WS(show_errors);
-	WS(use_for_aac);
+    WS(resolution);
+    WS(show_errors);
+    WS(use_for_aac);
+    WS(downmix);
+    WS(vbr_display);
+    //WS(titleformat);
 }
 
-//-----------------------------------------------------------------------------
-
-int WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID pRes)
-{
-	if (fdwReason == DLL_PROCESS_ATTACH)
-		hInstance = hInst;
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-//old entrypoint api
-PLUGIN_API BOOL QInputModule(QCDModInitIn *ModInit, QCDModInfo *ModInfo)
-{
-	ModInit->version					= PLUGIN_API_VERSION;
-	ModInit->toModule.ShutDown			= ShutDown;
-	ModInit->toModule.GetTrackExtents	= GetTrackExtents;
-	ModInit->toModule.GetMediaSupported = GetMediaSupported;
-	ModInit->toModule.GetCurrentPosition= GetCurrentPosition;
-	ModInit->toModule.Play				= Play;
-	ModInit->toModule.Pause				= Pause;
-	ModInit->toModule.Stop				= Stop;
-	ModInit->toModule.SetVolume			= SetVolume;
-	ModInit->toModule.About				= About;
-	ModInit->toModule.Configure			= Configure;
-	QCDCallbacks = ModInit;
-
-	/* read config */
-	QCDCallbacks->Service(opGetPluginSettingsFile, INI_FILE, MAX_PATH, 0);
-	config_read();
-
-	ModInfo->moduleString = "MPEG-4 General Audio Plugin v1.0";
-	ModInfo->moduleExtensions = m_use_for_aac ? "MP4:M4A:AAC" : "MP4:M4A";
-
-	hwndPlayer = (HWND)ModInit->Service(opGetParentWnd, 0, 0, 0);
-	mp4state.filename[0] = 0;
-	mp4state.seek_needed = -1;
-	mp4state.paused = 0;
-	play_thread_handle = INVALID_HANDLE_VALUE;
-
-	oldAPIs = 1;
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-
-PLUGIN_API QCDModInitIn* INPUTDLL_ENTRY_POINT(QCDModInitIn *ModInit, QCDModInfo *ModInfo)
-{
-	sQCDCallbacks.version						= PLUGIN_API_VERSION;
-	sQCDCallbacks.toModule.Initialize			= Initialize;
-	sQCDCallbacks.toModule.ShutDown				= ShutDown;
-	sQCDCallbacks.toModule.GetTrackExtents		= GetTrackExtents;
-	sQCDCallbacks.toModule.GetMediaSupported	= GetMediaSupported;
-	sQCDCallbacks.toModule.GetCurrentPosition	= GetCurrentPosition;
-	sQCDCallbacks.toModule.Play					= Play;
-	sQCDCallbacks.toModule.Pause				= Pause;
-	sQCDCallbacks.toModule.Stop					= Stop;
-	sQCDCallbacks.toModule.SetVolume			= SetVolume;
-	sQCDCallbacks.toModule.About				= About;
-	sQCDCallbacks.toModule.Configure			= Configure;
-
-	QCDCallbacks = &sQCDCallbacks;
-	return &sQCDCallbacks;
-}
-
-//----------------------------------------------------------------------------
-
 int Initialize(QCDModInfo *ModInfo, int flags)
 {
-	hwndPlayer = (HWND)QCDCallbacks->Service(opGetParentWnd, 0, 0, 0);
+	ModInfo->moduleString = "MP4 Plug-in v" FAAD2_VERSION;
 
-	mp4state.filename[0] = 0;
-	mp4state.seek_needed = -1;
-	mp4state.paused = 0;
-	play_thread_handle = INVALID_HANDLE_VALUE;
+	module.hMainWindow = (HWND)module.QCDCallbacks.Service(opGetParentWnd, 0, 0, 0);
 
-	/* read config */
-	QCDCallbacks->Service(opGetPluginSettingsFile, INI_FILE, MAX_PATH, 0);
+	// read config from config file
     config_read();
 
-	ModInfo->moduleString = "MPEG-4 General Audio Plugin v1.0";
-	ModInfo->moduleExtensions = m_use_for_aac ? "MP4:M4A:AAC" : "MP4:M4A";
+	ModInfo->moduleExtensions = !m_use_for_aac ? "MP4:M4A" : "MP4:M4A:AAC";
 
-	// insert menu item into plugin menu
-//	QCDCallbacks->Service(opSetPluginMenuItem, hInstance, IDD_CONFIG, (long)"Mp4 Plug-in");
-
-	return TRUE;
+	// return TRUE for successful initialization
+	return 1;
 }
 
 //----------------------------------------------------------------------------
@@ -255,122 +258,689 @@
 void ShutDown(int flags) 
 {
 	Stop(mp4state.filename, STOPFLAG_FORCESTOP);
-
-	// delete the inserted plugin menu
-//	QCDCallbacks->Service(opSetPluginMenuItem, hInstance, 0, 0);
 }
 
-//-----------------------------------------------------------------------------
+///* Convert UNICODE to UTF-8
+//   Return number of bytes written */
+//int unicodeToUtf8 ( const WCHAR* lpWideCharStr, char* lpMultiByteStr, int cwcChars )
+//{
+//    const unsigned short*   pwc = (unsigned short *)lpWideCharStr;
+//    unsigned char*          pmb = (unsigned char  *)lpMultiByteStr;
+//    const unsigned short*   pwce;
+//    size_t  cBytes = 0;
+//
+//    if ( cwcChars >= 0 ) {
+//        pwce = pwc + cwcChars;
+//    } else {
+//        pwce = (unsigned short *)((size_t)-1);
+//    }
+//
+//    while ( pwc < pwce ) {
+//        unsigned short  wc = *pwc++;
+//
+//        if ( wc < 0x00000080 ) {
+//            *pmb++ = (char)wc;
+//            cBytes++;
+//        } else
+//        if ( wc < 0x00000800 ) {
+//            *pmb++ = (char)(0xC0 | ((wc >>  6) & 0x1F));
+//            cBytes++;
+//            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
+//            cBytes++;
+//        } else
+//        if ( wc < 0x00010000 ) {
+//            *pmb++ = (char)(0xE0 | ((wc >> 12) & 0x0F));
+//            cBytes++;
+//            *pmb++ = (char)(0x80 | ((wc >>  6) & 0x3F));
+//            cBytes++;
+//            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
+//            cBytes++;
+//        }
+//        if ( wc == L'\0' )
+//            return cBytes;
+//    }
+//
+//    return cBytes;
+//}
+//
+///* Convert UTF-8 coded string to UNICODE
+//   Return number of characters converted */
+//int utf8ToUnicode ( const char* lpMultiByteStr, WCHAR* lpWideCharStr, int cmbChars )
+//{
+//    const unsigned char*    pmb = (unsigned char  *)lpMultiByteStr;
+//    unsigned short*         pwc = (unsigned short *)lpWideCharStr;
+//    const unsigned char*    pmbe;
+//    size_t  cwChars = 0;
+//
+//    if ( cmbChars >= 0 ) {
+//        pmbe = pmb + cmbChars;
+//    } else {
+//        pmbe = (unsigned char *)((size_t)-1);
+//    }
+//
+//    while ( pmb < pmbe ) {
+//        char            mb = *pmb++;
+//        unsigned int    cc = 0;
+//        unsigned int    wc;
+//
+//        while ( (cc < 7) && (mb & (1 << (7 - cc)))) {
+//            cc++;
+//        }
+//
+//        if ( cc == 1 || cc > 6 )                    // illegal character combination for UTF-8
+//            continue;
+//
+//        if ( cc == 0 ) {
+//            wc = mb;
+//        } else {
+//            wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6);
+//            while ( --cc > 0 ) {
+//                if ( pmb == pmbe )                  // reached end of the buffer
+//                    return cwChars;
+//                mb = *pmb++;
+//                if ( ((mb >> 6) & 0x03) != 2 )      // not part of multibyte character
+//                    return cwChars;
+//                wc |= (mb & 0x3F) << ((cc - 1) * 6);
+//            }
+//        }
+//
+//        if ( wc & 0xFFFF0000 )
+//            wc = L'?';
+//        *pwc++ = wc;
+//        cwChars++;
+//        if ( wc == L'\0' )
+//            return cwChars;
+//    }
+//
+//    return cwChars;
+//}
+//
+///* convert Windows ANSI to UTF-8 */
+//int ConvertANSIToUTF8 ( const char* ansi, char* utf8 )
+//{
+//    WCHAR*  wszValue;          // Unicode value
+//    size_t  ansi_len;
+//    size_t  len;
+//
+//    *utf8 = '\0';
+//    if ( ansi == NULL )
+//        return 0;
+//
+//    ansi_len = strlen ( ansi );
+//
+//    if ( (wszValue = (WCHAR *)malloc ( (ansi_len + 1) * 2 )) == NULL )
+//        return 0;
+//
+//    /* Convert ANSI value to Unicode */
+//    if ( (len = MultiByteToWideChar ( CP_ACP, 0, ansi, ansi_len + 1, wszValue, (ansi_len + 1) * 2 )) == 0 ) {
+//        free ( wszValue );
+//        return 0;
+//    }
+//
+//    /* Convert Unicode value to UTF-8 */
+//    if ( (len = unicodeToUtf8 ( wszValue, utf8, -1 )) == 0 ) {
+//        free ( wszValue );
+//        return 0;
+//    }
+//
+//    free ( wszValue );
+//
+//    return len-1;
+//}
+//
+///* convert UTF-8 to Windows ANSI */
+//int ConvertUTF8ToANSI ( const char* utf8, char* ansi )
+//{
+//    WCHAR*  wszValue;          // Unicode value
+//    size_t  utf8_len;
+//    size_t  len;
+//
+//    *ansi = '\0';
+//    if ( utf8 == NULL )
+//        return 0;
+//
+//    utf8_len = strlen ( utf8 );
+//
+//    if ( (wszValue = (WCHAR *)malloc ( (utf8_len + 1) * 2 )) == NULL )
+//        return 0;
+//
+//    /* Convert UTF-8 value to Unicode */
+//    if ( (len = utf8ToUnicode ( utf8, wszValue, utf8_len + 1 )) == 0 ) {
+//        free ( wszValue );
+//        return 0;
+//    }
+//
+//    /* Convert Unicode value to ANSI */
+//    if ( (len = WideCharToMultiByte ( CP_ACP, 0, wszValue, -1, ansi, (utf8_len + 1) * 2, NULL, NULL )) == 0 ) {
+//        free ( wszValue );
+//        return 0;
+//    }
+//
+//    free ( wszValue );
+//
+//    return len-1;
+//}
+//
+//BOOL uSetDlgItemText(HWND hwnd, int id, const char *str)
+//{
+//    char *temp;
+//    size_t len;
+//    int r;
+//
+//    if (!str) return FALSE;
+//    len = strlen(str);
+//    temp = malloc(len+1);
+//    if (!temp) return FALSE;
+//    r = ConvertUTF8ToANSI(str, temp);
+//    if (r > 0)
+//        SetDlgItemText(hwnd, id, temp);
+//    free(temp);
+//
+//    return r>0 ? TRUE : FALSE;
+//}
+//
+//UINT uGetDlgItemText(HWND hwnd, int id, char *str, int max)
+//{
+//    char *temp, *utf8;
+//    int len;
+//    HWND w;
+//
+//    if (!str) return 0;
+//    w = GetDlgItem(hwnd, id);
+//    len = GetWindowTextLength(w);
+//    temp = malloc(len+1);
+//    if (!temp) return 0;
+//    utf8 = malloc((len+1)*4);
+//    if (!utf8)
+//    {
+//        free(temp);
+//        return 0;
+//    }
+//
+//    len = GetWindowText(w, temp, len+1);
+//    if (len > 0)
+//    {
+//        len = ConvertANSIToUTF8(temp, utf8);
+//        if (len > max-1)
+//        {
+//            len = max-1;
+//            utf8[max] = '\0';
+//        }
+//        memcpy(str, utf8, len+1);
+//    }
+//
+//    free(temp);
+//    free(utf8);
+//
+//    return len;
+//}
+//
+//BOOL CALLBACK mp4_info_dialog_proc(HWND hwndDlg, UINT message,
+//                                   WPARAM wParam, LPARAM lParam)
+//{
+//    char *file_info;
+//    MP4FileHandle file;
+//    char *pVal, dummy1[1024], dummy3;
+//    short dummy, dummy2;
+//
+//#ifdef DEBUG_OUTPUT
+//    in_mp4_DebugOutput("mp4_info_dialog_proc");
+//#endif
+//
+//    switch (message) {
+//    case WM_INITDIALOG:
+//        EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT), FALSE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT), SW_HIDE);
+//        EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT1), FALSE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT1), SW_HIDE);
+//        EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT2), FALSE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT2), SW_HIDE);
+//
+//
+//        file = MP4Read(info_fn, 0);
+//
+//        if (file == MP4_INVALID_FILE_HANDLE)
+//            return FALSE;
+//
+//        file_info = MP4Info(file, MP4_INVALID_TRACK_ID);
+//        SetDlgItemText(hwndDlg, IDC_INFOTEXT, file_info);
+//        free(file_info);
+//
+//        /* get Metadata */
+//
+//        pVal = NULL;
+//        MP4GetMetadataName(file, &pVal);
+//        uSetDlgItemText(hwndDlg,IDC_METANAME, pVal);
+//
+//        pVal = NULL;
+//        MP4GetMetadataArtist(file, &pVal);
+//        uSetDlgItemText(hwndDlg,IDC_METAARTIST, pVal);
+//
+//        pVal = NULL;
+//        MP4GetMetadataWriter(file, &pVal);
+//        uSetDlgItemText(hwndDlg,IDC_METAWRITER, pVal);
+//
+//        pVal = NULL;
+//        MP4GetMetadataComment(file, &pVal);
+//        uSetDlgItemText(hwndDlg,IDC_METACOMMENTS, pVal);
+//
+//        pVal = NULL;
+//        MP4GetMetadataAlbum(file, &pVal);
+//        uSetDlgItemText(hwndDlg,IDC_METAALBUM, pVal);
+//
+//        pVal = NULL;
+//        MP4GetMetadataGenre(file, &pVal);
+//        uSetDlgItemText(hwndDlg,IDC_METAGENRE, pVal);
+//
+//        dummy = 0;
+//        MP4GetMetadataTempo(file, &dummy);
+//        wsprintf(dummy1, "%d", dummy);
+//        SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
+//
+//        dummy = 0; dummy2 = 0;
+//        MP4GetMetadataTrack(file, &dummy, &dummy2);
+//        wsprintf(dummy1, "%d", dummy);
+//        SetDlgItemText(hwndDlg,IDC_METATRACK1, dummy1);
+//        wsprintf(dummy1, "%d", dummy2);
+//        SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
+//
+//        dummy = 0; dummy2 = 0;
+//        MP4GetMetadataDisk(file, &dummy, &dummy2);
+//        wsprintf(dummy1, "%d", dummy);
+//        SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
+//        wsprintf(dummy1, "%d", dummy2);
+//        SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
+//
+//        pVal = NULL;
+//        MP4GetMetadataYear(file, &pVal);
+//        uSetDlgItemText(hwndDlg,IDC_METAYEAR, pVal);
+//
+//        dummy3 = 0;
+//        MP4GetMetadataCompilation(file, &dummy3);
+//        if (dummy3)
+//            SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_SETCHECK, BST_CHECKED, 0);
+//
+//        /* ! Metadata */
+//
+//        MP4Close(file);
+//
+//        return TRUE;
+//
+//    case WM_COMMAND:
+//        switch (LOWORD(wParam)) {
+//        case IDCANCEL:
+//            EndDialog(hwndDlg, wParam);
+//            return TRUE;
+//        case IDOK:
+//
+//            /* save Metadata changes */
+//
+//            file = MP4Modify(info_fn, 0, 0);
+//            if (file == MP4_INVALID_FILE_HANDLE)
+//            {
+//                EndDialog(hwndDlg, wParam);
+//                return FALSE;
+//            }
+//
+//            uGetDlgItemText(hwndDlg, IDC_METANAME, dummy1, 1024);
+//            MP4SetMetadataName(file, dummy1);
+//
+//            uGetDlgItemText(hwndDlg, IDC_METAWRITER, dummy1, 1024);
+//            MP4SetMetadataWriter(file, dummy1);
+//
+//            uGetDlgItemText(hwndDlg, IDC_METAARTIST, dummy1, 1024);
+//            MP4SetMetadataArtist(file, dummy1);
+//
+//            uGetDlgItemText(hwndDlg, IDC_METAALBUM, dummy1, 1024);
+//            MP4SetMetadataAlbum(file, dummy1);
+//
+//            uGetDlgItemText(hwndDlg, IDC_METACOMMENTS, dummy1, 1024);
+//            MP4SetMetadataComment(file, dummy1);
+//
+//            uGetDlgItemText(hwndDlg, IDC_METAGENRE, dummy1, 1024);
+//            MP4SetMetadataGenre(file, dummy1);
+//
+//            uGetDlgItemText(hwndDlg, IDC_METAYEAR, dummy1, 1024);
+//            MP4SetMetadataYear(file, dummy1);
+//
+//            GetDlgItemText(hwndDlg, IDC_METATRACK1, dummy1, 1024);
+//            dummy = atoi(dummy1);
+//            GetDlgItemText(hwndDlg, IDC_METATRACK2, dummy1, 1024);
+//            dummy2 = atoi(dummy1);
+//            MP4SetMetadataTrack(file, dummy, dummy2);
+//
+//            GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
+//            dummy = atoi(dummy1);
+//            GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
+//            dummy2 = atoi(dummy1);
+//            MP4SetMetadataDisk(file, dummy, dummy2);
+//
+//            GetDlgItemText(hwndDlg, IDC_METATEMPO, dummy1, 1024);
+//            dummy = atoi(dummy1);
+//            MP4SetMetadataTempo(file, dummy);
+//
+//            dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
+//            MP4SetMetadataCompilation(file, dummy3);
+//
+//            MP4Close(file);
+//
+//            MP4Optimize(info_fn, NULL, 0);
+//            /* ! */
+//
+//            EndDialog(hwndDlg, wParam);
+//            return TRUE;
+//        }
+//    }
+//    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;
+//}
+//
+//BOOL CALLBACK aac_info_dialog_proc(HWND hwndDlg, UINT message,
+//                                   WPARAM wParam, LPARAM lParam)
+//{
+//    faadAACInfo aacInfo;
+//    char *info_text, *header_string;
+//
+//#ifdef DEBUG_OUTPUT
+//    in_mp4_DebugOutput("aac_info_dialog_proc");
+//#endif
+//
+//    switch (message) {
+//    case WM_INITDIALOG:
+//        EnableWindow(GetDlgItem(hwndDlg,IDC_USERDATA), FALSE) ;
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_USERDATA), SW_HIDE);
+//
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC1), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC2), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC3), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC4), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC5), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC6), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC7), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC8), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC9), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC10), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC11), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_STATIC12), SW_HIDE);
+//
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METANAME), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METAARTIST), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METAWRITER), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METACOMMENTS), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METAALBUM), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METAGENRE), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METATEMPO), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METATRACK1), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METATRACK2), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METADISK1), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METADISK2), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METAYEAR), SW_HIDE);
+//        ShowWindow(GetDlgItem(hwndDlg,IDC_METACOMPILATION), SW_HIDE);
+//
+//        info_text = malloc(1024*sizeof(char));
+//
+//        get_AAC_format(info_fn, &aacInfo);
+//
+//        switch (aacInfo.headertype)
+//        {
+//        case 0: /* RAW */
+//            header_string = " RAW";
+//            break;
+//        case 1: /* ADIF */
+//            header_string = " ADIF";
+//            break;
+//        case 2: /* ADTS */
+//            header_string = " ADTS";
+//            break;
+//        }
+//
+//        sprintf(info_text, "%s AAC %s%s, %d sec, %d kbps, %d Hz",
+//            (aacInfo.version==2)?"MPEG-2":"MPEG-4", get_ot_string(aacInfo.object_type),
+//            header_string,
+//            (int)((float)aacInfo.length/1000.0), (int)((float)aacInfo.bitrate/1000.0+0.5),
+//            aacInfo.sampling_rate);
+//
+//        SetDlgItemText(hwndDlg, IDC_INFOTEXT, info_text);
+//
+//        free(info_text);
+//
+//        return TRUE;
+//
+//    case WM_COMMAND:
+//        switch (LOWORD(wParam))
+//        {
+//        case IDC_CONVERT:
+//            {
+//                char mp4FileName[256];
+//                char *extension;
+//                OPENFILENAME ofn;
+//
+//                lstrcpy(mp4FileName, info_fn);
+//                extension = strrchr(mp4FileName, '.');
+//                lstrcpy(extension, ".mp4");
+//
+//                memset(&ofn, 0, sizeof(OPENFILENAME));
+//                ofn.lStructSize = sizeof(OPENFILENAME);
+//                ofn.hwndOwner = hwndDlg;
+//                ofn.hInstance = module.hDllInstance;
+//                ofn.nMaxFileTitle = 31;
+//                ofn.lpstrFile = (LPSTR)mp4FileName;
+//                ofn.nMaxFile = _MAX_PATH;
+//                ofn.lpstrFilter = "MP4 Files (*.mp4)\0*.mp4\0";
+//                ofn.lpstrDefExt = "mp4";
+//                ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
+//                ofn.lpstrTitle = "Select Output File";
+//
+//                if (GetSaveFileName(&ofn))
+//                {
+//                    if (covert_aac_to_mp4(info_fn, mp4FileName))
+//                    {
+//                        MessageBox(hwndDlg, "An error occured while converting AAC to MP4!", "An error occured!", MB_OK);
+//                        return FALSE;
+//                    }
+//                }
+//                return TRUE;
+//            }
+//        case IDCANCEL:
+//        case IDOK:
+//            EndDialog(hwndDlg, wParam);
+//            return TRUE;
+//        }
+//    }
+//    return FALSE;
+//}
+//
+//int infoDlg(char *fn, HWND hwndParent)
+//{
+//    if(!stricmp(fn + strlen(fn) - 3,"AAC"))
+//    {
+//        lstrcpy(info_fn, fn);
+//
+//        DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
+//            hwndParent, aac_info_dialog_proc);
+//    } else {
+//        lstrcpy(info_fn, fn);
+//
+//        DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
+//            hwndParent, mp4_info_dialog_proc);
+//    }
+//
+//    return 0;
+//}
+//
+///* Get the title from the file */
+//void ConstructTitle(MP4FileHandle file, char *filename, char *title, char *format)
+//{
+//    char temp[4096];
+//    int some_info = 0;
+//    char *in = format;
+//    char *out = temp;//title;
+//    char *bound = out + sizeof(temp) - 256; //out + (MAX_PATH - 10 - 1);
+//    char *pVal, dummy1[1024];
+//    short dummy, dummy2;
+//
+//
+//    while (*in && out < bound)
+//    {
+//        switch (*in)
+//        {
+//        case '%':
+//            ++in;
+//            break;
+//
+//        default:
+//            *out++ = *in++;
+//            continue;
+//        }
+//
+//        /* handle % escape sequence */
+//        switch (*in++)
+//        {
+//        case '0':
+//            dummy = 0; dummy2 = 0;
+//            if (MP4GetMetadataTrack(file, &dummy, &dummy2))
+//            {
+//                out += wsprintf(out, "%d", (int)dummy);
+//                some_info = 1;
+//            }
+//            break;
+//
+//        case '1':
+//            pVal = NULL;
+//            if (MP4GetMetadataArtist(file, &pVal))
+//            {
+//                out += wsprintf(out, "%s", pVal);
+//                some_info = 1;
+//            }
+//            break;
+//
+//        case '2':
+//            pVal = NULL;
+//            if (MP4GetMetadataName(file, &pVal))
+//            {
+//                out += wsprintf(out, "%s", pVal);
+//                some_info = 1;
+//            }
+//            break;
+//
+//        case '3':
+//            pVal = NULL;
+//            if (MP4GetMetadataAlbum(file, &pVal))
+//            {
+//                out += wsprintf(out, "%s", pVal);
+//                some_info = 1;
+//            }
+//            break;
+//
+//        case '4':
+//            pVal = NULL;
+//            if (MP4GetMetadataYear(file, &pVal))
+//            {
+//                out += wsprintf(out, "%s", pVal);
+//                some_info = 1;
+//            }
+//            break;
+//
+//        case '5':
+//            pVal = NULL;
+//            if (MP4GetMetadataComment(file, &pVal))
+//            {
+//                out += wsprintf(out, "%s", pVal);
+//                some_info = 1;
+//            }
+//            break;
+//
+//        case '6':
+//            pVal = NULL;
+//            if (MP4GetMetadataGenre(file, &pVal))
+//            {
+//                out += wsprintf(out, "%s", pVal);
+//                some_info = 1;
+//            }
+//            break;
+//
+//        case '7':
+//            {
+//                const char *p=strrchr(filename,'\\');
+//                if (!p) p=filename; else p++;
+//                out += ConvertANSIToUTF8(p, out);
+//                some_info = 1;
+//                break;
+//            }
+//
+//        default:
+//            break;
+//        }
+//    }
+//
+//    *out = '\0';
+//
+//    if (!some_info)
+//    {
+//        char *p=filename+lstrlen(filename);
+//        while (*p != '\\' && p >= filename) p--;
+//        lstrcpy(title,++p);
+//    }
+//    else
+//    {
+//        int len = ConvertUTF8ToANSI(temp, dummy1);
+//        if (len > (MAX_PATH - 10 - 1)) len = (MAX_PATH - 10 - 1);
+//        memcpy(title, dummy1, len);
+//        title[len] = '\0';
+//    }
+//}
 
-int GetMediaSupported(const char* medianame, MediaInfo *mediaInfo) 
-{
-	char *ch = strrchr(medianame, '.');
-
-	if (!medianame || !*medianame)
-		return FALSE;
-
-	if(!ch)
-		return (lstrlen(medianame) > 2); // no extension defaults to me (if not drive letter)
-
-   /* Finally fixed */
-    if(StringComp(ch, ".mp4", 4) == 0)
-    {
-		mediaInfo->mediaType = DIGITAL_FILE_MEDIA;
-		mediaInfo->op_canSeek = TRUE;
-		mp4state.filetype = 0;
-		return TRUE;
-	}
-	else if(StringComp(ch, ".aac", 4) ==0)
-	{
-		mediaInfo->mediaType = DIGITAL_FILE_MEDIA;
-		mediaInfo->op_canSeek = FALSE;
-		mp4state.filetype = 1;
-		return TRUE;
-	}
-	else
-		return FALSE;
-}
-
-//-----------------------------------------------------------------------------
-
-int getsonglength(char *fn)
-{
-    long msDuration = 0;
-
-    if(StringComp(fn + strlen(fn) - 3, "MP4", 3) == 0)
-    {
-        int track;
-        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;
-    } 
-	else 
-	{
-//        faadAACInfo aacInfo;
-//        get_AAC_format(fn, &aacInfo);
-
-//        return aacInfo.length;
-        return 0;
-    }
-}
-
-int GetTrackExtents(const char* medianame, TrackExtents *ext, int flags)
-{
-	ext->track = 1;
-	ext->start = 0;
-	if( (ext->end = getsonglength(medianame)) < 0 )
-		return FALSE;
-	ext->bytesize = 0;
-	ext->unitpersec = 1000;
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-
 BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message,
                                  WPARAM wParam, LPARAM lParam)
 {
     int i;
 
-    switch (message) 
-	{
+    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, 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);
         if (m_use_for_aac)
             SendMessage(GetDlgItem(hwndDlg, IDC_USEFORAAC), BM_SETCHECK, BST_CHECKED, 0);
+        if (m_downmix)
+            SendMessage(GetDlgItem(hwndDlg, IDC_DOWNMIX), BM_SETCHECK, BST_CHECKED, 0);
+        if (m_vbr_display)
+            SendMessage(GetDlgItem(hwndDlg, IDC_VBR), BM_SETCHECK, BST_CHECKED, 0);
+        SetDlgItemText(hwndDlg, IDC_TITLEFORMAT, titleformat);
         return TRUE;
 
     case WM_COMMAND:
-        switch (LOWORD(wParam)) 
-		{
+        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_use_for_aac = SendMessage(GetDlgItem(hwndDlg, IDC_USEFORAAC), BM_GETCHECK, 0, 0);
+            m_downmix = SendMessage(GetDlgItem(hwndDlg, IDC_DOWNMIX), BM_GETCHECK, 0, 0);
+            m_vbr_display = SendMessage(GetDlgItem(hwndDlg, IDC_VBR), BM_GETCHECK, 0, 0);
+            GetDlgItemText(hwndDlg, IDC_TITLEFORMAT, titleformat, MAX_PATH);
+
             m_priority = SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_GETPOS, 0, 0);
-            for (i = 0; i < 5; i++)
+            for (i = 0; i < 6; i++)
             {
                 if (SendMessage(GetDlgItem(hwndDlg, res_id_table[i]), BM_GETCHECK, 0, 0))
                 {
@@ -381,8 +951,15 @@
 
             /* save config */
             config_write();
-        case IDCANCEL:
-            DestroyWindow(hwndDlg);
+
+            //if (!m_use_for_aac)
+            //{
+            //    module.FileExtensions = short_ext_list;
+            //} else {
+            //    module.FileExtensions = long_ext_list;
+            //}
+
+            EndDialog(hwndDlg, wParam);
             return TRUE;
         }
     }
@@ -391,358 +968,572 @@
 
 void Configure(int flags)
 {
-	if(!IsWindow(hwndConfig))
-		hwndConfig = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_CONFIG_INPUT), hwndPlayer, config_dialog_proc);
-	ShowWindow(hwndConfig, SW_SHOWNORMAL);
+	DialogBox(module.hInstance, MAKEINTRESOURCE(IDD_CONFIG),
+		module.hMainWindow, config_dialog_proc);
 }
 
 //-----------------------------------------------------------------------------
-// proc of "About Dialog"
-INT_PTR CALLBACK about_dialog_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+
+void About(int flags)
 {
-	static RECT rcLOGO, rcMail1, rcMail2/*, rcMail3*/;
-	POINT ptMouse;
-	static char szPluginVer[] = "QCD MP4 Input Plug-in v1.0\nCompiled on " __TIME__ ", " __DATE__;
-	static char szFLACVer[] = "Using: FAAD2 v "FAAD2_VERSION" by";
+	MessageBox(module.hMainWindow,
+        "AudioCoding.com MPEG-4 General Audio player " FAAD2_VERSION " compiled on " __DATE__ ".\n"
+        "Visit the website for more info.\n"
+		"Ported to QCD by Shao Hao.\n"
+        "Copyright 2002-2003 AudioCoding.com",
+        "About",
+        MB_OK);
+}
 
-	switch (uMsg)
-	{
-	case WM_INITDIALOG:
-	case WM_MOVE:
-		GetWindowRect(GetDlgItem(hwndDlg, IDC_LOGO), &rcLOGO);
-		GetWindowRect(GetDlgItem(hwndDlg, IDC_MAIL1), &rcMail1);
-		GetWindowRect(GetDlgItem(hwndDlg, IDC_MAIL2), &rcMail2);
-//		GetWindowRect(GetDlgItem(hwndDlg, IDC_MAIL2), &rcMail3);
+//-----------------------------------------------------------------------------
 
-		SetDlgItemText(hwndDlg, IDC_PLUGINVER, szPluginVer);
-		SetDlgItemText(hwndDlg, IDC_FAADVER, szFLACVer);
-		
-		return TRUE;
-	case WM_MOUSEMOVE:
-		ptMouse.x = LOWORD(lParam);
-		ptMouse.y = HIWORD(lParam);
-		ClientToScreen(hwndDlg, &ptMouse);
-		if( (ptMouse.x >= rcLOGO.left && ptMouse.x <= rcLOGO.right && 
-			ptMouse.y >= rcLOGO.top && ptMouse.y<= rcLOGO.bottom) 
-			||
-			(ptMouse.x >= rcMail1.left && ptMouse.x <= rcMail1.right && 
-			ptMouse.y >= rcMail1.top && ptMouse.y<= rcMail1.bottom) 
-			||
-			(ptMouse.x >= rcMail2.left && ptMouse.x <= rcMail2.right && 
-			ptMouse.y >= rcMail2.top && ptMouse.y<= rcMail2.bottom) 
-/*			||
-			(ptMouse.x >= rcMail3.left && ptMouse.x <= rcMail3.right && 
-			ptMouse.y >= rcMail3.top && ptMouse.y<= rcMail3.bottom)*/ )
-			SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(32649)));
-		else
-			SetCursor(LoadCursor(NULL, IDC_ARROW));
+int fill_buffer(state *st)
+{
+    int bread;
 
-		return TRUE;
-	case WM_LBUTTONDOWN:
-		ptMouse.x = LOWORD(lParam);
-		ptMouse.y = HIWORD(lParam);
-		ClientToScreen(hwndDlg, &ptMouse);
-		if(ptMouse.x >= rcLOGO.left && ptMouse.x <= rcLOGO.right && 
-			ptMouse.y >= rcLOGO.top && ptMouse.y<= rcLOGO.bottom)
-			ShellExecute(0, NULL, "http://www.audiocoding.com", NULL,NULL, SW_NORMAL);
-		else if(ptMouse.x >= rcMail1.left && ptMouse.x <= rcMail1.right && 
-			ptMouse.y >= rcMail1.top && ptMouse.y<= rcMail1.bottom)
-			ShellExecute(0, NULL, "mailto:shaohao@elong.com", NULL,NULL, SW_NORMAL);
-		else if(ptMouse.x >= rcMail2.left && ptMouse.x <= rcMail2.right && 
-			ptMouse.y >= rcMail2.top && ptMouse.y<= rcMail2.bottom)
-			ShellExecute(0, NULL, "mailto:menno@audiocoding.com", NULL,NULL, SW_NORMAL);
-/*		else if(ptMouse.x >= rcMail3.left && ptMouse.x <= rcMail3.right && 
-			ptMouse.y >= rcMail3.top && ptMouse.y<= rcMail3.bottom)
-			ShellExecute(0, NULL, "I don't know", NULL,NULL, SW_NORMAL);
-*/
-		return TRUE;
-	case WM_COMMAND:
-		switch(LOWORD(wParam))
-		{
-		case IDOK:
-		default:
-			DestroyWindow(hwndDlg);
-			return TRUE;
-		}
-	}
-	return FALSE;
+    if (st->m_aac_bytes_consumed > 0)
+    {
+        if (st->m_aac_bytes_into_buffer)
+        {
+            memmove((void*)st->m_aac_buffer, (void*)(st->m_aac_buffer + st->m_aac_bytes_consumed),
+                st->m_aac_bytes_into_buffer*sizeof(unsigned char));
+        }
+
+        if (!st->m_at_eof)
+        {
+            bread = fread((void*)(st->m_aac_buffer + st->m_aac_bytes_into_buffer),
+                1, st->m_aac_bytes_consumed, st->aacfile);
+
+            if (bread != st->m_aac_bytes_consumed)
+                st->m_at_eof = 1;
+
+            st->m_aac_bytes_into_buffer += bread;
+        }
+
+        st->m_aac_bytes_consumed = 0;
+
+        if (st->m_aac_bytes_into_buffer > 3)
+        {
+            if (memcmp(st->m_aac_buffer, "TAG", 3) == 0)
+                st->m_aac_bytes_into_buffer = 0;
+        }
+        if (st->m_aac_bytes_into_buffer > 11)
+        {
+            if (memcmp(st->m_aac_buffer, "LYRICSBEGIN", 11) == 0)
+                st->m_aac_bytes_into_buffer = 0;
+        }
+        if (st->m_aac_bytes_into_buffer > 8)
+        {
+            if (memcmp(st->m_aac_buffer, "APETAGEX", 8) == 0)
+                st->m_aac_bytes_into_buffer = 0;
+        }
+    }
+
+    return 1;
 }
 
-void About(int flags)
+void advance_buffer(state *st, int bytes)
 {
-	if(!IsWindow(hwndAbout))
-		hwndAbout = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_ABOUT), hwndPlayer, about_dialog_proc); 
-	ShowWindow(hwndAbout, SW_SHOWNORMAL);
+    st->m_file_offset += bytes;
+    st->m_aac_bytes_consumed = bytes;
+    st->m_aac_bytes_into_buffer -= bytes;
 }
 
-//-----------------------------------------------------------------------------
+int adts_parse(state *st, __int64 *bitrate, double *length)
+{
+    static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000};
+    int frames, frame_length;
+    int t_framelength = 0;
+    int samplerate;
+    double frames_per_sec, bytes_per_frame;
 
-int Play(const char* medianame, int playfrom, int playto, int flags)
+    /* Read all frames to ensure correct time and bitrate */
+    for (frames = 0; /* */; frames++)
+    {
+        fill_buffer(st);
+
+        if (st->m_aac_bytes_into_buffer > 7)
+        {
+            /* check syncword */
+            if (!((st->m_aac_buffer[0] == 0xFF)&&((st->m_aac_buffer[1] & 0xF6) == 0xF0)))
+                break;
+
+            st->m_tail->offset = st->m_file_offset;
+            st->m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
+            st->m_tail = st->m_tail->next;
+            st->m_tail->next = NULL;
+
+            if (frames == 0)
+                samplerate = sample_rates[(st->m_aac_buffer[2]&0x3c)>>2];
+
+            frame_length = ((((unsigned int)st->m_aac_buffer[3] & 0x3)) << 11)
+                | (((unsigned int)st->m_aac_buffer[4]) << 3) | (st->m_aac_buffer[5] >> 5);
+
+            t_framelength += frame_length;
+
+            if (frame_length > st->m_aac_bytes_into_buffer)
+                break;
+
+            advance_buffer(st, frame_length);
+        } else {
+            break;
+        }
+    }
+
+    frames_per_sec = (double)samplerate/1024.0;
+    if (frames != 0)
+        bytes_per_frame = (double)t_framelength/(double)(frames*1000);
+    else
+        bytes_per_frame = 0;
+    *bitrate = (__int64)(8. * bytes_per_frame * frames_per_sec + 0.5);
+    if (frames_per_sec != 0)
+        *length = (double)frames/frames_per_sec;
+    else
+        *length = 1;
+
+    return 1;
+}
+
+int skip_id3v2_tag()
 {
-	static WAVEFORMATEX wf;
+    unsigned char buf[10];
+    int bread, tagsize = 0;
 
-	if(flags == PLAYFLAG_ENCODING)
+    bread = fread(buf, 1, 10, mp4state.aacfile);
+    if (bread != 10) return -1;
+
+    if (!memcmp(buf, "ID3", 3))
+    {
+        /* high bit is not used */
+        tagsize = (buf[6] << 21) | (buf[7] << 14) | (buf[8] << 7) | (buf[9] << 0);
+
+        tagsize += 10;
+        fseek(mp4state.aacfile, tagsize, SEEK_SET);
+    } else {
+        fseek(mp4state.aacfile, 0, SEEK_SET);
+    }
+
+    return tagsize;
+}
+
+int GetMediaSupported(const char* medianame, MediaInfo *mediaInfo) 
+{
+    int tagsize = 0, init;
+
+	if (!medianame || !*medianame)
+		return 0;
+
+    if (!stricmp(medianame + strlen(medianame) - 3,"MP4") || !stricmp(medianame + strlen(medianame) - 3,"M4A"))
+    {
+		if (mediaInfo)
+		{
+			mediaInfo->mediaType = DIGITAL_FILE_MEDIA;
+			mediaInfo->op_canSeek = 1;
+		}
+		return 1;
+	}
+	else if (m_use_for_aac && !stricmp(medianame + strlen(medianame) - 3,"AAC"))
 	{
-		if(QCDCallbacks->toPlayer.OutputOpen(medianame, &wf))
-			Stop(medianame, STOPFLAG_FORCESTOP);
-		return FALSE;
+		if (mediaInfo)
+		{
+			mediaInfo->mediaType = DIGITAL_FILE_MEDIA;
+			mediaInfo->op_canSeek = 1;
+
+			memset(&mp4state, 0, sizeof(state));
+			lstrcpy(mp4state.filename, medianame);
+
+			if (!(mp4state.aacfile = fopen(mp4state.filename, "rb")))
+			{
+				// error
+				return 0;
+			}
+
+			tagsize = skip_id3v2_tag();
+			if (tagsize<0) return 0;
+
+			if (!(mp4state.m_aac_buffer = (unsigned char*)malloc(768*6)))
+			{
+				show_error(module.hMainWindow, "Memory allocation error.");
+				return 0;
+			}
+
+			for (init=0; init<2; init++)
+			{
+				memset(mp4state.m_aac_buffer, 0, 768*6);
+				fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
+
+				if (init==0)
+					fseek(mp4state.aacfile, tagsize, SEEK_SET);
+			}
+
+			if (memcmp(mp4state.m_aac_buffer, "ADIF", 4) == 0)
+				mediaInfo->op_canSeek = (double)file_length(mp4state.aacfile) == -1 ? 0 : 1;
+
+			free(mp4state.m_aac_buffer);
+
+			fclose(mp4state.aacfile);
+		}
+		return 1;
 	}
 
-	if(stricmp(mp4state.filename, medianame) != 0)
-	{
-		sQCDCallbacks.toPlayer.OutputStop(STOPFLAG_PLAYDONE);
+	return 0;
+}
+
+int Play(const char* medianame, int playfrom, int playto, int flags)
+{
+    WAVEFORMATEX wf;
+    //int maxlatency;
+    int thread_id;
+    int avg_bitrate, br, sr;
+    unsigned char *buffer;
+    int buffer_size;
+    faacDecConfigurationPtr config;
+
+#ifdef DEBUG_OUTPUT
+    in_mp4_DebugOutput("play");
+#endif
+
+	if (stricmp(mp4state.filename, medianame) != 0)
 		Stop(mp4state.filename, STOPFLAG_PLAYDONE);
-	}
 
-	if(mp4state.paused)
+	if (mp4state.paused)
 	{
 		// Update the player controls to reflect the new unpaused state
-		sQCDCallbacks.toPlayer.OutputPause(0);
-		
-		Pause(medianame, PAUSE_DISABLED);
-		
+		module.QCDCallbacks.toPlayer.OutputPause(0);
+
+		Pause(medianame, 0);
+
 		if (playfrom >= 0)
 			mp4state.seek_needed = playfrom;
 	}
-	else if(play_thread_handle != INVALID_HANDLE_VALUE)
+	else if (PlayThreadAlive) // is playing
 	{
 		mp4state.seek_needed = playfrom;
-		return TRUE;
+		return 1;
 	}
 	else
 	{
-#ifdef DEBUG_OUTPUT
-		in_mp4_DebugOutput("play");
-#endif
-		int thread_id;
-		int avg_bitrate, br, sr;
-		unsigned char *buffer;
-		int buffer_size;
-		faacDecConfigurationPtr config;	
-		
-		mp4state.channels = 0;
-		mp4state.samplerate = 0;
-		mp4state.filetype = 0;
+    memset(&mp4state, 0, sizeof(state));
 
-		strcpy(mp4state.filename, medianame);
+    lstrcpy(mp4state.filename, medianame);
 
-		if(StringComp(medianame + strlen(medianame) - 3, "AAC", 3) == 0)
-			mp4state.filetype = 1;
-		
-		mp4state.hDecoder = faacDecOpen();
-		if (!mp4state.hDecoder)
-		{
-			show_error(hwndPlayer, "Unable to open decoder library.");
-			return -1;
-		}
-		
-		config = faacDecGetCurrentConfiguration(mp4state.hDecoder);
-		config->outputFormat = m_resolution + 1;
-		faacDecSetConfiguration(mp4state.hDecoder, config);
-		
-		if (mp4state.filetype)
-		{
-			long pos, tmp, read, tagsize;
-			
-			//        get_AAC_format(mp4state.filename, &mp4state.aacInfo);
-			
-			mp4state.aacfile = fopen(mp4state.filename, "rb");
-			if (!mp4state.aacfile)
-			{
-				show_error(hwndPlayer, "Unable to open file.");
-				faacDecClose(mp4state.hDecoder);
-				return -1;
-			}
-			
-			pos = ftell(mp4state.aacfile);
-			fseek(mp4state.aacfile, 0, SEEK_END);
-			mp4state.filesize = ftell(mp4state.aacfile);
-			fseek(mp4state.aacfile, pos, SEEK_SET);
-			
-			if (!(mp4state.buffer=(unsigned char*)malloc(768*48)))
-			{
-				show_error(hwndPlayer, "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(hwndPlayer, "Error reading from file.");
-				faacDecClose(mp4state.hDecoder);
-				fclose(mp4state.aacfile);
-				return -1;
-			}
-			
-			if (StringComp(mp4state.buffer, "ID3", 3) == 0)
-			{
-				/* high bit is not used */
-				tagsize = (mp4state.buffer[6] << 21) | (mp4state.buffer[7] << 14) |
-					(mp4state.buffer[8] <<  7) | (mp4state.buffer[9] <<  0);
-				
-				tagsize += 10;
-			} 
-			else 
-			{
-				tagsize = 0;
-			}
-			
-			if ((mp4state.bytes_consumed = faacDecInit(mp4state.hDecoder,
-				mp4state.buffer+tagsize, mp4state.bytes_into_buffer,
-				&mp4state.samplerate, &mp4state.channels)) < 0)
-			{
-				show_error(hwndPlayer, "Can't initialize library.");
-				faacDecClose(mp4state.hDecoder);
-				fclose(mp4state.aacfile);
-				return -1;
-			}
-			mp4state.bytes_consumed += tagsize;
-			mp4state.bytes_into_buffer -= mp4state.bytes_consumed;
-			
-			//        avg_bitrate = mp4state.aacInfo.bitrate;
-			avg_bitrate = 0;
-			
-//			module.is_seekable = 0;
-		} 
-		else 
-		{
-			mp4state.mp4file = MP4Read(mp4state.filename, 0);
-			if (!mp4state.mp4file)
-			{
-				show_error(hwndPlayer, "Unable to open file.");
-				faacDecClose(mp4state.hDecoder);
-				return -1;
-			}
-			
-			if ((mp4state.mp4track = GetAACTrack(mp4state.mp4file)) < 0)
-			{
-				show_error(hwndPlayer, "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;
-		}
-		
-		if (mp4state.channels == 0)
-		{
-			show_error(hwndPlayer, "Number of channels not supported for playback.");
-			faacDecClose(mp4state.hDecoder);
-			if (mp4state.filetype)
-				fclose(mp4state.aacfile);
-			else
-				MP4Close(mp4state.mp4file);
-			return -1;
-		}
-		
-		// open outputdevice
-		wf.wFormatTag = WAVE_FORMAT_PCM;
-		wf.cbSize = 0;
-		wf.nChannels = mp4state.channels;
-		wf.wBitsPerSample = res_table[m_resolution];
-		wf.nSamplesPerSec = mp4state.samplerate;
-		wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
-		wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
-		if (!QCDCallbacks->toPlayer.OutputOpen(mp4state.filename, &wf))
-		{
-			show_error(hwndPlayer, "Error: Failed openning output plugin!");
-			faacDecClose(mp4state.hDecoder);
-			if (mp4state.filetype)
-				fclose(mp4state.aacfile);
-			else
-				MP4Close(mp4state.mp4file);
-			return -1; // cannot open sound device
-		}
-		
-		mp4state.paused			= 0;
-		mp4state.decode_pos_ms	= 0;
-		mp4state.seek_needed	= playfrom > 0 ? playfrom : -1;
-		
-		br = (int)floor(((float)avg_bitrate + 500.0)/1000.0);
-		sr = (int)floor((float)mp4state.samplerate/1000.0);
-		// show constant bitrate at first
-		{
-			AudioInfo cai;
-			cai.struct_size = sizeof(AudioInfo);
-			cai.frequency = sr * 1000;
-			cai.bitrate = br * 1000;
-			cai.mode = (mp4state.channels == 2) ? 0 : 3;
-			cai.layer = 0;
-			cai.level = 0;
-			QCDCallbacks->Service(opSetAudioInfo, &cai, sizeof(AudioInfo), 0);
-		}
-		
-		killPlayThread = 0;
-		
-		if (mp4state.filetype)
-		{
-			if ((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AACPlayThread,
-				(void *)&killPlayThread, 0, &thread_id)) == NULL)
-			{
-				show_error(hwndPlayer, "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(hwndPlayer, "Cannot create playback thread");
-				faacDecClose(mp4state.hDecoder);
-				MP4Close(mp4state.mp4file);
-				return -1;
-			}
-		}
-		
-		SetThreadAffinityMask(play_thread_handle, 1);
-		
-		if (m_priority != 3)
-			SetThreadPriority(play_thread_handle, priority_table[m_priority]);
+    if (!(mp4state.mp4file = MP4Read(mp4state.filename, 0)))
+    {
+        mp4state.filetype = 1;
+    } else {
+        MP4Close(mp4state.mp4file);
+        mp4state.filetype = 0;
+    }
+
+    if (mp4state.filetype)
+    {
+        int tagsize = 0, tmp = 0, init;
+        int bread = 0;
+        double length = 0.;
+        __int64 bitrate = 128;
+        faacDecFrameInfo frameInfo;
+
+        //module.is_seekable = 1;
+
+        if (!(mp4state.aacfile = fopen(mp4state.filename, "rb")))
+        {
+            // error
+            return -1;
+        }
+
+        tagsize = skip_id3v2_tag();
+        if (tagsize<0) return 0;
+
+        if (!(mp4state.m_aac_buffer = (unsigned char*)malloc(768*6)))
+        {
+            show_error(module.hMainWindow, "Memory allocation error.");
+            return -1;
+        }
+
+        for (init=0; init<2; init++)
+        {
+            mp4state.hDecoder = faacDecOpen();
+            if (!mp4state.hDecoder)
+            {
+                show_error(module.hMainWindow, "Unable to open decoder library.");
+                return -1;
+            }
+
+            config = faacDecGetCurrentConfiguration(mp4state.hDecoder);
+            config->outputFormat = m_resolution + 1;
+            config->downMatrix = m_downmix;
+            faacDecSetConfiguration(mp4state.hDecoder, config);
+
+            memset(mp4state.m_aac_buffer, 0, 768*6);
+            bread = fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
+            mp4state.m_aac_bytes_into_buffer = bread;
+            mp4state.m_aac_bytes_consumed = 0;
+            mp4state.m_file_offset = 0;
+            mp4state.m_at_eof = (bread != 768*6) ? 1 : 0;
+
+            if (init==0)
+            {
+                faacDecFrameInfo frameInfo;
+
+                fill_buffer(&mp4state);
+
+                if ((mp4state.m_aac_bytes_consumed = faacDecInit(mp4state.hDecoder,
+                    mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer,
+                    &mp4state.samplerate, &mp4state.channels)) < 0)
+                {
+                    show_error(module.hMainWindow, "Can't initialize decoder library.");
+                    return -1;
+                }
+                advance_buffer(&mp4state, mp4state.m_aac_bytes_consumed);
+
+                do {
+                    memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
+                    fill_buffer(&mp4state);
+                    faacDecDecode(mp4state.hDecoder, &frameInfo, mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer);
+                } while (!frameInfo.samples && !frameInfo.error);
+
+                if (frameInfo.error)
+                {
+                    show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
+                    return -1;
+                }
+
+                mp4state.channels = frameInfo.channels;
+                mp4state.samplerate = frameInfo.samplerate;
+                mp4state.framesize = (frameInfo.channels != 0) ? frameInfo.samples/frameInfo.channels : 0;
+                /*
+                sbr = frameInfo.sbr;
+                profile = frameInfo.object_type;
+                header_type = frameInfo.header_type;
+                */
+
+                faacDecClose(mp4state.hDecoder);
+                fseek(mp4state.aacfile, tagsize, SEEK_SET);
+            }
+        }
+
+        mp4state.m_head = (struct seek_list*)malloc(sizeof(struct seek_list));
+        mp4state.m_tail = mp4state.m_head;
+        mp4state.m_tail->next = NULL;
+
+        mp4state.m_header_type = 0;
+        if ((mp4state.m_aac_buffer[0] == 0xFF) && ((mp4state.m_aac_buffer[1] & 0xF6) == 0xF0))
+        {
+            if (1) //(can_seek)
+            {
+                adts_parse(&mp4state, &bitrate, &length);
+                fseek(mp4state.aacfile, tagsize, SEEK_SET);
+
+                bread = fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
+                if (bread != 768*6)
+                    mp4state.m_at_eof = 1;
+                else
+                    mp4state.m_at_eof = 0;
+                mp4state.m_aac_bytes_into_buffer = bread;
+                mp4state.m_aac_bytes_consumed = 0;
+
+                mp4state.m_header_type = 1;
+            }
+        } else if (memcmp(mp4state.m_aac_buffer, "ADIF", 4) == 0) {
+            int skip_size = (mp4state.m_aac_buffer[4] & 0x80) ? 9 : 0;
+            bitrate = ((unsigned int)(mp4state.m_aac_buffer[4 + skip_size] & 0x0F)<<19) |
+                ((unsigned int)mp4state.m_aac_buffer[5 + skip_size]<<11) |
+                ((unsigned int)mp4state.m_aac_buffer[6 + skip_size]<<3) |
+                ((unsigned int)mp4state.m_aac_buffer[7 + skip_size] & 0xE0);
+
+            length = (double)file_length(mp4state.aacfile);
+            if (length == -1)
+            {
+                //module.is_seekable = 0;
+                length = 0;
+            } else {
+                length = ((double)length*8.)/((double)bitrate) + 0.5;
+            }
+
+            mp4state.m_header_type = 2;
+        } else {
+            length = (double)file_length(mp4state.aacfile);
+            length = ((double)length*8.)/((double)bitrate*1000.) + 0.5;
+
+            //module.is_seekable = 1;
+        }
+
+        mp4state.m_length = (int)(length*1000.);
+
+        fill_buffer(&mp4state);
+        if ((mp4state.m_aac_bytes_consumed = faacDecInit(mp4state.hDecoder,
+            mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer,
+            &mp4state.samplerate, &mp4state.channels)) < 0)
+        {
+            show_error(module.hMainWindow, "Can't initialize decoder library.");
+            return -1;
+        }
+        advance_buffer(&mp4state, mp4state.m_aac_bytes_consumed);
+
+        if (mp4state.m_header_type == 2)
+            avg_bitrate = bitrate;
+        else
+            avg_bitrate = bitrate*1000;
+    } else {
+        mp4state.hDecoder = faacDecOpen();
+        if (!mp4state.hDecoder)
+        {
+            show_error(module.hMainWindow, "Unable to open decoder library.");
+            return -1;
+        }
+
+        config = faacDecGetCurrentConfiguration(mp4state.hDecoder);
+        config->outputFormat = m_resolution + 1;
+        config->downMatrix = m_downmix;
+        faacDecSetConfiguration(mp4state.hDecoder, config);
+
+        mp4state.mp4file = MP4Read(mp4state.filename, 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);
+            if (buffer) free (buffer);
+            return -1;
+        }
+
+        /* for gapless decoding */
+        {
+            mp4AudioSpecificConfig mp4ASC;
+
+            mp4state.timescale = MP4GetTrackTimeScale(mp4state.mp4file, mp4state.mp4track);
+            mp4state.framesize = 1024;
+            mp4state.useAacLength = 0;
+
+            if (buffer)
+            {
+                if (AudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0)
+                {
+                    if (mp4ASC.frameLengthFlag == 1) mp4state.framesize = 960;
+                    if (mp4ASC.sbr_present_flag == 1) mp4state.framesize *= 2;
+                }
+            }
+        }
+
+        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;
+    }
+
+    if (mp4state.channels == 0)
+    {
+        show_error(module.hMainWindow, "Number of channels not supported for playback.");
+        faacDecClose(mp4state.hDecoder);
+        if (mp4state.filetype)
+            fclose(mp4state.aacfile);
+        else
+            MP4Close(mp4state.mp4file);
+        return -1;
+    }
+
+    if (m_downmix && (mp4state.channels == 5 || mp4state.channels == 6))
+        mp4state.channels = 2;
+
+	wf.wFormatTag = WAVE_FORMAT_PCM;
+	wf.cbSize = 0;
+	wf.nChannels = mp4state.channels;
+	wf.wBitsPerSample = res_table[m_resolution];
+	wf.nSamplesPerSec = mp4state.samplerate;
+	wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
+	wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
+	if (!module.QCDCallbacks.toPlayer.OutputOpen(mp4state.filename, &wf)) // error opening device
+    {
+        faacDecClose(mp4state.hDecoder);
+        if (mp4state.filetype)
+            fclose(mp4state.aacfile);
+        else
+            MP4Close(mp4state.mp4file);
+        return -1;
+    }
+
+    mp4state.paused        =  0;
+    mp4state.decode_pos_ms =  0;
+    mp4state.seek_needed   = -1;
+
+    // initialize vis stuff
+    //module.SAVSAInit(maxlatency, mp4state.samplerate);
+    //module.VSASetInfo((int)mp4state.channels, mp4state.samplerate);
+
+    br = (int)floor(((float)avg_bitrate + 500.0)/1000.0 + 0.5);
+    sr = (int)floor((float)mp4state.samplerate/1000.0 + 0.5);
+	ai.struct_size = sizeof(AudioInfo);
+	ai.frequency = sr*1000;
+	ai.bitrate = br*1000;
+	ai.mode = (mp4state.channels == 2) ? 0 : 3;
+	ai.layer = 0;
+	ai.level = 0;
+	strcpy(ai.text, mp4state.filetype ? "AAC" : "MP4");
+	module.QCDCallbacks.Service(opSetAudioInfo, &ai, sizeof(AudioInfo), 0);
+
+    //module.outMod->SetVolume(-666); // set the output plug-ins default volume
+
+    killPlayThread = 0;
+
+    if (mp4state.filetype)
+    {
+        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;
+        }
+    }
+
+    SetThreadAffinityMask(play_thread_handle, 1);
+
+    SetThreadPriority(play_thread_handle, priority_table[m_priority]);
 	}
-	return TRUE;
+
+    return 1;
 }
 
 //-----------------------------------------------------------------------------
@@ -752,92 +1543,406 @@
 #ifdef DEBUG_OUTPUT
     in_mp4_DebugOutput("pause");
 #endif
-	if(QCDCallbacks->toPlayer.OutputPause(flags))
-	{
-		// send back pause/unpause notification
-		QCDCallbacks->toPlayer.PlayPaused(medianame, flags);
-		mp4state.paused = flags;
-		return TRUE;
-	}
-	return FALSE;
-}
 
-//-----------------------------------------------------------------------------
+    mp4state.paused = flags;
 
-void SetVolume(int levelleft, int levelright, int flags)
-{
-	QCDCallbacks->toPlayer.OutputSetVol(levelleft, levelright, flags);
+	if (module.QCDCallbacks.toPlayer.OutputPause(flags))
+		return 1;
+
+	mp4state.paused = !flags;
+	return 0;
 }
 
+//void unpause()
+//{
+//#ifdef DEBUG_OUTPUT
+//    in_mp4_DebugOutput("unpause");
+//#endif
+//
+//    mp4state.paused = 0;
+//    module.outMod->Pause(0);
+//}
+//
+//int ispaused()
+//{
+//#ifdef DEBUG_OUTPUT
+//    in_mp4_DebugOutput("ispaused");
+//#endif
+//
+//    return mp4state.paused;
+//}
+
 //-----------------------------------------------------------------------------
 
-int GetCurrentPosition(const char* medianame, long *track, long *offset)
+void SetVolume(int levelleft, int levelright, int flags)
 {
-	return QCDCallbacks->toPlayer.OutputGetCurrentPosition((UINT*)offset, 0);
+#ifdef DEBUG_OUTPUT
+    in_mp4_DebugOutput("setvolume");
+#endif
+
+	module.QCDCallbacks.toPlayer.OutputSetVol(levelleft, levelright, flags);
 }
 
+//void setpan(int pan)
+//{
+//#ifdef DEBUG_OUTPUT
+//    in_mp4_DebugOutput("setpan");
+//#endif
+//
+//    module.outMod->SetPan(pan);
+//}
+
 //-----------------------------------------------------------------------------
 
 int Stop(const char* medianame, int flags)
 {
+	struct seek_list *target = mp4state.m_head;
+
 #ifdef DEBUG_OUTPUT
-    in_mp4_DebugOutput("stop");
+	in_mp4_DebugOutput("stop");
 #endif
-	if(medianame && *medianame && stricmp(mp4state.filename, medianame) == 0)
+
+	if (medianame && *medianame && stricmp(mp4state.filename, medianame) == 0)
 	{
-		sQCDCallbacks.toPlayer.OutputStop(flags);
+		module.QCDCallbacks.toPlayer.OutputStop(flags);
+    killPlayThread = 1;
 
-		killPlayThread = 1;
-		if(play_thread_handle != INVALID_HANDLE_VALUE)
-		{
-			if (WaitForSingleObject(play_thread_handle, INFINITE) == WAIT_TIMEOUT)
-			{
-//				MessageBox(hwndPlayer, "MP4 thread kill timeout", "debug", 0);
-				TerminateThread(play_thread_handle,0);
-			}
-			CloseHandle(play_thread_handle);
-			play_thread_handle = INVALID_HANDLE_VALUE;
-		}
-		
-		if (oldAPIs)
-			QCDCallbacks->toPlayer.PlayStopped(mp4state.filename);
+    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;
+    }
 
-		mp4state.filename[0] = 0;
-		if(mp4state.hDecoder)
-			faacDecClose(mp4state.hDecoder);
-		if (mp4state.filetype)
-			fclose(mp4state.aacfile);
-		else
-			MP4Close(mp4state.mp4file);
+
+    if (mp4state.m_aac_buffer)
+        free(mp4state.m_aac_buffer);
+
+    while (target)
+    {
+        struct seek_list *tmp = target;
+        target = target->next;
+        if (tmp) free(tmp);
+    }
+    faacDecClose(mp4state.hDecoder);
+    if (mp4state.filetype)
+        fclose(mp4state.aacfile);
+    else
+        MP4Close(mp4state.mp4file);
+
+    //module.outMod->Close();
+    //module.SAVSADeInit();
+		mp4state.filename[0] = '\0';
+		mp4state.paused = 0;
 	}
-	
-	return TRUE;
+
+	return 1;
 }
 
+int getsonglength(char *fn)
+{
+    long msDuration = 0;
+
+    if(!stricmp(fn + strlen(fn) - 3,"MP4") || !stricmp(fn + strlen(fn) - 3,"M4A"))
+    {
+        int track;
+        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;
+    } else {
+        int tagsize = 0;
+        int bread = 0;
+        double length = 0.;
+        __int64 bitrate = 128;
+        struct seek_list *target;
+        state len_state;
+
+        memset(&len_state, 0, sizeof(state));
+
+        if (!(len_state.aacfile = fopen(fn, "rb")))
+        {
+            // error
+            return 0;
+        }
+
+        len_state.m_at_eof = 0;
+
+        if (!(len_state.m_aac_buffer = (unsigned char*)malloc(768*6)))
+        {
+            //console::error("Memory allocation error.", "foo_mp4");
+            return 0;
+        }
+        memset(len_state.m_aac_buffer, 0, 768*6);
+
+        bread = fread(len_state.m_aac_buffer, 1, 768*6, len_state.aacfile);
+        len_state.m_aac_bytes_into_buffer = bread;
+        len_state.m_aac_bytes_consumed = 0;
+        len_state.m_file_offset = 0;
+
+        if (bread != 768*6)
+            len_state.m_at_eof = 1;
+
+        if (!memcmp(len_state.m_aac_buffer, "ID3", 3))
+        {
+            /* high bit is not used */
+            tagsize = (len_state.m_aac_buffer[6] << 21) | (len_state.m_aac_buffer[7] << 14) |
+                (len_state.m_aac_buffer[8] <<  7) | (len_state.m_aac_buffer[9] <<  0);
+
+            tagsize += 10;
+            advance_buffer(&len_state, tagsize);
+        }
+
+        len_state.m_head = (struct seek_list*)malloc(sizeof(struct seek_list));
+        len_state.m_tail = len_state.m_head;
+        len_state.m_tail->next = NULL;
+
+        len_state.m_header_type = 0;
+        if ((len_state.m_aac_buffer[0] == 0xFF) && ((len_state.m_aac_buffer[1] & 0xF6) == 0xF0))
+        {
+            if (1) //(m_reader->can_seek())
+            {
+                adts_parse(&len_state, &bitrate, &length);
+                fseek(len_state.aacfile, tagsize, SEEK_SET);
+
+                bread = fread(len_state.m_aac_buffer, 1, 768*6, len_state.aacfile);
+                if (bread != 768*6)
+                    len_state.m_at_eof = 1;
+                else
+                    len_state.m_at_eof = 0;
+                len_state.m_aac_bytes_into_buffer = bread;
+                len_state.m_aac_bytes_consumed = 0;
+
+                len_state.m_header_type = 1;
+            }
+        } else if (memcmp(len_state.m_aac_buffer, "ADIF", 4) == 0) {
+            int skip_size = (len_state.m_aac_buffer[4] & 0x80) ? 9 : 0;
+            bitrate = ((unsigned int)(len_state.m_aac_buffer[4 + skip_size] & 0x0F)<<19) |
+                ((unsigned int)len_state.m_aac_buffer[5 + skip_size]<<11) |
+                ((unsigned int)len_state.m_aac_buffer[6 + skip_size]<<3) |
+                ((unsigned int)len_state.m_aac_buffer[7 + skip_size] & 0xE0);
+
+            length = (double)file_length(len_state.aacfile);
+            if (length == -1)
+                length = 0;
+            else
+                length = ((double)length*8.)/((double)bitrate) + 0.5;
+
+            len_state.m_header_type = 2;
+        } else {
+            length = (double)file_length(len_state.aacfile);
+            length = ((double)length*8.)/((double)bitrate*1000.) + 0.5;
+
+            len_state.m_header_type = 0;
+        }
+
+        if (len_state.m_aac_buffer)
+            free(len_state.m_aac_buffer);
+
+        target = len_state.m_head;
+        while (target)
+        {
+            struct seek_list *tmp = target;
+            target = target->next;
+            if (tmp) free(tmp);
+        }
+
+        fclose(len_state.aacfile);
+
+        return (int)(length*1000.);
+    }
+}
+
+//int getlength()
+//{
+//    if (!mp4state.filetype)
+//    {
+//        int track;
+//        long msDuration;
+//        MP4Duration length;
+//
+//        if ((track = GetAACTrack(mp4state.mp4file)) < 0)
+//        {
+//            return -1;
+//        }
+//
+//        length = MP4GetTrackDuration(mp4state.mp4file, track);
+//
+//        msDuration = MP4ConvertFromTrackDuration(mp4state.mp4file, track,
+//            length, MP4_MSECS_TIME_SCALE);
+//
+//        return msDuration;
+//    } else {
+//        return mp4state.m_length;
+//    }
+//    return 0;
+//}
+
+//-----------------------------------------------------------------------------
+
+int GetCurrentPosition(const char* medianame, long *track, long *offset)
+{
+	return module.QCDCallbacks.toPlayer.OutputGetCurrentPosition((UINT*)offset, 0);
+}
+
+//void setoutputtime(int time_in_ms)
+//{
+//#ifdef DEBUG_OUTPUT
+//    in_mp4_DebugOutput("setoutputtime");
+//#endif
+//
+//    mp4state.seek_needed = time_in_ms;
+//}
+
+//-----------------------------------------------------------------------------
+
+int GetTrackExtents(const char* medianame, TrackExtents *ext, int flags)
+{
+	int len;
+	FILE *fh;
+
+	len = getsonglength((char *)medianame);
+	fh = fopen(medianame, "rb");
+	if (len <= 0 || !fh)
+		return 0;
+
+	ext->track = 1;
+	ext->start = 0;
+	ext->end = len;
+	ext->bytesize = file_length(fh);
+	fclose(fh);
+	ext->unitpersec = 1000;
+
+	return 1;
+}
+
+//void eq_set(int on, char data[10], int preamp)
+//{
+//}
+
+static void remap_channels(unsigned char *data, unsigned int samples, unsigned int bps)
+{
+    unsigned int i;
+
+    switch (bps)
+    {
+    case 8:
+        {
+            unsigned char r1, r2, r3, r4, r5, r6;
+            for (i = 0; i < samples; i += 6)
+            {
+                r1 = data[i];
+                r2 = data[i+1];
+                r3 = data[i+2];
+                r4 = data[i+3];
+                r5 = data[i+4];
+                r6 = data[i+5];
+                data[i] = r2;
+                data[i+1] = r3;
+                data[i+2] = r1;
+                data[i+3] = r6;
+                data[i+4] = r4;
+                data[i+5] = r5;
+            }
+        }
+        break;
+
+    case 16:
+    default:
+        {
+            unsigned short r1, r2, r3, r4, r5, r6;
+            unsigned short *sample_buffer = (unsigned short *)data;
+            for (i = 0; i < samples; i += 6)
+            {
+                r1 = sample_buffer[i];
+                r2 = sample_buffer[i+1];
+                r3 = sample_buffer[i+2];
+                r4 = sample_buffer[i+3];
+                r5 = sample_buffer[i+4];
+                r6 = sample_buffer[i+5];
+                sample_buffer[i] = r2;
+                sample_buffer[i+1] = r3;
+                sample_buffer[i+2] = r1;
+                sample_buffer[i+3] = r6;
+                sample_buffer[i+4] = r4;
+                sample_buffer[i+5] = r5;
+            }
+        }
+        break;
+
+    case 24:
+    case 32:
+        {
+            unsigned int r1, r2, r3, r4, r5, r6;
+            unsigned int *sample_buffer = (unsigned int *)data;
+            for (i = 0; i < samples; i += 6)
+            {
+                r1 = sample_buffer[i];
+                r2 = sample_buffer[i+1];
+                r3 = sample_buffer[i+2];
+                r4 = sample_buffer[i+3];
+                r5 = sample_buffer[i+4];
+                r6 = sample_buffer[i+5];
+                sample_buffer[i] = r2;
+                sample_buffer[i+1] = r3;
+                sample_buffer[i+2] = r1;
+                sample_buffer[i+3] = r6;
+                sample_buffer[i+4] = r4;
+                sample_buffer[i+5] = r5;
+            }
+        }
+        break;
+    }
+}
+
 DWORD WINAPI MP4PlayThread(void *b)
 {
-	BOOL done = FALSE, updatePos = FALSE;
+    int done = 0, updatepos = 0;
     int l;
+    int seq_frames = 0;
+    int seq_bytes = 0;
 
     void *sample_buffer;
     unsigned char *buffer;
-    int buffer_size, ms;
+    int buffer_size;
     faacDecFrameInfo frameInfo;
 
+    WriteDataStruct wd;
+
 #ifdef DEBUG_OUTPUT
     in_mp4_DebugOutput("MP4PlayThread");
 #endif
 
+    PlayThreadAlive = 1;
     mp4state.last_frame = 0;
+    mp4state.initial = 1;
 
     while (!*((int *)b))
     {
         /* seeking */
-        if (!done && mp4state.seek_needed != -1)
+        if (mp4state.seek_needed != -1)
         {
             MP4Duration duration;
 
-			QCDCallbacks->toPlayer.OutputFlush(mp4state.decode_pos_ms);
+			module.QCDCallbacks.toPlayer.OutputFlush((unsigned int)mp4state.decode_pos_ms);
             duration = MP4ConvertToTrackDuration(mp4state.mp4file,
                 mp4state.mp4track, mp4state.seek_needed, MP4_MSECS_TIME_SCALE);
             mp4state.sampleId = MP4GetSampleIdFromTime(mp4state.mp4file,
@@ -844,37 +1949,37 @@
                 mp4state.mp4track, duration, 0);
 
             mp4state.decode_pos_ms = mp4state.seek_needed;
-			mp4state.seek_needed = -1;
-			updatePos = TRUE;
+            mp4state.seek_needed = -1;
         }
-		/* quit */
-		if (done)
-		{
-			if (QCDCallbacks->toPlayer.OutputDrain(0) && !(mp4state.seek_needed >= 0))
+
+        if (done)
+        {
+			if (module.QCDCallbacks.toPlayer.OutputDrain(0) && !(mp4state.seek_needed >= 0))
 			{
-				play_thread_handle = INVALID_HANDLE_VALUE;
-				QCDCallbacks->toPlayer.OutputStop(STOPFLAG_PLAYDONE);
-				QCDCallbacks->toPlayer.PlayDone(mp4state.filename);
+				module.QCDCallbacks.toPlayer.OutputStop(STOPFLAG_PLAYDONE);
+				module.QCDCallbacks.toPlayer.PlayDone(mp4state.filename);
+                PlayThreadAlive = 0;
 			}
 			else if (mp4state.seek_needed >= 0)
 			{
-				done = FALSE;
+				done = 0;
 				continue;
 			}
 			break;
-		}
-		/* decoding */
-		else
-		{
+        } else/* if (module.outMod->CanWrite() >= (2048*mp4state.channels*sizeof(short)))*/ {
 
             if (mp4state.last_frame)
             {
-                done = TRUE;
-            } 
-			else 
-			{
+                done = 1;
+            } else {
                 int rc;
 
+                /* for gapless decoding */
+                char *buf;
+                MP4Duration dur;
+                unsigned int sample_count;
+                unsigned int delay = 0;
+
                 /* get acces unit from MP4 file */
                 buffer = NULL;
                 buffer_size = 0;
@@ -881,234 +1986,441 @@
 
                 rc = MP4ReadSample(mp4state.mp4file, mp4state.mp4track,
                     mp4state.sampleId++, &buffer, &buffer_size,
-                    NULL, NULL, NULL, NULL);
+                    NULL, &dur, NULL, NULL);
+                if (mp4state.sampleId-1 == 1) dur = 0;
                 if (rc == 0 || buffer == NULL)
                 {
                     mp4state.last_frame = 1;
                     sample_buffer = NULL;
                     frameInfo.samples = 0;
-                } 
-				else 
-				{
+                } else {
                     sample_buffer = faacDecDecode(mp4state.hDecoder, &frameInfo,
                         buffer, buffer_size);
                 }
                 if (frameInfo.error > 0)
                 {
-                    show_error(hwndPlayer, faacDecGetErrorMessage(frameInfo.error));
+                    show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
                     mp4state.last_frame = 1;
                 }
-                if (mp4state.sampleId >= mp4state.numSamples)
+                if (mp4state.sampleId > mp4state.numSamples)
                     mp4state.last_frame = 1;
 
                 if (buffer) free(buffer);
 
-                if (!killPlayThread && (frameInfo.samples > 0))
+                if (mp4state.useAacLength || (mp4state.timescale != mp4state.samplerate)) {
+                    sample_count = frameInfo.samples;
+                } else {
+                    sample_count = (unsigned int)(dur * frameInfo.channels);
+
+                    if (!mp4state.useAacLength && !mp4state.initial && (mp4state.sampleId < mp4state.numSamples/2) && (dur*frameInfo.channels != frameInfo.samples))
+                    {
+                        //fprintf(stderr, "MP4 seems to have incorrect frame duration, using values from AAC data.\n");
+                        mp4state.useAacLength = 1;
+                        sample_count = frameInfo.samples;
+                    }
+                }
+
+                if (mp4state.initial && (sample_count < mp4state.framesize*mp4state.channels) && (frameInfo.samples > sample_count))
                 {
+                    delay = frameInfo.samples - sample_count;
+                }
+
+                if (!killPlayThread && (sample_count > 0))
+                {
+                    buf = (char *)sample_buffer;
+                    mp4state.initial = 0;
+
+                    switch (res_table[m_resolution])
+                    {
+                    case 8:
+                        buf += delay;
+                        break;
+                    case 16:
+                    default:
+                        buf += delay * 2;
+                        break;
+                    case 24:
+                    case 32:
+                        buf += delay * 4;
+                        break;
+                    case 64:
+                        buf += delay * 8;
+                    }
+
+                    if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
+                        remap_channels(buf, sample_count, res_table[m_resolution]);
+
                     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);
+                        char *temp_buffer = convert3in4to3in3(buf, sample_count);
+                        memcpy((void*)buf, (void*)temp_buffer, sample_count*3);
                         free(temp_buffer);
                     }
 
-                    ms = (int)floor(((float)frameInfo.samples*1000.0) /
-                        ((float)mp4state.samplerate*(float)frameInfo.channels));
-                    mp4state.decode_pos_ms += ms;
+                    //module.SAAddPCMData(buf, (int)mp4state.channels, res_table[m_resolution],
+                    //    mp4state.decode_pos_ms);
+                    //module.VSAAddPCMData(buf, (int)mp4state.channels, res_table[m_resolution],
+                    //    mp4state.decode_pos_ms);
+                    mp4state.decode_pos_ms += (double)sample_count * 1000.0 /
+                        ((double)frameInfo.samplerate * (double)frameInfo.channels);
 
-                    l = frameInfo.samples * res_table[m_resolution] / 8;
+                    l = sample_count * res_table[m_resolution] / 8;
 
-					if (updatePos)
+					if (updatepos)
 					{
-						QCDCallbacks->toPlayer.PositionUpdate(mp4state.decode_pos_ms);
-						updatePos = FALSE;
+						module.QCDCallbacks.toPlayer.PositionUpdate((unsigned int)mp4state.decode_pos_ms);
+						updatepos = 0;
 					}
-                    {
-						WriteDataStruct wd;
 
-						wd.bytelen = l;
-						wd.data = sample_buffer;
-						wd.markerend = 0;
-						wd.markerstart = mp4state.decode_pos_ms;
-						wd.bps = res_table[m_resolution];
-						wd.nch = frameInfo.channels;
-						wd.numsamples = frameInfo.samples/frameInfo.channels;
-						wd.srate = mp4state.samplerate;
+					wd.bytelen = l;
+					wd.data = (short*)buf;
+					wd.markerend = 0;
+					wd.markerstart = (UINT)mp4state.decode_pos_ms;
+					wd.bps = res_table[m_resolution];
+					wd.nch = frameInfo.channels;
+					wd.numsamples = sample_count/frameInfo.channels;
+					wd.srate = frameInfo.samplerate;
 
-						if (!QCDCallbacks->toPlayer.OutputWrite(&wd))
-							done = TRUE;
+					if (!module.QCDCallbacks.toPlayer.OutputWrite(&wd))
+						done = 1;
+
+                    //if (module.dsp_isactive())
+                    //{
+                    //    void *dsp_buffer = malloc(l*2);
+                    //    memcpy(dsp_buffer, buf, l);
+
+                    //    l = module.dsp_dosamples((short*)dsp_buffer,
+                    //        sample_count/frameInfo.channels,
+                    //        res_table[m_resolution],
+                    //        frameInfo.channels,
+                    //        frameInfo.samplerate) *
+                    //        (frameInfo.channels*(res_table[m_resolution]/8));
+
+                    //    module.outMod->Write(dsp_buffer, l);
+                    //    if (dsp_buffer) free(dsp_buffer);
+                    //} else {
+                    //    module.outMod->Write(buf, l);
+                    //}
+
+                    /* VBR bitrate display */
+                    if (m_vbr_display)
+                    {
+                        seq_frames++;
+                        seq_bytes += frameInfo.bytesconsumed;
+                        if (seq_frames == (int)(floor((float)frameInfo.samplerate/(float)(sample_count/frameInfo.channels) + 0.5)))
+                        {
+							ai.bitrate = (int)floor(((float)seq_bytes*8.)/1000. + 0.5) * 1000;
+							ai.frequency = (int)floor(frameInfo.samplerate/1000. + 0.5) * 1000;
+							ai.mode = (mp4state.channels == 2) ? 0 : 3;
+							module.QCDCallbacks.Service(opSetAudioInfo, &ai, sizeof(AudioInfo), 0);
+
+                            seq_frames = 0;
+                            seq_bytes = 0;
+                        }
                     }
                 }
             }
         }
+		
 		Sleep(10);
+
+		// catch pause
+		while (mp4state.paused && !killPlayThread)
+			Sleep(50);
     }
 
-	// close up
-	play_thread_handle = INVALID_HANDLE_VALUE;
+    PlayThreadAlive = 0;
 
-	return 0;
+    return 0;
 }
 
+void *decode_aac_frame(state *st, faacDecFrameInfo *frameInfo)
+{
+    void *sample_buffer = NULL;
+
+    do
+    {
+        fill_buffer(st);
+
+        if (st->m_aac_bytes_into_buffer != 0)
+        {
+            sample_buffer = faacDecDecode(st->hDecoder, frameInfo,
+                st->m_aac_buffer, st->m_aac_bytes_into_buffer);
+
+            if (st->m_header_type != 1)
+            {
+                if (st->last_offset < st->m_file_offset)
+                {
+                    st->m_tail->offset = st->m_file_offset;
+                    st->m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
+                    st->m_tail = st->m_tail->next;
+                    st->m_tail->next = NULL;
+                    st->last_offset = st->m_file_offset;
+                }
+            }
+
+            advance_buffer(st, frameInfo->bytesconsumed);
+        } else {
+            break;
+        }
+
+    } while (!frameInfo->samples && !frameInfo->error);
+
+    return sample_buffer;
+}
+
+int aac_seek(state *st, double seconds)
+{
+    int i, frames;
+    int bread;
+    struct seek_list *target = st->m_head;
+
+    if (1 /*can_seek*/ && ((st->m_header_type == 1) || (seconds < st->cur_pos_sec)))
+    {
+        frames = (int)(seconds*((double)st->samplerate/(double)st->framesize) + 0.5);
+
+        for (i = 0; i < frames; i++)
+        {
+            if (target->next)
+                target = target->next;
+            else
+                return 0;
+        }
+        if (target->offset == 0 && frames > 0)
+            return 0;
+        fseek(st->aacfile, target->offset, SEEK_SET);
+        st->m_file_offset = target->offset;
+
+        bread = fread(st->m_aac_buffer, 1, 768*6, st->aacfile);
+        if (bread != 768*6)
+            st->m_at_eof = 1;
+        else
+            st->m_at_eof = 0;
+        st->m_aac_bytes_into_buffer = bread;
+        st->m_aac_bytes_consumed = 0;
+        st->m_file_offset += bread;
+
+        faacDecPostSeekReset(st->hDecoder, -1);
+
+        return 1;
+    } else {
+        if (seconds > st->cur_pos_sec)
+        {
+            faacDecFrameInfo frameInfo;
+
+            frames = (int)((seconds - st->cur_pos_sec)*((double)st->samplerate/(double)st->framesize));
+
+            if (frames > 0)
+            {
+                for (i = 0; i < frames; i++)
+                {
+                    memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
+                    decode_aac_frame(st, &frameInfo);
+
+                    if (frameInfo.error || (st->m_aac_bytes_into_buffer == 0))
+                    {
+                        if (frameInfo.error)
+                        {
+                            if (faacDecGetErrorMessage(frameInfo.error) != NULL)
+                                show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
+                        }
+                        return 0;
+                    }
+                }
+            }
+
+            faacDecPostSeekReset(st->hDecoder, -1);
+        }
+        return 1;
+    }
+}
+
 DWORD WINAPI AACPlayThread(void *b)
 {
-	BOOL done = FALSE, updatePos = FALSE;
-    int l, ms;
+    int done = 0, updatepos = 0;
+    int l;
+    int seq_frames = 0;
+    int seq_bytes = 0;
 
-    void *sample_buffer;
-    faacDecFrameInfo frameInfo;
+	WriteDataStruct wd;
 
 #ifdef DEBUG_OUTPUT
     in_mp4_DebugOutput("AACPlayThread");
 #endif
 
+    PlayThreadAlive = 1;
     mp4state.last_frame = 0;
 
     while (!*((int *)b))
     {
-#if 0
         /* seeking */
-        if (!done && mp4state.seek_needed != -1)
+        if (mp4state.seek_needed != -1)
         {
-            int ms;
+            double ms;
 
-            /* Round off to a second */
-            ms = mp4state.seek_needed - (mp4state.seek_needed%1000);
-			QCDCallbacks->toPlayer.OutputFlush(mp4state.decode_pos_ms);
-            aac_seek(ms);
-            mp4state.decode_pos_ms = ms;
+            ms = mp4state.seek_needed/1000;
+            if (aac_seek(&mp4state, ms)!=0)
+            {
+                module.QCDCallbacks.toPlayer.OutputFlush((unsigned int)mp4state.decode_pos_ms);
+                mp4state.cur_pos_sec = ms;
+                mp4state.decode_pos_ms = mp4state.seek_needed;
+            }
             mp4state.seek_needed = -1;
-			updatePos = TRUE;
         }
-#endif
-		/* quit */
-		if (done)
-		{
-			if (QCDCallbacks->toPlayer.OutputDrain(0) && !(mp4state.seek_needed >= 0))
+
+        if (done)
+        {
+			if (module.QCDCallbacks.toPlayer.OutputDrain(0) && !(mp4state.seek_needed >= 0))
 			{
-				QCDCallbacks->toPlayer.OutputStop(STOPFLAG_PLAYDONE);
-				QCDCallbacks->toPlayer.PlayDone(mp4state.filename);
+				module.QCDCallbacks.toPlayer.OutputStop(STOPFLAG_PLAYDONE);
+				module.QCDCallbacks.toPlayer.PlayDone(mp4state.filename);
+                PlayThreadAlive = 0;
 			}
 			else if (mp4state.seek_needed >= 0)
 			{
-				done = FALSE;
+				done = 0;
 				continue;
 			}
 			break;
-		}
+        } else/* if (module.outMod->CanWrite() >= (2048*mp4state.channels*sizeof(short)))*/ {
+            faacDecFrameInfo frameInfo;
+            void *sample_buffer;
 
-		/* decoding */
-		else
-		{
-            if (mp4state.last_frame)
-            {
-                done = TRUE;
-            } 
-			else 
-			{
-                long tmp, read;
-                unsigned char *buffer = mp4state.buffer;
+            memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
 
-                do
-                {
-                    if (mp4state.bytes_consumed > 0)
-                    {
-                        if (mp4state.bytes_into_buffer)
-                        {
-                            memcpy(buffer, buffer+mp4state.bytes_consumed,
-                                mp4state.bytes_into_buffer);
-                        }
+            sample_buffer = decode_aac_frame(&mp4state, &frameInfo);
 
-                        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);
-                            }
-                        }
+            if (frameInfo.error || (mp4state.m_aac_bytes_into_buffer == 0))
+            {
+                if (frameInfo.error)
+                {
+                    if (faacDecGetErrorMessage(frameInfo.error) != NULL)
+                        show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
+                }
+                done = 1;
+            }
+
+            if (!killPlayThread && (frameInfo.samples > 0))
+            {
+                if (frameInfo.channels == 6 && frameInfo.num_lfe_channels)
+                    remap_channels(sample_buffer, frameInfo.samples, res_table[m_resolution]);
 
-                        mp4state.bytes_consumed = 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);
+                }
 
-                    if (mp4state.bytes_into_buffer < 1)
-                    {
-                        if (mp4state.bytes_read < mp4state.filesize)
-                        {
-                            show_error(hwndPlayer, faacDecGetErrorMessage(frameInfo.error));
-                            mp4state.last_frame = 1;
-                        } 
-						else
-						{
-                            mp4state.last_frame = 1;
-                        }
-                    }
+                //module.SAAddPCMData(sample_buffer, (int)mp4state.channels, res_table[m_resolution],
+                //    mp4state.decode_pos_ms);
+                //module.VSAAddPCMData(sample_buffer, (int)mp4state.channels, res_table[m_resolution],
+                //    mp4state.decode_pos_ms);
+                mp4state.decode_pos_ms += (double)frameInfo.samples * 1000.0 /
+                    ((double)frameInfo.samplerate* (double)frameInfo.channels);
 
-                    sample_buffer = faacDecDecode(mp4state.hDecoder, &frameInfo,
-                        buffer, mp4state.bytes_into_buffer);
+                l = frameInfo.samples * res_table[m_resolution] / 8;
 
-                    mp4state.bytes_consumed += frameInfo.bytesconsumed;
-                    mp4state.bytes_into_buffer -= mp4state.bytes_consumed;
-                } while (!frameInfo.samples && !frameInfo.error);
+				if (updatepos)
+				{
+					module.QCDCallbacks.toPlayer.PositionUpdate((unsigned int)mp4state.decode_pos_ms);
+					updatepos = 0;
+				}
 
-                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);
-                    }
+				wd.bytelen = l;
+				wd.data = (short*)sample_buffer;
+				wd.markerend = 0;
+				wd.markerstart = (UINT)mp4state.decode_pos_ms;
+				wd.bps = res_table[m_resolution];
+				wd.nch = frameInfo.channels;
+				wd.numsamples = frameInfo.samples/frameInfo.channels;
+				wd.srate = frameInfo.samplerate;
 
-                    ms = (int)floor(((float)frameInfo.samples*1000.0) /
-                        ((float)mp4state.samplerate*(float)frameInfo.channels));
-                    mp4state.decode_pos_ms += ms;
+				if (!module.QCDCallbacks.toPlayer.OutputWrite(&wd))
+					done = 1;
 
-                    l = frameInfo.samples * res_table[m_resolution] / 8;
+				//if (module.dsp_isactive())
+                //{
+                //    void *dsp_buffer = malloc(l*2);
+                //    memcpy(dsp_buffer, sample_buffer, l);
 
-					if (updatePos)
-					{
-						QCDCallbacks->toPlayer.PositionUpdate(mp4state.decode_pos_ms);
-						updatePos = FALSE;
-					}
-                    {
-						WriteDataStruct wd;
+                //    l = module.dsp_dosamples((short*)dsp_buffer,
+                //        frameInfo.samples/frameInfo.channels,
+                //        res_table[m_resolution],
+                //        frameInfo.channels,
+                //        frameInfo.samplerate) *
+                //        (frameInfo.channels*(res_table[m_resolution]/8));
 
-						wd.bytelen = l;
-						wd.data = sample_buffer;
-						wd.markerend = 0;
-						wd.markerstart = mp4state.decode_pos_ms;
-						wd.bps = res_table[m_resolution];
-						wd.nch = frameInfo.channels;
-						wd.numsamples = frameInfo.samples/frameInfo.channels;
-						wd.srate = mp4state.samplerate;
+                //    module.outMod->Write(dsp_buffer, l);
+                //    if (dsp_buffer) free(dsp_buffer);
+                //} else {
+                //    module.outMod->Write(sample_buffer, l);
+                //}
 
-						if (!QCDCallbacks->toPlayer.OutputWrite(&wd))
-							done = TRUE;
-                    } 
+                /* VBR bitrate display */
+                if (m_vbr_display)
+                {
+                    seq_frames++;
+                    seq_bytes += frameInfo.bytesconsumed;
+                    if (seq_frames == (int)(floor((float)frameInfo.samplerate/(float)(frameInfo.samples/frameInfo.channels) + 0.5)))
+                    {
+						ai.bitrate = (int)floor(((float)seq_bytes*8.)/1000. + 0.5) * 1000;
+						ai.frequency = (int)floor(frameInfo.samplerate/1000. + 0.5) * 1000;
+						ai.mode = (mp4state.channels == 2) ? 0 : 3;
+						module.QCDCallbacks.Service(opSetAudioInfo, &ai, sizeof(AudioInfo), 0);
+
+                        seq_frames = 0;
+                        seq_bytes = 0;
+                    }
                 }
             }
-        } 
+
+            if (frameInfo.channels > 0 && mp4state.samplerate > 0)
+                mp4state.cur_pos_sec += ((double)(frameInfo.samples/frameInfo.channels))/(double)mp4state.samplerate;
+        }
+		
 		Sleep(10);
+
+		// catch pause
+		while (mp4state.paused && !killPlayThread)
+			Sleep(50);
     }
 
-	// close up
-	play_thread_handle = INVALID_HANDLE_VALUE;
+    PlayThreadAlive = 0;
 
     return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+int WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID pRes)
+{
+	if (fdwReason == DLL_PROCESS_ATTACH)
+	{
+		module.hInstance = hInst;
+	}
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+
+PLUGIN_API QCDModInitIn* INPUTDLL_ENTRY_POINT(QCDModInitIn *ModInit, QCDModInfo *ModInfo)
+{
+	module.QCDCallbacks.size						= sizeof(QCDModInitIn);
+	module.QCDCallbacks.version						= PLUGIN_API_VERSION;
+	module.QCDCallbacks.toModule.Initialize			= Initialize;
+	module.QCDCallbacks.toModule.ShutDown			= ShutDown;
+	module.QCDCallbacks.toModule.GetTrackExtents	= GetTrackExtents;
+	module.QCDCallbacks.toModule.GetMediaSupported	= GetMediaSupported;
+	module.QCDCallbacks.toModule.Play				= Play;
+	module.QCDCallbacks.toModule.Pause				= Pause;
+	module.QCDCallbacks.toModule.Stop				= Stop;
+	module.QCDCallbacks.toModule.About				= About;
+	module.QCDCallbacks.toModule.Configure			= Configure;	
+	module.QCDCallbacks.toModule.SetEQ				= NULL;
+	module.QCDCallbacks.toModule.SetVolume			= SetVolume;
+
+	return &module.QCDCallbacks;
 }
--- a/plugins/QCDMp4/QCDMp4.dsp
+++ b/plugins/QCDMp4/QCDMp4.dsp
@@ -25,7 +25,7 @@
 # PROP AllowPerConfigDependencies 0
 # PROP Scc_ProjName ""
 # PROP Scc_LocalPath ""
-CPP=cl.exe
+CPP=xicl6.exe
 MTL=midl.exe
 RSC=rc.exe
 
@@ -43,7 +43,7 @@
 # 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 /MD /W3 /GX /O2 /I "..\..\include" /I "..\..\common\mp4v2" /I "..\..\common\mp4av" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O1 /I "..\..\include" /I "..\..\common\mp4v2" /I "..\..\common\mp4av" /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"
@@ -51,7 +51,7 @@
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
-LINK32=link.exe
+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
 
@@ -69,7 +69,7 @@
 # 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 /MDd /W3 /Gm /GX /ZI /Od /I "..\..\include" /I "..\..\common\mp4v2" /I "..\..\common\mp4av" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\..\include" /I "..\..\common\mp4v2" /I "..\..\common\mp4av" /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"
@@ -77,7 +77,7 @@
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
-LINK32=link.exe
+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
 
@@ -96,10 +96,6 @@
 # End Source File
 # Begin Source File
 
-SOURCE=.\AAC2Mp4Enc.c
-# End Source File
-# Begin Source File
-
 SOURCE=.\aacinfo.c
 # End Source File
 # Begin Source File
@@ -112,6 +108,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\QCDMp4Tag.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\utils.c
 # End Source File
 # End Group
@@ -120,10 +120,6 @@
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
-SOURCE=.\aac2mp4.h
-# End Source File
-# Begin Source File
-
 SOURCE=.\aacinfo.h
 # End Source File
 # Begin Source File
@@ -136,31 +132,23 @@
 # End Source File
 # Begin Source File
 
-SOURCE=.\mbs.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\QCDConvertDLL.h
-# End Source File
-# Begin Source File
-
 SOURCE=.\QCDInputDLL.h
 # End Source File
 # Begin Source File
 
-SOURCE=.\QCDModDefs.h
+SOURCE=.\QCDModInput.h
 # End Source File
 # Begin Source File
 
-SOURCE=.\QCDModEncode.h
+SOURCE=.\QCDTagsDLL.h
 # End Source File
 # Begin Source File
 
-SOURCE=.\QCDModInput.h
+SOURCE=.\QCDModTagEditor.h
 # End Source File
 # Begin Source File
 
-SOURCE=.\resource.h
+SOURCE=.\QCDModDefs.h
 # End Source File
 # Begin Source File
 
@@ -170,10 +158,6 @@
 # Begin Group "Resource Files"
 
 # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# Begin Source File
-
-SOURCE=.\logo.bmp
-# End Source File
 # Begin Source File
 
 SOURCE=.\QCDMp4.rc
--- a/plugins/QCDMp4/QCDMp4.dsw
+++ b/plugins/QCDMp4/QCDMp4.dsw
@@ -3,7 +3,7 @@
 
 ###############################################################################
 
-Project: "QCDMp4"=".\QCDMp4.dsp" - Package Owner=<4>
+Project: "QCDMp4"=.\QCDMp4.dsp - Package Owner=<4>
 
 Package=<5>
 {{{
@@ -15,16 +15,16 @@
     Project_Dep_Name libfaad
     End Project Dependency
     Begin Project Dependency
-    Project_Dep_Name libmp4av_st
+    Project_Dep_Name libmp4v2_st
     End Project Dependency
     Begin Project Dependency
-    Project_Dep_Name libmp4v2_st
+    Project_Dep_Name libmp4av_st
     End Project Dependency
 }}}
 
 ###############################################################################
 
-Project: "libfaad"="..\..\libfaad\libfaad.dsp" - Package Owner=<4>
+Project: "libfaad"=..\..\libfaad\libfaad.dsp - Package Owner=<4>
 
 Package=<5>
 {{{
@@ -36,7 +36,7 @@
 
 ###############################################################################
 
-Project: "libmp4av_st"="..\..\common\mp4av\libmp4av_st.dsp" - Package Owner=<4>
+Project: "libmp4av_st"=..\..\common\mp4av\libmp4av_st.dsp - Package Owner=<4>
 
 Package=<5>
 {{{
@@ -48,7 +48,7 @@
 
 ###############################################################################
 
-Project: "libmp4v2_st"="..\..\common\mp4v2\libmp4v2_st60.dsp" - Package Owner=<4>
+Project: "libmp4v2_st"=..\..\common\mp4v2\libmp4v2_st60.dsp - Package Owner=<4>
 
 Package=<5>
 {{{
--- a/plugins/QCDMp4/QCDMp4.rc
+++ b/plugins/QCDMp4/QCDMp4.rc
@@ -1,4 +1,4 @@
-//Microsoft Developer Studio generated resource script.
+// Microsoft Visual C++ generated resource script.
 //
 #include "resource.h"
 
@@ -13,7 +13,7 @@
 #undef APSTUDIO_READONLY_SYMBOLS
 
 /////////////////////////////////////////////////////////////////////////////
-// Dutch (Netherlands) resources
+// ������(����) resources
 
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NLD)
 #ifdef _WIN32
@@ -27,18 +27,18 @@
 // TEXTINCLUDE
 //
 
-1 TEXTINCLUDE MOVEABLE PURE 
+1 TEXTINCLUDE 
 BEGIN
     "resource.h\0"
 END
 
-2 TEXTINCLUDE MOVEABLE PURE 
+2 TEXTINCLUDE 
 BEGIN
     "#include ""afxres.h""\r\n"
     "\0"
 END
 
-3 TEXTINCLUDE MOVEABLE PURE 
+3 TEXTINCLUDE 
 BEGIN
     "\r\n"
     "\0"
@@ -52,10 +52,11 @@
 // Dialog
 //
 
-IDD_CONFIG_INPUT DIALOG DISCARDABLE  0, 0, 151, 108
-STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+IDD_CONFIG DIALOGEX 0, 0, 233, 93
+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,46
@@ -62,17 +63,21 @@
     CONTROL         "16 bits",IDC_16BITS,"Button",BS_AUTORADIOBUTTON,77,18,
                     37,10
     CONTROL         "16 bits dithered",IDC_16BITS_DITHERED,"Button",
-                    BS_AUTORADIOBUTTON,77,29,64,10
+                    BS_AUTORADIOBUTTON | WS_DISABLED,77,29,64,10
     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,70,53,10
+    CONTROL         "Downmix to stereo",IDC_DOWNMIX,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,152,13,74,10
     CONTROL         "Use for AAC",IDC_USEFORAAC,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,78,70,55,10
-    PUSHBUTTON      "Cancel",IDCANCEL,7,87,50,14
-    DEFPUSHBUTTON   "OK",IDOK,94,87,50,14
+                    WS_TABSTOP,152,26,55,10
+    CONTROL         "VBR Display",IDC_VBR,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,152,39,55,10
+    CONTROL         "Show errors",IDC_ERROR,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,152,52,53,10
+    DEFPUSHBUTTON   "OK",IDOK,176,72,50,14
+    PUSHBUTTON      "Cancel",IDCANCEL,115,72,50,14
     GROUPBOX        "Priority",IDC_STATIC,7,7,57,58
     LTEXT           "Highest",IDC_STATIC,34,18,25,8
     LTEXT           "Normal",IDC_STATIC,34,35,23,8
@@ -80,39 +85,7 @@
     GROUPBOX        "Resolution",IDC_STATIC,71,7,73,58
 END
 
-IDD_CONFIG_CONVERT DIALOG DISCARDABLE  0, 0, 306, 143
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "AAC to Mp4 Converter Setting"
-FONT 8, "MS Sans Serif"
-BEGIN
-    DEFPUSHBUTTON   "&OK",IDOK,127,122,50,14
-    PUSHBUTTON      "Select Oupput Folder",IDC_OUTPUTFOLDER,16,19,277,20
-    GROUPBOX        "Ouput Folder",IDC_STATIC,7,7,292,39
-    CONTROL         "You can convert AAC files to Mp4 files if you like.\n\nThis does not involve re-encoding, only the container format is changed.\n\nAdvantage Mp4 files are playable by a lot more players\nand they will have a lot of support in the future. ",
-                    IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,7,62,
-                    292,51
-END
 
-IDD_ABOUT DIALOG DISCARDABLE  0, 0, 191, 190
-STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "About MPEG-4 Plug-in"
-FONT 8, "MS Sans Serif"
-BEGIN
-    DEFPUSHBUTTON   "OK",IDOK,69,168,50,14
-    CTEXT           "",IDC_PLUGINVER,29,94,133,16
-    CTEXT           "",IDC_FAADVER,39,144,111,8
-    LTEXT           "QCD Input Plug-in by",IDC_STATIC,61,118,67,8
-    CONTROL         105,IDC_LOGO,"Static",SS_BITMAP | SS_CENTERIMAGE | 
-                    SS_REALSIZEIMAGE,7,0,177,68
-    LTEXT           "Shao Hao",IDC_MAIL1,78,132,33,8
-    LTEXT           "M. Bakker",IDC_MAIL3,58,155,34,8
-    LTEXT           "menno",IDC_MAIL2,108,155,22,8
-    LTEXT           "&&",IDC_STATIC,96,155,8,8
-    CTEXT           "AudioCoding.com MPEG-4 General Audio player\nCopyright 2002 AudioCoding.com",
-                    IDC_STATIC,7,72,177,18
-END
-
-
 /////////////////////////////////////////////////////////////////////////////
 //
 // DESIGNINFO
@@ -119,41 +92,19 @@
 //
 
 #ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO MOVEABLE PURE 
+GUIDELINES DESIGNINFO 
 BEGIN
-    IDD_CONFIG_INPUT, DIALOG
+    IDD_CONFIG, DIALOG
     BEGIN
         LEFTMARGIN, 7
-        RIGHTMARGIN, 144
+        RIGHTMARGIN, 226
         TOPMARGIN, 7
-        BOTTOMMARGIN, 101
+        BOTTOMMARGIN, 86
     END
-
-    IDD_CONFIG_CONVERT, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 299
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 136
-    END
-
-    IDD_ABOUT, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 184
-        BOTTOMMARGIN, 183
-    END
 END
 #endif    // APSTUDIO_INVOKED
 
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Bitmap
-//
-
-IDB_LOGO                BITMAP  DISCARDABLE     "logo.bmp"
-#endif    // Dutch (Netherlands) resources
+#endif    // ������(����) resources
 /////////////////////////////////////////////////////////////////////////////
 
 
--- a/plugins/QCDMp4/QCDMp4.sln
+++ b/plugins/QCDMp4/QCDMp4.sln
@@ -1,21 +1,27 @@
-Microsoft Visual Studio Solution File, Format Version 7.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "in_mp4", "in_mp4.vcproj", "{2D8F479D-A591-4502-9456-398425D5F834}"
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QCDMp4", "QCDMp4.vcproj", "{2D8F479D-A591-4502-9456-398425D5F834}"
+	ProjectSection(ProjectDependencies) = postProject
+		{2398BB2F-FFF9-490B-B4CC-863F2D21AE46} = {2398BB2F-FFF9-490B-B4CC-863F2D21AE46}
+		{8CAC9E26-BAA5-45A4-8721-E3170B3F8F49} = {8CAC9E26-BAA5-45A4-8721-E3170B3F8F49}
+		{82CAD808-21AF-40A6-92EC-AE01AA67B413} = {82CAD808-21AF-40A6-92EC-AE01AA67B413}
+	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfaad", "..\..\libfaad\libfaad.vcproj", "{82CAD808-21AF-40A6-92EC-AE01AA67B413}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmp4v2_st", "..\..\common\mp4v2\libmp4v2_st60.vcproj", "{2398BB2F-FFF9-490B-B4CC-863F2D21AE46}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmp4av_st", "..\..\common\mp4av\libmp4av_st.vcproj", "{8CAC9E26-BAA5-45A4-8721-E3170B3F8F49}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
 EndProject
 Global
 	GlobalSection(SolutionConfiguration) = preSolution
-		ConfigName.0 = Debug
-		ConfigName.1 = Release
-	EndGlobalSection
-	GlobalSection(ProjectDependencies) = postSolution
-		{2D8F479D-A591-4502-9456-398425D5F834}.0 = {82CAD808-21AF-40A6-92EC-AE01AA67B413}
-		{2D8F479D-A591-4502-9456-398425D5F834}.1 = {8CAC9E26-BAA5-45A4-8721-E3170B3F8F49}
-		{2D8F479D-A591-4502-9456-398425D5F834}.2 = {2398BB2F-FFF9-490B-B4CC-863F2D21AE46}
+		Debug = Debug
+		Release = Release
 	EndGlobalSection
 	GlobalSection(ProjectConfiguration) = postSolution
 		{2D8F479D-A591-4502-9456-398425D5F834}.Debug.ActiveCfg = Debug|Win32
--- a/plugins/QCDMp4/QCDMp4.vcproj
+++ b/plugins/QCDMp4/QCDMp4.vcproj
@@ -1,8 +1,8 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
+<?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
-	Version="7.00"
-	Name="in_mp4"
+	Version="7.10"
+	Name="QCDMp4"
 	SccProjectName=""
 	SccLocalPath="">
 	<Platforms>
@@ -25,7 +25,7 @@
 				BasicRuntimeChecks="0"
 				RuntimeLibrary="1"
 				UsePrecompiledHeader="2"
-				PrecompiledHeaderFile=".\Debug/in_mp4.pch"
+				PrecompiledHeaderFile=".\Debug/QCDMp4.pch"
 				AssemblerListingLocation=".\Debug/"
 				ObjectFile=".\Debug/"
 				ProgramDataBaseFileName=".\Debug/"
@@ -32,14 +32,7 @@
 				WarningLevel="3"
 				SuppressStartupBanner="TRUE"
 				DebugInformationFormat="4"
-				CompileAs="0">
-				<IntelOptions
-					Optimization="0"
-					MinimalRebuild="1"
-					BasicRuntimeChecks="0"
-					RuntimeLibrary="1"
-					AllOptions="/c  /I &quot;..\..\include&quot; /I &quot;..\..\common\mp4v2&quot; /I &quot;..\..\common\mp4av&quot; /ZI /nologo /W3 /Od /D &quot;WIN32&quot; /D &quot;_DEBUG&quot; /D &quot;_WINDOWS&quot; /D &quot;_WINDLL&quot; /Gm /EHsc /MTd /YX&quot;StdAfx.h&quot; /Fp&quot;.\Debug/in_mp4.pch&quot; /Fo&quot;.\Debug/&quot; /Fd&quot;.\Debug/&quot; /Gd"/>
-			</Tool>
+				CompileAs="0"/>
 			<Tool
 				Name="VCCustomBuildTool"/>
 			<Tool
@@ -46,16 +39,13 @@
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386"
 				AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
-				OutputFile=".\Debug/in_mp4.dll"
+				OutputFile=".\Debug/QCDMp4.dll"
 				LinkIncremental="2"
 				SuppressStartupBanner="TRUE"
 				GenerateDebugInformation="TRUE"
-				ProgramDatabaseFile=".\Debug/in_mp4.pdb"
+				ProgramDatabaseFile=".\Debug/QCDMp4.pdb"
 				SubSystem="2"
-				ImportLibrary=".\Debug/in_mp4.lib">
-				<IntelOptions
-					AllOptions="/NOLOGO /DLL /OUT:&quot;.\Debug/in_mp4.dll&quot; /INCREMENTAL ws2_32.lib odbc32.lib odbccp32.lib /DEBUG /PDB:&quot;.\Debug/in_mp4.pdb&quot; /SUBSYSTEM:WINDOWS /TLBID:1 /IMPLIB:&quot;.\Debug/in_mp4.lib&quot; /MACHINE:I386 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib"/>
-			</Tool>
+				ImportLibrary=".\Debug/QCDMp4.lib"/>
 			<Tool
 				Name="VCMIDLTool"
 				PreprocessorDefinitions="_DEBUG"
@@ -62,7 +52,7 @@
 				MkTypLibCompatible="TRUE"
 				SuppressStartupBanner="TRUE"
 				TargetEnvironment="1"
-				TypeLibraryName=".\Debug/in_mp4.tlb"/>
+				TypeLibraryName=".\Debug/QCDMp4.tlb"/>
 			<Tool
 				Name="VCPostBuildEventTool"/>
 			<Tool
@@ -76,7 +66,13 @@
 			<Tool
 				Name="VCWebServiceProxyGeneratorTool"/>
 			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
 				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
 		</Configuration>
 		<Configuration
 			Name="Release|Win32"
@@ -98,24 +94,13 @@
 				RuntimeLibrary="0"
 				EnableFunctionLevelLinking="TRUE"
 				UsePrecompiledHeader="2"
-				PrecompiledHeaderFile=".\Release/in_mp4.pch"
+				PrecompiledHeaderFile=".\Release/QCDMp4.pch"
 				AssemblerListingLocation=".\Release/"
 				ObjectFile=".\Release/"
 				ProgramDataBaseFileName=".\Release/"
 				WarningLevel="3"
 				SuppressStartupBanner="TRUE"
-				CompileAs="0">
-				<IntelOptions
-					Optimization="2"
-					GlobalOptimizations="1"
-					InlineFuncExpansion="1"
-					OmitFramePtrs="1"
-					StringPooling="1"
-					RuntimeLibrary="0"
-					BufferSecurityCheck="1"
-					FunctionLevelLinking="1"
-					AllOptions="/c  /I &quot;..\..\include&quot; /I &quot;..\..\common\mp4v2&quot; /I &quot;..\..\common\mp4av&quot; /nologo /W3 /O2 /Og /Ob1 /Oy /D &quot;WIN32&quot; /D &quot;NDEBUG&quot; /D &quot;_WINDOWS&quot; /D &quot;_WINDLL&quot; /GF /FD /EHsc /MT /GS /Gy /YX&quot;StdAfx.h&quot; /Fp&quot;.\Release/in_mp4.pch&quot; /Fo&quot;.\Release/&quot; /Fd&quot;.\Release/&quot; /Gd"/>
-			</Tool>
+				CompileAs="0"/>
 			<Tool
 				Name="VCCustomBuildTool"/>
 			<Tool
@@ -122,15 +107,12 @@
 				Name="VCLinkerTool"
 				AdditionalOptions="/MACHINE:I386"
 				AdditionalDependencies="ws2_32.lib"
-				OutputFile=".\Release/in_mp4.dll"
+				OutputFile=".\Release/QCDMp4.dll"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
-				ProgramDatabaseFile=".\Release/in_mp4.pdb"
+				ProgramDatabaseFile=".\Release/QCDMp4.pdb"
 				SubSystem="2"
-				ImportLibrary=".\Release/in_mp4.lib">
-				<IntelOptions
-					AllOptions="/NOLOGO /DLL /OUT:&quot;.\Release/in_mp4.dll&quot; /INCREMENTAL:NO ws2_32.lib /PDB:&quot;.\Release/in_mp4.pdb&quot; /SUBSYSTEM:WINDOWS /TLBID:1 /IMPLIB:&quot;.\Release/in_mp4.lib&quot; /MACHINE:I386 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib"/>
-			</Tool>
+				ImportLibrary=".\Release/QCDMp4.lib"/>
 			<Tool
 				Name="VCMIDLTool"
 				PreprocessorDefinitions="NDEBUG"
@@ -137,7 +119,7 @@
 				MkTypLibCompatible="TRUE"
 				SuppressStartupBanner="TRUE"
 				TargetEnvironment="1"
-				TypeLibraryName=".\Release/in_mp4.tlb"/>
+				TypeLibraryName=".\Release/QCDMp4.tlb"/>
 			<Tool
 				Name="VCPostBuildEventTool"/>
 			<Tool
@@ -151,50 +133,85 @@
 			<Tool
 				Name="VCWebServiceProxyGeneratorTool"/>
 			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
 				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
 		</Configuration>
 	</Configurations>
+	<References>
+	</References>
 	<Files>
 		<Filter
 			Name="Source Files"
 			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
 			<File
-				RelativePath="aac2mp4.cpp"/>
+				RelativePath="aac2mp4.cpp">
+			</File>
 			<File
-				RelativePath="aacinfo.c"/>
+				RelativePath="aacinfo.c">
+			</File>
 			<File
-				RelativePath=".\config.c"/>
+				RelativePath=".\config.c">
+			</File>
 			<File
-				RelativePath=".\in_mp4.c"/>
+				RelativePath=".\QCDMp4.c">
+			</File>
 			<File
-				RelativePath=".\utils.c"/>
+				RelativePath=".\QCDMp4Tag.cpp">
+			</File>
+			<File
+				RelativePath=".\utils.c">
+			</File>
 		</Filter>
 		<Filter
 			Name="Header Files"
 			Filter="h;hpp;hxx;hm;inl">
 			<File
-				RelativePath="aac2mp4.h"/>
+				RelativePath="aac2mp4.h">
+			</File>
 			<File
-				RelativePath="aacinfo.h"/>
+				RelativePath="aacinfo.h">
+			</File>
 			<File
-				RelativePath=".\config.h"/>
+				RelativePath=".\config.h">
+			</File>
 			<File
-				RelativePath="..\..\include\faad.h"/>
+				RelativePath="..\..\include\faad.h">
+			</File>
 			<File
-				RelativePath=".\in2.h"/>
+				RelativePath=".\QCDInputDLL.h">
+			</File>
 			<File
-				RelativePath=".\out.h"/>
+				RelativePath=".\QCDModDefs.h">
+			</File>
 			<File
-				RelativePath="resource.h"/>
+				RelativePath=".\QCDModInput.h">
+			</File>
 			<File
-				RelativePath=".\utils.h"/>
+				RelativePath=".\QCDModTagEditor.h">
+			</File>
+			<File
+				RelativePath=".\QCDTagsDLL.h">
+			</File>
+			<File
+				RelativePath="resource.h">
+			</File>
+			<File
+				RelativePath=".\utils.h">
+			</File>
 		</Filter>
 		<Filter
 			Name="Resource Files"
 			Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
 			<File
-				RelativePath=".\in_mp4.rc"/>
+				RelativePath=".\QCDMp4.rc">
+			</File>
 		</Filter>
 	</Files>
-	<Globals/>
+	<Globals>
+	</Globals>
 </VisualStudioProject>
--- /dev/null
+++ b/plugins/QCDMp4/QCDMp4Tag.cpp
@@ -1,0 +1,511 @@
+#include <mp4.h>
+#include <faad.h>
+#include "QCDTagsDLL.h"
+
+
+//..............................................................................
+// Global Variables
+
+QCDModInitTag	ModInitTag;
+BOOL uSetDlgItemText(void *tagHandle, int fieldId, const char *str);
+UINT uGetDlgItemText(void *tagHandle, int fieldId, char *str, int max);
+
+//------------------------------------------------------------------------------
+
+PLUGIN_API QCDModInitTag* TAGEDITORDLL_ENTRY_POINT()
+{	
+	ModInitTag.size			= sizeof(QCDModInitTag);
+	ModInitTag.version		= PLUGIN_API_VERSION;
+	ModInitTag.ShutDown		= ShutDown_Tag;
+
+	ModInitTag.Read			= Read_Tag;
+	ModInitTag.Write		= Write_Tag;	// Leave null for operations that plugin does not support
+	ModInitTag.Strip		= Strip_Tag;	// ie: if plugin only reads tags, leave Write and Strip null
+
+	ModInitTag.description	= "MP4 Tags";
+	ModInitTag.defaultexts	= "MP4:M4A";
+
+	return &ModInitTag;
+}
+
+//-----------------------------------------------------------------------------
+
+void ShutDown_Tag(int flags)
+{
+	// TODO:
+	// prepare plugin to be unloaded. All allocations should be freed.
+	// flags param is unused
+}
+
+//-----------------------------------------------------------------------------
+
+bool Read_Tag(LPCSTR filename, void* tagHandle)
+{
+	// TODO:
+	// read metadata from tag and set each field to tagHandle
+	// only TAGFIELD_* are supported (see QCDModTagEditor.h)
+
+	// example of how to set value to tagHandle
+	// use SetFieldA for ASCII or MultiBytes strings.
+	// use SetFieldW for UNICODE strings
+	//
+	//	ModInitTag.SetFieldW(tagHandle, TAGFIELD_COMPOSER, szwValue);
+
+	// return true for successfull read, false for failure
+
+	MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
+	char *pVal, dummy1[1024];
+	short dummy, dummy2;
+
+	unsigned __int32 valueSize = 0;
+
+#ifdef DEBUG_OUTPUT
+	in_mp4_DebugOutput("mp4_tag_read");
+#endif
+
+	file = MP4Read(filename, 0);
+
+	if (file == MP4_INVALID_FILE_HANDLE)
+		return false;
+
+	/* get Metadata */
+
+	pVal = NULL;
+	MP4GetMetadataName(file, &pVal);
+	uSetDlgItemText(tagHandle, TAGFIELD_TITLE, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataArtist(file, &pVal);
+	uSetDlgItemText(tagHandle, TAGFIELD_ARTIST, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataWriter(file, &pVal);
+	uSetDlgItemText(tagHandle, TAGFIELD_COMPOSER, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataComment(file, &pVal);
+	uSetDlgItemText(tagHandle, TAGFIELD_COMMENT, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataAlbum(file, &pVal);
+	uSetDlgItemText(tagHandle, TAGFIELD_ALBUM, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataGenre(file, &pVal);
+	uSetDlgItemText(tagHandle, TAGFIELD_GENRE, pVal);
+
+	//dummy = 0;
+	//MP4GetMetadataTempo(file, &dummy);
+	//wsprintf(dummy1, "%d", dummy);
+	//SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
+
+	dummy = 0; dummy2 = 0;
+	MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
+	wsprintf(dummy1, "%d", dummy);
+	ModInitTag.SetFieldA(tagHandle, TAGFIELD_TRACK, dummy1);
+	//wsprintf(dummy1, "%d", dummy2);
+	//SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
+
+	//dummy = 0; dummy2 = 0;
+	//MP4GetMetadataDisk(file, &dummy, &dummy2);
+	//wsprintf(dummy1, "%d", dummy);
+	//SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
+	//wsprintf(dummy1, "%d", dummy2);
+	//SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
+
+	pVal = NULL;
+	MP4GetMetadataYear(file, &pVal);
+	uSetDlgItemText(tagHandle, TAGFIELD_YEAR, pVal);
+
+	//dummy3 = 0;
+	//MP4GetMetadataCompilation(file, &dummy3);
+	//if (dummy3)
+	//	SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_SETCHECK, BST_CHECKED, 0);
+
+	pVal = NULL;
+	MP4GetMetadataTool(file, &pVal);
+	uSetDlgItemText(tagHandle, TAGFIELD_ENCODER, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataFreeForm(file, "CONDUCTOR", (unsigned __int8**)&pVal, &valueSize);
+	uSetDlgItemText(tagHandle, TAGFIELD_CONDUCTOR, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataFreeForm(file, "ORCHESTRA", (unsigned __int8**)&pVal, &valueSize);
+	uSetDlgItemText(tagHandle, TAGFIELD_ORCHESTRA, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataFreeForm(file, "YEARCOMPOSED", (unsigned __int8**)&pVal, &valueSize);
+	uSetDlgItemText(tagHandle, TAGFIELD_YEARCOMPOSED, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataFreeForm(file, "ORIGARTIST", (unsigned __int8**)&pVal, &valueSize);
+	uSetDlgItemText(tagHandle, TAGFIELD_ORIGARTIST, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataFreeForm(file, "LABEL", (unsigned __int8**)&pVal, &valueSize);
+	uSetDlgItemText(tagHandle, TAGFIELD_LABEL, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataFreeForm(file, "COPYRIGHT", (unsigned __int8**)&pVal, &valueSize);
+	uSetDlgItemText(tagHandle, TAGFIELD_COPYRIGHT, pVal);
+
+	pVal = NULL;
+	MP4GetMetadataFreeForm(file, "CDDBTAGID", (unsigned __int8**)&pVal, &valueSize);
+	uSetDlgItemText(tagHandle, TAGFIELD_CDDBTAGID, pVal);
+
+	/* ! Metadata */
+
+	MP4Close(file);
+
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool Write_Tag(LPCSTR filename, void* tagHandle)
+{
+	// TODO:
+	// read metadata from tagHandle and set each field to supported tag
+	// only TAGFIELD_* are supported (see QCDModTagEditor.h)
+
+	// example of how to get value from tagHandle
+	// use SetFieldA for ASCII or MultiBytes strings.
+	// use SetFieldW for UNICODE strings
+	//
+	// szwValue = ModInitTag.GetFieldW(tagHandle, TAGFIELD_ORCHESTRA);
+
+	// write tag to file
+
+	MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
+    char dummy1[1024];
+    short dummy, dummy2;
+
+#ifdef DEBUG_OUTPUT
+    in_mp4_DebugOutput("mp4_tag_write");
+#endif
+
+	/* save Metadata changes */
+
+	file = MP4Modify(filename, 0, 0);
+	if (file == MP4_INVALID_FILE_HANDLE)
+		return false;
+
+	uGetDlgItemText(tagHandle, TAGFIELD_TITLE, dummy1, 1024);
+	MP4SetMetadataName(file, dummy1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_COMPOSER, dummy1, 1024);
+	MP4SetMetadataWriter(file, dummy1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_ARTIST, dummy1, 1024);
+	MP4SetMetadataArtist(file, dummy1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_ALBUM, dummy1, 1024);
+	MP4SetMetadataAlbum(file, dummy1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_COMMENT, dummy1, 1024);
+	MP4SetMetadataComment(file, dummy1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_GENRE, dummy1, 1024);
+	MP4SetMetadataGenre(file, dummy1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_YEAR, dummy1, 1024);
+	MP4SetMetadataYear(file, dummy1);
+
+	dummy = 0; dummy2 = 0;
+	MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
+	memcpy(dummy1, ModInitTag.GetFieldA(tagHandle, TAGFIELD_TRACK), sizeof(dummy1));
+	//GetDlgItemText(hwndDlg, IDC_METATRACK1, dummy1, 1024);
+	dummy = atoi(dummy1);
+	//GetDlgItemText(hwndDlg, IDC_METATRACK2, dummy1, 1024);
+	//dummy2 = atoi(dummy1);
+	MP4SetMetadataTrack(file, dummy, dummy2);
+
+	//GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
+	//dummy = atoi(dummy1);
+	//GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
+	//dummy2 = atoi(dummy1);
+	//MP4SetMetadataDisk(file, dummy, dummy2);
+
+	//GetDlgItemText(hwndDlg, IDC_METATEMPO, dummy1, 1024);
+	//dummy = atoi(dummy1);
+	//MP4SetMetadataTempo(file, dummy);
+
+	//dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
+	//MP4SetMetadataCompilation(file, dummy3);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_ENCODER, dummy1, 1024);
+	MP4SetMetadataTool(file, dummy1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_CONDUCTOR, dummy1, 1024);
+	MP4SetMetadataFreeForm(file, "CONDUCTOR", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_ORCHESTRA, dummy1, 1024);
+	MP4SetMetadataFreeForm(file, "ORCHESTRA", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_YEARCOMPOSED, dummy1, 1024);
+	MP4SetMetadataFreeForm(file, "YEARCOMPOSED", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_ORIGARTIST, dummy1, 1024);
+	MP4SetMetadataFreeForm(file, "ORIGARTIST", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_LABEL, dummy1, 1024);
+	MP4SetMetadataFreeForm(file, "LABEL", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_COPYRIGHT, dummy1, 1024);
+	MP4SetMetadataFreeForm(file, "COPYRIGHT", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+
+	uGetDlgItemText(tagHandle, TAGFIELD_CDDBTAGID, dummy1, 1024);
+	MP4SetMetadataFreeForm(file, "CDDBTAGID", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+
+	MP4Close(file);
+
+	MP4Optimize(filename, NULL, 0);
+	/* ! */
+
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool Strip_Tag(LPCSTR filename)
+{
+	// TODO:
+	// remove tag from file.
+	// do whatever is need to remove the supported tag from filename
+
+	// return true for successfull strip, false for failure
+
+	MP4FileHandle file;
+
+	file = MP4Modify(filename, 0, 0);
+	if (file == MP4_INVALID_FILE_HANDLE)
+		return false;
+	
+	MP4MetadataDelete(file);
+
+	MP4Close(file);
+
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+
+/* Convert UNICODE to UTF-8
+   Return number of bytes written */
+int unicodeToUtf8 ( const WCHAR* lpWideCharStr, char* lpMultiByteStr, int cwcChars )
+{
+    const unsigned short*   pwc = (unsigned short *)lpWideCharStr;
+    unsigned char*          pmb = (unsigned char  *)lpMultiByteStr;
+    const unsigned short*   pwce;
+    size_t  cBytes = 0;
+
+    if ( cwcChars >= 0 ) {
+        pwce = pwc + cwcChars;
+    } else {
+        pwce = (unsigned short *)((size_t)-1);
+    }
+
+    while ( pwc < pwce ) {
+        unsigned short  wc = *pwc++;
+
+        if ( wc < 0x00000080 ) {
+            *pmb++ = (char)wc;
+            cBytes++;
+        } else
+        if ( wc < 0x00000800 ) {
+            *pmb++ = (char)(0xC0 | ((wc >>  6) & 0x1F));
+            cBytes++;
+            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
+            cBytes++;
+        } else
+        if ( wc < 0x00010000 ) {
+            *pmb++ = (char)(0xE0 | ((wc >> 12) & 0x0F));
+            cBytes++;
+            *pmb++ = (char)(0x80 | ((wc >>  6) & 0x3F));
+            cBytes++;
+            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
+            cBytes++;
+        }
+        if ( wc == L'\0' )
+            return cBytes;
+    }
+
+    return cBytes;
+}
+
+/* Convert UTF-8 coded string to UNICODE
+   Return number of characters converted */
+int utf8ToUnicode ( const char* lpMultiByteStr, WCHAR* lpWideCharStr, int cmbChars )
+{
+    const unsigned char*    pmb = (unsigned char  *)lpMultiByteStr;
+    unsigned short*         pwc = (unsigned short *)lpWideCharStr;
+    const unsigned char*    pmbe;
+    size_t  cwChars = 0;
+
+    if ( cmbChars >= 0 ) {
+        pmbe = pmb + cmbChars;
+    } else {
+        pmbe = (unsigned char *)((size_t)-1);
+    }
+
+    while ( pmb < pmbe ) {
+        char            mb = *pmb++;
+        unsigned int    cc = 0;
+        unsigned int    wc;
+
+        while ( (cc < 7) && (mb & (1 << (7 - cc)))) {
+            cc++;
+        }
+
+        if ( cc == 1 || cc > 6 )                    // illegal character combination for UTF-8
+            continue;
+
+        if ( cc == 0 ) {
+            wc = mb;
+        } else {
+            wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6);
+            while ( --cc > 0 ) {
+                if ( pmb == pmbe )                  // reached end of the buffer
+                    return cwChars;
+                mb = *pmb++;
+                if ( ((mb >> 6) & 0x03) != 2 )      // not part of multibyte character
+                    return cwChars;
+                wc |= (mb & 0x3F) << ((cc - 1) * 6);
+            }
+        }
+
+        if ( wc & 0xFFFF0000 )
+            wc = L'?';
+        *pwc++ = wc;
+        cwChars++;
+        if ( wc == L'\0' )
+            return cwChars;
+    }
+
+    return cwChars;
+}
+
+/* convert Windows ANSI to UTF-8 */
+int ConvertANSIToUTF8 ( const char* ansi, char* utf8 )
+{
+    WCHAR*  wszValue;          // Unicode value
+    size_t  ansi_len;
+    size_t  len;
+
+    *utf8 = '\0';
+    if ( ansi == NULL )
+        return 0;
+
+    ansi_len = strlen ( ansi );
+
+    if ( (wszValue = (WCHAR *)malloc ( (ansi_len + 1) * 2 )) == NULL )
+        return 0;
+
+    /* Convert ANSI value to Unicode */
+    if ( (len = MultiByteToWideChar ( CP_ACP, 0, ansi, ansi_len + 1, wszValue, (ansi_len + 1) * 2 )) == 0 ) {
+        free ( wszValue );
+        return 0;
+    }
+
+    /* Convert Unicode value to UTF-8 */
+    if ( (len = unicodeToUtf8 ( wszValue, utf8, -1 )) == 0 ) {
+        free ( wszValue );
+        return 0;
+    }
+
+    free ( wszValue );
+
+    return len-1;
+}
+
+/* convert UTF-8 to Windows ANSI */
+int ConvertUTF8ToANSI ( const char* utf8, char* ansi )
+{
+    WCHAR*  wszValue;          // Unicode value
+    size_t  utf8_len;
+    size_t  len;
+
+    *ansi = '\0';
+    if ( utf8 == NULL )
+        return 0;
+
+    utf8_len = strlen ( utf8 );
+
+    if ( (wszValue = (WCHAR *)malloc ( (utf8_len + 1) * 2 )) == NULL )
+        return 0;
+
+    /* Convert UTF-8 value to Unicode */
+    if ( (len = utf8ToUnicode ( utf8, wszValue, utf8_len + 1 )) == 0 ) {
+        free ( wszValue );
+        return 0;
+    }
+
+    /* Convert Unicode value to ANSI */
+    if ( (len = WideCharToMultiByte ( CP_ACP, 0, wszValue, -1, ansi, (utf8_len + 1) * 2, NULL, NULL )) == 0 ) {
+        free ( wszValue );
+        return 0;
+    }
+
+    free ( wszValue );
+
+    return len-1;
+}
+
+BOOL uSetDlgItemText(void *tagHandle, int fieldId, const char *str)
+{
+    char *temp;
+    size_t len;
+    int r;
+
+    if (!str) return FALSE;
+    len = strlen(str);
+    temp = (char *)malloc(len+1);
+    if (!temp) return FALSE;
+	memset(temp, '\0', len+1);
+    r = ConvertUTF8ToANSI(str, temp);
+    if (r > 0)
+        ModInitTag.SetFieldA(tagHandle, fieldId, temp);
+    free(temp);
+
+    return r>0 ? TRUE : FALSE;
+}
+
+UINT uGetDlgItemText(void *tagHandle, int fieldId, char *str, int max)
+{
+    char *temp, *utf8;;
+    int len;
+
+	const char *p;
+
+    if (!str) return 0;
+    len = strlen( ModInitTag.GetFieldA(tagHandle, fieldId) );
+    temp = (char *)malloc(len+1);
+    if (!temp) return 0;
+    utf8 = (char *)malloc((len+1)*4);
+    if (!utf8)
+    {
+        free(temp);
+        return 0;
+    }
+
+	memset(temp, '\0', len+1);
+	memset(utf8, '\0', (len+1)*4);
+	p = ModInitTag.GetFieldA(tagHandle, fieldId);
+	memcpy(temp, p, len+1);
+    if (len > 0)
+    {
+        len = ConvertANSIToUTF8(temp, utf8);
+        if (len > max-1)
+        {
+            len = max-1;
+            utf8[max] = '\0';
+        }
+        memcpy(str, utf8, len+1);
+    }
+
+    free(temp);
+    free(utf8);
+
+    return len;
+}
--- /dev/null
+++ b/plugins/QCDMp4/QCDTagsDLL.h
@@ -1,0 +1,14 @@
+#ifndef QCDTAGS_H
+#define QCDTAGS_H
+
+#include "QCDModTagEditor.h"
+
+extern HINSTANCE		hInstance;
+
+void ShutDown_Tag(int flags);
+bool Read_Tag(LPCSTR filename, void* tagData);
+bool Write_Tag(LPCSTR filename, void* tagData);
+bool Strip_Tag(LPCSTR filename);
+
+
+#endif
\ No newline at end of file
--- a/plugins/QCDMp4/aac2mp4.cpp
+++ b/plugins/QCDMp4/aac2mp4.cpp
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,7 +16,13 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: aac2mp4.cpp,v 1.1 2003/04/28 19:07:57 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: aac2mp4.cpp,v 1.3 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
 #include <mpeg4ip.h>
--- a/plugins/QCDMp4/aac2mp4.h
+++ b/plugins/QCDMp4/aac2mp4.h
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,7 +16,13 @@
 ** along with this program; if not, write to the Free Software 
 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 **
-** $Id: aac2mp4.h,v 1.1 2003/04/28 19:07:57 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: aac2mp4.h,v 1.3 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
 #ifndef AAC2MP4_H__
--- a/plugins/QCDMp4/aacinfo.c
+++ b/plugins/QCDMp4/aacinfo.c
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,7 +16,13 @@
 ** 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 2003/04/28 19:07:57 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: aacinfo.c,v 1.3 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
 #define WIN32_LEAN_AND_MEAN
@@ -108,13 +114,11 @@
         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);
         }
+        frame_length = ((((unsigned int)buffer[3] & 0x3)) << 11)
+            | (((unsigned int)buffer[4]) << 3) | (buffer[5] >> 5);
 
         t_framelength += frame_length;
 
--- a/plugins/QCDMp4/aacinfo.h
+++ b/plugins/QCDMp4/aacinfo.h
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,7 +16,13 @@
 ** 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 2003/04/28 19:07:57 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: aacinfo.h,v 1.3 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
 #ifndef AACINFO_INCLUDED
--- a/plugins/QCDMp4/config.c
+++ b/plugins/QCDMp4/config.c
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,7 +16,13 @@
 ** 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 2003/04/28 19:07:57 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: config.c,v 1.3 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
 #define WIN32_LEAN_AND_MEAN
@@ -23,12 +29,15 @@
 #include <windows.h>
 #include "config.h"
 
-char app_name[] = "QCDMp4";
+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;
 int m_use_for_aac = 1;
+int m_downmix = 0;
+int m_vbr_display = 0;
+char titleformat[MAX_PATH];
 
 void _r_s(char *name,char *data, int mlen)
 {
--- a/plugins/QCDMp4/config.h
+++ b/plugins/QCDMp4/config.h
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,18 +16,27 @@
 ** 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 2003/04/28 19:07:57 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: config.h,v 1.3 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
-extern char app_name[];
-extern char INI_FILE[];
+char app_name[];
+char INI_FILE[];
 int m_priority;
 int m_resolution;
 int m_show_errors;
 int m_use_for_aac;
+int m_downmix;
+int m_vbr_display;
+char titleformat[MAX_PATH];
 
 #define RS(x) (_r_s(#x,x,sizeof(x)))
 #define WS(x) (WritePrivateProfileString(app_name,#x,x,INI_FILE))
 
-extern void _r_s(char *name,char *data, int mlen);
+void _r_s(char *name,char *data, int mlen);
 
binary files a/plugins/QCDMp4/logo.bmp /dev/null differ
--- a/plugins/QCDMp4/resource.h
+++ b/plugins/QCDMp4/resource.h
@@ -1,13 +1,8 @@
 //{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
+// Microsoft Visual C++ generated include file.
 // Used by QCDMp4.rc
 //
-#define IDD_INFO                        101
 #define IDD_CONFIG                      102
-#define IDD_CONFIG_INPUT                102
-#define IDD_ABOUT                       103
-#define IDD_CONFIG_CONVERT              104
-#define IDB_LOGO                        105
 #define IDC_TYPE                        1000
 #define IDC_INFOTEXT                    1000
 #define IDC_DURATION                    1001
@@ -31,21 +26,42 @@
 #define IDC_CONVERT1                    1009
 #define IDC_USERDATA                    1010
 #define IDC_USEFORAAC                   1011
-#define IDC_OUTPUTFOLDER                1014
-#define IDC_LOGO                        1019
-#define IDC_PLUGINVER                   1050
-#define IDC_FAADVER                     1051
-#define IDC_MAIL1                       1052
-#define IDC_MAIL2                       1053
-#define IDC_MAIL3                       1054
+#define IDC_METACOMPILATION             1012
+#define IDC_METANAME                    1013
+#define IDC_METAARTIST                  1014
+#define IDC_METAWRITER                  1015
+#define IDC_METAALBUM                   1016
+#define IDC_METACOMMENTS                1017
+#define IDC_METAGENRE                   1018
+#define IDC_METAYEAR                    1019
+#define IDC_METATRACK1                  1020
+#define IDC_METADISK1                   1021
+#define IDC_METATEMPO                   1022
+#define IDC_METATRACK2                  1023
+#define IDC_METADISK2                   1024
+#define IDC_STATIC1                     1025
+#define IDC_STATIC2                     1026
+#define IDC_STATIC3                     1027
+#define IDC_STATIC4                     1028
+#define IDC_STATIC5                     1029
+#define IDC_STATIC6                     1030
+#define IDC_STATIC7                     1031
+#define IDC_STATIC8                     1032
+#define IDC_STATIC9                     1033
+#define IDC_STATIC10                    1034
+#define IDC_STATIC11                    1035
+#define IDC_STATIC12                    1036
+#define IDC_DOWNMIX                     1038
+#define IDC_VBR                         1039
+#define IDC_TITLEFORMAT                 1040
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        106
+#define _APS_NEXT_RESOURCE_VALUE        103
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1020
+#define _APS_NEXT_CONTROL_VALUE         1041
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
--- a/plugins/QCDMp4/utils.c
+++ b/plugins/QCDMp4/utils.c
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,7 +16,13 @@
 ** 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 2003/04/28 19:07:57 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: utils.c,v 1.3 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
 #define WIN32_LEAN_AND_MEAN
--- a/plugins/QCDMp4/utils.h
+++ b/plugins/QCDMp4/utils.h
@@ -1,6 +1,6 @@
 /*
-** FAAD - Freeware Advanced Audio Decoder
-** Copyright (C) 2002 M. Bakker
+** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
+** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com
 **  
 ** 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
@@ -16,7 +16,13 @@
 ** 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 2003/04/28 19:07:57 menno Exp $
+** Any non-GPL usage of this software or parts of this software is strictly
+** forbidden.
+**
+** Commercial non-GPL licensing of this software is possible.
+** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
+**
+** $Id: utils.h,v 1.3 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
 #ifndef UTILS_INCLUDED