1 /* ********************************************************************* *\
2
3 Copyright (C) 2013 Intel Corporation. All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 - Redistributions of source code must retain the above copyright notice,
8 this list of conditions and the following disclaimer.
9 - Redistributions in binary form must reproduce the above copyright notice,
10 this list of conditions and the following disclaimer in the documentation
11 and/or other materials provided with the distribution.
12 - Neither the name of Intel Corporation nor the names of its contributors
13 may be used to endorse or promote products derived from this software
14 without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 \* ********************************************************************* */
28
29 #include "handbrake/project.h"
30
31 #if HB_PROJECT_FEATURE_QSV
32
33 #include "handbrake/handbrake.h"
34 #include "handbrake/hbffmpeg.h"
35 #include "handbrake/qsv_filter.h"
36 #include "handbrake/qsv_libav.h"
37
38 struct hb_filter_private_s
39 {
40 hb_job_t * job;
41 hb_buffer_list_t list;
42
43 int width_in;
44 int height_in;
45 int pix_fmt;
46 int pix_fmt_out;
47 int width_out;
48 int height_out;
49 int crop[4];
50 int deinterlace;
51 int is_frc_used;
52
53 // set during init, used to configure input surfaces' "area of interest"
54 mfxU16 CropX;
55 mfxU16 CropY;
56 mfxU16 CropH;
57 mfxU16 CropW;
58
59 hb_qsv_space * vpp_space;
60
61 // FRC param(s)
62 mfxExtVPPFrameRateConversion frc_config;
63 };
64
65 static int hb_qsv_filter_init( hb_filter_object_t * filter,
66 hb_filter_init_t * init );
67
68 static int hb_qsv_filter_work( hb_filter_object_t * filter,
69 hb_buffer_t ** buf_in,
70 hb_buffer_t ** buf_out );
71
72 static hb_filter_info_t * hb_qsv_filter_info( hb_filter_object_t * filter );
73
74 static void hb_qsv_filter_close( hb_filter_object_t * filter );
75
76 static const char qsv_filter_template[] =
77 "width=^"HB_INT_REG"$:height=^"HB_INT_REG"$:"
78 "crop-top=^"HB_INT_REG"$:crop-bottom=^"HB_INT_REG"$:"
79 "crop-left=^"HB_INT_REG"$:crop-right=^"HB_INT_REG"$:"
80 "deinterlace=^([01])$";
81
82 hb_filter_object_t hb_filter_qsv =
83 {
84 .id = HB_FILTER_QSV,
85 .enforce_order = 1,
86 .name = "Quick Sync Video VPP",
87 .settings = NULL,
88 .init = hb_qsv_filter_init,
89 .work = hb_qsv_filter_work,
90 .close = hb_qsv_filter_close,
91 .info = hb_qsv_filter_info,
92 .settings_template = qsv_filter_template,
93 };
94
filter_init(hb_qsv_context * qsv,hb_filter_private_t * pv)95 static int filter_init( hb_qsv_context* qsv, hb_filter_private_t * pv ){
96 mfxStatus sts;
97 int i=0;
98
99 if(!qsv) return 3;
100
101
102 if(!qsv->vpp_space){
103 qsv->vpp_space = hb_qsv_list_init(HAVE_THREADS);
104 }
105 if(!pv->vpp_space){
106 for(i=0; i<hb_qsv_list_count(qsv->vpp_space);i++){
107 hb_qsv_space *qsv_vpp = hb_qsv_list_item( qsv->vpp_space, i );
108 if(qsv_vpp->type == HB_QSV_VPP_DEFAULT){
109 pv->vpp_space = qsv_vpp;
110 break;
111 }
112 }
113 }
114
115 if(!pv->vpp_space){
116 pv->vpp_space = calloc( 1, sizeof( hb_qsv_space ));
117 pv->vpp_space->type = HB_QSV_VPP_DEFAULT;
118 hb_qsv_list_add( qsv->vpp_space, pv->vpp_space );
119 }
120 else
121 if(pv->vpp_space->is_init_done ) return 1;
122
123 if(!qsv->dec_space || !qsv->dec_space->is_init_done) return 2;
124
125 // we need to know final output settings before we can properly configure
126 if (!pv->job->qsv.enc_info.is_init_done)
127 {
128 return 2;
129 }
130
131 hb_qsv_add_context_usage(qsv,HAVE_THREADS);
132
133 // see params needed like at mediasdk-man.pdf:"Appendix A: Configuration Parameter Constraints"
134 // for now - most will take from the decode
135 {
136 hb_qsv_space *qsv_vpp = pv->vpp_space;
137 HB_QSV_ZERO_MEMORY(qsv_vpp->m_mfxVideoParam);
138
139 if (pv->deinterlace)
140 {
141 /*
142 * Input may be progressive, interlaced or even mixed, so init with
143 * MFX_PICSTRUCT_UNKNOWN and use per-frame field order information
144 * (mfxFrameSurface1.Info.PicStruct)
145 */
146 qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = MFX_PICSTRUCT_UNKNOWN;
147 qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
148 }
149 else
150 {
151 /* Same PicStruct in/out: no filtering */
152 qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct;
153 qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct;
154 }
155
156 // FrameRate is important for VPP to start with
157 if( qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN == 0 &&
158 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD == 0 ){
159 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN = pv->job->title->vrate.num;
160 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD = pv->job->title->vrate.den;
161 }
162
163 /*
164 * In theory, input width/height and decode CropW/CropH should be the
165 * same; however, due to some versions of FFmpeg not applying the H.264
166 * "crop rect" properly, there can be a mismatch.
167 *
168 * Since we want the same behavior regardless of whether we're using
169 * software or hardware-accelerated decoding, prefer the FFmpeg values.
170 *
171 * Note that since CropW/CropH may be higher than the decode values, we
172 * need to adjust CropX/CropY to make sure we don't exceed the input's
173 * Width/Height boundaries.
174 */
175 pv->CropW = pv-> width_in;
176 pv->CropH = pv->height_in;
177 pv->CropX = FFMIN(qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX,
178 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Width - pv->CropW);
179 pv->CropY = FFMIN(qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY,
180 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Height - pv->CropH);
181 /* Then, apply additional cropping requested by the user, if any */
182 pv->CropX += pv->crop[2];
183 pv->CropY += pv->crop[0];
184 pv->CropW -= pv->crop[2] + pv->crop[3];
185 pv->CropH -= pv->crop[0] + pv->crop[1];
186
187
188 qsv_vpp->m_mfxVideoParam.vpp.In.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC;
189 qsv_vpp->m_mfxVideoParam.vpp.In.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat;
190 qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN = pv->job->vrate.num;
191 qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD = pv->job->vrate.den;
192 qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW;
193 qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH;
194 qsv_vpp->m_mfxVideoParam.vpp.In.Width = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Width;
195 qsv_vpp->m_mfxVideoParam.vpp.In.Height = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Height;
196 qsv_vpp->m_mfxVideoParam.vpp.In.CropX = pv->CropX;
197 qsv_vpp->m_mfxVideoParam.vpp.In.CropY = pv->CropY;
198 qsv_vpp->m_mfxVideoParam.vpp.In.CropW = pv->CropW;
199 qsv_vpp->m_mfxVideoParam.vpp.In.CropH = pv->CropH;
200
201 qsv_vpp->m_mfxVideoParam.vpp.Out.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC;
202 qsv_vpp->m_mfxVideoParam.vpp.Out.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat;
203 qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN = pv->job->vrate.num;
204 qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD = pv->job->vrate.den;
205 qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW;
206 qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH;
207 qsv_vpp->m_mfxVideoParam.vpp.Out.Width = pv->job->qsv.enc_info.align_width;
208 qsv_vpp->m_mfxVideoParam.vpp.Out.Height = pv->job->qsv.enc_info.align_height;
209 qsv_vpp->m_mfxVideoParam.vpp.Out.CropX = 0; // no letterboxing
210 qsv_vpp->m_mfxVideoParam.vpp.Out.CropY = 0; // no pillarboxing
211 qsv_vpp->m_mfxVideoParam.vpp.Out.CropW = pv-> width_out;
212 qsv_vpp->m_mfxVideoParam.vpp.Out.CropH = pv->height_out;
213
214 qsv_vpp->m_mfxVideoParam.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
215
216 qsv_vpp->m_mfxVideoParam.AsyncDepth = pv->job->qsv.async_depth;
217
218 memset(&qsv_vpp->request, 0, sizeof(mfxFrameAllocRequest)*2);
219
220 sts = MFXVideoVPP_QueryIOSurf(qsv->mfx_session, &qsv_vpp->m_mfxVideoParam, qsv_vpp->request );
221 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
222
223 int num_surfaces_in = qsv_vpp->request[0].NumFrameSuggested;
224 int num_surfaces_out = qsv_vpp->request[1].NumFrameSuggested;
225
226 hb_qsv_config *config = qsv->qsv_config;
227
228
229 qsv_vpp->surface_num = FFMIN( num_surfaces_in + num_surfaces_out + qsv_vpp->m_mfxVideoParam.AsyncDepth + config ? config->additional_buffers/2 :0 , HB_QSV_SURFACE_NUM );
230 if(qsv_vpp->surface_num <= 0 )
231 qsv_vpp->surface_num = HB_QSV_SURFACE_NUM;
232
233 int i = 0;
234 for (i = 0; i < qsv_vpp->surface_num; i++){
235 qsv_vpp->p_surfaces[i] = av_mallocz( sizeof(mfxFrameSurface1) );
236 HB_QSV_CHECK_POINTER(qsv_vpp->p_surfaces[i], MFX_ERR_MEMORY_ALLOC);
237 memcpy(&(qsv_vpp->p_surfaces[i]->Info), &(qsv_vpp->m_mfxVideoParam.vpp.Out), sizeof(mfxFrameInfo));
238 }
239
240 qsv_vpp->sync_num = FFMIN( qsv_vpp->surface_num, HB_QSV_SYNC_NUM );
241
242 for (i = 0; i < qsv_vpp->sync_num; i++){
243 qsv_vpp->p_syncp[i] = av_mallocz(sizeof(hb_qsv_sync));
244 HB_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i], MFX_ERR_MEMORY_ALLOC);
245 qsv_vpp->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint));
246 HB_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i]->p_sync, MFX_ERR_MEMORY_ALLOC);
247 }
248 /*
249 about available VPP filters, see "Table 4 Configurable VPP filters", mediasdk-man.pdf
250 Hints (optional feature) IDs:
251 MFX_EXTBUFF_VPP_DENOISE // Remove noise
252 // Value of 0-100 (inclusive) indicates
253 // the level of noise to remove.
254 MFX_EXTBUFF_VPP_DETAIL // Enhance picture details/edges:
255 // 0-100 value (inclusive) to indicate
256 // the level of details to be enhanced.
257 MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION // Convert input frame rate to match the output, based on frame interpolation:
258 // MFX_FRCALGM_PRESERVE_TIMESTAMP,
259 // MFX_FRCALGM_DISTRIBUTED_TIMESTAMP,
260 // MFX_FRCALGM_FRAME_INTERPOLATION
261 MFX_EXTBUFF_VPP_IMAGE_STABILIZATION // Perform image stabilization
262 // Stabilization modes:
263 // MFX_IMAGESTAB_MODE_UPSCALE
264 // MFX_IMAGESTAB_MODE_BOXING
265 MFX_EXTBUFF_VPP_PICSTRUCT_DETECTION // Perform detection of picture structure:
266 // Detected picture structure - top field first, bottom field first, progressive or unknown
267 // if video processor cannot detect picture structure.
268 MFX_EXTBUFF_VPP_PROCAMP // Adjust the brightness, contrast, saturation, and hue settings
269
270 // Initialize extended buffer for frame processing
271 // - Process amplifier (ProcAmp) used to control brightness
272 // - mfxExtVPPDoUse: Define the processing algorithm to be used
273 // - mfxExtVPPProcAmp: ProcAmp configuration
274 // - mfxExtBuffer: Add extended buffers to VPP parameter configuration
275 mfxExtVPPDoUse extDoUse;
276 mfxU32 tabDoUseAlg[1];
277 extDoUse.Header.BufferId = MFX_EXTBUFF_VPP_DOUSE;
278 extDoUse.Header.BufferSz = sizeof(mfxExtVPPDoUse);
279 extDoUse.NumAlg = 1;
280 extDoUse.AlgList = tabDoUseAlg;
281 tabDoUseAlg[0] = MFX_EXTBUFF_VPP_PROCAMP;
282
283 mfxExtVPPProcAmp procampConfig;
284 procampConfig.Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP;
285 procampConfig.Header.BufferSz = sizeof(mfxExtVPPProcAmp);
286 procampConfig.Hue = 0.0f; // Default
287 procampConfig.Saturation = 1.0f; // Default
288 procampConfig.Contrast = 1.0; // Default
289 procampConfig.Brightness = 40.0; // Adjust brightness
290
291 mfxExtBuffer* ExtBuffer[2];
292 ExtBuffer[0] = (mfxExtBuffer*)&extDoUse;
293 ExtBuffer[1] = (mfxExtBuffer*)&procampConfig;
294 VPPParams.NumExtParam = 2;
295 VPPParams.ExtParam = (mfxExtBuffer**)&ExtBuffer[0];
296 */
297 memset(&qsv_vpp->ext_opaque_alloc, 0, sizeof(qsv_vpp->ext_opaque_alloc));
298
299 if( (qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN / qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD ) !=
300 (qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN / qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD) )
301 {
302 pv->is_frc_used = 1;
303 }
304
305 qsv_vpp->m_mfxVideoParam.NumExtParam = qsv_vpp->p_ext_param_num = 1 + pv->is_frc_used;
306
307 qsv_vpp->p_ext_params = av_mallocz(sizeof(mfxExtBuffer *)*qsv_vpp->p_ext_param_num);
308 HB_QSV_CHECK_POINTER(qsv_vpp->p_ext_params, MFX_ERR_MEMORY_ALLOC);
309
310 qsv_vpp->m_mfxVideoParam.ExtParam = qsv_vpp->p_ext_params;
311
312 qsv_vpp->ext_opaque_alloc.In.Surfaces = qsv->dec_space->p_surfaces;
313 qsv_vpp->ext_opaque_alloc.In.NumSurface = qsv->dec_space->surface_num;
314 qsv_vpp->ext_opaque_alloc.In.Type = qsv->dec_space->request[0].Type;
315
316 qsv_vpp->ext_opaque_alloc.Out.Surfaces = qsv_vpp->p_surfaces;
317 qsv_vpp->ext_opaque_alloc.Out.NumSurface = qsv_vpp->surface_num;
318 qsv_vpp->ext_opaque_alloc.Out.Type = qsv->dec_space->request[0].Type;
319
320 qsv_vpp->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
321 qsv_vpp->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc);
322 qsv_vpp->p_ext_params[0] = (mfxExtBuffer*)&qsv_vpp->ext_opaque_alloc;
323
324 if(pv->is_frc_used)
325 {
326 pv->frc_config.Header.BufferId = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION;
327 pv->frc_config.Header.BufferSz = sizeof(mfxExtVPPFrameRateConversion);
328 pv->frc_config.Algorithm = MFX_FRCALGM_PRESERVE_TIMESTAMP;
329
330 qsv_vpp->p_ext_params[1] = (mfxExtBuffer*)&pv->frc_config;
331 }
332
333 sts = MFXVideoVPP_Init(qsv->mfx_session, &qsv_vpp->m_mfxVideoParam);
334
335 HB_QSV_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
336 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
337
338 qsv_vpp->is_init_done = 1;
339 }
340 return 0;
341 }
342
hb_qsv_filter_init(hb_filter_object_t * filter,hb_filter_init_t * init)343 static int hb_qsv_filter_init( hb_filter_object_t * filter,
344 hb_filter_init_t * init )
345 {
346
347 filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
348 hb_filter_private_t * pv = filter->private_data;
349
350 hb_buffer_list_clear(&pv->list);
351 // list of init params provided at work.c:~700
352 pv->width_in = init->geometry.width;
353 pv->height_in = init->geometry.height;
354 pv->width_out = init->geometry.width;
355 pv->height_out = init->geometry.height;
356 memcpy( pv->crop, init->crop, sizeof( int[4] ) );
357
358 hb_dict_extract_int(&pv->width_out, filter->settings, "width");
359 hb_dict_extract_int(&pv->height_out, filter->settings, "height");
360 hb_dict_extract_int(&pv->crop[0], filter->settings, "crop-top");
361 hb_dict_extract_int(&pv->crop[1], filter->settings, "crop-bottom");
362 hb_dict_extract_int(&pv->crop[2], filter->settings, "crop-left");
363 hb_dict_extract_int(&pv->crop[3], filter->settings, "crop-right");
364 hb_dict_extract_bool(&pv->deinterlace, filter->settings, "deinterlace");
365
366 pv->job = init->job;
367
368 // will be later as more params will be known
369 // filter_init(pv->job->qsv, pv);
370
371 // framerate shaping not yet supported
372 init->cfr = 0;
373
374 init->pix_fmt = pv->pix_fmt;
375 init->geometry.width = pv->width_out;
376 init->geometry.height = pv->height_out;
377 memcpy( init->crop, pv->crop, sizeof( int[4] ) );
378
379 return 0;
380 }
381
hb_qsv_filter_info(hb_filter_object_t * filter)382 static hb_filter_info_t * hb_qsv_filter_info( hb_filter_object_t * filter )
383 {
384 hb_filter_private_t *pv = filter->private_data;
385 hb_filter_info_t * info;
386
387 if( !pv )
388 return NULL;
389
390 info = calloc(1, sizeof(hb_filter_info_t));
391 info->human_readable_desc = malloc(128);
392 info->human_readable_desc[0] = 0;
393
394 snprintf(info->human_readable_desc, 128,
395 "source: %d * %d, crop (%d/%d/%d/%d): %d * %d, scale: %d * %d",
396 pv->width_in, pv->height_in,
397 pv->crop[0], pv->crop[1], pv->crop[2], pv->crop[3],
398 pv->width_in - pv->crop[2] - pv->crop[3],
399 pv->height_in - pv->crop[0] - pv->crop[1],
400 pv->width_out, pv->height_out);
401
402 if (pv->deinterlace)
403 {
404 int len = strlen(info->human_readable_desc);
405 snprintf(info->human_readable_desc + len, 128 - len, ", deinterlace");
406 }
407
408 return info;
409 }
410
qsv_filter_close(hb_qsv_context * qsv,HB_QSV_STAGE_TYPE vpp_type)411 void qsv_filter_close( hb_qsv_context* qsv, HB_QSV_STAGE_TYPE vpp_type ){
412 int i = 0;
413 int x = 0;
414 hb_qsv_space* vpp_space = 0;
415
416 if(qsv && qsv->is_context_active && qsv->vpp_space)
417 for(i=hb_qsv_list_count( qsv->vpp_space);i>0;i--){
418
419 vpp_space = hb_qsv_list_item( qsv->vpp_space, i-1 );
420 if( vpp_space->type == vpp_type && vpp_space->is_init_done){
421
422 hb_log( "qsv_filter[%s] done: max_surfaces: %u/%u , max_syncs: %u/%u", ((vpp_type == HB_QSV_VPP_DEFAULT)?"Default": "User") ,vpp_space->surface_num_max_used, vpp_space->surface_num, vpp_space->sync_num_max_used, vpp_space->sync_num );
423
424 for (x = 0; x < vpp_space->surface_num; x++){
425 av_freep(&vpp_space->p_surfaces[x]);
426 }
427 vpp_space->surface_num = 0;
428
429 if( vpp_space->p_ext_param_num || vpp_space->p_ext_params )
430 av_freep(&vpp_space->p_ext_params);
431 vpp_space->p_ext_param_num = 0;
432
433 for (x = 0; x < vpp_space->sync_num; x++){
434 av_freep(&vpp_space->p_syncp[x]->p_sync);
435 av_freep(&vpp_space->p_syncp[x]);
436 }
437 vpp_space->sync_num = 0;
438
439 hb_qsv_list_rem(qsv->vpp_space,vpp_space);
440 if( hb_qsv_list_count(qsv->vpp_space) == 0 )
441 hb_qsv_list_close(&qsv->vpp_space);
442
443 vpp_space->is_init_done = 0;
444 break;
445 }
446 }
447 }
448
hb_qsv_filter_close(hb_filter_object_t * filter)449 static void hb_qsv_filter_close( hb_filter_object_t * filter )
450 {
451 hb_filter_private_t * pv = filter->private_data;
452
453 if ( !pv )
454 {
455 return;
456 }
457
458 hb_qsv_context* qsv = pv->job->qsv.ctx;
459 if(qsv && qsv->vpp_space && hb_qsv_list_count(qsv->vpp_space) > 0){
460
461 // closing local stuff
462 qsv_filter_close(qsv,HB_QSV_VPP_DEFAULT);
463
464 // closing the common stuff
465 hb_qsv_context_clean(qsv,hb_qsv_full_path_is_enabled(pv->job));
466 }
467 hb_buffer_list_close(&pv->list);
468 free( pv );
469 filter->private_data = NULL;
470 }
471
process_frame(hb_qsv_list * received_item,hb_qsv_context * qsv,hb_filter_private_t * pv)472 int process_frame(hb_qsv_list* received_item, hb_qsv_context* qsv, hb_filter_private_t * pv ){
473
474 // 1 if have results , 0 - otherwise
475 int ret = 1;
476
477 mfxStatus sts = MFX_ERR_NONE;
478 mfxFrameSurface1 *work_surface = NULL;
479 hb_qsv_stage* stage = 0;
480
481 hb_qsv_space *qsv_vpp = pv->vpp_space;
482
483 if(received_item){
484 stage = hb_qsv_get_last_stage( received_item );
485 work_surface = stage->out.p_surface;
486 }
487
488 int sync_idx = hb_qsv_get_free_sync(qsv_vpp, qsv);
489 int surface_idx = -1;
490
491 for(;;)
492 {
493 if (sync_idx == -1)
494 {
495 hb_error("qsv: Not enough resources allocated for QSV filter");
496 ret = 0;
497 break;
498 }
499 if( sts == MFX_ERR_MORE_SURFACE || sts == MFX_ERR_NONE )
500 surface_idx = hb_qsv_get_free_surface(qsv_vpp, qsv, &(qsv_vpp->m_mfxVideoParam.vpp.Out), QSV_PART_ANY);
501 if (surface_idx == -1) {
502 hb_error("qsv: Not enough resources allocated for QSV filter");
503 ret = 0;
504 break;
505 }
506 if (work_surface != NULL)
507 {
508 work_surface->Info.CropX = pv->CropX;
509 work_surface->Info.CropY = pv->CropY;
510 work_surface->Info.CropW = pv->CropW;
511 work_surface->Info.CropH = pv->CropH;
512 }
513
514 sts = MFXVideoVPP_RunFrameVPPAsync(qsv->mfx_session, work_surface, qsv_vpp->p_surfaces[surface_idx] , NULL, qsv_vpp->p_syncp[sync_idx]->p_sync);
515
516 if( MFX_ERR_MORE_DATA == sts ){
517 if(!qsv_vpp->pending){
518 qsv_vpp->pending = hb_qsv_list_init(0);
519 }
520
521 // if we have no results, we should not miss resource(s)
522 hb_qsv_list_add( qsv_vpp->pending, received_item);
523
524 ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use);
525
526 ret = 0;
527 break;
528 }
529
530 if( MFX_ERR_MORE_DATA == sts || (MFX_ERR_NONE <= sts && MFX_WRN_DEVICE_BUSY != sts)){
531 if (work_surface){
532 ff_qsv_atomic_dec(&work_surface->Data.Locked);
533 }
534 }
535
536 if( MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE <= sts){
537 if( MFX_ERR_MORE_SURFACE == sts )
538 continue;
539
540 if (qsv_vpp->p_surfaces[surface_idx] && MFX_WRN_DEVICE_BUSY != sts )
541 ff_qsv_atomic_inc(&qsv_vpp->p_surfaces[surface_idx]->Data.Locked);
542 }
543
544 HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
545
546 if (MFX_ERR_NONE <= sts ) // repeat the call if warning and no output
547 {
548 if (MFX_WRN_DEVICE_BUSY == sts){
549 hb_qsv_sleep(10); // wait if device is busy
550 continue;
551 }
552
553 // shouldn't be a case but drain
554 if(stage){
555 hb_qsv_stage* new_stage = hb_qsv_stage_init();
556
557 new_stage->type = HB_QSV_VPP_DEFAULT;
558 new_stage->in.p_surface = work_surface;
559 new_stage->out.p_surface = qsv_vpp->p_surfaces[surface_idx];
560 new_stage->out.sync = qsv_vpp->p_syncp[sync_idx];
561 hb_qsv_add_stagee( &received_item, new_stage,HAVE_THREADS );
562
563 // add pending resources for the proper reclaim later
564 if( qsv_vpp->pending ){
565 if( hb_qsv_list_count(qsv_vpp->pending)>0 ){
566 new_stage->pending = qsv_vpp->pending;
567 }
568 qsv_vpp->pending = 0;
569
570 // making free via decrement for all pending
571 int i = 0;
572 for (i = hb_qsv_list_count(new_stage->pending); i > 0; i--){
573 hb_qsv_list *atom_list = hb_qsv_list_item(new_stage->pending, i-1);
574 hb_qsv_stage *stage = hb_qsv_get_last_stage( atom_list );
575 mfxFrameSurface1 *work_surface = stage->out.p_surface;
576 if (work_surface)
577 ff_qsv_atomic_dec(&work_surface->Data.Locked);
578 }
579 }
580 }
581 break;
582 }
583
584 ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use);
585
586 if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)
587 HB_DEBUG_ASSERT(1, "The bitstream buffer size is insufficient.");
588
589 break;
590 }
591
592 return ret;
593 }
594
hb_qsv_filter_work(hb_filter_object_t * filter,hb_buffer_t ** buf_in,hb_buffer_t ** buf_out)595 static int hb_qsv_filter_work( hb_filter_object_t * filter,
596 hb_buffer_t ** buf_in,
597 hb_buffer_t ** buf_out )
598 {
599
600 hb_filter_private_t * pv = filter->private_data;
601 hb_buffer_t * in = *buf_in;
602 hb_buffer_t * out = *buf_out;
603 int sts = 0;
604
605 if ( !pv )
606 {
607 *buf_out = in;
608 *buf_in = NULL;
609 return HB_FILTER_OK;
610 }
611
612 hb_qsv_context* qsv = pv->job->qsv.ctx;
613
614 while(1)
615 {
616 int ret = filter_init(qsv,pv);
617 if(ret >= 2)
618 hb_qsv_sleep(1);
619 else
620 break;
621 }
622
623 *buf_in = NULL;
624
625 if (in->s.flags & HB_BUF_FLAG_EOF)
626 {
627 while(1)
628 {
629 sts = process_frame(in->qsv_details.qsv_atom, qsv, pv);
630 if(sts)
631 hb_buffer_list_append(&pv->list, in);
632 else
633 break;
634 }
635
636 hb_buffer_list_append(&pv->list, in);
637 *buf_out = hb_buffer_list_clear(&pv->list);
638 return HB_FILTER_DONE;
639 }
640
641 sts = process_frame(in->qsv_details.qsv_atom, qsv, pv);
642
643 if(sts)
644 {
645 hb_buffer_list_append(&pv->list, in);
646 }
647
648 out = *buf_out = hb_buffer_list_rem_head(&pv->list);
649 if (pv->is_frc_used && out != NULL)
650 {
651 if (out->qsv_details.qsv_atom)
652 {
653 hb_qsv_stage* stage;
654 mfxFrameSurface1 *work_surface;
655 int64_t duration;
656 hb_qsv_space *qsv_vpp;
657
658 stage = hb_qsv_get_last_stage(out->qsv_details.qsv_atom);
659 work_surface = stage->out.p_surface;
660
661 hb_qsv_wait_on_sync( qsv,stage );
662
663 qsv_vpp = pv->vpp_space;
664 duration =
665 ((double)qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD /
666 (double)qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN ) *
667 90000.;
668 out->s.start = work_surface->Data.TimeStamp;
669 out->s.stop = work_surface->Data.TimeStamp + duration;
670 }
671 }
672
673 return HB_FILTER_OK;
674 }
675
676 #endif // HB_PROJECT_FEATURE_QSV
677
678