VideoThread.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. #include "main.h"
  2. #include "api__in_avi.h"
  3. #include "../nu/AutoLock.h"
  4. #include "../nu/SampleQueue.h"
  5. #include "../Winamp/wa_ipc.h"
  6. #include "interfaces.h"
  7. #include "../nsavi/nsavi.h"
  8. #include "../nu/ThreadName.h"
  9. #include "player.h"
  10. // {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
  11. static const GUID playbackConfigGroupGUID =
  12. { 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
  13. extern nsavi::HeaderList header_list;
  14. extern int video_stream_num;
  15. int width, height;
  16. extern IVideoOutput *video_output;
  17. static HANDLE video_thread=0;
  18. extern ifc_avivideodecoder *video_decoder;
  19. bool video_opened=false;
  20. static HANDLE coded_frames_event=0;
  21. static Nullsoft::Utility::LockGuard coded_frames_guard;
  22. uint64_t video_total_time=0;
  23. HANDLE video_break=0, video_flush=0, video_flush_done=0, video_resume=0, video_ready=0;
  24. static int GetStreamNumber(uint32_t id)
  25. {
  26. char *stream_data = (char *)(&id);
  27. if (!isxdigit(stream_data[0]) || !isxdigit(stream_data[1]))
  28. return -1;
  29. stream_data[2] = 0;
  30. int stream_number = strtoul(stream_data, 0, 16);
  31. return stream_number;
  32. }
  33. void Video_Init()
  34. {
  35. video_opened=false;
  36. video_decoder=0;
  37. video_thread=0;
  38. width=0;
  39. height=0;
  40. video_total_time=0;
  41. if (coded_frames_event == 0)
  42. coded_frames_event = CreateEvent(NULL, FALSE, FALSE, NULL);
  43. /* video events */
  44. if (!video_break)
  45. video_break = CreateEvent(NULL, TRUE, FALSE, NULL);
  46. if (!video_flush_done)
  47. video_flush_done = CreateEvent(NULL, FALSE, FALSE, NULL);
  48. if (!video_flush)
  49. video_flush = CreateEvent(NULL, TRUE, FALSE, NULL);
  50. if (!video_resume)
  51. video_resume = CreateEvent(NULL, TRUE, FALSE, NULL);
  52. if (!video_ready)
  53. video_ready = CreateEvent(NULL, TRUE, FALSE, NULL);
  54. }
  55. struct FRAMEDATA
  56. {
  57. FRAMEDATA()
  58. {
  59. type = 0;
  60. data=0;
  61. length=0;
  62. }
  63. ~FRAMEDATA()
  64. {
  65. free(data);
  66. }
  67. void Reset()
  68. {
  69. free(data);
  70. data=0;
  71. length=0;
  72. type = 0;
  73. }
  74. void Set(uint16_t _type, void *_data, size_t _length)
  75. {
  76. type = _type;
  77. data = _data;
  78. length = _length;
  79. }
  80. void *data;
  81. size_t length;
  82. uint16_t type;
  83. };
  84. static SampleQueue<FRAMEDATA> coded_frames;
  85. extern int GetOutputTime();
  86. struct VideoContext
  87. {
  88. nsavi::avi_reader *reader;
  89. nsavi::Demuxer *demuxer;
  90. int video_stream_num;
  91. };
  92. static void DecodeVideo(FRAMEDATA *frame_data)
  93. {
  94. HANDLE handles[] = {killswitch, video_break};
  95. if (WaitForMultipleObjects(2, handles, FALSE, 0) == WAIT_TIMEOUT)
  96. {
  97. int decodeResult = video_decoder->DecodeChunk(frame_data->type, frame_data->data, frame_data->length);
  98. if (decodeResult == ifc_avivideodecoder::AVI_SUCCESS)
  99. {
  100. void *data, *decoder_data;
  101. while (video_decoder->GetPicture(&data, &decoder_data) == ifc_avivideodecoder::AVI_SUCCESS)
  102. {
  103. if (!video_opened)
  104. {
  105. int color_format;
  106. double aspect_ratio=1.0;
  107. int flip=0;
  108. if (video_decoder->GetOutputProperties(&width, &height, &color_format, &aspect_ratio, &flip) == ifc_avivideodecoder::AVI_SUCCESS)
  109. {
  110. nsavi::VPRP *vprp = header_list.stream_list[video_stream_num].video_properties;
  111. if (vprp)
  112. {
  113. uint32_t asp = vprp->aspect_ratio;
  114. uint32_t aspect_x = HIWORD(asp);
  115. uint32_t aspect_y = LOWORD(asp);
  116. aspect_ratio = (double)vprp->frame_width / (double)vprp->frame_height / ((double)aspect_x / (double)aspect_y);
  117. }
  118. else
  119. aspect_ratio = 1.0/aspect_ratio;
  120. video_output->extended(VIDUSER_SET_THREAD_SAFE, 1, 0);
  121. video_output->open(width, height, flip, aspect_ratio, color_format);
  122. video_opened=true;
  123. }
  124. }
  125. if (video_opened)
  126. {
  127. int timestamp=(int)(video_total_time*1000ULL/(uint64_t) header_list.stream_list[video_stream_num].stream_header->rate);
  128. again:
  129. int real_time =(int)GetOutputTime();
  130. if (timestamp > (real_time+5))
  131. {
  132. HANDLE handles[] = {killswitch, video_break};
  133. int ret=WaitForMultipleObjects(2, handles, FALSE, timestamp-real_time);
  134. if (ret != WAIT_TIMEOUT)
  135. {
  136. video_decoder->FreePicture(data, decoder_data);
  137. frame_data->Reset();
  138. return ;
  139. }
  140. goto again; // TODO: handle paused state a little better than this
  141. }
  142. RGB32 *palette=0;
  143. if (video_decoder->GetPalette(&palette) == ifc_avivideodecoder::AVI_SUCCESS)
  144. {
  145. video_output->extended(VIDUSER_SET_PALETTE, (INT_PTR)palette, 0);
  146. }
  147. video_output->draw(data);
  148. }
  149. video_total_time += header_list.stream_list[video_stream_num].stream_header->scale;
  150. video_decoder->FreePicture(data, decoder_data);
  151. }
  152. }
  153. }
  154. // frame_data->Reset();
  155. }
  156. static DWORD CALLBACK VideoProcedure(LPVOID param)
  157. {
  158. SetThreadName(-1,"AVI_VideoProcedure");
  159. HANDLE wait_handles[] = { killswitch, video_break, video_flush, video_resume, coded_frames_event };
  160. while (1)
  161. {
  162. int ret = WaitForMultipleObjects(5, wait_handles, FALSE, INFINITE);
  163. if (ret == WAIT_OBJECT_0)
  164. {
  165. break;
  166. }
  167. if (ret == WAIT_OBJECT_0 + 1) // video break
  168. {
  169. ResetEvent(coded_frames_event);
  170. ResetEvent(video_break);
  171. SetEvent(video_flush_done);
  172. }
  173. else if (ret == WAIT_OBJECT_0 + 2) // video flush
  174. {
  175. if (video_decoder)
  176. video_decoder->Flush();
  177. ResetEvent(video_flush);
  178. coded_frames.Trim();
  179. SetEvent(video_flush_done);
  180. }
  181. else if (ret == WAIT_OBJECT_0 + 3) // video resume
  182. {
  183. ResetEvent(video_resume);
  184. SetEvent(coded_frames_event);
  185. SetEvent(video_flush_done);
  186. }
  187. else if (ret == WAIT_OBJECT_0 + 4) // data from demuxer
  188. {
  189. FRAMEDATA *frame_data = 0;
  190. while (frame_data = coded_frames.PopProcessed())
  191. {
  192. DecodeVideo(frame_data);
  193. frame_data->Reset();
  194. coded_frames.PushFree(frame_data);
  195. }
  196. }
  197. };
  198. if (video_opened && video_output)
  199. video_output->close();
  200. video_opened=false;
  201. return 0;
  202. }
  203. static DWORD CALLBACK VideoReaderProcedure(LPVOID param)
  204. {
  205. VideoContext *ctx = (VideoContext *)param;
  206. nsavi::avi_reader *reader = ctx->reader;
  207. nsavi::Demuxer *demuxer = ctx->demuxer;
  208. SetThreadName(-1,"AVI_VideoProcedure");
  209. HANDLE wait_handles[] = { killswitch, video_break, video_flush, video_resume };
  210. int waitTime = 0;
  211. while (1)
  212. {
  213. int ret = WaitForMultipleObjects(4, wait_handles, FALSE, waitTime);
  214. if (ret == WAIT_OBJECT_0)
  215. {
  216. break;
  217. }
  218. if (ret == WAIT_OBJECT_0 + 1) // video break
  219. {
  220. ResetEvent(coded_frames_event);
  221. ResetEvent(video_break);
  222. SetEvent(video_flush_done);
  223. waitTime = INFINITE;
  224. }
  225. else if (ret == WAIT_OBJECT_0 + 2) // video flush
  226. {
  227. if (video_decoder)
  228. video_decoder->Flush();
  229. ResetEvent(video_flush);
  230. coded_frames.Trim();
  231. SetEvent(video_flush_done);
  232. waitTime = 0;
  233. }
  234. else if (ret == WAIT_OBJECT_0 + 3) // video resume
  235. {
  236. ResetEvent(video_resume);
  237. SetEvent(coded_frames_event);
  238. SetEvent(video_flush_done);
  239. waitTime = 0;
  240. }
  241. else if (ret == WAIT_TIMEOUT)
  242. {
  243. void *data=0;
  244. uint32_t data_size = 0;
  245. uint32_t data_type = 0;
  246. int ret = demuxer->GetNextMovieChunk(reader, &data, &data_size, &data_type, video_stream_num);
  247. if (ret != nsavi::READ_OK)
  248. {
  249. break;
  250. }
  251. int stream_number = GetStreamNumber(data_type);
  252. uint16_t type = (data_type>>16);
  253. if (stream_number == video_stream_num)
  254. {
  255. FRAMEDATA frame_data;
  256. frame_data.data = data;
  257. frame_data.length = data_size;
  258. frame_data.type = type;
  259. DecodeVideo(&frame_data);
  260. frame_data.Reset();
  261. }
  262. else
  263. free(data);
  264. }
  265. };
  266. if (video_opened && video_output)
  267. video_output->close();
  268. video_opened=false;
  269. free(ctx);
  270. return 0;
  271. }
  272. bool CreateVideoReaderThread(nsavi::Demuxer *demuxer, nsavi::avi_reader *video_reader)
  273. {
  274. if (!video_decoder || video_only)
  275. return false;
  276. VideoContext *context = (VideoContext *)calloc(1, sizeof(VideoContext));
  277. context->reader = video_reader;
  278. context->demuxer = demuxer;
  279. DWORD threadId = 0;
  280. video_thread = CreateThread(0, 0, VideoReaderProcedure, context, 0, &threadId);
  281. SetThreadPriority(video_thread, (INT)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
  282. return true;
  283. }
  284. bool OnVideo(uint16_t type, void *data, size_t length)
  285. {
  286. if (!video_decoder)
  287. return false;
  288. if (!video_only && !video_thread)
  289. {
  290. DWORD threadId;
  291. video_thread = CreateThread(0, 0, VideoProcedure, 0, 0, &threadId);
  292. SetThreadPriority(video_thread, (INT)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
  293. }
  294. if (video_thread)
  295. {
  296. FRAMEDATA *new_frame = coded_frames.PopFree();
  297. if (new_frame)
  298. {
  299. new_frame->Set(type, data, length);
  300. coded_frames.PushProcessed(new_frame);
  301. SetEvent(coded_frames_event);
  302. }
  303. return true;
  304. }
  305. else if (video_only)
  306. {
  307. FRAMEDATA *new_frame = coded_frames.PopFree();
  308. if (new_frame)
  309. {
  310. new_frame->Set(type, data, length);
  311. DecodeVideo(new_frame);
  312. new_frame->Reset();
  313. }
  314. return true;
  315. }
  316. return false;
  317. }
  318. void Video_Stop()
  319. {
  320. SetEvent(killswitch);
  321. if (video_only)
  322. {
  323. video_thread=0;
  324. ResetEvent(coded_frames_event);
  325. Nullsoft::Utility::AutoLock l(coded_frames_guard);
  326. coded_frames.Trim();
  327. if (video_opened && video_output)
  328. video_output->close();
  329. video_opened=false;
  330. }
  331. else
  332. {
  333. if (video_thread)
  334. WaitForSingleObject(video_thread, INFINITE);
  335. video_thread=0;
  336. ResetEvent(coded_frames_event);
  337. Nullsoft::Utility::AutoLock l(coded_frames_guard);
  338. coded_frames.Trim();
  339. }
  340. }
  341. void Video_Close()
  342. {
  343. video_opened=false;
  344. if (video_decoder)
  345. {
  346. video_decoder->Close();
  347. video_decoder=0;
  348. }
  349. }
  350. void Video_Break()
  351. {
  352. if (!video_only && video_decoder)
  353. {
  354. SetEvent(video_break);
  355. HANDLE events[2] = {video_flush_done, video_thread};
  356. WaitForMultipleObjects(2, events, FALSE, INFINITE);
  357. }
  358. }
  359. void Video_Flush()
  360. {
  361. if (video_decoder)
  362. {
  363. if (video_only)
  364. {
  365. video_decoder->Flush();
  366. }
  367. else
  368. {
  369. SetEvent(video_flush);
  370. HANDLE events[2] = {video_flush_done, video_thread};
  371. WaitForMultipleObjects(2, events, FALSE, INFINITE);
  372. }
  373. }
  374. }
  375. /*
  376. bool Video_DecoderReady()
  377. {
  378. if (!video_decoder)
  379. return true;
  380. return !!video_decoder->Ready();
  381. }
  382. */