#include #include "api.h" #include "main.h" #include "vfw.h" #include #include "../nsv/svc_nsvFactory.h" #include #include "../../Winamp/in2.h" extern In_Module mod; // you should probably override these in your project settings // builtin decoders //#define BUILTIN_MP3_SUPPORT //#define BUILTIN_VP3_SUPPORT //#define BUILTIN_DIVX_SUPPORT //#define BUILTIN_PCM_SUPPORT //#define BUILTIN_VFW_SUPPORT // support dll decoders? //#define DLL_DECODER_SUPPORT //#define DLL_DECODER_SUPPORT_NOCURDIR #ifdef WINAMP_PLUGIN # ifndef DLL_DECODER_SUPPORT # define DLL_DECODER_SUPPORT # endif # ifndef DLL_DECODER_SUPPORT_NOCURDIR # define DLL_DECODER_SUPPORT_NOCURDIR # endif # ifndef DLL_DECODER_SUPPORT_IN_ # define DLL_DECODER_SUPPORT_IN_ # endif # ifndef BUILTIN_PCM_SUPPORT # define BUILTIN_PCM_SUPPORT # endif #endif #ifdef BUILTIN_VP3_SUPPORT #include "vp3stub.h" #endif #ifdef BUILTIN_VP5_SUPPORT #include "vp5stub.h" #endif #ifdef BUILTIN_MP3_SUPPORT #include "mp3stub.h" #endif #ifdef BUILTIN_VFW_SUPPORT class Gen_Decoder : public IVideoDecoder { public: Gen_Decoder(int w, int h); ~Gen_Decoder(); int decode(int need_kf, void *in, int in_len, void **out, // out is set to a pointer to data unsigned int *out_type, // 'Y','V','1','2' is currently defined int *is_kf); void flush() { } int m_err; int width,height; BITMAPINFO gen_bmo,gen_bmi; HIC gen_hic; unsigned char *vidbufdec; }; Gen_Decoder::Gen_Decoder(int w, int h) { width=w; height=h; m_err=0; gen_hic=0; vidbufdec=(unsigned char*)malloc(sizeof(YV12_PLANES) + w*h*3/2); } Gen_Decoder::~Gen_Decoder() { if (gen_hic) { ICDecompressEnd(gen_hic); ICClose(gen_hic); } free(vidbufdec); } int Gen_Decoder::decode(int need_kf, void *in, int in_len, void **out, // out is set to a pointer to data unsigned int *out_type, // 'Y','V','1','2' is currently defined int *is_kf) { *out_type=NSV_MAKETYPE('Y','V','1','2'); gen_bmi.bmiHeader.biSizeImage = in_len; if(ICERR_OK == ICDecompress(gen_hic,0,(BITMAPINFOHEADER *) &gen_bmi, (char*)in,(BITMAPINFOHEADER *) &gen_bmo, (char*)vidbufdec+sizeof(YV12_PLANES))) { //*is_kf=!(!in_len || ((unsigned char *)in)[0] > 0x7f); *is_kf=1; if (need_kf && !*is_kf) { return 0; } YV12_PLANES *image_vbd=(YV12_PLANES *)vidbufdec; image_vbd->y.baseAddr=(unsigned char *)(image_vbd+1); image_vbd->v.baseAddr=((unsigned char *)(image_vbd+1)) + width*height; image_vbd->u.baseAddr=((unsigned char *)(image_vbd+1)) + width*height*5/4; image_vbd->y.rowBytes=width; image_vbd->v.rowBytes=width/2; image_vbd->u.rowBytes=width/2; *out=(void*)vidbufdec; return 0; } return -1; } static IVideoDecoder *createVfw(int w, int h, double framerate, unsigned int type, int *flip) { HIC gen_hic = ICOpen(ICTYPE_VIDEO, type, ICMODE_DECOMPRESS); if (!gen_hic) return 0; BITMAPINFO gen_bmo={0,},gen_bmi={0,}; gen_bmi.bmiHeader.biSize=sizeof(gen_bmi.bmiHeader); gen_bmi.bmiHeader.biCompression = type; gen_bmi.bmiHeader.biHeight=h; gen_bmi.bmiHeader.biWidth =w; gen_bmi.bmiHeader.biPlanes=1; gen_bmo.bmiHeader.biSize=sizeof(gen_bmo.bmiHeader); gen_bmo.bmiHeader.biCompression = mmioFOURCC('Y','V','1','2'); gen_bmo.bmiHeader.biHeight=h; gen_bmo.bmiHeader.biWidth =w; gen_bmo.bmiHeader.biSizeImage=(w*h*3)/2; gen_bmo.bmiHeader.biPlanes=1; gen_bmo.bmiHeader.biBitCount=12; if (ICERR_OK !=ICDecompressBegin(gen_hic, &gen_bmi, &gen_bmo)) { ICClose(gen_hic); return 0; } Gen_Decoder *t=new Gen_Decoder(w,h); t->gen_bmi=gen_bmi; t->gen_bmo=gen_bmo; t->gen_hic=gen_hic; return t; } #endif #ifdef BUILTIN_DIVX_SUPPORT #include "../../divx5/decore.h" class CrapDivxDecoder : public IVideoDecoder { public: CrapDivxDecoder(int w, int h) { predict_keyframes=1; divx_param.x_dim = w; divx_param.y_dim = h; divx_param.output_format = DEC_USER; divx_param.codec_version = 412; // indicates that the stream is DivX 4.12 compatible divx_param.build_number = 0; // in this case, the build field is ignored divx_param.time_incr = 15; // time_incr default value g_decore((long) this, DEC_OPT_MEMORY_REQS, &divx_param, &decMemReqs); // the application allocates the data structures and the buffers divx_param.buffers.mp4_edged_ref_buffers = malloc(decMemReqs.mp4_edged_ref_buffers_size); divx_param.buffers.mp4_edged_for_buffers = malloc(decMemReqs.mp4_edged_for_buffers_size); divx_param.buffers.mp4_edged_back_buffers = malloc(decMemReqs.mp4_edged_back_buffers_size); divx_param.buffers.mp4_display_buffers = malloc(decMemReqs.mp4_display_buffers_size); divx_param.buffers.mp4_state = malloc(decMemReqs.mp4_state_size); divx_param.buffers.mp4_tables = malloc(decMemReqs.mp4_tables_size); divx_param.buffers.mp4_stream = malloc(decMemReqs.mp4_stream_size); divx_param.buffers.mp4_reference = malloc(decMemReqs.mp4_reference_size); memset(divx_param.buffers.mp4_state, 0, decMemReqs.mp4_state_size); memset(divx_param.buffers.mp4_tables, 0, decMemReqs.mp4_tables_size); memset(divx_param.buffers.mp4_stream, 0, decMemReqs.mp4_stream_size); memset(divx_param.buffers.mp4_reference, 0, decMemReqs.mp4_reference_size); g_decore((long) this, DEC_OPT_INIT, &divx_param, NULL); } ~CrapDivxDecoder() { if (g_decore) { g_decore((long) this,DEC_OPT_RELEASE,NULL,NULL); free(divx_param.buffers.mp4_display_buffers); free(divx_param.buffers.mp4_edged_for_buffers); free(divx_param.buffers.mp4_edged_back_buffers); free(divx_param.buffers.mp4_edged_ref_buffers); free(divx_param.buffers.mp4_reference); free(divx_param.buffers.mp4_state); free(divx_param.buffers.mp4_stream); free(divx_param.buffers.mp4_tables); } if (!--divx_cnt) { FreeModule(hDivxLib); hDivxLib=0; g_decore=0; } } int decode(int need_kf, void *in, int in_len, void **out, // out is set to a pointer to data unsigned int *out_type, // 'Y','V','1','2' is currently defined int *is_kf) { *out_type=NSV_MAKETYPE('Y','V','1','2'); *out=NULL; int kfpredict=0; if (predict_keyframes && in_len>3) { kfpredict=!((unsigned char *)in)[3]; if (need_kf && !kfpredict) return 0; } if (!in_len) return 0; *is_kf=kfpredict; DEC_PICTURE pic; DEC_FRAME decFrame; decFrame.bitstream = in; decFrame.bmp = &pic; decFrame.length = in_len; decFrame.render_flag = 1; DEC_FRAME_INFO fi; if (g_decore((long) this, DEC_OPT_FRAME, &decFrame, &fi) == DEC_OK) { if (!kfpredict != !fi.intra) predict_keyframes=0; *is_kf=fi.intra; if (need_kf && !fi.intra) return 0; image_vbd.y.baseAddr=(unsigned char *)pic.y; image_vbd.u.baseAddr=(unsigned char *)pic.u; image_vbd.v.baseAddr=(unsigned char *)pic.v; image_vbd.y.rowBytes=pic.stride_y; image_vbd.u.rowBytes=pic.stride_uv; image_vbd.v.rowBytes=pic.stride_uv; *out=&image_vbd; return 0; } return -1; } void flush() { } static int (STDCALL *g_decore)( unsigned long handle, // handle - the handle of the calling entity, must be unique unsigned long dec_opt, // dec_opt - the option for docoding, see below void *param1, // param1 - the parameter 1 (it's actually meaning depends on dec_opt void *param2); // param2 - the parameter 2 (it's actually meaning depends on dec_opt static HINSTANCE hDivxLib; static int divx_cnt; private: DEC_PARAM divx_param; YV12_PLANES image_vbd; DEC_MEM_REQS decMemReqs; int predict_keyframes; }; int (STDCALL *CrapDivxDecoder::g_decore)( unsigned long handle, // handle - the handle of the calling entity, must be unique unsigned long dec_opt, // dec_opt - the option for docoding, see below void *param1, // param1 - the parameter 1 (it's actually meaning depends on dec_opt void *param2)=0; // param2 - the parameter 2 (it's actually meaning depends on dec_opt HINSTANCE CrapDivxDecoder::hDivxLib=0; int CrapDivxDecoder::divx_cnt=0; IVideoDecoder *DIVX_CREATE(int w, int h, double framerate, unsigned int fmt, int *flip) { if (fmt == NSV_MAKETYPE('D','i','v','X')) { if (!CrapDivxDecoder::divx_cnt) { CrapDivxDecoder::hDivxLib=LoadLibrary("divx.dll"); if (CrapDivxDecoder::hDivxLib) *((void**)&CrapDivxDecoder::g_decore)=GetProcAddress(CrapDivxDecoder::hDivxLib,"decore"); } CrapDivxDecoder::divx_cnt++; if (CrapDivxDecoder::g_decore) return new CrapDivxDecoder(w,h); } return NULL; } #endif // end of divx gayness class NullVideoDecoder : public IVideoDecoder { public: NullVideoDecoder() { } ~NullVideoDecoder() { } int decode(int need_kf, void *in, int in_len, void **out, // out is set to a pointer to data unsigned int *out_type, // 'Y','V','1','2' is currently defined int *is_kf) { *out_type=NSV_MAKETYPE('Y','V','1','2'); *is_kf=1; *out=NULL; return 0; } void flush() { } }; class NullAudioDecoder : public IAudioDecoder { public: NullAudioDecoder(){} ~NullAudioDecoder(){} int decode(void *in, int in_len, void *out, int *out_len, unsigned int out_fmt[8]) { *out_len=0; out_fmt[0]=NSV_MAKETYPE('N','O','N','E'); // no output return 0; } void flush(){} }; #ifdef BUILTIN_PCM_SUPPORT class PCMAudioDecoder : public IAudioDecoder { public: PCMAudioDecoder() { fused=4; } ~PCMAudioDecoder(){} int decode(void *in, int in_len, void *out, int *out_len, unsigned int out_fmt[8]) { if (in_len < 4) { *out_len=0; out_fmt[0]=0; return 0; // screw this frame } unsigned char *t=(unsigned char *)in; int bps=t[0]; int nch=t[1]; int srate=((int)t[2] | (((int)t[3])<<8)); out_fmt[0]=NSV_MAKETYPE('P','C','M',' '); out_fmt[1]=srate; out_fmt[2]=nch; out_fmt[3]=bps; int l=in_len-fused; if (l > *out_len) l = *out_len; l&=~(nch*(bps/8)-1); if (l) memcpy(out,(char *)in + fused,l); fused+=l; *out_len=l; if (fused >= in_len) { fused=4; return 0; } return 1; } void flush() { fused=4; } private: int fused; }; #endif #ifdef DLL_DECODER_SUPPORT static char DLL_Dir[MAX_PATH]; static HINSTANCE DLL_Handles[512]; #endif void Decoders_Init(char *wapluginspath) { #ifdef DLL_DECODER_SUPPORT HKEY hKey; if (!DLL_Dir[0] && RegOpenKeyExA(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion", 0,KEY_READ,&hKey) == ERROR_SUCCESS) { DWORD l = sizeof(DLL_Dir); DWORD t; if (RegQueryValueExA(hKey,"CommonFilesDir",NULL,&t,(LPBYTE)DLL_Dir,&l ) != ERROR_SUCCESS || t != REG_SZ) DLL_Dir[0]=0; DLL_Dir[sizeof(DLL_Dir)-5]=0; CreateDirectoryA(DLL_Dir,NULL); strcat(DLL_Dir,"\\NSV"); CreateDirectoryA(DLL_Dir,NULL); RegCloseKey(hKey); } if (!DLL_Dir[0]) GetTempPathA(sizeof(DLL_Dir),DLL_Dir); Decoders_Quit(); HANDLE h; int x=0; WIN32_FIND_DATAA fd = {0}; char buf[MAX_PATH*2+1] = {0}; #ifndef DLL_DECODER_SUPPORT_NOCURDIR char curdir[MAX_PATH] = {0}; strcpy( curdir, ".\\" ); strcpy( buf, curdir ); strcat( buf, "nsvdec_*.dll" ); OutputDebugString( buf ); OutputDebugString( "\n" ); h = FindFirstFile(buf,&fd); if (h != INVALID_HANDLE_VALUE) { do { strcpy(buf,curdir); strcat(buf,fd.cFileName); DLL_Handles[x]=LoadLibrary(buf); if (DLL_Handles[x]) { if (GetProcAddress(DLL_Handles[x],"CreateVideoDecoder") || GetProcAddress(DLL_Handles[x],"CreateAudioDecoder")) x++; else { FreeLibrary(DLL_Handles[x]); DLL_Handles[x]=0; } } } while (x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && FindNextFile(h,&fd)); FindClose(h); } #endif #ifdef DLL_DECODER_SUPPORT_IN_ if (wapluginspath && wapluginspath[0]) { lstrcpynA(buf,wapluginspath,sizeof(buf)-16); strcat(buf,"\\in_*.dll"); h = FindFirstFileA(buf,&fd); if (h != INVALID_HANDLE_VALUE) { do { strncpy(buf, wapluginspath, MAX_PATH); strncat(buf, "\\", MAX_PATH); strncat(buf, fd.cFileName, MAX_PATH); DLL_Handles[x]=LoadLibraryA(buf); if (DLL_Handles[x]) { if (GetProcAddress(DLL_Handles[x],"CreateVideoDecoder") || GetProcAddress(DLL_Handles[x],"CreateAudioDecoder")) x++; else { FreeLibrary(DLL_Handles[x]); DLL_Handles[x]=0; } } } while (x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && FindNextFileA(h,&fd)); FindClose(h); } lstrcpynA(buf,wapluginspath,sizeof(buf)-16); strcat(buf,"\\nsvdec_*.dll"); h = FindFirstFileA(buf,&fd); if (h != INVALID_HANDLE_VALUE) { do { strncpy(buf, wapluginspath, MAX_PATH); strncat(buf, "\\", MAX_PATH); strncat(buf, fd.cFileName, MAX_PATH); DLL_Handles[x]=LoadLibraryA(buf); if (DLL_Handles[x]) { if (GetProcAddress(DLL_Handles[x],"CreateVideoDecoder") || GetProcAddress(DLL_Handles[x],"CreateAudioDecoder")) x++; else { FreeLibrary(DLL_Handles[x]); DLL_Handles[x]=0; } } } while (x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && FindNextFileA(h,&fd)); FindClose(h); } } #endif #ifndef WINAMPX strncpy(buf, DLL_Dir, MAX_PATH); strncat(buf, "\\nsvdec_*.dll", MAX_PATH); h = FindFirstFileA(buf,&fd); if (h != INVALID_HANDLE_VALUE) { do { strncpy(buf, DLL_Dir, MAX_PATH); strncat(buf, "\\", MAX_PATH); strncat(buf, fd.cFileName, MAX_PATH); DLL_Handles[x]=LoadLibraryA(buf); if (DLL_Handles[x]) { if (GetProcAddress(DLL_Handles[x],"CreateVideoDecoder") || GetProcAddress(DLL_Handles[x],"CreateAudioDecoder")) x++; else { FreeLibrary(DLL_Handles[x]); DLL_Handles[x]=0; } } } while (x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && FindNextFileA(h,&fd)); FindClose(h); } #endif #endif } void Decoders_Quit() { #ifdef DLL_DECODER_SUPPORT int x; for (x = 0; x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && DLL_Handles[x]; x ++) { FreeLibrary(DLL_Handles[x]); DLL_Handles[x]=0; } #endif } static IAudioDecoder *CreateAudioDecoderWasabi(unsigned int type, IAudioOutput **output) { int n = 0; waServiceFactory *sf = 0; while (sf = mod.service->service_enumService(WaSvc::NSVFACTORY, n++)) { svc_nsvFactory *factory = (svc_nsvFactory *)sf->getInterface(); if (factory) { IAudioDecoder *decoder = factory->CreateAudioDecoder(type, output); sf->releaseInterface(factory); if (decoder) return decoder; } } return 0; } static IVideoDecoder *CreateVideoDecoderWasabi(int w, int h, double framerate, unsigned int type, int *flip) { int n=0; waServiceFactory *sf = 0; while (sf = mod.service->service_enumService(WaSvc::NSVFACTORY, n++)) { svc_nsvFactory *factory = (svc_nsvFactory *)sf->getInterface(); if (factory) { IVideoDecoder *decoder = factory->CreateVideoDecoder(w, h, framerate, type, flip); sf->releaseInterface(factory); if (decoder) return decoder; } } return 0; } IAudioDecoder *CreateAudioDecoder(unsigned int type, int *wasNotNull, IAudioOutput **output) { IAudioDecoder *a=NULL; if (mod.service && !a) a = CreateAudioDecoderWasabi(type, output); #ifdef BUILTIN_MP3_SUPPORT if (!a) a=MP3_CREATE(type); #endif #ifdef BUILTIN_PCM_SUPPORT if (!a && type == NSV_MAKETYPE('P','C','M',' ')) a=new PCMAudioDecoder; #endif #ifdef BUILTIN_AAC_SUPPORT extern IAudioDecoder *AAC_CREATE(unsigned int fmt, IAudioOutput **output); if (!a && (type == NSV_MAKETYPE('A','A','C',' ') || type == NSV_MAKETYPE('V','L','B',' '))) a=AAC_CREATE(type,NULL); #endif #ifdef BUILTIN_AACP_SUPPOT extern IAudioDecoder *AACP_CREATE(unsigned int fmt, IAudioOutput **output); if (!a && (type == NSV_MAKETYPE('A','A','C','P') || type == NSV_MAKETYPE('A','A','C',' '))) a=AAC_CREATE(type,NULL); #endif #ifdef DLL_DECODER_SUPPORT int x; for (x = 0; !a && x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && DLL_Handles[x]; x ++) { IAudioDecoder *(*cad)(unsigned int type, IAudioOutput **output); *((void**)&cad) = (void*)GetProcAddress(DLL_Handles[x],"CreateAudioDecoder"); if (cad) a=cad(type,output); } #endif if (!a) { *wasNotNull=0; void *mem = WASABI_API_MEMMGR->sysMalloc(sizeof(NullAudioDecoder)); a = new (mem) NullAudioDecoder(); } else *wasNotNull=1; return a; } IVideoDecoder *CreateVideoDecoder(int w, int h, double framerate, unsigned int type, int *flip, int *wasNotNull) { IVideoDecoder *v=NULL; if (mod.service && !v) v = CreateVideoDecoderWasabi(w, h, framerate, type, flip); #ifdef BUILTIN_DIVX_SUPPORT if (!v) v=DIVX_CREATE(w,h,framerate,type,flip); #endif #ifdef BUILTIN_VP3_SUPPORT if (!v) v=VP3_CREATE(w,h,framerate,type,flip); #endif #ifdef BUILTIN_VP5_SUPPORT if (!v) v=VP5_CREATE(w,h,framerate,type,flip); #endif #ifdef BUILTIN_VP6_SUPPORT extern IVideoDecoder *VP6_CREATE(int w, int h, double framerate, unsigned int fmt, int *flip); if (!v) v=VP6_CREATE(w,h,framerate,type,flip); #endif #ifdef DLL_DECODER_SUPPORT int x; for (x = 0; !v && x < sizeof(DLL_Handles)/sizeof(DLL_Handles[0]) && DLL_Handles[x]; x ++) { IVideoDecoder *(*cvd)(int w, int h, double framerate, unsigned int type, int *flip); *((void**)&cvd) = (void*)GetProcAddress(DLL_Handles[x],"CreateVideoDecoder"); if (cvd) v=cvd(w,h,framerate,type,flip); } #endif #ifdef BUILTIN_VFW_SUPPORT if (!v) { v=createVfw(w,h,framerate,type,flip); } #endif if (!v) { if (wasNotNull) *wasNotNull=0; void *mem = WASABI_API_MEMMGR->sysMalloc(sizeof(NullVideoDecoder)); v = new (mem) NullVideoDecoder(); } else if (wasNotNull) *wasNotNull=1; return v; }