hw:d3d9: use d3d9_device_t instead of IDirect3DDevice9
[vlc.git] / modules / hw / d3d9 / dxva2_deinterlace.c
blob27f6fdb0d851ee5ada39a17a354a6ac509d2af3d
1 /*****************************************************************************
2 * dxva2_deinterlace.c: DxVA2 deinterlacing filter
3 *****************************************************************************
4 * Copyright (C) 2017 Videolabs SAS
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 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <stdlib.h>
28 #include <assert.h>
30 #include <vlc_common.h>
31 #include <vlc_filter.h>
32 #include <vlc_picture.h>
34 #define COBJMACROS
35 #include <initguid.h>
36 #include <d3d9.h>
37 #include <dxva2api.h>
38 #include "../../video_chroma/d3d9_fmt.h"
39 #include "../../video_filter/deinterlace/common.h"
41 #include "d3d9_filters.h"
43 struct filter_sys_t
45 HINSTANCE hdecoder_dll;
46 /* keep a reference in case the vout is released first */
47 HINSTANCE d3d9_dll;
48 d3d9_device_t d3d_dev;
49 IDirectXVideoProcessor *processor;
50 IDirect3DSurface9 *hw_surface;
52 DXVA2_VideoProcessorCaps decoder_caps;
54 SHORT Brightness;
55 SHORT Contrast;
56 SHORT Hue;
57 SHORT Saturation;
59 struct deinterlace_ctx context;
60 picture_t * (*buffer_new)( filter_t * );
63 struct filter_mode_t
65 const char *psz_mode;
66 UINT i_mode;
67 deinterlace_algo settings;
69 static struct filter_mode_t filter_mode [] = {
70 { "blend", DXVA2_DeinterlaceTech_BOBLineReplicate,
71 { false, false, false, false } },
72 { "bob", DXVA2_DeinterlaceTech_BOBVerticalStretch,
73 { true, false, false, false } },
74 { "x", DXVA2_DeinterlaceTech_BOBVerticalStretch4Tap,
75 { true, true, false, false } },
76 { "ivtc", DXVA2_DeinterlaceTech_InverseTelecine,
77 { false, true, true, false } },
78 { "yadif2x", DXVA2_DeinterlaceTech_PixelAdaptive,
79 { true, true, false, false } },
82 static void Flush(filter_t *filter)
84 FlushDeinterlacing(&filter->p_sys->context);
87 static void FillSample( DXVA2_VideoSample *p_sample,
88 const struct deinterlace_ctx *p_context,
89 picture_t *p_pic,
90 const video_format_t *p_fmt,
91 const RECT *p_area,
92 int i_field )
94 picture_sys_t *p_sys_src = ActivePictureSys(p_pic);
96 p_sample->SrcSurface = p_sys_src->surface;
97 p_sample->SampleFormat.SampleFormat = p_pic->b_top_field_first ?
98 DXVA2_SampleFieldInterleavedEvenFirst :
99 DXVA2_SampleFieldInterleavedOddFirst;
100 p_sample->Start = 0;
101 p_sample->End = GetFieldDuration(p_context, p_fmt, p_pic) * 10;
102 p_sample->SampleData = DXVA2_SampleData_RFF_TFF_Present;
103 if (!i_field)
104 p_sample->SampleData |= DXVA2_SampleData_TFF;
105 else
106 p_sample->SampleData |= DXVA2_SampleData_RFF;
107 p_sample->DstRect = p_sample->SrcRect = *p_area;
108 p_sample->PlanarAlpha = DXVA2_Fixed32OpaqueAlpha();
111 static void FillBlitParams( filter_sys_t *sys,
112 DXVA2_VideoProcessBltParams *params, const RECT *area,
113 const DXVA2_VideoSample *samples, int order )
115 memset(params, 0, sizeof(*params));
116 params->TargetFrame = (samples->End - samples->Start) * order / 2;
117 params->TargetRect = *area;
118 params->DestData = 0;
119 params->Alpha = DXVA2_Fixed32OpaqueAlpha();
120 params->DestFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
121 params->BackgroundColor.Alpha = 0xFFFF;
122 params->ConstrictionSize.cx = params->TargetRect.right;
123 params->ConstrictionSize.cy = params->TargetRect.bottom;
125 params->ProcAmpValues.Brightness.Value = sys->Brightness;
126 params->ProcAmpValues.Contrast.Value = sys->Contrast;
127 params->ProcAmpValues.Hue.Value = sys->Hue;
128 params->ProcAmpValues.Saturation.Value = sys->Saturation;
131 static int RenderPic( filter_t *filter, picture_t *p_outpic, picture_t *src,
132 int order, int i_field )
134 filter_sys_t *sys = filter->p_sys;
135 const int i_samples = sys->decoder_caps.NumBackwardRefSamples + 1 +
136 sys->decoder_caps.NumForwardRefSamples;
137 HRESULT hr;
138 DXVA2_VideoProcessBltParams params;
139 DXVA2_VideoSample samples[i_samples];
140 picture_t *pictures[i_samples];
141 D3DSURFACE_DESC srcDesc, dstDesc;
142 RECT area;
144 picture_t *p_prev = sys->context.pp_history[0];
145 picture_t *p_cur = sys->context.pp_history[1];
146 picture_t *p_next = sys->context.pp_history[2];
148 picture_sys_t *p_sys_src = ActivePictureSys(src);
150 hr = IDirect3DSurface9_GetDesc( p_sys_src->surface, &srcDesc );
151 if (unlikely(FAILED(hr)))
152 return VLC_EGENERIC;
153 hr = IDirect3DSurface9_GetDesc( sys->hw_surface, &dstDesc );
154 if (unlikely(FAILED(hr)))
155 return VLC_EGENERIC;
157 area.top = area.left = 0;
158 area.bottom = __MIN(srcDesc.Height, dstDesc.Height);
159 area.right = __MIN(srcDesc.Width, dstDesc.Width);
161 int idx = i_samples - 1;
162 if (p_next)
164 pictures[idx--] = p_next;
165 if (p_cur)
166 pictures[idx--] = p_cur;
167 if (p_prev)
168 pictures[idx--] = p_prev;
170 else
171 pictures[idx--] = src;
172 while (idx >= 0)
173 pictures[idx--] = NULL;
175 for (idx = 0; idx <= i_samples-1; idx++)
177 if (pictures[idx])
178 FillSample( &samples[idx], &sys->context, pictures[idx], &filter->fmt_out.video, &area, i_field);
179 else
181 FillSample( &samples[idx], &sys->context, src, &filter->fmt_out.video, &area, i_field);
182 samples[idx].SampleFormat.SampleFormat = DXVA2_SampleUnknown;
186 FillBlitParams( sys, &params, &area, samples, order );
188 hr = IDirectXVideoProcessor_VideoProcessBlt( sys->processor,
189 sys->hw_surface,
190 &params,
191 samples,
192 i_samples, NULL );
193 if (FAILED(hr))
194 return VLC_EGENERIC;
196 hr = IDirect3DDevice9_StretchRect( sys->d3d_dev.dev,
197 sys->hw_surface, NULL,
198 p_outpic->p_sys->surface, NULL,
199 D3DTEXF_NONE);
200 if (FAILED(hr))
201 return VLC_EGENERIC;
203 return VLC_SUCCESS;
206 static int RenderSinglePic( filter_t *p_filter, picture_t *p_outpic, picture_t *p_pic )
208 return RenderPic( p_filter, p_outpic, p_pic, 0, 0 );
211 static picture_t *Deinterlace(filter_t *p_filter, picture_t *p_pic)
213 return DoDeinterlacing( p_filter, &p_filter->p_sys->context, p_pic );
216 static const struct filter_mode_t *GetFilterMode(const char *mode)
218 if ( mode == NULL || !strcmp( mode, "auto" ) )
219 mode = "x";
221 for (size_t i=0; i<ARRAY_SIZE(filter_mode); i++)
223 if( !strcmp( mode, filter_mode[i].psz_mode ) )
224 return &filter_mode[i];
227 return NULL;
230 static void d3d9_pic_context_destroy(struct picture_context_t *ctx)
232 struct va_pic_context *pic_ctx = (struct va_pic_context*)ctx;
233 ReleasePictureSys(&pic_ctx->picsys);
234 free(pic_ctx);
237 static struct picture_context_t *d3d9_pic_context_copy(struct picture_context_t *ctx)
239 struct va_pic_context *src_ctx = (struct va_pic_context*)ctx;
240 struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
241 if (unlikely(pic_ctx==NULL))
242 return NULL;
243 pic_ctx->s.destroy = d3d9_pic_context_destroy;
244 pic_ctx->s.copy = d3d9_pic_context_copy;
245 pic_ctx->picsys = src_ctx->picsys;
246 AcquirePictureSys(&pic_ctx->picsys);
247 return &pic_ctx->s;
250 static picture_t *NewOutputPicture( filter_t *p_filter )
252 picture_t *pic = p_filter->p_sys->buffer_new( p_filter );
253 if ( !pic->context )
255 /* the picture might be duplicated for snapshots so it needs a context */
256 assert( pic->p_sys != NULL ); /* this opaque picture is wrong */
257 struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
258 if (likely(pic_ctx!=NULL))
260 pic_ctx->s.destroy = d3d9_pic_context_destroy;
261 pic_ctx->s.copy = d3d9_pic_context_copy;
262 pic_ctx->picsys = *pic->p_sys;
263 AcquirePictureSys( &pic_ctx->picsys );
264 pic->context = &pic_ctx->s;
267 return pic;
270 int D3D9OpenDeinterlace(vlc_object_t *obj)
272 filter_t *filter = (filter_t *)obj;
273 filter_sys_t *sys = NULL;
274 HINSTANCE hdecoder_dll = NULL;
275 HINSTANCE d3d9_dll = NULL;
276 HRESULT hr;
277 picture_t *dst = NULL;
278 GUID *processorGUIDs = NULL;
279 GUID *processorGUID = NULL;
280 IDirectXVideoProcessorService *processor = NULL;
282 if (filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE
283 && filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B)
284 return VLC_EGENERIC;
285 if (!video_format_IsSimilar(&filter->fmt_in.video, &filter->fmt_out.video))
286 return VLC_EGENERIC;
288 d3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
289 if (!d3d9_dll)
290 goto error;
292 hdecoder_dll = LoadLibrary(TEXT("DXVA2.DLL"));
293 if (!hdecoder_dll)
294 goto error;
296 sys = calloc(1, sizeof (*sys));
297 if (unlikely(sys == NULL))
298 goto error;
300 dst = filter_NewPicture(filter);
301 if (dst == NULL)
302 goto error;
304 if (!dst->p_sys)
306 msg_Dbg(filter, "D3D9 opaque without a texture");
307 goto error;
310 HRESULT (WINAPI *CreateVideoService)(IDirect3DDevice9 *,
311 REFIID riid,
312 void **ppService);
313 CreateVideoService =
314 (void *)GetProcAddress(hdecoder_dll, "DXVA2CreateVideoService");
315 if (CreateVideoService == NULL)
316 goto error;
318 hr = IDirect3DSurface9_GetDevice( dst->p_sys->surface, &sys->d3d_dev.dev );
319 if (FAILED(hr))
320 goto error;
322 D3DSURFACE_DESC dstDesc;
323 hr = IDirect3DSurface9_GetDesc( dst->p_sys->surface, &dstDesc );
324 if (unlikely(FAILED(hr)))
325 goto error;
327 hr = CreateVideoService( sys->d3d_dev.dev, &IID_IDirectXVideoProcessorService,
328 (void**)&processor);
329 if (FAILED(hr))
330 goto error;
332 DXVA2_VideoDesc dsc;
333 ZeroMemory(&dsc, sizeof(dsc));
334 dsc.SampleWidth = dstDesc.Width;
335 dsc.SampleHeight = dstDesc.Height;
336 dsc.Format = dstDesc.Format;
337 if (filter->fmt_in.video.i_frame_rate && filter->fmt_in.video.i_frame_rate_base) {
338 dsc.InputSampleFreq.Numerator = filter->fmt_in.video.i_frame_rate;
339 dsc.InputSampleFreq.Denominator = filter->fmt_in.video.i_frame_rate_base;
340 } else {
341 dsc.InputSampleFreq.Numerator = 0;
342 dsc.InputSampleFreq.Denominator = 0;
344 dsc.OutputFrameFreq = dsc.InputSampleFreq;
345 dsc.SampleFormat.SampleFormat = DXVA2_SampleFieldInterleavedEvenFirst;
347 UINT count = 0;
348 hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids( processor,
349 &dsc,
350 &count,
351 &processorGUIDs);
352 if (FAILED(hr))
353 goto error;
355 char *psz_mode = var_InheritString( filter, "deinterlace-mode" );
356 const struct filter_mode_t *p_mode = GetFilterMode(psz_mode);
357 if (p_mode == NULL)
359 msg_Dbg(filter, "unknown mode %s, trying blend", psz_mode);
360 p_mode = GetFilterMode("blend");
362 if (strcmp(p_mode->psz_mode, psz_mode))
363 msg_Dbg(filter, "using %s deinterlacing mode", p_mode->psz_mode);
365 DXVA2_VideoProcessorCaps caps, best_caps;
366 unsigned best_score = 0;
367 for (UINT i=0; i<count; ++i) {
368 hr = IDirectXVideoProcessorService_GetVideoProcessorCaps( processor,
369 processorGUIDs+i,
370 &dsc,
371 dsc.Format,
372 &caps);
373 if ( FAILED(hr) || !caps.DeinterlaceTechnology )
374 continue;
376 unsigned score = (caps.DeinterlaceTechnology & p_mode->i_mode) ? 10 : 1;
377 if (best_score < score) {
378 best_score = score;
379 best_caps = caps;
380 processorGUID = processorGUIDs + i;
384 if (processorGUID == NULL)
386 msg_Dbg(filter, "Could not find a filter to output the required format");
387 goto error;
390 hr = IDirectXVideoProcessorService_CreateVideoProcessor( processor,
391 processorGUID,
392 &dsc,
393 dsc.Format,
395 &sys->processor );
396 if (FAILED(hr))
397 goto error;
399 hr = IDirectXVideoProcessorService_CreateSurface( processor,
400 dstDesc.Width,
401 dstDesc.Height,
403 dstDesc.Format,
404 D3DPOOL_DEFAULT,
406 DXVA2_VideoProcessorRenderTarget,
407 &sys->hw_surface,
408 NULL);
409 if (FAILED(hr))
410 goto error;
412 DXVA2_ValueRange Range;
413 hr = IDirectXVideoProcessorService_GetProcAmpRange( processor, processorGUID, &dsc,
414 dstDesc.Format, DXVA2_ProcAmp_Brightness,
415 &Range );
416 if (FAILED(hr))
417 goto error;
418 sys->Brightness = Range.DefaultValue.Value;
420 hr = IDirectXVideoProcessorService_GetProcAmpRange( processor, processorGUID, &dsc,
421 dstDesc.Format, DXVA2_ProcAmp_Contrast,
422 &Range );
423 if (FAILED(hr))
424 goto error;
425 sys->Contrast = Range.DefaultValue.Value;
427 hr = IDirectXVideoProcessorService_GetProcAmpRange( processor, processorGUID, &dsc,
428 dstDesc.Format, DXVA2_ProcAmp_Hue,
429 &Range );
430 if (FAILED(hr))
431 goto error;
432 sys->Hue = Range.DefaultValue.Value;
434 hr = IDirectXVideoProcessorService_GetProcAmpRange( processor, processorGUID, &dsc,
435 dstDesc.Format, DXVA2_ProcAmp_Saturation,
436 &Range );
437 if (FAILED(hr))
438 goto error;
439 sys->Saturation = Range.DefaultValue.Value;
441 sys->hdecoder_dll = hdecoder_dll;
442 sys->d3d9_dll = d3d9_dll;
443 sys->decoder_caps = best_caps;
445 InitDeinterlacingContext( &sys->context );
447 sys->context.settings = p_mode->settings;
448 sys->context.settings.b_use_frame_history = best_caps.NumBackwardRefSamples != 0 ||
449 best_caps.NumForwardRefSamples != 0;
450 if (sys->context.settings.b_use_frame_history != p_mode->settings.b_use_frame_history)
451 msg_Dbg( filter, "deinterlacing not using frame history as requested");
452 if (sys->context.settings.b_double_rate)
453 sys->context.pf_render_ordered = RenderPic;
454 else
455 sys->context.pf_render_single_pic = RenderSinglePic;
457 video_format_t out_fmt;
458 GetDeinterlacingOutput( &sys->context, &out_fmt, &filter->fmt_in.video );
459 if( !filter->b_allow_fmt_out_change &&
460 out_fmt.i_height != filter->fmt_in.video.i_height )
462 goto error;
465 CoTaskMemFree(processorGUIDs);
466 IDirectXVideoProcessorService_Release(processor);
467 picture_Release(dst);
469 sys->buffer_new = filter->owner.video.buffer_new;
470 filter->owner.video.buffer_new = NewOutputPicture;
471 filter->fmt_out.video = out_fmt;
472 filter->pf_video_filter = Deinterlace;
473 filter->pf_flush = Flush;
474 filter->p_sys = sys;
476 return VLC_SUCCESS;
477 error:
478 CoTaskMemFree(processorGUIDs);
479 if (sys && sys->processor)
480 IDirectXVideoProcessor_Release( sys->processor );
481 if (processor)
482 IDirectXVideoProcessorService_Release(processor);
483 D3D9_ReleaseDevice( &sys->d3d_dev );
484 if (hdecoder_dll)
485 FreeLibrary(hdecoder_dll);
486 if (d3d9_dll)
487 FreeLibrary(d3d9_dll);
488 if (dst)
489 picture_Release(dst);
490 free(sys);
492 return VLC_EGENERIC;
495 void D3D9CloseDeinterlace(vlc_object_t *obj)
497 filter_t *filter = (filter_t *)obj;
498 filter_sys_t *sys = filter->p_sys;
500 IDirect3DSurface9_Release( sys->hw_surface );
501 IDirectXVideoProcessor_Release( sys->processor );
502 D3D9_ReleaseDevice( &sys->d3d_dev );
503 FreeLibrary( sys->hdecoder_dll );
504 FreeLibrary( sys->d3d9_dll );
506 free(sys);