VideoLayer.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #include "Main.h"
  2. #include "VideoLayer.h"
  3. #include <initguid.h>
  4. #include <wmsdkidl.h>
  5. #include <cassert>
  6. #include "util.h"
  7. #include "resource.h"
  8. #include <strsafe.h>
  9. #include "config.h"
  10. #define VIDEO_ACCEPTABLE_DROP (config_video_drop_threshold*10000)
  11. VideoLayer::VideoLayer(IWMReader *_reader)
  12. : reader(_reader), videoOutputNum(-1),
  13. reader2(0), offset(0), nextRest(0),
  14. converter(NULL), videoOpened(false),
  15. video_output_opened(false),
  16. killSwitch(0), aspect(0),
  17. earlyDelivery(0), fourcc(0),
  18. drmProtected(false),
  19. videoStream(0), flip(false),
  20. videoWidth(0), videoHeight(0)
  21. {
  22. reader->AddRef();
  23. if (FAILED(reader->QueryInterface(&reader2)))
  24. reader2 = 0;
  25. if (FAILED(reader->QueryInterface(&header)))
  26. header = 0;
  27. killSwitch = CreateEvent(NULL, TRUE, FALSE, NULL);
  28. }
  29. VideoLayer::~VideoLayer()
  30. {
  31. videoThread.Kill();
  32. if (reader2)
  33. reader2->Release();
  34. if (header)
  35. header->Release();
  36. reader->Release();
  37. CloseHandle(killSwitch);
  38. }
  39. bool AcceptableFormat(GUID &subtype)
  40. {
  41. if (subtype == WMMEDIASUBTYPE_YV12
  42. || subtype == WMMEDIASUBTYPE_YUY2
  43. || subtype == WMMEDIASUBTYPE_UYVY
  44. //|| subtype == WMMEDIASUBTYPE_YVYU
  45. || subtype == WMMEDIASUBTYPE_RGB24
  46. || subtype == WMMEDIASUBTYPE_RGB32
  47. || subtype == WMMEDIASUBTYPE_I420
  48. || subtype == WMMEDIASUBTYPE_IYUV
  49. || subtype == WMMEDIASUBTYPE_RGB1
  50. || subtype == WMMEDIASUBTYPE_RGB4
  51. || subtype == WMMEDIASUBTYPE_RGB8
  52. || subtype == WMMEDIASUBTYPE_RGB565
  53. || subtype == WMMEDIASUBTYPE_RGB555
  54. )
  55. return true;
  56. else
  57. return false;
  58. }
  59. bool VideoLayer::AttemptOpenVideo(VideoOutputStream *attempt)
  60. {
  61. videoWidth = attempt->DestinationWidth();
  62. videoHeight = attempt->DestinationHeight();
  63. flip = attempt->Flipped();
  64. fourcc = attempt->FourCC();
  65. if (!fourcc)
  66. return false;
  67. aspect = 1.0;
  68. return true;
  69. }
  70. bool VideoLayer::OpenVideo()
  71. {
  72. videoOutputNum = -1;
  73. DWORD numOutputs, numFormats;
  74. IWMOutputMediaProps *formatProperties;
  75. VideoOutputStream *stream;
  76. GUID mediaType;
  77. reader->GetOutputCount(&numOutputs);
  78. for (DWORD output = 0;output < numOutputs;output++)
  79. {
  80. // test the default format first, and if that fails, iterate through the rest
  81. const int defaultFormat = -1;
  82. HRESULT hr;
  83. if (FAILED(hr = reader->GetOutputFormatCount(output, &numFormats)))
  84. continue;
  85. for (int format = 0/*defaultFormat*/;format != numFormats;format++)
  86. {
  87. if (format == defaultFormat)
  88. reader->GetOutputProps(output, &formatProperties);
  89. else
  90. reader->GetOutputFormat(output, format, &formatProperties);
  91. formatProperties->GetType(&mediaType);
  92. if (mediaType == WMMEDIATYPE_Video)
  93. {
  94. stream = new VideoOutputStream(formatProperties);
  95. if (stream->IsVideo() // if it's video
  96. && AcceptableFormat(stream->GetSubType()) // and a video format we like
  97. && AttemptOpenVideo(stream)) // and winamp was able to open it
  98. {
  99. videoOpened = true;
  100. int fourcc = stream->FourCC();
  101. if (fourcc == '8BGR')
  102. {
  103. RGBQUAD *palette = stream->CreatePalette();
  104. winamp.SetVideoPalette(palette);
  105. // TODO: don't leak the palette
  106. }
  107. char *cc = (char *) & fourcc;
  108. char status[512] = {0};
  109. StringCchPrintfA(status, 512, WASABI_API_LNGSTRING(IDS_WINDOWS_MEDIA_XXX),
  110. stream->DestinationWidth(), stream->DestinationHeight(), cc[0], cc[1], cc[2], cc[3]);
  111. winamp.SetVideoStatusText(status);
  112. converter = MakeConverter(stream);
  113. videoOutputNum = output;
  114. videoStream = stream;
  115. reader->SetOutputProps(output, formatProperties);
  116. formatProperties->Release();
  117. return true;
  118. }
  119. delete stream;
  120. stream = 0;
  121. }
  122. formatProperties->Release();
  123. }
  124. }
  125. return false;
  126. }
  127. void VideoLayer::SampleReceived(QWORD &timeStamp, QWORD &duration, unsigned long &outputNum, unsigned long &flags, INSSBuffer *&sample)
  128. {
  129. if (outputNum == videoOutputNum)
  130. {
  131. if (WaitForSingleObject(killSwitch, 0) == WAIT_OBJECT_0)
  132. return ;
  133. INSSBuffer3 *buff3;
  134. if (SUCCEEDED(sample->QueryInterface(&buff3)))
  135. {
  136. short aspectHex = 0;
  137. DWORD size = 2;
  138. buff3->GetProperty(WM_SampleExtensionGUID_PixelAspectRatio, &aspectHex, &size);
  139. if (aspectHex)
  140. {
  141. double newAspect = (double)((aspectHex & 0xFF00) >> 8) / (double)(aspectHex & 0xFF) ;
  142. if (newAspect != aspect)
  143. {
  144. aspect = newAspect;
  145. videoThread.OpenVideo(drmProtected, videoWidth, videoHeight, flip, aspect, fourcc);
  146. video_output_opened=true;
  147. }
  148. }
  149. buff3->Release();
  150. }
  151. if (!video_output_opened)
  152. {
  153. videoThread.OpenVideo(drmProtected, videoWidth, videoHeight, flip, aspect, fourcc);
  154. video_output_opened=true;
  155. }
  156. __int64 timeDiff;
  157. First().TimeToSync(timeStamp, timeDiff);
  158. if (timeDiff < -VIDEO_ACCEPTABLE_DROP) // late
  159. {
  160. timeDiff = -timeDiff;
  161. if (config_video_catchup) First().VideoCatchup(timeDiff);
  162. if (config_video_framedropoffset) this->VideoFrameDrop((DWORD)(timeDiff / 10000));
  163. if (config_video_notifylate) reader2->NotifyLateDelivery(timeDiff);
  164. // drop the frame
  165. }
  166. else // early
  167. {
  168. while (!videoThread.AddBuffer(sample, timeStamp, flags, drmProtected))
  169. {
  170. if (WaitForSingleObject(killSwitch, VIDEO_ACCEPTABLE_JITTER_MS) == WAIT_OBJECT_0)
  171. return ;
  172. }
  173. }
  174. }
  175. else
  176. WMHandler::SampleReceived(timeStamp, duration, outputNum, flags, sample);
  177. }
  178. void VideoLayer::Opened()
  179. {
  180. WORD stream = 0;
  181. WMT_ATTR_DATATYPE type = WMT_TYPE_BOOL;
  182. BOOL value;
  183. WORD valueLen = sizeof(value);
  184. header->GetAttributeByName(&stream, g_wszWMProtected, &type, (BYTE *)&value, &valueLen);
  185. drmProtected = !!value;
  186. ResetEvent(killSwitch);
  187. if (OpenVideo())
  188. {
  189. ResetEvent(killSwitch);
  190. HRESULT hr;
  191. BOOL dedicatedThread = config_video_dedicated_thread ? TRUE : FALSE;
  192. hr = reader2->SetOutputSetting(videoOutputNum, g_wszDedicatedDeliveryThread, WMT_TYPE_BOOL, (BYTE *) & dedicatedThread, sizeof(dedicatedThread));
  193. assert(hr == S_OK);
  194. earlyDelivery = config_video_early ? config_video_early_pad : 0;
  195. hr = reader2->SetOutputSetting(videoOutputNum, g_wszEarlyDataDelivery, WMT_TYPE_DWORD, (BYTE *) & earlyDelivery , sizeof(earlyDelivery));
  196. assert(hr == S_OK);
  197. BOOL outOfOrder = config_video_outoforder ? TRUE : FALSE;
  198. hr = reader2->SetOutputSetting(videoOutputNum, g_wszDeliverOnReceive, WMT_TYPE_BOOL, (BYTE *) & outOfOrder, sizeof(outOfOrder));
  199. assert(hr == S_OK);
  200. BOOL justInTime = config_lowmemory ? TRUE : FALSE;
  201. hr = reader2->SetOutputSetting(videoOutputNum, g_wszJustInTimeDecode, WMT_TYPE_BOOL, (BYTE *) & justInTime, sizeof(justInTime));
  202. assert(hr == S_OK);
  203. }
  204. else
  205. {
  206. videoOpened = false;
  207. }
  208. WMHandler::Opened();
  209. }
  210. void VideoLayer::VideoFrameDrop(DWORD lateness)
  211. {
  212. //earlyDelivery+=lateness;
  213. lateness += earlyDelivery;
  214. HRESULT hr = reader2->SetOutputSetting(videoOutputNum, g_wszEarlyDataDelivery, WMT_TYPE_DWORD, (BYTE *) & lateness, sizeof(lateness));
  215. assert(hr == S_OK);
  216. }
  217. void VideoLayer::Closed()
  218. {
  219. if (video_output_opened)
  220. {
  221. videoThread.CloseVideo(drmProtected);
  222. video_output_opened = false;
  223. }
  224. videoOpened = false;
  225. delete videoStream;
  226. videoStream=0;
  227. WMHandler::Closed();
  228. }
  229. bool VideoLayer::IsOpen()
  230. {
  231. return videoOpened;
  232. }
  233. void VideoLayer::HasVideo(bool &video)
  234. {
  235. video=videoOpened;
  236. }
  237. void VideoLayer::Kill()
  238. {
  239. SetEvent(killSwitch);
  240. if (videoOpened)
  241. videoThread.SignalStop();//SignalStop();
  242. WMHandler::Kill();
  243. if (videoOpened)
  244. videoThread.WaitForStop();
  245. }
  246. void VideoLayer::Started()
  247. {
  248. ResetEvent(killSwitch);
  249. if (videoOpened)
  250. videoThread.Start(converter, &First());
  251. WMHandler::Started();
  252. }
  253. void VideoLayer::Stopped()
  254. {
  255. if (videoOpened)
  256. videoThread.Stop();
  257. WMHandler::Stopped();
  258. }