WinGui: Fix another instance of the Caliburn vs Json.net sillyness where objects...
[HandBrake.git] / libhb / qsv_filter.c
blob87e10ee284eadd04b735e577857f7bbdfbf55469
1 /* ********************************************************************* *\
3 Copyright (C) 2013 Intel Corporation. All rights reserved.
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.
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.
27 \* ********************************************************************* */
29 #ifdef USE_QSV
31 #include "hb.h"
32 #include "hbffmpeg.h"
33 #include "libavcodec/qsv.h"
34 #include "qsv_filter.h"
36 struct hb_filter_private_s
38 hb_job_t *job;
39 hb_list_t *list;
41 int width_in;
42 int height_in;
43 int pix_fmt;
44 int pix_fmt_out;
45 int width_out;
46 int height_out;
47 int crop[4];
48 int deinterlace;
49 int is_frc_used;
51 // set during init, used to configure input surfaces' "area of interest"
52 mfxU16 CropX;
53 mfxU16 CropY;
54 mfxU16 CropH;
55 mfxU16 CropW;
57 av_qsv_space *vpp_space;
59 // FRC param(s)
60 mfxExtVPPFrameRateConversion frc_config;
63 static int hb_qsv_filter_init( hb_filter_object_t * filter,
64 hb_filter_init_t * init );
66 static int hb_qsv_filter_work( hb_filter_object_t * filter,
67 hb_buffer_t ** buf_in,
68 hb_buffer_t ** buf_out );
70 static int hb_qsv_filter_info( hb_filter_object_t * filter,
71 hb_filter_info_t * info );
73 static void hb_qsv_filter_close( hb_filter_object_t * filter );
75 hb_filter_object_t hb_filter_qsv =
77 .id = HB_FILTER_QSV,
78 .enforce_order = 1,
79 .name = "Quick Sync Video VPP",
80 .settings = NULL,
81 .init = hb_qsv_filter_init,
82 .work = hb_qsv_filter_work,
83 .close = hb_qsv_filter_close,
84 .info = hb_qsv_filter_info,
87 static int filter_init( av_qsv_context* qsv, hb_filter_private_t * pv ){
88 mfxStatus sts;
89 int i=0;
91 if(!qsv) return 3;
94 if(!qsv->vpp_space){
95 qsv->vpp_space = av_qsv_list_init(HAVE_THREADS);
97 if(!pv->vpp_space){
98 for(i=0; i<av_qsv_list_count(qsv->vpp_space);i++){
99 av_qsv_space *qsv_vpp = av_qsv_list_item( qsv->vpp_space, i );
100 if(qsv_vpp->type == AV_QSV_VPP_DEFAULT){
101 pv->vpp_space = qsv_vpp;
102 break;
107 if(!pv->vpp_space){
108 pv->vpp_space = calloc( 1, sizeof( av_qsv_space ));
109 pv->vpp_space->type = AV_QSV_VPP_DEFAULT;
110 av_qsv_list_add( qsv->vpp_space, pv->vpp_space );
112 else
113 if(pv->vpp_space->is_init_done ) return 1;
115 if(!qsv->dec_space || !qsv->dec_space->is_init_done) return 2;
117 // we need to know final output settings before we can properly configure
118 if (!pv->job->qsv.enc_info.is_init_done)
120 return 2;
123 av_qsv_add_context_usage(qsv,HAVE_THREADS);
125 // see params needed like at mediasdk-man.pdf:"Appendix A: Configuration Parameter Constraints"
126 // for now - most will take from the decode
128 av_qsv_space *qsv_vpp = pv->vpp_space;
129 AV_QSV_ZERO_MEMORY(qsv_vpp->m_mfxVideoParam);
131 if (pv->deinterlace)
134 * Input may be progressive, interlaced or even mixed, so init with
135 * MFX_PICSTRUCT_UNKNOWN and use per-frame field order information
136 * (mfxFrameSurface1.Info.PicStruct)
138 qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = MFX_PICSTRUCT_UNKNOWN;
139 qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
141 else
143 /* Same PicStruct in/out: no filtering */
144 qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct;
145 qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct;
148 // FrameRate is important for VPP to start with
149 if( qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN == 0 &&
150 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD == 0 ){
151 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN = pv->job->title->vrate.num;
152 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD = pv->job->title->vrate.den;
156 * In theory, input width/height and decode CropW/CropH should be the
157 * same; however, due to some versions of Libav not applying the H.264
158 * "crop rect" properly, there can be a mismatch.
160 * Since we want the same bahevior regardless of whether we're using
161 * software or hardware-accelerated decoding, prefer the Libav values.
163 * Note that since CropW/CropH may be higher than the decode values, we
164 * need to adjust CropX/CropY to make sure we don't exceed the input's
165 * Width/Height boundaries.
167 pv->CropW = pv-> width_in;
168 pv->CropH = pv->height_in;
169 pv->CropX = FFMIN(qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX,
170 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Width - pv->CropW);
171 pv->CropY = FFMIN(qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY,
172 qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Height - pv->CropH);
173 /* Then, apply additional cropping requested by the user, if any */
174 pv->CropX += pv->crop[2];
175 pv->CropY += pv->crop[0];
176 pv->CropW -= pv->crop[2] + pv->crop[3];
177 pv->CropH -= pv->crop[0] + pv->crop[1];
180 qsv_vpp->m_mfxVideoParam.vpp.In.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC;
181 qsv_vpp->m_mfxVideoParam.vpp.In.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat;
182 qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN = pv->job->vrate.num;
183 qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD = pv->job->vrate.den;
184 qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW;
185 qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH;
186 qsv_vpp->m_mfxVideoParam.vpp.In.Width = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Width;
187 qsv_vpp->m_mfxVideoParam.vpp.In.Height = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Height;
188 qsv_vpp->m_mfxVideoParam.vpp.In.CropX = pv->CropX;
189 qsv_vpp->m_mfxVideoParam.vpp.In.CropY = pv->CropY;
190 qsv_vpp->m_mfxVideoParam.vpp.In.CropW = pv->CropW;
191 qsv_vpp->m_mfxVideoParam.vpp.In.CropH = pv->CropH;
193 qsv_vpp->m_mfxVideoParam.vpp.Out.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC;
194 qsv_vpp->m_mfxVideoParam.vpp.Out.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat;
195 qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN = pv->job->vrate.num;
196 qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD = pv->job->vrate.den;
197 qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW;
198 qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH;
199 qsv_vpp->m_mfxVideoParam.vpp.Out.Width = pv->job->qsv.enc_info.align_width;
200 qsv_vpp->m_mfxVideoParam.vpp.Out.Height = pv->job->qsv.enc_info.align_height;
201 qsv_vpp->m_mfxVideoParam.vpp.Out.CropX = 0; // no letterboxing
202 qsv_vpp->m_mfxVideoParam.vpp.Out.CropY = 0; // no pillarboxing
203 qsv_vpp->m_mfxVideoParam.vpp.Out.CropW = pv-> width_out;
204 qsv_vpp->m_mfxVideoParam.vpp.Out.CropH = pv->height_out;
206 qsv_vpp->m_mfxVideoParam.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
208 qsv_vpp->m_mfxVideoParam.AsyncDepth = pv->job->qsv.async_depth;
210 memset(&qsv_vpp->request, 0, sizeof(mfxFrameAllocRequest)*2);
212 sts = MFXVideoVPP_QueryIOSurf(qsv->mfx_session, &qsv_vpp->m_mfxVideoParam, qsv_vpp->request );
213 AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
215 int num_surfaces_in = qsv_vpp->request[0].NumFrameSuggested;
216 int num_surfaces_out = qsv_vpp->request[1].NumFrameSuggested;
218 av_qsv_config *config = qsv->qsv_config;
221 qsv_vpp->surface_num = FFMIN( num_surfaces_in + num_surfaces_out + qsv_vpp->m_mfxVideoParam.AsyncDepth + config ? config->additional_buffers/2 :0 , AV_QSV_SURFACE_NUM );
222 if(qsv_vpp->surface_num <= 0 )
223 qsv_vpp->surface_num = AV_QSV_SURFACE_NUM;
225 int i = 0;
226 for (i = 0; i < qsv_vpp->surface_num; i++){
227 qsv_vpp->p_surfaces[i] = av_mallocz( sizeof(mfxFrameSurface1) );
228 AV_QSV_CHECK_POINTER(qsv_vpp->p_surfaces[i], MFX_ERR_MEMORY_ALLOC);
229 memcpy(&(qsv_vpp->p_surfaces[i]->Info), &(qsv_vpp->m_mfxVideoParam.vpp.Out), sizeof(mfxFrameInfo));
232 qsv_vpp->sync_num = FFMIN( qsv_vpp->surface_num, AV_QSV_SYNC_NUM );
234 for (i = 0; i < qsv_vpp->sync_num; i++){
235 qsv_vpp->p_syncp[i] = av_mallocz(sizeof(av_qsv_sync));
236 AV_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i], MFX_ERR_MEMORY_ALLOC);
237 qsv_vpp->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint));
238 AV_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i]->p_sync, MFX_ERR_MEMORY_ALLOC);
241 about available VPP filters, see "Table 4 Configurable VPP filters", mediasdk-man.pdf
242 Hints (optional feature) IDs:
243 MFX_EXTBUFF_VPP_DENOISE // Remove noise
244 // Value of 0-100 (inclusive) indicates
245 // the level of noise to remove.
246 MFX_EXTBUFF_VPP_DETAIL // Enhance picture details/edges:
247 // 0-100 value (inclusive) to indicate
248 // the level of details to be enhanced.
249 MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION // Convert input frame rate to match the output, based on frame interpolation:
250 // MFX_FRCALGM_PRESERVE_TIMESTAMP,
251 // MFX_FRCALGM_DISTRIBUTED_TIMESTAMP,
252 // MFX_FRCALGM_FRAME_INTERPOLATION
253 MFX_EXTBUFF_VPP_IMAGE_STABILIZATION // Perform image stabilization
254 // Stabilization modes:
255 // MFX_IMAGESTAB_MODE_UPSCALE
256 // MFX_IMAGESTAB_MODE_BOXING
257 MFX_EXTBUFF_VPP_PICSTRUCT_DETECTION // Perform detection of picture structure:
258 // Detected picture structure - top field first, bottom field first, progressive or unknown
259 // if video processor cannot detect picture structure.
260 MFX_EXTBUFF_VPP_PROCAMP // Adjust the brightness, contrast, saturation, and hue settings
262 // Initialize extended buffer for frame processing
263 // - Process amplifier (ProcAmp) used to control brightness
264 // - mfxExtVPPDoUse: Define the processing algorithm to be used
265 // - mfxExtVPPProcAmp: ProcAmp configuration
266 // - mfxExtBuffer: Add extended buffers to VPP parameter configuration
267 mfxExtVPPDoUse extDoUse;
268 mfxU32 tabDoUseAlg[1];
269 extDoUse.Header.BufferId = MFX_EXTBUFF_VPP_DOUSE;
270 extDoUse.Header.BufferSz = sizeof(mfxExtVPPDoUse);
271 extDoUse.NumAlg = 1;
272 extDoUse.AlgList = tabDoUseAlg;
273 tabDoUseAlg[0] = MFX_EXTBUFF_VPP_PROCAMP;
275 mfxExtVPPProcAmp procampConfig;
276 procampConfig.Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP;
277 procampConfig.Header.BufferSz = sizeof(mfxExtVPPProcAmp);
278 procampConfig.Hue = 0.0f; // Default
279 procampConfig.Saturation = 1.0f; // Default
280 procampConfig.Contrast = 1.0; // Default
281 procampConfig.Brightness = 40.0; // Adjust brightness
283 mfxExtBuffer* ExtBuffer[2];
284 ExtBuffer[0] = (mfxExtBuffer*)&extDoUse;
285 ExtBuffer[1] = (mfxExtBuffer*)&procampConfig;
286 VPPParams.NumExtParam = 2;
287 VPPParams.ExtParam = (mfxExtBuffer**)&ExtBuffer[0];
289 memset(&qsv_vpp->ext_opaque_alloc, 0, sizeof(qsv_vpp->ext_opaque_alloc));
291 if( (qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN / qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD ) !=
292 (qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN / qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD) )
294 pv->is_frc_used = 1;
297 qsv_vpp->m_mfxVideoParam.NumExtParam = qsv_vpp->p_ext_param_num = 1 + pv->is_frc_used;
299 qsv_vpp->p_ext_params = av_mallocz(sizeof(mfxExtBuffer *)*qsv_vpp->p_ext_param_num);
300 AV_QSV_CHECK_POINTER(qsv_vpp->p_ext_params, MFX_ERR_MEMORY_ALLOC);
302 qsv_vpp->m_mfxVideoParam.ExtParam = qsv_vpp->p_ext_params;
304 qsv_vpp->ext_opaque_alloc.In.Surfaces = qsv->dec_space->p_surfaces;
305 qsv_vpp->ext_opaque_alloc.In.NumSurface = qsv->dec_space->surface_num;
306 qsv_vpp->ext_opaque_alloc.In.Type = qsv->dec_space->request[0].Type;
308 qsv_vpp->ext_opaque_alloc.Out.Surfaces = qsv_vpp->p_surfaces;
309 qsv_vpp->ext_opaque_alloc.Out.NumSurface = qsv_vpp->surface_num;
310 qsv_vpp->ext_opaque_alloc.Out.Type = qsv->dec_space->request[0].Type;
312 qsv_vpp->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
313 qsv_vpp->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc);
314 qsv_vpp->p_ext_params[0] = (mfxExtBuffer*)&qsv_vpp->ext_opaque_alloc;
316 if(pv->is_frc_used)
318 pv->frc_config.Header.BufferId = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION;
319 pv->frc_config.Header.BufferSz = sizeof(mfxExtVPPFrameRateConversion);
320 pv->frc_config.Algorithm = MFX_FRCALGM_PRESERVE_TIMESTAMP;
322 qsv_vpp->p_ext_params[1] = (mfxExtBuffer*)&pv->frc_config;
325 sts = MFXVideoVPP_Init(qsv->mfx_session, &qsv_vpp->m_mfxVideoParam);
327 AV_QSV_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION);
328 AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
330 qsv_vpp->is_init_done = 1;
332 return 0;
335 static int hb_qsv_filter_init( hb_filter_object_t * filter,
336 hb_filter_init_t * init )
339 filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) );
340 hb_filter_private_t * pv = filter->private_data;
342 pv->list = hb_list_init();
343 // list of init params provided at work.c:~700
344 pv->width_in = init->geometry.width;
345 pv->height_in = init->geometry.height;
346 pv->width_out = init->geometry.width;
347 pv->height_out = init->geometry.height;
348 memcpy( pv->crop, init->crop, sizeof( int[4] ) );
350 if (filter->settings != NULL)
352 sscanf(filter->settings, "%d:%d:%d:%d:%d:%d_dei:%d",
353 &pv->width_out, &pv->height_out,
354 &pv->crop[0], &pv->crop[1], &pv->crop[2], &pv->crop[3],
355 &pv->deinterlace);
358 pv->job = init->job;
360 // will be later as more params will be known
361 // filter_init(pv->job->qsv, pv);
363 // framerate shaping not yet supported
364 init->cfr = 0;
366 init->pix_fmt = pv->pix_fmt;
367 init->geometry.width = pv->width_out;
368 init->geometry.height = pv->height_out;
369 memcpy( init->crop, pv->crop, sizeof( int[4] ) );
371 return 0;
374 static int hb_qsv_filter_info( hb_filter_object_t * filter,
375 hb_filter_info_t * info )
378 hb_filter_private_t *pv = filter->private_data;
379 if (pv == NULL)
380 return -1;
382 sprintf(info->human_readable_desc,
383 "source: %d * %d, crop (%d/%d/%d/%d): %d * %d, scale: %d * %d",
384 pv->width_in, pv->height_in,
385 pv->crop[0], pv->crop[1], pv->crop[2], pv->crop[3],
386 pv->width_in - pv->crop[2] - pv->crop[3],
387 pv->height_in - pv->crop[0] - pv->crop[1],
388 pv->width_out, pv->height_out);
390 if (pv->deinterlace)
392 sprintf(info->human_readable_desc + strlen(info->human_readable_desc),
393 ", deinterlace");
396 return 0;
399 void qsv_filter_close( av_qsv_context* qsv, AV_QSV_STAGE_TYPE vpp_type ){
400 int i = 0;
401 av_qsv_space* vpp_space = 0;
403 if(qsv && qsv->is_context_active && qsv->vpp_space)
404 for(i=av_qsv_list_count( qsv->vpp_space);i>0;i--){
406 vpp_space = av_qsv_list_item( qsv->vpp_space, i-1 );
407 if( vpp_space->type == vpp_type && vpp_space->is_init_done){
409 hb_log( "qsv_filter[%s] done: max_surfaces: %u/%u , max_syncs: %u/%u", ((vpp_type == AV_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 );
411 for (i = 0; i < vpp_space->surface_num; i++){
412 av_freep(&vpp_space->p_surfaces[i]);
414 vpp_space->surface_num = 0;
416 if( vpp_space->p_ext_param_num || vpp_space->p_ext_params )
417 av_freep(&vpp_space->p_ext_params);
418 vpp_space->p_ext_param_num = 0;
420 for (i = 0; i < vpp_space->sync_num; i++){
421 av_freep(&vpp_space->p_syncp[i]->p_sync);
422 av_freep(&vpp_space->p_syncp[i]);
424 vpp_space->sync_num = 0;
426 av_qsv_list_rem(qsv->vpp_space,vpp_space);
427 if( av_qsv_list_count(qsv->vpp_space) == 0 )
428 av_qsv_list_close(&qsv->vpp_space);
430 vpp_space->is_init_done = 0;
431 break;
436 static void hb_qsv_filter_close( hb_filter_object_t * filter )
438 hb_filter_private_t * pv = filter->private_data;
440 if ( !pv )
442 return;
445 av_qsv_context* qsv = pv->job->qsv.ctx;
446 if(qsv && qsv->vpp_space && av_qsv_list_count(qsv->vpp_space) > 0){
448 // closing local stuff
449 qsv_filter_close(qsv,AV_QSV_VPP_DEFAULT);
451 // closing the commong stuff
452 av_qsv_context_clean(qsv);
454 hb_list_close(&pv->list);
455 free( pv );
456 filter->private_data = NULL;
459 int process_frame(av_qsv_list* received_item, av_qsv_context* qsv, hb_filter_private_t * pv ){
461 // 1 if have results , 0 - otherwise
462 int ret = 1;
464 mfxStatus sts = MFX_ERR_NONE;
465 mfxFrameSurface1 *work_surface = NULL;
466 av_qsv_stage* stage = 0;
468 av_qsv_space *qsv_vpp = pv->vpp_space;
470 if(received_item){
471 stage = av_qsv_get_last_stage( received_item );
472 work_surface = stage->out.p_surface;
475 int sync_idx = av_qsv_get_free_sync(qsv_vpp, qsv);
476 int surface_idx = -1;
478 for(;;)
480 if (sync_idx == -1)
482 hb_error("qsv: Not enough resources allocated for QSV filter");
483 ret = 0;
484 break;
486 if( sts == MFX_ERR_MORE_SURFACE || sts == MFX_ERR_NONE )
487 surface_idx = av_qsv_get_free_surface(qsv_vpp, qsv, &(qsv_vpp->m_mfxVideoParam.vpp.Out), QSV_PART_ANY);
488 if (surface_idx == -1) {
489 hb_error("qsv: Not enough resources allocated for QSV filter");
490 ret = 0;
491 break;
493 if (work_surface != NULL)
495 work_surface->Info.CropX = pv->CropX;
496 work_surface->Info.CropY = pv->CropY;
497 work_surface->Info.CropW = pv->CropW;
498 work_surface->Info.CropH = pv->CropH;
501 sts = MFXVideoVPP_RunFrameVPPAsync(qsv->mfx_session, work_surface, qsv_vpp->p_surfaces[surface_idx] , NULL, qsv_vpp->p_syncp[sync_idx]->p_sync);
503 if( MFX_ERR_MORE_DATA == sts ){
504 if(!qsv_vpp->pending){
505 qsv_vpp->pending = av_qsv_list_init(0);
508 // if we have no results, we should not miss resource(s)
509 av_qsv_list_add( qsv_vpp->pending, received_item);
511 ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use);
513 ret = 0;
514 break;
517 if( MFX_ERR_MORE_DATA == sts || (MFX_ERR_NONE <= sts && MFX_WRN_DEVICE_BUSY != sts)){
518 if (work_surface){
519 ff_qsv_atomic_dec(&work_surface->Data.Locked);
523 if( MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE <= sts){
524 if( MFX_ERR_MORE_SURFACE == sts )
525 continue;
527 if (qsv_vpp->p_surfaces[surface_idx] && MFX_WRN_DEVICE_BUSY != sts )
528 ff_qsv_atomic_inc(&qsv_vpp->p_surfaces[surface_idx]->Data.Locked);
531 AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
533 if (MFX_ERR_NONE <= sts ) // repeat the call if warning and no output
535 if (MFX_WRN_DEVICE_BUSY == sts){
536 av_qsv_sleep(10); // wait if device is busy
537 continue;
540 // shouldnt be a case but drain
541 if(stage){
542 av_qsv_stage* new_stage = av_qsv_stage_init();
544 new_stage->type = AV_QSV_VPP_DEFAULT;
545 new_stage->in.p_surface = work_surface;
546 new_stage->out.p_surface = qsv_vpp->p_surfaces[surface_idx];
547 new_stage->out.sync = qsv_vpp->p_syncp[sync_idx];
548 av_qsv_add_stagee( &received_item, new_stage,HAVE_THREADS );
550 // add pending resources for the proper reclaim later
551 if( qsv_vpp->pending ){
552 if( av_qsv_list_count(qsv_vpp->pending)>0 ){
553 new_stage->pending = qsv_vpp->pending;
555 qsv_vpp->pending = 0;
557 // making free via decrement for all pending
558 int i = 0;
559 for (i = av_qsv_list_count(new_stage->pending); i > 0; i--){
560 av_qsv_list *atom_list = av_qsv_list_item(new_stage->pending, i-1);
561 av_qsv_stage *stage = av_qsv_get_last_stage( atom_list );
562 mfxFrameSurface1 *work_surface = stage->out.p_surface;
563 if (work_surface)
564 ff_qsv_atomic_dec(&work_surface->Data.Locked);
568 break;
571 ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use);
573 if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)
574 HB_DEBUG_ASSERT(1, "The bitstream buffer size is insufficient.");
576 break;
579 return ret;
582 static int hb_qsv_filter_work( hb_filter_object_t * filter,
583 hb_buffer_t ** buf_in,
584 hb_buffer_t ** buf_out )
587 hb_filter_private_t * pv = filter->private_data;
588 hb_buffer_t * in = *buf_in;
589 hb_buffer_t * out = *buf_out;
590 int sts = 0;
592 av_qsv_context* qsv = pv->job->qsv.ctx;
594 if ( !pv )
596 *buf_out = in;
597 *buf_in = NULL;
598 return HB_FILTER_OK;
601 while(1){
602 int ret = filter_init(qsv,pv);
603 if(ret >= 2)
604 av_qsv_sleep(1);
605 else
606 break;
609 *buf_in = NULL;
611 if (in->s.flags & HB_BUF_FLAG_EOF)
613 while(1){
614 sts = process_frame(in->qsv_details.qsv_atom, qsv, pv);
615 if(sts)
616 hb_list_add(pv->list,in);
617 else
618 break;
621 hb_list_add( pv->list, in );
622 *buf_out = link_buf_list( pv );
623 return HB_FILTER_DONE;
626 sts = process_frame(in->qsv_details.qsv_atom, qsv, pv);
628 if(sts){
629 hb_list_add(pv->list,in);
632 if( hb_list_count(pv->list) ){
633 *buf_out = hb_list_item(pv->list,0);
634 out = *buf_out;
635 if(pv->is_frc_used && out)
637 if(out->qsv_details.qsv_atom){
638 av_qsv_stage* stage = av_qsv_get_last_stage( out->qsv_details.qsv_atom );
639 mfxFrameSurface1 *work_surface = stage->out.p_surface;
641 av_qsv_wait_on_sync( qsv,stage );
643 av_qsv_space *qsv_vpp = pv->vpp_space;
644 int64_t duration = ((double)qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD/(double)qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN ) * 90000.;
645 out->s.start = work_surface->Data.TimeStamp;
646 out->s.stop = work_surface->Data.TimeStamp + duration;
649 hb_list_rem(pv->list,*buf_out);
651 else
652 *buf_out = NULL;
654 return HB_FILTER_OK;
657 // see devavcode.c
658 hb_buffer_t *link_buf_list( hb_filter_private_t *pv )
660 hb_buffer_t *head = hb_list_item( pv->list, 0 );
662 if ( head )
664 hb_list_rem( pv->list, head );
665 hb_buffer_t *last = head, *buf;
666 while ( ( buf = hb_list_item( pv->list, 0 ) ) != NULL )
668 hb_list_rem( pv->list, buf );
669 last->next = buf;
670 last = buf;
673 return head;
676 #endif // USE_QSV