1 /*****************************************************************************
2 * d3d11_surface.c : D3D11 GPU surface conversion module for vlc
3 *****************************************************************************
4 * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
6 * Authors: Steve Lhomme <robux4@gmail.com>
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.
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.
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 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_filter.h>
34 #include <vlc_picture.h>
35 #include <vlc_modules.h>
43 #include "d3d11_fmt.h"
45 #ifdef ID3D11VideoContext_VideoProcessorBlt
46 #define CAN_PROCESSOR 1
48 #define CAN_PROCESSOR 0
54 ID3D11Texture2D
*staging
;
55 ID3D11Resource
*staging_resource
;
57 vlc_mutex_t staging_lock
;
61 ID3D11Texture2D
*procOutTexture
;
62 ID3D11Resource
*procOutResource
;
64 /* 420_OPAQUE processor */
65 ID3D11VideoDevice
*d3dviddev
;
66 ID3D11VideoContext
*d3dvidctx
;
67 ID3D11VideoProcessorOutputView
*processorOutput
;
68 ID3D11VideoProcessorEnumerator
*procEnumerator
;
69 ID3D11VideoProcessor
*videoProcessor
;
74 picture_t
*staging_pic
;
80 static int SetupProcessor(filter_t
*p_filter
, ID3D11Device
*d3ddevice
,
81 ID3D11DeviceContext
*d3dctx
,
82 DXGI_FORMAT srcFormat
, DXGI_FORMAT dstFormat
)
84 filter_sys_t
*sys
= (filter_sys_t
*) p_filter
->p_sys
;
86 ID3D11VideoProcessorEnumerator
*processorEnumerator
= NULL
;
88 hr
= ID3D11DeviceContext_QueryInterface(d3dctx
, &IID_ID3D11VideoContext
, (void **)&sys
->d3dvidctx
);
89 if (unlikely(FAILED(hr
)))
92 hr
= ID3D11Device_QueryInterface( d3ddevice
, &IID_ID3D11VideoDevice
, (void **)&sys
->d3dviddev
);
93 if (unlikely(FAILED(hr
)))
96 const video_format_t
*fmt
= &p_filter
->fmt_in
.video
;
97 D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc
= {
98 .InputFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE
,
100 .Numerator
= fmt
->i_frame_rate_base
> 0 ? fmt
->i_frame_rate
: 0,
101 .Denominator
= fmt
->i_frame_rate_base
,
103 .InputWidth
= fmt
->i_width
,
104 .InputHeight
= fmt
->i_height
,
105 .OutputWidth
= fmt
->i_width
,
106 .OutputHeight
= fmt
->i_height
,
107 .Usage
= D3D11_VIDEO_USAGE_PLAYBACK_NORMAL
,
109 hr
= ID3D11VideoDevice_CreateVideoProcessorEnumerator(sys
->d3dviddev
, &processorDesc
, &processorEnumerator
);
110 if ( processorEnumerator
== NULL
)
112 msg_Dbg(p_filter
, "Can't get a video processor for the video.");
118 for (int format
= 0; format
< 188; format
++) {
119 hr
= ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator
, format
, &flags
);
120 if (SUCCEEDED(hr
) && (flags
& D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT
))
121 msg_Dbg(p_filter
, "processor format %s (%d) is supported for input", DxgiFormatToStr(format
),format
);
122 if (SUCCEEDED(hr
) && (flags
& D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT
))
123 msg_Dbg(p_filter
, "processor format %s (%d) is supported for output", DxgiFormatToStr(format
),format
);
126 /* shortcut for the rendering output */
127 hr
= ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator
, srcFormat
, &flags
);
128 if (FAILED(hr
) || !(flags
& D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT
))
130 msg_Dbg(p_filter
, "processor format %s not supported for output", DxgiFormatToStr(srcFormat
));
133 hr
= ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator
, dstFormat
, &flags
);
134 if (FAILED(hr
) || !(flags
& D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT
))
136 msg_Dbg(p_filter
, "processor format %s not supported for input", DxgiFormatToStr(dstFormat
));
140 D3D11_VIDEO_PROCESSOR_CAPS processorCaps
;
141 hr
= ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator
, &processorCaps
);
142 for (UINT type
= 0; type
< processorCaps
.RateConversionCapsCount
; ++type
)
144 hr
= ID3D11VideoDevice_CreateVideoProcessor(sys
->d3dviddev
,
145 processorEnumerator
, type
, &sys
->videoProcessor
);
148 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc
= {
149 .ViewDimension
= D3D11_VPOV_DIMENSION_TEXTURE2D
,
152 hr
= ID3D11VideoDevice_CreateVideoProcessorOutputView(sys
->d3dviddev
,
153 sys
->procOutResource
,
156 &sys
->processorOutput
);
158 msg_Err(p_filter
, "Failed to create the processor output. (hr=0x%lX)", hr
);
161 sys
->procEnumerator
= processorEnumerator
;
165 if (sys
->videoProcessor
)
167 ID3D11VideoProcessor_Release(sys
->videoProcessor
);
168 sys
->videoProcessor
= NULL
;
173 if (processorEnumerator
)
174 ID3D11VideoProcessorEnumerator_Release(processorEnumerator
);
176 ID3D11VideoContext_Release(sys
->d3dvidctx
);
178 ID3D11VideoDevice_Release(sys
->d3dviddev
);
183 static int assert_staging(filter_t
*p_filter
, picture_sys_t
*p_sys
)
185 filter_sys_t
*sys
= (filter_sys_t
*) p_filter
->p_sys
;
191 D3D11_TEXTURE2D_DESC texDesc
;
192 ID3D11Texture2D_GetDesc( p_sys
->texture
[KNOWN_DXGI_INDEX
], &texDesc
);
194 texDesc
.MipLevels
= 1;
195 //texDesc.SampleDesc.Count = 1;
196 texDesc
.MiscFlags
= 0;
197 texDesc
.ArraySize
= 1;
198 texDesc
.Usage
= D3D11_USAGE_STAGING
;
199 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
200 texDesc
.BindFlags
= 0;
202 ID3D11Device
*p_device
;
203 ID3D11DeviceContext_GetDevice(p_sys
->context
, &p_device
);
205 hr
= ID3D11Device_CreateTexture2D( p_device
, &texDesc
, NULL
, &sys
->staging
);
208 /* failed with the this format, try a different one */
209 UINT supportFlags
= D3D11_FORMAT_SUPPORT_SHADER_LOAD
| D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT
;
210 const d3d_format_t
*new_fmt
=
211 FindD3D11Format( p_device
, 0, 0, false, supportFlags
);
212 if (new_fmt
&& texDesc
.Format
!= new_fmt
->formatTexture
)
214 DXGI_FORMAT srcFormat
= texDesc
.Format
;
215 texDesc
.Format
= new_fmt
->formatTexture
;
216 hr
= ID3D11Device_CreateTexture2D( p_device
, &texDesc
, NULL
, &sys
->staging
);
219 texDesc
.Usage
= D3D11_USAGE_DEFAULT
;
220 texDesc
.CPUAccessFlags
= 0;
221 texDesc
.BindFlags
|= D3D11_BIND_RENDER_TARGET
;
222 hr
= ID3D11Device_CreateTexture2D( p_device
, &texDesc
, NULL
, &sys
->procOutTexture
);
225 if (SetupProcessor(p_filter
, p_device
, p_sys
->context
, srcFormat
, new_fmt
->formatTexture
))
227 ID3D11Texture2D_Release(sys
->procOutTexture
);
228 ID3D11Texture2D_Release(sys
->staging
);
235 ID3D11Texture2D_Release(sys
->staging
);
243 ID3D11Device_Release(p_device
);
245 msg_Err(p_filter
, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc
.Format
), hr
);
252 static void D3D11_YUY2(filter_t
*p_filter
, picture_t
*src
, picture_t
*dst
)
254 filter_sys_t
*sys
= (filter_sys_t
*) p_filter
->p_sys
;
255 assert(src
->context
!= NULL
);
256 picture_sys_t
*p_sys
= &((struct va_pic_context
*)src
->context
)->picsys
;
258 D3D11_TEXTURE2D_DESC desc
;
259 D3D11_MAPPED_SUBRESOURCE lock
;
261 vlc_mutex_lock(&sys
->staging_lock
);
262 if (assert_staging(p_filter
, p_sys
) != VLC_SUCCESS
)
264 vlc_mutex_unlock(&sys
->staging_lock
);
269 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc
;
272 ID3D11VideoDecoderOutputView_GetDesc( p_sys
->decoder
, &viewDesc
);
273 srcSlice
= viewDesc
.Texture2D
.ArraySlice
;
277 ID3D11Resource
*srcResource
= p_sys
->resource
[KNOWN_DXGI_INDEX
];
280 if (sys
->procEnumerator
)
283 if (!p_sys
->processorInput
)
285 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc
= {
287 .ViewDimension
= D3D11_VPIV_DIMENSION_TEXTURE2D
,
288 .Texture2D
.MipSlice
= 0,
289 .Texture2D
.ArraySlice
= viewDesc
.Texture2D
.ArraySlice
,
292 hr
= ID3D11VideoDevice_CreateVideoProcessorInputView(sys
->d3dviddev
,
293 p_sys
->resource
[KNOWN_DXGI_INDEX
],
296 &p_sys
->processorInput
);
300 msg_Dbg(p_filter
,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys
->slice_index
, hr
);
305 D3D11_VIDEO_PROCESSOR_STREAM stream
= {
307 .pInputSurface
= p_sys
->processorInput
,
310 hr
= ID3D11VideoContext_VideoProcessorBlt(sys
->d3dvidctx
, sys
->videoProcessor
,
311 sys
->processorOutput
,
315 msg_Err(p_filter
, "Failed to process the video. (hr=0x%lX)", hr
);
316 vlc_mutex_unlock(&sys
->staging_lock
);
320 srcResource
= sys
->procOutResource
;
324 ID3D11DeviceContext_CopySubresourceRegion(p_sys
->context
, sys
->staging_resource
,
330 HRESULT hr
= ID3D11DeviceContext_Map(p_sys
->context
, sys
->staging_resource
,
331 0, D3D11_MAP_READ
, 0, &lock
);
333 msg_Err(p_filter
, "Failed to map source surface. (hr=0x%0lx)", hr
);
334 vlc_mutex_unlock(&sys
->staging_lock
);
338 if (dst
->format
.i_chroma
== VLC_CODEC_I420
) {
339 uint8_t *tmp
= dst
->p
[1].p_pixels
;
340 dst
->p
[1].p_pixels
= dst
->p
[2].p_pixels
;
341 dst
->p
[2].p_pixels
= tmp
;
344 ID3D11Texture2D_GetDesc(sys
->staging
, &desc
);
346 if (desc
.Format
== DXGI_FORMAT_YUY2
) {
347 size_t chroma_pitch
= (lock
.RowPitch
/ 2);
355 uint8_t *plane
[3] = {
356 (uint8_t*)lock
.pData
,
357 (uint8_t*)lock
.pData
+ pitch
[0] * desc
.Height
,
358 (uint8_t*)lock
.pData
+ pitch
[0] * desc
.Height
359 + pitch
[1] * desc
.Height
/ 2,
362 CopyFromYv12ToYv12(dst
, plane
, pitch
,
363 src
->format
.i_visible_height
+ src
->format
.i_y_offset
, &sys
->cache
);
364 } else if (desc
.Format
== DXGI_FORMAT_NV12
) {
365 uint8_t *plane
[2] = {
367 (uint8_t*)lock
.pData
+ lock
.RowPitch
* desc
.Height
373 CopyFromNv12ToYv12(dst
, plane
, pitch
,
374 src
->format
.i_visible_height
+ src
->format
.i_y_offset
, &sys
->cache
);
376 msg_Err(p_filter
, "Unsupported D3D11VA conversion from 0x%08X to YV12", desc
.Format
);
379 if (dst
->format
.i_chroma
== VLC_CODEC_I420
) {
380 uint8_t *tmp
= dst
->p
[1].p_pixels
;
381 dst
->p
[1].p_pixels
= dst
->p
[2].p_pixels
;
382 dst
->p
[2].p_pixels
= tmp
;
386 ID3D11DeviceContext_Unmap(p_sys
->context
, sys
->staging_resource
, 0);
387 vlc_mutex_unlock(&sys
->staging_lock
);
390 static void D3D11_NV12(filter_t
*p_filter
, picture_t
*src
, picture_t
*dst
)
392 filter_sys_t
*sys
= (filter_sys_t
*) p_filter
->p_sys
;
393 assert(src
->context
!= NULL
);
394 picture_sys_t
*p_sys
= &((struct va_pic_context
*)src
->context
)->picsys
;
396 D3D11_TEXTURE2D_DESC desc
;
397 D3D11_MAPPED_SUBRESOURCE lock
;
399 vlc_mutex_lock(&sys
->staging_lock
);
400 if (assert_staging(p_filter
, p_sys
) != VLC_SUCCESS
)
402 vlc_mutex_unlock(&sys
->staging_lock
);
406 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc
;
407 ID3D11VideoDecoderOutputView_GetDesc( p_sys
->decoder
, &viewDesc
);
409 ID3D11Resource
*srcResource
= p_sys
->resource
[KNOWN_DXGI_INDEX
];
410 UINT srcSlice
= viewDesc
.Texture2D
.ArraySlice
;
413 if (sys
->procEnumerator
)
416 if (!p_sys
->processorInput
)
418 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc
= {
420 .ViewDimension
= D3D11_VPIV_DIMENSION_TEXTURE2D
,
421 .Texture2D
.MipSlice
= 0,
422 .Texture2D
.ArraySlice
= viewDesc
.Texture2D
.ArraySlice
,
425 hr
= ID3D11VideoDevice_CreateVideoProcessorInputView(sys
->d3dviddev
,
426 p_sys
->resource
[KNOWN_DXGI_INDEX
],
429 &p_sys
->processorInput
);
433 msg_Dbg(p_filter
,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys
->slice_index
, hr
);
438 D3D11_VIDEO_PROCESSOR_STREAM stream
= {
440 .pInputSurface
= p_sys
->processorInput
,
443 hr
= ID3D11VideoContext_VideoProcessorBlt(sys
->d3dvidctx
, sys
->videoProcessor
,
444 sys
->processorOutput
,
448 msg_Err(p_filter
, "Failed to process the video. (hr=0x%lX)", hr
);
449 vlc_mutex_unlock(&sys
->staging_lock
);
453 srcResource
= sys
->procOutResource
;
457 ID3D11DeviceContext_CopySubresourceRegion(p_sys
->context
, sys
->staging_resource
,
463 HRESULT hr
= ID3D11DeviceContext_Map(p_sys
->context
, sys
->staging_resource
,
464 0, D3D11_MAP_READ
, 0, &lock
);
466 msg_Err(p_filter
, "Failed to map source surface. (hr=0x%0lx)", hr
);
467 vlc_mutex_unlock(&sys
->staging_lock
);
471 ID3D11Texture2D_GetDesc(sys
->staging
, &desc
);
473 if (desc
.Format
== DXGI_FORMAT_NV12
) {
474 uint8_t *plane
[2] = {
476 (uint8_t*)lock
.pData
+ lock
.RowPitch
* desc
.Height
482 CopyFromNv12ToNv12(dst
, plane
, pitch
,
483 src
->format
.i_visible_height
+ src
->format
.i_y_offset
, &sys
->cache
);
485 msg_Err(p_filter
, "Unsupported D3D11VA conversion from 0x%08X to NV12", desc
.Format
);
489 ID3D11DeviceContext_Unmap(p_sys
->context
, sys
->staging_resource
, 0);
490 vlc_mutex_unlock(&sys
->staging_lock
);
493 static void DestroyPicture(picture_t
*picture
)
495 picture_sys_t
*p_sys
= picture
->p_sys
;
496 ReleasePictureSys( p_sys
);
501 static void DeleteFilter( filter_t
* p_filter
)
503 if( p_filter
->p_module
)
504 module_unneed( p_filter
, p_filter
->p_module
);
506 es_format_Clean( &p_filter
->fmt_in
);
507 es_format_Clean( &p_filter
->fmt_out
);
509 vlc_object_release( p_filter
);
512 static picture_t
*NewBuffer(filter_t
*p_filter
)
514 filter_t
*p_parent
= p_filter
->owner
.sys
;
515 return p_parent
->p_sys
->staging_pic
;
518 static filter_t
*CreateFilter( vlc_object_t
*p_this
, const es_format_t
*p_fmt_in
,
519 vlc_fourcc_t dst_chroma
)
523 p_filter
= vlc_object_create( p_this
, sizeof(filter_t
) );
524 if (unlikely(p_filter
== NULL
))
527 p_filter
->b_allow_fmt_out_change
= false;
528 p_filter
->owner
.video
.buffer_new
= NewBuffer
;
529 p_filter
->owner
.sys
= p_this
;
531 es_format_InitFromVideo( &p_filter
->fmt_in
, &p_fmt_in
->video
);
532 es_format_InitFromVideo( &p_filter
->fmt_out
, &p_fmt_in
->video
);
533 p_filter
->fmt_out
.i_codec
= p_filter
->fmt_out
.video
.i_chroma
= dst_chroma
;
534 p_filter
->p_module
= module_need( p_filter
, "video converter", NULL
, false );
536 if( !p_filter
->p_module
)
538 msg_Dbg( p_filter
, "no video converter found" );
539 DeleteFilter( p_filter
);
546 static void d3d11_pic_context_destroy(struct picture_context_t
*opaque
)
548 struct va_pic_context
*pic_ctx
= (struct va_pic_context
*)opaque
;
549 ReleasePictureSys(&pic_ctx
->picsys
);
553 static struct picture_context_t
*d3d11_pic_context_copy(struct picture_context_t
*ctx
)
555 struct va_pic_context
*src_ctx
= (struct va_pic_context
*)ctx
;
556 struct va_pic_context
*pic_ctx
= calloc(1, sizeof(*pic_ctx
));
557 if (unlikely(pic_ctx
==NULL
))
559 pic_ctx
->s
.destroy
= d3d11_pic_context_destroy
;
560 pic_ctx
->s
.copy
= d3d11_pic_context_copy
;
561 pic_ctx
->picsys
= src_ctx
->picsys
;
562 AcquirePictureSys(&pic_ctx
->picsys
);
566 static void NV12_D3D11(filter_t
*p_filter
, picture_t
*src
, picture_t
*dst
)
568 filter_sys_t
*sys
= (filter_sys_t
*) p_filter
->p_sys
;
569 picture_sys_t
*p_sys
= dst
->p_sys
;
571 D3D11_TEXTURE2D_DESC texDesc
;
572 ID3D11Texture2D_GetDesc( sys
->staging_pic
->p_sys
->texture
[KNOWN_DXGI_INDEX
], &texDesc
);
574 D3D11_MAPPED_SUBRESOURCE lock
;
575 HRESULT hr
= ID3D11DeviceContext_Map(p_sys
->context
, sys
->staging_pic
->p_sys
->resource
[KNOWN_DXGI_INDEX
],
576 0, D3D11_MAP_WRITE
, 0, &lock
);
578 msg_Err(p_filter
, "Failed to map source surface. (hr=0x%0lx)", hr
);
582 picture_UpdatePlanes(sys
->staging_pic
, lock
.pData
, lock
.RowPitch
);
585 sys
->filter
->pf_video_filter(sys
->filter
, src
);
587 ID3D11DeviceContext_Unmap(p_sys
->context
, sys
->staging_pic
->p_sys
->resource
[KNOWN_DXGI_INDEX
], 0);
589 D3D11_BOX copyBox
= {
590 .right
= dst
->format
.i_width
, .bottom
= dst
->format
.i_height
, .back
= 1,
592 ID3D11DeviceContext_CopySubresourceRegion(p_sys
->context
,
593 p_sys
->resource
[KNOWN_DXGI_INDEX
],
596 sys
->staging_pic
->p_sys
->resource
[KNOWN_DXGI_INDEX
], 0,
598 if (dst
->context
== NULL
)
600 struct va_pic_context
*pic_ctx
= calloc(1, sizeof(*pic_ctx
));
603 pic_ctx
->s
.destroy
= d3d11_pic_context_destroy
;
604 pic_ctx
->s
.copy
= d3d11_pic_context_copy
;
605 pic_ctx
->picsys
= *dst
->p_sys
;
606 AcquirePictureSys(&pic_ctx
->picsys
);
607 dst
->context
= &pic_ctx
->s
;
612 VIDEO_FILTER_WRAPPER (D3D11_NV12
)
613 VIDEO_FILTER_WRAPPER (D3D11_YUY2
)
614 VIDEO_FILTER_WRAPPER (NV12_D3D11
)
616 static int OpenConverter( vlc_object_t
*obj
)
618 filter_t
*p_filter
= (filter_t
*)obj
;
619 HINSTANCE hd3d_dll
= NULL
;
620 int err
= VLC_EGENERIC
;
622 if ( p_filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE
)
625 if ( p_filter
->fmt_in
.video
.i_height
!= p_filter
->fmt_out
.video
.i_height
626 || p_filter
->fmt_in
.video
.i_width
!= p_filter
->fmt_out
.video
.i_width
)
629 switch( p_filter
->fmt_out
.video
.i_chroma
) {
632 p_filter
->pf_video_filter
= D3D11_YUY2_Filter
;
635 p_filter
->pf_video_filter
= D3D11_NV12_Filter
;
641 hd3d_dll
= LoadLibrary(TEXT("D3D11.DLL"));
642 if (unlikely(!hd3d_dll
)) {
643 msg_Warn(p_filter
, "cannot load d3d11.dll, aborting");
647 filter_sys_t
*p_sys
= calloc(1, sizeof(filter_sys_t
));
651 CopyInitCache(&p_sys
->cache
, p_filter
->fmt_in
.video
.i_width
);
652 vlc_mutex_init(&p_sys
->staging_lock
);
653 p_sys
->hd3d_dll
= hd3d_dll
;
654 p_filter
->p_sys
= p_sys
;
658 if (err
!= VLC_SUCCESS
)
661 FreeLibrary(hd3d_dll
);
665 static int OpenFromCPU( vlc_object_t
*obj
)
667 filter_t
*p_filter
= (filter_t
*)obj
;
668 int err
= VLC_EGENERIC
;
669 ID3D11Texture2D
*texture
= NULL
;
670 filter_t
*p_cpu_filter
= NULL
;
671 HINSTANCE hd3d_dll
= NULL
;
672 video_format_t fmt_staging
;
674 if ( p_filter
->fmt_out
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE
)
677 if ( p_filter
->fmt_in
.video
.i_height
!= p_filter
->fmt_out
.video
.i_height
678 || p_filter
->fmt_in
.video
.i_width
!= p_filter
->fmt_out
.video
.i_width
)
681 switch( p_filter
->fmt_in
.video
.i_chroma
) {
686 p_filter
->pf_video_filter
= NV12_D3D11_Filter
;
692 picture_t
*peek
= filter_NewPicture(p_filter
);
697 msg_Dbg(p_filter
, "D3D11 opaque without a texture");
701 video_format_Init(&fmt_staging
, 0);
703 D3D11_TEXTURE2D_DESC texDesc
;
704 ID3D11Texture2D_GetDesc( peek
->p_sys
->texture
[KNOWN_DXGI_INDEX
], &texDesc
);
705 vlc_fourcc_t d3d_fourcc
= DxgiFormatFourcc(texDesc
.Format
);
709 picture_resource_t res
;
710 res
.pf_destroy
= DestroyPicture
;
711 res
.p_sys
= calloc(1, sizeof(picture_sys_t
));
712 if (res
.p_sys
== NULL
) {
716 res
.p_sys
->context
= peek
->p_sys
->context
;
717 res
.p_sys
->formatTexture
= texDesc
.Format
;
719 video_format_Copy(&fmt_staging
, &p_filter
->fmt_out
.video
);
720 fmt_staging
.i_chroma
= d3d_fourcc
;
721 fmt_staging
.i_height
= texDesc
.Height
;
722 fmt_staging
.i_width
= texDesc
.Width
;
724 picture_t
*p_dst
= picture_NewFromResource(&fmt_staging
, &res
);
726 msg_Err(p_filter
, "Failed to map create the temporary picture.");
729 picture_Setup(p_dst
, &p_dst
->format
);
731 texDesc
.MipLevels
= 1;
732 //texDesc.SampleDesc.Count = 1;
733 texDesc
.MiscFlags
= 0;
734 texDesc
.ArraySize
= 1;
735 texDesc
.Usage
= D3D11_USAGE_STAGING
;
736 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
737 texDesc
.BindFlags
= 0;
738 texDesc
.Height
= p_dst
->format
.i_height
; /* make sure we match picture_Setup() */
740 ID3D11Device
*p_device
;
741 ID3D11DeviceContext_GetDevice(peek
->p_sys
->context
, &p_device
);
742 HRESULT hr
= ID3D11Device_CreateTexture2D( p_device
, &texDesc
, NULL
, &texture
);
743 ID3D11Device_Release(p_device
);
745 msg_Err(p_filter
, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc
.Format
), hr
);
749 res
.p_sys
->texture
[KNOWN_DXGI_INDEX
] = texture
;
750 ID3D11DeviceContext_AddRef(p_dst
->p_sys
->context
);
752 if ( p_filter
->fmt_in
.video
.i_chroma
!= d3d_fourcc
)
754 p_cpu_filter
= CreateFilter(VLC_OBJECT(p_filter
), &p_filter
->fmt_in
, p_dst
->format
.i_chroma
);
759 hd3d_dll
= LoadLibrary(TEXT("D3D11.DLL"));
760 if (unlikely(!hd3d_dll
)) {
761 msg_Warn(p_filter
, "cannot load d3d11.dll, aborting");
765 filter_sys_t
*p_sys
= calloc(1, sizeof(filter_sys_t
));
770 p_sys
->filter
= p_cpu_filter
;
771 p_sys
->staging_pic
= p_dst
;
772 p_sys
->hd3d_dll
= hd3d_dll
;
773 p_filter
->p_sys
= p_sys
;
777 video_format_Clean(&fmt_staging
);
778 picture_Release(peek
);
779 if (err
!= VLC_SUCCESS
)
782 DeleteFilter( p_cpu_filter
);
784 ID3D11Texture2D_Release(texture
);
786 FreeLibrary(hd3d_dll
);
791 static void CloseConverter( vlc_object_t
*obj
)
793 filter_t
*p_filter
= (filter_t
*)obj
;
794 filter_sys_t
*p_sys
= (filter_sys_t
*) p_filter
->p_sys
;
796 if (p_sys
->d3dviddev
)
797 ID3D11VideoDevice_Release(p_sys
->d3dviddev
);
798 if (p_sys
->d3dvidctx
)
799 ID3D11VideoContext_Release(p_sys
->d3dvidctx
);
800 if (p_sys
->procEnumerator
)
801 ID3D11VideoProcessorEnumerator_Release(p_sys
->procEnumerator
);
802 if (p_sys
->videoProcessor
)
803 ID3D11VideoProcessor_Release(p_sys
->videoProcessor
);
805 CopyCleanCache(&p_sys
->cache
);
806 vlc_mutex_destroy(&p_sys
->staging_lock
);
808 ID3D11Texture2D_Release(p_sys
->staging
);
809 FreeLibrary(p_sys
->hd3d_dll
);
811 p_filter
->p_sys
= NULL
;
814 static void CloseFromCPU( vlc_object_t
*obj
)
816 filter_t
*p_filter
= (filter_t
*)obj
;
817 filter_sys_t
*p_sys
= (filter_sys_t
*) p_filter
->p_sys
;
818 DeleteFilter(p_sys
->filter
);
819 picture_Release(p_sys
->staging_pic
);
820 FreeLibrary(p_sys
->hd3d_dll
);
822 p_filter
->p_sys
= NULL
;
825 /*****************************************************************************
827 *****************************************************************************/
829 set_description( N_("Conversions from D3D11 to YUV") )
830 set_capability( "video converter", 10 )
831 set_callbacks( OpenConverter
, CloseConverter
)
833 set_callbacks( OpenFromCPU
, CloseFromCPU
)
834 set_capability( "video converter", 10 )