Main.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575
  1. //#define PLUGIN_NAME "Nullsoft DirectShow Decoder"
  2. #define PLUGIN_VERSION L"1.15"
  3. #define WIN32_LEAN_AND_MEAN
  4. #include <windows.h>
  5. #include <math.h>
  6. #include <assert.h>
  7. #include "../Agave/Language/api_language.h"
  8. #include <api/service/waServiceFactory.h>
  9. #include "resource.h"
  10. #include "../nu/ns_wc.h"
  11. #define IPC_GETINIFILE 334 // returns a pointer to winamp.ini
  12. #define WM_WA_IPC WM_USER
  13. #define VIDUSER_SET_TRACKSELINTERFACE 0x1003 // give your ITrackSelector interface as param2
  14. #define VIDUSER_SET_INFOSTRING 0x1000
  15. #define DEFGUID 1
  16. #include <AtlBase.h>
  17. //#include <streams.h>
  18. //#include <qedit.h>
  19. #include <qnetwork.h>
  20. #ifdef DEFGUID
  21. #include <initguid.h> // declares DEFINE_GUID to declare an EXTERN_C const.
  22. #endif
  23. #include "main.h"
  24. #include "CWAAudioRenderer.h"
  25. #include "CWAVideoRenderer.h"
  26. #include "header_asf.h"
  27. #include "header_avi.h"
  28. #include "header_mpg.h"
  29. #include "header_wav.h"
  30. #include "../Winamp/wa_ipc.h"
  31. #include "../nsutil/pcm.h"
  32. static Header *infoHeader=0;
  33. wchar_t *infoFn=0;
  34. DEFINE_GUID(IID_IAMNetworkStatus,0xFA2AA8F3L,0x8B62,0x11D0,0xA5,0x20,0x00,0x00,0x00,0x00,0x00,0x00);
  35. // post this to the main window at end of file (after playback as stopped)
  36. #define WM_WA_MPEG_EOF WM_USER+2
  37. #define IPC_GET_IVIDEOOUTPUT 500
  38. #define VIDEO_MAKETYPE(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24))
  39. #define VIDUSER_SET_VFLIP 0x1002
  40. // wasabi based services for localisation support
  41. api_language *WASABI_API_LNG = 0;
  42. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  43. HINSTANCE g_hInstance=0;
  44. BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
  45. {
  46. if (dwReason == DLL_PROCESS_ATTACH)
  47. {
  48. g_hInstance=hInstance;
  49. }
  50. return TRUE;
  51. }
  52. int GetFileLength(const wchar_t *filename)
  53. {
  54. static wchar_t fn[MAX_PATH*4] = L"";
  55. static int l = -1;
  56. if(!_wcsicmp(filename,fn)) return l;
  57. //return -1000;
  58. CComPtr<IGraphBuilder> graph;
  59. graph.CoCreateInstance(CLSID_FilterGraph);
  60. if (graph)
  61. {
  62. HRESULT hr;
  63. try
  64. {
  65. hr = graph->RenderFile(filename,NULL);
  66. }
  67. catch (...)
  68. {
  69. return -1000;
  70. }
  71. if (hr == S_OK)
  72. {
  73. CComPtr<IMediaPosition> pMediaPosition;
  74. graph->QueryInterface(IID_IMediaPosition, (void **)&pMediaPosition);
  75. if (pMediaPosition)
  76. {
  77. REFTIME length;
  78. pMediaPosition->get_Duration(&length);
  79. lstrcpynW(fn,filename,sizeof(fn)/sizeof(wchar_t));
  80. l = (int)(length*1000.0);
  81. return (int)(length*1000.0);
  82. }
  83. }
  84. }
  85. return -1000;
  86. }
  87. wchar_t lastfn[MAX_PATH] = {0}; // currently playing file (used for getting info on the current file)
  88. int file_length; // file length, in bytes
  89. int decode_pos_ms; // current decoding position, in milliseconds.
  90. // Used for correcting DSP plug-in pitch changes
  91. int paused; // are we paused?
  92. volatile int seek_needed; // if != -1, it is the point that the decode
  93. // thread should seek to, in ms.
  94. HANDLE input_file=INVALID_HANDLE_VALUE; // input file handle
  95. volatile int killDecodeThread=0; // the kill switch for the decode thread
  96. HANDLE thread_handle=INVALID_HANDLE_VALUE; // the handle to the decode thread
  97. const char *INI_FILE;
  98. wchar_t m_lastfn[2048] = {0}; // currently playing file (used for getting info on the current file)
  99. wchar_t m_status[512] = {0};
  100. DWORD m_laststatus;
  101. int m_bitrate=0;
  102. //config.cpp
  103. extern void doConfig(HINSTANCE hInstance, HWND hwndParent);
  104. extern void config_read();
  105. extern char *getfileextensions();
  106. extern void getInfo(const wchar_t *fn, wchar_t *linetext, int linetextCch, wchar_t *fulltext, int fulltextCch, int *bitrate, int *channel);
  107. //info.cpp
  108. extern void doInfo(HINSTANCE hInstance, HWND hwndParent, const wchar_t *fn);
  109. int getoutputtime();
  110. void releaseObjects();
  111. IVideoOutput *m_video_output;
  112. IGraphBuilder *pGraphBuilder=0;
  113. static ICaptureGraphBuilder2 *pCapture=0;
  114. static IBaseFilter *pNullFilter2=0;
  115. static IMediaEvent *pMediaEventEx=0;
  116. IMediaControl *pMediaControl=0;
  117. static IMediaSeeking *pMediaSeeking=0;
  118. static IBaseFilter *pCapVidSrcFilter=0;
  119. static IBaseFilter *pCapAudSrcFilter=0;
  120. bool has_audio, has_video, has_palette;
  121. int video_mediatype;
  122. int video_w,video_h,video_len;
  123. int audio_bps, audio_srate, audio_nch;
  124. RGBQUAD palette[0x100] = {0}; // for RGB8
  125. int m_length=-1;
  126. int g_quit;
  127. DWORD m_starttime,m_time_paused;
  128. unsigned int m_nbframes;
  129. DWORD m_avgfps_start;
  130. int m_float, m_src_bps;
  131. #ifdef IN_DSHOW_CAPTURE_SUPPORT // disable capture, for now
  132. int m_is_capture;
  133. #endif
  134. HWND m_notif_hwnd;
  135. ITrackSelector *pTrackSelector = NULL;
  136. static int doingaudioshit=0;
  137. bool s_using_dsr = false;
  138. wchar_t lastfn_status[256]=L"";
  139. static LONG_PTR m_buffering=0;
  140. int g_bufferstat;
  141. //capture stuff
  142. #include "../nsv/nsvbs.h"
  143. nsv_InBS g_video_refs;
  144. #define G_MAX_FREE_FRAMES 64
  145. void *g_free_frames[G_MAX_FREE_FRAMES];
  146. int g_num_free_frames;
  147. #define PA_CLIP_( val, min, max )\
  148. { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
  149. #if !defined(__alpha) && !defined(_WIN64)
  150. static __inline long float_to_long(double t)
  151. {
  152. long r;
  153. __asm fld t
  154. __asm fistp r
  155. return r;
  156. }
  157. #else
  158. #define float_to_long(x) ((long)( x ))
  159. #endif
  160. inline static void clip(double &x, double a, double b)
  161. {
  162. double x1 = fabs(x - a);
  163. double x2 = fabs(x - b);
  164. x = x1 + (a + b);
  165. x -= x2;
  166. x *= 0.5;
  167. }
  168. template <typename FLOAT_T>
  169. void Float32_To_Int24_Clip(void *destinationBuffer, FLOAT_T *sourceBuffer, unsigned int count, double gain)
  170. {
  171. FLOAT_T *src = sourceBuffer;
  172. unsigned char *dest = (unsigned char*)destinationBuffer;
  173. gain*=65536. * 32768.0;
  174. while (count--)
  175. {
  176. /* convert to 32 bit and drop the low 8 bits */
  177. double scaled = *src * gain;
  178. clip(scaled, -2147483648., 2147483647.);
  179. signed long temp = (signed long) scaled;
  180. dest[0] = (unsigned char)(temp >> 8);
  181. dest[1] = (unsigned char)(temp >> 16);
  182. dest[2] = (unsigned char)(temp >> 24);
  183. src++;
  184. dest += 3;
  185. }
  186. }
  187. template <typename FLOAT_T>
  188. void Float32_To_Int16_Clip(void *destinationBuffer, FLOAT_T *sourceBuffer, unsigned int count, double gain)
  189. {
  190. FLOAT_T *src = sourceBuffer;
  191. signed short *dest = (signed short*)destinationBuffer;
  192. gain*=32768.0;
  193. while (count--)
  194. {
  195. long samp = float_to_long((*src) * gain/* - 0.5*/);
  196. PA_CLIP_(samp, -0x8000, 0x7FFF);
  197. *dest = (signed short) samp;
  198. src ++;
  199. dest ++;
  200. }
  201. }
  202. class CAudioGrab : public CSampleCB
  203. {
  204. public:
  205. CAudioGrab() { }
  206. void sample_cb(LONGLONG starttime, LONGLONG endtime, IMediaSample *pSample)
  207. {
  208. if (g_quit) return;
  209. doingaudioshit=1;
  210. int l=pSample->GetActualDataLength();
  211. if (l)
  212. {
  213. unsigned char *b=NULL;
  214. pSample->GetPointer(&b);
  215. double t=(double)(starttime)/10000;
  216. decode_pos_ms=(int)t; //it's a fix so we stay in sync according to what DirectShit is sending us
  217. if (g_quit)
  218. {
  219. doingaudioshit=0;
  220. return;
  221. }
  222. //convert IEEE Floats to PCM
  223. if (m_float)
  224. {
  225. if (m_src_bps==32)
  226. {
  227. l/=sizeof(float);
  228. nsutil_pcm_FloatToInt_Interleaved(b, (const float *)b, audio_bps, l);
  229. l *= (audio_bps/8);
  230. }
  231. else if (m_src_bps==64)
  232. {
  233. l/=sizeof(double);
  234. switch (audio_bps)
  235. {
  236. case 16:
  237. Float32_To_Int16_Clip(b, (double *)b, l, 1.0);
  238. l*=2;
  239. break;
  240. case 24:
  241. Float32_To_Int24_Clip(b, (double *)b, l, 1.0);
  242. l*=3;
  243. break;
  244. }
  245. }
  246. }
  247. {
  248. int len=l;
  249. int s=576*audio_nch*(audio_bps/8);
  250. while (len>0&&!g_quit)
  251. {
  252. if (len>=s)
  253. {
  254. mod.SAAddPCMData(b,audio_nch,audio_bps,decode_pos_ms);
  255. mod.VSAAddPCMData(b,audio_nch,audio_bps,decode_pos_ms);
  256. }
  257. int l=min(s,len);
  258. if (mod.dsp_isactive())
  259. {
  260. char *sample_buffer = (char *)alloca(l*2);
  261. memcpy(sample_buffer,b,l);
  262. int l2=mod.dsp_dosamples((short *)sample_buffer,l/audio_nch/(audio_bps/8),audio_bps,audio_nch,audio_srate)*(audio_nch*(audio_bps/8));
  263. while (mod.outMod->CanWrite()<l2 && !g_quit) Sleep(10);
  264. if (g_quit)
  265. {
  266. doingaudioshit=0;
  267. return;
  268. }
  269. mod.outMod->Write(sample_buffer,l2);
  270. }
  271. else
  272. {
  273. while (mod.outMod->CanWrite()<l && !g_quit) Sleep(10);
  274. if (g_quit)
  275. {
  276. doingaudioshit=0;
  277. return;
  278. }
  279. mod.outMod->Write((char *)b,l);
  280. }
  281. //FUCKO:this is clearly having a precision problem
  282. decode_pos_ms+=((l/audio_nch/(audio_bps/8))*1000)/audio_srate;
  283. len-=l;
  284. b+=l;
  285. }
  286. }
  287. }
  288. doingaudioshit=0;
  289. }
  290. void endofstream()
  291. {
  292. while (!g_quit && mod.outMod->IsPlaying()) Sleep(10);
  293. PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
  294. }
  295. private:
  296. };
  297. CWAAudioRenderer *nullfilter;
  298. CWAVideoRenderer *nullfilter2;
  299. #include "DSTrackSelector.h"
  300. //#define DEBUGVIDEO
  301. #ifdef DEBUGVIDEO
  302. void outputDebugStr(char *str)
  303. {
  304. FILE *fh=fopen("c:\\dshow_dbg.log","at");
  305. fprintf(fh,"%s",str);
  306. fclose(fh);
  307. }
  308. #endif
  309. class CVideoGrab : public CSampleCB
  310. {
  311. public:
  312. CVideoGrab() {}
  313. void sample_cb(LONGLONG starttime, LONGLONG endtime, IMediaSample *pSample)
  314. {
  315. m_nbframes++;
  316. if (!m_avgfps_start) m_avgfps_start=(DWORD)GetTickCount64();
  317. if ((DWORD)GetTickCount64()-m_laststatus>500)
  318. {
  319. DWORD t= (DWORD)GetTickCount64()-m_avgfps_start;
  320. if (t)
  321. {
  322. wchar_t text[512] = {0};
  323. StringCchPrintfW(text,512,L"%s %.02f%s",m_status,(double)m_nbframes*1000/t,WASABI_API_LNGSTRINGW(IDS_FPS));
  324. m_video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)text,0);
  325. m_laststatus= (DWORD)GetTickCount64();
  326. }
  327. }
  328. if (g_quit) return;
  329. unsigned char *b=NULL;
  330. pSample->GetPointer(&b);
  331. //wait for the right time
  332. int evtime=(int)(starttime/10000);
  333. #ifdef IN_DSHOW_CAPTURE_SUPPORT // disable capture, for now
  334. if (m_is_capture)
  335. {
  336. //capture shit
  337. //check if frame to display
  338. for (;g_video_refs.avail()>=64;)
  339. {
  340. int *ptr = (int *)g_video_refs.getcurbyteptr();
  341. if (getoutputtime()<ptr[0]) break;
  342. //display it
  343. void *b=(void*)ptr[1];
  344. if (video_mediatype==VIDEO_MAKETYPE('Y','V','1','2'))
  345. {
  346. // YV12 needs to pass a YV12_PLANES structure.
  347. static YV12_PLANES yv12planes;
  348. int s=video_h*video_w;
  349. yv12planes.y.baseAddr=(unsigned char *)b;
  350. yv12planes.y.rowBytes=video_w;
  351. yv12planes.v.baseAddr=(unsigned char *)b+s;
  352. yv12planes.v.rowBytes=video_w/2;
  353. yv12planes.u.baseAddr=(unsigned char *)b+(s*5)/4;
  354. yv12planes.u.rowBytes=video_w/2;
  355. m_video_output->draw((void *)&yv12planes);
  356. }
  357. else
  358. m_video_output->draw(b);
  359. //free frame
  360. if (g_num_free_frames < G_MAX_FREE_FRAMES)
  361. {
  362. g_free_frames[g_num_free_frames++]=b;
  363. }
  364. else
  365. {
  366. free(b);
  367. }
  368. g_video_refs.seek(64);
  369. g_video_refs.compact();
  370. }
  371. //store the frame in buffer
  372. //alloc frame
  373. int len=pSample->GetActualDataLength();
  374. if (!len) //very unlikely but oh well...
  375. {
  376. int s=4;
  377. switch (video_mediatype)
  378. {
  379. case VIDEO_MAKETYPE('Y','U','Y','2'):
  380. case VIDEO_MAKETYPE('Y','V','Y','U'):
  381. case VIDEO_MAKETYPE('R','G','1','6'):
  382. s=2;
  383. break;
  384. case VIDEO_MAKETYPE('R','G','2','4'):
  385. s=3;
  386. break;
  387. }
  388. len=video_w*video_h*s;
  389. }
  390. void *t;
  391. if (g_num_free_frames)
  392. {
  393. t=g_free_frames[--g_num_free_frames];
  394. g_free_frames[g_num_free_frames]=0;
  395. }
  396. else
  397. t=malloc(len);
  398. memcpy(t,b,len);
  399. g_video_refs.add(&evtime,4);
  400. g_video_refs.add(&t,4);
  401. return;
  402. }
  403. #endif
  404. if (has_audio)
  405. {
  406. //sync based on audio
  407. if (getoutputtime()>evtime)
  408. {
  409. //too late, zap it
  410. return;
  411. }
  412. while (getoutputtime()<evtime && !g_quit) Sleep(1);
  413. }
  414. else
  415. {
  416. //sync based on time
  417. while (paused && !g_quit) Sleep(1);
  418. while ((GetTickCount64()-m_starttime)<(unsigned int)evtime && !g_quit) Sleep(1);
  419. }
  420. if (g_quit) return;
  421. if (video_mediatype==VIDEO_MAKETYPE('Y','V','1','2'))
  422. {
  423. // YV12 needs to pass a YV12_PLANES structure.
  424. static YV12_PLANES yv12planes;
  425. int s=video_h*video_w;
  426. yv12planes.y.baseAddr=(unsigned char *)b;
  427. yv12planes.y.rowBytes=video_w;
  428. yv12planes.v.baseAddr=(unsigned char *)b+s;
  429. yv12planes.v.rowBytes=video_w/2;
  430. yv12planes.u.baseAddr=(unsigned char *)b+(s*5)/4;
  431. yv12planes.u.rowBytes=video_w/2;
  432. m_video_output->draw((void *)&yv12planes);
  433. }
  434. else
  435. m_video_output->draw(b);
  436. }
  437. void endofstream()
  438. {
  439. if (!has_audio) PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
  440. }
  441. };
  442. const wchar_t *extension(const wchar_t *fn)
  443. {
  444. const wchar_t *x = PathFindExtensionW(fn);
  445. if (*x)
  446. return CharNextW(x);
  447. else
  448. return x;
  449. }
  450. DWORD WINAPI DecodeThread(LPVOID b); // the decode thread procedure
  451. void config(HWND hwndParent)
  452. {
  453. doConfig(WASABI_API_LNG_HINST,hwndParent);
  454. mod.FileExtensions=getfileextensions();
  455. }
  456. int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
  457. {
  458. MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
  459. msgbx.lpszText = message;
  460. msgbx.lpszCaption = title;
  461. msgbx.lpszIcon = MAKEINTRESOURCEW(102);
  462. msgbx.hInstance = GetModuleHandle(0);
  463. msgbx.dwStyle = MB_USERICON;
  464. msgbx.hwndOwner = parent;
  465. return MessageBoxIndirectW(&msgbx);
  466. }
  467. void about(HWND hwndParent)
  468. {
  469. wchar_t message[1024] = {0}, text[1024] = {0};
  470. WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_DSHOW_PLUGIN_OLD,text,1024);
  471. StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
  472. mod.description, __DATE__);
  473. DoAboutMessageBox(hwndParent,text,message);
  474. }
  475. int init()
  476. {
  477. if (!IsWindow(mod.hMainWindow))
  478. return IN_INIT_FAILURE;
  479. INI_FILE = (const char *)SendMessage(mod.hMainWindow, WM_WA_IPC, 0, IPC_GETINIFILE);
  480. config_read();
  481. waServiceFactory *sf = mod.service->service_getServiceByGuid(languageApiGUID);
  482. if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
  483. // need to have this initialised before we try to do anything with localisation features
  484. WASABI_API_START_LANG(mod.hDllInstance,IndshowLangGUID);
  485. static wchar_t szDescription[256];
  486. StringCchPrintfW(szDescription,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_DSHOW_PLUGIN),PLUGIN_VERSION);
  487. mod.description = (char*)szDescription;
  488. mod.FileExtensions=getfileextensions();
  489. pTrackSelector = new DSTrackSelector();
  490. return IN_INIT_SUCCESS;
  491. }
  492. void quit()
  493. {
  494. if (pTrackSelector) { delete pTrackSelector; pTrackSelector = NULL; }
  495. if (infoFn) { free(infoFn); infoFn = 0; }
  496. if (infoHeader) { delete infoHeader; infoHeader = 0; }
  497. }
  498. int isourfile(const wchar_t *fn)
  499. {
  500. // TODO: re-enable this, but only via an option
  501. #if 0
  502. if (!strncmp(fn,"mms://",6) || !strncmp(fn,"mmst://",7) || !strncmp(fn,"mmsu://",7))
  503. {
  504. if (!strstr(fn,".wma")) return 1;
  505. }
  506. #endif
  507. #ifdef IN_DSHOW_CAPTURE_SUPPORT // disable capture, for now
  508. return !strncmp(fn,"cap://",6);
  509. #endif
  510. return 0;
  511. }
  512. #ifdef DEBUG
  513. HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
  514. {
  515. IMoniker * pMoniker;
  516. IRunningObjectTable *pROT;
  517. if (FAILED(GetRunningObjectTable(0, &pROT)))
  518. {
  519. return E_FAIL;
  520. }
  521. WCHAR wsz[256] = {0};
  522. StringCchPrintfW(wsz, 256, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
  523. HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
  524. if (SUCCEEDED(hr))
  525. {
  526. hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph,
  527. pMoniker, pdwRegister);
  528. pMoniker->Release();
  529. }
  530. pROT->Release();
  531. return hr;
  532. }
  533. #endif
  534. IBaseFilter* GetCaptureDevice(ICreateDevEnum *pDevEnum, const GUID dwCLSID, int nDeviceSelected)
  535. {
  536. IBaseFilter *pSrc = NULL;
  537. IEnumMoniker *pClassEnum = NULL;
  538. pDevEnum->CreateClassEnumerator(dwCLSID, &pClassEnum, 0);
  539. ULONG cFetched;
  540. IMoniker *pMoniker = NULL;
  541. int nEnumPos = 0;
  542. while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
  543. {
  544. if (nEnumPos == nDeviceSelected)
  545. {
  546. pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);
  547. pMoniker->Release();
  548. pClassEnum->Release();
  549. return pSrc;
  550. }
  551. pMoniker->Release();
  552. nEnumPos++;
  553. }
  554. pClassEnum->Release();
  555. return pSrc;
  556. }
  557. void stop();
  558. void releaseObjects()
  559. {
  560. if (m_notif_hwnd)
  561. {
  562. KillTimer(m_notif_hwnd,111);
  563. DestroyWindow(m_notif_hwnd);
  564. }
  565. m_notif_hwnd=NULL;
  566. if (pGraphBuilder)
  567. pGraphBuilder->Release();
  568. pGraphBuilder=0;
  569. if (pCapture)
  570. pCapture->Release();
  571. pCapture=0;
  572. if (pMediaEventEx)
  573. pMediaEventEx->Release();
  574. pMediaEventEx=0;
  575. if (pMediaControl)
  576. pMediaControl->Release();
  577. pMediaControl=0;
  578. if (pMediaSeeking)
  579. pMediaSeeking->Release();
  580. pMediaSeeking=0;
  581. if (pCapVidSrcFilter)
  582. pCapVidSrcFilter->Release();
  583. pCapVidSrcFilter=0;
  584. if (pCapAudSrcFilter)
  585. pCapAudSrcFilter->Release();
  586. pCapAudSrcFilter=0;
  587. /*
  588. if (nullfilter)
  589. {
  590. ((CBaseFilter *)nullfilter)->Release();
  591. }
  592. */
  593. nullfilter=0;
  594. /*
  595. if (nullfilter2)
  596. {
  597. nullfilter2->Release();
  598. //TODO: why does this still have 3 refcounts?
  599. }
  600. */
  601. nullfilter2=0;
  602. }
  603. #define BeginEnumFilters(pFilterGraph, pEnumFilters, pBaseFilter) \
  604. {CComPtr<IEnumFilters> pEnumFilters; \
  605. if(pFilterGraph && SUCCEEDED(pFilterGraph->EnumFilters(&pEnumFilters))) \
  606. { \
  607. for(CComPtr<IBaseFilter> pBaseFilter; S_OK == pEnumFilters->Next(1, &pBaseFilter, 0); pBaseFilter = NULL) \
  608. { \
  609. #define EndEnumFilters }}}
  610. void handleNotifyEvents()
  611. {
  612. for (;;)
  613. {
  614. long evCode;
  615. LONG_PTR param1, param2;
  616. HRESULT h = pMediaEventEx->GetEvent(&evCode, &param1, &param2, 0);
  617. if (FAILED(h)) break;
  618. switch (evCode)
  619. {
  620. case EC_OLE_EVENT:
  621. {
  622. char str[MAX_PATH] = {0};
  623. WideCharToMultiByteSZ(CP_ACP,0,(BSTR)param1,-1,str,MAX_PATH,NULL,NULL);
  624. if (!lstrcmpiA(str,"URLAndExit"))
  625. {
  626. //FUCKO
  627. /*
  628. WCHAR str[16384],*str2;
  629. WCHAR m_filename[MAX_PATH] = {0};
  630. MultiByteToWideChar( CP_ACP, 0, infos->getFilename(), lstrlen( infos->getFilename() ) + 1, m_filename, sizeof( m_filename ) );
  631. wcscpy(str,(BSTR)param2);
  632. wcscat(str,L"&filename=");
  633. MakeEscapedURL(m_filename,&str2);
  634. wcscat(str,str2);
  635. delete str2;
  636. LaunchURL(str);
  637. */
  638. }
  639. break;
  640. }
  641. case EC_BUFFERING_DATA:
  642. {
  643. m_buffering=param1;
  644. if (!m_buffering)
  645. {
  646. lastfn_status[0]=0;
  647. g_bufferstat=0;
  648. PostMessage(mod.hMainWindow,WM_USER,0,243);
  649. break;
  650. }
  651. }
  652. break;
  653. }
  654. pMediaEventEx->FreeEventParams(evCode, param1, param2);
  655. }
  656. }
  657. LRESULT CALLBACK notif_wndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  658. {
  659. if (uMsg==WM_TIMER && wParam==111 && m_notif_hwnd)
  660. {
  661. handleNotifyEvents();
  662. if (m_buffering)
  663. {
  664. BeginEnumFilters(pGraphBuilder, pEF, pBF)
  665. {
  666. if (CComQIPtr<IAMNetworkStatus, &IID_IAMNetworkStatus> pAMNS = pBF)
  667. {
  668. long BufferingProgress = 0;
  669. if (SUCCEEDED(pAMNS->get_BufferingProgress(&BufferingProgress)) && BufferingProgress > 0)
  670. {
  671. StringCchPrintfW(lastfn_status, 256,WASABI_API_LNGSTRINGW(IDS_BUFFERING),BufferingProgress);
  672. if (m_video_output) m_video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)lastfn_status,0);
  673. int bpos=BufferingProgress;
  674. int csa = mod.SAGetMode();
  675. char tempdata[75*2]={0,};
  676. int x;
  677. if (csa&1)
  678. {
  679. for (x = 0; x < bpos*75/100; x ++)
  680. {
  681. tempdata[x]=x*16/75;
  682. }
  683. }
  684. if (csa&2)
  685. {
  686. int offs=(csa&1) ? 75 : 0;
  687. x=0;
  688. while (x < bpos*75/100)
  689. {
  690. tempdata[offs + x++]=-6+x*14/75;
  691. }
  692. while (x < 75)
  693. {
  694. tempdata[offs + x++]=0;
  695. }
  696. }
  697. if (csa==4)
  698. {
  699. tempdata[0]=tempdata[1]=(bpos*127/100);
  700. }
  701. if (csa) mod.SAAdd(tempdata,++g_bufferstat,(csa==3)?0x80000003:csa);
  702. PostMessage(mod.hMainWindow,WM_USER,0,243);
  703. break;
  704. }
  705. }
  706. }
  707. EndEnumFilters
  708. }
  709. }
  710. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  711. }
  712. int play(const wchar_t *fn)
  713. {
  714. paused=0;
  715. decode_pos_ms=0;
  716. seek_needed=-1;
  717. m_length=-1;
  718. g_quit=0;
  719. lstrcpyn(m_lastfn,fn, 2048);
  720. m_avgfps_start=0;
  721. m_nbframes=0;
  722. m_float=0;
  723. m_notif_hwnd=NULL;
  724. lastfn_status[0]=0;
  725. m_buffering=0;
  726. g_bufferstat=0;
  727. double aspect=1.0;
  728. HRESULT hr;
  729. assert(pGraphBuilder==0);
  730. hr = ::CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void**)&pGraphBuilder);
  731. if (FAILED(hr))
  732. return 1;
  733. #ifdef DEBUG
  734. DWORD dwRegister;
  735. AddToRot(pGraphBuilder, &dwRegister);
  736. #endif
  737. #ifdef IN_DSHOW_CAPTURE_SUPPORT // disable capture, for now
  738. m_is_capture=!wcsncmp(fn, L"cap://",6);
  739. #endif
  740. // CWAAudioRenderer *nullfilter;
  741. // CWAVideoRenderer *nullfilter2;
  742. has_audio=true; has_video=true; has_palette=false;
  743. // insert audio renderer
  744. nullfilter=new CWAAudioRenderer();
  745. pGraphBuilder->AddFilter(nullfilter,L"Null Audio");
  746. nullfilter->SetCallback(new CAudioGrab());
  747. // insert video renderer
  748. nullfilter2=new CWAVideoRenderer();
  749. pGraphBuilder->AddFilter(nullfilter2,L"Null Video");
  750. nullfilter2->SetCallback(new CVideoGrab());
  751. assert(pMediaEventEx==0);
  752. pGraphBuilder->QueryInterface(IID_IMediaEvent, (void **)&pMediaEventEx);
  753. if (!pMediaEventEx)
  754. {
  755. releaseObjects();
  756. return 1;
  757. }
  758. m_video_output=(IVideoOutput *)SendMessage(mod.hMainWindow,WM_USER,0,IPC_GET_IVIDEOOUTPUT);
  759. if (!m_video_output)
  760. {
  761. releaseObjects();
  762. return 1;
  763. }
  764. m_video_output->extended(VIDUSER_SET_TRACKSELINTERFACE, (INT_PTR)pTrackSelector, 0);
  765. //create window that will receive filter notifications
  766. static int classReg=0;
  767. if (!classReg)
  768. {
  769. WNDCLASS wc={0,};
  770. wc.style = CS_DBLCLKS;
  771. wc.lpfnWndProc = notif_wndProc;
  772. wc.hInstance = mod.hDllInstance;
  773. wc.hIcon = NULL;
  774. wc.hCursor = NULL;
  775. wc.lpszClassName = L"in_dshowClass";
  776. if (!RegisterClassW(&wc))
  777. return 1;
  778. classReg=1;
  779. }
  780. m_notif_hwnd=CreateWindow(L"in_dshowClass",L"dshow_notif",NULL,0,0,1,1,NULL,NULL,mod.hDllInstance,NULL);
  781. SetTimer(m_notif_hwnd,111,500,0);
  782. #ifdef IN_DSHOW_CAPTURE_SUPPORT // disable capture, for now
  783. if (m_is_capture)
  784. {
  785. //build capture graph
  786. assert(pCapture==0);
  787. HRESULT hr = CoCreateInstance((REFCLSID)CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, (REFIID)IID_ICaptureGraphBuilder2, (void **)&pCapture);
  788. pCapture->SetFiltergraph(pGraphBuilder);
  789. CComPtr<ICreateDevEnum> pDevEnum = NULL;
  790. if (CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pDevEnum) != S_OK)
  791. {
  792. releaseObjects();
  793. return 1;
  794. }
  795. int vcapdev=_wtoi(fn+6);
  796. int acapdev=_wtoi(fn+8); //FUCKO
  797. assert(pCapVidSrcFilter==0);
  798. pCapVidSrcFilter = GetCaptureDevice(pDevEnum, CLSID_VideoInputDeviceCategory, vcapdev);
  799. if (!pCapVidSrcFilter || pGraphBuilder->AddFilter(pCapVidSrcFilter, L"Video Capture") != S_OK)
  800. {
  801. releaseObjects();
  802. return 1;
  803. }
  804. //if (g_config_vidcap) {
  805. if (1)
  806. {
  807. IAMStreamConfig *pSC;
  808. hr = pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, pCapVidSrcFilter, IID_IAMStreamConfig, (void **)&pSC);
  809. if (hr != NOERROR)
  810. pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pCapVidSrcFilter, IID_IAMStreamConfig, (void **)&pSC);
  811. ISpecifyPropertyPages *pSpec=NULL;
  812. if (pSC)
  813. {
  814. pSC->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpec);
  815. if (pSpec)
  816. {
  817. CAUUID cauuid;
  818. pSpec->GetPages(&cauuid);
  819. OleCreatePropertyFrame(NULL, 0, 0, L"Poopie", 1, (IUnknown **)&pSC, cauuid.cElems, (GUID *)cauuid.pElems, 0, 0, NULL);
  820. CoTaskMemFree(cauuid.pElems);
  821. pSpec->Release();
  822. }
  823. pSC->Release();
  824. }
  825. }
  826. if (pCapVidSrcFilter && pCapture->RenderStream(0,&MEDIATYPE_Video, pCapVidSrcFilter, 0, nullfilter2) != S_OK)
  827. {
  828. releaseObjects();
  829. return 1;
  830. }
  831. assert(pCapAudSrcFilter==0);
  832. pCapAudSrcFilter = GetCaptureDevice(pDevEnum, CLSID_AudioInputDeviceCategory, acapdev);
  833. if (!pCapVidSrcFilter || pGraphBuilder->AddFilter(pCapAudSrcFilter, L"Audio Capture") != S_OK)
  834. {
  835. releaseObjects();
  836. return 1;
  837. }
  838. if (pCapVidSrcFilter && pCapture->RenderStream(0,&MEDIATYPE_Audio, pCapAudSrcFilter, 0, nullfilter) != S_OK)
  839. {
  840. releaseObjects();
  841. return 1;
  842. }
  843. }
  844. else
  845. #endif
  846. {
  847. try
  848. {
  849. hr = pGraphBuilder->RenderFile(fn,NULL);
  850. }
  851. catch (...)
  852. {
  853. releaseObjects();
  854. return 1;
  855. }
  856. if (FAILED(hr))
  857. {
  858. // check for URL launch (WMA/ASF/...)
  859. handleNotifyEvents();
  860. releaseObjects();
  861. #ifdef WINAMPX
  862. if ((hr == CLASS_E_CLASSNOTAVAILABLE) || (hr == VFW_E_UNSUPPORTED_VIDEO) || (hr == VFW_E_NO_DECOMPRESSOR))
  863. {
  864. if (ReportMissingCodec(fn)) // returns true if we sent a message
  865. return -500; // Unsupported format
  866. return -200; // Can't play file
  867. }
  868. #endif // WINAMPX
  869. return 1;
  870. }
  871. #ifdef WINAMPX
  872. // Check if it's a partial playing of the file (likely video missing)
  873. if ((hr == VFW_S_PARTIAL_RENDER) || (hr == VFW_S_VIDEO_NOT_RENDERED))
  874. {
  875. if (!ReportMissingCodec(fn)) // Report the missing codec if we can determine it
  876. mod.fire_winampstatus(WINAMPX_STATUS_MISSING_AVI_CODEC, 0); // If we can't report a null codec missing
  877. }
  878. #endif // WINAMPX
  879. }
  880. // check if video has been negociated
  881. {
  882. CMediaType *mt=nullfilter2->GetAcceptedType();
  883. GUID t=mt->subtype;
  884. if (t==MEDIASUBTYPE_YUY2) video_mediatype=VIDEO_MAKETYPE('Y','U','Y','2');
  885. else if (t==MEDIASUBTYPE_YV12) video_mediatype=VIDEO_MAKETYPE('Y','V','1','2');
  886. else if (t==MEDIASUBTYPE_RGB32) video_mediatype=VIDEO_MAKETYPE('R','G','3','2');
  887. else if (t==MEDIASUBTYPE_RGB24) video_mediatype=VIDEO_MAKETYPE('R','G','2','4');
  888. else if (t==MEDIASUBTYPE_RGB8) video_mediatype=VIDEO_MAKETYPE('R','G','B','8');
  889. else if (t==MEDIASUBTYPE_YVYU) video_mediatype=VIDEO_MAKETYPE('Y','V','Y','U');
  890. else
  891. {
  892. has_video=NULL;
  893. }
  894. if (has_video)
  895. {
  896. #ifdef DEBUGVIDEO
  897. char tmp[512] = {0};
  898. int a=video_mediatype;
  899. wsprintf(tmp,"file: %s %c%c%c%c\n",fn,(char)(a&0xff),(char)((a>>8)&0xff),(char)((a>>16)&0xff),(char)((a>>24)&0xff));
  900. outputDebugStr(tmp);
  901. #endif
  902. GUID format=mt->formattype;
  903. int pw,ph;
  904. if (format==FORMAT_VideoInfo)
  905. {
  906. VIDEOINFOHEADER *pHeader=(VIDEOINFOHEADER*)mt->pbFormat;
  907. pw=pHeader->bmiHeader.biWidth;
  908. ph=abs(pHeader->bmiHeader.biHeight);
  909. if (pHeader->bmiHeader.biBitCount==8)
  910. {
  911. VIDEOINFO *pHeader=(VIDEOINFO*)mt->pbFormat;
  912. memcpy(palette,&pHeader->bmiColors,sizeof(RGBQUAD)*0x100);
  913. has_palette = true;
  914. }
  915. #ifdef DEBUGVIDEO
  916. RECT r=pHeader->rcSource;
  917. RECT r2=pHeader->rcTarget;
  918. char tmp[512] = {0};
  919. wsprintf(tmp,"init videoheader1: %i %i %i %i, %i %i %i %i\n",r.left,r.right,r.top,r.bottom,r2.left,r2.right,r2.top,r2.bottom);
  920. outputDebugStr(tmp);
  921. #endif
  922. }
  923. else
  924. {
  925. VIDEOINFOHEADER2 *pHeader=(VIDEOINFOHEADER2*)mt->pbFormat;
  926. pw=pHeader->bmiHeader.biWidth;
  927. ph=abs(pHeader->bmiHeader.biHeight);
  928. if (pHeader->dwPictAspectRatioX) aspect *= (double)pHeader->dwPictAspectRatioY * (double)pw / ((double)ph * (double)pHeader->dwPictAspectRatioX);
  929. #ifdef DEBUGVIDEO
  930. RECT r=pHeader->rcSource;
  931. RECT r2=pHeader->rcTarget;
  932. char tmp[512] = {0};
  933. wsprintf(tmp,"init videoheader2: %i %i %i %i, %i %i %i %i\n",r.left,r.right,r.top,r.bottom,r2.left,r2.right,r2.top,r2.bottom);
  934. outputDebugStr(tmp);
  935. #endif
  936. }
  937. video_w=pw; video_h=ph;
  938. video_len=(video_w*video_h*4)+sizeof(double); //CT> might be wrong for YUY2, etc...
  939. }
  940. else
  941. {
  942. pGraphBuilder->RemoveFilter(nullfilter2);
  943. // TODO: release?
  944. nullfilter2=0;
  945. }
  946. }
  947. // check if audio has been negociated
  948. {
  949. CMediaType *mt=nullfilter->GetAcceptedType();
  950. if (mt->subtype!=MEDIASUBTYPE_PCM && mt->subtype!=MEDIASUBTYPE_IEEE_FLOAT)
  951. has_audio=NULL;
  952. else
  953. {
  954. WAVEFORMATEX *pHeader = (WAVEFORMATEX*)mt->pbFormat;
  955. // reget this cause this is the real UNCOMPRESSED format
  956. audio_bps = pHeader->wBitsPerSample;
  957. audio_srate = pHeader->nSamplesPerSec;
  958. audio_nch = pHeader->nChannels;
  959. if (mt->subtype == MEDIASUBTYPE_IEEE_FLOAT/*WAVE_FORMAT_IEEE_FLOAT*//*audio_bps==32 || audio_bps==64*/)
  960. {
  961. m_float = 1;
  962. m_src_bps = audio_bps;
  963. //audio_bps = 16; //TODO: read bits from AGAVE_API_CONFIG :)
  964. }
  965. }
  966. }
  967. // if none has been negociated, fuck off
  968. if (!has_video && !has_audio)
  969. {
  970. releaseObjects();
  971. return 1;
  972. }
  973. if (!has_audio)
  974. {
  975. pGraphBuilder->RemoveFilter(nullfilter);
  976. // TODO: release?
  977. nullfilter=0;
  978. }
  979. // QueryInterface for some basic interfaces
  980. assert(pMediaControl==0);
  981. pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
  982. assert(pMediaSeeking==0);
  983. pGraphBuilder->QueryInterface(IID_IMediaSeeking, (void **)&pMediaSeeking);
  984. if (pMediaControl == NULL || pMediaEventEx == NULL)
  985. {
  986. releaseObjects();
  987. return 1;
  988. }
  989. CComPtr<IVideoWindow> pVideoWindow;
  990. pGraphBuilder->QueryInterface(IID_IVideoWindow, (void**)&pVideoWindow);
  991. pVideoWindow->put_AutoShow(OAFALSE);
  992. CComPtr<IMediaFilter> pMediaFilter;
  993. pGraphBuilder->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter);
  994. //FUCKO: verify if setsyncsource is really necessary (might be useful for sync under
  995. // heavy cpu load)
  996. /*if(!STRICMP(ext,"wma") || !STRICMP(ext,"asf") || !STRICMP(ext,"wmv")) { }
  997. else*/
  998. #if IN_DSHOW_CAPTURE_SUPPORT // disable
  999. if (!m_is_capture)
  1000. pMediaFilter->SetSyncSource(NULL);
  1001. #endif
  1002. // retrieves length
  1003. {
  1004. CComPtr<IMediaPosition> pMediaPosition=NULL;
  1005. pGraphBuilder->QueryInterface(IID_IMediaPosition, (void **)&pMediaPosition);
  1006. if (pMediaPosition)
  1007. {
  1008. REFTIME length;
  1009. pMediaPosition->get_Duration(&length);
  1010. m_length=(int)(length*1000);
  1011. }
  1012. }
  1013. getInfo(fn, m_status, 512, NULL,0, &m_bitrate, &audio_nch);
  1014. if (has_audio)
  1015. {
  1016. //open output plugin
  1017. int maxlat=mod.outMod->Open(audio_srate,audio_nch,audio_bps,-1,-1);
  1018. if (maxlat<0)
  1019. {
  1020. releaseObjects();
  1021. return 1;
  1022. }
  1023. // if (has_video)
  1024. mod.SetInfo(m_bitrate,audio_srate/1000,audio_nch,1);
  1025. //else
  1026. // mod.SetInfo(audioBitrate,audio_srate/1000,audio_nch,1);
  1027. mod.SAVSAInit(maxlat,audio_srate);
  1028. mod.VSASetInfo(audio_srate,audio_nch);
  1029. mod.outMod->SetVolume(-666);
  1030. }
  1031. if (has_video)
  1032. {
  1033. //open video stuff
  1034. m_video_output->extended(VIDUSER_SET_THREAD_SAFE, 0, 0); // we are NOT thread safe - we call draw() than a different thread than open()
  1035. m_video_output->open(video_w,video_h,0,aspect,video_mediatype);
  1036. #ifdef WINAMPX
  1037. if (has_palette)
  1038. {
  1039. m_video_output->extended(VIDUSER_SET_PALETTE, (int)palette, 0);
  1040. }
  1041. HWND hVideoWnd = (HWND)m_video_output->extended(VIDUSER_GET_VIDEOHWND, 0, 0);
  1042. InvalidateRect(hVideoWnd, NULL, TRUE);
  1043. #endif
  1044. }
  1045. m_video_output->extended(VIDUSER_SET_INFOSTRINGW,(INT_PTR)m_status,0);
  1046. m_laststatus=GetTickCount();
  1047. m_starttime=GetTickCount(); //used for non-audio videos
  1048. hr = pMediaControl->Run();
  1049. if (FAILED(hr))
  1050. {
  1051. stop();
  1052. releaseObjects();
  1053. return 1;
  1054. }
  1055. lstrcpynW(lastfn,fn, MAX_PATH);
  1056. return 0;
  1057. }
  1058. // standard pause implementation
  1059. void pause()
  1060. {
  1061. paused=1;
  1062. m_time_paused=GetTickCount()-m_starttime;
  1063. if (has_audio) mod.outMod->Pause(1);
  1064. }
  1065. void unpause()
  1066. {
  1067. paused=0;
  1068. if (has_audio)
  1069. mod.outMod->Pause(0);
  1070. m_starttime=GetTickCount()-m_time_paused;
  1071. m_nbframes=m_avgfps_start=0;
  1072. m_laststatus=GetTickCount();
  1073. }
  1074. int ispaused()
  1075. {
  1076. return paused;
  1077. } // Note: Shared with the dsr routines
  1078. // stop playing.
  1079. void stop()
  1080. {
  1081. g_quit=1;
  1082. while (doingaudioshit) Sleep(10);
  1083. if (pMediaControl)
  1084. pMediaControl->Stop();
  1085. if (m_video_output)
  1086. m_video_output->close();
  1087. mod.outMod->Close();
  1088. mod.SAVSADeInit();
  1089. releaseObjects();
  1090. m_length=-1;
  1091. m_lastfn[0]=0;
  1092. }
  1093. int getlength()
  1094. {
  1095. return m_length;
  1096. }
  1097. int getoutputtime()
  1098. {
  1099. if (g_bufferstat) return g_bufferstat;
  1100. if (has_audio)
  1101. {
  1102. return decode_pos_ms+
  1103. (mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime());
  1104. }
  1105. else
  1106. {
  1107. if (paused)
  1108. return m_time_paused;
  1109. return GetTickCount()-m_starttime;
  1110. }
  1111. }
  1112. void setoutputtime(int time_in_ms)
  1113. {
  1114. if (pMediaSeeking)
  1115. {
  1116. DWORD dwCaps = AM_SEEKING_CanSeekAbsolute;
  1117. if (pMediaSeeking->CheckCapabilities(&dwCaps) == S_OK)
  1118. {
  1119. int oldpause=paused;
  1120. if (oldpause) unpause();
  1121. pMediaSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
  1122. LONGLONG l=((LONGLONG)time_in_ms)*10000;
  1123. pMediaSeeking->SetPositions(&l,AM_SEEKING_AbsolutePositioning|AM_SEEKING_SeekToKeyFrame|AM_SEEKING_ReturnTime ,NULL,AM_SEEKING_NoPositioning);
  1124. l/=10000;
  1125. time_in_ms=(int)l;
  1126. mod.outMod->Flush(time_in_ms);
  1127. decode_pos_ms=time_in_ms;
  1128. m_starttime=GetTickCount()-time_in_ms; //non-audio videos
  1129. m_nbframes=m_avgfps_start=0;
  1130. m_laststatus=GetTickCount();
  1131. if (oldpause) pause();
  1132. }
  1133. }
  1134. }
  1135. void setvolume(int volume)
  1136. {
  1137. {
  1138. mod.outMod->SetVolume(volume);
  1139. }
  1140. }
  1141. void setpan(int pan)
  1142. {
  1143. mod.outMod->SetPan(pan);
  1144. }
  1145. int infoDlg(const wchar_t *fn, HWND hwnd)
  1146. {
  1147. doInfo(WASABI_API_LNG_HINST,hwnd, fn);
  1148. return INFOBOX_UNCHANGED;
  1149. }
  1150. // this is an odd function. it is used to get the title and/or
  1151. // length of a track.
  1152. // if filename is either NULL or of length 0, it means you should
  1153. // return the info of lastfn. Otherwise, return the information
  1154. // for the file in filename.
  1155. // if title is NULL, no title is copied into it.
  1156. // if length_in_ms is NULL, no length is copied into it.
  1157. void getfileinfo(const wchar_t *filename, wchar_t *title, int *length_in_ms)
  1158. {
  1159. if (!filename || !*filename) // currently playing file
  1160. {
  1161. if (length_in_ms) *length_in_ms=getlength();
  1162. if (title) // get non-path portion.of filename
  1163. {
  1164. wchar_t *p = PathFindFileNameW(lastfn);
  1165. if (lastfn_status[0])
  1166. {
  1167. StringCchPrintfW(title, GETFILEINFO_TITLE_LENGTH, L"[%s] %s",lastfn_status,p);
  1168. }
  1169. else
  1170. {
  1171. lstrcpynW(title,p, GETFILEINFO_TITLE_LENGTH);
  1172. }
  1173. }
  1174. }
  1175. else // some other file
  1176. {
  1177. if (length_in_ms) // calculate length
  1178. {
  1179. *length_in_ms = GetFileLength(filename);
  1180. }
  1181. if (title) // get non path portion of filename
  1182. {
  1183. lstrcpynW(title, filename, GETFILEINFO_TITLE_LENGTH);
  1184. PathStripPathW(title);
  1185. PathRemoveExtensionW(title);
  1186. }
  1187. }
  1188. }
  1189. void eq_set(int on, char data[10], int preamp)
  1190. {
  1191. }
  1192. // module definition.
  1193. In_Module mod =
  1194. {
  1195. IN_VER_RET, // defined in IN2.H
  1196. "nullsoft(in_dshow.dll)",
  1197. 0, // hMainWindow (filled in by winamp)
  1198. 0, // hDllInstance (filled in by winamp)
  1199. /*"MPG;MPEG;M2V\0MPG File (*.MPG;*.MPEG;*.M2V)\0"
  1200. "AVI\0AVI File (*.AVI)\0"
  1201. "ASF;WMV\0ASF/WMV File (*.ASF;*.WMV)\0"*/
  1202. 0, // this is a double-null limited list. "EXT\0Description\0EXT\0Description\0" etc.
  1203. 1, // is_seekable
  1204. 1, // uses output plug-in system
  1205. config,
  1206. about,
  1207. init,
  1208. quit,
  1209. getfileinfo,
  1210. infoDlg,
  1211. isourfile,
  1212. play,
  1213. pause,
  1214. unpause,
  1215. ispaused,
  1216. stop,
  1217. getlength,
  1218. getoutputtime,
  1219. setoutputtime,
  1220. setvolume,
  1221. setpan,
  1222. 0,0,0,0,0,0,0,0,0, // visualization calls filled in by winamp
  1223. 0,0, // dsp calls filled in by winamp
  1224. eq_set,
  1225. NULL, // setinfo call filled in by winamp
  1226. 0 // out_mod filled in by winamp
  1227. };
  1228. static char default_extlist[]="MPG;MPEG;M2V";
  1229. static const wchar_t *pExtList[]={L"MPG",L"MPEG",L"M2V",L"AVI",L"MOV",L"FLV",L"FLV1",L"OGV",L"OGA",L"OGM",L"RMVB",L"RM",L"VOB",L"AC3",L"MKV",L"MP4",L"M4V",L"3GP"};
  1230. static const int pExtDescIdList[] = {0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14,};
  1231. static const int pExtDescList[] =
  1232. {
  1233. IDS_FAMILY_STRING_MPEG,
  1234. IDS_FAMILY_STRING_MPEG2,
  1235. IDS_FAMILY_STRING_AVI,
  1236. IDS_FAMILY_STRING_MOV,
  1237. IDS_FAMILY_STRING_FLV,
  1238. IDS_FAMILY_STRING_OGV,
  1239. IDS_FAMILY_STRING_OGA,
  1240. IDS_FAMILY_STRING_OGM,
  1241. IDS_FAMILY_STRING_RM,
  1242. IDS_FAMILY_STRING_VOB,
  1243. IDS_FAMILY_STRING_AC3,
  1244. IDS_FAMILY_STRING_MKV,
  1245. IDS_FAMILY_STRING_MP4,
  1246. IDS_FAMILY_STRING_M4V,
  1247. IDS_FAMILY_STRING_3GPP,
  1248. };
  1249. static FILETIME ftLastWriteTime;
  1250. // is used to determine if the last write time of the file has changed when
  1251. // asked to get the metadata for the same cached file so we can update things
  1252. BOOL HasFileTimeChanged(const wchar_t *fn)
  1253. {
  1254. WIN32_FILE_ATTRIBUTE_DATA fileData = {0};
  1255. if (GetFileAttributesExW(fn, GetFileExInfoStandard, &fileData) == TRUE)
  1256. {
  1257. if(CompareFileTime(&ftLastWriteTime, &fileData.ftLastWriteTime))
  1258. {
  1259. ftLastWriteTime = fileData.ftLastWriteTime;
  1260. return TRUE;
  1261. }
  1262. }
  1263. return FALSE;
  1264. }
  1265. extern "C"
  1266. {
  1267. __declspec(dllexport) In_Module * winampGetInModule2()
  1268. {
  1269. return &mod;
  1270. }
  1271. _declspec(dllexport) int winampGetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *dest, int destlen)
  1272. {
  1273. if (!fn || !*fn)
  1274. {
  1275. if (!lstrcmpiA(data,"type"))
  1276. {
  1277. lstrcpyn(dest,L"1", destlen); //video
  1278. return 1;
  1279. }
  1280. return 0;
  1281. }
  1282. if (!infoFn || !infoHeader || lstrcmpiW(fn, infoFn) || HasFileTimeChanged(fn))
  1283. {
  1284. free(infoFn);
  1285. infoFn = _wcsdup(fn);
  1286. delete infoHeader;
  1287. infoHeader = MakeHeader(fn, true);
  1288. }
  1289. if (!lstrcmpiA(data,"type"))
  1290. {
  1291. if (infoHeader)
  1292. {
  1293. if (infoHeader->has_video)
  1294. lstrcpyn(dest,L"1", destlen); //video
  1295. else
  1296. lstrcpyn(dest,L"0", destlen); // no video
  1297. }
  1298. else // assume video
  1299. {
  1300. lstrcpyn(dest,L"1", destlen); //video
  1301. }
  1302. return 1;
  1303. }
  1304. if (!lstrcmpiA(data, "family"))
  1305. {
  1306. INT index;
  1307. LPCWSTR e;
  1308. DWORD lcid;
  1309. e = PathFindExtension(fn);
  1310. if (L'.' != *e || 0x00 == *(++e)) return 0;
  1311. lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
  1312. for (index = sizeof(pExtList)/sizeof(wchar_t*) - 1; index >= 0 && CSTR_EQUAL != CompareStringW(lcid, NORM_IGNORECASE, e, -1, pExtList[index], -1); index--);
  1313. if (index >= 0 && S_OK == StringCchCopyW(dest, destlen, WASABI_API_LNGSTRINGW(pExtDescList[pExtDescIdList[index]]))) return 1;
  1314. return 0;
  1315. }
  1316. if (!lstrcmpiA(data,"length"))
  1317. {
  1318. int len = GetFileLength(fn);
  1319. if (len == -1000)
  1320. dest[0]=0;
  1321. else
  1322. StringCchPrintf(dest, destlen, L"%d", len);
  1323. return 1;
  1324. }
  1325. else if (!lstrcmpiA(data, "bitrate"))
  1326. {
  1327. int bitrate;
  1328. getInfo(fn, NULL, 0, NULL,0, &bitrate, NULL);
  1329. StringCchPrintf(dest, destlen, L"%d", bitrate);
  1330. return 1;
  1331. }
  1332. else if (!lstrcmpiA(data,"title"))
  1333. {
  1334. if (infoHeader && infoHeader->title)
  1335. lstrcpyn(dest,infoHeader->title, destlen);
  1336. else
  1337. dest[0]=0;
  1338. return 1;
  1339. }
  1340. else if (!lstrcmpiA(data,"artist"))
  1341. {
  1342. if (infoHeader && infoHeader->artist)
  1343. lstrcpyn(dest,infoHeader->artist, destlen);
  1344. else
  1345. dest[0]=0;
  1346. return 1;
  1347. }
  1348. else if (!lstrcmpiA(data,"comment"))
  1349. {
  1350. if (infoHeader && infoHeader->comment)
  1351. lstrcpyn(dest,infoHeader->comment, destlen);
  1352. else
  1353. dest[0]=0;
  1354. return 1;
  1355. }
  1356. else if (!lstrcmpiA(data,"genre"))
  1357. {
  1358. if (infoHeader && infoHeader->genre)
  1359. lstrcpyn(dest,infoHeader->genre, destlen);
  1360. else
  1361. dest[0]=0;
  1362. return 1;
  1363. }
  1364. else if (!lstrcmpiA(data,"album"))
  1365. {
  1366. if (infoHeader && infoHeader->album)
  1367. lstrcpyn(dest,infoHeader->album, destlen);
  1368. else
  1369. dest[0]=0;
  1370. return 1;
  1371. }
  1372. else if (!lstrcmpiA(data,"composer"))
  1373. {
  1374. if (infoHeader && infoHeader->composer)
  1375. lstrcpyn(dest,infoHeader->composer, destlen);
  1376. else
  1377. dest[0]=0;
  1378. return 1;
  1379. }
  1380. else if (!lstrcmpiA(data,"publisher"))
  1381. {
  1382. if (infoHeader && infoHeader->publisher)
  1383. lstrcpyn(dest,infoHeader->publisher, destlen);
  1384. else
  1385. dest[0]=0;
  1386. return 1;
  1387. }
  1388. return 0;
  1389. }
  1390. };