summaryrefslogtreecommitdiff
path: root/faad2/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'faad2/src/plugins')
-rw-r--r--faad2/src/plugins/Makefile.am13
-rw-r--r--faad2/src/plugins/QCD/QCDFAAD.c1030
-rw-r--r--faad2/src/plugins/QCD/QCDFAAD.sln29
-rw-r--r--faad2/src/plugins/QCD/QCDFAAD.vcproj348
-rw-r--r--faad2/src/plugins/QCD/QCDInputDLL.h50
-rw-r--r--faad2/src/plugins/QCD/QCDModDefs.h340
-rw-r--r--faad2/src/plugins/QCD/QCDModInput.h117
-rw-r--r--faad2/src/plugins/QCD/ReadMe.txt11
-rw-r--r--faad2/src/plugins/QCD/logo.bmpbin0 -> 87614 bytes
-rw-r--r--faad2/src/plugins/QCD/plugin_dlg.rc141
-rw-r--r--faad2/src/plugins/QCD/resource.h33
-rw-r--r--faad2/src/plugins/QCDMp4/QCDInputDLL.h46
-rw-r--r--faad2/src/plugins/QCDMp4/QCDModDefs.h413
-rw-r--r--faad2/src/plugins/QCDMp4/QCDModInput.h117
-rw-r--r--faad2/src/plugins/QCDMp4/QCDModTagEditor.h84
-rw-r--r--faad2/src/plugins/QCDMp4/QCDMp4.c2992
-rw-r--r--faad2/src/plugins/QCDMp4/QCDMp4.rc191
-rw-r--r--faad2/src/plugins/QCDMp4/QCDMp4.sln35
-rw-r--r--faad2/src/plugins/QCDMp4/QCDMp4.vcproj285
-rw-r--r--faad2/src/plugins/QCDMp4/QCDMp4Tag.cpp839
-rw-r--r--faad2/src/plugins/QCDMp4/QCDTagsDLL.h14
-rw-r--r--faad2/src/plugins/QCDMp4/aac2mp4.cpp319
-rw-r--r--faad2/src/plugins/QCDMp4/aac2mp4.h42
-rw-r--r--faad2/src/plugins/QCDMp4/aacinfo.c224
-rw-r--r--faad2/src/plugins/QCDMp4/aacinfo.h46
-rw-r--r--faad2/src/plugins/QCDMp4/config.c48
-rw-r--r--faad2/src/plugins/QCDMp4/config.h42
-rw-r--r--faad2/src/plugins/QCDMp4/mbs.h81
-rw-r--r--faad2/src/plugins/QCDMp4/resource.h67
-rw-r--r--faad2/src/plugins/QCDMp4/utils.c153
-rw-r--r--faad2/src/plugins/QCDMp4/utils.h40
-rw-r--r--faad2/src/plugins/mpeg4ip/Makefile.am22
-rw-r--r--faad2/src/plugins/mpeg4ip/README_WIN32.txt11
-rw-r--r--faad2/src/plugins/mpeg4ip/aa_file.cpp130
-rw-r--r--faad2/src/plugins/mpeg4ip/aa_file.h26
-rw-r--r--faad2/src/plugins/mpeg4ip/faad2.cpp388
-rw-r--r--faad2/src/plugins/mpeg4ip/faad2.h92
-rw-r--r--faad2/src/plugins/xmms/AUTHORS3
-rw-r--r--faad2/src/plugins/xmms/ChangeLog43
-rw-r--r--faad2/src/plugins/xmms/INSTALL2
-rw-r--r--faad2/src/plugins/xmms/Makefile.am2
-rw-r--r--faad2/src/plugins/xmms/NEWS21
-rw-r--r--faad2/src/plugins/xmms/README23
-rw-r--r--faad2/src/plugins/xmms/TODO6
-rw-r--r--faad2/src/plugins/xmms/src/Makefile.am14
-rw-r--r--faad2/src/plugins/xmms/src/aac_utils.c104
-rw-r--r--faad2/src/plugins/xmms/src/libmp4.c586
-rw-r--r--faad2/src/plugins/xmms/src/mp4_utils.c469
48 files changed, 10132 insertions, 0 deletions
diff --git a/faad2/src/plugins/Makefile.am b/faad2/src/plugins/Makefile.am
new file mode 100644
index 0000000..6286f9f
--- /dev/null
+++ b/faad2/src/plugins/Makefile.am
@@ -0,0 +1,13 @@
+if HAVE_MPEG4IP_PLUG
+if HAVE_XMMS
+SUBDIRS = xmms mpeg4ip
+else
+SUBDIRS = mpeg4ip
+endif #HAVE_XMMS
+else
+if HAVE_XMMS
+SUBDIRS = xmms
+else
+SUBDIRS =
+endif #HAVE_XMMS
+endif #HAVE_MPEG4IP_PLUG
diff --git a/faad2/src/plugins/QCD/QCDFAAD.c b/faad2/src/plugins/QCD/QCDFAAD.c
new file mode 100644
index 0000000..1d12295
--- /dev/null
+++ b/faad2/src/plugins/QCD/QCDFAAD.c
@@ -0,0 +1,1030 @@
+/*
+** FAAD - Freeware Advanced Audio Decoder
+** Copyright (C) 2002 M. Bakker
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** $Id: QCDFAAD.c,v 1.2 2003/04/28 19:04:35 menno Exp $
+** based on menno's in_faad.dll plugin for Winamp
+**
+** The tag function has been removed because QCD supports ID3v1 & ID3v2 very well
+** About how to tagging: Please read the "ReadMe.txt" first
+**/
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <windows.h>
+#include <mmreg.h>
+#include <commctrl.h>
+#include <shellapi.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "QCDInputDLL.h"
+
+#include "resource.h"
+
+#include <faad.h>
+#include <aacinfo.h>
+#include <filestream.h>
+//#include <id3v2tag.h>
+
+static char app_name[] = "QCDFAAD";
+
+faadAACInfo file_info;
+
+faacDecHandle hDecoder;
+faacDecFrameInfo frameInfo;
+
+HINSTANCE hInstance;
+HWND hwndPlayer, hwndConfig, hwndAbout;
+QCDModInitIn sQCDCallbacks, *QCDCallbacks;
+BOOL oldAPIs = 0;
+static char lastfn[MAX_PATH]; // currently playing file (used for getting info on the current file)
+int file_length; // file length, in bytes
+int paused; // are we paused?
+int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.
+
+char *sample_buffer; // sample buffer
+unsigned char *buffer; // input buffer
+unsigned char *memmap_buffer; // input buffer for whole file
+long memmap_index;
+
+long buffercount, fileread, bytecount;
+
+// seek table for ADTS header files
+unsigned long *seek_table = NULL;
+int seek_table_length=0;
+
+int killPlayThread = 0; // the kill switch for the decode thread
+HANDLE play_thread_handle = INVALID_HANDLE_VALUE; // the handle to the decode thread
+FILE_STREAM *infile;
+
+/* Function definitions */
+int id3v2_tag(unsigned char *buffer);
+DWORD WINAPI PlayThread(void *b); // the decode thread procedure
+
+// general funcz
+static void show_error(const char *message,...)
+{
+ char foo[512];
+ va_list args;
+ va_start(args, message);
+ vsprintf(foo, message, args);
+ va_end(args);
+ MessageBox(hwndPlayer, foo, "FAAD Plug-in Error", MB_ICONSTOP);
+}
+
+
+// 1= use vbr display, 0 = use average bitrate. This value only controls what shows up in the
+// configuration form. Also- Streaming uses an on-the-fly bitrate display regardless of this value.
+long m_variable_bitrate_display=0;
+long m_priority = 5;
+long m_memmap_file = 0;
+static char INI_FILE[MAX_PATH];
+
+char *priority_text[] = { "",
+ "Decode Thread Priority: Lowest",
+ "Decode Thread Priority: Lower",
+ "Decode Thread Priority: Normal",
+ "Decode Thread Priority: Higher",
+ "Decode Thread Priority: Highest (default)"
+ };
+
+long priority_table[] = {0, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST};
+
+long current_file_mode = 0;
+
+int PlayThread_memmap();
+int PlayThread_file();
+
+static void _r_s(char *name,char *data, int mlen)
+{
+ char buf[10];
+ strcpy(buf,data);
+ GetPrivateProfileString(app_name,name,buf,data,mlen,INI_FILE);
+}
+
+#define RS(x) (_r_s(#x,x,sizeof(x)))
+#define WS(x) (WritePrivateProfileString(app_name,#x,x,INI_FILE))
+
+void config_read()
+{
+ char variable_bitrate_display[10];
+ char priority[10];
+ char memmap_file[10];
+ char local_buffer_size[10];
+ char stream_buffer_size[10];
+
+ strcpy(variable_bitrate_display, "1");
+ strcpy(priority, "5");
+ strcpy(memmap_file, "0");
+ strcpy(local_buffer_size, "128");
+ strcpy(stream_buffer_size, "64");
+
+ RS(variable_bitrate_display);
+ RS(priority);
+ RS(memmap_file);
+ RS(local_buffer_size);
+ RS(stream_buffer_size);
+
+ m_priority = atoi(priority);
+ m_variable_bitrate_display = atoi(variable_bitrate_display);
+ m_memmap_file = atoi(memmap_file);
+ m_local_buffer_size = atoi(local_buffer_size);
+ m_stream_buffer_size = atoi(stream_buffer_size);
+}
+
+void config_write()
+{
+ char variable_bitrate_display[10];
+ char priority[10];
+ char memmap_file[10];
+ char local_buffer_size[10];
+ char stream_buffer_size[10];
+
+ itoa(m_priority, priority, 10);
+ itoa(m_variable_bitrate_display, variable_bitrate_display, 10);
+ itoa(m_memmap_file, memmap_file, 10);
+ itoa(m_local_buffer_size, local_buffer_size, 10);
+ itoa(m_stream_buffer_size, stream_buffer_size, 10);
+
+ WS(variable_bitrate_display);
+ WS(priority);
+ WS(memmap_file);
+ WS(local_buffer_size);
+ WS(stream_buffer_size);
+}
+
+//-----------------------------------------------------------------------------
+
+BOOL 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;
+
+ ModInfo->moduleString = "FAAD Plugin v1.0b";
+ /* read config */
+ QCDCallbacks->Service(opGetPluginSettingsFile, INI_FILE, MAX_PATH, 0);
+
+ config_read();
+ ModInfo->moduleExtensions = "AAC";
+
+ hwndPlayer = (HWND)ModInit->Service(opGetParentWnd, 0, 0, 0);
+ lastfn[0] = 0;
+ play_thread_handle = INVALID_HANDLE_VALUE;
+
+ oldAPIs = 1;
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+
+PLUGIN_API QCDModInitIn* INPUTDLL_ENTRY_POINT()
+{
+ 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;
+}
+
+//----------------------------------------------------------------------------
+
+BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ char tmp[10];
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ /* Set priority slider range and previous position */
+ SendMessage(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER), TBM_SETRANGE, TRUE, MAKELONG(1, 5));
+ SendMessage(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER), TBM_SETPOS, TRUE, m_priority);
+ SetDlgItemText(hwndDlg, IDC_STATIC2, priority_text[m_priority]);
+
+ /* Put a limit to the amount of characters allowed in the buffer boxes */
+ SendMessage(GetDlgItem(hwndDlg, LOCAL_BUFFER_TXT), EM_LIMITTEXT, 4, 0);
+ SendMessage(GetDlgItem(hwndDlg, STREAM_BUFFER_TXT), EM_LIMITTEXT, 4, 0);
+
+ if(m_variable_bitrate_display)
+ SendMessage(GetDlgItem(hwndDlg, VARBITRATE_CHK), BM_SETCHECK, BST_CHECKED, 0);
+ if(m_memmap_file)
+ SendMessage(GetDlgItem(hwndDlg, IDC_MEMMAP), BM_SETCHECK, BST_CHECKED, 0);
+
+ itoa(m_local_buffer_size, tmp, 10);
+ SetDlgItemText(hwndDlg, LOCAL_BUFFER_TXT, tmp);
+
+ itoa(m_stream_buffer_size, tmp, 10);
+ SetDlgItemText(hwndDlg, STREAM_BUFFER_TXT, tmp);
+
+ return TRUE;
+
+ case WM_HSCROLL:
+
+ /* Thread priority slider moved */
+ if(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER) == (HWND) lParam)
+ {
+ int tmp;
+ tmp = SendMessage(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER), TBM_GETPOS, 0, 0);
+
+ if(tmp > 0)
+ {
+ m_priority = tmp;
+
+ SetDlgItemText(hwndDlg, IDC_STATIC2, priority_text[m_priority]);
+
+ if(play_thread_handle)
+ SetThreadPriority(play_thread_handle, priority_table[m_priority]);
+ }
+ }
+
+ return TRUE;
+
+ case WM_COMMAND:
+
+ if(HIWORD(wParam) == BN_CLICKED)
+ {
+ if(GetDlgItem(hwndDlg, VARBITRATE_CHK) == (HWND) lParam)
+ {
+ /* Variable Bitrate checkbox hit */
+ m_variable_bitrate_display = SendMessage(GetDlgItem(hwndDlg, VARBITRATE_CHK), BM_GETCHECK, 0, 0);
+ }
+ if(GetDlgItem(hwndDlg, IDC_MEMMAP) == (HWND) lParam)
+ {
+ /* Variable Bitrate checkbox hit */
+ m_memmap_file = SendMessage(GetDlgItem(hwndDlg, IDC_MEMMAP), BM_GETCHECK, 0, 0);
+ }
+ }
+
+ switch (LOWORD(wParam))
+ {
+ case OK_BTN:
+ /* User hit OK, save buffer settings (all others are set on command) */
+ GetDlgItemText(hwndDlg, LOCAL_BUFFER_TXT, tmp, 5);
+ m_local_buffer_size = atol(tmp);
+
+ GetDlgItemText(hwndDlg, STREAM_BUFFER_TXT, tmp, 5);
+ m_stream_buffer_size = atol(tmp);
+
+ config_write();
+
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ case RESET_BTN:
+ SendMessage(GetDlgItem(hwndDlg, VARBITRATE_CHK), BM_SETCHECK, BST_CHECKED, 0);
+ m_variable_bitrate_display = 1;
+ SendMessage(GetDlgItem(hwndDlg, IDC_MEMMAP), BM_SETCHECK, BST_UNCHECKED, 0);
+ m_memmap_file = 0;
+ SendMessage(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER), TBM_SETPOS, TRUE, 5);
+ m_priority = 5;
+ SetDlgItemText(hwndDlg, IDC_STATIC2, priority_text[5]);
+ SetDlgItemText(hwndDlg, LOCAL_BUFFER_TXT, "128");
+ m_local_buffer_size = 128;
+ SetDlgItemText(hwndDlg, STREAM_BUFFER_TXT, "64");
+ m_stream_buffer_size = 64;
+ return TRUE;
+ case IDCANCEL:
+ case CANCEL_BTN:
+ /* User hit Cancel or the X, just close without saving buffer settings */
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+void Configure(int flags)
+{
+ if(!IsWindow(hwndConfig))
+ hwndConfig = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_CONFIG), hwndPlayer, config_dialog_proc);
+ ShowWindow(hwndConfig, SW_NORMAL);
+}
+
+//-----------------------------------------------------------------------------
+// proc of "About Dialog"
+INT_PTR CALLBACK about_dialog_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static RECT rcLOGO, rcMail1, rcMail2/*, rcMail3*/;
+ POINT ptMouse;
+ static char szPluginVer[] = "QCD FAAD Input Plug-in v1.0b\nCompiled on " __TIME__ ", " __DATE__;
+ static char szFLACVer[] = "Using: FAAD2 v "FAAD2_VERSION" by";
+
+ 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));
+
+ 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;
+}
+
+void About(int flags)
+{
+ if(!IsWindow(hwndAbout))
+ hwndAbout = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_ABOUT), hwndPlayer, about_dialog_proc);
+ ShowWindow(hwndAbout, SW_SHOW);
+}
+
+//-----------------------------------------------------------------------------
+
+BOOL Initialize(QCDModInfo *ModInfo, int flags)
+{
+ hwndPlayer = (HWND)QCDCallbacks->Service(opGetParentWnd, 0, 0, 0);
+
+ lastfn[0] = 0;
+ seek_needed = -1;
+ paused = 0;
+ play_thread_handle = INVALID_HANDLE_VALUE;
+
+ /* read config */
+ QCDCallbacks->Service(opGetPluginSettingsFile, INI_FILE, MAX_PATH, 0);
+ config_read();
+
+ ModInfo->moduleString = "FAAD Plugin v1.0b";
+ ModInfo->moduleExtensions = "AAC";
+
+ /* Initialize winsock, necessary for streaming */
+ WinsockInit();
+
+ // insert menu item into plugin menu
+// QCDCallbacks->Service(opSetPluginMenuItem, hInstance, IDD_CONFIG, (long)"FAAD Plug-in");
+
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+
+void ShutDown(int flags)
+{
+ Stop(lastfn, STOPFLAG_FORCESTOP);
+
+ if(buffer)
+ LocalFree(buffer);
+
+ /* Deallocate winsock */
+ WinsockDeInit();
+
+ // delete the inserted plugin menu
+// QCDCallbacks->Service(opSetPluginMenuItem, hInstance, 0, 0);
+}
+
+//-----------------------------------------------------------------------------
+
+BOOL GetMediaSupported(LPCSTR medianame, MediaInfo *mediaInfo)
+{
+ FILE_STREAM *in;
+ faadAACInfo tmp;
+ 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, ".aac", 4) == 0)
+ {
+ in = open_filestream((char *)medianame);
+
+ if(in != NULL && mediaInfo)
+ {
+ if(in->http)
+ {
+ /* No seeking in http streams */
+ mediaInfo->mediaType = DIGITAL_STREAM_MEDIA;
+ mediaInfo->op_canSeek = FALSE;
+ }
+ else
+ {
+ mediaInfo->mediaType = DIGITAL_FILE_MEDIA;
+ get_AAC_format((char *)medianame, &tmp, NULL, NULL, 1);
+ if(tmp.headertype == 2) /* ADTS header - seekable */
+ mediaInfo->op_canSeek = TRUE;
+ else
+ mediaInfo->op_canSeek = FALSE; /* ADIF or Headerless - not seekable */
+ }
+
+ close_filestream(in);
+ return TRUE;
+ }
+ else
+ {
+ close_filestream(in);
+ return FALSE;
+ }
+ }
+ else
+ return FALSE;
+}
+
+unsigned long samplerate, channels;
+
+int play_memmap(char *fn)
+{
+ int tagsize = 0;
+
+ infile = open_filestream(fn);
+
+ if (infile == NULL)
+ return 1;
+
+ fileread = filelength_filestream(infile);
+
+ memmap_buffer = (char*)LocalAlloc(LPTR, fileread);
+ read_buffer_filestream(infile, memmap_buffer, fileread);
+
+ /* skip id3v2 tag */
+ memmap_index = id3v2_tag(memmap_buffer);
+
+ hDecoder = faacDecOpen();
+
+ /* Copy the configuration dialog setting and use it as the default */
+ /* initialize the decoder, and get samplerate and channel info */
+
+ if( (buffercount = faacDecInit(hDecoder, memmap_buffer + memmap_index,
+ fileread - memmap_index - 1, &samplerate, &channels)) < 0 )
+ {
+ show_error("Error opening input file");
+ return 1;
+ }
+
+ memmap_index += buffercount;
+
+ PlayThread_memmap();
+
+ return 0;
+}
+
+int play_file(char *fn)
+{
+ int k;
+ int tagsize;
+
+ ZeroMemory(buffer, 768*2);
+
+ infile = open_filestream(fn);
+
+ if (infile == NULL)
+ return 1;
+
+ fileread = filelength_filestream(infile);
+
+ buffercount = bytecount = 0;
+ read_buffer_filestream(infile, buffer, 768*2);
+
+ tagsize = id3v2_tag(buffer);
+
+ /* If we find a tag, run right over it */
+ if(tagsize)
+ {
+ if(infile->http)
+ {
+ int i;
+ /* Crude way of doing this, but I believe its fast enough to not make a big difference */
+ close_filestream(infile);
+ infile = open_filestream(fn);
+
+ for(i=0; i < tagsize; i++)
+ read_byte_filestream(infile);
+ }
+ else
+ seek_filestream(infile, tagsize, FILE_BEGIN);
+
+ bytecount = tagsize;
+ buffercount = 0;
+ read_buffer_filestream(infile, buffer, 768*2);
+ }
+
+ hDecoder = faacDecOpen();
+
+ /* Copy the configuration dialog setting and use it as the default */
+ /* initialize the decoder, and get samplerate and channel info */
+
+ if((buffercount = faacDecInit(hDecoder, buffer, 768*2, &samplerate, &channels)) < 0)
+ {
+ show_error("Error opening input file");
+ return 1;
+ }
+
+ if(buffercount > 0)
+ {
+ bytecount += buffercount;
+
+ for (k = 0; k < (768*2 - buffercount); k++)
+ buffer[k] = buffer[k + buffercount];
+
+ read_buffer_filestream(infile, buffer + (768*2) - buffercount, buffercount);
+ buffercount = 0;
+ }
+
+ PlayThread_file();
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+
+BOOL Play(LPCSTR medianame, int playfrom, int playto, int flags)
+{
+ if(stricmp(lastfn, medianame) != 0)
+ {
+ sQCDCallbacks.toPlayer.OutputStop(STOPFLAG_PLAYDONE);
+ Stop(lastfn, STOPFLAG_PLAYDONE);
+ }
+
+ if(paused)
+ {
+ // Update the player controls to reflect the new unpaused state
+ sQCDCallbacks.toPlayer.OutputPause(0);
+
+ Pause(medianame, PAUSE_DISABLED);
+
+ if (playfrom >= 0)
+ seek_needed = playfrom;
+ }
+ else if(play_thread_handle != INVALID_HANDLE_VALUE)
+ {
+ seek_needed = playfrom;
+ return TRUE;
+ }
+ else
+ {
+ int thread_id;
+
+ // alloc the input buffer
+ buffer = (unsigned char*)LocalAlloc(LPTR, 768*2);
+
+ current_file_mode = m_memmap_file;
+
+ if(current_file_mode)
+ {
+ if(play_memmap((char *)medianame))
+ return FALSE;
+ }
+ else
+ {
+ if(play_file((char *)medianame))
+ return FALSE;
+ }
+
+ if(seek_table)
+ {
+ free(seek_table);
+ seek_table = NULL;
+ seek_table_length = 0;
+ }
+
+ get_AAC_format((char *)medianame, &file_info, &seek_table, &seek_table_length, 0);
+
+ seek_needed = playfrom > 0 ? playfrom : -1;
+ killPlayThread = 0;
+ strcpy(lastfn,medianame);
+
+ /*
+ To RageAmp: This is really needed, because aacinfo isn't very accurate on ADIF files yet.
+ Can be fixed though :-)
+ */
+ file_info.sampling_rate = samplerate;
+ file_info.channels = frameInfo.channels;
+
+ play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) PlayThread, (void *) &killPlayThread, 0, &thread_id);
+ if(!play_thread_handle)
+ return FALSE;
+
+ // Note: This line seriously slows down start up time
+ if(m_priority != 3) // if the priority in config window is set to normal, there is nothing to reset!
+ SetThreadPriority(play_thread_handle, priority_table[m_priority]);
+
+ }
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+
+BOOL Pause(LPCSTR medianame, int flags)
+{
+ if(QCDCallbacks->toPlayer.OutputPause(flags))
+ {
+ // send back pause/unpause notification
+ QCDCallbacks->toPlayer.PlayPaused(medianame, flags);
+ paused = flags;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+
+BOOL Stop(LPCSTR medianame, int flags)
+{
+ if(medianame && *medianame && stricmp(lastfn, medianame) == 0)
+ {
+ sQCDCallbacks.toPlayer.OutputStop(flags);
+
+ killPlayThread = 1;
+ if(play_thread_handle != INVALID_HANDLE_VALUE)
+ {
+ if(WaitForSingleObject(play_thread_handle, INFINITE) == WAIT_TIMEOUT)
+ {
+// MessageBox(hwndPlayer, "FAAD 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(lastfn);
+
+ lastfn[0] = 0;
+ }
+
+ return TRUE;
+}
+
+int aac_seek(int pos_ms, int *sktable)
+{
+ double offset_sec;
+
+ offset_sec = pos_ms / 1000.0;
+ if(!current_file_mode)
+ {
+ seek_filestream(infile, sktable[(int)(offset_sec+0.5)], FILE_BEGIN);
+
+ bytecount = sktable[(int)(offset_sec+0.5)];
+ buffercount = 0;
+ read_buffer_filestream(infile, buffer, 768*2);
+ }
+ else
+ {
+ memmap_index = sktable[(int)(offset_sec+0.5)];
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+void SetVolume(int levelleft, int levelright, int flags)
+{
+ QCDCallbacks->toPlayer.OutputSetVol(levelleft, levelright, flags);
+}
+
+//-----------------------------------------------------------------------------
+
+BOOL GetCurrentPosition(LPCSTR medianame, long *track, long *offset)
+{
+ return QCDCallbacks->toPlayer.OutputGetCurrentPosition((UINT*)offset, 0);
+}
+
+//-----------------------------------------------------------------------------
+
+BOOL GetTrackExtents(LPCSTR medianame, TrackExtents *ext, int flags)
+{
+ faadAACInfo tmp;
+
+ if(get_AAC_format((char*)medianame, &tmp, NULL, NULL, 1))
+ return FALSE;
+
+ ext->track = 1;
+ ext->start = 0;
+ ext->end = tmp.length;
+ ext->bytesize = tmp.bitrate * tmp.length;
+ ext->unitpersec = 1000;
+
+ return TRUE;
+}
+
+//--------------------------for play thread-------------------------------------
+
+int last_frame;
+
+DWORD WINAPI PlayThread(void *b)
+{
+ BOOL done = FALSE, updatePos = FALSE;
+ int decode_pos_ms = 0; // current decoding position, in milliseconds
+ int l;
+ int decoded_frames=0;
+ int br_calc_frames=0;
+ int br_bytes_consumed=0;
+ unsigned long bytesconsumed;
+
+ last_frame = 0;
+
+ if(!done)
+ {
+ // open outputdevice
+ WAVEFORMATEX wf;
+ wf.wFormatTag = WAVE_FORMAT_PCM;
+ wf.cbSize = 0;
+ wf.nChannels = file_info.channels;
+ wf.wBitsPerSample = 16;
+ wf.nSamplesPerSec = file_info.sampling_rate;
+ wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
+ wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
+ if (!QCDCallbacks->toPlayer.OutputOpen(lastfn, &wf))
+ {
+ show_error("Error: Failed openning output plugin!");
+ done = TRUE; // cannot open sound device
+ }
+ }
+
+ while (! *((int *)b) )
+ {
+ /********************** SEEK ************************/
+ if (!done && seek_needed >= 0)
+ {
+ int seconds;
+
+ // Round off to a second
+ seconds = seek_needed - (seek_needed%1000);
+ QCDCallbacks->toPlayer.OutputFlush(decode_pos_ms);
+ aac_seek(seconds, seek_table);
+ decode_pos_ms = seconds;
+ decoded_frames = 0;
+ br_calc_frames = 0;
+ br_bytes_consumed = 0;
+
+ seek_needed = -1;
+ updatePos = 1;
+ }
+
+ /********************* QUIT *************************/
+ if (done)
+ {
+ if (QCDCallbacks->toPlayer.OutputDrain(0) && !(seek_needed >= 0))
+ {
+ play_thread_handle = INVALID_HANDLE_VALUE;
+ QCDCallbacks->toPlayer.OutputStop(STOPFLAG_PLAYDONE);
+ QCDCallbacks->toPlayer.PlayDone(lastfn);
+ }
+ else if (seek_needed >= 0)
+ {
+ done = FALSE;
+ continue;
+ }
+ break;
+ }
+
+ /******************* DECODE TO BUFFER ****************/
+ else
+ {
+ if (current_file_mode)
+ bytesconsumed = PlayThread_memmap();
+ else
+ bytesconsumed = PlayThread_file();
+
+ if(last_frame)
+ done = TRUE;
+ else
+ {
+
+ decoded_frames++;
+ br_calc_frames++;
+ br_bytes_consumed += bytesconsumed;
+
+ /* Update the variable bitrate about every second */
+ if(m_variable_bitrate_display && br_calc_frames == 43)
+ {
+ AudioInfo vai;
+ vai.struct_size = sizeof(AudioInfo);
+ vai.frequency = file_info.sampling_rate;
+ vai.bitrate = (int)((br_bytes_consumed * 8) / (decoded_frames / 43.07));
+ vai.mode = (channels == 2) ? 0 : 3;
+ vai.layer = 0;
+ vai.level = file_info.version;
+ QCDCallbacks->Service(opSetAudioInfo, &vai, sizeof(AudioInfo), 0);
+
+ br_calc_frames = 0;
+ }
+
+ if (!killPlayThread && (frameInfo.samples > 0))
+ {
+ //update the time display
+ if (updatePos)
+ {
+ QCDCallbacks->toPlayer.PositionUpdate(decode_pos_ms);
+ updatePos = 0;
+ }
+
+ {
+ WriteDataStruct wd;
+
+ l = frameInfo.samples * sizeof(short);
+
+ decode_pos_ms += (1024*1000)/file_info.sampling_rate;
+
+ wd.bytelen = l;
+ wd.data = sample_buffer;
+ wd.markerend = 0;
+ wd.markerstart = decode_pos_ms;
+ wd.bps = 16;
+ wd.nch = frameInfo.channels;
+ wd.numsamples =l/file_info.channels/(16/8);
+ wd.srate = file_info.sampling_rate;
+
+ if (!QCDCallbacks->toPlayer.OutputWrite(&wd))
+ done = TRUE;
+ }
+ }
+ }
+ }
+ Sleep(10);
+ }
+
+ // close up
+ play_thread_handle = INVALID_HANDLE_VALUE;
+
+ faacDecClose(hDecoder);
+ hDecoder = INVALID_HANDLE_VALUE;
+ close_filestream(infile);
+ infile = NULL;
+
+ if(seek_table)
+ {
+ free(seek_table);
+ seek_table = NULL;
+ seek_table_length = 0;
+ }
+
+ if(buffer)
+ {
+ LocalFree(buffer);
+ buffer = NULL;
+ }
+ if(memmap_buffer)
+ {
+ LocalFree(memmap_buffer);
+ memmap_buffer = NULL;
+ }
+
+ return 0;
+}
+
+// thread play funcs
+int PlayThread_memmap()
+{
+ sample_buffer = (char*)faacDecDecode(hDecoder, &frameInfo,
+ memmap_buffer + memmap_index, fileread - memmap_index - 1);
+ if (frameInfo.error)
+ {
+// show_error(faacDecGetErrorMessage(frameInfo.error));
+ last_frame = 1;
+ }
+
+ memmap_index += frameInfo.bytesconsumed;
+ if (memmap_index >= fileread)
+ last_frame = 1;
+
+ return frameInfo.bytesconsumed;
+}
+
+int PlayThread_file()
+{
+ int k;
+
+ if (buffercount > 0)
+ {
+ for (k = 0; k < (768*2 - buffercount); k++)
+ buffer[k] = buffer[k + buffercount];
+
+ read_buffer_filestream(infile, buffer + (768*2) - buffercount, buffercount);
+ buffercount = 0;
+ }
+
+ sample_buffer = (char*)faacDecDecode(hDecoder, &frameInfo, buffer, 768*2);
+ if (frameInfo.error)
+ {
+// show_error(faacDecGetErrorMessage(frameInfo.error));
+ last_frame = 1;
+ }
+
+ buffercount += frameInfo.bytesconsumed;
+
+ bytecount += frameInfo.bytesconsumed;
+ if (bytecount >= fileread)
+ last_frame = 1;
+
+ return frameInfo.bytesconsumed;
+}
+
+// tag
+int id3v2_tag(unsigned char *buffer)
+{
+ if (StringComp(buffer, "ID3", 3) == 0)
+ {
+ unsigned long tagsize;
+
+ /* high bit is not used */
+ tagsize = (buffer[6] << 21) | (buffer[7] << 14) |
+ (buffer[8] << 7) | (buffer[9] << 0);
+
+ tagsize += 10;
+
+ return tagsize;
+ }
+ else
+ {
+ return 0;
+ }
+} \ No newline at end of file
diff --git a/faad2/src/plugins/QCD/QCDFAAD.sln b/faad2/src/plugins/QCD/QCDFAAD.sln
new file mode 100644
index 0000000..5810dde
--- /dev/null
+++ b/faad2/src/plugins/QCD/QCDFAAD.sln
@@ -0,0 +1,29 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QCDFAAD", "QCDFAAD.vcproj", "{71955EB0-4F77-462B-A844-2BA56E74B87E}"
+ ProjectSection(ProjectDependencies) = postProject
+ {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114} = {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfaad", "..\..\libfaad\libfaad.vcproj", "{BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {71955EB0-4F77-462B-A844-2BA56E74B87E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {71955EB0-4F77-462B-A844-2BA56E74B87E}.Debug|Win32.Build.0 = Debug|Win32
+ {71955EB0-4F77-462B-A844-2BA56E74B87E}.Release|Win32.ActiveCfg = Release|Win32
+ {71955EB0-4F77-462B-A844-2BA56E74B87E}.Release|Win32.Build.0 = Release|Win32
+ {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Debug|Win32.Build.0 = Debug|Win32
+ {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Release|Win32.ActiveCfg = Release|Win32
+ {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/faad2/src/plugins/QCD/QCDFAAD.vcproj b/faad2/src/plugins/QCD/QCDFAAD.vcproj
new file mode 100644
index 0000000..a57975e
--- /dev/null
+++ b/faad2/src/plugins/QCD/QCDFAAD.vcproj
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="QCDFAAD"
+ ProjectGUID="{71955EB0-4F77-462B-A844-2BA56E74B87E}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/QCDFAAD.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include,..\..\common\faad,..\..\plugins\winamp,..\..\common\id3lib\include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;ID3LIB_COMPILATION"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ PrecompiledHeaderFile=".\Debug/QCDFAAD.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1043"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+ OutputFile=".\Debug/QCDFAAD.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Debug/QCDFAAD.pdb"
+ SubSystem="2"
+ ImportLibrary=".\Debug/QCDFAAD.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Debug/QCDFAAD.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/QCDFAAD.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\..\include,..\..\common\faad,..\..\plugins\winamp,..\..\common\id3lib\include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;ID3LIB_COMPILATION"
+ StringPooling="true"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ PrecompiledHeaderFile=".\Release/QCDFAAD.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1043"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+ OutputFile=".\Release/QCDFAAD.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ ProgramDatabaseFile=".\Release/QCDFAAD.pdb"
+ SubSystem="2"
+ ImportLibrary=".\Release/QCDFAAD.lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ SuppressStartupBanner="true"
+ OutputFile=".\Release/QCDFAAD.bsc"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath="..\..\common\faad\aacinfo.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\common\faad\filestream.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="QCDFAAD.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath="..\..\common\faad\aacinfo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\faad.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\common\faad\filestream.h"
+ >
+ </File>
+ <File
+ RelativePath="QCDInputDLL.h"
+ >
+ </File>
+ <File
+ RelativePath="QCDModDefs.h"
+ >
+ </File>
+ <File
+ RelativePath="QCDModInput.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+ >
+ <File
+ RelativePath="hand.cur"
+ >
+ </File>
+ <File
+ RelativePath="logo.bmp"
+ >
+ </File>
+ <File
+ RelativePath="plugin_dlg.rc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions=""
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/faad2/src/plugins/QCD/QCDInputDLL.h b/faad2/src/plugins/QCD/QCDInputDLL.h
new file mode 100644
index 0000000..a69023b
--- /dev/null
+++ b/faad2/src/plugins/QCD/QCDInputDLL.h
@@ -0,0 +1,50 @@
+//-----------------------------------------------------------------------------
+//
+// File: QCDInputDLL.h
+//
+// About: QCD Player Input module DLL interface. For more documentation, see
+// QCDModInput.h.
+//
+// Authors: Written by Paul Quinn and Richard Carlson.
+//
+// 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 QCDInputDLL_H
+#define QCDInputDLL_H
+
+#include "QCDModInput.h"
+
+extern HINSTANCE hInstance;
+extern HWND hwndPlayer;
+extern QCDModInitIn sQCDCallbacks, *QCDCallbacks;
+
+// Calls from the Player
+int GetMediaSupported(const char* medianame, MediaInfo *mediaInfo);
+int GetTrackExtents(const char* medianame, TrackExtents *ext, int flags);
+int GetCurrentPosition(const char* medianame, long *track, long *offset);
+
+void SetEQ(EQInfo*);
+void SetVolume(int levelleft, int levelright, int flags);
+
+int Play(const char* medianame, int framefrom, int frameto, int flags);
+int Pause(const char* medianame, int flags);
+int Stop(const char* medianame, int flags);
+int Eject(const char* medianame, int flags);
+
+int Initialize(QCDModInfo *ModInfo, int flags);
+void ShutDown(int flags);
+void Configure(int flags);
+void About(int flags);
+
+#endif //QCDInputDLL_H \ No newline at end of file
diff --git a/faad2/src/plugins/QCD/QCDModDefs.h b/faad2/src/plugins/QCD/QCDModDefs.h
new file mode 100644
index 0000000..1f68baf
--- /dev/null
+++ b/faad2/src/plugins/QCD/QCDModDefs.h
@@ -0,0 +1,340 @@
+//-----------------------------------------------------------------------------
+//
+// File: QCDModDefs.h
+//
+// About: Module definitions file. Miscellanious definitions used by different
+// module types. This file is published with the plugin SDKs.
+//
+// Authors: Written by Paul Quinn and Richard Carlson.
+//
+// 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 QCDMODDEFS_H
+#define QCDMODDEFS_H
+
+#include <windows.h>
+
+#ifdef __cplusplus
+#define PLUGIN_API extern "C" __declspec(dllexport)
+#else
+#define PLUGIN_API __declspec(dllexport)
+#endif
+
+// Current plugin version
+#define PLUGIN_API_VERSION 250
+
+//-----------------------------------------------------------------------------
+
+typedef struct {
+ char *moduleString;
+ char *moduleExtensions;
+
+} QCDModInfo;
+
+//-----------------------------------------------------------------------------
+// Services (ops) provided by the Player
+//-----------------------------------------------------------------------------
+typedef enum
+{ //*** below returns numeric info (*buffer not used)
+
+ opGetPlayerVersion = 0, // high-order word = major version (eg 3.01 is 3), low-order word = minor (eg 3.01 = 1)
+ opGetParentWnd = 1, // handle to player window
+ opGetPlayerInstance = 2, // HINSTANCE to player executable
+
+ opGetPlayerState = 9, // get current state of the player (returns: 1 = stopped, 2 = playing, 3 = paused, 0 = failed)
+ opGetNumTracks = 10, // number of tracks in playlist
+ opGetCurrentIndex = 11, // index of current track in playlist (0 based)
+ 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
+
+ opGetTrackLength = 14, // get track length, param1 = index of track in playlist, -1 for current
+ // param2 = 0 for seconds, 1 for milliseconds
+ opGetTime = 15, // get time on player, param1 = 0 for time displayed, 1 for track time, 2 for playlist time
+ // param2 = 0 for elapsed, 1 for remaining
+ opGetTrackState = 16, // get whether track is marked, param1 = index of track, -1 for current
+ opGetPlaylistNum = 17, // get playlist number of index, param1 = index of track in playlist, -1 for current
+ opGetMediaType = 18, // get media type of track, param1 = index if track in playlist, -1 for current
+ // - see MediaTypes below for return values
+
+ opGetAudioInfo = 19, // get format info about currently playing track
+ // - param1 = 0 for samplerate, 1 for bitrate, 2 for num channels
+
+ opGetOffline = 20, // true if client is in Offline Mode
+ opGetVisTarget = 21, // where is vis being drawn > 0 - internal to skin, 1 - external window, 2 - full screen
+ opGetAlwaysOnTop = 22, // true if player is set to 'Always on Top'
+ opGetRepeatState = 23, // returns: 0 - repeat off, 1 - repeat track, 2 - repeat all
+ opGetShuffleState = 27, // returns: 0 - shuffle off, 1 - shuffle enabled
+
+ opGetTimerState = 24, // low-order word: 0 - track ascend, 1 - playlist ascend, 2 - track descend, 3 - playlist descend
+ // hi-order word: 1 if 'show hours' is set, else 0
+
+ opGetVolume = 25, // get master volume level (0 - 100), param1: 0 = combined, 1 = left, 2 = right
+ opSetVolume = 26, // set master volume level, param1: vol level 0 - 100, param2: balance (-100 left, 0 center, 100 right)
+
+ opGetIndexFromPLNum = 28, // get index from playlist number, param1 = playlist number
+
+ opGetChildWnd = 30, // handle to the draggable window extension (only available on some skins)
+ opGetExtVisWnd = 31, // handle to the external visual window
+ opGetMusicBrowserWnd = 32, // handle to the music browser window
+ opGetSkinPreviewWnd = 33, // handle to the skin preview window
+ opGetPropertiesWnd = 34, // handle to the player properties window
+ opGetExtInfoWnd = 35, // handle to the extended information window
+ opGetAboutWnd = 36, // handle to the about window
+ opGetSegmentsWnd = 37, // handle to the segments window
+ opGetEQPresetsWnd = 38, // handle to the EQ presets 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
+
+ opGetQueriesComplete = 60, // get status on whether all tracks in playlist have been queryied for their info
+
+ // playlist manipulation
+ opDeleteIndex = 90, // delete index from playlist (param1 = index)
+ 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
+ // param2 = pointer to integer that receives track value
+ // returns: pointer to CddbDisc object. Do not release or deallocate this pointer
+
+
+ //*** below returns string info in buffer, param1 = size of buffer
+ //*** returns 1 on success, 0 on failure
+
+ opGetTrackName = 100, // get track name, param2 = index of track in playlist, -1 for current
+ opGetArtistName = 101, // get artist name, param2 = index of track in playlist, -1 for current
+ opGetDiscName = 102, // get disc name, param2 = index of track in playlist, -1 for current
+
+ opGetTrackFile = 103, // file name of track in playlist, param2 = index of track in playlist, -1 for current
+ opGetSkinName = 104, // get current skin name
+
+ opGetPluginFolder = 105, // get current plugin folder
+ opGetPluginSettingsFile = 106, // get settings file (plugins.ini) that plugin should save settings to
+ opGetPluginCacheFile = 107, // get file that describes plugin validity, functions and names
+ opGetPlayerSettingsFile = 108, // get settings file (qcd.ini) that player saves it settings to (should use for read-only)
+
+ opGetMusicFolder = 110, // get current music folder
+ opGetPlaylistFolder = 111, // get current playlist folder
+ opGetSkinFolder = 112, // get current skin folder
+ opGetCDDBCacheFolder = 113, // get current folder for CDDB cached info
+
+ opGetCurrentPlaylist = 114, // get full pathname of playlist currently loaded
+
+ opGetMediaID = 115, // get media identifier, param2 = index of track in playlist, -1 for current
+ // - for CD's it's the TOC - for anything else, right now it's 0
+
+ opGetSupportedExtensions = 116, // get file extensions supported by the player, param2 = 0 - get all extensions, 1 - get registered extensions
+ // - returned extensions will be colon delimited
+
+
+ //*** below buffer points to struct or other object
+ //*** returns 1 on success, 0 on failure
+
+ opShowMainMenu = 120, // Display Main QCD Menu (buffer = POINT* - location to display menu)
+ 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)
+
+ opGetEQVals = 200, // get current EQ levels/on/off (buffer = EQInfo*)
+ opSetEQVals = 201, // set EQ levels/on/off (buffer = EQInfo*)
+
+ opGetProxyInfo = 202, // get proxy info (buffer = ProxyInfo*), returns 0 if proxy not in use
+
+
+ //*** below returns numeric info, buffer used
+
+ opGetIndexFromFilename = 210, // get the index of a file that exists in current playlist (buffer = full path of file),
+ // param1 = startindex (index to start searching on)
+ // returns -1 if file not in playlist
+
+
+ //*** below send information to player
+ //*** returns 1 on success, 0 on failure
+
+ opSetStatusMessage = 1000, // display message in status area (buffer = msg buffer (null term), param1 = text flags (see below))
+
+ opSetBrowserUrl = 1001, // set music browser URL (buffer = url (null term))
+ // null url buffer - closes browser
+ // param1 = 0 - normal, 1 - force open
+
+ opSetAudioInfo = 1002, // set the current music bitrate/khz (buffer = AudioInfo*, param1 = size of AudioInfo)
+
+ opSetTrackAlbum = 1003, // update track ablum name (buffer = album (null term), param1 = (string ptr)file name), param2 = MediaTypes
+ opSetTrackTitle = 1004, // update track title (buffer = title (null term), param1 = (string ptr)file name), param2 = MediaTypes
+ opSetTrackArtist = 1005, // update track artist name (buffer = artist (null term), param1 = (string ptr)file name), param2 = MediaTypes
+
+ opSetPlaylist = 1006, // add files to or reset playlist with new files (buffer = file list (null term), param1 = (string ptr)originating path (can be NULL), param2 = 1 - clear playlist flag, 2 - enqueue to top
+
+ opSetTrackExtents = 1007, // update track TrackExtents info (buffer = &TrackExtents), param1 = (string ptr)file name)
+ opSetTrackSeekable = 1008, // update track seekable flag (buffer = (string ptr)file name), param1 = TRUE/FALSE
+ opSetPlayNext = 1009, // set the next index to be played (buffer = NULL, param1 = index, index = -1 unsets playnext)
+ opSetIndexFilename = 1010, // updates the filename (or stream) that an index in the current playlist refers to, buffer = new filename, param1 = index
+
+ 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))
+
+
+ //*** 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
+
+ opSetPluginMenuItem = 2000, // buffer = HINSTANCE of plugin, param1 = item id, param2 = (string ptr)string to display
+ // - set param2 = 0 to remove item id from menu
+ // - set param1 = 0 and param2 = 0 to remove whole menu
+ opSetPluginMenuState = 2001, // buffer = HINSTANCE of plugin, param1 = item id, param2 = menu flags (same as windows menu flags - eg: MF_CHECKED)
+
+
+ //*** other services
+
+ 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
+
+} PluginServiceOp;
+
+//-----------------------------------------------------------------------------
+// Info services api provided by the Player, called by Plugin.
+//-----------------------------------------------------------------------------
+typedef long (*PluginServiceFunc)(PluginServiceOp op, void *buffer, long param1, long param2);
+
+
+//-----------------------------------------------------------------------------
+typedef struct // for Output Plugin Write callback
+{
+ void *data; // pointer to valid data
+ int bytelen; // length of data pointed to by 'data' in bytes
+ UINT numsamples; // number of samples represented by 'data'
+ UINT bps; // bits per sample
+ UINT nch; // number of channels
+ UINT srate; // sample rate
+
+ UINT markerstart; // Marker position at start of data (marker is time value of data)
+ // (set to WAVE_VIS_DATA_ONLY to not have data sent to output plugins)
+ UINT markerend; // Marker position at end of data (not currently used, set to 0)
+} WriteDataStruct;
+
+//-----------------------------------------------------------------------------
+typedef struct // for GetTrackExtents Input Plugin callback
+{
+ UINT track; // for CD's, set the track number. Otherwise set to 1.
+ UINT start; // for CD's or media that doesn't start at the beginning
+ // of the file, set to start position. Otherwise set to 0.
+ UINT end; // set to end position of media.
+ UINT unitpersec; // whatever units are being used for this media, how many
+ // of them per second.
+ // (Note: ((end - start) / unitpersecond) = file length
+ UINT bytesize; // size of file in bytes (if applicable, otherwise 0).
+} TrackExtents;
+
+//-----------------------------------------------------------------------------
+typedef struct // for opSetAudioInfo service
+{
+ long struct_size; // sizeof(AudioInfo)
+ long level; // MPEG level (1 for MPEG1, 2 for MPEG2, 3 for MPEG2.5, 7 for MPEGpro)
+ long layer; // and layer (1, 2 or 3)
+ 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
+} AudioInfo;
+
+//-----------------------------------------------------------------------------
+// Equalizer Info
+//-----------------------------------------------------------------------------
+typedef struct // for coming QCD version
+{
+ long struct_size; // sizeof(EQInfo)
+ char enabled;
+ char preamp; // -128 to 127, 0 is even
+ char bands[10]; // -128 to 127, 0 is even
+} EQInfo;
+
+//-----------------------------------------------------------------------------
+typedef struct
+{
+ long struct_size; // sizeof(ProxyInfo)
+ char hostname[200];
+ long port;
+ char username[100];
+ char password[100];
+} ProxyInfo;
+
+//-----------------------------------------------------------------------------
+typedef enum // for MediaInfo.mediaType
+{
+ UNKNOWN_MEDIA = 0,
+ CD_AUDIO_MEDIA = 1,
+ DIGITAL_FILE_MEDIA = 2,
+ DIGITAL_STREAM_MEDIA = 3
+} MediaTypes;
+
+//-----------------------------------------------------------------------------
+#define MAX_TOC_LEN 2048
+typedef struct
+{
+ // media descriptors
+ CHAR mediaFile[MAX_PATH];
+ MediaTypes mediaType;
+
+ // cd audio media info
+ CHAR cd_mediaTOC[MAX_TOC_LEN];
+ int cd_numTracks;
+ int cd_hasAudio;
+
+ // operation info
+ int op_canSeek;
+
+ // not used
+ int reserved[4];
+
+} MediaInfo;
+
+
+//-----------------------------------------------------------------------------
+// When subclassing the parent window, a plugin can watch for these messages
+// to react to events going on between plugins and player
+// DO NOT SEND THESE MESSAGES - can only watch for them
+
+// Plugin to Player Notifiers
+#define WM_PN_POSITIONUPDATE (WM_USER + 100) // playback progress updated
+#define WM_PN_PLAYSTARTED (WM_USER + 101) // playback has started
+#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_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)
+
+// Player to Plugin Notifiers
+#define WM_PN_PLAYLISTCHANGED (WM_USER + 200) // playlist has changed in some way (add, delete, sort, shuffle, drag-n-drop, etc...)
+
+// For intercepting main menu display
+// (so you can get handle, modify, and display your own)
+#define WM_SHOWMAINMENU (WM_USER + 20)
+
+//-----------------------------------------------------------------------------
+// To shutdown player, send this command
+#define WM_SHUTDOWN (WM_USER + 5)
+
+//-----------------------------------------------------------------------------
+// opSetStatusMessage textflags
+#define TEXT_DEFAULT 0x0 // message scrolls by in status window
+#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)
+
+
+#endif //QCDMODDEFS_H \ No newline at end of file
diff --git a/faad2/src/plugins/QCD/QCDModInput.h b/faad2/src/plugins/QCD/QCDModInput.h
new file mode 100644
index 0000000..40a7ae5
--- /dev/null
+++ b/faad2/src/plugins/QCD/QCDModInput.h
@@ -0,0 +1,117 @@
+//-----------------------------------------------------------------------------
+//
+// File: QCDModInput.h
+//
+// About: Input plugin module interface. This file is published with the
+// Input plugin SDK.
+//
+// Authors: Written by Paul Quinn and Richard Carlson.
+//
+// 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 QCDMODINPUT_H
+#define QCDMODINPUT_H
+
+#include "QCDModDefs.h"
+
+// name of the DLL export for input plugins
+#define INPUTDLL_ENTRY_POINT QInputModule2 // (updated plugin api version 240+)
+
+// media insert flags
+#define MEDIAINSERT_PLAY 0x1
+#define MEDIAINSERT_ADDTRACKS 0x2
+#define MEDIAINSERT_ADDSEGMENTS 0x4
+#define MEDIAINSERT_CLEARPLAYLIST 0x8
+
+// Stop will receive one of these flags (pass to output plugin's stop())
+#define STOPFLAG_FORCESTOP 0 // stop occuring due to user action or other event
+#define STOPFLAG_PLAYDONE 1 // stop occuring due to playlist completion
+
+// play flags
+#define PLAYFLAG_PLAYBACK 0x0
+#define PLAYFLAG_ENCODING 0x1
+#define PLAYFLAG_SEEKING 0x2
+
+// Wave Marker flags
+#define WAVE_VIS_DATA_ONLY -1 // set to WaveDataStruct.markerstart in OutputWrite() call have data only go to vis
+ // and not to output plugin
+// pause flags
+#define PAUSE_DISABLED 0 // Pause() call is to unpause playback
+#define PAUSE_ENABLED 1 // Pause() call is to pause playback
+
+//-----------------------------------------------------------------------------
+// Input Module
+//-----------------------------------------------------------------------------
+typedef struct
+{
+ unsigned int size; // size of init structure
+ unsigned int version; // plugin structure version (set to PLUGIN_API_VERSION)
+ PluginServiceFunc Service; // player supplied services callback
+
+ struct
+ {
+ void (*PositionUpdate)(unsigned int position);
+ void (*PlayStopped)(const char* medianame); // notify player of play stop
+ void (*PlayStarted)(const char* medianame); // notify player of play start
+ void (*PlayPaused)(const char* medianame, int flags); // notify player of play pause
+ void (*PlayDone)(const char* medianame); // notify player when play done
+ void (*PlayTrackChanged)(const char* medianame); // notify player when playing track changes (cd audio relevant only)
+ void (*MediaEjected)(const char* medianame); // notify player of media eject (cd audio relevant)
+ void (*MediaInserted)(const char* medianame, int flags); // notify player of media insert (cd audio relevant)
+
+ // output plugin calls
+ int (*OutputOpen)(const char* medianame, WAVEFORMATEX*); // open output for wave data
+ int (*OutputWrite)(WriteDataStruct*); // send PCM audio data to output
+ // (blocks until write completes, thus if output is paused can
+ // block until unpaused)
+ int (*OutputDrain)(int flags); // wait for all output to complete (blocking)
+ int (*OutputDrainCancel)(int flags); // break a drain in progress
+ int (*OutputFlush)(unsigned int marker); // flush output upto marker
+ int (*OutputStop)(int flags); // stop output
+ int (*OutputPause)(int flags); // pause output
+
+ int (*OutputSetVol)(int levelleft, int levelright, int flags);
+ int (*OutputGetCurrentPosition)(unsigned int *position, int flags);
+
+ void *Reserved[10];
+ } toPlayer;
+
+ struct
+ {
+ int (*Initialize)(QCDModInfo *modInfo, int flags); // initialize plugin
+ void (*ShutDown)(int flags); // shutdown plugin
+
+ int (*Play)(const char* medianame, int playfrom, int playto, int flags); // start playing playfrom->playto
+ int (*Stop)(const char* medianame, int flags); // stop playing
+ int (*Pause)(const char* medianame, int flags); // pause playback
+ int (*Eject)(const char* medianame, int flags); // eject media
+ void (*SetEQ)(EQInfo*); // update EQ settings
+
+ int (*GetMediaSupported)(const char* medianame, MediaInfo *mediaInfo); // does plugin support medianame (and provides info for media)
+ int (*GetTrackExtents)(const char* medianame, TrackExtents *ext, int flags); // get media start, end & units
+ int (*GetCurrentPosition)(const char* medianame, long *track, long *offset); // get playing media's position
+
+ void (*Configure)(int flags); // launch configuration
+ void (*About)(int flags); // launch about info
+
+ void (*SetVolume)(int levelleft, int levelright, int flags); // level 0 - 100
+
+ void *Reserved[10];
+ } toModule;
+
+} QCDModInitIn;
+
+#endif //QCDMODINPUT_H
diff --git a/faad2/src/plugins/QCD/ReadMe.txt b/faad2/src/plugins/QCD/ReadMe.txt
new file mode 100644
index 0000000..2e89c09
--- /dev/null
+++ b/faad2/src/plugins/QCD/ReadMe.txt
@@ -0,0 +1,11 @@
+QCDFAAD.dll input Plugin for Quintessential Player (QCD)
+Please goto http://www.quinnware.com to download the latest version of QCD.
+
+About Tagging music file:
+
+Because QCD support ID3v1 & ID3v2 functions. So you can add a string -- ":AAC"
+in the configuration dialog box of QCDcddb.dll Libarary Plugin.
+(I think you will find it and will know how to do it,
+otherwise you can visite the message forum on the web site.)
+
+Have a good time:) \ No newline at end of file
diff --git a/faad2/src/plugins/QCD/logo.bmp b/faad2/src/plugins/QCD/logo.bmp
new file mode 100644
index 0000000..a01eb84
--- /dev/null
+++ b/faad2/src/plugins/QCD/logo.bmp
Binary files differ
diff --git a/faad2/src/plugins/QCD/plugin_dlg.rc b/faad2/src/plugins/QCD/plugin_dlg.rc
new file mode 100644
index 0000000..1316be9
--- /dev/null
+++ b/faad2/src/plugins/QCD/plugin_dlg.rc
@@ -0,0 +1,141 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONFIG DIALOGEX 0, 0, 179, 133
+STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "FAAC Decoder Configuration"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ CONTROL "Enable variable bitrate display",VARBITRATE_CHK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,7,140,10
+ EDITTEXT STREAM_BUFFER_TXT,87,21,21,12,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT LOCAL_BUFFER_TXT,87,38,21,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Buffer entire files into memory",IDC_MEMMAP,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,60,140,10
+ CONTROL "Slider1",THREAD_PRIORITY_SLIDER,"msctls_trackbar32",
+ TBS_AUTOTICKS | WS_TABSTOP,7,89,165,11,WS_EX_TRANSPARENT
+ PUSHBUTTON "OK",OK_BTN,64,112,50,14
+ PUSHBUTTON "Cancel",CANCEL_BTN,121,112,50,14
+ LTEXT "HTTP stream buffer:",IDC_STATIC,7,22,77,8
+ LTEXT "Decode Thread Priority: Highest (default)",IDC_STATIC2,
+ 7,78,165,8
+ LTEXT "Local file buffer: ",IDC_STATIC,7,40,77,8
+ PUSHBUTTON "Reset",RESET_BTN,7,112,50,14
+END
+
+IDD_ABOUT DIALOG DISCARDABLE 0, 0, 191, 168
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About FAAD Plug-in"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,70,147,50,14
+ CTEXT "",IDC_PLUGINVER,29,73,133,16
+ CTEXT "",IDC_FAADVER,40,123,111,8
+ LTEXT "QCD Input Plug-in by",IDC_STATIC,62,97,67,8
+ CONTROL 107,IDC_LOGO,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE,7,0,177,68
+ LTEXT "Shao Hao",IDC_MAIL1,79,111,33,8
+ LTEXT "M. Bakker",IDC_MAIL3,59,134,34,8
+ LTEXT "menno",IDC_MAIL2,109,134,22,8
+ LTEXT "&&",IDC_STATIC,97,134,8,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_CONFIG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 172
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 126
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 184
+ BOTTOMMARGIN, 161
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_LOGO BITMAP DISCARDABLE "logo.bmp"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/faad2/src/plugins/QCD/resource.h b/faad2/src/plugins/QCD/resource.h
new file mode 100644
index 0000000..7837a2c
--- /dev/null
+++ b/faad2/src/plugins/QCD/resource.h
@@ -0,0 +1,33 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by plugin_dlg.rc
+//
+#define IDD_CONFIG 101
+#define IDD_ABOUT 106
+#define IDB_LOGO 107
+#define VARBITRATE_CHK 1004
+#define THREAD_PRIORITY_SLIDER 1007
+#define IDC_STATIC2 1034
+#define LOCAL_BUFFER_TXT 1035
+#define STREAM_BUFFER_TXT 1036
+#define IDC_MEMMAP 1037
+#define OK_BTN 1038
+#define CANCEL_BTN 1039
+#define RESET_BTN 1047
+#define IDC_LOGO 1048
+#define IDC_PLUGINVER 1050
+#define IDC_FAADVER 1051
+#define IDC_MAIL1 1052
+#define IDC_MAIL2 1053
+#define IDC_MAIL3 1054
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 109
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1055
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/faad2/src/plugins/QCDMp4/QCDInputDLL.h b/faad2/src/plugins/QCDMp4/QCDInputDLL.h
new file mode 100644
index 0000000..46a811a
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDInputDLL.h
@@ -0,0 +1,46 @@
+//-----------------------------------------------------------------------------
+//
+// File: QCDInputDLL.h
+//
+// About: QCD Player Input module DLL interface. For more documentation, see
+// QCDModInput.h.
+//
+// Authors: Written by Paul Quinn and Richard Carlson.
+//
+// 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 QCDInputDLL_H
+#define QCDInputDLL_H
+
+#include "QCDModInput.h"
+
+// Calls from the Player
+int GetMediaSupported(const char* medianame, MediaInfo *mediaInfo);
+int GetTrackExtents(const char* medianame, TrackExtents *ext, int flags);
+int GetCurrentPosition(const char* medianame, long *track, long *offset);
+
+void SetEQ(EQInfo*);
+void SetVolume(int levelleft, int levelright, int flags);
+
+int Play(const char* medianame, int framefrom, int frameto, int flags);
+int Pause(const char* medianame, int flags);
+int Stop(const char* medianame, int flags);
+int Eject(const char* medianame, int flags);
+
+int Initialize(QCDModInfo *ModInfo, int flags);
+void ShutDown(int flags);
+void Configure(int flags);
+void About(int flags);
+
+#endif //QCDInputDLL_H \ No newline at end of file
diff --git a/faad2/src/plugins/QCDMp4/QCDModDefs.h b/faad2/src/plugins/QCDMp4/QCDModDefs.h
new file mode 100644
index 0000000..6b87006
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDModDefs.h
@@ -0,0 +1,413 @@
+//-----------------------------------------------------------------------------
+//
+// File: QCDModDefs.h
+//
+// About: Module definitions file. Miscellanious definitions used by different
+// module types. This file is published with the plugin SDKs.
+//
+// Authors: Written by Paul Quinn and Richard Carlson.
+//
+// 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 QCDMODDEFS_H
+#define QCDMODDEFS_H
+
+#include <mmreg.h>
+#include <windows.h>
+
+#ifdef __cplusplus
+#define PLUGIN_API extern "C" __declspec(dllexport)
+#else
+#define PLUGIN_API __declspec(dllexport)
+#endif
+
+// Current plugin version
+
+// 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
+{
+ char *moduleString;
+ char *moduleExtensions;
+} QCDModInfo;
+
+//-----------------------------------------------------------------------------
+// Services (ops) provided by the Player
+//-----------------------------------------------------------------------------
+typedef enum
+{ //*** below returns numeric info (*buffer not used)
+
+ opGetPlayerVersion = 0, // high-order word = major version (eg 3.01 is 3), low-order word = minor (eg 3.01 = 1)
+ opGetParentWnd = 1, // handle to player window
+ opGetPlayerInstance = 2, // HINSTANCE to player executable
+
+ opGetPlayerState = 9, // get current state of the player (returns: 1 = stopped, 2 = playing, 3 = paused, 0 = failed)
+ opGetNumTracks = 10, // number of tracks in playlist
+ opGetCurrentIndex = 11, // index of current track in playlist (0 based)
+ 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 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
+ opGetTime = 15, // get time on player, param1 = 0 for time displayed, 1 for track time, 2 for playlist time
+ // param2 = 0 for elapsed, 1 for remaining
+ opGetTrackState = 16, // get whether track is marked, param1 = index of track, -1 for current
+ opGetPlaylistNum = 17, // get playlist number of index, param1 = index of track in playlist, -1 for current
+ opGetMediaType = 18, // get media type of track, param1 = index if track in playlist, -1 for current
+ // - see MediaTypes below for return values
+
+ opGetAudioInfo = 19, // get format info about currently playing track
+ // - param1 = 0 for samplerate, 1 for bitrate, 2 for num channels
+
+ opGetOffline = 20, // true if client is in Offline Mode
+ opGetVisTarget = 21, // where is vis being drawn > 0 - internal to skin, 1 - external window, 2 - full screen
+ opGetAlwaysOnTop = 22, // true if player is set to 'Always on Top'
+ opGetRepeatState = 23, // returns: 0 - repeat off, 1 - repeat track, 2 - repeat all
+ opGetShuffleState = 27, // returns: 0 - shuffle off, 1 - shuffle enabled
+
+ opGetTimerState = 24, // low-order word: 0 - track ascend, 1 - playlist ascend, 2 - track descend, 3 - playlist descend
+ // hi-order word: 1 if 'show hours' is set, else 0
+
+ opGetVolume = 25, // get master volume level (0 - 100), param1: 0 = combined, 1 = left, 2 = right
+ opSetVolume = 26, // set master volume level, param1: vol level 0 - 100, param2: balance (-100 left, 0 center, 100 right)
+
+ opGetIndexFromPLNum = 28, // get index from playlist number, param1 = playlist number
+
+ 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
+ opGetPropertiesWnd = 34, // handle to the player properties window
+ opGetExtInfoWnd = 35, // handle to the extended information window
+ 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
+ opDeleteIndex = 90, // delete index from playlist (param1 = index)
+ 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 ICddbDisc object for the index specified, param1 = index of track, -1 for current
+ // param2 = pointer to integer that receives track value
+ // returns: pointer to ICddbDisc object. Do not release or deallocate this pointer
+
+
+ //*** below returns string info in buffer, param1 = size of buffer
+ //*** returns 1 on success, 0 on failure
+
+ opGetTrackName = 100, // get track name, param2 = index of track in playlist, -1 for current
+ opGetArtistName = 101, // get artist name, param2 = index of track in playlist, -1 for current
+ opGetDiscName = 102, // get disc name, param2 = index of track in playlist, -1 for current
+
+ opGetTrackFile = 103, // file name of track in playlist, param2 = index of track in playlist, -1 for current
+ opGetSkinName = 104, // get current skin name
+
+ opGetPluginFolder = 105, // get current plugin folder
+ opGetPluginSettingsFile = 106, // get settings file (plugins.ini) that plugin should save settings to
+ opGetPluginCacheFile = 107, // get file that describes plugin validity, functions and names
+ opGetPlayerSettingsFile = 108, // get settings file (qcd.ini) that player saves it settings to (should use for read-only)
+
+ opGetMusicFolder = 110, // get current music folder
+ opGetPlaylistFolder = 111, // get current playlist folder
+ opGetSkinFolder = 112, // get current skin folder
+ opGetCDDBCacheFolder = 113, // get current folder for CDDB cached info
+
+ opGetCurrentPlaylist = 114, // get full pathname of playlist currently loaded
+
+ opGetMediaID = 115, // get media identifier, param2 = index of track in playlist, -1 for current
+ // - for CD's it's the TOC - for anything else, right now it's 0
+
+ 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
+
+ opShowMainMenu = 120, // Display Main QCD Menu (buffer = POINT* - location to display menu)
+ 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*)
+
+ opGetProxyInfo = 202, // get proxy info (buffer = ProxyInfo*), returns 0 if proxy not in use
+
+
+ //*** below returns numeric info, buffer used
+
+ opGetIndexFromFilename = 210, // get the index of a file that exists in current playlist (buffer = full path of file),
+ // param1 = startindex (index to start searching on)
+ // returns -1 if file not in playlist
+
+
+ //*** below send information to player
+ //*** returns 1 on success, 0 on failure
+
+ opSetStatusMessage = 1000, // display message in status area (buffer = msg buffer (null term), param1 = text flags (see below))
+
+ opSetBrowserUrl = 1001, // set music browser URL (buffer = url (null term))
+ // null url buffer - closes browser
+ // param1 = 0 - normal, 1 - force open
+
+ opSetAudioInfo = 1002, // set the current music bitrate/khz (buffer = AudioInfo*, param1 = size of AudioInfo)
+
+ opSetTrackAlbum = 1003, // update track ablum name (buffer = album (null term), param1 = (string ptr)file name), param2 = MediaTypes
+ opSetTrackTitle = 1004, // update track title (buffer = title (null term), param1 = (string ptr)file name), param2 = MediaTypes
+ opSetTrackArtist = 1005, // update track artist name (buffer = artist (null term), param1 = (string ptr)file name), param2 = MediaTypes
+
+ opSetTrackExtents = 1007, // update track TrackExtents info (buffer = &TrackExtents), param1 = (string ptr)file name)
+ opSetTrackSeekable = 1008, // update track seekable flag (buffer = (string ptr)file name), param1 = TRUE/FALSE
+ opSetPlayNext = 1009, // set the next index to be played (buffer = NULL, param1 = index, index = -1 unsets playnext)
+ opSetIndexFilename = 1010, // updates the filename (or stream) that an index in the current playlist refers to, buffer = new filename, param1 = index
+
+ opSetPlaylist = 1006, // clear playlist, add files to playlist or reset playlist with new files
+ // buffer = file list (each file in quotes, string null terminated) Eg; buffer="\"file1.mp3\" \"file2.mp3\"\0" - NULL to clear playlist
+ // param1 = (string ptr)originating path (can be NULL if paths included with files)
+ // param2 = 1 - clear playlist flag, 2 - enqueue to top
+
+ opInsertPlaylist = 1011, // insert tracks into playlist
+ // buffer = file list (each file in quotes, string null terminated) Eg; buffer="\"file1.mp3\" \"file2.mp3\"\0"
+ // param1 = (string ptr)originating path (can be NULL if paths included with files)
+ // param2 = index location to insert tracks (-1 to insert at end)
+
+ 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
+
+ opSetPluginMenuItem = 2000, // buffer = HINSTANCE of plugin, param1 = item id, param2 = (string ptr)string to display
+ // - set param2 = 0 to remove item id from menu
+ // - set param1 = 0 and param2 = 0 to remove whole menu
+ 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
+
+} PluginServiceOp;
+
+//-----------------------------------------------------------------------------
+// Info services api provided by the Player, called by Plugin.
+//-----------------------------------------------------------------------------
+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
+{
+ void *data; // pointer to valid data
+ int bytelen; // length of data pointed to by 'data' in bytes
+ UINT numsamples; // number of samples represented by 'data'
+ UINT bps; // bits per sample
+ UINT nch; // number of channels
+ UINT srate; // sample rate
+
+ UINT markerstart; // Marker position at start of data (marker is time value of data)
+ // (set to WAVE_VIS_DATA_ONLY to not have data sent to output plugins)
+ UINT markerend; // Marker position at end of data (not currently used, set to 0)
+} WriteDataStruct;
+
+//-----------------------------------------------------------------------------
+typedef struct // for GetTrackExtents Input Plugin callback
+{
+ UINT track; // for CD's, set the track number. Otherwise set to 1.
+ UINT start; // for CD's or media that doesn't start at the beginning
+ // of the file, set to start position. Otherwise set to 0.
+ UINT end; // set to end position of media.
+ UINT unitpersec; // whatever units are being used for this media, how many
+ // of them per second.
+ // (Note: ((end - start) / unitpersecond) = file length
+ UINT bytesize; // size of file in bytes (if applicable, otherwise 0).
+} TrackExtents;
+
+//-----------------------------------------------------------------------------
+typedef struct // for opSetAudioInfo service
+{
+ long struct_size; // sizeof(AudioInfo)
+ long level; // MPEG level (1 for MPEG1, 2 for MPEG2, 3 for MPEG2.5, 7 for MPEGpro)
+ long layer; // and layer (1, 2 or 3)
+ 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;
+
+//-----------------------------------------------------------------------------
+// Equalizer Info
+//-----------------------------------------------------------------------------
+typedef struct // for coming QCD version
+{
+ long struct_size; // sizeof(EQInfo)
+ char enabled;
+ char preamp; // -128 to 127, 0 is even
+ char bands[10]; // -128 to 127, 0 is even
+} EQInfo;
+
+//-----------------------------------------------------------------------------
+typedef struct
+{
+ long struct_size; // sizeof(ProxyInfo)
+ char hostname[200];
+ long port;
+ char username[100];
+ char password[100];
+} ProxyInfo;
+
+//-----------------------------------------------------------------------------
+typedef enum // for MediaInfo.mediaType
+{
+ UNKNOWN_MEDIA = 0,
+ CD_AUDIO_MEDIA = 1,
+ DIGITAL_FILE_MEDIA = 2,
+ DIGITAL_STREAM_MEDIA = 3
+} MediaTypes;
+
+//-----------------------------------------------------------------------------
+#define MAX_TOC_LEN 2048
+typedef struct
+{
+ // media descriptors
+ CHAR mediaFile[MAX_PATH];
+ MediaTypes mediaType;
+
+ // cd audio media info
+ CHAR cd_mediaTOC[MAX_TOC_LEN];
+ int cd_numTracks;
+ int cd_hasAudio;
+
+ // operation info
+ int op_canSeek;
+
+ // not used
+ int reserved[4];
+
+} 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
+// DO NOT SEND THESE MESSAGES - can only watch for them
+
+// Plugin to Player Notifiers
+#define WM_PN_POSITIONUPDATE (WM_USER + 100) // playback progress updated
+#define WM_PN_PLAYSTARTED (WM_USER + 101) // playback has started
+#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 (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)
+
+// Player to Plugin Notifiers
+#define WM_PN_PLAYLISTCHANGED (WM_USER + 200) // playlist has changed in some way (add, delete, sort, shuffle, drag-n-drop, etc...)
+
+// For intercepting main menu display
+// (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)
+
+//-----------------------------------------------------------------------------
+// opSetStatusMessage textflags
+#define TEXT_DEFAULT 0x0 // message scrolls by in status window
+#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
diff --git a/faad2/src/plugins/QCDMp4/QCDModInput.h b/faad2/src/plugins/QCDMp4/QCDModInput.h
new file mode 100644
index 0000000..4150ff1
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDModInput.h
@@ -0,0 +1,117 @@
+//-----------------------------------------------------------------------------
+//
+// File: QCDModInput.h
+//
+// About: Input plugin module interface. This file is published with the
+// Input plugin SDK.
+//
+// Authors: Written by Paul Quinn and Richard Carlson.
+//
+// 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 QCDMODINPUT_H
+#define QCDMODINPUT_H
+
+#include "QCDModDefs.h"
+
+// name of the DLL export for input plugins
+#define INPUTDLL_ENTRY_POINT QInputModule2 // (updated plugin api version 240+)
+
+// media insert flags
+#define MEDIAINSERT_PLAY 0x1
+#define MEDIAINSERT_ADDTRACKS 0x2
+#define MEDIAINSERT_ADDSEGMENTS 0x4
+#define MEDIAINSERT_CLEARPLAYLIST 0x8
+
+// Stop will receive one of these flags (pass to output plugin's stop())
+#define STOPFLAG_FORCESTOP 0 // stop occuring due to user action or other event
+#define STOPFLAG_PLAYDONE 1 // stop occuring due to playlist completion
+
+// play flags
+#define PLAYFLAG_PLAYBACK 0x0
+#define PLAYFLAG_ENCODING 0x1
+#define PLAYFLAG_SEEKING 0x2
+
+// Wave Marker flags
+#define WAVE_VIS_DATA_ONLY -1 // set to WaveDataStruct.markerstart in OutputWrite() call have data only go to vis
+ // and not to output plugin
+// pause flags
+#define PAUSE_DISABLED 0 // Pause() call is to unpause playback
+#define PAUSE_ENABLED 1 // Pause() call is to pause playback
+
+//-----------------------------------------------------------------------------
+// Input Module
+//-----------------------------------------------------------------------------
+typedef struct
+{
+ unsigned int size; // size of init structure
+ unsigned int version; // plugin structure version (set to PLUGIN_API_VERSION)
+ PluginServiceFunc Service; // player supplied services callback
+
+ struct
+ {
+ void (*PositionUpdate)(unsigned int position);
+ void (*PlayStopped)(const char* medianame); // notify player of play stop
+ void (*PlayStarted)(const char* medianame); // notify player of play start
+ void (*PlayPaused)(const char* medianame, int flags); // notify player of play pause
+ void (*PlayDone)(const char* medianame); // notify player when play done
+ void (*PlayTrackChanged)(const char* medianame); // notify player when playing track changes (cd audio relevant only)
+ void (*MediaEjected)(const char* medianame); // notify player of media eject (cd audio relevant)
+ void (*MediaInserted)(const char* medianame, int flags); // notify player of media insert (cd audio relevant)
+
+ // output plugin calls
+ int (*OutputOpen)(const char* medianame, WAVEFORMATEX*); // open output for wave data
+ int (*OutputWrite)(WriteDataStruct*); // send PCM audio data to output
+ // (blocks until write completes, thus if output is paused can
+ // block until unpaused)
+ int (*OutputDrain)(int flags); // wait for all output to complete (blocking)
+ int (*OutputDrainCancel)(int flags); // break a drain in progress
+ int (*OutputFlush)(unsigned int marker); // flush output upto marker
+ int (*OutputStop)(int flags); // stop output
+ int (*OutputPause)(int flags); // pause output
+
+ int (*OutputSetVol)(int levelleft, int levelright, int flags);
+ int (*OutputGetCurrentPosition)(unsigned int *position, int flags);
+
+ void *Reserved[10];
+ } toPlayer;
+
+ struct
+ {
+ int (*Initialize)(QCDModInfo *modInfo, int flags); // initialize plugin
+ void (*ShutDown)(int flags); // shutdown plugin
+
+ int (*Play)(const char* medianame, int playfrom, int playto, int flags); // start playing playfrom->playto
+ int (*Stop)(const char* medianame, int flags); // stop playing
+ int (*Pause)(const char* medianame, int flags); // pause playback
+ int (*Eject)(const char* medianame, int flags); // eject media
+ void (*SetEQ)(EQInfo*); // update EQ settings
+
+ int (*GetMediaSupported)(const char* medianame, MediaInfo *mediaInfo); // does plugin support medianame (and provides info for media)
+ int (*GetTrackExtents)(const char* medianame, TrackExtents *ext, int flags); // get media start, end & units
+ int (*GetCurrentPosition)(const char* medianame, long *track, long *offset); // get playing media's position
+
+ void (*Configure)(int flags); // launch configuration
+ void (*About)(int flags); // launch about info
+
+ void (*SetVolume)(int levelleft, int levelright, int flags); // level 0 - 100
+
+ void *Reserved[10];
+ } toModule;
+
+} QCDModInitIn;
+
+#endif //QCDMODINPUT_H
diff --git a/faad2/src/plugins/QCDMp4/QCDModTagEditor.h b/faad2/src/plugins/QCDMp4/QCDModTagEditor.h
new file mode 100644
index 0000000..13555f3
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDModTagEditor.h
@@ -0,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
diff --git a/faad2/src/plugins/QCDMp4/QCDMp4.c b/faad2/src/plugins/QCDMp4/QCDMp4.c
new file mode 100644
index 0000000..0709629
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDMp4.c
@@ -0,0 +1,2992 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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.4 2003/12/06 04:24:17 rjamorim Exp $
+**/
+
+//#define DEBUG_OUTPUT
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <stdlib.h>
+#include <math.h>
+#include <faad.h>
+#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,
+ THREAD_PRIORITY_ABOVE_NORMAL,
+ THREAD_PRIORITY_NORMAL,
+ THREAD_PRIORITY_BELOW_NORMAL,
+ THREAD_PRIORITY_LOWEST
+};
+static int res_id_table[] = {
+ IDC_16BITS,
+ IDC_24BITS,
+ IDC_32BITS,
+ 0,
+ 0,
+ /*IDC_16BITS_DITHERED*/ IDC_16BITS /* temp hack */
+};
+static int res_table[] = {
+ 16,
+ 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 */
+ faacDecHandle hDecoder;
+ int samplerate;
+ unsigned char channels;
+ 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;
+ int mp4track;
+ MP4SampleId numSamples;
+ MP4SampleId sampleId;
+
+ /* AAC stuff */
+ FILE *aacfile;
+ 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;
+
+//static In_Module module; // the output module (declared near the bottom of this file)
+struct {
+ HINSTANCE hDllInstance;
+ 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
+
+
+//typedef struct tag
+//{
+// char *item;
+// char *value;
+//} tag;
+//
+//typedef struct medialib_tags
+//{
+// struct tag *tags;
+// unsigned int count;
+//} medialib_tags;
+//
+//int tag_add_field(medialib_tags *tags, const char *item, const char *value)
+//{
+// void *backup = (void *)tags->tags;
+//
+// if (!item || (item && !*item) || !value) return 0;
+//
+// tags->tags = (struct tag *)realloc(tags->tags, (tags->count+1) * sizeof(tag));
+// if (!tags->tags) {
+// if (backup) free(backup);
+// return 0;
+// }
+// else
+// {
+// int i_len = strlen(item);
+// int v_len = strlen(value);
+//
+// tags->tags[tags->count].item = (char *)malloc(i_len+1);
+// tags->tags[tags->count].value = (char *)malloc(v_len+1);
+//
+// if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
+// {
+// if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
+// if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
+// tags->tags[tags->count].item = NULL;
+// tags->tags[tags->count].value = NULL;
+// return 0;
+// }
+//
+// memcpy(tags->tags[tags->count].item, item, i_len);
+// memcpy(tags->tags[tags->count].value, value, v_len);
+// tags->tags[tags->count].item[i_len] = '\0';
+// tags->tags[tags->count].value[v_len] = '\0';
+//
+// tags->count++;
+// return 1;
+// }
+//}
+//
+//int tag_set_field(medialib_tags *tags, const char *item, const char *value)
+//{
+// unsigned int i;
+//
+// if (!item || (item && !*item) || !value) return 0;
+//
+// for (i = 0; i < tags->count; i++)
+// {
+// if (!stricmp(tags->tags[i].item, item))
+// {
+// void *backup = (void *)tags->tags[i].value;
+// int v_len = strlen(value);
+//
+// tags->tags[i].value = (char *)realloc(tags->tags[i].value, v_len+1);
+// if (!tags->tags[i].value)
+// {
+// if (backup) free(backup);
+// return 0;
+// }
+//
+// memcpy(tags->tags[i].value, value, v_len);
+// tags->tags[i].value[v_len] = '\0';
+//
+// return 1;
+// }
+// }
+//
+// return tag_add_field(tags, item, value);
+//}
+//
+//int tag_delete(medialib_tags *tags)
+//{
+// unsigned int i;
+//
+// for (i = 0; i < tags->count; i++)
+// {
+// if (tags->tags[i].item) free(tags->tags[i].item);
+// if (tags->tags[i].value) free(tags->tags[i].value);
+// }
+//
+// if (tags->tags) free(tags->tags);
+//
+// tags->tags = NULL;
+// tags->count = 0;
+//}
+//
+//int ReadMP4Tag(MP4FileHandle file, medialib_tags *tags)
+//{
+// unsigned __int32 valueSize;
+// unsigned __int8 *pValue;
+// char *pName;
+// unsigned int i = 0;
+//
+// do {
+// pName = 0;
+// pValue = 0;
+// valueSize = 0;
+//
+// MP4GetMetadataByIndex(file, i, (const char **)&pName, &pValue, &valueSize);
+//
+// if (valueSize > 0)
+// {
+// char *val = (char *)malloc(valueSize+1);
+// if (!val) return 0;
+// memcpy(val, pValue, valueSize);
+// val[valueSize] = '\0';
+//
+// if (pName[0] == '\xa9')
+// {
+// if (memcmp(pName, "©nam", 4) == 0)
+// {
+// tag_add_field(tags, "title", val);
+// } else if (memcmp(pName, "©ART", 4) == 0) {
+// tag_add_field(tags, "artist", val);
+// } else if (memcmp(pName, "©wrt", 4) == 0) {
+// tag_add_field(tags, "writer", val);
+// } else if (memcmp(pName, "©alb", 4) == 0) {
+// tag_add_field(tags, "album", val);
+// } else if (memcmp(pName, "©day", 4) == 0) {
+// tag_add_field(tags, "date", val);
+// } else if (memcmp(pName, "©too", 4) == 0) {
+// tag_add_field(tags, "tool", val);
+// } else if (memcmp(pName, "©cmt", 4) == 0) {
+// tag_add_field(tags, "comment", val);
+// } else if (memcmp(pName, "©gen", 4) == 0) {
+// tag_add_field(tags, "genre", val);
+// } else {
+// tag_add_field(tags, pName, val);
+// }
+// } else if (memcmp(pName, "gnre", 4) == 0) {
+// char *t=0;
+// if (MP4GetMetadataGenre(file, &t))
+// {
+// tag_add_field(tags, "genre", t);
+// }
+// } else if (memcmp(pName, "trkn", 4) == 0) {
+// unsigned __int16 trkn = 0, tot = 0;
+// char t[200];
+// if (MP4GetMetadataTrack(file, &trkn, &tot))
+// {
+// if (tot > 0)
+// wsprintf(t, "%d/%d", trkn, tot);
+// else
+// wsprintf(t, "%d", trkn);
+// tag_add_field(tags, "tracknumber", t);
+// }
+// } else if (memcmp(pName, "disk", 4) == 0) {
+// unsigned __int16 disk = 0, tot = 0;
+// char t[200];
+// if (MP4GetMetadataDisk(file, &disk, &tot))
+// {
+// if (tot > 0)
+// wsprintf(t, "%d/%d", disk, tot);
+// else
+// wsprintf(t, "%d", disk);
+// tag_add_field(tags, "disc", t);
+// }
+// } else if (memcmp(pName, "cpil", 4) == 0) {
+// unsigned __int8 cpil = 0;
+// char t[200];
+// if (MP4GetMetadataCompilation(file, &cpil))
+// {
+// wsprintf(t, "%d", cpil);
+// tag_add_field(tags, "compilation", t);
+// }
+// } else if (memcmp(pName, "tmpo", 4) == 0) {
+// unsigned __int16 tempo = 0;
+// char t[200];
+// if (MP4GetMetadataTempo(file, &tempo))
+// {
+// wsprintf(t, "%d BPM", tempo);
+// tag_add_field(tags, "tempo", t);
+// }
+// } else if (memcmp(pName, "NDFL", 4) == 0) {
+// /* Removed */
+// } else {
+// tag_add_field(tags, pName, val);
+// }
+//
+// free(val);
+// }
+//
+// i++;
+// } while (valueSize > 0);
+//
+// return 1;
+//}
+//
+//int mp4_set_metadata(MP4FileHandle file, const char *item, const char *val)
+//{
+// if (!item || (item && !*item) || !val || (val && !*val)) return 0;
+//
+// if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
+// {
+// unsigned __int16 trkn, tot;
+// int t1 = 0, t2 = 0;
+// sscanf(val, "%d/%d", &t1, &t2);
+// trkn = t1, tot = t2;
+// if (!trkn) return 1;
+// if (MP4SetMetadataTrack(file, trkn, tot)) return 1;
+// }
+// else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
+// {
+// unsigned __int16 disk, tot;
+// int t1 = 0, t2 = 0;
+// sscanf(val, "%d/%d", &t1, &t2);
+// disk = t1, tot = t2;
+// if (!disk) return 1;
+// if (MP4SetMetadataDisk(file, disk, tot)) return 1;
+// }
+// else if (!stricmp(item, "compilation"))
+// {
+// unsigned __int8 cpil = atoi(val);
+// if (!cpil) return 1;
+// if (MP4SetMetadataCompilation(file, cpil)) return 1;
+// }
+// else if (!stricmp(item, "tempo"))
+// {
+// unsigned __int16 tempo = atoi(val);
+// if (!tempo) return 1;
+// if (MP4SetMetadataTempo(file, tempo)) return 1;
+// }
+// else if (!stricmp(item, "artist"))
+// {
+// if (MP4SetMetadataArtist(file, val)) return 1;
+// }
+// else if (!stricmp(item, "writer"))
+// {
+// if (MP4SetMetadataWriter(file, val)) return 1;
+// }
+// else if (!stricmp(item, "title"))
+// {
+// if (MP4SetMetadataName(file, val)) return 1;
+// }
+// else if (!stricmp(item, "album"))
+// {
+// if (MP4SetMetadataAlbum(file, val)) return 1;
+// }
+// else if (!stricmp(item, "date") || !stricmp(item, "year"))
+// {
+// if (MP4SetMetadataYear(file, val)) return 1;
+// }
+// else if (!stricmp(item, "comment"))
+// {
+// if (MP4SetMetadataComment(file, val)) return 1;
+// }
+// else if (!stricmp(item, "genre"))
+// {
+// if (MP4SetMetadataGenre(file, val)) return 1;
+// }
+// else if (!stricmp(item, "tool"))
+// {
+// if (MP4SetMetadataTool(file, val)) return 1;
+// }
+// else
+// {
+// if (MP4SetMetadataFreeForm(file, (char *)item, (u_int8_t *)val, (u_int32_t)strlen(val))) return 1;
+// }
+//
+// return 0;
+//}
+//
+//int WriteMP4Tag(MP4FileHandle file, const medialib_tags *tags)
+//{
+// unsigned int i;
+//
+// for (i = 0; i < tags->count; i++)
+// {
+// const char *item = tags->tags[i].item;
+// const char *value = tags->tags[i].value;
+//
+// if (value && *value)
+// {
+// mp4_set_metadata(file, item, value);
+// }
+// }
+//}
+
+
+#ifdef DEBUG_OUTPUT
+void in_mp4_DebugOutput(char *message)
+{
+ char s[1024];
+
+ 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)
+ 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];
+ 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(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()
+{
+ char priority[10];
+ 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(downmix);
+ WS(vbr_display);
+ //WS(titleformat);
+}
+
+int Initialize(QCDModInfo *ModInfo, int flags)
+{
+ ModInfo->moduleString = "MP4 Plug-in v" FAAD2_VERSION;
+
+ module.hMainWindow = (HWND)module.QCDCallbacks.Service(opGetParentWnd, 0, 0, 0);
+
+ // read config from config file
+ config_read();
+
+ ModInfo->moduleExtensions = !m_use_for_aac ? "MP4:M4A" : "MP4:M4A:AAC";
+
+ // return TRUE for successful initialization
+ return 1;
+}
+
+//----------------------------------------------------------------------------
+
+void ShutDown(int flags)
+{
+ Stop(mp4state.filename, STOPFLAG_FORCESTOP);
+}
+
+///* 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;
+// if (!*str) return TRUE;
+// 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 || !max) return 0;
+// *str = '\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;
+// char temp[1024];
+// struct medialib_tags tags;
+// tags.count = 0;
+// tags.tags = NULL;
+//
+//#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;
+// if (MP4GetMetadataName(file, &pVal))
+// uSetDlgItemText(hwndDlg,IDC_METANAME, pVal);
+//
+// pVal = NULL;
+// if (MP4GetMetadataArtist(file, &pVal))
+// uSetDlgItemText(hwndDlg,IDC_METAARTIST, pVal);
+//
+// pVal = NULL;
+// if (MP4GetMetadataWriter(file, &pVal))
+// uSetDlgItemText(hwndDlg,IDC_METAWRITER, pVal);
+//
+// pVal = NULL;
+// if (MP4GetMetadataComment(file, &pVal))
+// uSetDlgItemText(hwndDlg,IDC_METACOMMENTS, pVal);
+//
+// pVal = NULL;
+// if (MP4GetMetadataAlbum(file, &pVal))
+// uSetDlgItemText(hwndDlg,IDC_METAALBUM, pVal);
+//
+// pVal = NULL;
+// if (MP4GetMetadataGenre(file, &pVal))
+// uSetDlgItemText(hwndDlg,IDC_METAGENRE, pVal);
+//
+// dummy = 0;
+// MP4GetMetadataTempo(file, &dummy);
+// if (dummy)
+// {
+// wsprintf(dummy1, "%d", dummy);
+// SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
+// }
+//
+// dummy = 0; dummy2 = 0;
+// MP4GetMetadataTrack(file, &dummy, &dummy2);
+// if (dummy)
+// {
+// wsprintf(dummy1, "%d", dummy);
+// SetDlgItemText(hwndDlg,IDC_METATRACK1, dummy1);
+// }
+// if (dummy2)
+// {
+// wsprintf(dummy1, "%d", dummy2);
+// SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
+// }
+//
+// dummy = 0; dummy2 = 0;
+// MP4GetMetadataDisk(file, &dummy, &dummy2);
+// if (dummy)
+// {
+// wsprintf(dummy1, "%d", dummy);
+// SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
+// }
+// if (dummy2)
+// {
+// wsprintf(dummy1, "%d", dummy2);
+// SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
+// }
+//
+// pVal = NULL;
+// if (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 */
+//
+// tag_delete(&tags);
+// file = MP4Read(info_fn, 0);
+// if (file != MP4_INVALID_FILE_HANDLE)
+// {
+// ReadMP4Tag(file, &tags);
+// MP4Close(file);
+//
+// file = MP4Modify(info_fn, 0, 0);
+// if (file != MP4_INVALID_FILE_HANDLE)
+// {
+// MP4MetadataDelete(file);
+// MP4Close(file);
+// }
+// }
+//
+// file = MP4Modify(info_fn, 0, 0);
+// if (file == MP4_INVALID_FILE_HANDLE)
+// {
+// tag_delete(&tags);
+// EndDialog(hwndDlg, wParam);
+// return FALSE;
+// }
+//
+// uGetDlgItemText(hwndDlg, IDC_METANAME, dummy1, 1024);
+// tag_set_field(&tags, "title", dummy1);
+//
+// uGetDlgItemText(hwndDlg, IDC_METAWRITER, dummy1, 1024);
+// tag_set_field(&tags, "writer", dummy1);
+//
+// uGetDlgItemText(hwndDlg, IDC_METAARTIST, dummy1, 1024);
+// tag_set_field(&tags, "artist", dummy1);
+//
+// uGetDlgItemText(hwndDlg, IDC_METAALBUM, dummy1, 1024);
+// tag_set_field(&tags, "album", dummy1);
+//
+// uGetDlgItemText(hwndDlg, IDC_METACOMMENTS, dummy1, 1024);
+// tag_set_field(&tags, "comment", dummy1);
+//
+// uGetDlgItemText(hwndDlg, IDC_METAGENRE, dummy1, 1024);
+// tag_set_field(&tags, "genre", dummy1);
+//
+// uGetDlgItemText(hwndDlg, IDC_METAYEAR, dummy1, 1024);
+// tag_set_field(&tags, "year", dummy1);
+//
+// GetDlgItemText(hwndDlg, IDC_METATRACK1, dummy1, 1024);
+// dummy = atoi(dummy1);
+// GetDlgItemText(hwndDlg, IDC_METATRACK2, dummy1, 1024);
+// dummy2 = atoi(dummy1);
+// wsprintf(temp, "%d/%d", dummy, dummy2);
+// tag_set_field(&tags, "track", temp);
+//
+// GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
+// dummy = atoi(dummy1);
+// GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
+// dummy2 = atoi(dummy1);
+// wsprintf(temp, "%d/%d", dummy, dummy2);
+// tag_set_field(&tags, "disc", temp);
+//
+// GetDlgItemText(hwndDlg, IDC_METATEMPO, dummy1, 1024);
+// tag_set_field(&tags, "tempo", dummy1);
+//
+// dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
+// tag_set_field(&tags, "compilation", (dummy3 ? "1" : "0"));
+//
+// WriteMP4Tag(file, &tags);
+//
+// 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';
+// }
+//}
+
+BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message,
+ WPARAM wParam, LPARAM lParam)
+{
+ int i;
+
+ switch (message) {
+ case WM_INITDIALOG:
+ SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETRANGE, TRUE, MAKELONG(1,5));
+ SendMessage(GetDlgItem(hwndDlg, IDC_PRIORITY), TBM_SETPOS, TRUE, m_priority);
+ SendMessage(GetDlgItem(hwndDlg, res_id_table[m_resolution]), BM_SETCHECK, BST_CHECKED, 0);
+ if (m_show_errors)
+ SendMessage(GetDlgItem(hwndDlg, IDC_ERROR), BM_SETCHECK, BST_CHECKED, 0);
+ 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)) {
+ 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 < 6; i++)
+ {
+ if (SendMessage(GetDlgItem(hwndDlg, res_id_table[i]), BM_GETCHECK, 0, 0))
+ {
+ m_resolution = i;
+ break;
+ }
+ }
+
+ /* save config */
+ config_write();
+
+ //if (!m_use_for_aac)
+ //{
+ // module.FileExtensions = short_ext_list;
+ //} else {
+ // module.FileExtensions = long_ext_list;
+ //}
+
+ EndDialog(hwndDlg, wParam);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void Configure(int flags)
+{
+ DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG),
+ module.hMainWindow, config_dialog_proc);
+}
+
+//-----------------------------------------------------------------------------
+
+void About(int flags)
+{
+ 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);
+}
+
+//-----------------------------------------------------------------------------
+
+int fill_buffer(state *st)
+{
+ int bread;
+
+ 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 advance_buffer(state *st, int bytes)
+{
+ 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;
+
+ /* 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()
+{
+ unsigned char buf[10];
+ int bread, tagsize = 0;
+
+ 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 (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;
+ }
+
+ 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)
+ {
+ // Update the player controls to reflect the new unpaused state
+ module.QCDCallbacks.toPlayer.OutputPause(0);
+
+ Pause(medianame, 0);
+
+ if (playfrom >= 0)
+ mp4state.seek_needed = playfrom;
+ }
+ else if (PlayThreadAlive) // is playing
+ {
+ mp4state.seek_needed = playfrom;
+ return 1;
+ }
+ else
+ {
+ memset(&mp4state, 0, sizeof(state));
+
+ lstrcpy(mp4state.filename, medianame);
+
+ 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;
+
+ //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 1;
+}
+
+//-----------------------------------------------------------------------------
+
+int Pause(const char* medianame, int flags)
+{
+#ifdef DEBUG_OUTPUT
+ in_mp4_DebugOutput("pause");
+#endif
+
+ mp4state.paused = 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;
+//}
+
+//-----------------------------------------------------------------------------
+
+void SetVolume(int levelleft, int levelright, int flags)
+{
+#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");
+#endif
+
+ if (medianame && *medianame && stricmp(mp4state.filename, medianame) == 0)
+ {
+ module.QCDCallbacks.toPlayer.OutputStop(flags);
+ killPlayThread = 1;
+
+ if (play_thread_handle != INVALID_HANDLE_VALUE)
+ {
+ if (WaitForSingleObject(play_thread_handle, INFINITE) == WAIT_TIMEOUT)
+ TerminateThread(play_thread_handle,0);
+ CloseHandle(play_thread_handle);
+ play_thread_handle = INVALID_HANDLE_VALUE;
+ }
+
+
+ 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 1;
+}
+
+int getsonglength(const 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)
+{
+ int done = 0, updatepos = 0;
+ int l;
+ int seq_frames = 0;
+ int seq_bytes = 0;
+
+ void *sample_buffer;
+ unsigned char *buffer;
+ 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 (mp4state.seek_needed != -1)
+ {
+ MP4Duration duration;
+
+ 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,
+ mp4state.mp4track, duration, 0);
+
+ mp4state.decode_pos_ms = mp4state.seek_needed;
+ mp4state.seek_needed = -1;
+ updatepos = 1;
+ }
+
+ if (done)
+ {
+ if (module.QCDCallbacks.toPlayer.OutputDrain(0) && !(mp4state.seek_needed >= 0))
+ {
+ module.QCDCallbacks.toPlayer.OutputStop(STOPFLAG_PLAYDONE);
+ module.QCDCallbacks.toPlayer.PlayDone(mp4state.filename);
+ PlayThreadAlive = 0;
+ }
+ else if (mp4state.seek_needed >= 0)
+ {
+ done = 0;
+ continue;
+ }
+ break;
+ } else/* if (module.outMod->CanWrite() >= (2048*mp4state.channels*sizeof(short)))*/ {
+
+ if (mp4state.last_frame)
+ {
+ 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;
+
+ rc = MP4ReadSample(mp4state.mp4file, mp4state.mp4track,
+ mp4state.sampleId++, &buffer, &buffer_size,
+ 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 {
+ sample_buffer = faacDecDecode(mp4state.hDecoder, &frameInfo,
+ buffer, buffer_size);
+ }
+ if (frameInfo.error > 0)
+ {
+ show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
+ mp4state.last_frame = 1;
+ }
+ if (mp4state.sampleId > mp4state.numSamples)
+ mp4state.last_frame = 1;
+
+ if (buffer) free(buffer);
+
+ 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(buf, sample_count);
+ memcpy((void*)buf, (void*)temp_buffer, sample_count*3);
+ free(temp_buffer);
+ }
+
+ //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 = sample_count * res_table[m_resolution] / 8;
+
+ if (updatepos)
+ {
+ module.QCDCallbacks.toPlayer.PositionUpdate((unsigned int)mp4state.decode_pos_ms);
+ updatepos = 0;
+ }
+
+ 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 (!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);
+ }
+
+ PlayThreadAlive = 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)
+{
+ int done = 0, updatepos = 0;
+ int l;
+ int seq_frames = 0;
+ int seq_bytes = 0;
+
+ WriteDataStruct wd;
+
+#ifdef DEBUG_OUTPUT
+ in_mp4_DebugOutput("AACPlayThread");
+#endif
+
+ PlayThreadAlive = 1;
+ mp4state.last_frame = 0;
+
+ while (!*((int *)b))
+ {
+ /* seeking */
+ if (mp4state.seek_needed != -1)
+ {
+ double 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 = 1;
+ }
+
+ if (done)
+ {
+ if (module.QCDCallbacks.toPlayer.OutputDrain(0) && !(mp4state.seek_needed >= 0))
+ {
+ module.QCDCallbacks.toPlayer.OutputStop(STOPFLAG_PLAYDONE);
+ module.QCDCallbacks.toPlayer.PlayDone(mp4state.filename);
+ PlayThreadAlive = 0;
+ }
+ else if (mp4state.seek_needed >= 0)
+ {
+ done = 0;
+ continue;
+ }
+ break;
+ } else/* if (module.outMod->CanWrite() >= (2048*mp4state.channels*sizeof(short)))*/ {
+ faacDecFrameInfo frameInfo;
+ void *sample_buffer;
+
+ memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
+
+ sample_buffer = decode_aac_frame(&mp4state, &frameInfo);
+
+ 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]);
+
+ if (res_table[m_resolution] == 24)
+ {
+ /* convert libfaad output (3 bytes packed in 4 bytes) */
+ char *temp_buffer = convert3in4to3in3(sample_buffer, frameInfo.samples);
+ memcpy((void*)sample_buffer, (void*)temp_buffer, frameInfo.samples*3);
+ free(temp_buffer);
+ }
+
+ //module.SAAddPCMData(sample_buffer, (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);
+
+ l = frameInfo.samples * res_table[m_resolution] / 8;
+
+ if (updatepos)
+ {
+ module.QCDCallbacks.toPlayer.PositionUpdate((unsigned int)mp4state.decode_pos_ms);
+ updatepos = 0;
+ }
+
+ 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;
+
+ if (!module.QCDCallbacks.toPlayer.OutputWrite(&wd))
+ done = 1;
+
+ //if (module.dsp_isactive())
+ //{
+ // void *dsp_buffer = malloc(l*2);
+ // memcpy(dsp_buffer, sample_buffer, l);
+
+ // 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));
+
+ // module.outMod->Write(dsp_buffer, l);
+ // if (dsp_buffer) free(dsp_buffer);
+ //} else {
+ // module.outMod->Write(sample_buffer, l);
+ //}
+
+ /* 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);
+ }
+
+ PlayThreadAlive = 0;
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+int WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID pRes)
+{
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ {
+ module.hDllInstance = hInst;
+ }
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+
+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;
+}
+
+///* new Media Library interface */
+//
+//int mp4_get_metadata(MP4FileHandle file, const char *item, char *dest, int dlen)
+//{
+// char *pVal = NULL, dummy1[4096];
+// short dummy = 0, dummy2 = 0;
+//
+// if (dlen < 1) return 0;
+//
+// if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
+// {
+// if (MP4GetMetadataTrack(file, &dummy, &dummy2))
+// {
+// wsprintf(dummy1, "%d", (int)dummy);
+// strncpy(dest, dummy1, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
+// {
+// if (MP4GetMetadataDisk(file, &dummy, &dummy2))
+// {
+// wsprintf(dummy1, "%d", (int)dummy);
+// strncpy(dest, dummy1, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "compilation"))
+// {
+// u_int8_t cpil = 0;
+// if (MP4GetMetadataCompilation(file, &cpil))
+// {
+// wsprintf(dummy1, "%d", (int)cpil);
+// strncpy(dest, dummy1, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "tempo"))
+// {
+// u_int16_t tempo = 0;
+// if (MP4GetMetadataTempo(file, &tempo))
+// {
+// wsprintf(dummy1, "%d", (int)tempo);
+// strncpy(dest, dummy1, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "artist"))
+// {
+// if (MP4GetMetadataArtist(file, &pVal))
+// {
+// strncpy(dest, pVal, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "writer"))
+// {
+// if (MP4GetMetadataWriter(file, &pVal))
+// {
+// strncpy(dest, pVal, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "title"))
+// {
+// if (MP4GetMetadataName(file, &pVal))
+// {
+// strncpy(dest, pVal, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "album"))
+// {
+// if (MP4GetMetadataAlbum(file, &pVal))
+// {
+// strncpy(dest, pVal, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "date") || !stricmp(item, "year"))
+// {
+// if (MP4GetMetadataYear(file, &pVal))
+// {
+// strncpy(dest, pVal, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "comment"))
+// {
+// if (MP4GetMetadataComment(file, &pVal))
+// {
+// strncpy(dest, pVal, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "genre"))
+// {
+// if (MP4GetMetadataGenre(file, &pVal))
+// {
+// strncpy(dest, pVal, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else if (!stricmp(item, "tool"))
+// {
+// if (MP4GetMetadataTool(file, &pVal))
+// {
+// strncpy(dest, pVal, dlen-1);
+// dest[dlen-1] = '\0';
+// return 1;
+// }
+// }
+// else
+// {
+// u_int32_t valueSize = 0;
+// u_int8_t *pValue = NULL;
+//
+// if (MP4GetMetadataFreeForm(file, (char *)item, &pValue, &valueSize))
+// {
+// unsigned int len = (valueSize < (unsigned int)(dlen-1)) ? valueSize : (unsigned int)(dlen-1);
+// memcpy(dest, pValue, len);
+// dest[len] = '\0';
+// return 1;
+// }
+// }
+//
+// return 0;
+//}
+//
+//__declspec(dllexport) int winampGetExtendedFileInfo(const char *fn, const char *data, char *dest, int destlen)
+//{
+// if (!fn || (fn && !*fn) || !destlen) return 0;
+//
+// dest[0] = '\0';
+//
+// if (!stricmp(data, "length"))
+// {
+// char temp[32];
+// int len = getsonglength(fn);
+// itoa(len, temp, 10);
+// strncpy(dest, temp, destlen-1);
+// dest[destlen-1] = '\0';
+// }
+// else
+// {
+// char temp[2048], temp2[2048];
+// MP4FileHandle file = MP4Read(fn, 0);
+// if (file == MP4_INVALID_FILE_HANDLE) return 0;
+//
+// if (mp4_get_metadata(file, data, temp, sizeof(temp)))
+// {
+// int len = ConvertUTF8ToANSI(temp, temp2);
+// if (len > destlen-1) len = destlen-1;
+// memcpy(dest, temp2, len);
+// dest[len] = '\0';
+// }
+//
+// MP4Close(file);
+// }
+//
+// return 1;
+//}
+//
+//static struct medialib_tags mltags = {0, 0};
+//static BOOL medialib_init = FALSE;
+//static char medialib_lastfn[2048] = "";
+//
+//__declspec(dllexport) int winampSetExtendedFileInfo(const char *fn, const char *data, char *val)
+//{
+// int len, ret = 0;
+// char *temp;
+//
+// if (!medialib_init || (medialib_init && stricmp(fn, medialib_lastfn))) {
+// MP4FileHandle file;
+// strcpy(medialib_lastfn, fn);
+//
+// if (medialib_init) tag_delete(&mltags);
+//
+// file = MP4Read(fn, 0);
+// if (file == MP4_INVALID_FILE_HANDLE) return 0;
+// ReadMP4Tag(file, &mltags);
+// MP4Close(file);
+// medialib_init = TRUE;
+// }
+//
+// len = strlen(val);
+// temp = (char *)malloc((len+1)*4);
+// if (!temp) return 0;
+//
+// if (ConvertANSIToUTF8(val, temp))
+// {
+// ret = 1;
+// tag_set_field(&mltags, data, temp);
+// }
+//
+// free(temp);
+//
+// return ret;
+//}
+//
+//__declspec(dllexport) int winampWriteExtendedFileInfo()
+//{
+// if (medialib_init)
+// {
+// MP4FileHandle file = MP4Modify(medialib_lastfn, 0, 0);
+// if (file == MP4_INVALID_FILE_HANDLE) return 0;
+//
+// MP4MetadataDelete(file);
+// MP4Close(file);
+//
+// file = MP4Modify(medialib_lastfn, 0, 0);
+// if (file == MP4_INVALID_FILE_HANDLE) return 0;
+//
+// WriteMP4Tag(file, &mltags);
+//
+// MP4Close(file);
+//
+// return 1;
+// }
+// else
+// {
+// return 0;
+// }
+//}
diff --git a/faad2/src/plugins/QCDMp4/QCDMp4.rc b/faad2/src/plugins/QCDMp4/QCDMp4.rc
new file mode 100644
index 0000000..1ed6198
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDMp4.rc
@@ -0,0 +1,191 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// ÖÐÎÄ(ÖлªÈËÃñ¹²ºÍ¹ú) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
+#ifdef _WIN32
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+#pragma code_page(936)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONFIG DIALOGEX 0, 0, 242, 93
+STYLE DS_SETFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Configuration"
+FONT 9, "ËÎÌå", 400, 0, 0x86
+BEGIN
+ CONTROL "Slider1",IDC_PRIORITY,"msctls_trackbar32",TBS_VERT |
+ TBS_NOTICKS | WS_TABSTOP,13,15,18,46
+ CONTROL "16 λ",IDC_16BITS,"Button",BS_AUTORADIOBUTTON,77,18,37,
+ 10
+ CONTROL "16 λ¸ßƵ¶¶¶¯",IDC_16BITS_DITHERED,"Button",
+ BS_AUTORADIOBUTTON | WS_DISABLED,77,29,64,10
+ CONTROL "24 λ",IDC_24BITS,"Button",BS_AUTORADIOBUTTON,77,40,37,
+ 10
+ CONTROL "32 λ",IDC_32BITS,"Button",BS_AUTORADIOBUTTON,77,51,37,
+ 10
+ CONTROL "ÏòÏ»ìƵµ½Á¢ÌåÉù",IDC_DOWNMIX,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,152,13,80,10
+ CONTROL "Ö§³Ö AAC ¸ñʽ",IDC_USEFORAAC,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,152,26,68,10
+ CONTROL "ÏÔʾ¿É±ä±ÈÌØÂÊ",IDC_VBR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,152,39,72,10
+ CONTROL "ÏÔʾ´íÎóÐÅÏ¢",IDC_ERROR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,152,52,64,10
+ DEFPUSHBUTTON "È·¶¨",IDOK,185,72,50,14
+ PUSHBUTTON "È¡Ïû",IDCANCEL,127,72,50,14
+ GROUPBOX "ÓÅÏȼ¶",IDC_STATIC,7,7,57,58
+ LTEXT "¸ß",IDC_STATIC,34,18,25,8
+ LTEXT "±ê×¼",IDC_STATIC,34,35,23,8
+ LTEXT "µÍ",IDC_STATIC,34,52,24,8
+ GROUPBOX "½âÎö¶È",IDC_STATIC,71,7,73,58
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_CONFIG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 235
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 86
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // ÖÐÎÄ(ÖлªÈËÃñ¹²ºÍ¹ú) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// ºÉÀ¼Óï(ºÉÀ¼) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NLD)
+#ifdef _WIN32
+LANGUAGE LANG_DUTCH, SUBLANG_DUTCH
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+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", 0, 0, 0x0
+BEGIN
+ CONTROL "Slider1",IDC_PRIORITY,"msctls_trackbar32",TBS_VERT |
+ TBS_NOTICKS | WS_TABSTOP,13,15,18,46
+ CONTROL "16 bits",IDC_16BITS,"Button",BS_AUTORADIOBUTTON,77,18,
+ 37,10
+ CONTROL "16 bits dithered",IDC_16BITS_DITHERED,"Button",
+ 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 "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,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
+ LTEXT "Lowest",IDC_STATIC,34,52,24,8
+ GROUPBOX "Resolution",IDC_STATIC,71,7,73,58
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_CONFIG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 226
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 86
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // ºÉÀ¼Óï(ºÉÀ¼) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/faad2/src/plugins/QCDMp4/QCDMp4.sln b/faad2/src/plugins/QCDMp4/QCDMp4.sln
new file mode 100644
index 0000000..7167f45
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDMp4.sln
@@ -0,0 +1,35 @@
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+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}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfaad", "..\..\libfaad\libfaad.vcproj", "{BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmp4v2_st", "..\..\common\mp4v2\libmp4v2_st60.vcproj", "{2398BB2F-FFF9-490B-B4CC-863F2D21AE46}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmp4av_st", "..\..\common\mp4av\libmp4av_st.vcproj", "{8CAC9E26-BAA5-45A4-8721-E3170B3F8F49}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2D8F479D-A591-4502-9456-398425D5F834}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2D8F479D-A591-4502-9456-398425D5F834}.Debug|Win32.Build.0 = Debug|Win32
+ {2D8F479D-A591-4502-9456-398425D5F834}.Release|Win32.ActiveCfg = Release|Win32
+ {2D8F479D-A591-4502-9456-398425D5F834}.Release|Win32.Build.0 = Release|Win32
+ {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Release|Win32.ActiveCfg = Release|Win32
+ {2398BB2F-FFF9-490B-B4CC-863F2D21AE46}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2398BB2F-FFF9-490B-B4CC-863F2D21AE46}.Release|Win32.ActiveCfg = Release|Win32
+ {8CAC9E26-BAA5-45A4-8721-E3170B3F8F49}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8CAC9E26-BAA5-45A4-8721-E3170B3F8F49}.Release|Win32.ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/faad2/src/plugins/QCDMp4/QCDMp4.vcproj b/faad2/src/plugins/QCDMp4/QCDMp4.vcproj
new file mode 100644
index 0000000..2770362
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDMp4.vcproj
@@ -0,0 +1,285 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="QCDMp4"
+ ProjectGUID="{2D8F479D-A591-4502-9456-398425D5F834}"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/QCDMp4.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\include,..\..\common\mp4v2,..\..\common\mp4av"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderFile=".\Debug/QCDMp4.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1043"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ AdditionalDependencies="ws2_32.lib odbc32.lib odbccp32.lib"
+ OutputFile=".\Debug/QCDMp4.dll"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Debug/QCDMp4.pdb"
+ SubSystem="2"
+ ImportLibrary=".\Debug/QCDMp4.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/QCDMp4.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="1"
+ AdditionalIncludeDirectories="..\..\include,..\..\common\mp4v2,..\..\common\mp4av"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+ StringPooling="true"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderFile=".\Release/QCDMp4.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1043"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/MACHINE:I386"
+ AdditionalDependencies="ws2_32.lib"
+ OutputFile=".\Release/QCDMp4.dll"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ IgnoreDefaultLibraryNames=""
+ ProgramDatabaseFile=".\Release/QCDMp4.pdb"
+ SubSystem="2"
+ ImportLibrary=".\Release/QCDMp4.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+ >
+ <File
+ RelativePath=".\config.c"
+ >
+ </File>
+ <File
+ RelativePath=".\QCDMp4.c"
+ >
+ </File>
+ <File
+ RelativePath=".\QCDMp4Tag.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\utils.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl"
+ >
+ <File
+ RelativePath=".\config.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\faad.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QCDInputDLL.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QCDModDefs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\QCDModInput.h"
+ >
+ </File>
+ <File
+ 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=".\QCDMp4.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/faad2/src/plugins/QCDMp4/QCDMp4Tag.cpp b/faad2/src/plugins/QCDMp4/QCDMp4Tag.cpp
new file mode 100644
index 0000000..6fabbe1
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDMp4Tag.cpp
@@ -0,0 +1,839 @@
+#include <mp4.h>
+#include <faad.h>
+#include "QCDTagsDLL.h"
+
+
+//..............................................................................
+// Global Variables
+
+typedef struct tag
+{
+ char *item;
+ char *value;
+} tag;
+
+typedef struct medialib_tags
+{
+ struct tag *tags;
+ unsigned int count;
+} medialib_tags;
+
+int tag_add_field(medialib_tags *tags, const char *item, const char *value)
+{
+ void *backup = (void *)tags->tags;
+
+ if (!item || (item && !*item) || !value) return 0;
+
+ tags->tags = (struct tag *)realloc(tags->tags, (tags->count+1) * sizeof(tag));
+ if (!tags->tags) {
+ if (backup) free(backup);
+ return 0;
+ }
+ else
+ {
+ int i_len = strlen(item);
+ int v_len = strlen(value);
+
+ tags->tags[tags->count].item = (char *)malloc(i_len+1);
+ tags->tags[tags->count].value = (char *)malloc(v_len+1);
+
+ if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
+ {
+ if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
+ if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
+ tags->tags[tags->count].item = NULL;
+ tags->tags[tags->count].value = NULL;
+ return 0;
+ }
+
+ memcpy(tags->tags[tags->count].item, item, i_len);
+ memcpy(tags->tags[tags->count].value, value, v_len);
+ tags->tags[tags->count].item[i_len] = '\0';
+ tags->tags[tags->count].value[v_len] = '\0';
+
+ tags->count++;
+ return 1;
+ }
+}
+
+int tag_set_field(medialib_tags *tags, const char *item, const char *value)
+{
+ unsigned int i;
+
+ if (!item || (item && !*item) || !value) return 0;
+
+ for (i = 0; i < tags->count; i++)
+ {
+ if (!stricmp(tags->tags[i].item, item))
+ {
+ void *backup = (void *)tags->tags[i].value;
+ int v_len = strlen(value);
+
+ tags->tags[i].value = (char *)realloc(tags->tags[i].value, v_len+1);
+ if (!tags->tags[i].value)
+ {
+ if (backup) free(backup);
+ return 0;
+ }
+
+ memcpy(tags->tags[i].value, value, v_len);
+ tags->tags[i].value[v_len] = '\0';
+
+ return 1;
+ }
+ }
+
+ return tag_add_field(tags, item, value);
+}
+
+void tag_delete(medialib_tags *tags)
+{
+ unsigned int i;
+
+ for (i = 0; i < tags->count; i++)
+ {
+ if (tags->tags[i].item) free(tags->tags[i].item);
+ if (tags->tags[i].value) free(tags->tags[i].value);
+ }
+
+ if (tags->tags) free(tags->tags);
+
+ tags->tags = NULL;
+ tags->count = 0;
+}
+
+int ReadMP4Tag(MP4FileHandle file, medialib_tags *tags)
+{
+ unsigned __int32 valueSize;
+ unsigned __int8 *pValue;
+ char *pName;
+ unsigned int i = 0;
+
+ do {
+ pName = 0;
+ pValue = 0;
+ valueSize = 0;
+
+ MP4GetMetadataByIndex(file, i, (const char **)&pName, &pValue, &valueSize);
+
+ if (valueSize > 0)
+ {
+ char *val = (char *)malloc(valueSize+1);
+ if (!val) return 0;
+ memcpy(val, pValue, valueSize);
+ val[valueSize] = '\0';
+
+ if (pName[0] == '\xa9')
+ {
+ if (memcmp(pName, "©nam", 4) == 0)
+ {
+ tag_add_field(tags, "title", val);
+ } else if (memcmp(pName, "©ART", 4) == 0) {
+ tag_add_field(tags, "artist", val);
+ } else if (memcmp(pName, "©wrt", 4) == 0) {
+ tag_add_field(tags, "writer", val);
+ } else if (memcmp(pName, "©alb", 4) == 0) {
+ tag_add_field(tags, "album", val);
+ } else if (memcmp(pName, "©day", 4) == 0) {
+ tag_add_field(tags, "date", val);
+ } else if (memcmp(pName, "©too", 4) == 0) {
+ tag_add_field(tags, "tool", val);
+ } else if (memcmp(pName, "©cmt", 4) == 0) {
+ tag_add_field(tags, "comment", val);
+ } else if (memcmp(pName, "©gen", 4) == 0) {
+ tag_add_field(tags, "genre", val);
+ } else {
+ tag_add_field(tags, pName, val);
+ }
+ } else if (memcmp(pName, "gnre", 4) == 0) {
+ char *t=0;
+ if (MP4GetMetadataGenre(file, &t))
+ {
+ tag_add_field(tags, "genre", t);
+ }
+ } else if (memcmp(pName, "trkn", 4) == 0) {
+ unsigned __int16 trkn = 0, tot = 0;
+ char t[200];
+ if (MP4GetMetadataTrack(file, &trkn, &tot))
+ {
+ if (tot > 0)
+ wsprintf(t, "%d/%d", trkn, tot);
+ else
+ wsprintf(t, "%d", trkn);
+ tag_add_field(tags, "tracknumber", t);
+ }
+ } else if (memcmp(pName, "disk", 4) == 0) {
+ unsigned __int16 disk = 0, tot = 0;
+ char t[200];
+ if (MP4GetMetadataDisk(file, &disk, &tot))
+ {
+ if (tot > 0)
+ wsprintf(t, "%d/%d", disk, tot);
+ else
+ wsprintf(t, "%d", disk);
+ tag_add_field(tags, "disc", t);
+ }
+ } else if (memcmp(pName, "cpil", 4) == 0) {
+ unsigned __int8 cpil = 0;
+ char t[200];
+ if (MP4GetMetadataCompilation(file, &cpil))
+ {
+ wsprintf(t, "%d", cpil);
+ tag_add_field(tags, "compilation", t);
+ }
+ } else if (memcmp(pName, "tmpo", 4) == 0) {
+ unsigned __int16 tempo = 0;
+ char t[200];
+ if (MP4GetMetadataTempo(file, &tempo))
+ {
+ wsprintf(t, "%d BPM", tempo);
+ tag_add_field(tags, "tempo", t);
+ }
+ } else if (memcmp(pName, "NDFL", 4) == 0) {
+ /* Removed */
+ } else {
+ tag_add_field(tags, pName, val);
+ }
+
+ free(val);
+ }
+
+ i++;
+ } while (valueSize > 0);
+
+ return 1;
+}
+
+int mp4_set_metadata(MP4FileHandle file, const char *item, const char *val)
+{
+ if (!item || (item && !*item) || !val || (val && !*val)) return 0;
+
+ if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
+ {
+ unsigned __int16 trkn, tot;
+ int t1 = 0, t2 = 0;
+ sscanf(val, "%d/%d", &t1, &t2);
+ trkn = t1, tot = t2;
+ if (!trkn) return 1;
+ if (MP4SetMetadataTrack(file, trkn, tot)) return 1;
+ }
+ else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
+ {
+ unsigned __int16 disk, tot;
+ int t1 = 0, t2 = 0;
+ sscanf(val, "%d/%d", &t1, &t2);
+ disk = t1, tot = t2;
+ if (!disk) return 1;
+ if (MP4SetMetadataDisk(file, disk, tot)) return 1;
+ }
+ else if (!stricmp(item, "compilation"))
+ {
+ unsigned __int8 cpil = atoi(val);
+ if (!cpil) return 1;
+ if (MP4SetMetadataCompilation(file, cpil)) return 1;
+ }
+ else if (!stricmp(item, "tempo"))
+ {
+ unsigned __int16 tempo = atoi(val);
+ if (!tempo) return 1;
+ if (MP4SetMetadataTempo(file, tempo)) return 1;
+ }
+ else if (!stricmp(item, "artist"))
+ {
+ if (MP4SetMetadataArtist(file, val)) return 1;
+ }
+ else if (!stricmp(item, "writer"))
+ {
+ if (MP4SetMetadataWriter(file, val)) return 1;
+ }
+ else if (!stricmp(item, "title"))
+ {
+ if (MP4SetMetadataName(file, val)) return 1;
+ }
+ else if (!stricmp(item, "album"))
+ {
+ if (MP4SetMetadataAlbum(file, val)) return 1;
+ }
+ else if (!stricmp(item, "date") || !stricmp(item, "year"))
+ {
+ if (MP4SetMetadataYear(file, val)) return 1;
+ }
+ else if (!stricmp(item, "comment"))
+ {
+ if (MP4SetMetadataComment(file, val)) return 1;
+ }
+ else if (!stricmp(item, "genre"))
+ {
+ if (MP4SetMetadataGenre(file, val)) return 1;
+ }
+ else if (!stricmp(item, "tool"))
+ {
+ if (MP4SetMetadataTool(file, val)) return 1;
+ }
+ else
+ {
+ if (MP4SetMetadataFreeForm(file, (char *)item, (u_int8_t *)val, (u_int32_t)strlen(val) + 1)) return 1;
+ }
+
+ return 0;
+}
+
+void WriteMP4Tag(MP4FileHandle file, const medialib_tags *tags)
+{
+ unsigned int i;
+
+ for (i = 0; i < tags->count; i++)
+ {
+ const char *item = tags->tags[i].item;
+ const char *value = tags->tags[i].value;
+
+ if (value && *value)
+ {
+ mp4_set_metadata(file, item, value);
+ }
+ }
+}
+
+QCDModInitTag ModInitTag;
+
+medialib_tags tags;
+
+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
+ tag_delete(&tags);
+}
+
+//-----------------------------------------------------------------------------
+
+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;
+ u_int32_t 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);
+ //if (dummy)
+ //{
+ // wsprintf(dummy1, "%d", dummy);
+ // SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
+ //}
+
+ dummy = 0; dummy2 = 0;
+ MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
+ if (dummy)
+ {
+ wsprintf(dummy1, "%d", dummy);
+ ModInitTag.SetFieldA(tagHandle, TAGFIELD_TRACK, dummy1);
+ }
+ //if (dumm2)
+ //{
+ // wsprintf(dummy1, "%d", dummy2);
+ // SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
+ //}
+
+ //dummy = 0; dummy2 = 0;
+ //MP4GetMetadataDisk(file, &dummy, &dummy2);
+ //if (dummy)
+ //{
+ // wsprintf(dummy1, "%d", dummy);
+ // SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
+ //}
+ //if (dummy)
+ //{
+ // wsprintf(dummy1, "%d", dummy2);
+ // SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
+ //}
+
+ pVal = NULL;
+ if (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];
+ char temp[1024];
+ short dummy, dummy2;
+
+#ifdef DEBUG_OUTPUT
+ in_mp4_DebugOutput("mp4_tag_write");
+#endif
+
+ /* save Metadata changes */
+
+ tag_delete(&tags);
+ file = MP4Read(filename, 0);
+ if (file != MP4_INVALID_FILE_HANDLE)
+ {
+ ReadMP4Tag(file, &tags);
+ MP4Close(file);
+
+ file = MP4Modify(filename, 0, 0);
+ if (file != MP4_INVALID_FILE_HANDLE)
+ {
+ MP4MetadataDelete(file);
+ MP4Close(file);
+ }
+ }
+
+ file = MP4Modify(filename, 0, 0);
+ if (file == MP4_INVALID_FILE_HANDLE)
+ {
+ tag_delete(&tags);
+ //EndDialog(hwndDlg, wParam);
+ return false;
+ }
+
+ uGetDlgItemText(tagHandle, TAGFIELD_TITLE, dummy1, 1024);
+ tag_set_field(&tags, "title", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_COMPOSER, dummy1, 1024);
+ tag_set_field(&tags, "writer", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_ARTIST, dummy1, 1024);
+ tag_set_field(&tags, "artist", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_ALBUM, dummy1, 1024);
+ tag_set_field(&tags, "album", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_COMMENT, dummy1, 1024);
+ tag_set_field(&tags, "comment", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_GENRE, dummy1, 1024);
+ tag_set_field(&tags, "genre", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_YEAR, dummy1, 1024);
+ tag_set_field(&tags, "year", dummy1);
+
+ dummy = 0;
+ MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
+ memcpy(dummy1, ModInitTag.GetFieldA(tagHandle, TAGFIELD_TRACK), sizeof(dummy1));
+ dummy = atoi(dummy1);
+ wsprintf(temp, "%d/%d", dummy, dummy2);
+ tag_set_field(&tags, "track", temp);
+
+ //GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
+ //dummy = atoi(dummy1);
+ //GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
+ //dummy2 = atoi(dummy1);
+ //wsprintf(temp, "%d/%d", dummy, dummy2);
+ //tag_set_field(&tags, "disc", temp);
+
+ //GetDlgItemText(hwndDlg, IDC_METATEMPO, dummy1, 1024);
+ //tag_set_field(&tags, "tempo", dummy1);
+
+ //dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
+ //tag_set_field(&tags, "compilation", (dummy3 ? "1" : "0"));
+
+ uGetDlgItemText(tagHandle, TAGFIELD_ENCODER, dummy1, 1024);
+ tag_set_field(&tags, "tool", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_CONDUCTOR, dummy1, 1024);
+ tag_set_field(&tags, "CONDUCTOR", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_ORCHESTRA, dummy1, 1024);
+ tag_set_field(&tags, "ORCHESTRA", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_YEARCOMPOSED, dummy1, 1024);
+ tag_set_field(&tags, "YEARCOMPOSED", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_ORIGARTIST, dummy1, 1024);
+ tag_set_field(&tags, "ORIGARTIST", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_LABEL, dummy1, 1024);
+ tag_set_field(&tags, "LABEL", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_COPYRIGHT, dummy1, 1024);
+ tag_set_field(&tags, "COPYRIGHT", dummy1);
+
+ uGetDlgItemText(tagHandle, TAGFIELD_CDDBTAGID, dummy1, 1024);
+ tag_set_field(&tags, "CDDBTAGID", dummy1);
+
+ WriteMP4Tag(file, &tags);
+
+ 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;
+ 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 || !max) 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);
+ memset(str, '\0', max);
+ 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;
+}
diff --git a/faad2/src/plugins/QCDMp4/QCDTagsDLL.h b/faad2/src/plugins/QCDMp4/QCDTagsDLL.h
new file mode 100644
index 0000000..d8621cc
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/QCDTagsDLL.h
@@ -0,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
diff --git a/faad2/src/plugins/QCDMp4/aac2mp4.cpp b/faad2/src/plugins/QCDMp4/aac2mp4.cpp
new file mode 100644
index 0000000..8dd0811
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/aac2mp4.cpp
@@ -0,0 +1,319 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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>
+#include <mp4.h>
+#include <mp4av.h>
+
+#include "aac2mp4.h"
+
+int covert_aac_to_mp4(char *inputFileName, char *mp4FileName)
+{
+ int Mp4TimeScale = 90000;
+ int allMpeg4Streams = 0;
+ MP4FileHandle mp4File;
+ FILE* inFile;
+ const char *type;
+ MP4TrackId createdTrackId = MP4_INVALID_TRACK_ID;
+
+ mp4File = MP4Create(mp4FileName, 0, 0, 0);
+ if (mp4File)
+ {
+ MP4SetTimeScale(mp4File, Mp4TimeScale);
+ } else {
+ return 1;
+ }
+
+ inFile = fopen(inputFileName, "rb");
+
+ if (inFile == NULL)
+ {
+ MP4Close(mp4File);
+ return 2;
+ }
+
+ createdTrackId = AacCreator(mp4File, inFile);
+
+ if (createdTrackId == MP4_INVALID_TRACK_ID)
+ {
+ fclose(inFile);
+ MP4Close(mp4File);
+ return 3;
+ }
+
+ type = MP4GetTrackType(mp4File, createdTrackId);
+
+ if (!strcmp(type, MP4_AUDIO_TRACK_TYPE))
+ {
+ allMpeg4Streams &=
+ (MP4GetTrackAudioType(mp4File, createdTrackId)
+ == MP4_MPEG4_AUDIO_TYPE);
+ }
+
+ if (inFile)
+ {
+ fclose(inFile);
+ }
+
+ MP4Close(mp4File);
+ MP4MakeIsmaCompliant(mp4FileName, 0, allMpeg4Streams);
+
+ return 0;
+}
+
+#define ADTS_HEADER_MAX_SIZE 10 /* bytes */
+
+static u_int8_t firstHeader[ADTS_HEADER_MAX_SIZE];
+
+/*
+ * hdr must point to at least ADTS_HEADER_MAX_SIZE bytes of memory
+ */
+static bool LoadNextAdtsHeader(FILE* inFile, u_int8_t* hdr)
+{
+ u_int state = 0;
+ u_int dropped = 0;
+ u_int hdrByteSize = ADTS_HEADER_MAX_SIZE;
+
+ while (1) {
+ /* read a byte */
+ u_int8_t b;
+
+ if (fread(&b, 1, 1, inFile) == 0) {
+ return false;
+ }
+
+ /* header is complete, return it */
+ if (state == hdrByteSize - 1) {
+ hdr[state] = b;
+ if (dropped > 0) {
+ fprintf(stderr, "Warning: dropped %u input bytes\n", dropped);
+ }
+ return true;
+ }
+
+ /* collect requisite number of bytes, no constraints on data */
+ if (state >= 2) {
+ hdr[state++] = b;
+ } else {
+ /* have first byte, check if we have 1111X00X */
+ if (state == 1) {
+ if ((b & 0xF6) == 0xF0) {
+ hdr[state] = b;
+ state = 2;
+ /* compute desired header size */
+ hdrByteSize = MP4AV_AdtsGetHeaderByteSize(hdr);
+ } else {
+ state = 0;
+ }
+ }
+ /* initial state, looking for 11111111 */
+ if (state == 0) {
+ if (b == 0xFF) {
+ hdr[state] = b;
+ state = 1;
+ } else {
+ /* else drop it */
+ dropped++;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Load the next frame from the file
+ * into the supplied buffer, which better be large enough!
+ *
+ * Note: Frames are padded to byte boundaries
+ */
+static bool LoadNextAacFrame(FILE* inFile, u_int8_t* pBuf, u_int32_t* pBufSize, bool stripAdts)
+{
+ u_int16_t frameSize;
+ u_int16_t hdrBitSize, hdrByteSize;
+ u_int8_t hdrBuf[ADTS_HEADER_MAX_SIZE];
+
+ /* get the next AAC frame header, more or less */
+ if (!LoadNextAdtsHeader(inFile, hdrBuf)) {
+ return false;
+ }
+
+ /* get frame size from header */
+ frameSize = MP4AV_AdtsGetFrameSize(hdrBuf);
+
+ /* get header size in bits and bytes from header */
+ hdrBitSize = MP4AV_AdtsGetHeaderBitSize(hdrBuf);
+ hdrByteSize = MP4AV_AdtsGetHeaderByteSize(hdrBuf);
+
+ /* adjust the frame size to what remains to be read */
+ frameSize -= hdrByteSize;
+
+ if (stripAdts) {
+ if ((hdrBitSize % 8) == 0) {
+ /* header is byte aligned, i.e. MPEG-2 ADTS */
+ /* read the frame data into the buffer */
+ if (fread(pBuf, 1, frameSize, inFile) != frameSize) {
+ return false;
+ }
+ (*pBufSize) = frameSize;
+ } else {
+ /* header is not byte aligned, i.e. MPEG-4 ADTS */
+ int i;
+ u_int8_t newByte;
+ int upShift = hdrBitSize % 8;
+ int downShift = 8 - upShift;
+
+ pBuf[0] = hdrBuf[hdrBitSize / 8] << upShift;
+
+ for (i = 0; i < frameSize; i++) {
+ if (fread(&newByte, 1, 1, inFile) != 1) {
+ return false;
+ }
+ pBuf[i] |= (newByte >> downShift);
+ pBuf[i+1] = (newByte << upShift);
+ }
+ (*pBufSize) = frameSize + 1;
+ }
+ } else { /* don't strip ADTS headers */
+ memcpy(pBuf, hdrBuf, hdrByteSize);
+ if (fread(&pBuf[hdrByteSize], 1, frameSize, inFile) != frameSize) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool GetFirstHeader(FILE* inFile)
+{
+ /* read file until we find an audio frame */
+ fpos_t curPos;
+
+ /* already read first header */
+ if (firstHeader[0] == 0xff) {
+ return true;
+ }
+
+ /* remember where we are */
+ fgetpos(inFile, &curPos);
+
+ /* go back to start of file */
+ rewind(inFile);
+
+ if (!LoadNextAdtsHeader(inFile, firstHeader)) {
+ return false;
+ }
+
+ /* reposition the file to where we were */
+ fsetpos(inFile, &curPos);
+
+ return true;
+}
+
+MP4TrackId AacCreator(MP4FileHandle mp4File, FILE* inFile)
+{
+ // collect all the necessary meta information
+ u_int32_t samplesPerSecond;
+ u_int8_t mpegVersion;
+ u_int8_t profile;
+ u_int8_t channelConfig;
+
+ if (!GetFirstHeader(inFile)) {
+ return MP4_INVALID_TRACK_ID;
+ }
+
+ samplesPerSecond = MP4AV_AdtsGetSamplingRate(firstHeader);
+ mpegVersion = MP4AV_AdtsGetVersion(firstHeader);
+ profile = MP4AV_AdtsGetProfile(firstHeader);
+ channelConfig = MP4AV_AdtsGetChannels(firstHeader);
+
+ u_int8_t audioType = MP4_INVALID_AUDIO_TYPE;
+ switch (mpegVersion) {
+ case 0:
+ audioType = MP4_MPEG4_AUDIO_TYPE;
+ break;
+ case 1:
+ switch (profile) {
+ case 0:
+ audioType = MP4_MPEG2_AAC_MAIN_AUDIO_TYPE;
+ break;
+ case 1:
+ audioType = MP4_MPEG2_AAC_LC_AUDIO_TYPE;
+ break;
+ case 2:
+ audioType = MP4_MPEG2_AAC_SSR_AUDIO_TYPE;
+ break;
+ case 3:
+ return MP4_INVALID_TRACK_ID;
+ }
+ break;
+ }
+
+ // add the new audio track
+ MP4TrackId trackId =
+ MP4AddAudioTrack(mp4File,
+ samplesPerSecond, 1024, audioType);
+
+ if (trackId == MP4_INVALID_TRACK_ID) {
+ return MP4_INVALID_TRACK_ID;
+ }
+
+ if (MP4GetNumberOfTracks(mp4File, MP4_AUDIO_TRACK_TYPE) == 1) {
+ MP4SetAudioProfileLevel(mp4File, 0x0F);
+ }
+
+ u_int8_t* pConfig = NULL;
+ u_int32_t configLength = 0;
+
+ MP4AV_AacGetConfiguration(
+ &pConfig,
+ &configLength,
+ profile,
+ samplesPerSecond,
+ channelConfig);
+
+ if (!MP4SetTrackESConfiguration(mp4File, trackId,
+ pConfig, configLength)) {
+ MP4DeleteTrack(mp4File, trackId);
+ return MP4_INVALID_TRACK_ID;
+ }
+
+ // parse the ADTS frames, and write the MP4 samples
+ u_int8_t sampleBuffer[8 * 1024];
+ u_int32_t sampleSize = sizeof(sampleBuffer);
+ MP4SampleId sampleId = 1;
+
+ while (LoadNextAacFrame(inFile, sampleBuffer, &sampleSize, true)) {
+ if (!MP4WriteSample(mp4File, trackId, sampleBuffer, sampleSize)) {
+ MP4DeleteTrack(mp4File, trackId);
+ return MP4_INVALID_TRACK_ID;
+ }
+ sampleId++;
+ sampleSize = sizeof(sampleBuffer);
+ }
+
+ return trackId;
+}
diff --git a/faad2/src/plugins/QCDMp4/aac2mp4.h b/faad2/src/plugins/QCDMp4/aac2mp4.h
new file mode 100644
index 0000000..b14913c
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/aac2mp4.h
@@ -0,0 +1,42 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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__
+#define AAC2MP4_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int covert_aac_to_mp4(char *inputFileName, char *mp4FileName);
+MP4TrackId AacCreator(MP4FileHandle mp4File, FILE* inFile);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif \ No newline at end of file
diff --git a/faad2/src/plugins/QCDMp4/aacinfo.c b/faad2/src/plugins/QCDMp4/aacinfo.c
new file mode 100644
index 0000000..fb689d6
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/aacinfo.c
@@ -0,0 +1,224 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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
+#include <windows.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "aacinfo.h"
+#include "utils.h"
+
+#define ADIF_MAX_SIZE 30 /* Should be enough */
+#define ADTS_MAX_SIZE 10 /* Should be enough */
+
+static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000};
+
+static int read_ADIF_header(FILE *file, faadAACInfo *info)
+{
+ int bitstream;
+ unsigned char buffer[ADIF_MAX_SIZE];
+ int skip_size = 0;
+ int sf_idx;
+
+ /* Get ADIF header data */
+ info->headertype = 1;
+
+ if (fread(buffer, 1, ADIF_MAX_SIZE, file) != ADIF_MAX_SIZE)
+ return -1;
+
+ /* copyright string */
+ if(buffer[0] & 0x80)
+ skip_size += 9; /* skip 9 bytes */
+
+ bitstream = buffer[0 + skip_size] & 0x10;
+ info->bitrate = ((unsigned int)(buffer[0 + skip_size] & 0x0F)<<19)|
+ ((unsigned int)buffer[1 + skip_size]<<11)|
+ ((unsigned int)buffer[2 + skip_size]<<3)|
+ ((unsigned int)buffer[3 + skip_size] & 0xE0);
+
+ if (bitstream == 0)
+ {
+ info->object_type = ((buffer[6 + skip_size]&0x01)<<1)|((buffer[7 + skip_size]&0x80)>>7);
+ sf_idx = (buffer[7 + skip_size]&0x78)>>3;
+ } else {
+ info->object_type = (buffer[4 + skip_size] & 0x18)>>3;
+ sf_idx = ((buffer[4 + skip_size] & 0x07)<<1)|((buffer[5 + skip_size] & 0x80)>>7);
+ }
+ info->sampling_rate = sample_rates[sf_idx];
+
+ return 0;
+}
+
+static int read_ADTS_header(FILE *file, faadAACInfo *info)
+{
+ /* Get ADTS header data */
+ unsigned char buffer[ADTS_MAX_SIZE];
+ int frames, t_framelength = 0, frame_length, sr_idx = 0, ID;
+ int second = 0, pos;
+ float frames_per_sec = 0;
+ unsigned long bytes;
+ unsigned long *tmp_seek_table = NULL;
+
+ info->headertype = 2;
+
+ /* Read all frames to ensure correct time and bitrate */
+ for (frames = 0; /* */; frames++)
+ {
+ bytes = fread(buffer, 1, ADTS_MAX_SIZE, file);
+
+ if (bytes != ADTS_MAX_SIZE)
+ break;
+
+ /* check syncword */
+ if (!((buffer[0] == 0xFF)&&((buffer[1] & 0xF6) == 0xF0)))
+ break;
+
+ if (!frames)
+ {
+ /* fixed ADTS header is the same for every frame, so we read it only once */
+ /* Syncword found, proceed to read in the fixed ADTS header */
+ ID = buffer[1] & 0x08;
+ info->object_type = (buffer[2]&0xC0)>>6;
+ sr_idx = (buffer[2]&0x3C)>>2;
+ info->channels = ((buffer[2]&0x01)<<2)|((buffer[3]&0xC0)>>6);
+
+ frames_per_sec = sample_rates[sr_idx] / 1024.f;
+ }
+
+ /* ...and the variable ADTS header */
+ if (ID == 0)
+ {
+ info->version = 4;
+ } else { /* MPEG-2 */
+ info->version = 2;
+ }
+ frame_length = ((((unsigned int)buffer[3] & 0x3)) << 11)
+ | (((unsigned int)buffer[4]) << 3) | (buffer[5] >> 5);
+
+ t_framelength += frame_length;
+
+ pos = ftell(file) - ADTS_MAX_SIZE;
+
+ fseek(file, frame_length - ADTS_MAX_SIZE, SEEK_CUR);
+ }
+
+ if (frames > 0)
+ {
+ float sec_per_frame, bytes_per_frame;
+ info->sampling_rate = sample_rates[sr_idx];
+ sec_per_frame = (float)info->sampling_rate/1024.0;
+ bytes_per_frame = (float)t_framelength / (float)frames;
+ info->bitrate = 8 * (int)floor(bytes_per_frame * sec_per_frame);
+ info->length = (int)floor((float)frames/frames_per_sec)*1000;
+ } else {
+ info->sampling_rate = 4;
+ info->bitrate = 128000;
+ info->length = 0;
+ info->channels = 0;
+ }
+
+ return 0;
+}
+
+int get_AAC_format(char *filename, faadAACInfo *info)
+{
+ unsigned long tagsize;
+ FILE *file;
+ char buffer[10];
+ unsigned long file_len;
+ unsigned char adxx_id[5];
+ unsigned long tmp;
+
+ memset(info, 0, sizeof(faadAACInfo));
+
+ file = fopen(filename, "rb");
+
+ if(file == NULL)
+ return -1;
+
+ fseek(file, 0, SEEK_END);
+ file_len = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ /* Skip the tag, if it's there */
+ tmp = fread(buffer, 10, 1, file);
+
+ if (StringComp(buffer, "ID3", 3) == 0)
+ {
+ /* high bit is not used */
+ tagsize = (buffer[6] << 21) | (buffer[7] << 14) |
+ (buffer[8] << 7) | (buffer[9] << 0);
+
+ fseek(file, tagsize, SEEK_CUR);
+ tagsize += 10;
+ } else {
+ tagsize = 0;
+ fseek(file, 0, SEEK_SET);
+ }
+
+ if (file_len)
+ file_len -= tagsize;
+
+ tmp = fread(adxx_id, 2, 1, file);
+ adxx_id[5-1] = 0;
+ info->length = 0;
+
+ /* Determine the header type of the file, check the first two bytes */
+ if (StringComp(adxx_id, "AD", 2) == 0)
+ {
+ /* We think its an ADIF header, but check the rest just to make sure */
+ tmp = fread(adxx_id + 2, 2, 1, file);
+
+ if (StringComp(adxx_id, "ADIF", 4) == 0)
+ {
+ read_ADIF_header(file, info);
+
+ info->length = (int)((float)file_len*8000.0/((float)info->bitrate));
+ }
+ } else {
+ /* No ADIF, check for ADTS header */
+ if ((adxx_id[0] == 0xFF)&&((adxx_id[1] & 0xF6) == 0xF0))
+ {
+ /* ADTS header located */
+ fseek(file, tagsize, SEEK_SET);
+ read_ADTS_header(file, info);
+ } else {
+ /* Unknown/headerless AAC file, assume format: */
+ info->version = 2;
+ info->bitrate = 128000;
+ info->sampling_rate = 44100;
+ info->channels = 2;
+ info->headertype = 0;
+ info->object_type = 1;
+ }
+ }
+
+ fclose(file);
+
+ return 0;
+}
diff --git a/faad2/src/plugins/QCDMp4/aacinfo.h b/faad2/src/plugins/QCDMp4/aacinfo.h
new file mode 100644
index 0000000..867fef9
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/aacinfo.h
@@ -0,0 +1,46 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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
+#define AACINFO_INCLUDED
+
+typedef struct {
+ int version;
+ int channels;
+ int sampling_rate;
+ int bitrate;
+ int length;
+ int object_type;
+ int headertype;
+} faadAACInfo;
+
+int get_AAC_format(char *filename, faadAACInfo *info);
+
+static int read_ADIF_header(FILE *file, faadAACInfo *info);
+static int read_ADTS_header(FILE *file, faadAACInfo *info);
+
+#endif
diff --git a/faad2/src/plugins/QCDMp4/config.c b/faad2/src/plugins/QCDMp4/config.c
new file mode 100644
index 0000000..af5af5a
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/config.c
@@ -0,0 +1,48 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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
+#include <windows.h>
+#include "config.h"
+
+char app_name[] = "AudioCoding.com MPEG-4 General Audio player";
+char INI_FILE[MAX_PATH];
+int m_priority = 3;
+int m_resolution = 0;
+int m_show_errors = 1;
+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)
+{
+ char buf[10];
+ strcpy(buf,data);
+ GetPrivateProfileString(app_name,name,buf,data,mlen,INI_FILE);
+}
+
diff --git a/faad2/src/plugins/QCDMp4/config.h b/faad2/src/plugins/QCDMp4/config.h
new file mode 100644
index 0000000..93f6d71
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/config.h
@@ -0,0 +1,42 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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 $
+**/
+
+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))
+
+void _r_s(char *name,char *data, int mlen);
+
diff --git a/faad2/src/plugins/QCDMp4/mbs.h b/faad2/src/plugins/QCDMp4/mbs.h
new file mode 100644
index 0000000..bda58ed
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/mbs.h
@@ -0,0 +1,81 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is MPEG4IP.
+ *
+ * The Initial Developer of the Original Code is Cisco Systems Inc.
+ * Portions created by Cisco Systems Inc. are
+ * Copyright (C) Cisco Systems Inc. 2001-2002. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dave Mackie dmackie@cisco.com
+ */
+
+#ifndef __MBS_INCLUDED__
+#define __MBS_INCLUDED__
+
+class CMemoryBitstream {
+public:
+ CMemoryBitstream() {
+ m_pBuf = NULL;
+ m_bitPos = 0;
+ m_numBits = 0;
+ }
+
+ void AllocBytes(u_int32_t numBytes);
+
+ void SetBytes(u_int8_t* pBytes, u_int32_t numBytes);
+
+ void PutBytes(u_int8_t* pBytes, u_int32_t numBytes);
+
+ void PutBits(u_int32_t bits, u_int32_t numBits);
+
+ u_int32_t GetBits(u_int32_t numBits);
+
+ void SkipBytes(u_int32_t numBytes) {
+ SkipBits(numBytes << 3);
+ }
+
+ void SkipBits(u_int32_t numBits) {
+ SetBitPosition(GetBitPosition() + numBits);
+ }
+
+ u_int32_t GetBitPosition() {
+ return m_bitPos;
+ }
+
+ void SetBitPosition(u_int32_t bitPos) {
+ if (bitPos > m_numBits) {
+ throw;
+ }
+ m_bitPos = bitPos;
+ }
+
+ u_int8_t* GetBuffer() {
+ return m_pBuf;
+ }
+
+ u_int32_t GetNumberOfBytes() {
+ return (GetNumberOfBits() + 7) / 8;
+ }
+
+ u_int32_t GetNumberOfBits() {
+ return m_numBits;
+ }
+
+protected:
+ u_int8_t* m_pBuf;
+ u_int32_t m_bitPos;
+ u_int32_t m_numBits;
+};
+
+#endif /* __MBS_INCLUDED__ */
+
diff --git a/faad2/src/plugins/QCDMp4/resource.h b/faad2/src/plugins/QCDMp4/resource.h
new file mode 100644
index 0000000..e04de22
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/resource.h
@@ -0,0 +1,67 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by QCDMp4.rc
+//
+#define IDD_CONFIG 102
+#define IDC_TYPE 1000
+#define IDC_INFOTEXT 1000
+#define IDC_DURATION 1001
+#define IDC_BITRATE 1002
+#define IDC_SAMPLERATE 1003
+#define IDC_VTYPE 1004
+#define IDC_PRIORITY 1004
+#define IDC_VBITRATE 1005
+#define IDC_ERROR 1005
+#define IDC_VDURATION 1006
+#define IDC_16BITS 1006
+#define IDC_VSIZE 1007
+#define IDC_24BITS 1007
+#define IDC_CONVERT 1007
+#define IDC_VFPS 1008
+#define IDC_32BITS 1008
+#define IDC_CONVERT2 1008
+#define IDC_CHANNELS 1009
+#define IDC_24BITS2 1009
+#define IDC_16BITS_DITHERED 1009
+#define IDC_CONVERT1 1009
+#define IDC_USERDATA 1010
+#define IDC_USEFORAAC 1011
+#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 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1041
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/faad2/src/plugins/QCDMp4/utils.c b/faad2/src/plugins/QCDMp4/utils.c
new file mode 100644
index 0000000..9302de6
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/utils.c
@@ -0,0 +1,153 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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
+#include <windows.h>
+#include <mp4.h>
+#include <faad.h>
+#include "utils.h"
+
+int StringComp(char const *str1, char const *str2, unsigned long len)
+{
+ signed int c1 = 0, c2 = 0;
+
+ while (len--)
+ {
+ c1 = tolower(*str1++);
+ c2 = tolower(*str2++);
+
+ if (c1 == 0 || c1 != c2)
+ break;
+ }
+
+ return c1 - c2;
+}
+
+int GetAACTrack(MP4FileHandle infile)
+{
+ /* find AAC track */
+ int i, rc;
+ int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
+
+ for (i = 0; i < numTracks; i++)
+ {
+ MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
+ const char* trackType = MP4GetTrackType(infile, trackId);
+
+ if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE))
+ {
+ unsigned char *buff = NULL;
+ int buff_size = 0;
+ mp4AudioSpecificConfig mp4ASC;
+
+ MP4GetTrackESConfiguration(infile, trackId, &buff, &buff_size);
+
+ if (buff)
+ {
+ rc = AudioSpecificConfig(buff, buff_size, &mp4ASC);
+ free(buff);
+
+ if (rc < 0)
+ return -1;
+ return trackId;
+ }
+ }
+ }
+
+ /* can't decode this */
+ return -1;
+}
+
+int GetAudioTrack(MP4FileHandle infile)
+{
+ /* find AAC track */
+ int i;
+ int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
+
+ for (i = 0; i < numTracks; i++)
+ {
+ MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
+ const char* trackType = MP4GetTrackType(infile, trackId);
+
+ if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE))
+ {
+ return trackId;
+ }
+ }
+
+ /* can't decode this */
+ return -1;
+}
+
+int GetVideoTrack(MP4FileHandle infile)
+{
+ /* find AAC track */
+ int i;
+ int numTracks = MP4GetNumberOfTracks(infile, NULL, 0);
+
+ for (i = 0; i < numTracks; i++)
+ {
+ MP4TrackId trackId = MP4FindTrackId(infile, i, NULL, 0);
+ const char* trackType = MP4GetTrackType(infile, trackId);
+
+ if (!strcmp(trackType, MP4_VIDEO_TRACK_TYPE))
+ {
+ return trackId;
+ }
+ }
+
+ /* can't decode this */
+ return -1;
+}
+
+LPTSTR PathFindFileName(LPCTSTR pPath)
+{
+ LPCTSTR pT;
+
+ for (pT = pPath; *pPath; pPath = CharNext(pPath)) {
+ if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':')) && pPath[1] && (pPath[1] != TEXT('\\')))
+ pT = pPath + 1;
+ }
+
+ return (LPTSTR)pT; // const -> non const
+}
+
+char *convert3in4to3in3(void *sample_buffer, int samples)
+{
+ int i;
+ long *sample_buffer24 = (long*)sample_buffer;
+ char *data = malloc(samples*3*sizeof(char));
+
+ for (i = 0; i < samples; i++)
+ {
+ data[i*3] = sample_buffer24[i] & 0xFF;
+ data[i*3+1] = (sample_buffer24[i] >> 8) & 0xFF;
+ data[i*3+2] = (sample_buffer24[i] >> 16) & 0xFF;
+ }
+
+ return data;
+}
diff --git a/faad2/src/plugins/QCDMp4/utils.h b/faad2/src/plugins/QCDMp4/utils.h
new file mode 100644
index 0000000..494e019
--- /dev/null
+++ b/faad2/src/plugins/QCDMp4/utils.h
@@ -0,0 +1,40 @@
+/*
+** 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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** 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
+#define UTILS_INCLUDED
+
+#include <mp4.h>
+
+LPTSTR PathFindFileName(LPCTSTR pPath);
+int GetVideoTrack(MP4FileHandle infile);
+int GetAudioTrack(MP4FileHandle infile);
+int GetAACTrack(MP4FileHandle infile);
+int StringComp(char const *str1, char const *str2, unsigned long len);
+char *convert3in4to3in3(void *sample_buffer, int samples);
+
+#endif \ No newline at end of file
diff --git a/faad2/src/plugins/mpeg4ip/Makefile.am b/faad2/src/plugins/mpeg4ip/Makefile.am
new file mode 100644
index 0000000..8024d2a
--- /dev/null
+++ b/faad2/src/plugins/mpeg4ip/Makefile.am
@@ -0,0 +1,22 @@
+libdir = @MPEG4IP_PLAYER_PLUGIN_DIR@
+
+lib_LTLIBRARIES = faad2_plugin.la
+faad2_plugin_la_LDFLAGS = -module
+faad2_plugin_la_SOURCES = \
+ faad2.cpp \
+ faad2.h \
+ aa_file.cpp \
+ aa_file.h
+
+faad2_plugin_la_LIBADD = \
+ $(top_builddir)/libfaad/libfaad.la \
+ -lm
+
+
+INCLUDES = -I$(top_srcdir)/include
+
+AM_CFLAGS = -D_REENTRANT -fexceptions
+
+AM_CXXFLAGS = -D_REENTRANT -DNOCONTROLS -fexceptions
+
+
diff --git a/faad2/src/plugins/mpeg4ip/README_WIN32.txt b/faad2/src/plugins/mpeg4ip/README_WIN32.txt
new file mode 100644
index 0000000..7fc864a
--- /dev/null
+++ b/faad2/src/plugins/mpeg4ip/README_WIN32.txt
@@ -0,0 +1,11 @@
+Creating mpeg4ip plugin for Windows.
+
+You will need to have mpeg4ip installed. If you install it on the same drive, with the top level directory
+name of /mpeg4ip, you will have to do nothing other than move the faad2_plugin.dll from the Release or
+Debug directory to the same directory as the other mpeg4ip plugins.
+
+If you install it somewhere else, you will have to change the include paths and link paths in the project
+settings for faad2_plugin to the proper directory. Look for /mpeg4ip (or \mpeg4ip) and change all occurances
+of these in the file.
+
+It might be best to hand-edit the faad_plugin.sdp file with wordpad and use the search and replace function. \ No newline at end of file
diff --git a/faad2/src/plugins/mpeg4ip/aa_file.cpp b/faad2/src/plugins/mpeg4ip/aa_file.cpp
new file mode 100644
index 0000000..a0cccb9
--- /dev/null
+++ b/faad2/src/plugins/mpeg4ip/aa_file.cpp
@@ -0,0 +1,130 @@
+/*
+** MPEG4IP plugin for FAAD2
+** Copyright (C) 2003 Bill May wmay@cisco.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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** $Id: aa_file.cpp,v 1.2 2004/01/05 14:05:12 menno Exp $
+**/
+/*
+ * aa_file.cpp - create media structure for aac files
+ */
+
+#include "faad2.h"
+codec_data_t *aac_file_check (lib_message_func_t message,
+ const char *name,
+ double *max,
+ char *desc[4]
+#ifdef HAVE_PLUGIN_VERSION_0_8
+ , CConfigSet *pConfig
+#endif
+)
+{
+ aac_codec_t *aac;
+ int len = strlen(name);
+ if (strcasecmp(name + len - 4, ".aac") != 0) {
+ return (NULL);
+ }
+
+ aac = MALLOC_STRUCTURE(aac_codec_t);
+ memset(aac, 0, sizeof(*aac));
+ *max = 0;
+
+ aac->m_buffer = (uint8_t *)malloc(MAX_READ_BUFFER);
+ aac->m_buffer_size_max = MAX_READ_BUFFER;
+ aac->m_ifile = fopen(name, FOPEN_READ_BINARY);
+ if (aac->m_ifile == NULL) {
+ free(aac);
+ return NULL;
+ }
+ aac->m_output_frame_size = 1024;
+ aac->m_info = faacDecOpen(); // use defaults here...
+ aac->m_buffer_size = fread(aac->m_buffer,
+ 1,
+ aac->m_buffer_size_max,
+ aac->m_ifile);
+
+ unsigned long freq;
+ unsigned char chans;
+
+ faacDecInit(aac->m_info, (unsigned char *)aac->m_buffer,
+ aac->m_buffer_size, &freq, &chans);
+ // may want to actually decode the first frame...
+ if (freq == 0) {
+ message(LOG_ERR, aaclib, "Couldn't determine AAC frame rate");
+ aac_close((codec_data_t *)aac);
+ return (NULL);
+ }
+ aac->m_freq = freq;
+ aac->m_chans = chans;
+ aac->m_faad_inited = 1;
+ aac->m_framecount = 0;
+ return ((codec_data_t *)aac);
+}
+
+
+int aac_file_next_frame (codec_data_t *your,
+ uint8_t **buffer,
+ uint64_t *ts)
+{
+ aac_codec_t *aac = (aac_codec_t *)your;
+
+ if (aac->m_buffer_on > 0) {
+ memmove(aac->m_buffer,
+ &aac->m_buffer[aac->m_buffer_on],
+ aac->m_buffer_size - aac->m_buffer_on);
+ }
+ aac->m_buffer_size -= aac->m_buffer_on;
+ aac->m_buffer_size += fread(aac->m_buffer + aac->m_buffer_size,
+ 1,
+ aac->m_buffer_size_max - aac->m_buffer_size,
+ aac->m_ifile);
+ aac->m_buffer_on = 0;
+ if (aac->m_buffer_size == 0) return 0;
+
+
+ uint64_t calc;
+ calc = aac->m_framecount * 1024 * M_LLU;
+ calc /= aac->m_freq;
+ *ts = calc;
+ *buffer = aac->m_buffer;
+ aac->m_framecount++;
+ return (aac->m_buffer_size);
+}
+
+void aac_file_used_for_frame (codec_data_t *ifptr,
+ uint32_t bytes)
+{
+ aac_codec_t *aac = (aac_codec_t *)ifptr;
+ aac->m_buffer_on += bytes;
+ if (aac->m_buffer_on > aac->m_buffer_size) aac->m_buffer_on = aac->m_buffer_size;
+}
+
+int aac_file_eof (codec_data_t *ifptr)
+{
+ aac_codec_t *aac = (aac_codec_t *)ifptr;
+ return aac->m_buffer_on == aac->m_buffer_size && feof(aac->m_ifile);
+}
+
+int aac_raw_file_seek_to (codec_data_t *ifptr, uint64_t ts)
+{
+ if (ts != 0) return -1;
+
+ aac_codec_t *aac = (aac_codec_t *)ifptr;
+ rewind(aac->m_ifile);
+ aac->m_buffer_size = aac->m_buffer_on = 0;
+ aac->m_framecount = 0;
+ return 0;
+}
diff --git a/faad2/src/plugins/mpeg4ip/aa_file.h b/faad2/src/plugins/mpeg4ip/aa_file.h
new file mode 100644
index 0000000..dfed15d
--- /dev/null
+++ b/faad2/src/plugins/mpeg4ip/aa_file.h
@@ -0,0 +1,26 @@
+/*
+** MPEG4IP plugin for FAAD2
+** Copyright (C) 2003 Bill May wmay@cisco.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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** $Id: aa_file.h,v 1.1 2003/08/07 17:21:21 menno Exp $
+**/
+/*
+ * aa_file.h - prototypes for aac files
+ */
+int create_media_for_aac_file (CPlayerSession *pspstr,
+ const char *name,
+ const char **errmsg);
diff --git a/faad2/src/plugins/mpeg4ip/faad2.cpp b/faad2/src/plugins/mpeg4ip/faad2.cpp
new file mode 100644
index 0000000..72ff0c8
--- /dev/null
+++ b/faad2/src/plugins/mpeg4ip/faad2.cpp
@@ -0,0 +1,388 @@
+/*
+** MPEG4IP plugin for FAAD2
+** Copyright (C) 2003 Bill May wmay@cisco.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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** $Id: faad2.cpp,v 1.3 2004/08/20 08:30:53 menno Exp $
+**/
+#include "faad2.h"
+#include <mpeg4_audio_config.h>
+#include <mpeg4_sdp.h>
+#include <mp4.h>
+#include <SDL/SDL.h>
+
+#define DEBUG_SYNC 2
+
+#ifndef M_LLU
+#define M_LLU M_64
+#define LLU U64
+#endif
+const char *aaclib="faad2";
+
+/*
+ * Create CAACodec class
+ */
+static codec_data_t *aac_codec_create (const char *compressor,
+ int type,
+ int profile,
+ format_list_t *media_fmt,
+ audio_info_t *audio,
+ const uint8_t *userdata,
+ uint32_t userdata_size,
+ audio_vft_t *vft,
+ void *ifptr)
+
+{
+ aac_codec_t *aac;
+
+ aac = (aac_codec_t *)malloc(sizeof(aac_codec_t));
+ memset(aac, 0, sizeof(aac_codec_t));
+
+ aac->m_vft = vft;
+ aac->m_ifptr = ifptr;
+ fmtp_parse_t *fmtp = NULL;
+ // Start setting up FAAC stuff...
+
+ aac->m_resync_with_header = 1;
+ aac->m_record_sync_time = 1;
+
+ aac->m_audio_inited = 0;
+
+ // Use media_fmt to indicate that we're streaming.
+ if (media_fmt != NULL) {
+ // haven't checked for null buffer
+ // This is not necessarilly right - it is, for the most part, but
+ // we should be reading the fmtp statement, and looking at the config.
+ // (like we do below in the userdata section...
+ aac->m_freq = media_fmt->rtpmap->clock_rate;
+ fmtp = parse_fmtp_for_mpeg4(media_fmt->fmt_param, vft->log_msg);
+ if (fmtp != NULL) {
+ userdata = fmtp->config_binary;
+ userdata_size = fmtp->config_binary_len;
+ }
+ }
+
+ aac->m_info = faacDecOpen();
+ unsigned long srate;
+ unsigned char chan;
+ if ((userdata == NULL && fmtp == NULL) ||
+ (faacDecInit2(aac->m_info,
+ (uint8_t *)userdata,
+ userdata_size,
+ &srate,
+ &chan) < 0)) {
+ if (fmtp != NULL) free_fmtp_parse(fmtp);
+ return NULL;
+ }
+
+ mp4AudioSpecificConfig mp4ASC;
+ aac->m_output_frame_size = 1024;
+ if (AudioSpecificConfig((unsigned char *)userdata,
+ userdata_size,
+ &mp4ASC)) {
+ if (mp4ASC.frameLengthFlag) {
+ aac->m_output_frame_size = 960;
+ }
+ }
+ aac->m_freq = srate;
+ aac->m_chans = chan;
+ aac->m_faad_inited = 1;
+ aac->m_msec_per_frame = aac->m_output_frame_size;
+ aac->m_msec_per_frame *= M_LLU;
+ aac->m_msec_per_frame /= aac->m_freq;
+
+ // faad_init_bytestream(&m_info->ld, c_read_byte, c_bookmark, m_bytestream);
+
+ aa_message(LOG_INFO, aaclib, "Setting freq to %d", aac->m_freq);
+#if DUMP_OUTPUT_TO_FILE
+ aac->m_outfile = fopen("temp.raw", "w");
+#endif
+ if (fmtp != NULL) {
+ free_fmtp_parse(fmtp);
+ }
+ return (codec_data_t *)aac;
+}
+
+void aac_close (codec_data_t *ptr)
+{
+ if (ptr == NULL) {
+ return;
+ }
+ aac_codec_t *aac = (aac_codec_t *)ptr;
+ faacDecClose(aac->m_info);
+ aac->m_info = NULL;
+
+#if DUMP_OUTPUT_TO_FILE
+ fclose(aac->m_outfile);
+#endif
+ free(aac);
+}
+
+/*
+ * Handle pause - basically re-init the codec
+ */
+static void aac_do_pause (codec_data_t *ifptr)
+{
+ aac_codec_t *aac = (aac_codec_t *)ifptr;
+ aac->m_resync_with_header = 1;
+ aac->m_record_sync_time = 1;
+ aac->m_audio_inited = 0;
+ aac->m_ignore_first_sample = 0;
+ faacDecPostSeekReset(aac->m_info, 0);
+}
+
+/*
+ * Decode task call for FAAC
+ */
+static int aac_decode (codec_data_t *ptr,
+ uint64_t ts,
+ int from_rtp,
+ int *sync_frame,
+ uint8_t *buffer,
+ uint32_t buflen,
+ void *userdata)
+{
+ aac_codec_t *aac = (aac_codec_t *)ptr;
+ unsigned long bytes_consummed;
+ int bits = -1;
+ // struct timezone tz;
+
+ if (aac->m_record_sync_time) {
+ aac->m_current_frame = 0;
+ aac->m_record_sync_time = 0;
+ aac->m_current_time = ts;
+ aac->m_last_rtp_ts = ts;
+ } else {
+ if (aac->m_last_rtp_ts == ts) {
+ aac->m_current_time += aac->m_msec_per_frame;
+ aac->m_current_frame++;
+ } else {
+ aac->m_last_rtp_ts = ts;
+ aac->m_current_time = ts;
+ aac->m_current_frame = 0;
+ }
+
+ // Note - here m_current_time should pretty much always be >= rtpts.
+ // If we're not, we most likely want to stop and resync. We don't
+ // need to keep decoding - just decode this frame and indicate we
+ // need a resync... That should handle fast forwards... We need
+ // someway to handle reverses - perhaps if we're more than .5 seconds
+ // later...
+ }
+
+ if (aac->m_faad_inited == 0) {
+ /*
+ * If not initialized, do so.
+ */
+ abort();
+ unsigned long freq;
+ unsigned char chans;
+
+ faacDecInit(aac->m_info,
+ (unsigned char *)buffer,
+ buflen,
+ &freq,
+ &chans);
+ aac->m_freq = freq;
+ aac->m_chans = chans;
+ aac->m_faad_inited = 1;
+ }
+
+ uint8_t *buff;
+ unsigned long samples;
+ bytes_consummed = buflen;
+ //aa_message(LOG_DEBUG, aaclib, "decoding %d bits", buflen * 8);
+ faacDecFrameInfo frame_info;
+ buff = (uint8_t *)faacDecDecode(aac->m_info,
+ &frame_info,
+ buffer,
+ buflen);
+ if (buff != NULL) {
+ bytes_consummed = frame_info.bytesconsumed;
+#if 0
+ aa_message(LOG_DEBUG, aaclib, LLU" bytes %d samples %d",
+ ts, bytes_consummed, frame_info.samples);
+#endif
+ if (aac->m_audio_inited != 0) {
+ int tempchans = frame_info.channels;
+ if (tempchans != aac->m_chans) {
+ aa_message(LOG_NOTICE, aaclib, "chupdate - chans from data is %d",
+ tempchans);
+ }
+ } else {
+ int tempchans = frame_info.channels;
+
+ if (tempchans == 0) {
+ aa_message(LOG_ERR, aaclib, "initializing aac, returned channels are 0");
+ aac->m_resync_with_header = 1;
+ aac->m_record_sync_time = 1;
+ return bytes_consummed;
+ }
+ aac->m_chans = tempchans;
+ aac->m_freq = frame_info.samplerate;
+
+ aac->m_vft->audio_configure(aac->m_ifptr,
+ aac->m_freq,
+ aac->m_chans,
+ (audio_format_t)AUDIO_S16SYS,
+ aac->m_output_frame_size);
+ uint8_t *now = aac->m_vft->audio_get_buffer(aac->m_ifptr);
+ aac->m_audio_inited = 1;
+ }
+ /*
+ * good result - give it to audio sync class
+ */
+#if DUMP_OUTPUT_TO_FILE
+ fwrite(buff, aac->m_output_frame_size * 4, 1, aac->m_outfile);
+#endif
+ if (frame_info.samples != 0) {
+ aac->m_vft->audio_load_buffer(aac->m_ifptr,
+ buff,
+ frame_info.samples * 2,
+ aac->m_last_ts,
+ aac->m_resync_with_header);
+ if (aac->m_resync_with_header == 1) {
+ aac->m_resync_with_header = 0;
+#ifdef DEBUG_SYNC
+ aa_message(LOG_DEBUG, aaclib, "Back to good at "LLU, aac->m_current_time);
+#endif
+ }
+ }
+ } else {
+ aa_message(LOG_ERR, aaclib, "error return is %d", frame_info.error);
+ aac->m_resync_with_header = 1;
+#ifdef DEBUG_SYNC
+ aa_message(LOG_ERR, aaclib, "Audio decode problem - at "LLU,
+ aac->m_current_time);
+#endif
+ }
+ aac->m_last_ts = aac->m_current_time;
+ return (bytes_consummed);
+}
+
+static const char *aac_compressors[] = {
+ "aac ",
+ "mp4a",
+ "enca",
+ NULL
+};
+
+static int aac_codec_check (lib_message_func_t message,
+ const char *compressor,
+ int type,
+ int profile,
+ format_list_t *fptr,
+ const uint8_t *userdata,
+ uint32_t userdata_size
+#ifdef HAVE_PLUGIN_VERSION_0_8
+ ,CConfigSet *pConfig
+#endif
+ )
+{
+ fmtp_parse_t *fmtp = NULL;
+ if (compressor != NULL &&
+ strcasecmp(compressor, "MP4 FILE") == 0 &&
+ type != -1) {
+ switch (type) {
+ case MP4_MPEG2_AAC_MAIN_AUDIO_TYPE:
+ case MP4_MPEG2_AAC_LC_AUDIO_TYPE:
+ case MP4_MPEG2_AAC_SSR_AUDIO_TYPE:
+ case MP4_MPEG4_AUDIO_TYPE:
+ break;
+ default:
+ return -1;
+ }
+ }
+ if (fptr != NULL &&
+ fptr->rtpmap != NULL &&
+ fptr->rtpmap->encode_name != NULL) {
+ if (strcasecmp(fptr->rtpmap->encode_name, "mpeg4-generic") != 0) {
+ return -1;
+ }
+ if (userdata == NULL) {
+ fmtp = parse_fmtp_for_mpeg4(fptr->fmt_param, message);
+ if (fmtp != NULL) {
+ userdata = fmtp->config_binary;
+ userdata_size = fmtp->config_binary_len;
+ }
+ }
+ }
+ if (userdata != NULL) {
+ mpeg4_audio_config_t audio_config;
+ decode_mpeg4_audio_config(userdata, userdata_size, &audio_config);
+ message(LOG_DEBUG, "aac", "audio type is %d", audio_config.audio_object_type);
+ if (fmtp != NULL) free_fmtp_parse(fmtp);
+
+ if (audio_object_type_is_aac(&audio_config) == 0) {
+ return -1;
+ }
+#if 0
+ if (audio_config.audio_object_type == 17) {
+ message(LOG_INFO, "aac", "audio type is legal ISMA, but not supported");
+ return -1;
+ }
+#endif
+ return 2;
+ }
+#if 0
+ // I'm not sure I want to be here if we don't have an audio config
+ if (compressor != NULL) {
+ const char **lptr = aac_compressors;
+ while (*lptr != NULL) {
+ if (strcasecmp(*lptr, compressor) == 0) {
+ return 2;
+ }
+ lptr++;
+ }
+ }
+#endif
+ return -1;
+}
+
+#ifndef HAVE_PLUGIN_VERSION_0_8
+AUDIO_CODEC_WITH_RAW_FILE_PLUGIN("faad2",
+ aac_codec_create,
+ aac_do_pause,
+ aac_decode,
+ NULL,
+ aac_close,
+ aac_codec_check,
+ aac_file_check,
+ aac_file_next_frame,
+ aac_file_used_for_frame,
+ aac_raw_file_seek_to,
+ aac_file_eof
+ );
+#else
+AUDIO_CODEC_WITH_RAW_FILE_PLUGIN("faad2",
+ aac_codec_create,
+ aac_do_pause,
+ aac_decode,
+ NULL,
+ aac_close,
+ aac_codec_check,
+ aac_file_check,
+ aac_file_next_frame,
+ aac_file_used_for_frame,
+ aac_raw_file_seek_to,
+ aac_file_eof,
+ NULL,
+ 0
+ );
+#endif
+/* end file aa.cpp */
+
+
diff --git a/faad2/src/plugins/mpeg4ip/faad2.h b/faad2/src/plugins/mpeg4ip/faad2.h
new file mode 100644
index 0000000..b74cdff
--- /dev/null
+++ b/faad2/src/plugins/mpeg4ip/faad2.h
@@ -0,0 +1,92 @@
+/*
+** MPEG4IP plugin for FAAD2
+** Copyright (C) 2003 Bill May wmay@cisco.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
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+** $Id: faad2.h,v 1.2 2004/01/05 14:05:12 menno Exp $
+**/
+/*
+ * aa.h - class definition for AAC codec.
+ */
+
+#ifndef __AA_H__
+#define __AA_H__ 1
+#include "faad.h"
+#include "codec_plugin.h"
+
+#ifndef M_LLU
+#define M_LLU M_64
+#define LLU U64
+#endif
+
+typedef struct aac_codec_t {
+ codec_data_t c;
+ audio_vft_t *m_vft;
+ void *m_ifptr;
+ faacDecHandle m_info;
+ int m_object_type;
+ int m_resync_with_header;
+ int m_record_sync_time;
+ uint64_t m_current_time;
+ uint64_t m_last_rtp_ts;
+ uint64_t m_msec_per_frame;
+ uint32_t m_current_frame;
+ int m_audio_inited;
+ int m_faad_inited;
+ int m_freq; // frequency
+ int m_chans; // channels
+ int m_output_frame_size;
+#if DUMP_OUTPUT_TO_FILE
+ FILE *m_outfile;
+#endif
+ FILE *m_ifile;
+ uint8_t *m_buffer;
+ uint32_t m_buffer_size_max;
+ uint32_t m_buffer_size;
+ uint32_t m_buffer_on;
+ uint64_t m_framecount;
+ int m_ignore_first_sample;
+ uint64_t m_last_ts;
+} aac_codec_t;
+
+#define m_vft c.v.audio_vft
+#define m_ifptr c.ifptr
+#define MAX_READ_BUFFER (768 * 8)
+
+#define aa_message aac->m_vft->log_msg
+void aac_close(codec_data_t *ptr);
+extern const char *aaclib;
+
+codec_data_t *aac_file_check(lib_message_func_t message,
+ const char *name,
+ double *max,
+ char *desc[4]
+#ifdef HAVE_PLUGIN_VERSION_0_8
+ , CConfigSet *pConfig
+#endif
+);
+
+int aac_file_next_frame(codec_data_t *ifptr,
+ uint8_t **buffer,
+ uint64_t *ts);
+int aac_file_eof(codec_data_t *ifptr);
+
+void aac_file_used_for_frame(codec_data_t *ifptr,
+ uint32_t bytes);
+
+int aac_raw_file_seek_to(codec_data_t *ifptr,
+ uint64_t ts);
+#endif
diff --git a/faad2/src/plugins/xmms/AUTHORS b/faad2/src/plugins/xmms/AUTHORS
new file mode 100644
index 0000000..1def44f
--- /dev/null
+++ b/faad2/src/plugins/xmms/AUTHORS
@@ -0,0 +1,3 @@
+xmms-mp4 plugin for xmms-1.2.x
+
+re-coded by ciberfred from scratch
diff --git a/faad2/src/plugins/xmms/ChangeLog b/faad2/src/plugins/xmms/ChangeLog
new file mode 100644
index 0000000..4a89f46
--- /dev/null
+++ b/faad2/src/plugins/xmms/ChangeLog
@@ -0,0 +1,43 @@
+22 August 2004:
+ * move from libmp4v2 to libmp4ff
+
+1 December 2003:
+ * remove aac plug and merge the aac part with the mp4 part
+ so now 2 plugins in one :)
+
+4 juillet 2003:
+ * package the plugin for faad2
+ * upgrade code to libfaad2-2.0 API
+ * version 0.5
+
+15 juin 2003:
+ * better configuration code
+ (choose automaticaly at compile time)
+ * installation must be set by root
+ * version 0.4
+
+15 mai 2003:
+ * update configure script to be better
+ * version 0.3
+
+01 Novembre 2002:
+ * check automake/autoconf/libtool for plugin, now 'make install' work
+ * handle seeking
+ * configuration box created (thanks glade !)
+ * handle aac informations
+ * modification to a better infobox (thanks angain glade !)
+ * version 0.2 ready to public :)
+
+25 Aout 2002:
+ * gtk-1.2.x info file with some 'static' useful ID3 info
+ * title show in xmms correctly
+ * version 0.1 ready to public :)
+
+20 Aout 2002:
+ * everything...
+ * work with faad2lib-1.1, id3lib-3.8.0 (glibc-2.2.5, gcc-2.95.3)
+ i think the minimum required but need testing...
+ * playlist working
+ * handle id3tag, the plugin work :)
+ * new maintener : ciberfred
+
diff --git a/faad2/src/plugins/xmms/INSTALL b/faad2/src/plugins/xmms/INSTALL
new file mode 100644
index 0000000..3f5cccf
--- /dev/null
+++ b/faad2/src/plugins/xmms/INSTALL
@@ -0,0 +1,2 @@
+the installation of this plugin is provide by the faad2 package.
+add to configure time the option '--with-xmms' and the plugin will be build \ No newline at end of file
diff --git a/faad2/src/plugins/xmms/Makefile.am b/faad2/src/plugins/xmms/Makefile.am
new file mode 100644
index 0000000..5d39788
--- /dev/null
+++ b/faad2/src/plugins/xmms/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = src
+
diff --git a/faad2/src/plugins/xmms/NEWS b/faad2/src/plugins/xmms/NEWS
new file mode 100644
index 0000000..32b85d3
--- /dev/null
+++ b/faad2/src/plugins/xmms/NEWS
@@ -0,0 +1,21 @@
+22 Aout 2004
+------------
+modification du system de compilation, passage de libmp4v2 a libmp4ff
+en static, libfaad en dynamique.
+
+1 Decembre 2003
+---------------
+merge du plugin aac et du plugin mp4. modification des script du projet faad
+le plugin ne doit pas etre construit en meme temps que le projet
+
+4 Juillet 2003
+--------------
+integration du plugin xmms-aac dans le projet faad2 version 2.x
+
+15 aout 2002
+------------
+
+Recodage en entier du plugin aac
+me contacter par mail a :
+
+frederic.fondriest@laposte.net
diff --git a/faad2/src/plugins/xmms/README b/faad2/src/plugins/xmms/README
new file mode 100644
index 0000000..7380891
--- /dev/null
+++ b/faad2/src/plugins/xmms/README
@@ -0,0 +1,23 @@
+ xmms-mp4 plugin v0.5
+ (dynamic version)
+ "a mp4/aac audio player for xmms"
+ coded by ciberfred from france
+ -------------
+
+This source code allow to xmms to read .mp4/.m4a/.aac files
+
+About.
+ This plugin is a merge between aac and mp4 plugin. so now you could read
+all new and old files encoded with different encoder and different format
+(for the aac part). This is possible since the libfaad2 allow to read
+old aac ADTS format.
+
+For any informations about this plugin contact me at :
+
+mail : frederic.fondriest@laposte.net
+ICQ : 17293220
+aac plugin homepage (and more) : http://fondriest.frederic.free.fr/realisations/
+IRC : irc.eu.freenode.net (#lamip)
+
+--
+Frederic Fondriest
diff --git a/faad2/src/plugins/xmms/TODO b/faad2/src/plugins/xmms/TODO
new file mode 100644
index 0000000..e2de779
--- /dev/null
+++ b/faad2/src/plugins/xmms/TODO
@@ -0,0 +1,6 @@
+TODO:
+
+ * handle AAC info such as MPEG-AAC type, header (ADTS/ADIF),...
+ * seeking... but it will certainly an option because it need
+ a reading of whole file....
+ * any suggestions ... send me somes messages about it :)
diff --git a/faad2/src/plugins/xmms/src/Makefile.am b/faad2/src/plugins/xmms/src/Makefile.am
new file mode 100644
index 0000000..33d21fc
--- /dev/null
+++ b/faad2/src/plugins/xmms/src/Makefile.am
@@ -0,0 +1,14 @@
+local_CFLAGS=`$(XMMS_CONFIG) --cflags` -Wall
+local_LDFLAGS=`$(XMMS_CONFIG) --libs`
+libdir = `$(XMMS_CONFIG) --input-plugin-dir`
+lib_LTLIBRARIES = libmp4.la
+
+libmp4_la_CFLAGS = $(local_CFLAGS) -Wall \
+ -I$(top_srcdir)/include -I$(top_srcdir)/common/mp4ff
+
+libmp4_la_LIBADD = $(top_builddir)/libfaad/libfaad.la \
+ $(top_builddir)/common/mp4ff/libmp4ff.a
+
+libmp4_la_LDFLAGS = -module -avoid-version $(local_LDFLAGS) -lpthread
+
+libmp4_la_SOURCES = libmp4.c mp4_utils.c aac_utils.c
diff --git a/faad2/src/plugins/xmms/src/aac_utils.c b/faad2/src/plugins/xmms/src/aac_utils.c
new file mode 100644
index 0000000..45543e6
--- /dev/null
+++ b/faad2/src/plugins/xmms/src/aac_utils.c
@@ -0,0 +1,104 @@
+/*
+ *
+ * utils for AAC informations
+*/
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define ADTS_HEADER_SIZE 8
+#define SEEK_TABLE_CHUNK 60
+#define MPEG4_TYPE 0
+#define MPEG2_TYPE 1
+
+// Read ADTS header, the file descriptor must be at
+// the begining of the aac frame not at the id3tag
+
+int getAacInfo(FILE *fd)
+{
+ unsigned char header[ADTS_HEADER_SIZE];
+ unsigned int id;
+ unsigned long originPosition;
+
+ originPosition = ftell(fd);
+ if(fread(header, 1, ADTS_HEADER_SIZE, fd) != ADTS_HEADER_SIZE){
+ fseek(fd, originPosition, SEEK_SET);
+ return(-1);
+ }
+ if(!((header[0]==0xFF)&&((header[1]& 0xF6)==0xF0))){
+ printf("Bad header\n");
+ return(-1);
+ }
+ id = header[1]&0x08;
+ if(id==0){//MPEG-4 AAC
+ fseek(fd, originPosition, SEEK_SET);
+ return(MPEG4_TYPE);
+ }else{
+ fseek(fd, originPosition, SEEK_SET);
+ return(MPEG2_TYPE);
+ }
+ fseek(fd, originPosition, SEEK_SET);
+ return(-1);
+}
+
+// as AAC is VBR we need to check all ADTS header
+// to enable seeking...
+// there is no other solution
+void checkADTSForSeeking(FILE *fd,
+ unsigned long **seekTable,
+ unsigned long *seekTableLength)
+{
+ unsigned long originPosition;
+ unsigned long position;
+ unsigned char header[ADTS_HEADER_SIZE];
+ unsigned int frameCount, frameLength, frameInsec;
+ unsigned int id=0, seconds=0;
+
+ originPosition = ftell(fd);
+
+ for(frameCount=0,frameInsec=0;; frameCount++,frameInsec++){
+ position = ftell(fd);
+ if(fread(header, 1, ADTS_HEADER_SIZE, fd)!=ADTS_HEADER_SIZE){
+ break;
+ }
+ if(!strncmp(header, "ID3", 3)){
+ break;
+ }
+ if(!((header[0]==0xFF)&&((header[1]& 0xF6)==0xF0))){
+ printf("error : Bad 1st header, file may be corrupt !\n");
+ break;
+ }
+ if(!frameCount){
+ id=header[1]&0x08;
+ if(((*seekTable) = malloc(SEEK_TABLE_CHUNK * sizeof(unsigned long)))==0){
+ printf("malloc error\n");
+ return;
+ }
+ (*seekTableLength) = SEEK_TABLE_CHUNK;
+ }
+
+ //if(id==0){//MPEG-4
+ //frameLength = ((unsigned int)header[4]<<5)|((unsigned int)header[5]>>3);
+ //}else{//MPEG-2
+ frameLength = (((unsigned int)header[3]&0x3)<<11)|((unsigned int)header[4]<<3)|(header[5]>>5);
+ //}
+ if(frameInsec==43){//???
+ frameInsec=0;
+ }
+ if(frameInsec==0){
+ if(seconds == (*seekTableLength)){
+ (*seekTable) = realloc((*seekTable), (seconds+SEEK_TABLE_CHUNK)*sizeof(unsigned long));
+ (*seekTableLength) = seconds+SEEK_TABLE_CHUNK;
+ }
+ (*seekTable)[seconds] = position;
+ seconds++;
+ }
+ if(fseek(fd, frameLength-ADTS_HEADER_SIZE, SEEK_CUR)==-1){
+ break;
+ }
+ }
+ (*seekTableLength) = seconds;
+ fseek(fd, originPosition, SEEK_SET);
+}
diff --git a/faad2/src/plugins/xmms/src/libmp4.c b/faad2/src/plugins/xmms/src/libmp4.c
new file mode 100644
index 0000000..117a087
--- /dev/null
+++ b/faad2/src/plugins/xmms/src/libmp4.c
@@ -0,0 +1,586 @@
+/*
+ * MP4/AAC decoder for xmms
+ *
+ * OPTIONNAL need
+ * --------------
+ * libid3 (3.8.x - www.id3.org)
+*/
+
+#include <pthread.h>
+#include <gtk/gtk.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(HAVE_BMP)
+#include <bmp/plugin.h>
+#include <bmp/util.h>
+#include <bmp/configfile.h>
+#include <bmp/titlestring.h>
+#else
+#include <xmms/plugin.h>
+#include <xmms/util.h>
+#include <xmms/configfile.h>
+#include <xmms/titlestring.h>
+#endif /*HAVE_BMP*/
+
+#include "neaacdec.h"
+#include "mp4ff.h"
+
+#define MP4_DESCRIPTION "MP4 & MPEG2/4-AAC audio player - 1.2.x"
+#define MP4_VERSION "ver. 0.5-faad2-version - 22 August 2004"
+#define MP4_ABOUT "Written by ciberfred"
+#define BUFFER_SIZE FAAD_MIN_STREAMSIZE*64
+
+static void mp4_init(void);
+static void mp4_about(void);
+static void mp4_play(char *);
+static void mp4_stop(void);
+static void mp4_pause(short);
+static void mp4_seek(int);
+static int mp4_getTime(void);
+static void mp4_cleanup(void);
+static void mp4_getSongTitle(char *, char **, int *);
+static void mp4_getSongInfo(char *);
+static int mp4_isFile(char *);
+static void* mp4Decode(void *);
+
+InputPlugin mp4_ip =
+ {
+ 0, // handle
+ 0, // filename
+ MP4_DESCRIPTION,
+ mp4_init,
+ mp4_about,
+ 0, // configuration
+ mp4_isFile,
+ 0, //scandir
+ mp4_play,
+ mp4_stop,
+ mp4_pause,
+ mp4_seek,
+ 0, // set equalizer
+ mp4_getTime,
+ 0, // get volume
+ 0,
+ mp4_cleanup,
+ 0, // obsolete
+ 0, // send visualisation data
+ 0, // set player window info
+ 0, // set song title text
+ mp4_getSongTitle, // get song title text
+ mp4_getSongInfo, // info box
+ 0, // to output plugin
+ };
+
+typedef struct _mp4cfg{
+ gshort file_type;
+#define FILE_UNKNOW 0
+#define FILE_MP4 1
+#define FILE_AAC 2
+} Mp4Config;
+
+static Mp4Config mp4cfg;
+static gboolean bPlaying = FALSE;
+static pthread_t decodeThread;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static int seekPosition = -1;
+
+// Functions from mp4_utils.c
+extern int getAACTrack(mp4ff_t *infile);
+extern mp4ff_callback_t *getMP4FF_cb(FILE *mp4file);
+extern char *getMP4title(mp4ff_t *infile, char *filename);
+extern void getMP4info(char* filename, FILE *mp4file);
+
+InputPlugin *get_iplugin_info(void)
+{
+ return(&mp4_ip);
+}
+
+static void mp4_init(void)
+{
+ memset(&decodeThread, 0, sizeof(pthread_t));
+ mp4cfg.file_type = FILE_UNKNOW;
+ seekPosition = -1;
+ return;
+}
+
+static void mp4_play(char *filename)
+{
+ bPlaying = TRUE;
+ pthread_create(&decodeThread, 0, mp4Decode, g_strdup(filename));
+ return;
+}
+
+static void mp4_stop(void)
+{
+ if(bPlaying){
+ bPlaying = FALSE;
+ pthread_join(decodeThread, NULL);
+ memset(&decodeThread, 0, sizeof(pthread_t));
+ mp4_ip.output->close_audio();
+ }
+}
+
+static int mp4_isFile(char *filename)
+{
+ if(filename){
+ gchar* extention;
+
+ extention = strrchr(filename, '.');
+ if(extention &&
+ (!strncasecmp(extention, ".mp4", 4) || // official extention
+ !strncasecmp(extention, ".m4a", 4) || // Apple mp4 extention
+ !strncasecmp(extention, ".aac", 4) // old MPEG2/4-AAC extention
+ )){
+ return (1);
+ }
+ }
+ return(0);
+}
+
+static void mp4_about(void)
+{
+ static GtkWidget *aboutbox;
+
+ if(aboutbox!=NULL)
+ return;
+ aboutbox = xmms_show_message("About MP4 AAC player plugin",
+ "libfaad2-" FAAD2_VERSION "\n"
+ "plugin version: " MP4_VERSION "\n"
+ MP4_ABOUT,
+ "Ok", FALSE, NULL, NULL);
+ gtk_signal_connect(GTK_OBJECT(aboutbox), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &aboutbox);
+}
+
+static void mp4_pause(short flag)
+{
+ mp4_ip.output->pause(flag);
+}
+
+static void mp4_seek(int time)
+{
+ seekPosition = time;
+ while(bPlaying && seekPosition!=-1)
+ xmms_usleep(10000);
+}
+
+static int mp4_getTime(void)
+{
+ if(!bPlaying)
+ return (-1);
+ else
+ return (mp4_ip.output->output_time());
+}
+
+static void mp4_cleanup(void)
+{
+}
+
+void mp4_get_file_type(FILE *mp4file)
+{
+ unsigned char header[10] = {0};
+
+ fseek(mp4file, 0, SEEK_SET);
+ fread(header, 1, 8, mp4file);
+ if(header[4]=='f' &&
+ header[5]=='t' &&
+ header[6]=='y' &&
+ header[7]=='p'){
+ mp4cfg.file_type = FILE_MP4;
+ }else{
+ mp4cfg.file_type = FILE_AAC;
+ }
+}
+
+static void mp4_getSongTitle(char *filename, char **title, int *len) {
+ FILE* mp4file;
+
+ (*title) = NULL;
+ (*len) = -1;
+
+ if((mp4file = fopen(filename, "rb"))){
+ mp4_get_file_type(mp4file);
+ fseek(mp4file, 0, SEEK_SET);
+ if(mp4cfg.file_type == FILE_MP4){
+ mp4ff_callback_t* mp4cb;
+ mp4ff_t* infile;
+ gint mp4track;
+
+ mp4cb = getMP4FF_cb(mp4file);
+ if ((infile = mp4ff_open_read_metaonly(mp4cb)) &&
+ ((mp4track = getAACTrack(infile)) >= 0)){
+ (*title) = getMP4title(infile, filename);
+
+ double track_duration = mp4ff_get_track_duration(infile, mp4track);
+ unsigned long time_scale = mp4ff_time_scale(infile, mp4track);
+ unsigned long length = (track_duration * 1000 / time_scale);
+ (*len) = length;
+ }
+ if(infile) mp4ff_close(infile);
+ if(mp4cb) g_free(mp4cb);
+ }
+ else{
+ // Check AAC ID3 tag...
+ }
+ fclose(mp4file);
+ }
+}
+
+static void mp4_getSongInfo(char *filename)
+{
+ FILE* mp4file;
+ if((mp4file = fopen(filename, "rb"))){
+ if (mp4cfg.file_type == FILE_UNKNOW)
+ mp4_get_file_type(mp4file);
+ fseek(mp4file, 0, SEEK_SET);
+ if(mp4cfg.file_type == FILE_MP4)
+ getMP4info(filename, mp4file);
+ else if(mp4cfg.file_type == FILE_AAC)
+ /*
+ * check the id3tagv2
+ */
+ ;
+ fclose(mp4file);
+ }
+}
+
+static void *mp4Decode(void *args)
+{
+ FILE* mp4file;
+
+ pthread_mutex_lock(&mutex);
+ seekPosition = -1;
+ bPlaying = TRUE;
+
+ if(!(mp4file = fopen(args, "rb"))){
+ g_print("MP4!AAC - Can't open file\n");
+ g_free(args);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+
+ }
+ mp4_get_file_type(mp4file);
+ fseek(mp4file, 0, SEEK_SET);
+ if(mp4cfg.file_type == FILE_MP4){// We are reading a MP4 file
+ mp4ff_callback_t* mp4cb;
+ mp4ff_t* infile;
+ gint mp4track;
+
+ mp4cb = getMP4FF_cb(mp4file);
+ if(!(infile = mp4ff_open_read(mp4cb))){
+ g_print("MP4 - Can't open file\n");
+ goto end;
+ }
+
+ if((mp4track = getAACTrack(infile)) < 0){
+ /*
+ * TODO: check here for others Audio format.....
+ *
+ */
+ g_print("Unsupported Audio track type\n");
+ g_free(args);
+ fclose(mp4file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }else{
+ NeAACDecHandle decoder;
+ unsigned char *buffer = NULL;
+ guint bufferSize = 0;
+ gulong samplerate;
+ guchar channels;
+ //guint avgBitrate;
+ //MP4Duration duration;
+ int msDuration;
+ int numSamples;
+ int sampleID = 0;
+ unsigned int framesize;
+ mp4AudioSpecificConfig mp4ASC;
+ gchar *xmmstitle;
+
+ decoder = NeAACDecOpen();
+ mp4ff_get_decoder_config(infile, mp4track, &buffer, &bufferSize);
+ if(NeAACDecInit2(decoder, buffer, bufferSize, &samplerate, &channels)<0){
+ goto end;
+ }
+ if(buffer){
+ framesize = 1024;
+ if(NeAACDecAudioSpecificConfig(buffer, bufferSize, &mp4ASC) >= 0){
+ if(mp4ASC.frameLengthFlag == 1) framesize = 960;
+ if(mp4ASC.sbr_present_flag == 1) framesize *= 2;
+ }
+ g_free(buffer);
+ }
+ if(channels == 0){
+ g_print("Number of Channels not supported\n");
+ goto end;
+ }
+
+ //duration = MP4GetTrackDuration(mp4file, mp4track);
+ //msDuration = MP4ConvertFromTrackDuration(mp4file, mp4track,
+ // duration,MP4_MSECS_TIME_SCALE);
+
+ //msDuration = mp4ff_get_track_duration(infile, mp4track);
+ //printf("%d\n", msDuration);
+
+ //numSamples = MP4GetTrackNumberOfSamples(mp4file, mp4track);
+ numSamples = mp4ff_num_samples(infile, mp4track);
+ {
+ float f = 1024.0;
+ if(mp4ASC.sbr_present_flag == 1)
+ f = f * 2.0;
+ msDuration = ((float)numSamples*(float)(f-1.0)/
+ (float)samplerate)*1000;
+ }
+ xmmstitle = getMP4title(infile, args);
+ mp4_ip.output->open_audio(FMT_S16_NE, samplerate, channels);
+ mp4_ip.output->flush(0);
+ mp4_ip.set_info(xmmstitle, msDuration, -1, samplerate/1000, channels);
+ g_print("MP4 - %d channels @ %ld Hz\n", channels, samplerate);
+
+ while(bPlaying){
+ void* sampleBuffer;
+ faacDecFrameInfo frameInfo;
+ gint rc;
+
+ if(seekPosition!=-1){
+ /*
+ duration = MP4ConvertToTrackDuration(mp4file,
+ mp4track,
+ seekPosition*1000,
+ MP4_MSECS_TIME_SCALE);
+ sampleID = MP4GetSampleIdFromTime(mp4file, mp4track, duration, 0);
+ */
+ float f = 1024.0;
+ if(mp4ASC.sbr_present_flag == 1)
+ f = f * 2.0;
+ sampleID = (float)seekPosition*(float)samplerate/(float)(f-1.0);
+ mp4_ip.output->flush(seekPosition*1000);
+ seekPosition = -1;
+ }
+ buffer=NULL;
+ bufferSize=0;
+ rc = mp4ff_read_sample(infile, mp4track, sampleID++,
+ &buffer, &bufferSize);
+ //g_print("%d/%d\n", sampleID-1, numSamples);
+ if((rc==0) || (buffer== NULL)){
+ g_print("MP4: read error\n");
+ sampleBuffer = NULL;
+ sampleID=0;
+ mp4_ip.output->buffer_free();
+ goto end;
+ }else{
+ sampleBuffer = NeAACDecDecode(decoder, &frameInfo, buffer, bufferSize);
+ if(frameInfo.error > 0){
+ g_print("MP4: %s\n",
+ faacDecGetErrorMessage(frameInfo.error));
+ goto end;
+ }
+ if(buffer){
+ g_free(buffer); buffer=NULL; bufferSize=0;
+ }
+ while(bPlaying && mp4_ip.output->buffer_free()<frameInfo.samples<<1)
+ xmms_usleep(30000);
+ }
+ mp4_ip.add_vis_pcm(mp4_ip.output->written_time(),
+ FMT_S16_NE,
+ channels,
+ frameInfo.samples<<1,
+ sampleBuffer);
+ mp4_ip.output->write_audio(sampleBuffer, frameInfo.samples<<1);
+ if(sampleID >= numSamples){
+ break;
+ }
+ }
+ while(bPlaying && mp4_ip.output->buffer_playing() && mp4_ip.output->buffer_free()){
+ xmms_usleep(10000);
+ }
+end:
+ mp4_ip.output->close_audio();
+ g_free(args);
+ NeAACDecClose(decoder);
+ if(infile) mp4ff_close(infile);
+ if(mp4cb) g_free(mp4cb);
+ bPlaying = FALSE;
+ fclose(mp4file);
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ }else{
+ // WE ARE READING AN AAC FILE
+ FILE *file = NULL;
+ NeAACDecHandle decoder = 0;
+ guchar *buffer = 0;
+ gulong bufferconsumed = 0;
+ gulong samplerate = 0;
+ guchar channels;
+ gulong buffervalid = 0;
+ TitleInput* input;
+ gchar *temp = g_strdup(args);
+ gchar *ext = strrchr(temp, '.');
+ gchar *xmmstitle = NULL;
+ NeAACDecConfigurationPtr config;
+
+ if((file = fopen(args, "rb")) == 0){
+ g_print("AAC: can't find file %s\n", args);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ if((decoder = NeAACDecOpen()) == NULL){
+ g_print("AAC: Open Decoder Error\n");
+ fclose(file);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ config = NeAACDecGetCurrentConfiguration(decoder);
+ config->useOldADTSFormat = 0;
+ NeAACDecSetConfiguration(decoder, config);
+ if((buffer = g_malloc(BUFFER_SIZE)) == NULL){
+ g_print("AAC: error g_malloc\n");
+ fclose(file);
+ bPlaying = FALSE;
+ NeAACDecClose(decoder);
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ if((buffervalid = fread(buffer, 1, BUFFER_SIZE, file))==0){
+ g_print("AAC: Error reading file\n");
+ g_free(buffer);
+ fclose(file);
+ bPlaying = FALSE;
+ NeAACDecClose(decoder);
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ XMMS_NEW_TITLEINPUT(input);
+ input->file_name = g_basename(temp);
+ input->file_ext = ext ? ext+1 : NULL;
+ input->file_path = temp;
+ if(!strncmp(buffer, "ID3", 3)){
+ gint size = 0;
+
+ fseek(file, 0, SEEK_SET);
+ size = (buffer[6]<<21) | (buffer[7]<<14) | (buffer[8]<<7) | buffer[9];
+ size+=10;
+ fread(buffer, 1, size, file);
+ buffervalid = fread(buffer, 1, BUFFER_SIZE, file);
+ }
+ xmmstitle = xmms_get_titlestring(xmms_get_gentitle_format(), input);
+ if(xmmstitle == NULL)
+ xmmstitle = g_strdup(input->file_name);
+ if(temp) g_free(temp);
+ if(input->performer) g_free(input->performer);
+ if(input->album_name) g_free(input->album_name);
+ if(input->track_name) g_free(input->track_name);
+ if(input->genre) g_free(input->genre);
+ g_free(input);
+ bufferconsumed = NeAACDecInit(decoder,
+ buffer,
+ buffervalid,
+ &samplerate,
+ &channels);
+ if(mp4_ip.output->open_audio(FMT_S16_NE,samplerate,channels) == FALSE){
+ g_print("AAC: Output Error\n");
+ g_free(buffer); buffer=0;
+ faacDecClose(decoder);
+ fclose(file);
+ mp4_ip.output->close_audio();
+ /*
+ if(positionTable){
+ g_free(positionTable); positionTable=0;
+ }
+ */
+ g_free(xmmstitle);
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+ }
+ //if(bSeek){
+ //mp4_ip.set_info(xmmstitle, lenght*1000, -1, samplerate, channels);
+ //}else{
+ mp4_ip.set_info(xmmstitle, -1, -1, samplerate, channels);
+ //}
+ mp4_ip.output->flush(0);
+
+ while(bPlaying && buffervalid > 0){
+ NeAACDecFrameInfo finfo;
+ unsigned long samplesdecoded;
+ char* sample_buffer = NULL;
+ /*
+ if(bSeek && seekPosition!=-1){
+ fseek(file, positionTable[seekPosition], SEEK_SET);
+ bufferconsumed=0;
+ buffervalid = fread(buffer, 1, BUFFER_SIZE, file);
+ aac_ip.output->flush(seekPosition*1000);
+ seekPosition=-1;
+ }
+ */
+ if(bufferconsumed > 0){
+ memmove(buffer, &buffer[bufferconsumed], buffervalid-bufferconsumed);
+ buffervalid -= bufferconsumed;
+ buffervalid += fread(&buffer[buffervalid], 1,
+ BUFFER_SIZE-buffervalid, file);
+ bufferconsumed = 0;
+ }
+ sample_buffer = NeAACDecDecode(decoder, &finfo, buffer, buffervalid);
+ if(finfo.error){
+ config = NeAACDecGetCurrentConfiguration(decoder);
+ if(config->useOldADTSFormat != 1){
+ NeAACDecClose(decoder);
+ decoder = NeAACDecOpen();
+ config = NeAACDecGetCurrentConfiguration(decoder);
+ config->useOldADTSFormat = 1;
+ NeAACDecSetConfiguration(decoder, config);
+ finfo.bytesconsumed=0;
+ finfo.samples = 0;
+ NeAACDecInit(decoder,
+ buffer,
+ buffervalid,
+ &samplerate,
+ &channels);
+ }else{
+ g_print("FAAD2 Warning %s\n", NeAACDecGetErrorMessage(finfo.error));
+ buffervalid = 0;
+ }
+ }
+ bufferconsumed += finfo.bytesconsumed;
+ samplesdecoded = finfo.samples;
+ if((samplesdecoded<=0) && !sample_buffer){
+ g_print("AAC: error sample decoding\n");
+ continue;
+ }
+ while(bPlaying && mp4_ip.output->buffer_free() < (samplesdecoded<<1)){
+ xmms_usleep(10000);
+ }
+ mp4_ip.add_vis_pcm(mp4_ip.output->written_time(),
+ FMT_S16_LE, channels,
+ samplesdecoded<<1, sample_buffer);
+ mp4_ip.output->write_audio(sample_buffer, samplesdecoded<<1);
+ }
+ while(bPlaying && mp4_ip.output->buffer_playing()){
+ xmms_usleep(10000);
+ }
+ mp4_ip.output->buffer_free();
+ mp4_ip.output->close_audio();
+ bPlaying = FALSE;
+ g_free(buffer);
+ NeAACDecClose(decoder);
+ g_free(xmmstitle);
+ fclose(file);
+ seekPosition = -1;
+ /*
+ if(positionTable){
+ g_free(positionTable); positionTable=0;
+ }
+ */
+ bPlaying = FALSE;
+ pthread_mutex_unlock(&mutex);
+ pthread_exit(NULL);
+
+ }
+}
diff --git a/faad2/src/plugins/xmms/src/mp4_utils.c b/faad2/src/plugins/xmms/src/mp4_utils.c
new file mode 100644
index 0000000..a517963
--- /dev/null
+++ b/faad2/src/plugins/xmms/src/mp4_utils.c
@@ -0,0 +1,469 @@
+/*
+ * some functions for MP4 files
+*/
+
+#include "mp4ff.h"
+#include "faad.h"
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <xmms/plugin.h>
+#include <xmms/titlestring.h>
+#include <xmms/util.h>
+
+const char *mp4AudioNames[]=
+ {
+ "MPEG-1 Audio Layers 1,2 or 3",
+ "MPEG-2 low biterate (MPEG-1 extension) - MP3",
+ "MPEG-2 AAC Main Profile",
+ "MPEG-2 AAC Low Complexity profile",
+ "MPEG-2 AAC SSR profile",
+ "MPEG-4 audio (MPEG-4 AAC)",
+ 0
+ };
+
+/* MPEG-4 Audio types from 14496-3 Table 1.5.1 (from mp4.h)*/
+const char *mpeg4AudioNames[]=
+ {
+ "!!!!MPEG-4 Audio track Invalid !!!!!!!",
+ "MPEG-4 AAC Main profile",
+ "MPEG-4 AAC Low Complexity profile",
+ "MPEG-4 AAC SSR profile",
+ "MPEG-4 AAC Long Term Prediction profile",
+ "MPEG-4 AAC Scalable",
+ "MPEG-4 CELP",
+ "MPEG-4 HVXC",
+ "MPEG-4 Text To Speech",
+ "MPEG-4 Main Synthetic profile",
+ "MPEG-4 Wavetable Synthesis profile",
+ "MPEG-4 MIDI Profile",
+ "MPEG-4 Algorithmic Synthesis and Audio FX profile"
+ };
+
+static GtkWidget *mp4_info_dialog = NULL;
+
+/*
+ * find AAC track
+*/
+
+int getAACTrack(mp4ff_t *infile)
+{
+ int i, rc;
+ int numTracks = mp4ff_total_tracks(infile);
+
+ printf("total-tracks: %d\n", numTracks);
+ for(i=0; i<numTracks; i++){
+ unsigned char* buff = 0;
+ int buff_size = 0;
+ mp4AudioSpecificConfig mp4ASC;
+
+ printf("testing-track: %d\n", i);
+ mp4ff_get_decoder_config(infile, i, &buff, &buff_size);
+ if(buff){
+ rc = NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC);
+ g_free(buff);
+ if(rc < 0)
+ continue;
+ return(i);
+ }
+ }
+ return(-1);
+}
+
+uint32_t read_callback(void *user_data, void *buffer, uint32_t length)
+{
+ return fread(buffer, 1, length, (FILE*)user_data);
+}
+
+uint32_t seek_callback(void *user_data, uint64_t position)
+{
+ return fseek((FILE*)user_data, position, SEEK_SET);
+}
+
+mp4ff_callback_t *getMP4FF_cb(FILE *mp4file)
+{
+ mp4ff_callback_t* mp4cb = malloc(sizeof(mp4ff_callback_t));
+ mp4cb->read = read_callback;
+ mp4cb->seek = seek_callback;
+ mp4cb->user_data = mp4file;
+ return mp4cb;
+}
+
+/*
+ * Function to display an info box for an mp4 file.
+ * This code is based heavily on fileinfo.c from the xmms mpg123
+ * plugin, and the info box layout mimics that plugin.
+*/
+void create_mp4_info_dialog (char *filename, FILE *mp4file, mp4ff_t *infile, gint mp4track)
+{
+ char *window_title, *value, *value2;
+ static GtkWidget *filename_entry, *title_entry, *artist_entry, *album_entry;
+ static GtkWidget *genre_entry, *year_entry, *track_entry, *comment_entry;
+ static GtkWidget *mp4_info_label;
+
+ if (!mp4_info_dialog)
+ {
+ GtkWidget *dialog_vbox1, *vbox1, *hbox2, *hbox3, *hbox4;
+ GtkWidget *frame2, *frame3, *table1, *dialog_action_area1;
+ GtkWidget *filename_label, *title_label, *artist_label, *album_label;
+ GtkWidget *genre_label, *year_label, *track_label, *comment_label;
+ GtkWidget *close_button;
+
+ mp4_info_dialog = gtk_dialog_new ();
+ gtk_object_set_data (GTK_OBJECT (mp4_info_dialog), "mp4_info_dialog", mp4_info_dialog);
+ gtk_window_set_policy (GTK_WINDOW (mp4_info_dialog), TRUE, TRUE, FALSE);
+ gtk_signal_connect(GTK_OBJECT (mp4_info_dialog), "destroy",
+ gtk_widget_destroyed, &mp4_info_dialog);
+
+ dialog_vbox1 = GTK_DIALOG (mp4_info_dialog)->vbox;
+ gtk_object_set_data (GTK_OBJECT (mp4_info_dialog), "dialog_vbox1", dialog_vbox1);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog_vbox1), 3);
+
+ hbox2 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox2);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "hbox2", hbox2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), hbox2, FALSE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox2), 3);
+
+ filename_label = gtk_label_new ("Filename: ");
+ gtk_widget_ref (filename_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "filename_label", filename_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (hbox2), filename_label, FALSE, FALSE, 0);
+
+ filename_entry = gtk_entry_new ();
+ gtk_widget_ref (filename_entry);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "filename_entry", filename_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (hbox2), filename_entry, TRUE, TRUE, 0);
+ gtk_entry_set_editable (GTK_ENTRY (filename_entry), FALSE);
+
+ hbox3 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox3);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "hbox3", hbox3,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), hbox3, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox3), 3);
+
+ frame2 = gtk_frame_new ("Tag Info: ");
+ gtk_widget_ref (frame2);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "frame2", frame2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (hbox3), frame2, TRUE, TRUE, 0);
+
+ table1 = gtk_table_new (6, 2, FALSE);
+ gtk_widget_ref (table1);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "table1", table1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_container_add (GTK_CONTAINER (frame2), table1);
+ gtk_container_set_border_width (GTK_CONTAINER (table1), 5);
+
+ comment_label = gtk_label_new ("Comment: ");
+ gtk_widget_ref (comment_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "comment_label", comment_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), comment_label, 0, 1, 5, 6,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (comment_label), 1, 0.5);
+
+ genre_label = gtk_label_new ("Genre: ");
+ gtk_widget_ref (genre_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "genre_label", genre_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), genre_label, 0, 1, 4, 5,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (genre_label), 1, 0.5);
+
+ album_label = gtk_label_new ("Album: ");
+ gtk_widget_ref (album_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "album_label", album_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), album_label, 0, 1, 2, 3,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (album_label), 1, 0.5);
+
+ title_label = gtk_label_new ("Title: ");
+ gtk_widget_ref (title_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "title_label", title_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), title_label, 0, 1, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (title_label), 1, 0.5);
+
+ artist_label = gtk_label_new ("Artist: ");
+ gtk_widget_ref (artist_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "artist_label", artist_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), artist_label, 0, 1, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (artist_label), 1, 0.5);
+
+ year_label = gtk_label_new ("Year: ");
+ gtk_widget_ref (year_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "year_label", year_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), year_label, 0, 1, 3, 4,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (year_label), 1, 0.5);
+
+ hbox4 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_ref (hbox4);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "hbox4", hbox4,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), hbox4, 1, 2, 3, 4,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (GTK_FILL), 0, 0);
+
+ year_entry = gtk_entry_new ();
+ gtk_widget_ref (year_entry);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "year_entry", year_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (hbox4), year_entry, FALSE, FALSE, 0);
+ gtk_widget_set_usize (year_entry, 60, -2);
+ gtk_entry_set_editable (GTK_ENTRY (year_entry), FALSE);
+
+ track_label = gtk_label_new (" Track: ");
+ gtk_widget_ref (track_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "track_label", track_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (hbox4), track_label, FALSE, FALSE, 0);
+ gtk_misc_set_alignment (GTK_MISC (track_label), 1, 0.5);
+
+ track_entry = gtk_entry_new ();
+ gtk_widget_ref (track_entry);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "track_entry", track_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (hbox4), track_entry, FALSE, FALSE, 0);
+ gtk_widget_set_usize (track_entry, 60, -2);
+ gtk_entry_set_editable (GTK_ENTRY (track_entry), FALSE);
+
+ title_entry = gtk_entry_new ();
+ gtk_widget_ref (title_entry);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "title_entry", title_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), title_entry, 1, 2, 0, 1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_entry_set_editable (GTK_ENTRY (title_entry), FALSE);
+
+ artist_entry = gtk_entry_new ();
+ gtk_widget_ref (artist_entry);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "artist_entry", artist_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), artist_entry, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_entry_set_editable (GTK_ENTRY (artist_entry), FALSE);
+
+ album_entry = gtk_entry_new ();
+ gtk_widget_ref (album_entry);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "album_entry", album_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), album_entry, 1, 2, 2, 3,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_entry_set_editable (GTK_ENTRY (album_entry), FALSE);
+
+ genre_entry = gtk_entry_new ();
+ gtk_widget_ref (genre_entry);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "genre_entry", genre_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), genre_entry, 1, 2, 4, 5,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_entry_set_editable (GTK_ENTRY (genre_entry), FALSE);
+
+ comment_entry = gtk_entry_new ();
+ gtk_widget_ref (comment_entry);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "comment_entry", comment_entry,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_table_attach (GTK_TABLE (table1), comment_entry, 1, 2, 5, 6,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_entry_set_editable (GTK_ENTRY (comment_entry), FALSE);
+
+ frame3 = gtk_frame_new ("MP4 Info: ");
+ gtk_widget_ref (frame3);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "frame3", frame3,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (hbox3), frame3, FALSE, TRUE, 0);
+
+ vbox1 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_ref (vbox1);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "vbox1", vbox1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_container_add (GTK_CONTAINER (frame3), vbox1);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox1), 5);
+
+ mp4_info_label = gtk_label_new ("");
+ gtk_widget_ref (mp4_info_label);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "mp4_info_label", mp4_info_label,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (vbox1), mp4_info_label, TRUE, TRUE, 0);
+ gtk_label_set_justify (GTK_LABEL (mp4_info_label), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment (GTK_MISC (mp4_info_label), 0, 0);
+
+ dialog_action_area1 = GTK_DIALOG (mp4_info_dialog)->action_area;
+ gtk_object_set_data (GTK_OBJECT (mp4_info_dialog), "dialog_action_area1", dialog_action_area1);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area1), 4);
+
+ close_button = gtk_button_new_with_label ("Close");
+ gtk_widget_ref (close_button);
+ gtk_object_set_data_full (GTK_OBJECT (mp4_info_dialog), "close_button", close_button,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_box_pack_start (GTK_BOX (dialog_action_area1), close_button, FALSE, FALSE, 0);
+
+ gtk_signal_connect_object (GTK_OBJECT (close_button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (mp4_info_dialog));
+
+ }
+
+ window_title = g_strdup_printf("File Info - %s", g_basename(filename));
+ gtk_window_set_title (GTK_WINDOW (mp4_info_dialog), window_title);
+ g_free(window_title);
+
+ gtk_entry_set_text (GTK_ENTRY (filename_entry), filename);
+
+ gtk_entry_set_text (GTK_ENTRY (title_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (artist_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (album_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (year_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (track_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (genre_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (comment_entry), "");
+
+ if ((mp4ff_meta_get_title(infile, &value)) && value != NULL) {
+ gtk_entry_set_text (GTK_ENTRY(title_entry), value);
+ g_free(value);
+ }
+ if ((mp4ff_meta_get_artist(infile, &value)) && value != NULL) {
+ gtk_entry_set_text (GTK_ENTRY(artist_entry), value);
+ g_free(value);
+ }
+ if ((mp4ff_meta_get_album(infile, &value)) && value != NULL) {
+ gtk_entry_set_text (GTK_ENTRY(album_entry), value);
+ g_free(value);
+ }
+ if ((mp4ff_meta_get_date(infile, &value)) && value != NULL) {
+ gtk_entry_set_text (GTK_ENTRY(year_entry), value);
+ g_free(value);
+ }
+ if ((mp4ff_meta_get_track(infile, &value)) && value != NULL) {
+ if ((mp4ff_meta_get_totaltracks(infile, &value2)) && value2 != NULL) {
+ char *tmp = g_strdup_printf("%s of %s", value, value2);
+ g_free(value2);
+ g_free(value);
+ value = tmp;
+ }
+ gtk_entry_set_text (GTK_ENTRY(track_entry), value);
+ g_free(value);
+ }
+ if ((mp4ff_meta_get_genre(infile, &value)) && value != NULL) {
+ gtk_entry_set_text (GTK_ENTRY(genre_entry), value);
+ g_free(value);
+ }
+ if ((mp4ff_meta_get_comment(infile, &value)) && value != NULL) {
+ gtk_entry_set_text (GTK_ENTRY(comment_entry), value);
+ g_free(value);
+ }
+
+ // Get the length of the track.
+ double track_duration = mp4ff_get_track_duration(infile, mp4track);
+ unsigned long time_scale = mp4ff_time_scale(infile, mp4track);
+ unsigned long length = (track_duration / time_scale);
+ int min = length / 60;
+ int sec = length % 60;
+
+ // Get other info about the track.
+ unsigned long bitrate = mp4ff_get_avg_bitrate(infile, mp4track) / 1000;
+ unsigned long samplerate = mp4ff_get_sample_rate(infile, mp4track);
+ unsigned long channels = mp4ff_get_channel_count(infile, mp4track);
+ unsigned long audio_type = mp4ff_get_audio_type(infile, mp4track);
+ fseek(mp4file, 0, SEEK_END);
+ int filesize = ftell(mp4file) / 1024;
+
+ value = g_strdup_printf("Length: %d:%d\nAvg. Bitrate: %ld kbps\nSample Rate: %ld Hz\nChannels: %ld\nAudio Type: %ld\nFile Size: %d KB", min, sec, bitrate, samplerate, channels, audio_type, filesize);
+ gtk_label_set_text (GTK_LABEL(mp4_info_label), value);
+ g_free(value);
+
+ gtk_widget_show_all(mp4_info_dialog);
+}
+
+
+void getMP4info(char* filename, FILE* mp4file)
+{
+ mp4ff_callback_t* mp4cb;
+ mp4ff_t* infile;
+ gint mp4track;
+
+ mp4cb = getMP4FF_cb(mp4file);
+ if ((infile = mp4ff_open_read_metaonly(mp4cb)) &&
+ ((mp4track = getAACTrack(infile)) >= 0)){
+ create_mp4_info_dialog (filename, mp4file, infile, mp4track);
+ }
+ if(infile) mp4ff_close(infile);
+ if(mp4cb) g_free(mp4cb);
+}
+
+/* Get the xmms titlestring for the file based on metadata.
+The following code was adapted from the gtkpod project, specifically
+mp4file.c (C) Jorg Schuler, but written to use the mp4ff library. The
+mpg123 input plugin for xmms was used as a guide for this function.
+ --Jason Arroyo, 2004 */
+char *getMP4title(mp4ff_t *infile, char *filename) {
+ char *ret=NULL;
+ gchar *value, *path, *temp;
+
+ TitleInput *input;
+ XMMS_NEW_TITLEINPUT(input);
+
+ // Fill in the TitleInput with the relevant data
+ // from the mp4 file that can be used to display the title.
+ mp4ff_meta_get_title(infile, &input->track_name);
+ mp4ff_meta_get_artist(infile, &input->performer);
+ mp4ff_meta_get_album(infile, &input->album_name);
+ if (mp4ff_meta_get_track(infile, &value) && value != NULL) {
+ input->track_number = atoi(value);
+ g_free(value);
+ }
+ if (mp4ff_meta_get_date(infile, &value) && value != NULL) {
+ input->year = atoi(value);
+ g_free(value);
+ }
+ mp4ff_meta_get_genre(infile, &input->genre);
+ mp4ff_meta_get_comment(infile, &input->comment);
+ input->file_name = g_strdup(g_basename(filename));
+ path = g_strdup(filename);
+ temp = strrchr(path, '.');
+ if (temp != NULL) {++temp;}
+ input->file_ext = g_strdup_printf("%s", temp);
+ temp = strrchr(path, '/');
+ if (temp) {*temp = '\0';}
+ input->file_path = g_strdup_printf("%s/", path);
+
+ // Use the default xmms title format to format the
+ // title from the above info.
+ ret = xmms_get_titlestring(xmms_get_gentitle_format(), input);
+
+ g_free(input->track_name);
+ g_free(input->performer);
+ g_free(input->album_name);
+ g_free(input->genre);
+ g_free(input->comment);
+ g_free(input->file_name);
+ g_free(input->file_ext);
+ g_free(input->file_path);
+ g_free(input);
+ g_free(path);
+
+ return ret;
+}