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 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_filter.h>
32 #include <vlc_picture.h>
38 #include "../../video_chroma/d3d9_fmt.h"
39 #include "../../video_filter/deinterlace/common.h"
41 #include "d3d9_filters.h"
45 HINSTANCE hdecoder_dll
;
46 /* keep a reference in case the vout is released first */
48 d3d9_device_t d3d_dev
;
49 IDirectXVideoProcessor
*processor
;
50 IDirect3DSurface9
*hw_surface
;
52 DXVA2_VideoProcessorCaps decoder_caps
;
59 struct deinterlace_ctx context
;
60 picture_t
* (*buffer_new
)( filter_t
* );
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
,
90 const video_format_t
*p_fmt
,
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
;
101 p_sample
->End
= GetFieldDuration(p_context
, p_fmt
, p_pic
) * 10;
102 p_sample
->SampleData
= DXVA2_SampleData_RFF_TFF_Present
;
104 p_sample
->SampleData
|= DXVA2_SampleData_TFF
;
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
;
138 DXVA2_VideoProcessBltParams params
;
139 DXVA2_VideoSample samples
[i_samples
];
140 picture_t
*pictures
[i_samples
];
141 D3DSURFACE_DESC srcDesc
, dstDesc
;
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
)))
153 hr
= IDirect3DSurface9_GetDesc( sys
->hw_surface
, &dstDesc
);
154 if (unlikely(FAILED(hr
)))
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;
164 pictures
[idx
--] = p_next
;
166 pictures
[idx
--] = p_cur
;
168 pictures
[idx
--] = p_prev
;
171 pictures
[idx
--] = src
;
173 pictures
[idx
--] = NULL
;
175 for (idx
= 0; idx
<= i_samples
-1; idx
++)
178 FillSample( &samples
[idx
], &sys
->context
, pictures
[idx
], &filter
->fmt_out
.video
, &area
, i_field
);
181 FillSample( &samples
[idx
], &sys
->context
, src
, &filter
->fmt_out
.video
, &area
, i_field
);
182 samples
[idx
].SampleFormat
.SampleFormat
= DXVA2_SampleUnknown
;
186 FillBlitParams( sys
, ¶ms
, &area
, samples
, order
);
188 hr
= IDirectXVideoProcessor_VideoProcessBlt( sys
->processor
,
196 hr
= IDirect3DDevice9_StretchRect( sys
->d3d_dev
.dev
,
197 sys
->hw_surface
, NULL
,
198 p_outpic
->p_sys
->surface
, NULL
,
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" ) )
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
];
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
);
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
))
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
);
250 static picture_t
*NewOutputPicture( filter_t
*p_filter
)
252 picture_t
*pic
= p_filter
->p_sys
->buffer_new( p_filter
);
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
;
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
;
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
)
285 if (!video_format_IsSimilar(&filter
->fmt_in
.video
, &filter
->fmt_out
.video
))
288 d3d9_dll
= LoadLibrary(TEXT("D3D9.DLL"));
292 hdecoder_dll
= LoadLibrary(TEXT("DXVA2.DLL"));
296 sys
= calloc(1, sizeof (*sys
));
297 if (unlikely(sys
== NULL
))
300 dst
= filter_NewPicture(filter
);
306 msg_Dbg(filter
, "D3D9 opaque without a texture");
310 HRESULT (WINAPI
*CreateVideoService
)(IDirect3DDevice9
*,
314 (void *)GetProcAddress(hdecoder_dll
, "DXVA2CreateVideoService");
315 if (CreateVideoService
== NULL
)
318 hr
= IDirect3DSurface9_GetDevice( dst
->p_sys
->surface
, &sys
->d3d_dev
.dev
);
322 D3DSURFACE_DESC dstDesc
;
323 hr
= IDirect3DSurface9_GetDesc( dst
->p_sys
->surface
, &dstDesc
);
324 if (unlikely(FAILED(hr
)))
327 hr
= CreateVideoService( sys
->d3d_dev
.dev
, &IID_IDirectXVideoProcessorService
,
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
;
341 dsc
.InputSampleFreq
.Numerator
= 0;
342 dsc
.InputSampleFreq
.Denominator
= 0;
344 dsc
.OutputFrameFreq
= dsc
.InputSampleFreq
;
345 dsc
.SampleFormat
.SampleFormat
= DXVA2_SampleFieldInterleavedEvenFirst
;
348 hr
= IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids( processor
,
355 char *psz_mode
= var_InheritString( filter
, "deinterlace-mode" );
356 const struct filter_mode_t
*p_mode
= GetFilterMode(psz_mode
);
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
,
373 if ( FAILED(hr
) || !caps
.DeinterlaceTechnology
)
376 unsigned score
= (caps
.DeinterlaceTechnology
& p_mode
->i_mode
) ? 10 : 1;
377 if (best_score
< score
) {
380 processorGUID
= processorGUIDs
+ i
;
384 if (processorGUID
== NULL
)
386 msg_Dbg(filter
, "Could not find a filter to output the required format");
390 hr
= IDirectXVideoProcessorService_CreateVideoProcessor( processor
,
399 hr
= IDirectXVideoProcessorService_CreateSurface( processor
,
406 DXVA2_VideoProcessorRenderTarget
,
412 DXVA2_ValueRange Range
;
413 hr
= IDirectXVideoProcessorService_GetProcAmpRange( processor
, processorGUID
, &dsc
,
414 dstDesc
.Format
, DXVA2_ProcAmp_Brightness
,
418 sys
->Brightness
= Range
.DefaultValue
.Value
;
420 hr
= IDirectXVideoProcessorService_GetProcAmpRange( processor
, processorGUID
, &dsc
,
421 dstDesc
.Format
, DXVA2_ProcAmp_Contrast
,
425 sys
->Contrast
= Range
.DefaultValue
.Value
;
427 hr
= IDirectXVideoProcessorService_GetProcAmpRange( processor
, processorGUID
, &dsc
,
428 dstDesc
.Format
, DXVA2_ProcAmp_Hue
,
432 sys
->Hue
= Range
.DefaultValue
.Value
;
434 hr
= IDirectXVideoProcessorService_GetProcAmpRange( processor
, processorGUID
, &dsc
,
435 dstDesc
.Format
, DXVA2_ProcAmp_Saturation
,
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
;
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
)
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
;
478 CoTaskMemFree(processorGUIDs
);
479 if (sys
&& sys
->processor
)
480 IDirectXVideoProcessor_Release( sys
->processor
);
482 IDirectXVideoProcessorService_Release(processor
);
483 D3D9_ReleaseDevice( &sys
->d3d_dev
);
485 FreeLibrary(hdecoder_dll
);
487 FreeLibrary(d3d9_dll
);
489 picture_Release(dst
);
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
);