d3d11_surface.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /*****************************************************************************
  2. * d3d11_surface.c : D3D11 GPU surface conversion module for vlc
  3. *****************************************************************************
  4. * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
  5. *
  6. * Authors: Steve Lhomme <robux4@gmail.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU Lesser General Public License as published by
  10. * the Free Software Foundation; either version 2.1 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with this program; if not, write to the Free Software Foundation,
  20. * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  21. *****************************************************************************/
  22. /*****************************************************************************
  23. * Preamble
  24. *****************************************************************************/
  25. #ifdef HAVE_CONFIG_H
  26. # include "config.h"
  27. #endif
  28. #include <vlc_common.h>
  29. #include <vlc_plugin.h>
  30. #include <vlc_filter.h>
  31. #include <vlc_picture.h>
  32. #include "copy.h"
  33. static int OpenConverter( vlc_object_t * );
  34. static void CloseConverter( vlc_object_t * );
  35. /*****************************************************************************
  36. * Module descriptor.
  37. *****************************************************************************/
  38. vlc_module_begin ()
  39. set_description( N_("Conversions from D3D11 to YUV") )
  40. set_capability( "video converter", 10 )
  41. set_callbacks( OpenConverter, CloseConverter )
  42. vlc_module_end ()
  43. #include <windows.h>
  44. #define COBJMACROS
  45. #include <d3d11.h>
  46. #include "d3d11_fmt.h"
  47. #ifdef ID3D11VideoContext_VideoProcessorBlt
  48. #define CAN_PROCESSOR 1
  49. #else
  50. #define CAN_PROCESSOR 0
  51. #endif
  52. struct filter_sys_t {
  53. copy_cache_t cache;
  54. union {
  55. ID3D11Texture2D *staging;
  56. ID3D11Resource *staging_resource;
  57. };
  58. vlc_mutex_t staging_lock;
  59. #if CAN_PROCESSOR
  60. union {
  61. ID3D11Texture2D *procOutTexture;
  62. ID3D11Resource *procOutResource;
  63. };
  64. /* 420_OPAQUE processor */
  65. ID3D11VideoDevice *d3dviddev;
  66. ID3D11VideoContext *d3dvidctx;
  67. ID3D11VideoProcessorOutputView *processorOutput;
  68. ID3D11VideoProcessorEnumerator *procEnumerator;
  69. ID3D11VideoProcessor *videoProcessor;
  70. #endif
  71. };
  72. #if CAN_PROCESSOR
  73. static int SetupProcessor(filter_t *p_filter, ID3D11Device *d3ddevice,
  74. ID3D11DeviceContext *d3dctx,
  75. DXGI_FORMAT srcFormat, DXGI_FORMAT dstFormat)
  76. {
  77. filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
  78. HRESULT hr;
  79. ID3D11VideoProcessorEnumerator *processorEnumerator = NULL;
  80. hr = ID3D11DeviceContext_QueryInterface(d3dctx, &IID_ID3D11VideoContext, (void **)&sys->d3dvidctx);
  81. if (unlikely(FAILED(hr)))
  82. goto error;
  83. hr = ID3D11Device_QueryInterface( d3ddevice, &IID_ID3D11VideoDevice, (void **)&sys->d3dviddev);
  84. if (unlikely(FAILED(hr)))
  85. goto error;
  86. const video_format_t *fmt = &p_filter->fmt_in.video;
  87. D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc = {
  88. .InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE,
  89. .InputFrameRate = {
  90. .Numerator = fmt->i_frame_rate_base > 0 ? fmt->i_frame_rate : 0,
  91. .Denominator = fmt->i_frame_rate_base,
  92. },
  93. .InputWidth = fmt->i_width,
  94. .InputHeight = fmt->i_height,
  95. .OutputWidth = fmt->i_width,
  96. .OutputHeight = fmt->i_height,
  97. .Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL,
  98. };
  99. hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(sys->d3dviddev, &processorDesc, &processorEnumerator);
  100. if ( processorEnumerator == NULL )
  101. {
  102. msg_Dbg(p_filter, "Can't get a video processor for the video.");
  103. goto error;
  104. }
  105. UINT flags;
  106. #ifndef NDEBUG
  107. for (int format = 0; format < 188; format++) {
  108. hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, format, &flags);
  109. if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT))
  110. msg_Dbg(p_filter, "processor format %s (%d) is supported for input", DxgiFormatToStr(format),format);
  111. if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
  112. msg_Dbg(p_filter, "processor format %s (%d) is supported for output", DxgiFormatToStr(format),format);
  113. }
  114. #endif
  115. /* shortcut for the rendering output */
  116. hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, srcFormat, &flags);
  117. if (FAILED(hr) || !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT))
  118. {
  119. msg_Dbg(p_filter, "processor format %s not supported for output", DxgiFormatToStr(srcFormat));
  120. goto error;
  121. }
  122. hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, dstFormat, &flags);
  123. if (FAILED(hr) || !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
  124. {
  125. msg_Dbg(p_filter, "processor format %s not supported for input", DxgiFormatToStr(dstFormat));
  126. goto error;
  127. }
  128. D3D11_VIDEO_PROCESSOR_CAPS processorCaps;
  129. hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator, &processorCaps);
  130. for (UINT type = 0; type < processorCaps.RateConversionCapsCount; ++type)
  131. {
  132. hr = ID3D11VideoDevice_CreateVideoProcessor(sys->d3dviddev,
  133. processorEnumerator, type, &sys->videoProcessor);
  134. if (SUCCEEDED(hr))
  135. {
  136. D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc = {
  137. .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D,
  138. };
  139. hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(sys->d3dviddev,
  140. sys->procOutResource,
  141. processorEnumerator,
  142. &outDesc,
  143. &sys->processorOutput);
  144. if (FAILED(hr))
  145. msg_Err(p_filter, "Failed to create the processor output. (hr=0x%lX)", hr);
  146. else
  147. {
  148. sys->procEnumerator = processorEnumerator;
  149. return VLC_SUCCESS;
  150. }
  151. }
  152. if (sys->videoProcessor)
  153. {
  154. ID3D11VideoProcessor_Release(sys->videoProcessor);
  155. sys->videoProcessor = NULL;
  156. }
  157. }
  158. error:
  159. if (processorEnumerator)
  160. ID3D11VideoProcessorEnumerator_Release(processorEnumerator);
  161. if (sys->d3dvidctx)
  162. ID3D11VideoContext_Release(sys->d3dvidctx);
  163. if (sys->d3dviddev)
  164. ID3D11VideoDevice_Release(sys->d3dviddev);
  165. return VLC_EGENERIC;
  166. }
  167. #endif
  168. static int assert_staging(filter_t *p_filter, picture_sys_t *p_sys)
  169. {
  170. filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
  171. HRESULT hr;
  172. if (sys->staging)
  173. goto ok;
  174. D3D11_TEXTURE2D_DESC texDesc;
  175. ID3D11Texture2D_GetDesc( p_sys->texture[KNOWN_DXGI_INDEX], &texDesc);
  176. texDesc.MipLevels = 1;
  177. //texDesc.SampleDesc.Count = 1;
  178. texDesc.MiscFlags = 0;
  179. texDesc.ArraySize = 1;
  180. texDesc.Usage = D3D11_USAGE_STAGING;
  181. texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
  182. texDesc.BindFlags = 0;
  183. ID3D11Device *p_device;
  184. ID3D11DeviceContext_GetDevice(p_sys->context, &p_device);
  185. sys->staging = NULL;
  186. hr = ID3D11Device_CreateTexture2D( p_device, &texDesc, NULL, &sys->staging);
  187. #if CAN_PROCESSOR
  188. if (FAILED(hr)) {
  189. /* failed with the this format, try a different one */
  190. UINT supportFlags = D3D11_FORMAT_SUPPORT_SHADER_LOAD | D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT;
  191. const d3d_format_t *new_fmt =
  192. FindD3D11Format( p_device, 0, 0, false, supportFlags );
  193. if (new_fmt && texDesc.Format != new_fmt->formatTexture)
  194. {
  195. DXGI_FORMAT srcFormat = texDesc.Format;
  196. texDesc.Format = new_fmt->formatTexture;
  197. hr = ID3D11Device_CreateTexture2D( p_device, &texDesc, NULL, &sys->staging);
  198. if (SUCCEEDED(hr))
  199. {
  200. texDesc.Usage = D3D11_USAGE_DEFAULT;
  201. texDesc.CPUAccessFlags = 0;
  202. texDesc.BindFlags |= D3D11_BIND_RENDER_TARGET;
  203. hr = ID3D11Device_CreateTexture2D( p_device, &texDesc, NULL, &sys->procOutTexture);
  204. if (SUCCEEDED(hr))
  205. {
  206. if (SetupProcessor(p_filter, p_device, p_sys->context, srcFormat, new_fmt->formatTexture))
  207. {
  208. ID3D11Texture2D_Release(sys->procOutTexture);
  209. ID3D11Texture2D_Release(sys->staging);
  210. sys->staging = NULL;
  211. hr = E_FAIL;
  212. }
  213. }
  214. else
  215. {
  216. ID3D11Texture2D_Release(sys->staging);
  217. sys->staging = NULL;
  218. hr = E_FAIL;
  219. }
  220. }
  221. }
  222. }
  223. #endif
  224. ID3D11Device_Release(p_device);
  225. if (FAILED(hr)) {
  226. msg_Err(p_filter, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc.Format), hr );
  227. return VLC_EGENERIC;
  228. }
  229. ok:
  230. return VLC_SUCCESS;
  231. }
  232. static void D3D11_YUY2(filter_t *p_filter, picture_t *src, picture_t *dst)
  233. {
  234. filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
  235. picture_sys_t *p_sys = &((struct va_pic_context*)src->context)->picsys;
  236. D3D11_TEXTURE2D_DESC desc;
  237. D3D11_MAPPED_SUBRESOURCE lock;
  238. vlc_mutex_lock(&sys->staging_lock);
  239. if (assert_staging(p_filter, p_sys) != VLC_SUCCESS)
  240. {
  241. vlc_mutex_unlock(&sys->staging_lock);
  242. return;
  243. }
  244. D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
  245. ID3D11VideoDecoderOutputView_GetDesc( p_sys->decoder, &viewDesc );
  246. ID3D11Resource *srcResource = p_sys->resource[KNOWN_DXGI_INDEX];
  247. UINT srcSlice = viewDesc.Texture2D.ArraySlice;
  248. #if CAN_PROCESSOR
  249. if (sys->procEnumerator)
  250. {
  251. HRESULT hr;
  252. if (!p_sys->processorInput)
  253. {
  254. D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
  255. .FourCC = 0,
  256. .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
  257. .Texture2D.MipSlice = 0,
  258. .Texture2D.ArraySlice = viewDesc.Texture2D.ArraySlice,
  259. };
  260. hr = ID3D11VideoDevice_CreateVideoProcessorInputView(sys->d3dviddev,
  261. p_sys->resource[KNOWN_DXGI_INDEX],
  262. sys->procEnumerator,
  263. &inDesc,
  264. &p_sys->processorInput);
  265. if (FAILED(hr))
  266. {
  267. #ifndef NDEBUG
  268. msg_Dbg(p_filter,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys->slice_index, hr);
  269. #endif
  270. return;
  271. }
  272. }
  273. D3D11_VIDEO_PROCESSOR_STREAM stream = {
  274. .Enable = TRUE,
  275. .pInputSurface = p_sys->processorInput,
  276. };
  277. hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->videoProcessor,
  278. sys->processorOutput,
  279. 0, 1, &stream);
  280. if (FAILED(hr))
  281. {
  282. msg_Err(p_filter, "Failed to process the video. (hr=0x%lX)", hr);
  283. vlc_mutex_unlock(&sys->staging_lock);
  284. return;
  285. }
  286. srcResource = sys->procOutResource;
  287. srcSlice = 0;
  288. }
  289. #endif
  290. ID3D11DeviceContext_CopySubresourceRegion(p_sys->context, sys->staging_resource,
  291. 0, 0, 0, 0,
  292. srcResource,
  293. srcSlice,
  294. NULL);
  295. HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_resource,
  296. 0, D3D11_MAP_READ, 0, &lock);
  297. if (FAILED(hr)) {
  298. msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
  299. vlc_mutex_unlock(&sys->staging_lock);
  300. return;
  301. }
  302. if (dst->format.i_chroma == VLC_CODEC_I420) {
  303. uint8_t *tmp = dst->p[1].p_pixels;
  304. dst->p[1].p_pixels = dst->p[2].p_pixels;
  305. dst->p[2].p_pixels = tmp;
  306. }
  307. ID3D11Texture2D_GetDesc(sys->staging, &desc);
  308. if (desc.Format == DXGI_FORMAT_YUY2) {
  309. size_t chroma_pitch = (lock.RowPitch / 2);
  310. size_t pitch[3] = {
  311. lock.RowPitch,
  312. chroma_pitch,
  313. chroma_pitch,
  314. };
  315. uint8_t *plane[3] = {
  316. (uint8_t*)lock.pData,
  317. (uint8_t*)lock.pData + pitch[0] * desc.Height,
  318. (uint8_t*)lock.pData + pitch[0] * desc.Height
  319. + pitch[1] * desc.Height / 2,
  320. };
  321. CopyFromYv12ToYv12(dst, plane, pitch,
  322. src->format.i_visible_height + src->format.i_y_offset, &sys->cache);
  323. } else if (desc.Format == DXGI_FORMAT_NV12) {
  324. uint8_t *plane[2] = {
  325. lock.pData,
  326. (uint8_t*)lock.pData + lock.RowPitch * desc.Height
  327. };
  328. size_t pitch[2] = {
  329. lock.RowPitch,
  330. lock.RowPitch,
  331. };
  332. CopyFromNv12ToYv12(dst, plane, pitch,
  333. src->format.i_visible_height + src->format.i_y_offset, &sys->cache);
  334. } else {
  335. msg_Err(p_filter, "Unsupported D3D11VA conversion from 0x%08X to YV12", desc.Format);
  336. }
  337. if (dst->format.i_chroma == VLC_CODEC_I420) {
  338. uint8_t *tmp = dst->p[1].p_pixels;
  339. dst->p[1].p_pixels = dst->p[2].p_pixels;
  340. dst->p[2].p_pixels = tmp;
  341. }
  342. /* */
  343. ID3D11DeviceContext_Unmap(p_sys->context, sys->staging_resource, 0);
  344. vlc_mutex_unlock(&sys->staging_lock);
  345. }
  346. static void D3D11_NV12(filter_t *p_filter, picture_t *src, picture_t *dst)
  347. {
  348. filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
  349. picture_sys_t *p_sys = &((struct va_pic_context*)src->context)->picsys;
  350. D3D11_TEXTURE2D_DESC desc;
  351. D3D11_MAPPED_SUBRESOURCE lock;
  352. vlc_mutex_lock(&sys->staging_lock);
  353. if (assert_staging(p_filter, p_sys) != VLC_SUCCESS)
  354. {
  355. vlc_mutex_unlock(&sys->staging_lock);
  356. return;
  357. }
  358. D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
  359. ID3D11VideoDecoderOutputView_GetDesc( p_sys->decoder, &viewDesc );
  360. ID3D11Resource *srcResource = p_sys->resource[KNOWN_DXGI_INDEX];
  361. UINT srcSlice = viewDesc.Texture2D.ArraySlice;
  362. #if CAN_PROCESSOR
  363. if (sys->procEnumerator)
  364. {
  365. HRESULT hr;
  366. if (!p_sys->processorInput)
  367. {
  368. D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
  369. .FourCC = 0,
  370. .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
  371. .Texture2D.MipSlice = 0,
  372. .Texture2D.ArraySlice = viewDesc.Texture2D.ArraySlice,
  373. };
  374. hr = ID3D11VideoDevice_CreateVideoProcessorInputView(sys->d3dviddev,
  375. p_sys->resource[KNOWN_DXGI_INDEX],
  376. sys->procEnumerator,
  377. &inDesc,
  378. &p_sys->processorInput);
  379. if (FAILED(hr))
  380. {
  381. #ifndef NDEBUG
  382. msg_Dbg(p_filter,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys->slice_index, hr);
  383. #endif
  384. return;
  385. }
  386. }
  387. D3D11_VIDEO_PROCESSOR_STREAM stream = {
  388. .Enable = TRUE,
  389. .pInputSurface = p_sys->processorInput,
  390. };
  391. hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->videoProcessor,
  392. sys->processorOutput,
  393. 0, 1, &stream);
  394. if (FAILED(hr))
  395. {
  396. msg_Err(p_filter, "Failed to process the video. (hr=0x%lX)", hr);
  397. vlc_mutex_unlock(&sys->staging_lock);
  398. return;
  399. }
  400. srcResource = sys->procOutResource;
  401. srcSlice = 0;
  402. }
  403. #endif
  404. ID3D11DeviceContext_CopySubresourceRegion(p_sys->context, sys->staging_resource,
  405. 0, 0, 0, 0,
  406. srcResource,
  407. srcSlice,
  408. NULL);
  409. HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_resource,
  410. 0, D3D11_MAP_READ, 0, &lock);
  411. if (FAILED(hr)) {
  412. msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
  413. vlc_mutex_unlock(&sys->staging_lock);
  414. return;
  415. }
  416. ID3D11Texture2D_GetDesc(sys->staging, &desc);
  417. if (desc.Format == DXGI_FORMAT_NV12) {
  418. uint8_t *plane[2] = {
  419. lock.pData,
  420. (uint8_t*)lock.pData + lock.RowPitch * desc.Height
  421. };
  422. size_t pitch[2] = {
  423. lock.RowPitch,
  424. lock.RowPitch,
  425. };
  426. CopyFromNv12ToNv12(dst, plane, pitch,
  427. src->format.i_visible_height + src->format.i_y_offset, &sys->cache);
  428. } else {
  429. msg_Err(p_filter, "Unsupported D3D11VA conversion from 0x%08X to NV12", desc.Format);
  430. }
  431. /* */
  432. ID3D11DeviceContext_Unmap(p_sys->context, sys->staging_resource, 0);
  433. vlc_mutex_unlock(&sys->staging_lock);
  434. }
  435. VIDEO_FILTER_WRAPPER (D3D11_NV12)
  436. VIDEO_FILTER_WRAPPER (D3D11_YUY2)
  437. static int OpenConverter( vlc_object_t *obj )
  438. {
  439. filter_t *p_filter = (filter_t *)obj;
  440. if ( p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE )
  441. return VLC_EGENERIC;
  442. if ( p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height
  443. || p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width )
  444. return VLC_EGENERIC;
  445. switch( p_filter->fmt_out.video.i_chroma ) {
  446. case VLC_CODEC_I420:
  447. case VLC_CODEC_YV12:
  448. p_filter->pf_video_filter = D3D11_YUY2_Filter;
  449. break;
  450. case VLC_CODEC_NV12:
  451. p_filter->pf_video_filter = D3D11_NV12_Filter;
  452. break;
  453. default:
  454. return VLC_EGENERIC;
  455. }
  456. filter_sys_t *p_sys = calloc(1, sizeof(filter_sys_t));
  457. if (!p_sys)
  458. return VLC_ENOMEM;
  459. CopyInitCache(&p_sys->cache, p_filter->fmt_in.video.i_width );
  460. vlc_mutex_init(&p_sys->staging_lock);
  461. p_filter->p_sys = p_sys;
  462. return VLC_SUCCESS;
  463. }
  464. static void CloseConverter( vlc_object_t *obj )
  465. {
  466. filter_t *p_filter = (filter_t *)obj;
  467. filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys;
  468. #if CAN_PROCESSOR
  469. if (p_sys->d3dviddev)
  470. ID3D11VideoDevice_Release(p_sys->d3dviddev);
  471. if (p_sys->d3dvidctx)
  472. ID3D11VideoContext_Release(p_sys->d3dvidctx);
  473. if (p_sys->procEnumerator)
  474. ID3D11VideoProcessorEnumerator_Release(p_sys->procEnumerator);
  475. if (p_sys->videoProcessor)
  476. ID3D11VideoProcessor_Release(p_sys->videoProcessor);
  477. #endif
  478. CopyCleanCache(&p_sys->cache);
  479. vlc_mutex_destroy(&p_sys->staging_lock);
  480. if (p_sys->staging)
  481. ID3D11Texture2D_Release(p_sys->staging);
  482. free( p_sys );
  483. p_filter->p_sys = NULL;
  484. }