main.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. #include "main.h"
  2. #include <shlwapi.h>
  3. #include "api__in_flv.h"
  4. #include <stdio.h>
  5. #include <api/service/waservicefactory.h>
  6. #include "../Winamp/wa_ipc.h"
  7. #include "resource.h"
  8. #include "FileProcessor.h"
  9. #include "FLVCOM.h"
  10. #include "VideoThread.h"
  11. #include "../f263/flv_f263_decoder.h"
  12. #include <strsafe.h>
  13. #define FLV_PLUGIN_VERSION L"1.47"
  14. template <class api_T>
  15. static void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
  16. {
  17. if (plugin.service)
  18. {
  19. waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
  20. if (factory)
  21. api_t = reinterpret_cast<api_T *>( factory->getInterface() );
  22. }
  23. }
  24. template <class api_T>
  25. static void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
  26. {
  27. if (plugin.service && api_t)
  28. {
  29. waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
  30. if (factory)
  31. factory->releaseInterface(api_t);
  32. }
  33. api_t = NULL;
  34. }
  35. /* Wasabi services */
  36. api_application *WASABI_API_APP=0;
  37. api_config *AGAVE_API_CONFIG=0;
  38. api_language *WASABI_API_LNG = 0;
  39. In_Module *swf_mod = 0;
  40. HMODULE in_swf = 0;
  41. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  42. wchar_t pluginName[256] = {0};
  43. wchar_t *playFile=0;
  44. HANDLE killswitch, playthread=0;
  45. int g_length=-1000;
  46. bool video_only=false;
  47. int paused = 0;
  48. nu::VideoClock video_clock;
  49. int m_need_seek=-1;
  50. extern uint32_t last_timestamp;
  51. int pan = 0, volume = -666;
  52. wchar_t *stream_title=0;
  53. Nullsoft::Utility::LockGuard stream_title_guard;
  54. // {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
  55. static const GUID playbackConfigGroupGUID =
  56. { 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
  57. void SetFileExtensions(void)
  58. {
  59. static char fileExtensionsString[256] = {0}; // "FLV\0Flash Video\0"
  60. char* end = 0;
  61. size_t remaining;
  62. StringCchCopyExA(fileExtensionsString, 256, "FLV", &end, &remaining, 0);
  63. StringCchCopyExA(end+1, remaining-1, WASABI_API_LNGSTRING(IDS_FLASH_VIDEO), 0, 0, 0);
  64. plugin.FileExtensions = fileExtensionsString;
  65. }
  66. int Init()
  67. {
  68. if (!IsWindow(plugin.hMainWindow))
  69. return IN_INIT_FAILURE;
  70. ServiceBuild(AGAVE_API_CONFIG, AgaveConfigGUID);
  71. ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
  72. ServiceBuild(WASABI_API_LNG, languageApiGUID);
  73. // need to have this initialised before we try to do anything with localisation features
  74. WASABI_API_START_LANG(plugin.hDllInstance,InFlvLangGUID);
  75. if (plugin.service->service_getServiceByGuid(flv_h263_guid))
  76. StringCchPrintfW(pluginName,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_FLV),FLV_PLUGIN_VERSION L" (h)");
  77. else
  78. StringCchPrintfW(pluginName,256,WASABI_API_LNGSTRINGW(IDS_NULLSOFT_FLV),FLV_PLUGIN_VERSION);
  79. plugin.description = (char*)pluginName;
  80. SetFileExtensions();
  81. DispatchInfo flvDisp = { L"FLV", &flvCOM };
  82. SendMessage(plugin.hMainWindow, WM_WA_IPC, (WPARAM)&flvDisp, IPC_ADD_DISPATCH_OBJECT);
  83. killswitch = CreateEvent(NULL, TRUE, FALSE, NULL);
  84. return IN_INIT_SUCCESS;
  85. }
  86. void Quit()
  87. {
  88. CloseHandle(killswitch);
  89. ServiceRelease(AGAVE_API_CONFIG, AgaveConfigGUID);
  90. ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
  91. ServiceRelease(WASABI_API_LNG, languageApiGUID);
  92. if (in_swf)
  93. FreeLibrary(in_swf);
  94. }
  95. void GetFileInfo(const wchar_t *file, wchar_t *title, int *length_in_ms)
  96. {
  97. if (!file || !*file)
  98. {
  99. if (swf_mod)
  100. {
  101. swf_mod->GetFileInfo(file, title, length_in_ms);
  102. return;
  103. }
  104. file = playFile;
  105. }
  106. // no title support as it's not always stored in a standard way in FLV
  107. if (title)
  108. {
  109. Nullsoft::Utility::AutoLock stream_lock(stream_title_guard);
  110. if (stream_title && (!file || !file[0]))
  111. {
  112. lstrcpyn(title, stream_title, GETFILEINFO_TITLE_LENGTH);
  113. }
  114. else
  115. {
  116. lstrcpyn(title, file ? file : L"", GETFILEINFO_TITLE_LENGTH);
  117. PathStripPath(title);
  118. }
  119. }
  120. // calculate length
  121. if (file == playFile) // currently playing song?
  122. *length_in_ms = g_length; // easy!
  123. else if (PathIsURLW(file)) // don't calculate lengths for URLs since we'd have to connect
  124. {
  125. *length_in_ms = -1;
  126. }
  127. else
  128. {
  129. // open the file and find the "duration" metadata
  130. FileProcessor processor(file);
  131. size_t frameIndex=0;
  132. FrameData frameData;
  133. int length=-1;
  134. bool found=false;
  135. do
  136. {
  137. // enumerate the frames as we process
  138. // this function will fail the first few times
  139. // because Process() hasn't been called enough
  140. if (processor.GetFrame(frameIndex, frameData))
  141. {
  142. if (frameData.header.type == FLV::FRAME_TYPE_METADATA)
  143. {
  144. if (processor.Seek(frameData.location + 15) == -1)
  145. break;
  146. size_t dataSize = frameData.header.dataSize;
  147. uint8_t *metadatadata= (uint8_t *)calloc(dataSize, sizeof(uint8_t));
  148. if (metadatadata)
  149. {
  150. size_t bytesRead = processor.Read(metadatadata, dataSize);
  151. if (bytesRead != dataSize)
  152. {
  153. free(metadatadata);
  154. break;
  155. }
  156. FLVMetadata metadata;
  157. metadata.Read(metadatadata, dataSize);
  158. for ( FLVMetadata::Tag *tag : metadata.tags )
  159. {
  160. if ( !_wcsicmp( tag->name.str, L"onMetaData" ) )
  161. {
  162. AMFType *duration = tag->parameters->array[ L"duration" ];
  163. if ( duration )
  164. {
  165. length = (int)( AMFGetDouble( duration ) * 1000.0 );
  166. found = true;
  167. }
  168. }
  169. }
  170. free(metadatadata);
  171. }
  172. else
  173. break;
  174. }
  175. frameIndex++;
  176. }
  177. }
  178. while (!found && processor.Process() == FLV_OK); // for local files, any return value other than FLV_OK is a failure
  179. *length_in_ms = length;
  180. }
  181. }
  182. int InfoBox(const wchar_t *file, HWND hwndParent)
  183. {
  184. return INFOBOX_UNCHANGED;
  185. }
  186. int IsOurFile(const wchar_t *file)
  187. {
  188. return 0;
  189. }
  190. int Play(const wchar_t *file)
  191. {
  192. {
  193. Nullsoft::Utility::AutoLock stream_lock(stream_title_guard);
  194. free(stream_title);
  195. stream_title=0;
  196. }
  197. if (!videoOutput)
  198. videoOutput = (IVideoOutput *)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GET_IVIDEOOUTPUT);
  199. video_only=false;
  200. m_need_seek = -1;
  201. video_clock.Reset();
  202. paused=0;
  203. ResetEvent(killswitch);
  204. free(playFile);
  205. playFile = _wcsdup(file);
  206. playthread=CreateThread(0, 0, PlayProcedure, 0, 0, 0);
  207. SetThreadPriority(playthread, (INT)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
  208. return 0; // success
  209. }
  210. void Pause()
  211. {
  212. paused = 1;
  213. if (swf_mod)
  214. {
  215. swf_mod->Pause();
  216. }
  217. else if (video_only)
  218. {
  219. video_clock.Pause();
  220. }
  221. else
  222. {
  223. plugin.outMod->Pause(1);
  224. }
  225. }
  226. void UnPause()
  227. {
  228. paused = 0;
  229. if (swf_mod)
  230. {
  231. swf_mod->UnPause();
  232. }
  233. else if (video_only)
  234. {
  235. video_clock.Unpause();
  236. }
  237. else
  238. {
  239. plugin.outMod->Pause(0);
  240. }
  241. }
  242. int IsPaused()
  243. {
  244. if (swf_mod)
  245. return swf_mod->IsPaused();
  246. return paused;
  247. }
  248. void Stop()
  249. {
  250. if (swf_mod)
  251. {
  252. swf_mod->Stop();
  253. swf_mod=0;
  254. return;
  255. }
  256. SetEvent(killswitch);
  257. WaitForSingleObject(playthread, INFINITE);
  258. playthread=0;
  259. plugin.outMod->Close();
  260. plugin.SAVSADeInit();
  261. paused=0;
  262. }
  263. int GetLength()
  264. {
  265. if (swf_mod)
  266. {
  267. return swf_mod->GetLength();
  268. }
  269. return g_length;
  270. }
  271. int GetOutputTime()
  272. {
  273. if (swf_mod)
  274. {
  275. return swf_mod->GetOutputTime();
  276. }
  277. else if (video_only)
  278. {
  279. return video_clock.GetOutputTime();
  280. }
  281. else if (plugin.outMod)
  282. {
  283. return plugin.outMod->GetOutputTime();
  284. }
  285. else
  286. return 0;
  287. }
  288. void SetOutputTime(int time_in_ms)
  289. {
  290. if (swf_mod)
  291. {
  292. swf_mod->SetOutputTime(time_in_ms);
  293. return ;
  294. }
  295. m_need_seek=time_in_ms;
  296. }
  297. void SetVolume(int _volume)
  298. {
  299. if (swf_mod)
  300. {
  301. swf_mod->SetVolume(_volume);
  302. return ;
  303. }
  304. volume = _volume;
  305. if (plugin.outMod)
  306. plugin.outMod->SetVolume(volume);
  307. }
  308. void SetPan(int _pan)
  309. {
  310. if (swf_mod)
  311. {
  312. swf_mod->SetPan(_pan);
  313. return ;
  314. }
  315. pan = _pan;
  316. if (plugin.outMod)
  317. plugin.outMod->SetPan(pan);
  318. }
  319. void EQSet(int on, char data[10], int preamp)
  320. {
  321. if (swf_mod)
  322. {
  323. swf_mod->EQSet(on, data, preamp);
  324. return;
  325. }
  326. }
  327. int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
  328. {
  329. MSGBOXPARAMS msgbx = {sizeof(MSGBOXPARAMS),0};
  330. msgbx.lpszText = message;
  331. msgbx.lpszCaption = title;
  332. msgbx.lpszIcon = MAKEINTRESOURCE(102);
  333. msgbx.hInstance = GetModuleHandle(0);
  334. msgbx.dwStyle = MB_USERICON;
  335. msgbx.hwndOwner = parent;
  336. return MessageBoxIndirect(&msgbx);
  337. }
  338. void About(HWND hwndParent)
  339. {
  340. wchar_t message[1024] = {0}, text[1024] = {0};
  341. WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_FLV_OLD,text,1024);
  342. StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
  343. plugin.description, TEXT(__DATE__));
  344. DoAboutMessageBox(hwndParent,text,message);
  345. }
  346. In_Module plugin =
  347. {
  348. IN_VER_RET,
  349. "nullsoft(in_flv.dll)",
  350. 0,
  351. 0,
  352. 0 /*"FLV\0Flash Video\0"*/,
  353. 1, // not seekable, for now
  354. 1,
  355. About,
  356. About,
  357. Init,
  358. Quit,
  359. GetFileInfo,
  360. InfoBox,
  361. IsOurFile,
  362. Play,
  363. Pause,
  364. UnPause,
  365. IsPaused,
  366. Stop,
  367. GetLength,
  368. GetOutputTime,
  369. SetOutputTime,
  370. SetVolume,
  371. SetPan,
  372. 0,
  373. 0,
  374. 0,
  375. 0,
  376. 0,
  377. 0,
  378. 0,
  379. 0,
  380. 0,
  381. 0,
  382. 0,
  383. EQSet,
  384. 0,
  385. 0
  386. };
  387. extern "C" __declspec(dllexport) In_Module * winampGetInModule2()
  388. {
  389. return &plugin;
  390. }