ref: a929acdf788d7899bf2631e0f8b9a2acdae09ef7
dir: /plugins/cooledit/Faad.cpp/
#include <windows.h> #include <stdio.h> // FILE * #include "filters.h" //CoolEdit #include "faad.h" #include "faac.h" #include "aacinfo.h" #include "..\..\..\faad2\common\mp4v2\mp4.h" #define MAX_CHANNELS 2 #define QWORD __int32 typedef struct input_tag // any special vars associated with input file { //AAC FILE *fFile; DWORD lSize; DWORD tagsize; DWORD bytes_read; // from file DWORD bytes_consumed; // by faadDecDecode long bytes_into_buffer; unsigned char *buffer; //MP4 MP4FileHandle mp4File; MP4SampleId sampleId, numSamples; int track; unsigned char type; // GENERAL faacDecHandle hDecoder; faadAACInfo file_info; QWORD len_ms; WORD wChannels; DWORD dwSamprate; WORD wBitsPerSample; char szName[256]; DWORD full_size; // size of decoded file needed to set the length of progress bar bool IsAAC; } MYINPUT; static const char* mpeg4AudioNames[]= { "Raw PCM", "AAC Main", "AAC Low Complexity", "AAC SSR", "AAC LTP", "Reserved", "AAC Scalable", "TwinVQ", "CELP", "HVXC", "Reserved", "Reserved", "TTSI", "Wavetable synthesis", "General MIDI", "Algorithmic Synthesis and Audio FX", "Reserved" }; int id3v2_tag(unsigned char *buffer) { if(StringComp((const char *)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; } int GetAACTrack(MP4FileHandle infile) { /* find AAC track */ int i, rc; int numTracks = MP4GetNumberOfTracks(infile, NULL); for (i = 0; i < numTracks; i++) { MP4TrackId trackId = MP4FindTrackId(infile, i, NULL); const char* trackType = MP4GetTrackType(infile, trackId); if (!strcmp(trackType, MP4_AUDIO_TRACK_TYPE)) { unsigned char *buff = NULL; unsigned __int32 buff_size = 0; DWORD dummy; unsigned char ch_dummy; MP4GetTrackESConfiguration(infile, trackId, &buff, &buff_size); if (buff) { rc = AudioSpecificConfig(buff, &dummy, &ch_dummy, &ch_dummy, &ch_dummy); free(buff); if (rc < 0) return -1; return trackId; } } } /* can't decode this */ return -1; } // ********************************************************************************************* __declspec(dllexport) BOOL FAR PASCAL FilterUnderstandsFormat(LPSTR filename) { WORD len; if((len=lstrlen(filename))>4 && (!strcmpi(filename+len-4,".aac") || !strcmpi(filename+len-4,".mp4"))) return TRUE; return FALSE; } __declspec(dllexport) long FAR PASCAL FilterGetFileSize(HANDLE hInput) { DWORD full_size; if(hInput) { MYINPUT *mi; mi=(MYINPUT *)GlobalLock(hInput); full_size=mi->full_size; GlobalUnlock(hInput); } return full_size; } __declspec(dllexport) DWORD FAR PASCAL FilterOptionsString(HANDLE hInput, LPSTR szString) { char buf[20]; if(hInput) { MYINPUT *mi; mi=(MYINPUT *)GlobalLock(hInput); lstrcpy(szString,""); if(mi->file_info.version == 2) lstrcat(szString,"MPEG2 - "); else lstrcat(szString,"MPEG4 - "); sprintf(buf,"%lu bps\n",mi->file_info.bitrate); lstrcat(szString,buf); if(mi->IsAAC) { switch(mi->file_info.headertype) { case 0: lstrcat(szString,"RAW\n"); return 0L; case 1: lstrcat(szString,"ADIF\n"); break; case 2: lstrcat(szString,"ADTS\n"); break; } switch(mi->file_info.object_type) { case MAIN: lstrcat(szString,"Main"); break; case LOW: lstrcat(szString,"Low Complexity"); break; case SSR: lstrcat(szString,"SSR (unsupported)"); break; case LTP: lstrcat(szString,"Main LTP"); break; } } else lstrcat(szString,mpeg4AudioNames[mi->type]); GlobalUnlock(hInput); } return 1; } __declspec(dllexport) DWORD FAR PASCAL FilterGetFirstSpecialData(HANDLE hInput, SPECIALDATA * psp) { return 0L; } __declspec(dllexport) DWORD FAR PASCAL FilterGetNextSpecialData(HANDLE hInput, SPECIALDATA * psp) { return 0; // only has 1 special data! Otherwise we would use psp->hSpecialData // as either a counter to know which item to retrieve next, or as a // structure with other state information in it. } __declspec(dllexport) void FAR PASCAL CloseFilterInput(HANDLE hInput) { if(hInput) { MYINPUT far *mi; mi=(MYINPUT far *)GlobalLock(hInput); if(mi->fFile) fclose(mi->fFile); if(mi->buffer) free(mi->buffer); if(mi->hDecoder) faacDecClose(mi->hDecoder); GlobalUnlock(hInput); GlobalFree(hInput); } } #define ERROR_ON_OPEN_MP4(msg) \ { \ MessageBox(0, msg, "FAAD interface", MB_OK); \ if(infile) \ MP4Close(infile); \ if(hDecoder) \ faacDecClose(hDecoder); \ GlobalUnlock(hInput); \ return 0; \ } #define ERROR_ON_OPEN_AAC(msg) \ { \ MessageBox(0, msg, "FAAD interface", MB_OK); \ fclose(infile); \ if(buffer) \ free(buffer); \ if(hDecoder) \ faacDecClose(hDecoder); \ GlobalUnlock(hInput); \ return 0; \ } // return handle that will be passed in to close, and write routines __declspec(dllexport) HANDLE FAR PASCAL OpenFilterInput( LPSTR lpstrFilename, long far *lSamprate, WORD far *wBitsPerSample, WORD far *wChannels, HWND hWnd, long far *lChunkSize) { HANDLE hInput; MYINPUT *mi; faacDecHandle hDecoder=0; faacDecConfigurationPtr config; DWORD tmp; DWORD samplerate; unsigned char channels; unsigned char *buffer=0; hInput=GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE|GMEM_ZEROINIT,sizeof(MYINPUT)); if(!hInput) return 0; mi=(MYINPUT *)GlobalLock(hInput); memset(mi,0,sizeof(MYINPUT)); mi->IsAAC=strcmpi(lpstrFilename+lstrlen(lpstrFilename)-4,".aac")==0; if(!mi->IsAAC) // MP4 file --------------------------------------------------------------------- { // faacDecFrameInfo frameInfo; MP4FileHandle infile; MP4SampleId numSamples; MP4Duration length; int fileType=FAAD_FMT_16BIT; // default int track; unsigned __int32 buffer_size; unsigned long timeScale; unsigned char sf; if(!(infile = MP4Read(lpstrFilename, 0))) ERROR_ON_OPEN_MP4("Error opening file"); mi->mp4File=infile; if ((track = GetAACTrack(infile)) < 0) ERROR_ON_OPEN_MP4("Unable to find correct AAC sound track in the MP4 file"); length = MP4GetTrackDuration(infile, track); mi->len_ms=(DWORD) MP4ConvertFromTrackDuration(infile, track, length, MP4_MSECS_TIME_SCALE); if(!(hDecoder=faacDecOpen())) ERROR_ON_OPEN_MP4("Can't init library"); buffer = NULL; buffer_size = 0; MP4GetTrackESConfiguration(infile, track, &buffer, &buffer_size); if(buffer) AudioSpecificConfig(buffer, &timeScale, &channels, &sf, &mi->type); mi->file_info.bitrate=(int)MP4GetTrackIntegerProperty(infile, track, "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.avgBitrate"); numSamples = MP4GetTrackNumberOfSamples(infile, track); if(faacDecInit2(hDecoder, buffer, buffer_size, &samplerate, &channels) < 0) ERROR_ON_OPEN_MP4("Error initializing decoder library"); if (buffer) free(buffer); mi->numSamples=numSamples; mi->track=track; mi->sampleId=1; } else // AAC file ------------------------------------------------------------------------------ { FILE *infile; DWORD pos; // into the file. Needed to obtain length of file DWORD read; int *seek_table; long tagsize; if(!(infile=fopen(lpstrFilename,"rb"))) ERROR_ON_OPEN_AAC("Error opening file"); mi->fFile=infile; pos=ftell(infile); fseek(infile, 0, SEEK_END); mi->lSize=ftell(infile); fseek(infile, pos, SEEK_SET); if(!(buffer=(BYTE *)malloc(768*MAX_CHANNELS))) { MessageBox(0, "Memory allocation error: buffer", "FAAD interface", MB_OK); GlobalUnlock(hInput); return 0; } mi->buffer=buffer; memset(buffer, 0, 768*MAX_CHANNELS); if(mi->lSize<768*MAX_CHANNELS) tmp=mi->lSize; else tmp=768*MAX_CHANNELS; read=fread(buffer, 1, tmp, infile); if(read==tmp) { mi->bytes_read=read; mi->bytes_into_buffer=read; } else ERROR_ON_OPEN_AAC("fread"); tagsize=id3v2_tag(buffer); if(tagsize) { memcpy(buffer,buffer+tagsize,768*MAX_CHANNELS - tagsize); if(mi->bytes_read+tagsize<mi->lSize) tmp=tagsize; else tmp=mi->lSize-mi->bytes_read; read=fread(buffer+mi->bytes_into_buffer, 1, tmp, mi->fFile); if(read==tmp) { mi->bytes_read+=read; mi->bytes_into_buffer+=read; } else ERROR_ON_OPEN_AAC("fread"); } mi->tagsize=tagsize; if(!(hDecoder=faacDecOpen())) ERROR_ON_OPEN_AAC("Can't init library"); config = faacDecGetCurrentConfiguration(hDecoder); // config->defObjectType = MAIN; config->defSampleRate = 44100; config->outputFormat=FAAD_FMT_16BIT; faacDecSetConfiguration(hDecoder, config); if((mi->bytes_consumed=faacDecInit(hDecoder, buffer, &samplerate, &channels)) < 0) ERROR_ON_OPEN_AAC("Error retrieving information form input file"); mi->bytes_into_buffer-=mi->bytes_consumed; // if(mi->bytes_consumed>0) // faacDecInit reports there is an header to skip // this operation will be done in ReadFilterInput if(seek_table=(int *)malloc(sizeof(int)*10800)) { get_AAC_format(lpstrFilename, &(mi->file_info), seek_table); free(seek_table); } if(!mi->file_info.version) ERROR_ON_OPEN_AAC("Error retrieving information form input file"); mi->len_ms=(DWORD)((1000*((float)mi->lSize*8))/mi->file_info.bitrate); } // END AAC file ----------------------------------------------------------------------------- if(mi->len_ms) mi->full_size=(DWORD)(mi->len_ms*((float)samplerate/1000)*channels*(16/8)); else mi->full_size=mi->lSize; // corrupted stream? mi->hDecoder=hDecoder; *lSamprate=samplerate; *wBitsPerSample=16; *wChannels=(WORD)channels; *lChunkSize=sizeof(short)*1024*channels; mi->wChannels=(WORD)channels; mi->dwSamprate=samplerate; mi->wBitsPerSample=*wBitsPerSample; strcpy(mi->szName,lpstrFilename); GlobalUnlock(hInput); return hInput; } #define ERROR_ReadFilterInput(msg) \ { \ if(msg) \ MessageBox(0, msg, "FAAD interface", MB_OK); \ GlobalUnlock(hInput); \ return 0; \ } \ __declspec(dllexport) DWORD FAR PASCAL ReadFilterInput(HANDLE hInput, unsigned char far *bufout, long lBytes) { DWORD read, tmp, shorts_decoded=0; unsigned char *buffer=0; faacDecFrameInfo frameInfo; char *sample_buffer=0; MYINPUT *mi; if(!hInput) return 0; mi=(MYINPUT *)GlobalLock(hInput); if(!mi->IsAAC) // MP4 file -------------------------------------------------------------------------- { unsigned __int32 buffer_size=0; int rc; do { buffer=NULL; if(mi->sampleId>=mi->numSamples) ERROR_ReadFilterInput(0); rc=MP4ReadSample(mi->mp4File, mi->track, mi->sampleId++, &buffer, &buffer_size, NULL, NULL, NULL, NULL); if(rc==0 || buffer==NULL) { if(buffer) free(buffer); ERROR_ReadFilterInput("MP4ReadSample") } sample_buffer=(char *)faacDecDecode(mi->hDecoder,&frameInfo,buffer); shorts_decoded=frameInfo.samples*sizeof(short); memcpy(bufout,sample_buffer,shorts_decoded); if (buffer) free(buffer); }while(!shorts_decoded && !frameInfo.error); } else // AAC file -------------------------------------------------------------------------- { buffer=mi->buffer; do { if(mi->bytes_consumed>0) { if(mi->bytes_into_buffer) memcpy(buffer,buffer+mi->bytes_consumed,mi->bytes_into_buffer); if(mi->bytes_read<mi->lSize) { if(mi->bytes_read+mi->bytes_consumed<mi->lSize) tmp=mi->bytes_consumed; else tmp=mi->lSize-mi->bytes_read; read=fread(buffer+mi->bytes_into_buffer, 1, tmp, mi->fFile); if(read==tmp) { mi->bytes_read+=read; mi->bytes_into_buffer+=read; } } else if(mi->bytes_into_buffer) memset(buffer+mi->bytes_into_buffer, 0, mi->bytes_consumed); mi->bytes_consumed=0; } if(mi->bytes_into_buffer<1) if(mi->bytes_read<mi->lSize) ERROR_ReadFilterInput("ReadFilterInput: buffer empty!") else return 0; sample_buffer=(char *)faacDecDecode(mi->hDecoder,&frameInfo,buffer); shorts_decoded=frameInfo.samples*sizeof(short); memcpy(bufout,sample_buffer,shorts_decoded); mi->bytes_consumed +=frameInfo.bytesconsumed; mi->bytes_into_buffer-=mi->bytes_consumed; }while(!shorts_decoded && !frameInfo.error); } // END AAC file -------------------------------------------------------------------------- GlobalUnlock(hInput); if(frameInfo.error) ERROR_ReadFilterInput(faacDecGetErrorMessage(frameInfo.error)); return shorts_decoded; }