ref: 28139279d1c1df736e0db341f30b70ab080e1326
dir: /plugins/winamp/in_faad.c/
/*
** FAAD - Freeware Advanced Audio Decoder
** Copyright (C) 2002 M. Bakker
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** $Id: in_faad.c,v 1.3 2002/02/18 10:01:05 menno Exp $
**/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <commctrl.h>
#include "resource.h"
#include <faad.h>
#include <stdlib.h>
#include <stdio.h>
#include <aacinfo.h>
#include <filestream.h>
#include <id3v2tag.h>
#include "in2.h"
static char app_name[] = "AudioCoding.com AAC Player";
// post this to the main window at end of file (after playback has stopped)
#define WM_WA_AAC_EOF WM_USER+2
faadAACInfo file_info;
faacDecHandle hDecoder;
faacDecFrameInfo frameInfo;
In_Module mod; // the output module (declared near the bottom of this file)
char *lastfn; // currently playing file (used for getting info on the current file)
int file_length; // file length, in bytes
int decode_pos_ms; // current decoding position, in milliseconds
int paused; // are we paused?
int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.
char *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
int PlayThreadAlive=0; // 1=play thread still running
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
BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
// 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;
char m_format_string[50] = "%1 - %2";
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))
static void config_init()
{
char *p=INI_FILE;
GetModuleFileName(NULL,INI_FILE,sizeof(INI_FILE));
while (*p) p++;
while (p >= INI_FILE && *p != '.') p--;
strcpy(p+1,"ini");
}
void config_read()
{
char variable_bitrate_display[10];
char priority[10];
char memmap_file[10];
char local_buffer_size[10];
char stream_buffer_size[10];
config_init();
strcpy(variable_bitrate_display, "1");
strcpy(priority, "4");
strcpy(memmap_file, "0");
strcpy(local_buffer_size, "128");
strcpy(stream_buffer_size, "64");
RS(variable_bitrate_display);
RS(priority);
RS(m_format_string);
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(m_format_string);
WS(memmap_file);
WS(local_buffer_size);
WS(stream_buffer_size);
}
void config(HWND hwndParent)
{
DialogBox(mod.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG), hwndParent, config_dialog_proc);
}
BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
char tmp[10];
switch (message)
{
case WM_INITDIALOG:
SetDlgItemText(hwndDlg, IDC_FORMAT, m_format_string);
/* 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);
GetDlgItemText(hwndDlg, IDC_FORMAT, m_format_string, 50);
config_write();
case IDCANCEL:
case CANCEL_BTN:
/* User hit Cancel or the X, just close without saving buffer settings */
EndDialog(hwndDlg, wParam);
return TRUE;
}
}
return FALSE;
}
void about(HWND hwndParent)
{
MessageBox(hwndParent,"AudioCoding.com AAC Player\n"
"Compiled on: " __DATE__ "\n"
"http://www.audiocoding.com\n"
"Copyright 2002 AudioCoding.com",
"About AAC Player",MB_OK);
}
void init()
{
char plugin_path[1024];
int i;
config_read();
hInstance_for_id3editor = mod.hDllInstance;
buffer = (unsigned char*)LocalAlloc(LPTR, 768*2);
lastfn = (char*)LocalAlloc(LPTR, 1024*sizeof(char));
/* Initialize winsock, necessary for streaming */
WinsockInit();
}
void quit()
{
if (lastfn) LocalFree(lastfn);
if (buffer) LocalFree(buffer);
/* Deallocate winsock */
WinsockDeInit();
if(seek_table)
{
free(seek_table);
seek_table = NULL;
seek_table_length = 0;
}
}
int isourfile(char *fn)
{
/* Finally fixed */
if(StringComp(fn + strlen(fn) - 3, "aac", 3) == 0)
{
return 1;
}
return 0;
}
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, &samplerate, &channels)) < 0)
{
MessageBox(mod.hMainWindow, "Error opening input file\n", "FAAD Error", MB_OK);
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, &samplerate, &channels)) < 0)
{
MessageBox(mod.hMainWindow, "Error opening input file\n", "FAAD Error", MB_OK);
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;
}
int play(char *fn)
{
int maxlatency;
int thread_id;
current_file_mode = m_memmap_file;
if (current_file_mode) {
if (play_memmap(fn))
return -1;
} else {
if (play_file(fn))
return -1;
}
if(seek_table)
{
free(seek_table);
seek_table = NULL;
seek_table_length = 0;
}
get_AAC_format(fn, &file_info, &seek_table, &seek_table_length, 0);
if(infile->http)
{
/* No seeking in http streams */
mod.is_seekable = 0;
}
else
{
if (file_info.headertype == 2) /* ADTS header - seekable */
mod.is_seekable = 1;
else
mod.is_seekable = 0; /* ADIF or Headerless - not seekable */
}
strcpy(lastfn,fn);
paused=0;
decode_pos_ms=0;
seek_needed=-1;
/*
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;
maxlatency = mod.outMod->Open(file_info.sampling_rate, file_info.channels, 16, -1,-1);
if (maxlatency < 0) // error opening device
{
return -1;
}
// initialize vis stuff
mod.SAVSAInit(maxlatency, file_info.sampling_rate);
mod.VSASetInfo(file_info.sampling_rate, file_info.channels);
mod.SetInfo(file_info.bitrate/1000, file_info.sampling_rate/1000, file_info.channels,1);
mod.outMod->SetVolume(-666); // set the output plug-ins default volume
killPlayThread = 0;
if((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) PlayThread, (void *) &killPlayThread, 0, &thread_id)) == NULL)
{
MessageBox(mod.hMainWindow, "Fatal error: Cannot create playback thread\n", "FAAD Error", MB_OK);
return -1;
}
// 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 0;
}
void pause() { paused=1; mod.outMod->Pause(1); }
void unpause() { paused=0; mod.outMod->Pause(0); }
int ispaused() { return paused; }
void stop()
{
killPlayThread=1;
if (play_thread_handle != INVALID_HANDLE_VALUE)
{
if (WaitForSingleObject(play_thread_handle, INFINITE) == WAIT_TIMEOUT)
TerminateThread(play_thread_handle,0);
CloseHandle(play_thread_handle);
play_thread_handle = INVALID_HANDLE_VALUE;
}
faacDecClose(hDecoder);
close_filestream(infile);
mod.outMod->Close();
mod.SAVSADeInit();
if (memmap_buffer) LocalFree(memmap_buffer);
if(seek_table)
{
free(seek_table);
seek_table = NULL;
seek_table_length = 0;
}
}
int getlength()
{
return file_info.length;
}
int getoutputtime()
{
return decode_pos_ms+(mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime());
}
void setoutputtime(int time_in_ms)
{
if (file_info.headertype == 2)
seek_needed=time_in_ms;
else
seek_needed = -1;
}
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 EnableCheckbox(HWND checkBox, BOOL bEnable, BOOL bChecked)
{
if (bEnable) {
EnableWindow(checkBox, TRUE);
SendMessage(checkBox, BM_SETCHECK, bChecked?BST_CHECKED:BST_UNCHECKED, 0);
} else {
EnableWindow(checkBox, FALSE);
SendMessage(checkBox, BM_SETCHECK, bChecked?BST_CHECKED:BST_UNCHECKED, 0);
}
}
void setvolume(int volume) { mod.outMod->SetVolume(volume); }
void setpan(int pan) { mod.outMod->SetPan(pan); }
char info_fn[255];
BOOL bFileChanged;
BOOL CALLBACK info_dialog_proc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
faadAACInfo format;
char *tmp_string;
char info[1024];
LV_COLUMN lvc;
BOOL bResult;
switch (message) {
case WM_INITDIALOG:
/* Set up the list control for the ID3 tag */
/* Initialize the LV_COLUMN structure. */
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvc.fmt = LVCFMT_LEFT;
/* Add the columns. */
lvc.iSubItem = 0;
lvc.cx = 100;
lvc.pszText = "Frame";
ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_ID3LIST), 0, &lvc);
lvc.iSubItem = 1;
lvc.cx = 250;
lvc.pszText = "Data";
ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_ID3LIST), 1, &lvc);
/* get AAC info */
get_AAC_format(info_fn, &format, NULL, NULL, 1);
switch(format.headertype)
{
case 0: /* Headerless */
tmp_string = "RAW"; break;
case 1: /* ADIF */
tmp_string = "ADIF"; break;
case 2: /* ADTS */
tmp_string = "ADTS"; break;
}
SetDlgItemText(hwndDlg, IDC_HEADER, tmp_string);
if (format.object_type == 0 /* Main */)
tmp_string = "Main";
else if (format.object_type == 1 /* Low Complexity */)
tmp_string = "Low Complexity";
else if (format.object_type == 2 /* SSR */)
tmp_string = "SSR (unsupported)";
else if (format.object_type == 3 /* LTP */)
tmp_string = "Main LTP";
SetDlgItemText(hwndDlg, IDC_PROFILE, tmp_string);
if (format.version == 2) tmp_string = "MPEG2";
else tmp_string = "MPEG4";
SetDlgItemText(hwndDlg, IDC_VERSION, tmp_string);
wsprintf(info, "%d bps", format.bitrate);
SetDlgItemText(hwndDlg, IDC_BITRATE, info);
wsprintf(info, "%d Hz", format.sampling_rate);
SetDlgItemText(hwndDlg, IDC_SAMPLERATE, info);
wsprintf(info, "%d ch", format.channels);
SetDlgItemText(hwndDlg, IDC_CHANNELS, info);
FillID3List(hwndDlg, GetDlgItem(hwndDlg, IDC_ID3LIST), info_fn);
if (ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_ID3LIST)) == 0)
EnableWindow(GetDlgItem(hwndDlg, IDC_ID3V2TAG), FALSE);
else
EnableCheckbox(GetDlgItem(hwndDlg, IDC_ID3V2TAG), TRUE, TRUE);
bFileChanged = FALSE;
return TRUE;
case WM_NOTIFY:
/* Branch depending on the specific notification message. */
switch (((LPNMHDR) lParam)->code) {
/* Process LVN_GETDISPINFO to supply information about */
/* callback items. */
case LVN_GETDISPINFO:
List_OnGetDispInfo((LV_DISPINFO *)lParam);
break;
case NM_DBLCLK:
bResult = List_EditData(hwndDlg, GetDlgItem(hwndDlg, IDC_ID3LIST));
if (bResult)
EnableCheckbox(GetDlgItem(hwndDlg, IDC_ID3V2TAG), TRUE, TRUE);
bFileChanged = bFileChanged ? bFileChanged : bResult;
break;
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_ADDSTFRAMES:
bResult = List_AddStandardFrames(hwndDlg, GetDlgItem(hwndDlg, IDC_ID3LIST));
if (bResult)
EnableCheckbox(GetDlgItem(hwndDlg, IDC_ID3V2TAG), TRUE, TRUE);
bFileChanged = bFileChanged ? bFileChanged : bResult;
return TRUE;
case IDC_ADDFRAME:
bResult = List_AddFrame(hwndDlg, GetDlgItem(hwndDlg, IDC_ID3LIST));
if (bResult)
EnableCheckbox(GetDlgItem(hwndDlg, IDC_ID3V2TAG), TRUE, TRUE);
bFileChanged = bFileChanged ? bFileChanged : bResult;
return TRUE;
case IDC_DELFRAME:
bResult = List_DeleteSelected(hwndDlg, GetDlgItem(hwndDlg, IDC_ID3LIST));
if (ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_ID3LIST)) == 0)
EnableCheckbox(GetDlgItem(hwndDlg, IDC_ID3V2TAG), FALSE, FALSE);
bFileChanged = bFileChanged ? bFileChanged : bResult;
return TRUE;
case IDC_EDITFRAME:
bResult = List_EditData(hwndDlg, GetDlgItem(hwndDlg, IDC_ID3LIST));
if (bResult)
EnableCheckbox(GetDlgItem(hwndDlg, IDC_ID3V2TAG), TRUE, TRUE);
bFileChanged = bFileChanged ? bFileChanged : bResult;
return TRUE;
case IDC_ID3V2TAG:
bFileChanged = TRUE;
return TRUE;
case IDC_CLOSE:
case IDCANCEL:
if (bFileChanged == TRUE) {
if (MessageBox(hwndDlg, "Save changes?", "Save changes", MB_YESNO) == IDYES)
List_SaveID3(hwndDlg, GetDlgItem(hwndDlg, IDC_ID3LIST), info_fn);
}
EndDialog(hwndDlg, wParam);
return TRUE;
}
}
return FALSE;
}
int infoDlg(char *fn, HWND hwnd)
{
lstrcpy(info_fn, fn);
DialogBox(mod.hDllInstance, MAKEINTRESOURCE(IDD_INFO),
hwnd, info_dialog_proc);
return 0;
}
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
}
int getsonglength(char *fn)
{
faadAACInfo tmp;
get_AAC_format(fn, &tmp, NULL, NULL, 1);
return tmp.length;
}
void getfileinfo(char *filename, char *title, int *length_in_ms)
{
if (!filename || !*filename) // currently playing file
{
if (length_in_ms)
*length_in_ms=getlength();
if (title)
GetID3FileTitle(lastfn, title, m_format_string);
}
else // some other file
{
if (length_in_ms)
*length_in_ms = getsonglength(filename);
if (title)
GetID3FileTitle(filename, title, m_format_string);
}
}
void eq_set(int on, char data[10], int preamp)
{
}
int last_frame;
int PlayThread_memmap()
{
sample_buffer = (char*)faacDecDecode(hDecoder, &frameInfo, memmap_buffer + memmap_index);
if (frameInfo.error)
{
MessageBox(NULL, faacDecGetErrorMessage(frameInfo.error), "FAAD Error", MB_OK);
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);
if (frameInfo.error)
{
MessageBox(NULL, faacDecGetErrorMessage(frameInfo.error), "FAAD Error", MB_OK);
last_frame = 1;
}
buffercount += frameInfo.bytesconsumed;
bytecount += frameInfo.bytesconsumed;
if (bytecount >= fileread)
last_frame = 1;
return frameInfo.bytesconsumed;
}
DWORD WINAPI PlayThread(void *b)
{
int done=0;
int l;
int decoded_frames=0;
int br_calc_frames=0;
int br_bytes_consumed=0;
unsigned long bytesconsumed;
PlayThreadAlive = 1;
last_frame = 0;
while (! *((int *)b) )
{
if (seek_needed != -1)
{
int seconds;
// Round off to a second
seconds = seek_needed - (seek_needed%1000);
mod.outMod->Flush(decode_pos_ms);
aac_seek(seconds, seek_table);
decode_pos_ms = seconds;
seek_needed = -1;
decoded_frames = 0;
br_calc_frames = 0;
br_bytes_consumed = 0;
}
if (done)
{
mod.outMod->CanWrite();
if (!mod.outMod->IsPlaying())
{
PostMessage(mod.hMainWindow,WM_WA_AAC_EOF,0,0);
PlayThreadAlive = 0;
return 0;
}
Sleep(10);
}
//assume that max channels is 2.
else if (mod.outMod->CanWrite() >= ((1024*file_info.channels*sizeof(short))<<(mod.dsp_isactive()?1:0)))
{
if(last_frame)
{
done=1;
}
else
{
if (current_file_mode)
bytesconsumed = PlayThread_memmap();
else
bytesconsumed = PlayThread_file();
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)
{
int br;
br = (int)((br_bytes_consumed * 8) / (decoded_frames / 43.07));
mod.SetInfo(br/1000, file_info.sampling_rate/1000, file_info.channels, 1);
br_calc_frames = 0;
}
if (!killPlayThread && (frameInfo.samples > 0))
{
mod.SAAddPCMData(sample_buffer,file_info.channels, 16, decode_pos_ms);
mod.VSAAddPCMData(sample_buffer,file_info.channels, 16, decode_pos_ms);
decode_pos_ms+=(1024*1000)/file_info.sampling_rate;
if (mod.dsp_isactive())
l=mod.dsp_dosamples((short *)sample_buffer,frameInfo.samples*sizeof(short)/file_info.channels/(16/8),16,file_info.channels,file_info.sampling_rate)*(file_info.channels*(16/8));
else
l = frameInfo.samples*sizeof(short);
mod.outMod->Write(sample_buffer, l);
}
}
}
else
{
Sleep(10);
}
}
if(seek_table)
{
free(seek_table);
seek_table = NULL;
seek_table_length = 0;
}
PlayThreadAlive = 0;
return 0;
}
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;
}
}
In_Module mod =
{
IN_VER,
"AudioCoding.com AAC Player: " __DATE__,
0, // hMainWindow
0, // hDllInstance
"AAC\0AAC File (*.AAC)\0"
,
1, // is_seekable
1, // uses output
config,
about,
init,
quit,
getfileinfo,
infoDlg,
isourfile,
play,
pause,
unpause,
ispaused,
stop,
getlength,
getoutputtime,
setoutputtime,
setvolume,
setpan,
0,0,0,0,0,0,0,0,0, // vis stuff
0,0, // dsp
eq_set,
NULL, // setinfo
0 // out_mod
};
__declspec( dllexport ) In_Module * winampGetInModule2()
{
return &mod;
}