VideoThread.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #include "main.h"
  2. #include "VideoThread.h"
  3. #include "api__in_flv.h"
  4. #include "FLVVideoHeader.h"
  5. #include <shlwapi.h>
  6. #include <windows.h>
  7. #include "../nu/threadname.h"
  8. #include <api/service/waservicefactory.h>
  9. #include "../nu/AutoLock.h"
  10. #include "../nu/SampleQueue.h"
  11. int width, height;
  12. IVideoOutput *videoOutput=0;
  13. static HANDLE videoThread=0;
  14. static volatile LONG video_flush=0;
  15. static ifc_flvvideodecoder *videoDecoder=0;
  16. bool video_opened=false;
  17. static HANDLE coded_frames_event=0;
  18. static HANDLE video_flush_event=0;
  19. static Nullsoft::Utility::LockGuard coded_frames_guard;
  20. extern bool video_only;
  21. void Video_Init()
  22. {
  23. video_opened=false;
  24. videoDecoder=0;
  25. videoThread=0;
  26. width=0;
  27. height=0;
  28. if (coded_frames_event == 0)
  29. coded_frames_event = CreateEvent(NULL, FALSE, FALSE, NULL);
  30. if (video_flush_event == 0)
  31. video_flush_event = CreateEvent(NULL, TRUE, FALSE, NULL);
  32. video_flush=0;
  33. }
  34. struct FRAMEDATA
  35. {
  36. FRAMEDATA()
  37. {
  38. data=0;
  39. length=0;
  40. timestamp=0;
  41. }
  42. ~FRAMEDATA()
  43. {
  44. free(data);
  45. }
  46. void Reset()
  47. {
  48. free(data);
  49. data=0;
  50. length=0;
  51. timestamp=0;
  52. }
  53. void Set(void *_data, size_t _length, uint32_t ts)
  54. {
  55. data = _data;
  56. length = _length;
  57. timestamp = ts;
  58. }
  59. void *data;
  60. size_t length;
  61. uint32_t timestamp;
  62. };
  63. static SampleQueue<FRAMEDATA> coded_frames;
  64. extern int GetOutputTime();
  65. static void DecodeVideo(FRAMEDATA *framedata)
  66. {
  67. if (WaitForSingleObject(killswitch, 0) != WAIT_OBJECT_0)
  68. {
  69. int decodeResult = videoDecoder->DecodeSample(framedata->data, framedata->length, framedata->timestamp);
  70. if (decodeResult == FLV_VIDEO_SUCCESS)
  71. {
  72. void *data, *decoder_data;
  73. uint64_t timestamp=framedata->timestamp;
  74. while (videoDecoder->GetPicture(&data, &decoder_data, &timestamp) == FLV_VIDEO_SUCCESS)
  75. {
  76. if (!video_opened)
  77. {
  78. int color_format;
  79. if (videoDecoder->GetOutputFormat(&width, &height, &color_format) == FLV_VIDEO_SUCCESS)
  80. {
  81. videoOutput->extended(VIDUSER_SET_THREAD_SAFE, 1, 0);
  82. videoOutput->open(width, height, 0, 1.0, color_format);
  83. video_opened=true;
  84. }
  85. }
  86. if (video_opened)
  87. {
  88. again:
  89. int realTime =(int)GetOutputTime();
  90. if (timestamp > (realTime+5))
  91. {
  92. HANDLE handles[] = {killswitch, video_flush_event};
  93. int ret=WaitForMultipleObjects(2, handles, FALSE, (DWORD)(timestamp-realTime));
  94. if (ret != WAIT_TIMEOUT)
  95. {
  96. videoDecoder->FreePicture(data, decoder_data);
  97. framedata->Reset();
  98. return ;
  99. }
  100. goto again; // TODO: handle paused state a little better than this
  101. }
  102. videoOutput->draw(data);
  103. }
  104. videoDecoder->FreePicture(data, decoder_data);
  105. }
  106. }
  107. }
  108. framedata->Reset();
  109. }
  110. DWORD CALLBACK VideoProcedure(LPVOID param)
  111. {
  112. SetThreadName(-1,"FLV_VideoProcedure");
  113. HANDLE wait_handles[] = { killswitch, video_flush_event, coded_frames_event};
  114. int ret;
  115. do
  116. {
  117. ret = WaitForMultipleObjects(3, wait_handles, FALSE, INFINITE);
  118. if (ret == WAIT_OBJECT_0 + 1)
  119. {
  120. if (video_flush)
  121. {
  122. InterlockedDecrement(&video_flush);
  123. if (videoDecoder)
  124. videoDecoder->Flush();
  125. }
  126. ResetEvent(video_flush_event);
  127. }
  128. else if (ret == WAIT_OBJECT_0 + 2)
  129. {
  130. FRAMEDATA *frame_data = 0;
  131. while (frame_data = coded_frames.PopProcessed())
  132. {
  133. DecodeVideo(frame_data);
  134. frame_data->Reset();
  135. coded_frames.PushFree(frame_data);
  136. }
  137. }
  138. } while (ret != WAIT_OBJECT_0);
  139. if (video_opened && videoOutput)
  140. videoOutput->close();
  141. video_opened=false;
  142. return 0;
  143. }
  144. bool Video_IsSupported(int type)
  145. {
  146. size_t n = 0;
  147. waServiceFactory *factory = NULL;
  148. while (factory = plugin.service->service_enumService(WaSvc::FLVDECODER, n++))
  149. {
  150. svc_flvdecoder *creator = (svc_flvdecoder *)factory->getInterface();
  151. if (creator)
  152. {
  153. int supported = creator->HandlesVideo(type);
  154. factory->releaseInterface(creator);
  155. if (supported == svc_flvdecoder::CREATEDECODER_SUCCESS)
  156. return true;
  157. }
  158. }
  159. return false;
  160. }
  161. static ifc_flvvideodecoder *CreateVideoDecoder(int type)
  162. {
  163. ifc_flvvideodecoder *video_decoder = 0;
  164. size_t n = 0;
  165. waServiceFactory *factory = NULL;
  166. while (factory = plugin.service->service_enumService(WaSvc::FLVDECODER, n++))
  167. {
  168. svc_flvdecoder *creator = (svc_flvdecoder *)factory->getInterface();
  169. if (creator)
  170. {
  171. if (creator->CreateVideoDecoder(type, width, height, &video_decoder) == FLV_VIDEO_SUCCESS)
  172. return video_decoder;
  173. factory->releaseInterface(creator);
  174. }
  175. }
  176. return 0;
  177. }
  178. // {B6CB4A7C-A8D0-4c55-8E60-9F7A7A23DA0F}
  179. static const GUID playbackConfigGroupGUID =
  180. { 0xb6cb4a7c, 0xa8d0, 0x4c55, { 0x8e, 0x60, 0x9f, 0x7a, 0x7a, 0x23, 0xda, 0xf } };
  181. bool OnVideo(void *data, size_t length, int type, unsigned __int32 timestamp)
  182. {
  183. if (!videoDecoder)
  184. {
  185. videoDecoder = CreateVideoDecoder(type);
  186. }
  187. if (videoDecoder)
  188. {
  189. if (!video_only && !videoThread)
  190. {
  191. DWORD threadId;
  192. videoThread = CreateThread(0, 0, VideoProcedure, 0, 0, &threadId);
  193. SetThreadPriority(videoThread, (INT)AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
  194. }
  195. FRAMEDATA *new_frame = coded_frames.PopFree();
  196. if (new_frame)
  197. {
  198. new_frame->Set(data, length, timestamp);
  199. if (video_only)
  200. {
  201. DecodeVideo(new_frame);
  202. new_frame->Reset();
  203. coded_frames.PushFree(new_frame);
  204. }
  205. else
  206. {
  207. coded_frames.PushProcessed(new_frame);
  208. SetEvent(coded_frames_event);
  209. }
  210. }
  211. return true;
  212. }
  213. return false;
  214. }
  215. void Video_Stop()
  216. {
  217. if (video_only)
  218. {
  219. ResetEvent(coded_frames_event);
  220. Nullsoft::Utility::AutoLock l(coded_frames_guard);
  221. coded_frames.Trim();
  222. if (video_opened && videoOutput)
  223. videoOutput->close();
  224. video_opened=false;
  225. }
  226. else
  227. {
  228. if (videoThread)
  229. WaitForSingleObject(videoThread, INFINITE);
  230. videoThread=0;
  231. InterlockedIncrement(&video_flush);
  232. ResetEvent(coded_frames_event);
  233. Nullsoft::Utility::AutoLock l(coded_frames_guard);
  234. coded_frames.Trim();
  235. }
  236. }
  237. void Video_Close()
  238. {
  239. video_opened=false;
  240. if (videoDecoder)
  241. {
  242. videoDecoder->Close();
  243. videoDecoder=0;
  244. }
  245. }
  246. void VideoFlush()
  247. {
  248. if (video_only)
  249. {
  250. if (videoDecoder)
  251. videoDecoder->Flush();
  252. }
  253. else if (videoThread)
  254. {
  255. InterlockedIncrement(&video_flush);
  256. ResetEvent(coded_frames_event);
  257. coded_frames.Trim();
  258. SetEvent(video_flush_event);
  259. }
  260. }
  261. bool Video_DecoderReady()
  262. {
  263. if (!videoDecoder)
  264. return true;
  265. return !!videoDecoder->Ready();
  266. }