diff options
Diffstat (limited to 'Src/nsv/nsvplay/decoders.cpp')
-rw-r--r-- | Src/nsv/nsvplay/decoders.cpp | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/Src/nsv/nsvplay/decoders.cpp b/Src/nsv/nsvplay/decoders.cpp new file mode 100644 index 00000000..82cba2bd --- /dev/null +++ b/Src/nsv/nsvplay/decoders.cpp @@ -0,0 +1,675 @@ +#include <windows.h> +#include "api.h" +#include "main.h" +#include "vfw.h" +#include <api/service/services.h> +#include "../nsv/svc_nsvFactory.h" +#include <api/service/waservicefactory.h> +#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; +}
\ No newline at end of file |