1 // Copyright (c) 2017-2020 Intel Corporation
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 #include "mfx_common.h"
22 
23 #if defined (MFX_ENABLE_VPP)
24 #if defined (MFX_VA_LINUX)
25 
26 #include "mfx_session.h"
27 #include <math.h>
28 #include "mfx_vpp_defs.h"
29 #include "mfx_vpp_vaapi.h"
30 #include "mfx_utils.h"
31 #include "libmfx_core_vaapi.h"
32 #include <algorithm>
33 
34 template<typename T>
SetPlaneROI(T value,T * pDst,int dstStep,mfxSize roiSize)35 bool SetPlaneROI(T value, T* pDst, int dstStep, mfxSize roiSize)
36 {
37     if (!pDst || roiSize.width < 0 || roiSize.height < 0)
38         return false;
39 
40     for(int h = 0; h < roiSize.height; h++ ) {
41         std::fill(pDst, pDst + roiSize.width, value);
42         pDst = (T *)((unsigned char*)pDst + dstStep);
43     }
44 
45     return true;
46 }
47 
48 
49 enum QueryStatus
50 {
51     VPREP_GPU_READY         =   0,
52     VPREP_GPU_BUSY          =   1,
53     VPREP_GPU_NOT_REACHED   =   2,
54     VPREP_GPU_FAILED        =   3
55 };
56 
57 //////////////////////////////////////////////////////////////////////////
58 using namespace MfxHwVideoProcessing;
59 
convertValue(const float OldMin,const float OldMax,const float NewMin,const float NewMax,const float OldValue)60 static float convertValue(const float OldMin,const float OldMax,const float NewMin,const float NewMax,const float OldValue)
61 {
62     if((0 == NewMin) && (0 == NewMax)) return OldValue; //workaround
63     float oldRange = OldMax - OldMin;
64     float newRange = NewMax - NewMin;
65     return (((OldValue - OldMin) * newRange) / oldRange) + NewMin;
66 }
67 
68 #define DEFAULT_HUE 0
69 #define DEFAULT_SATURATION 1
70 #define DEFAULT_CONTRAST 1
71 #define DEFAULT_BRIGHTNESS 0
72 
73 
74 #define VA_TOP_FIELD_WEAVE        0x00000004
75 #define VA_BOTTOM_FIELD_WEAVE     0x00000008
76 
77 #define VPP_COMP_BACKGROUND_SURFACE_WIDTH  320
78 #define VPP_COMP_BACKGROUND_SURFACE_HEIGHT 256
79 
VAAPIVideoProcessing()80 VAAPIVideoProcessing::VAAPIVideoProcessing():
81   m_bRunning(false)
82 , m_core(NULL)
83 , m_vaDisplay(0)
84 , m_vaConfig(VA_INVALID_ID)
85 , m_vaContextVPP(VA_INVALID_ID)
86 , m_denoiseFilterID(VA_INVALID_ID)
87 , m_detailFilterID(VA_INVALID_ID)
88 , m_deintFilterID(VA_INVALID_ID)
89 , m_procampFilterID(VA_INVALID_ID)
90 , m_frcFilterID(VA_INVALID_ID)
91 , m_gpuPriorityID(VA_INVALID_ID)
92 , m_deintFrameCount(0)
93 #ifdef MFX_ENABLE_VPP_FRC
94 , m_frcCyclicCounter(0)
95 #endif
96 , m_numFilterBufs(0)
97 , m_MaxContextPriority(0)
98 , m_primarySurface4Composition(NULL)
99 {
100 
101     for(int i = 0; i < VAProcFilterCount; i++)
102         m_filterBufs[i] = VA_INVALID_ID;
103 
104     memset( (void*)&m_pipelineCaps, 0, sizeof(m_pipelineCaps));
105     memset( (void*)&m_denoiseCaps, 0, sizeof(m_denoiseCaps));
106     memset( (void*)&m_detailCaps, 0, sizeof(m_detailCaps));
107     memset( (void*)&m_deinterlacingCaps, 0, sizeof(m_deinterlacingCaps));
108 #ifdef MFX_ENABLE_VPP_FRC
109     memset( (void*)&m_frcCaps, 0, sizeof(m_frcCaps));
110 #endif
111     memset( (void*)&m_procampCaps, 0, sizeof(m_procampCaps));
112 
113     m_cachedReadyTaskIndex.clear();
114     m_feedbackCache.clear();
115 
116 } // VAAPIVideoProcessing::VAAPIVideoProcessing()
117 
118 
~VAAPIVideoProcessing()119 VAAPIVideoProcessing::~VAAPIVideoProcessing()
120 {
121     Close();
122 
123 } // VAAPIVideoProcessing::~VAAPIVideoProcessing()
124 
CreateDevice(VideoCORE * core,mfxVideoParam * pParams,bool)125 mfxStatus VAAPIVideoProcessing::CreateDevice(VideoCORE * core, mfxVideoParam* pParams, bool /*isTemporal*/)
126 {
127     MFX_CHECK_NULL_PTR1( core );
128 
129     VAAPIVideoCORE* hwCore = dynamic_cast<VAAPIVideoCORE*>(core);
130 
131     MFX_CHECK_NULL_PTR1( hwCore );
132 
133     mfxStatus sts = hwCore->GetVAService( &m_vaDisplay);
134     MFX_CHECK_STS( sts );
135 
136     sts = Init( &m_vaDisplay, pParams);
137 
138     MFX_CHECK_STS(sts);
139 
140     m_cachedReadyTaskIndex.clear();
141 
142     m_core = core;
143 
144     return MFX_ERR_NONE;
145 
146 } // mfxStatus VAAPIVideoProcessing::CreateDevice(VideoCORE * core, mfxInitParams* pParams)
147 
148 
DestroyDevice(void)149 mfxStatus VAAPIVideoProcessing::DestroyDevice(void)
150 {
151     mfxStatus sts = Close();
152 
153     return sts;
154 
155 } // mfxStatus VAAPIVideoProcessing::DestroyDevice(void)
156 
157 
Close(void)158 mfxStatus VAAPIVideoProcessing::Close(void)
159 {
160     VAStatus vaSts;
161     if (m_primarySurface4Composition != NULL)
162     {
163         vaSts = vaDestroySurfaces(m_vaDisplay,m_primarySurface4Composition,1);
164         std::ignore = MFX_STS_TRACE(vaSts);
165 
166         free(m_primarySurface4Composition);
167         m_primarySurface4Composition = NULL;
168     }
169 
170     mfxStatus sts = CheckAndDestroyVAbuffer(m_vaDisplay, m_denoiseFilterID);
171     std::ignore = MFX_STS_TRACE(sts);
172 
173     sts = CheckAndDestroyVAbuffer(m_vaDisplay, m_detailFilterID);
174     std::ignore = MFX_STS_TRACE(sts);
175 
176     sts = CheckAndDestroyVAbuffer(m_vaDisplay, m_procampFilterID);
177     std::ignore = MFX_STS_TRACE(sts);
178 
179     sts = CheckAndDestroyVAbuffer(m_vaDisplay, m_deintFilterID);
180     std::ignore = MFX_STS_TRACE(sts);
181 
182     sts = CheckAndDestroyVAbuffer(m_vaDisplay, m_frcFilterID);
183     std::ignore = MFX_STS_TRACE(sts);
184 
185     if (m_vaContextVPP != VA_INVALID_ID)
186     {
187         MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaDestroyContext");
188         vaSts = vaDestroyContext( m_vaDisplay, m_vaContextVPP );
189         std::ignore = MFX_STS_TRACE(vaSts);
190 
191         m_vaContextVPP = VA_INVALID_ID;
192     }
193 
194     if (m_vaConfig != VA_INVALID_ID)
195     {
196         vaSts = vaDestroyConfig( m_vaDisplay, m_vaConfig );
197         std::ignore = MFX_STS_TRACE(vaSts);
198 
199         m_vaConfig = VA_INVALID_ID;
200     }
201 
202     for(int i = 0; i < VAProcFilterCount; i++)
203         m_filterBufs[i] = VA_INVALID_ID;
204 
205     m_denoiseFilterID   = VA_INVALID_ID;
206     m_deintFilterID     = VA_INVALID_ID;
207     m_procampFilterID   = VA_INVALID_ID;
208 
209     memset( (void*)&m_pipelineCaps, 0, sizeof(m_pipelineCaps));
210     memset( (void*)&m_denoiseCaps, 0, sizeof(m_denoiseCaps));
211     memset( (void*)&m_detailCaps, 0, sizeof(m_detailCaps));
212     memset( (void*)&m_procampCaps,  0, sizeof(m_procampCaps));
213     memset( (void*)&m_deinterlacingCaps, 0, sizeof(m_deinterlacingCaps));
214 
215     return MFX_ERR_NONE;
216 
217 } // mfxStatus VAAPIVideoProcessing::Close(void)
218 
Init(_mfxPlatformAccelerationService * pVADisplay,mfxVideoParam * pParams)219 mfxStatus VAAPIVideoProcessing::Init(_mfxPlatformAccelerationService* pVADisplay, mfxVideoParam* pParams)
220 {
221     if(false == m_bRunning)
222     {
223         MFX_CHECK_NULL_PTR1( pVADisplay );
224         MFX_CHECK_NULL_PTR1( pParams );
225 
226         m_cachedReadyTaskIndex.clear();
227 
228         VAEntrypoint* va_entrypoints = NULL;
229         VAStatus vaSts;
230         int va_max_num_entrypoints   = vaMaxNumEntrypoints(m_vaDisplay);
231         if(va_max_num_entrypoints)
232             va_entrypoints = new VAEntrypoint[va_max_num_entrypoints];
233         else
234             return MFX_ERR_DEVICE_FAILED;
235 
236         mfxI32 entrypointsCount = 0, entrypointsIndx = 0;
237 
238         vaSts = vaQueryConfigEntrypoints(m_vaDisplay,
239                                             VAProfileNone,
240                                             va_entrypoints,
241                                             &entrypointsCount);
242         MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
243 
244         for( entrypointsIndx = 0; entrypointsIndx < entrypointsCount; entrypointsIndx++ )
245         {
246             if( VAEntrypointVideoProc == va_entrypoints[entrypointsIndx] )
247             {
248                 m_bRunning = true;
249                 break;
250             }
251         }
252         delete[] va_entrypoints;
253 
254         if( !m_bRunning )
255         {
256             return MFX_ERR_DEVICE_FAILED;
257         }
258 
259         vaSts = vaCreateConfig( m_vaDisplay,
260                                 VAProfileNone,
261                                 VAEntrypointVideoProc,
262                                 NULL,
263                                 0,
264                                 &m_vaConfig);
265         MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
266 
267         // Context
268         int width = pParams->vpp.Out.Width;
269         int height = pParams->vpp.Out.Height;
270 
271         {
272             MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaCreateContext");
273             vaSts = vaCreateContext(m_vaDisplay,
274                                     m_vaConfig,
275                                     width,
276                                     height,
277                                     VA_PROGRESSIVE,
278                                     0, 0,
279                                     &m_vaContextVPP);
280         }
281         MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
282     }
283 
284     return MFX_ERR_NONE;
285 
286 } // mfxStatus VAAPIVideoProcessing::Init(_mfxPlatformAccelerationService* pVADisplay, mfxVideoParam* pParams)
287 
288 
Register(mfxHDLPair *,mfxU32,BOOL)289 mfxStatus VAAPIVideoProcessing::Register(
290     mfxHDLPair* /*pSurfaces*/,
291     mfxU32 /*num*/,
292     BOOL /*bRegister*/)
293 {
294     return MFX_ERR_NONE;
295 } // mfxStatus VAAPIVideoProcessing::Register(_mfxPlatformVideoSurface *pSurfaces, ...)
296 
297 
QueryCapabilities(mfxVppCaps & caps)298 mfxStatus VAAPIVideoProcessing::QueryCapabilities(mfxVppCaps& caps)
299 {
300     VAStatus vaSts;
301 
302     VAProcFilterType filters[VAProcFilterCount];
303     mfxU32 num_filters = VAProcFilterCount;
304 
305     vaSts = vaQueryVideoProcFilters(m_vaDisplay, m_vaContextVPP, filters, &num_filters);
306     MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
307 
308     mfxU32 num_procamp_caps = VAProcColorBalanceCount;
309     vaSts = vaQueryVideoProcFilterCaps(m_vaDisplay,
310                                m_vaContextVPP,
311                                VAProcFilterColorBalance,
312                                &m_procampCaps, &num_procamp_caps);
313     MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
314 
315     mfxU32 num_denoise_caps = 1;
316     vaSts = vaQueryVideoProcFilterCaps(m_vaDisplay,
317                                m_vaContextVPP,
318                                VAProcFilterNoiseReduction,
319                                &m_denoiseCaps, &num_denoise_caps);
320     MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
321 
322     mfxU32 num_detail_caps = 1;
323     vaSts = vaQueryVideoProcFilterCaps(m_vaDisplay,
324                                m_vaContextVPP,
325                                VAProcFilterSharpening,
326                                &m_detailCaps, &num_detail_caps);
327     MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
328 
329     mfxU32 num_deinterlacing_caps = VAProcDeinterlacingCount;
330     vaSts = vaQueryVideoProcFilterCaps(m_vaDisplay,
331                                m_vaContextVPP,
332                                VAProcFilterDeinterlacing,
333                                &m_deinterlacingCaps, &num_deinterlacing_caps);
334     MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
335 
336 #ifdef MFX_ENABLE_VPP_FRC
337     /* to check is FRC enabled or not*/
338     /* first need to get number of modes supported by driver*/
339     VAProcFilterCapFrameRateConversion tempFRC_Caps;
340     mfxU32 num_frc_caps = 1;
341 
342     tempFRC_Caps.bget_custom_rates = 1;
343     vaSts = vaQueryVideoProcFilterCaps(m_vaDisplay,
344                                m_vaContextVPP,
345                                VAProcFilterFrameRateConversion,
346                                &tempFRC_Caps, &num_frc_caps);
347     MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
348 
349     if (0 != tempFRC_Caps.frc_custom_rates) /* FRC is enabled, at least one mode */
350     {
351         caps.uFrameRateConversion = 1 ;
352         /* Again, only two modes: 24p->60p and 30p->60p is available
353          * But driver report 3, but 3rd is equal to 2rd,
354          * So only 2 real modes*/
355         if (tempFRC_Caps.frc_custom_rates > 2)
356             tempFRC_Caps.frc_custom_rates = 2;
357         caps.frcCaps.customRateData.resize(tempFRC_Caps.frc_custom_rates);
358         /*to get details about each mode */
359         tempFRC_Caps.bget_custom_rates = 0;
360 
361         for (mfxU32 ii = 0; ii < tempFRC_Caps.frc_custom_rates; ii++)
362         {
363             m_frcCaps[ii].frc_custom_rates = ii + 1;
364             vaSts = vaQueryVideoProcFilterCaps(m_vaDisplay,
365                                                 m_vaContextVPP,
366                                                 VAProcFilterFrameRateConversion,
367                                                 &m_frcCaps[ii], &num_frc_caps);
368             MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
369             caps.frcCaps.customRateData[ii].inputFramesOrFieldPerCycle = m_frcCaps[ii].input_frames;
370             caps.frcCaps.customRateData[ii].outputIndexCountPerCycle = m_frcCaps[ii].output_frames;
371             /* out frame rate*/
372             caps.frcCaps.customRateData[ii].customRate.FrameRateExtN = m_frcCaps[ii].output_fps;
373             /*input frame rate */
374             caps.frcCaps.customRateData[ii].customRate.FrameRateExtD = m_frcCaps[ii].input_fps;
375         }
376     }
377 #endif // #ifdef MFX_ENABLE_VPP_FRC
378 
379     for( mfxU32 filtersIndx = 0; filtersIndx < num_filters; filtersIndx++ )
380     {
381         if (filters[filtersIndx])
382         {
383             switch (filters[filtersIndx])
384             {
385                 case VAProcFilterNoiseReduction:
386                     caps.uDenoiseFilter = 1;
387                     break;
388                 case VAProcFilterSharpening:
389                     caps.uDetailFilter = 1;
390                     break;
391                 case VAProcFilterDeinterlacing:
392                     for (mfxU32 i = 0; i < num_deinterlacing_caps; i++)
393                     {
394                         if (VAProcDeinterlacingBob == m_deinterlacingCaps[i].type)
395                             caps.uSimpleDI = 1;
396                         if (VAProcDeinterlacingWeave == m_deinterlacingCaps[i].type           ||
397                             VAProcDeinterlacingMotionAdaptive == m_deinterlacingCaps[i].type  ||
398                             VAProcDeinterlacingMotionCompensated == m_deinterlacingCaps[i].type)
399                             caps.uAdvancedDI = 1;
400                     }
401                     break;
402                 case VAProcFilterColorBalance:
403                     caps.uProcampFilter = 1;
404                     break;
405                default:
406                     break;
407             }
408         }
409     }
410 
411     memset(&m_pipelineCaps,  0, sizeof(VAProcPipelineCaps));
412     vaSts = vaQueryVideoProcPipelineCaps(m_vaDisplay,
413                                  m_vaContextVPP,
414                                  NULL,
415                                  0,
416                                  &m_pipelineCaps);
417 #ifdef MFX_ENABLE_VPP_ROTATION
418     MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
419     if (m_pipelineCaps.rotation_flags & (1 << VA_ROTATION_90 ) &&
420         m_pipelineCaps.rotation_flags & (1 << VA_ROTATION_180) &&
421         m_pipelineCaps.rotation_flags & (1 << VA_ROTATION_270))
422     {
423         caps.uRotation = 1;
424     }
425 #endif
426 
427     if ((m_pipelineCaps.mirror_flags & VA_MIRROR_HORIZONTAL) &&
428         (m_pipelineCaps.mirror_flags & VA_MIRROR_VERTICAL))
429     {
430         caps.uMirroring = 1;
431     }
432 
433     if (m_pipelineCaps.max_output_width && m_pipelineCaps.max_output_height)
434     {
435         caps.uMaxWidth = m_pipelineCaps.max_output_width;
436         caps.uMaxHeight = m_pipelineCaps.max_output_height;
437     }
438     else
439     {
440         caps.uMaxWidth = 4096;
441         caps.uMaxHeight = 4096;
442     }
443 
444     caps.uFieldWeavingControl = 1;
445 
446     // [FourCC]
447     // should be changed by libva support
448     for (auto fourcc : g_TABLE_SUPPORTED_FOURCC)
449     {
450         // Mark supported input
451         switch(fourcc)
452         {
453         case MFX_FOURCC_NV12:
454         case MFX_FOURCC_YV12:
455         case MFX_FOURCC_YUY2:
456         case MFX_FOURCC_UYVY:
457         case MFX_FOURCC_RGB4:
458 #if defined (MFX_ENABLE_FOURCC_RGB565)
459         case MFX_FOURCC_RGB565:
460 #endif
461 #ifdef MFX_ENABLE_RGBP
462     case MFX_FOURCC_RGBP:
463 #endif
464 #if (MFX_VERSION >= 1027)
465         case MFX_FOURCC_AYUV:
466         case MFX_FOURCC_Y210:
467         case MFX_FOURCC_Y410:
468 #endif
469 #if (MFX_VERSION >= 1031)
470         case MFX_FOURCC_P016:
471         case MFX_FOURCC_Y216:
472         case MFX_FOURCC_Y416:
473 #endif
474         case MFX_FOURCC_P010:
475         // A2RGB10 supported as input in case of passthru copy
476         case MFX_FOURCC_A2RGB10:
477             caps.mFormatSupport[fourcc] |= MFX_FORMAT_SUPPORT_INPUT;
478             break;
479         default:
480             break;
481         }
482 
483         // Mark supported output
484         switch(fourcc)
485         {
486         case MFX_FOURCC_NV12:
487         case MFX_FOURCC_YV12:
488         case MFX_FOURCC_YUY2:
489         case MFX_FOURCC_RGB4:
490         case MFX_FOURCC_UYVY:
491 #if (MFX_VERSION >= 1027)
492         case MFX_FOURCC_AYUV:
493         case MFX_FOURCC_Y210:
494         case MFX_FOURCC_Y410:
495 #endif
496 #ifdef MFX_ENABLE_RGBP
497         case MFX_FOURCC_RGBP:
498 #endif
499 #if (MFX_VERSION >= 1031)
500         case MFX_FOURCC_P016:
501         case MFX_FOURCC_Y216:
502         case MFX_FOURCC_Y416:
503 #endif
504         case MFX_FOURCC_P010:
505         case MFX_FOURCC_A2RGB10:
506             caps.mFormatSupport[fourcc] |= MFX_FORMAT_SUPPORT_OUTPUT;
507             break;
508         default:
509             break;
510         }
511     }
512 
513     caps.uScaling = 1;
514 
515     eMFXPlatform platform = m_core->GetPlatformType();
516     if (platform == MFX_PLATFORM_HARDWARE)
517     {
518         caps.uChromaSiting = m_core->GetHWType() >= MFX_HW_SCL ? 1 : 0;
519     }
520 
521     std::vector<VAConfigAttrib> attrib(1);
522     attrib[0].type = VAConfigAttribContextPriority;
523     vaSts = vaGetConfigAttributes(m_vaDisplay,
524                                   VAProfileNone,
525                                   VAEntrypointVideoProc,
526                                   attrib.data(),
527                                   attrib.size());
528     MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
529     if (attrib[0].value != VA_ATTRIB_NOT_SUPPORTED)
530         m_MaxContextPriority = attrib[0].value;
531 
532     return MFX_ERR_NONE;
533 
534 } // mfxStatus VAAPIVideoProcessing::QueryCapabilities(mfxVppCaps& caps)
535 
536 /// Setup VPP VAAPI driver parameters
537 /*!
538  Setup VPP surfaces and VPP VAAPI parameters.
539 
540  \param[in] pParams
541  structure with VPP parameters and associated input and reference surfaces.
542  \param[out] deint
543  VAProcFilterParameterBufferDeinterlacing structure containing deinterlace information (scene change, which field to display).
544  \param[out] m_pipelineParam
545  VAProcPipelineParameterBuffer structure containing input and reference frames.
546 
547  return mfxStatus
548  MFX_ERR_NONE id successful
549  */
Execute(mfxExecuteParams * pParams)550 mfxStatus VAAPIVideoProcessing::Execute(mfxExecuteParams *pParams)
551 {
552     MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_HOTSPOTS, "VAAPIVideoProcessing::Execute");
553 
554     bool bIsFirstField = true;
555     bool bUseReference = false;
556     VAStatus vaSts = VA_STATUS_SUCCESS;
557 
558     VAAPIVideoCORE* hwCore = dynamic_cast<VAAPIVideoCORE*>(m_core);
559     eMFXHWType hwType = hwCore->GetHWType();
560 
561     // NOTE the following variables should be visible till vaRenderPicture/vaEndPicture,
562     // not till vaCreateBuffer as the data they hold are passed to the driver via a pointer
563     // to the memory and driver simply copies the pointer till further dereference in the
564     // functions noted above. Thus, safer to simply make sure these variable are visible
565     // thru the whole scope of the function.
566     VARectangle input_region, output_region;
567 
568     MFX_CHECK_NULL_PTR1( pParams );
569     MFX_CHECK_NULL_PTR1( pParams->targetSurface.hdl.first );
570     MFX_CHECK_NULL_PTR1( pParams->pRefSurfaces );
571     MFX_CHECK_NULL_PTR1( pParams->pRefSurfaces[0].hdl.first );
572 
573     /* There is a special case for composition */
574     mfxStatus mfxSts = MFX_ERR_NONE;
575     if (pParams->bComposite)
576     {
577         if ((pParams->iTilesNum4Comp > 0) || (isVideoWall(pParams)) )
578         {
579             mfxSts = Execute_Composition_TiledVideoWall(pParams);
580             if (MFX_ERR_NONE == mfxSts)
581                 return mfxSts;
582         }
583         /* if there is errors in params for tiling usage it may work for usual composition */
584         else
585             mfxSts = Execute_Composition(pParams);
586         return mfxSts;
587     }
588 
589 
590     // This works for ADI 30i->30p for now
591     // Better way may involve enabling bEOS for 30i->30p mode
592     if ((1 == pParams->refCount) && (pParams->bDeinterlace30i60p == false))
593         m_deintFrameCount = 0;
594 
595     if (VA_INVALID_ID == m_deintFilterID)
596     {
597         if (pParams->iDeinterlacingAlgorithm)
598         {
599             VAProcFilterParameterBufferDeinterlacing deint;
600             deint.type  = VAProcFilterDeinterlacing;
601             deint.flags = 0;
602 
603             if (MFX_DEINTERLACING_BOB == pParams->iDeinterlacingAlgorithm)
604             {
605                 deint.algorithm = VAProcDeinterlacingBob;
606             }
607             else if(0 == pParams->iDeinterlacingAlgorithm) // skip DI for progressive frames
608             {
609                 deint.algorithm = VAProcDeinterlacingNone;
610             }
611             else
612             {
613                 deint.algorithm = VAProcDeinterlacingMotionAdaptive;
614             }
615 
616             // Get picture structure of ouput frame
617             mfxDrvSurface* pRefSurf_frameInfo = &(pParams->pRefSurfaces[0]); // previous input frame
618             mfxDrvSurface *pCurSurf_frameInfo = &(pParams->pRefSurfaces[pParams->bkwdRefCount]); // current input frame
619 
620             // PicStruc can take values: MFX_PICSTRUCT_PROGRESSIVE | MFX_PICSTRUCT_FIELD_TFF | MFX_PICSTRUCT_FIELD_REPEATED=0x10
621             // default deint.flags = 0 is for top field in TFF frame.
622             if (pCurSurf_frameInfo->frameInfo.PicStruct == MFX_PICSTRUCT_PROGRESSIVE)
623                 deint.flags = VA_DEINTERLACING_ONE_FIELD;
624             else if (pCurSurf_frameInfo->frameInfo.PicStruct & MFX_PICSTRUCT_FIELD_BFF)
625                 deint.flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST | VA_DEINTERLACING_BOTTOM_FIELD;
626 
627             /* Deinterlacer:
628              * BOB is used in first output frame (pParams->refCount = 1) and
629              * when scene change flag is set (pParams->scene > 0) ADI is
630              * used otherwise.
631              * ADI output is late by one field. Current and reference field
632              * are fed into de-interlacer.
633              **/
634 
635             /* ADI 30i->30p: To get first field of current frame only
636              * For TFF cases, deint.flags required to set VA_DEINTERLACING_ONE_FIELD
637              * ensure driver go 30i->30p mode and surface set correct
638              * For BFF cases, deint.flags required to set all bits
639              * ensure driver go 30i->30p mode and surface set correct
640              **/
641             if(deint.algorithm == VAProcDeinterlacingMotionAdaptive && (pParams->refCount > 1))
642             {
643                 if (MFX_PICSTRUCT_FIELD_TFF & pCurSurf_frameInfo->frameInfo.PicStruct)
644                     deint.flags = VA_DEINTERLACING_ONE_FIELD;
645                 else /* For BFF case required to set all bits  */
646                     deint.flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST | VA_DEINTERLACING_BOTTOM_FIELD | VA_DEINTERLACING_ONE_FIELD;
647             }
648 
649             /* For 30i->60p case we have to indicate
650              * to driver which field Top or Bottom we a going to send.
651              * ADI uses reference frame and start after first frame:
652              *   m_deintFrameCount==1, if TFF, TOP=second field of reference, BOTTOM=first field of current
653              * BOB, ADI_no_ref do not use reference frame and are used on first frame:
654              *   m_deintFrameCount==0, if TFF, TOP=first field of current, BOTTOM=seconf field of current.
655              */
656             if (pParams->bDeinterlace30i60p == true)
657             {
658                 mfxU32 refFramePicStruct = pRefSurf_frameInfo->frameInfo.PicStruct;
659                 mfxU32 currFramePicStruct = pCurSurf_frameInfo->frameInfo.PicStruct;
660                 bool isCurrentProgressive = false;
661                 bool isPreviousProgressive = false;
662                 bool isSameParity = false;
663 
664                 // Deinterlace with reference can be used after first frame is processed
665                 if(pParams->refCount > 1 && m_deintFrameCount)
666                     bUseReference = true;
667 
668                 // Check if previous is progressive
669                 if ((refFramePicStruct == MFX_PICSTRUCT_PROGRESSIVE) ||
670                 (refFramePicStruct & MFX_PICSTRUCT_FIELD_REPEATED) ||
671                 (refFramePicStruct & MFX_PICSTRUCT_FRAME_DOUBLING) ||
672                 (refFramePicStruct & MFX_PICSTRUCT_FRAME_TRIPLING))
673                 {
674                     isPreviousProgressive = true;
675                 }
676 
677                 if ((currFramePicStruct == MFX_PICSTRUCT_PROGRESSIVE) ||
678                     (currFramePicStruct & MFX_PICSTRUCT_FIELD_REPEATED) ||
679                     (currFramePicStruct & MFX_PICSTRUCT_FRAME_DOUBLING) ||
680                     (currFramePicStruct & MFX_PICSTRUCT_FRAME_TRIPLING))
681                 {
682                     isCurrentProgressive = true;
683                 }
684 
685                 // Use BOB when scene change occur
686                 if ( MFX_DEINTERLACING_ADVANCED_SCD == pParams->iDeinterlacingAlgorithm &&
687                 ( pParams->scene != VPP_NO_SCENE_CHANGE))
688                     bUseReference = false;
689 
690                 // Set up wich field to display for 30i->60p mode
691                 // ADI uses second Field on even frames
692                 // BOB, ADI_no_ref uses second Field on odd frames
693                 if (0 == (m_deintFrameCount %2) && bUseReference)
694                 {
695                     bIsFirstField = false;
696                 }
697                 else if (1 == (m_deintFrameCount %2) && ((!bUseReference)))
698                 {
699                     bIsFirstField = false;
700                 }
701 
702                 // Set deinterlace flag depending on parity and field to display
703                 if (bIsFirstField) // output is second field of previous input
704                 {
705                     if (MFX_PICSTRUCT_FIELD_TFF & pRefSurf_frameInfo->frameInfo.PicStruct)
706                         deint.flags = 0;
707                     else
708                         deint.flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST | VA_DEINTERLACING_BOTTOM_FIELD;
709                 }
710                 else // output is first field of current input
711                 {
712                     if (MFX_PICSTRUCT_FIELD_TFF & pCurSurf_frameInfo->frameInfo.PicStruct)
713                         deint.flags = VA_DEINTERLACING_BOTTOM_FIELD;
714                     else
715                         deint.flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
716                 }
717 
718                 // case where previous and current have different parity -> use ADI no ref on current
719                 // To avoid frame duplication
720 
721                 if((refFramePicStruct & MFX_PICSTRUCT_FIELD_TFF) && (currFramePicStruct & MFX_PICSTRUCT_FIELD_TFF))
722                     isSameParity = true;
723                 else if((refFramePicStruct & MFX_PICSTRUCT_FIELD_BFF) && (currFramePicStruct & MFX_PICSTRUCT_FIELD_BFF))
724                     isSameParity = true;
725 
726                 if((!isPreviousProgressive) && (!isCurrentProgressive) && (!isSameParity))
727                 {
728                     // Current is BFF
729                     if(!bIsFirstField && (currFramePicStruct & MFX_PICSTRUCT_FIELD_BFF))
730                     {
731                         deint.flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST | VA_DEINTERLACING_BOTTOM_FIELD;
732                         pParams->refCount =1; // Force ADI no ref on first Field of current frame
733                     }
734 
735                     // Current is TFF
736                     if(!bIsFirstField && (currFramePicStruct & MFX_PICSTRUCT_FIELD_TFF))
737                     {
738                         deint.flags = 0;
739                         pParams->refCount =1; // Force ADI no ref on first Field of current frame
740                     }
741                 }
742             } //  if ((30i->60p) && (pParams->refCount > 1)) /* 30i->60p mode only*/
743 
744             /* Process special case and scene change flag*/
745             if ( MFX_DEINTERLACING_ADVANCED_SCD == pParams->iDeinterlacingAlgorithm &&
746                 ( pParams->scene != VPP_NO_SCENE_CHANGE))
747             {
748                 if(pParams->bDeinterlace30i60p) // 30i->60p mode
749                 {
750                     // In case of multiple scene changes, use BOB with same field to avoid out of frame order
751                     if(VPP_MORE_SCENE_CHANGE_DETECTED == pParams->scene)
752                     {
753                         if (MFX_PICSTRUCT_FIELD_TFF & pCurSurf_frameInfo->frameInfo.PicStruct)
754                             deint.flags = 0;
755                         else /* BFF */
756                             deint.flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST | VA_DEINTERLACING_BOTTOM_FIELD;
757                     }
758                 }
759                 else /* BOB 30i->30p use First Field to generate output*/
760                 {
761                     if (MFX_PICSTRUCT_FIELD_TFF & pCurSurf_frameInfo->frameInfo.PicStruct)
762                         deint.flags = 0;
763                     else /* Frame is BFF */
764                         deint.flags = VA_DEINTERLACING_BOTTOM_FIELD_FIRST | VA_DEINTERLACING_BOTTOM_FIELD;
765                 }
766 
767                 deint.flags |= VA_DEINTERLACING_SCD_ENABLE; // It forces BOB
768             }
769 
770             vaSts = vaCreateBuffer(m_vaDisplay,
771                                    m_vaContextVPP,
772                                    VAProcFilterParameterBufferType,
773                                    sizeof(deint), 1,
774                                    &deint, &m_deintFilterID);
775             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
776 
777             m_filterBufs[m_numFilterBufs++] = m_deintFilterID;
778         }
779     }
780 
781     if (pParams->bEnableProcAmp)
782     {
783         /* Buffer was created earlier and it's time to refresh its value */
784         mfxSts = RemoveBufferFromPipe(m_procampFilterID);
785         MFX_CHECK_STS(mfxSts);
786     }
787 
788     if (VA_INVALID_ID == m_procampFilterID)
789     {
790         if ( pParams->bEnableProcAmp )
791         {
792             VAProcFilterParameterBufferColorBalance procamp[4];
793 
794             procamp[0].type   = VAProcFilterColorBalance;
795             procamp[0].attrib = VAProcColorBalanceBrightness;
796             procamp[0].value  = 0;
797 
798             if ( pParams->Brightness)
799             {
800                 procamp[0].value = convertValue(-100,
801                                 100,
802                                 m_procampCaps[VAProcColorBalanceBrightness-1].range.min_value,
803                                 m_procampCaps[VAProcColorBalanceBrightness-1].range.max_value,
804                                 pParams->Brightness);
805             }
806 
807             procamp[1].type   = VAProcFilterColorBalance;
808             procamp[1].attrib = VAProcColorBalanceContrast;
809             procamp[1].value  = 1;
810 
811             if ( pParams->Contrast != 1 )
812             {
813                 procamp[1].value = convertValue(0,
814                                 10,
815                                 m_procampCaps[VAProcColorBalanceContrast-1].range.min_value,
816                                 m_procampCaps[VAProcColorBalanceContrast-1].range.max_value,
817                                 pParams->Contrast);
818             }
819 
820             procamp[2].type   = VAProcFilterColorBalance;
821             procamp[2].attrib = VAProcColorBalanceHue;
822             procamp[2].value  = 0;
823 
824             if ( pParams->Hue)
825             {
826                 procamp[2].value = convertValue(-180,
827                                 180,
828                                 m_procampCaps[VAProcColorBalanceHue-1].range.min_value,
829                                 m_procampCaps[VAProcColorBalanceHue-1].range.max_value,
830                                 pParams->Hue);
831             }
832 
833             procamp[3].type   = VAProcFilterColorBalance;
834             procamp[3].attrib = VAProcColorBalanceSaturation;
835             procamp[3].value  = 1;
836 
837             if ( pParams->Saturation != 1 )
838             {
839                 procamp[3].value = convertValue(0,
840                                 10,
841                                 m_procampCaps[VAProcColorBalanceSaturation-1].range.min_value,
842                                 m_procampCaps[VAProcColorBalanceSaturation-1].range.max_value,
843                                 pParams->Saturation);
844             }
845 
846             vaSts = vaCreateBuffer((void*)m_vaDisplay,
847                                           m_vaContextVPP,
848                                           VAProcFilterParameterBufferType,
849                                           sizeof(procamp), 4,
850                                           &procamp, &m_procampFilterID);
851             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
852 
853             m_filterBufs[m_numFilterBufs++] = m_procampFilterID;
854 
855             /* Clear enable flag. Since appropriate buffer has been created,
856              * it will be used in consequent Execute calls.
857              * If application will Reset or call Init/Close with setting procamp
858              * with new value, this flag will be raised again thus new buffer with
859              * new value will be created. */
860             pParams->bEnableProcAmp = false;
861         }
862     }
863 
864     if (pParams->denoiseFactor || pParams->bDenoiseAutoAdjust)
865     {
866         /* Buffer was created earlier and it's time to refresh its value */
867         mfxSts = RemoveBufferFromPipe(m_denoiseFilterID);
868         MFX_CHECK_STS(mfxSts);
869     }
870 
871     if (VA_INVALID_ID == m_denoiseFilterID)
872     {
873         if (pParams->denoiseFactor || pParams->bDenoiseAutoAdjust)
874         {
875             VAProcFilterParameterBuffer denoise;
876             denoise.type  = VAProcFilterNoiseReduction;
877             if(pParams->bDenoiseAutoAdjust)
878                 denoise.value = m_denoiseCaps.range.default_value;
879             else
880                 denoise.value = (mfxU16)floor(
881                                             convertValue(0,
882                                               100,
883                                               m_denoiseCaps.range.min_value,
884                                               m_denoiseCaps.range.max_value,
885                                               pParams->denoiseFactor) + 0.5);
886             vaSts = vaCreateBuffer((void*)m_vaDisplay,
887                           m_vaContextVPP,
888                           VAProcFilterParameterBufferType,
889                           sizeof(denoise), 1,
890                           &denoise, &m_denoiseFilterID);
891             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
892 
893             m_filterBufs[m_numFilterBufs++] = m_denoiseFilterID;
894             pParams->denoiseFactor = 0;
895             pParams->bDenoiseAutoAdjust = false;
896         }
897     }
898 
899     if (pParams->detailFactor || pParams->bDetailAutoAdjust)
900     {
901         /* Buffer was created earlier and it's time to refresh its value */
902         mfxSts = RemoveBufferFromPipe(m_detailFilterID);
903         MFX_CHECK_STS(mfxSts);
904     }
905 
906     if (VA_INVALID_ID == m_detailFilterID)
907     {
908         if (pParams->detailFactor || pParams->bDetailAutoAdjust)
909         {
910             VAProcFilterParameterBuffer detail;
911             detail.type  = VAProcFilterSharpening;
912             if(pParams->bDetailAutoAdjust)
913                 detail.value = m_detailCaps.range.default_value;
914             else
915                 detail.value = (mfxU16)floor(
916                                            convertValue(0,
917                                              100,
918                                              m_detailCaps.range.min_value,
919                                              m_detailCaps.range.max_value,
920                                              pParams->detailFactor) + 0.5);
921             vaSts = vaCreateBuffer((void*)m_vaDisplay,
922                           m_vaContextVPP,
923                           VAProcFilterParameterBufferType,
924                           sizeof(detail), 1,
925                           &detail, &m_detailFilterID);
926             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
927 
928             m_filterBufs[m_numFilterBufs++] = m_detailFilterID;
929             pParams->detailFactor = 0;
930             pParams->bDetailAutoAdjust = false;
931         }
932     }
933 
934     if (VA_INVALID_ID == m_frcFilterID)
935     {
936         if (pParams->bFRCEnable)
937         {
938 #ifdef MFX_ENABLE_VPP_FRC
939           VAProcFilterParameterBufferFrameRateConversion frcParams;
940 
941           memset(&frcParams, 0, sizeof(VAProcFilterParameterBufferFrameRateConversion));
942           frcParams.type = VAProcFilterFrameRateConversion;
943           if (30 == pParams->customRateData.customRate.FrameRateExtD)
944           {
945               frcParams.input_fps = 30;
946               frcParams.output_fps = 60;
947               frcParams.num_output_frames = 2;
948               frcParams.repeat_frame = 0;
949           }
950           else if (24 == pParams->customRateData.customRate.FrameRateExtD)
951           {
952               frcParams.input_fps = 24;
953               frcParams.output_fps = 60;
954               frcParams.num_output_frames = 5;
955               frcParams.repeat_frame = 0;
956           }
957 
958           frcParams.cyclic_counter = m_frcCyclicCounter++;
959           if ((frcParams.input_fps == 30) && (m_frcCyclicCounter == 2))
960                 m_frcCyclicCounter = 0;
961           if ((frcParams.input_fps == 24) && (m_frcCyclicCounter == 5))
962                 m_frcCyclicCounter = 0;
963           frcParams.output_frames = (VASurfaceID*)(pParams->targetSurface.hdl.first);
964           vaSts = vaCreateBuffer((void*)m_vaDisplay,
965                         m_vaContextVPP,
966                         VAProcFilterParameterBufferType,
967                         sizeof(frcParams), 1,
968                         &frcParams, &m_frcFilterID);
969           MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
970 
971           m_filterBufs[m_numFilterBufs++] = m_frcFilterID;
972 #else
973           return MFX_ERR_UNSUPPORTED;
974 #endif
975         }
976     }
977 
978     /* pParams->refCount is total number of processing surfaces:
979      * in case of composition this is primary + sub streams*/
980 
981     m_pipelineParam.resize(pParams->refCount);
982     m_pipelineParamID.resize(pParams->refCount, VA_INVALID_ID);
983 
984     mfxDrvSurface* pRefSurf = &(pParams->pRefSurfaces[0]);
985     memset(&m_pipelineParam[0], 0, sizeof(m_pipelineParam[0]));
986 
987     if (pParams->bFieldWeaving || ( (pParams->refCount > 1) && (0 != pParams->iDeinterlacingAlgorithm )))
988     {
989         m_pipelineParam[0].num_backward_references = 1;
990         mfxDrvSurface* pRefSurf_1 = NULL;
991         /* in pRefSurfaces
992             * first is backward references
993             * then current src surface
994             * and only after this is forward references
995             * */
996         pRefSurf_1 = &(pParams->pRefSurfaces[0]); // point to previous frame
997         VASurfaceID *ref_srf = (VASurfaceID *)(pRefSurf_1->hdl.first);
998         m_pipelineParam[0].backward_references = ref_srf;
999     }
1000     /* FRC Interpolated case */
1001     if (0 != pParams->bFRCEnable)
1002     {
1003         if (30 == pParams->customRateData.customRate.FrameRateExtD)
1004             m_pipelineParam[0].num_forward_references = 2;
1005         else if (24 == pParams->customRateData.customRate.FrameRateExtD)
1006             m_pipelineParam[0].num_forward_references = 3;
1007 
1008         if (2 == pParams->refCount) /* may be End of Stream case */
1009         {
1010             mfxDrvSurface* pRefSurf_frc1;
1011             pRefSurf_frc1 = &(pParams->pRefSurfaces[1]);
1012             m_refForFRC[0] = *(VASurfaceID*)(pRefSurf_frc1->hdl.first);
1013             m_refForFRC[2] = m_refForFRC[1] = m_refForFRC[0];
1014         }
1015         if (3 == pParams->refCount)
1016         {
1017             mfxDrvSurface* pRefSurf_frc1;
1018             pRefSurf_frc1 = &(pParams->pRefSurfaces[1]);
1019             m_refForFRC[0] = *(VASurfaceID*)(pRefSurf_frc1->hdl.first);
1020             mfxDrvSurface* pRefSurf_frc2;
1021             pRefSurf_frc2 = &(pParams->pRefSurfaces[2]);
1022             m_refForFRC[1] = *(VASurfaceID*) (pRefSurf_frc2->hdl.first);
1023         }
1024         if (4 == pParams->refCount)
1025         {
1026             mfxDrvSurface* pRefSurf_frc1;
1027             pRefSurf_frc1 = &(pParams->pRefSurfaces[1]);
1028             m_refForFRC[0] = *(VASurfaceID*)(pRefSurf_frc1->hdl.first);
1029             mfxDrvSurface* pRefSurf_frc2;
1030             pRefSurf_frc2 = &(pParams->pRefSurfaces[2]);
1031             m_refForFRC[1] = *(VASurfaceID*) (pRefSurf_frc2->hdl.first);
1032             mfxDrvSurface* pRefSurf_frc3;
1033             pRefSurf_frc3 = &(pParams->pRefSurfaces[3]);
1034             m_refForFRC[2] = *(VASurfaceID*) (pRefSurf_frc3->hdl.first);
1035         }
1036         /* to pass ref list to pipeline */
1037         m_pipelineParam[0].forward_references = m_refForFRC;
1038     } /*if (0 != pParams->bFRCEnable)*/
1039 
1040     /* SRC surface */
1041     mfxDrvSurface* pSrcInputSurf = &pRefSurf[pParams->bkwdRefCount];
1042     /* in 30i->60p mode, when scene change occurs, BOB is used and needs current input frame.
1043         * Current frame = ADI reference for odd output frames
1044         * Current frame = ADI input for even output frames
1045         * when mixed picture is progressive, even frame use reference frame for output due to ADI delay
1046     **/
1047     if(pParams->bDeinterlace30i60p && ((VPP_SCENE_NEW == pParams->scene)|| (pParams->iDeinterlacingAlgorithm == 0)))
1048     {
1049         if(m_deintFrameCount % 2)
1050             pSrcInputSurf = &(pParams->pRefSurfaces[0]); // point to reference frame
1051     }
1052 
1053     VASurfaceID *srf = (VASurfaceID *)(pSrcInputSurf->hdl.first);
1054     m_pipelineParam[0].surface = *srf;
1055 
1056 #ifdef MFX_ENABLE_VPP_ROTATION
1057     switch (pParams->rotation)
1058     {
1059     case MFX_ANGLE_90:
1060         if ( m_pipelineCaps.rotation_flags & (1 << VA_ROTATION_90))
1061         {
1062             m_pipelineParam[0].rotation_state = VA_ROTATION_90;
1063         }
1064         break;
1065     case MFX_ANGLE_180:
1066         if ( m_pipelineCaps.rotation_flags & (1 << VA_ROTATION_180))
1067         {
1068             m_pipelineParam[0].rotation_state = VA_ROTATION_180;
1069         }
1070         break;
1071     case MFX_ANGLE_270:
1072         if ( m_pipelineCaps.rotation_flags & (1 << VA_ROTATION_270))
1073         {
1074             m_pipelineParam[0].rotation_state = VA_ROTATION_270;
1075         }
1076         break;
1077     }
1078 #endif
1079 
1080     /*
1081      * Execute mirroring for MIRROR_WO_EXEC only because MSDK will do
1082      * copy-with-mirror for others.
1083      */
1084     if (pParams->mirroringPosition == MIRROR_WO_EXEC) {
1085         switch (pParams->mirroring) {
1086         case MFX_MIRRORING_HORIZONTAL:
1087             m_pipelineParam[0].mirror_state = VA_MIRROR_HORIZONTAL;
1088             break;
1089 
1090         case MFX_MIRRORING_VERTICAL:
1091             m_pipelineParam[0].mirror_state = VA_MIRROR_VERTICAL;
1092             break;
1093         }
1094     }
1095 
1096     // source cropping
1097     mfxFrameInfo *inInfo = &(pRefSurf->frameInfo);
1098     input_region.y   = inInfo->CropY;
1099     input_region.x   = inInfo->CropX;
1100     input_region.height = inInfo->CropH;
1101     input_region.width  = inInfo->CropW;
1102     m_pipelineParam[0].surface_region = &input_region;
1103 
1104     // destination cropping
1105     mfxFrameInfo *outInfo = &(pParams->targetSurface.frameInfo);
1106     output_region.y  = outInfo->CropY;
1107     output_region.x   = outInfo->CropX;
1108     output_region.height= outInfo->CropH;
1109     output_region.width  = outInfo->CropW;
1110     m_pipelineParam[0].output_region = &output_region;
1111 
1112     m_pipelineParam[0].output_background_color = 0xff000000; // black for ARGB
1113 
1114 #ifdef MFX_ENABLE_VPP_VIDEO_SIGNAL
1115 #define ENABLE_VPP_VIDEO_SIGNAL(X) X
1116 #else
1117 #define ENABLE_VPP_VIDEO_SIGNAL(X)
1118 #endif
1119 
1120     mfxU32  refFourcc = pRefSurf->frameInfo.FourCC;
1121     switch (refFourcc)
1122     {
1123     case MFX_FOURCC_RGB4:
1124 #ifdef MFX_ENABLE_RGBP
1125     case MFX_FOURCC_RGBP:
1126 #endif
1127 #if (MFX_VERSION >= 1028)
1128     case MFX_FOURCC_RGB565:
1129 #endif
1130         m_pipelineParam[0].surface_color_standard = VAProcColorStandardNone;
1131         ENABLE_VPP_VIDEO_SIGNAL(m_pipelineParam[0].input_color_properties.color_range = VA_SOURCE_RANGE_FULL);
1132         break;
1133     case MFX_FOURCC_NV12:
1134     default:
1135         m_pipelineParam[0].surface_color_standard = VAProcColorStandardBT601;
1136         ENABLE_VPP_VIDEO_SIGNAL(m_pipelineParam[0].input_color_properties.color_range = VA_SOURCE_RANGE_REDUCED);
1137         break;
1138     }
1139 
1140     mfxU32  targetFourcc = pParams->targetSurface.frameInfo.FourCC;
1141     switch (targetFourcc)
1142     {
1143     case MFX_FOURCC_RGB4:
1144 #ifdef MFX_ENABLE_RGBP
1145     case MFX_FOURCC_RGBP:
1146 #endif
1147 #if (MFX_VERSION >= 1028)
1148     case MFX_FOURCC_RGB565:
1149 #endif
1150         m_pipelineParam[0].output_color_standard = VAProcColorStandardNone;
1151         ENABLE_VPP_VIDEO_SIGNAL(m_pipelineParam[0].output_color_properties.color_range = VA_SOURCE_RANGE_FULL);
1152         break;
1153     case MFX_FOURCC_NV12:
1154         m_pipelineParam[0].output_color_standard = VAProcColorStandardBT601;
1155         if(refFourcc == MFX_FOURCC_RGBP)
1156         {
1157             ENABLE_VPP_VIDEO_SIGNAL(m_pipelineParam[0].output_color_properties.color_range = VA_SOURCE_RANGE_FULL);
1158         }
1159         else
1160         {
1161             ENABLE_VPP_VIDEO_SIGNAL(m_pipelineParam[0].output_color_properties.color_range = VA_SOURCE_RANGE_REDUCED);
1162         }
1163         break;
1164     default:
1165         m_pipelineParam[0].output_color_standard = VAProcColorStandardBT601;
1166         ENABLE_VPP_VIDEO_SIGNAL(m_pipelineParam[0].output_color_properties.color_range = VA_SOURCE_RANGE_REDUCED);
1167         break;
1168     }
1169 
1170     m_pipelineParam[0].input_color_properties.chroma_sample_location  = VA_CHROMA_SITING_UNKNOWN;
1171     m_pipelineParam[0].output_color_properties.chroma_sample_location = VA_CHROMA_SITING_UNKNOWN;
1172 
1173     /* It needs interlaced flag passed only for
1174         * deinterlacing and scaling. All other filters must
1175         * use progressive even for interlaced content.
1176         */
1177     bool forceProgressive = true;
1178     if (pParams->iDeinterlacingAlgorithm ||
1179         inInfo->CropH != outInfo->CropH    ||
1180         inInfo->CropW != outInfo->CropW)
1181     {
1182         forceProgressive = false;
1183     }
1184 
1185     switch (pRefSurf->frameInfo.PicStruct)
1186     {
1187         case MFX_PICSTRUCT_PROGRESSIVE:
1188             m_pipelineParam[0].filter_flags = VA_FRAME_PICTURE;
1189             break;
1190         case MFX_PICSTRUCT_FIELD_TFF:
1191             m_pipelineParam[0].filter_flags = forceProgressive ? VA_FRAME_PICTURE : VA_TOP_FIELD;
1192             break;
1193         case MFX_PICSTRUCT_FIELD_BFF:
1194             m_pipelineParam[0].filter_flags = forceProgressive ? VA_FRAME_PICTURE : VA_BOTTOM_FIELD;
1195             break;
1196     }
1197 
1198     if (pParams->bFieldWeaving)
1199     {
1200         // Field weaving needs flags that are different from usual pipeline
1201         switch (pRefSurf->frameInfo.PicStruct)
1202         {
1203             case MFX_PICSTRUCT_FIELD_TFF:
1204                 m_pipelineParam[0].filter_flags = VA_TOP_FIELD_WEAVE;
1205                 break;
1206             case MFX_PICSTRUCT_FIELD_BFF:
1207                 m_pipelineParam[0].filter_flags = VA_BOTTOM_FIELD_WEAVE;
1208                 break;
1209         }
1210     }
1211 
1212     m_pipelineParam[0].filters      = m_filterBufs;
1213     m_pipelineParam[0].num_filters  = m_numFilterBufs;
1214 
1215     int index = GetCurFrameSignalIdx(pParams);
1216     if ((index >= 0) && pParams->VideoSignalInfo[index].enabled)
1217     {
1218 #ifdef MFX_ENABLE_VPP_VIDEO_SIGNAL
1219         if(pParams->VideoSignalInfo[index].TransferMatrix != MFX_TRANSFERMATRIX_UNKNOWN)
1220         {
1221             m_pipelineParam[0].surface_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfo[index].TransferMatrix ? VAProcColorStandardBT709 : VAProcColorStandardBT601);
1222         }
1223 
1224         if(pParams->VideoSignalInfo[index].NominalRange != MFX_NOMINALRANGE_UNKNOWN)
1225         {
1226             m_pipelineParam[0].input_color_properties.color_range = (MFX_NOMINALRANGE_0_255 == pParams->VideoSignalInfo[index].NominalRange) ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
1227         }
1228     }
1229 
1230     if (pParams->VideoSignalInfoOut.enabled)
1231     {
1232         if(pParams->VideoSignalInfoOut.TransferMatrix != MFX_TRANSFERMATRIX_UNKNOWN)
1233         {
1234             m_pipelineParam[0].output_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfoOut.TransferMatrix ? VAProcColorStandardBT709 : VAProcColorStandardBT601);
1235         }
1236 
1237         if(pParams->VideoSignalInfoOut.NominalRange != MFX_NOMINALRANGE_UNKNOWN)
1238         {
1239             m_pipelineParam[0].output_color_properties.color_range = (MFX_NOMINALRANGE_0_255 == pParams->VideoSignalInfoOut.NominalRange) ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
1240         }
1241 #else
1242         return MFX_ERR_UNSUPPORTED;
1243 #endif // #ifdef MFX_ENABLE_VPP_VIDEO_SIGNAL
1244     }
1245 
1246     m_pipelineParam[0].input_color_properties.chroma_sample_location  = VA_CHROMA_SITING_UNKNOWN;
1247     m_pipelineParam[0].output_color_properties.chroma_sample_location = VA_CHROMA_SITING_UNKNOWN;
1248 
1249     /* Scaling params */
1250     switch (pParams->scalingMode)
1251     {
1252     case MFX_SCALING_MODE_LOWPOWER:
1253         /* VA_FILTER_SCALING_DEFAULT means the following:
1254             *  First priority is HW fixed function scaling engine. If it can't work, revert to AVS
1255             *  If scaling ratio between 1/8...8 -> HW fixed function
1256             *  If scaling ratio between 1/16...1/8 or larger than 8 -> AVS
1257             *  If scaling ratio is less than 1/16 -> bilinear
1258             */
1259         m_pipelineParam[0].filter_flags |= VA_FILTER_SCALING_DEFAULT;
1260         break;
1261     case MFX_SCALING_MODE_QUALITY:
1262         /*  VA_FILTER_SCALING_HQ means the following:
1263             *  If scaling ratio is less than 1/16 -> bilinear
1264             *  For all other cases, AVS is used.
1265             */
1266         m_pipelineParam[0].filter_flags |= VA_FILTER_SCALING_HQ;
1267         break;
1268     case MFX_SCALING_MODE_DEFAULT:
1269     default:
1270         if(MFX_HW_APL == hwType)
1271         {
1272             /* Use HW fixed function scaling engine by default on APL due to power consumption considerations */
1273             m_pipelineParam[0].filter_flags |= VA_FILTER_SCALING_DEFAULT;
1274         }
1275         else
1276         {
1277             /* Force AVS by default for all platforms except BXT */
1278             m_pipelineParam[0].filter_flags |= VA_FILTER_SCALING_HQ;
1279         }
1280         break;
1281     }
1282 
1283 #if (MFX_VERSION >= 1025)
1284         uint8_t& chromaSitingMode = m_pipelineParam[0].input_color_properties.chroma_sample_location;
1285         chromaSitingMode = VA_CHROMA_SITING_UNKNOWN;
1286 
1287         switch (pParams->chromaSiting)
1288         {
1289         case MFX_CHROMA_SITING_HORIZONTAL_LEFT | MFX_CHROMA_SITING_VERTICAL_TOP:
1290             //Option A : Chroma samples are aligned horizontally and vertically with multiples of the luma samples
1291             chromaSitingMode = VA_CHROMA_SITING_HORIZONTAL_LEFT | VA_CHROMA_SITING_VERTICAL_TOP;
1292             break;
1293         case MFX_CHROMA_SITING_HORIZONTAL_LEFT | MFX_CHROMA_SITING_VERTICAL_CENTER:
1294             //Option AB : Chroma samples are vertically centered between, but horizontally aligned with luma samples.
1295             chromaSitingMode = VA_CHROMA_SITING_HORIZONTAL_LEFT | VA_CHROMA_SITING_VERTICAL_CENTER;
1296             break;
1297         case MFX_CHROMA_SITING_HORIZONTAL_LEFT | MFX_CHROMA_SITING_VERTICAL_BOTTOM:
1298             //Option B : Chroma samples are horizontally aligned and vertically 1 pixel offset to the bottom.
1299             chromaSitingMode = VA_CHROMA_SITING_HORIZONTAL_LEFT | VA_CHROMA_SITING_VERTICAL_BOTTOM;
1300             break;
1301         case MFX_CHROMA_SITING_HORIZONTAL_CENTER | MFX_CHROMA_SITING_VERTICAL_CENTER:
1302             //Option ABCD : Chroma samples are centered between luma samples both horizontally and vertically.
1303             chromaSitingMode = VA_CHROMA_SITING_HORIZONTAL_CENTER | VA_CHROMA_SITING_VERTICAL_CENTER;
1304             break;
1305         case MFX_CHROMA_SITING_HORIZONTAL_CENTER | MFX_CHROMA_SITING_VERTICAL_TOP:
1306             //Option AC : Chroma samples are vertically aligned with, and horizontally centered between luma
1307             chromaSitingMode = VA_CHROMA_SITING_HORIZONTAL_CENTER | VA_CHROMA_SITING_VERTICAL_TOP;
1308             break;
1309         case MFX_CHROMA_SITING_HORIZONTAL_CENTER | MFX_CHROMA_SITING_VERTICAL_BOTTOM:
1310             //Option BD : Chroma samples are horizontally 0.5 pixel offset to the right and vertically 1 pixel offset to the bottom.
1311             chromaSitingMode = VA_CHROMA_SITING_HORIZONTAL_CENTER | VA_CHROMA_SITING_VERTICAL_BOTTOM;
1312             break;
1313         case MFX_CHROMA_SITING_UNKNOWN:
1314         default:
1315             break;
1316         }
1317         m_pipelineParam[0].output_color_properties.chroma_sample_location = chromaSitingMode;
1318 #endif
1319 
1320 if (pParams->mirroringExt)
1321 {
1322     // First priority is HW fixed function scaling engine. If it can't work, revert to AVS
1323     // Starting from ATS there is only HW fixed function scaling engine due to AVS removal
1324     m_pipelineParam[0].filter_flags = VA_FILTER_SCALING_DEFAULT;
1325 
1326     switch (pParams->mirroring)
1327     {
1328     case MFX_MIRRORING_VERTICAL:
1329         m_pipelineParam[0].mirror_state = VA_MIRROR_VERTICAL;
1330         break;
1331     case MFX_MIRRORING_HORIZONTAL:
1332         m_pipelineParam[0].mirror_state = VA_MIRROR_HORIZONTAL;
1333         break;
1334     }
1335 }
1336 
1337     vaSts = vaCreateBuffer(m_vaDisplay,
1338                         m_vaContextVPP,
1339                         VAProcPipelineParameterBufferType,
1340                         sizeof(VAProcPipelineParameterBuffer),
1341                         1,
1342                         &m_pipelineParam[0],
1343                         &m_pipelineParamID[0]);
1344     MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1345 
1346     // increase deinterlacer frame count after frame has been processed
1347     m_deintFrameCount ++;
1348 
1349     // for ADI 30i->60p, EOS is received on second field after vpp_reset
1350     // reset m_deintFrameCount to zero after processing second field
1351     if((pParams->bEOS) && (pParams->bDeinterlace30i60p == true))
1352         m_deintFrameCount = 0;
1353 
1354     VASurfaceID *outputSurface = (VASurfaceID*)(pParams->targetSurface.hdl.first);
1355 
1356     //create gpu priority buffer and bufferID
1357     if(m_MaxContextPriority)
1358     {
1359         mfxPriority contextPriority = m_core->GetSession()->m_priority;
1360         VAContextParameterUpdateBuffer GpuPriorityBuf_vpp;
1361         memset(&GpuPriorityBuf_vpp, 0, sizeof(VAContextParameterUpdateBuffer));
1362 
1363         GpuPriorityBuf_vpp.flags.bits.context_priority_update = 1;
1364         if(contextPriority == MFX_PRIORITY_LOW)
1365         {
1366             GpuPriorityBuf_vpp.context_priority.bits.priority = 0;
1367         }
1368         else if (contextPriority == MFX_PRIORITY_HIGH)
1369         {
1370             GpuPriorityBuf_vpp.context_priority.bits.priority = m_MaxContextPriority;
1371         }
1372         else
1373         {
1374             GpuPriorityBuf_vpp.context_priority.bits.priority = m_MaxContextPriority/2;
1375         }
1376 
1377         vaSts = vaCreateBuffer((void*)m_vaDisplay,
1378                             m_vaContextVPP,
1379                             VAContextParameterUpdateBufferType,
1380                             sizeof(GpuPriorityBuf_vpp), 1,
1381                             &GpuPriorityBuf_vpp, &m_gpuPriorityID);
1382         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1383     }
1384 
1385     MFX_LTRACE_2(MFX_TRACE_LEVEL_HOTSPOTS, "A|VPP|FILTER|PACKET_START|", "%d|%d", m_vaContextVPP, 0);
1386     {
1387         MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaBeginPicture");
1388         vaSts = vaBeginPicture(m_vaDisplay,
1389                             m_vaContextVPP,
1390                             *outputSurface);
1391         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1392     }
1393 
1394     if(m_MaxContextPriority)
1395     {
1396         MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaRenderPicture_gpuPriority");
1397         vaSts = vaRenderPicture(m_vaDisplay, m_vaContextVPP, &m_gpuPriorityID, 1);
1398         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1399     }
1400 
1401     {
1402         MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaRenderPicture");
1403         vaSts = vaRenderPicture(m_vaDisplay, m_vaContextVPP, &m_pipelineParamID[0], 1);
1404         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1405     }
1406 
1407     {
1408         MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaEndPicture");
1409         vaSts = vaEndPicture(m_vaDisplay, m_vaContextVPP);
1410         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1411     }
1412     MFX_LTRACE_2(MFX_TRACE_LEVEL_HOTSPOTS, "A|VPP|FILTER|PACKET_END|", "%d|%d", m_vaContextVPP, 0);
1413 
1414     for (VABufferID& id : m_pipelineParamID)
1415     {
1416         mfxSts = CheckAndDestroyVAbuffer(m_vaDisplay, id);
1417         MFX_CHECK_STS(mfxSts);
1418     }
1419 
1420     if(m_MaxContextPriority)
1421     {
1422         mfxSts = CheckAndDestroyVAbuffer(m_vaDisplay, m_gpuPriorityID);
1423         MFX_CHECK_STS(mfxSts);
1424     }
1425 
1426     mfxSts = RemoveBufferFromPipe(m_deintFilterID);
1427     MFX_CHECK_STS(mfxSts);
1428 
1429     // (3) info needed for sync operation
1430     //-------------------------------------------------------
1431     {
1432         UMC::AutomaticUMCMutex guard(m_guard);
1433 
1434         ExtVASurface currentFeedback; // {surface & number_of_task}
1435         currentFeedback.surface = *outputSurface;
1436         currentFeedback.number = pParams->statusReportID;
1437         m_feedbackCache.push_back(currentFeedback);
1438     }
1439 
1440     mfxSts = RemoveBufferFromPipe(m_frcFilterID);
1441     MFX_CHECK_STS(mfxSts);
1442 
1443     return MFX_ERR_NONE;
1444 } // mfxStatus VAAPIVideoProcessing::Execute(FASTCOMP_BLT_PARAMS *pVideoCompositingBlt)
1445 
RemoveBufferFromPipe(VABufferID & id)1446 mfxStatus VAAPIVideoProcessing::RemoveBufferFromPipe(VABufferID& id)
1447 {
1448     if (id != VA_INVALID_ID)
1449     {
1450         VABufferID tmp = id;
1451         mfxStatus sts = CheckAndDestroyVAbuffer(m_vaDisplay, id);
1452         MFX_CHECK_STS(sts);
1453 
1454         std::remove(m_filterBufs, m_filterBufs + m_numFilterBufs, tmp);
1455         m_filterBufs[m_numFilterBufs] = VA_INVALID_ID;
1456         --m_numFilterBufs;
1457     }
1458 
1459     return MFX_ERR_NONE;
1460 }
1461 
1462 
isVideoWall(mfxExecuteParams * pParams)1463 BOOL    VAAPIVideoProcessing::isVideoWall(mfxExecuteParams *pParams)
1464 {
1465     BOOL result = false;
1466     mfxU16 outputWidth;
1467     mfxU16 outputHeight;
1468     mfxU16 layerWidth  = 0;
1469     mfxU16 layerHeight = 0;
1470     mfxU16 numX = 0;
1471     mfxU16 numY = 0;
1472     std::vector <mfxU32> indexVW;
1473     std::map<mfxU16, compStreamElem> layout;
1474 
1475     mfxU32 layerCount = (mfxU32) pParams->fwdRefCount + 1;
1476 
1477     if ( layerCount % MAX_STREAMS_PER_TILE != 0 )
1478     {
1479         /* Number of streams must be multiple of 8. That's just for simplicity.
1480          * TODO: need to handle the case when number is not multiple of 8*/
1481         return result;
1482     }
1483 
1484     indexVW.reserve(layerCount);
1485     outputWidth  = pParams->targetSurface.frameInfo.CropW;
1486     outputHeight = pParams->targetSurface.frameInfo.CropH;
1487 
1488     /**/
1489     layerWidth = pParams->dstRects[0].DstW;
1490     numX = outputWidth / layerWidth;
1491     layerHeight = pParams->dstRects[0].DstH;
1492     numY = outputHeight / layerHeight;
1493 
1494     // Set up perfect layout of the video wall
1495     for ( unsigned int j = 0; j < layerCount; j++ )
1496     {
1497         mfxU16 render_order = (j/numX)*numX + (j % numX);
1498         compStreamElem element;
1499         element.x  = (j % numX)*layerWidth;
1500         element.y  = (j/numX)*layerHeight;
1501         layout.insert(std::pair<mfxU16, compStreamElem>(render_order, element));
1502     }
1503 
1504     for ( unsigned int i = 0; i < layerCount; i++)
1505     {
1506         std::map<mfxU16, compStreamElem>::iterator it;
1507         DstRect rect = pParams->dstRects[i];
1508 
1509         if ( outputWidth % rect.DstW != 0 )
1510         {
1511             /* Layer width should fit output */
1512             return result;
1513         }
1514 
1515         if ( layerWidth != rect.DstW)
1516         {
1517             /* All layers must have the same width */
1518             return result;
1519         }
1520 
1521         if ( outputHeight % rect.DstH != 0 )
1522         {
1523             /* Layer height should fit output */
1524             return result;
1525         }
1526 
1527         if ( layerHeight != rect.DstH)
1528         {
1529             /* All layers must have the same height */
1530             return result;
1531         }
1532 
1533         mfxU16 render_order = 0;
1534         render_order  = rect.DstX/(outputWidth/numX);
1535         render_order += numX * (rect.DstY/(outputHeight/numY));
1536         it = layout.find(render_order);
1537         if ( layout.end() == it )
1538         {
1539             /* All layers must have the same height */
1540             return result;
1541         }
1542         else if (it->second.active)
1543         {
1544             /* Slot is busy with another layer already */
1545             return result;
1546         }
1547         else if (it->second.x != rect.DstX || it->second.y != rect.DstY)
1548         {
1549             /* Layers should be ordered in proper way allowing partial rendering on output */
1550             return result;
1551         }
1552         else
1553         {
1554             it->second.active = true;
1555             it->second.index  = i;
1556             indexVW.push_back(render_order);
1557         }
1558     }
1559 
1560     if ( numX > 1 && numX % 2 != 0 )
1561     {
1562         /* Number of layers on X-axis is not correct */
1563         return result;
1564     }
1565 
1566     if ( numY % 2 != 0 )
1567     {
1568         /* Number of layers on Y-axis is not correct */
1569         return result;
1570     }
1571 
1572     result = true;
1573 
1574     pParams->iTilesNum4Comp = layerCount / MAX_STREAMS_PER_TILE;
1575     for ( unsigned int i = 0; i < layerCount; i++)
1576     {
1577         pParams->dstRects[i].TileId = indexVW[i] / MAX_STREAMS_PER_TILE;
1578     }
1579 
1580     return result;
1581 }
1582 
1583 #ifdef MFX_ENABLE_VPP_COMPOSITION
Execute_Composition_TiledVideoWall(mfxExecuteParams * pParams)1584 mfxStatus VAAPIVideoProcessing::Execute_Composition_TiledVideoWall(mfxExecuteParams *pParams)
1585 {
1586     MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_HOTSPOTS, "VAAPIVideoProcessing::Execute_Composition_TiledVideoWall");
1587 
1588     mfxStatus sts;
1589     VAStatus vaSts = VA_STATUS_SUCCESS;
1590     std::vector<VABlendState> blend_state;
1591 
1592     MFX_CHECK_NULL_PTR1( pParams );
1593     MFX_CHECK_NULL_PTR1( pParams->targetSurface.hdl.first );
1594     MFX_CHECK_NULL_PTR1( pParams->pRefSurfaces );
1595     MFX_CHECK_NULL_PTR1( pParams->pRefSurfaces[0].hdl.first );
1596 
1597     if ( 0 == pParams->iTilesNum4Comp )
1598     {
1599         return MFX_ERR_UNKNOWN;
1600     }
1601     mfxU32 layerCount = (mfxU32) pParams->fwdRefCount + 1;
1602 
1603     std::vector<m_tiledVideoWallParams> tilingParams;
1604     tilingParams.resize(pParams->iTilesNum4Comp);
1605     for ( unsigned int i = 0; i < tilingParams.size(); i++)
1606     {
1607         tilingParams[i].targerRect.x = tilingParams[i].targerRect.y = 0x7fff;
1608         tilingParams[i].targerRect.width = tilingParams[i].targerRect.height = 0;
1609     }
1610 
1611     m_pipelineParam.resize(pParams->refCount + 1);
1612     m_pipelineParamID.resize(pParams->refCount + 1, VA_INVALID_ID);
1613     blend_state.resize(pParams->refCount + 1);
1614 
1615     std::vector<VARectangle> input_region;
1616     input_region.resize(pParams->refCount + 1);
1617     std::vector<VARectangle> output_region;
1618     output_region.resize(pParams->refCount + 1);
1619 
1620     /* Initial set up for layers */
1621     for ( unsigned int i = 0; i < layerCount; i++)
1622     {
1623         mfxDrvSurface* pRefSurf = &(pParams->pRefSurfaces[i]);
1624         VASurfaceID* srf        = (VASurfaceID*)(pRefSurf->hdl.first);
1625 
1626         m_pipelineParam[i].surface = *srf;
1627 
1628         // source cropping
1629         mfxU32  refFourcc = pRefSurf->frameInfo.FourCC;
1630         switch (refFourcc)
1631         {
1632             case MFX_FOURCC_RGB4:
1633                 m_pipelineParam[i].surface_color_standard = VAProcColorStandardNone;
1634                 break;
1635             case MFX_FOURCC_NV12:
1636             default:
1637                 m_pipelineParam[i].surface_color_standard = VAProcColorStandardBT601;
1638                 break;
1639         }
1640 
1641         mfxU32  targetFourcc = pParams->targetSurface.frameInfo.FourCC;
1642         switch (targetFourcc)
1643         {
1644             case MFX_FOURCC_RGB4:
1645                 m_pipelineParam[i].output_color_standard = VAProcColorStandardNone;
1646                 break;
1647             case MFX_FOURCC_NV12:
1648             default:
1649                 m_pipelineParam[i].output_color_standard = VAProcColorStandardBT601;
1650                 break;
1651         }
1652 
1653         if(pParams->VideoSignalInfo[i].enabled)
1654         {
1655             if(pParams->VideoSignalInfo[i].TransferMatrix != MFX_TRANSFERMATRIX_UNKNOWN)
1656             {
1657                 m_pipelineParam[i].surface_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfo[i].TransferMatrix) ? VAProcColorStandardBT709 : VAProcColorStandardBT601;
1658             }
1659 
1660             if(pParams->VideoSignalInfo[i].NominalRange != MFX_NOMINALRANGE_UNKNOWN)
1661             {
1662                 m_pipelineParam[i].input_color_properties.color_range = (MFX_NOMINALRANGE_0_255 == pParams->VideoSignalInfo[i].NominalRange) ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
1663             }
1664         }
1665 
1666         switch (pRefSurf->frameInfo.PicStruct)
1667         {
1668             case MFX_PICSTRUCT_PROGRESSIVE:
1669                 m_pipelineParam[i].filter_flags = VA_FRAME_PICTURE;
1670                 break;
1671             case MFX_PICSTRUCT_FIELD_TFF:
1672                 m_pipelineParam[i].filter_flags = VA_TOP_FIELD;
1673                 break;
1674             case MFX_PICSTRUCT_FIELD_BFF:
1675                 m_pipelineParam[i].filter_flags = VA_BOTTOM_FIELD;
1676                 break;
1677         }
1678 
1679         /* to process input parameters of sub stream:
1680          * crop info and original size*/
1681         mfxFrameInfo *inInfo              = &(pRefSurf->frameInfo);
1682         input_region[i].y                 = inInfo->CropY;
1683         input_region[i].x                 = inInfo->CropX;
1684         input_region[i].height            = inInfo->CropH;
1685         input_region[i].width             = inInfo->CropW;
1686         m_pipelineParam[i].surface_region = &input_region[i];
1687 
1688         /* to process output parameters of sub stream:
1689          *  position and destination size */
1690         output_region[i].y               = pParams->dstRects[i].DstY;
1691         output_region[i].x               = pParams->dstRects[i].DstX;
1692         output_region[i].height          = pParams->dstRects[i].DstH;
1693         output_region[i].width           = pParams->dstRects[i].DstW;
1694         m_pipelineParam[i].output_region = &output_region[i];
1695 
1696         mfxU32 currTileId = pParams->dstRects[i].TileId;
1697 
1698         if (((currTileId > (pParams->iTilesNum4Comp - 1) )) ||
1699             (tilingParams[currTileId].numChannels >=8))
1700         {
1701             // Maximum number channels in tile is 8
1702             // fallback case
1703             return MFX_ERR_INCOMPATIBLE_VIDEO_PARAM;
1704         }
1705         else
1706         {
1707             tilingParams[currTileId].channelIds[tilingParams[currTileId].numChannels] = i;
1708             tilingParams[currTileId].numChannels++;
1709             /* lets define tiles working rectangle */
1710             if (tilingParams[currTileId].targerRect.x > output_region[i].x)
1711                 tilingParams[currTileId].targerRect.x =  output_region[i].x;
1712             if (tilingParams[currTileId].targerRect.y > output_region[i].y)
1713                 tilingParams[currTileId].targerRect.y =  output_region[i].y;
1714             if (tilingParams[currTileId].targerRect.width <
1715                     (output_region[i].x + output_region[i].width) )
1716                 tilingParams[currTileId].targerRect.width =  output_region[i].x + output_region[i].width;
1717             if (tilingParams[currTileId].targerRect.height <
1718                     (output_region[i].y + output_region[i].height) )
1719                 tilingParams[currTileId].targerRect.height =  output_region[i].y + output_region[i].height;
1720         }
1721 
1722         /* Global alpha and luma key can not be enabled together*/
1723         if (pParams->dstRects[i].GlobalAlphaEnable !=0)
1724         {
1725             blend_state[i].flags = VA_BLEND_GLOBAL_ALPHA;
1726             blend_state[i].global_alpha = ((float)pParams->dstRects[i].GlobalAlpha) /255;
1727         }
1728         /* Luma color key  for YUV surfaces only.
1729          * And Premultiplied alpha blending for RGBA surfaces only.
1730          * So, these two flags can't combine together  */
1731         if ((pParams->dstRects[i].LumaKeyEnable    != 0) &&
1732             (pParams->dstRects[i].PixelAlphaEnable == 0) )
1733         {
1734             blend_state[i].flags |= VA_BLEND_LUMA_KEY;
1735             blend_state[i].min_luma = ((float)pParams->dstRects[i].LumaKeyMin/255);
1736             blend_state[i].max_luma = ((float)pParams->dstRects[i].LumaKeyMax/255);
1737         }
1738         if ((pParams->dstRects[i].LumaKeyEnable    == 0 ) &&
1739             (pParams->dstRects[i].PixelAlphaEnable != 0 ) )
1740         {
1741             blend_state[i].flags |= VA_BLEND_PREMULTIPLIED_ALPHA;
1742         }
1743         if ((pParams->dstRects[i].GlobalAlphaEnable != 0) ||
1744             (pParams->dstRects[i].LumaKeyEnable     != 0) ||
1745             (pParams->dstRects[i].PixelAlphaEnable  != 0))
1746         {
1747             m_pipelineParam[i].blend_state = &blend_state[i];
1748         }
1749 
1750         m_pipelineParam[i].pipeline_flags |= VA_PROC_PIPELINE_SUBPICTURES;
1751         m_pipelineParam[i].filter_flags |= VA_FILTER_SCALING_HQ;
1752 
1753         m_pipelineParam[i].filters      = 0;
1754         m_pipelineParam[i].num_filters  = 0;
1755         m_pipelineParam[i].output_background_color = 0xff000000;
1756 
1757         vaSts = vaCreateBuffer(m_vaDisplay,
1758                             m_vaContextVPP,
1759                             VAProcPipelineParameterBufferType,
1760                             sizeof(VAProcPipelineParameterBuffer),
1761                             1,
1762                             &m_pipelineParam[i],
1763                             &m_pipelineParamID[i]);
1764         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1765     }
1766 
1767     VASurfaceID *outputSurface = (VASurfaceID*)(pParams->targetSurface.hdl.first);
1768     VAProcPipelineParameterBuffer outputparam = {};
1769     VABufferID vpp_pipeline_outbuf = VA_INVALID_ID;
1770 
1771     MFX_CHECK_NULL_PTR1(outputSurface);
1772 
1773     /* Process by groups. Video wall case assumes
1774      * that surfaces has the same output dimensions
1775      * We split output by several horizontal tiles */
1776     for (unsigned int currTile = 0; currTile < tilingParams.size(); currTile++)
1777     {
1778         MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaBeginPicture");
1779         vaSts = vaBeginPicture(m_vaDisplay,
1780                                m_vaContextVPP,
1781                                *outputSurface);
1782         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1783 
1784         outputparam.surface = *outputSurface;
1785         // The targerRect.width and targerRect.height here actually storing the x2 and y2
1786         // value. Deduct x and y respectively to get the exact targerRect.width and
1787         // targerRect.height
1788         tilingParams[currTile].targerRect.width  -= tilingParams[currTile].targerRect.x;
1789         tilingParams[currTile].targerRect.height -= tilingParams[currTile].targerRect.y;
1790 
1791         outputparam.output_region  = &tilingParams[currTile].targerRect;
1792         outputparam.surface_region = &tilingParams[currTile].targerRect;
1793         outputparam.output_background_color = 0;
1794 
1795         vaSts = vaCreateBuffer(m_vaDisplay,
1796                                   m_vaContextVPP,
1797                                    VAProcPipelineParameterBufferType,
1798                                    sizeof(VAProcPipelineParameterBuffer),
1799                                    1,
1800                                    &outputparam,
1801                                    &vpp_pipeline_outbuf);
1802         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1803 
1804         vaSts = vaRenderPicture(m_vaDisplay, m_vaContextVPP, &vpp_pipeline_outbuf, 1);
1805         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1806 
1807         for (unsigned int i = 0; i < tilingParams[currTile].numChannels; i++)
1808         {
1809             vaSts = vaRenderPicture(m_vaDisplay, m_vaContextVPP, &m_pipelineParamID[tilingParams[currTile].channelIds[i]], 1);
1810             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1811         }
1812         {
1813             MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaEndPicture");
1814             vaSts = vaEndPicture(m_vaDisplay, m_vaContextVPP);
1815             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1816         }
1817 
1818         sts = CheckAndDestroyVAbuffer(m_vaDisplay, vpp_pipeline_outbuf);
1819         MFX_CHECK_STS(sts);
1820     }
1821 
1822     for (VABufferID& id : m_pipelineParamID)
1823     {
1824         sts = CheckAndDestroyVAbuffer(m_vaDisplay, id);
1825         MFX_CHECK_STS(sts);
1826     }
1827 
1828     // (3) info needed for sync operation
1829     //-------------------------------------------------------
1830     {
1831         UMC::AutomaticUMCMutex guard(m_guard);
1832 
1833         ExtVASurface currentFeedback; // {surface & number_of_task}
1834         currentFeedback.surface = *outputSurface;
1835         currentFeedback.number  = pParams->statusReportID;
1836         m_feedbackCache.push_back(currentFeedback);
1837     }
1838 
1839     return MFX_ERR_NONE;
1840 } // mfxStatus VAAPIVideoProcessing::Execute_Composition_TileVideoWall(mfxExecuteParams *pParams)
1841 
Execute_Composition(mfxExecuteParams * pParams)1842 mfxStatus VAAPIVideoProcessing::Execute_Composition(mfxExecuteParams *pParams)
1843 {
1844     MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_HOTSPOTS, "VAAPIVideoProcessing::Execute_Composition");
1845 
1846     VAStatus vaSts = VA_STATUS_SUCCESS;
1847     VASurfaceAttrib attrib;
1848     std::vector<VABlendState> blend_state;
1849     VAImage imagePrimarySurface;
1850     mfxU8* pPrimarySurfaceBuffer;
1851 
1852     MFX_CHECK_NULL_PTR1( pParams );
1853     MFX_CHECK_NULL_PTR1( pParams->targetSurface.hdl.first );
1854     MFX_CHECK_NULL_PTR1( pParams->pRefSurfaces );
1855     MFX_CHECK_NULL_PTR1( pParams->pRefSurfaces[0].hdl.first );
1856 
1857     mfxU32 refCount = (mfxU32) pParams->fwdRefCount;
1858     bool hasResize = false;
1859 
1860     for(mfxU32 i = 0; i < refCount; i++)
1861     {
1862         // Check if there is a resize for input streams
1863         mfxFrameInfo *surf_info = &(pParams->pRefSurfaces[i].frameInfo);
1864         if (surf_info->CropW != pParams->dstRects[i].DstW ||
1865             surf_info->CropH != pParams->dstRects[i].DstH){
1866             hasResize = true;
1867             break;
1868         }
1869     }
1870 
1871     if ((m_primarySurface4Composition == NULL) && (pParams->bBackgroundRequired))
1872     {
1873         mfxDrvSurface* pRefSurf = &(pParams->targetSurface);
1874         mfxFrameInfo *inInfo = &(pRefSurf->frameInfo);
1875 
1876         m_primarySurface4Composition = (VASurfaceID*)calloc(1,1*sizeof(VASurfaceID));
1877         /* required to check, is memory allocated o not  */
1878         if (m_primarySurface4Composition == NULL)
1879             return MFX_ERR_MEMORY_ALLOC;
1880 
1881         attrib.type = VASurfaceAttribPixelFormat;
1882         attrib.value.type = VAGenericValueTypeInteger;
1883 
1884         unsigned int rt_format;
1885 
1886         // default format is NV12
1887         if (inInfo->FourCC == MFX_FOURCC_RGB4)
1888         {
1889             attrib.value.value.i = VA_FOURCC_ARGB;
1890             rt_format = VA_RT_FORMAT_RGB32;
1891         }
1892         else if(inInfo->FourCC == MFX_FOURCC_P010
1893                 || inInfo->FourCC == MFX_FOURCC_P210
1894 #if (MFX_VERSION >= 1027)
1895                 || inInfo->FourCC == MFX_FOURCC_Y210
1896                 || inInfo->FourCC == MFX_FOURCC_Y410
1897 #endif
1898             )
1899         {
1900             attrib.value.value.i = VA_FOURCC_P010; // We're going to flood fill this surface, so let's use most common 10-bit format
1901             rt_format = VA_RT_FORMAT_YUV420;
1902         }
1903 #if (MFX_VERSION >= 1031)
1904         else if(inInfo->FourCC == MFX_FOURCC_P016
1905                 || inInfo->FourCC == MFX_FOURCC_Y216
1906                 || inInfo->FourCC == MFX_FOURCC_Y416
1907             )
1908         {
1909             attrib.value.value.i = VA_FOURCC_P016; // We're going to flood fill this surface, so let's use most common 10-bit format
1910             rt_format = VA_RT_FORMAT_YUV420_10BPP;
1911         }
1912 #endif
1913         else
1914         {
1915             attrib.value.value.i = VA_FOURCC_NV12;
1916             rt_format = VA_RT_FORMAT_YUV420;
1917         }
1918         attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
1919 
1920         // Check what resolution is better. If input surfaces are going to be resized, then
1921         // it's better to allocate small surface for background. If there is no resize for
1922         // input streams, then it's better to allocate surface with the resolution equal to
1923         // the output stream to eliminate resize for background surface.
1924         mfxU32 width  = hasResize ? VPP_COMP_BACKGROUND_SURFACE_WIDTH  : inInfo->Width;
1925         mfxU32 height = hasResize ? VPP_COMP_BACKGROUND_SURFACE_HEIGHT : inInfo->Height;
1926 
1927         vaSts = vaCreateSurfaces(m_vaDisplay, rt_format, width, height,
1928                 m_primarySurface4Composition, 1, &attrib, 1);
1929         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1930 
1931         for ( int iPrSurfCount = 0; iPrSurfCount < 1; iPrSurfCount++)
1932         {
1933             vaSts = vaDeriveImage(m_vaDisplay, m_primarySurface4Composition[iPrSurfCount], &imagePrimarySurface);
1934             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1935 
1936             vaSts = vaMapBuffer(m_vaDisplay, imagePrimarySurface.buf, (void **) &pPrimarySurfaceBuffer);
1937             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
1938 
1939             mfxSize roiSize;
1940             roiSize.width = imagePrimarySurface.width;
1941             roiSize.height = imagePrimarySurface.height;
1942 
1943             /* We need to fill up empty surface by background color...
1944              * iBackgroundColor is now U64, with 16 bits per channel (see mfx_vpp_hw.cpp)
1945              * it is easy for ARGB format as Initial background value ARGB*/
1946             if (imagePrimarySurface.format.fourcc == VA_FOURCC_ARGB)
1947             {
1948                 uint32_t A, R, G, B;
1949                 uint32_t iBackgroundColorRGBA;
1950 
1951                 A = (uint32_t)((pParams->iBackgroundColor >> 48) & 0x00ff);
1952                 R = (uint32_t)((pParams->iBackgroundColor >> 32) & 0x00ff);
1953                 G = (uint32_t)((pParams->iBackgroundColor >> 16) & 0x00ff);
1954                 B = (uint32_t)((pParams->iBackgroundColor >>  0) & 0x00ff);
1955 
1956                 iBackgroundColorRGBA = (A << 24) | (R << 16) | (G << 8) | (B << 0);
1957 
1958                 bool setPlaneSts = SetPlaneROI<uint32_t>(iBackgroundColorRGBA, (uint32_t *)pPrimarySurfaceBuffer, imagePrimarySurface.pitches[0], roiSize);
1959                 MFX_CHECK(setPlaneSts, MFX_ERR_DEVICE_FAILED);
1960             }
1961             /* A bit more complicated for NV12 as you need to do conversion ARGB => NV12 */
1962             if (imagePrimarySurface.format.fourcc == VA_FOURCC_NV12)
1963             {
1964                 uint32_t Y = (uint32_t)((pParams->iBackgroundColor >> 32) & 0x00ff);
1965                 uint32_t U = (uint32_t)((pParams->iBackgroundColor >> 16) & 0x00ff);
1966                 uint32_t V = (uint32_t)((pParams->iBackgroundColor >>  0) & 0x00ff);
1967 
1968                 uint8_t valueY = (uint8_t) Y;
1969                 int16_t valueUV = (int16_t)((V<<8)  + U); // Keep in mind that short is stored in memory using little-endian notation
1970 
1971                 bool setPlaneSts = SetPlaneROI<uint8_t>(valueY, pPrimarySurfaceBuffer, imagePrimarySurface.pitches[0], roiSize);
1972                 MFX_CHECK(setPlaneSts, MFX_ERR_DEVICE_FAILED);
1973 
1974                 // NV12 format -> need to divide height 2 times less
1975                 roiSize.height = roiSize.height/2;
1976                 // "UV" this is short (16 bit) value already
1977                 // so need to divide width 2 times less too!
1978                 roiSize.width = roiSize.width/2;
1979                 setPlaneSts = SetPlaneROI<int16_t>(valueUV, (int16_t *)(pPrimarySurfaceBuffer + imagePrimarySurface.offsets[1]),
1980                                                 imagePrimarySurface.pitches[1], roiSize);
1981                 MFX_CHECK(setPlaneSts, MFX_ERR_DEVICE_FAILED);
1982             }
1983 
1984             if (imagePrimarySurface.format.fourcc == VA_FOURCC_P010
1985 #if (MFX_VERSION >= 1031)
1986                 || imagePrimarySurface.format.fourcc == VA_FOURCC_P016
1987 #endif
1988             )
1989             {
1990                 uint32_t Y=0;
1991                 uint32_t U=0;
1992                 uint32_t V=0;
1993                 if(imagePrimarySurface.format.fourcc == VA_FOURCC_P010 )
1994                 {
1995                     Y = (uint32_t)((pParams->iBackgroundColor >> 26) & 0xffC0);
1996                     U = (uint32_t)((pParams->iBackgroundColor >> 10) & 0xffC0);
1997                     V = (uint32_t)((pParams->iBackgroundColor <<  6) & 0xffC0);
1998                 }
1999 #if (MFX_VERSION >= 1031)
2000                 else
2001                 {
2002                     // 12 bit depth is used for these CCs
2003                     Y = (uint32_t)((pParams->iBackgroundColor >> 28) & 0xfff0);
2004                     U = (uint32_t)((pParams->iBackgroundColor >> 12) & 0xfff0);
2005                     V = (uint32_t)((pParams->iBackgroundColor <<  4) & 0xfff0);
2006                 }
2007 #endif
2008 
2009                 uint16_t valueY = (uint16_t)Y;
2010                 uint32_t valueUV = (int32_t)((V << 16) + U); // Keep in mind that short is stored in memory using little-endian notation
2011 
2012                 bool setPlaneSts = SetPlaneROI<uint16_t>(valueY, (uint16_t*)pPrimarySurfaceBuffer, imagePrimarySurface.pitches[0], roiSize);
2013                 MFX_CHECK(setPlaneSts, MFX_ERR_DEVICE_FAILED);
2014 
2015                 // NV12 format -> need to divide height 2 times less
2016                 roiSize.height = roiSize.height / 2;
2017                 // "UV" encodes 2 pixels in a row
2018                 // so need to divide width 2 times
2019                 roiSize.width = roiSize.width / 2;
2020                 setPlaneSts = SetPlaneROI<uint32_t>(valueUV, (uint32_t *)(pPrimarySurfaceBuffer + imagePrimarySurface.offsets[1]),
2021                     imagePrimarySurface.pitches[1], roiSize);
2022                 MFX_CHECK(setPlaneSts, MFX_ERR_DEVICE_FAILED);
2023             }
2024 
2025             vaSts = vaUnmapBuffer(m_vaDisplay, imagePrimarySurface.buf);
2026             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2027             vaSts = vaDestroyImage(m_vaDisplay, imagePrimarySurface.image_id);
2028             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2029         } // for ( int iPrSurfCount = 0; iPrSurfCount < 3; iPrSurfCount++)
2030     }
2031 
2032     /* pParams->refCount is total number of processing surfaces:
2033      * in case of composition this is primary + sub streams*/
2034 
2035     mfxU32 SampleCount = 1;
2036     mfxU32 refIdx = 0;
2037 
2038     m_pipelineParam.resize(pParams->refCount + 1);
2039     m_pipelineParamID.resize(pParams->refCount + 1, VA_INVALID_ID);
2040     blend_state.resize(pParams->refCount + 1);
2041 
2042     std::vector<VARectangle> input_region;
2043     input_region.resize(pParams->refCount + 1);
2044     std::vector<VARectangle> output_region;
2045     output_region.resize(pParams->refCount + 1);
2046     VASurfaceID *outputSurface = (VASurfaceID*)(pParams->targetSurface.hdl.first);
2047 
2048     for( refIdx = 0; refIdx < SampleCount; refIdx++ )
2049     {
2050         mfxDrvSurface* pRefSurf = &(pParams->targetSurface);
2051         memset(&m_pipelineParam[refIdx], 0, sizeof(m_pipelineParam[refIdx]));
2052 
2053         //VASurfaceID* srf_1 = (VASurfaceID*)(pRefSurf->hdl.first);
2054         //m_pipelineParam[refIdx].surface = *srf_1;
2055         /* First "primary" surface should be our allocated empty surface filled by background color.
2056          * Else we can not process first input surface as usual one */
2057         if (pParams->bBackgroundRequired)
2058             m_pipelineParam[refIdx].surface = m_primarySurface4Composition[0];
2059         //VASurfaceID *outputSurface = (VASurfaceID*)(pParams->targetSurface.hdl.first);
2060         //m_pipelineParam[refIdx].surface = *outputSurface;
2061 
2062         // source cropping
2063         //mfxFrameInfo *inInfo = &(pRefSurf->frameInfo);
2064         mfxFrameInfo *outInfo = &(pParams->targetSurface.frameInfo);
2065         input_region[refIdx].y   = 0;
2066         input_region[refIdx].x   = 0;
2067         input_region[refIdx].height = outInfo->CropH;
2068         input_region[refIdx].width  = outInfo->CropW;
2069         m_pipelineParam[refIdx].surface_region = &input_region[refIdx];
2070 
2071         // destination cropping
2072         //mfxFrameInfo *outInfo = &(pParams->targetSurface.frameInfo);
2073         output_region[refIdx].y  = 0; //outInfo->CropY;
2074         output_region[refIdx].x   = 0; //outInfo->CropX;
2075         output_region[refIdx].height= outInfo->CropH;
2076         output_region[refIdx].width  = outInfo->CropW;
2077         m_pipelineParam[refIdx].output_region = &output_region[refIdx];
2078 
2079         /* Actually as background color managed by "m_primarySurface4Composition" surface
2080          * this param will not make sense */
2081         //m_pipelineParam[refIdx].output_background_color = pParams->iBackgroundColor;
2082 
2083         mfxU32  refFourcc = pRefSurf->frameInfo.FourCC;
2084         switch (refFourcc)
2085         {
2086         case MFX_FOURCC_RGB4:
2087             m_pipelineParam[refIdx].surface_color_standard = VAProcColorStandardNone;
2088             break;
2089         case MFX_FOURCC_NV12:
2090         default:
2091             m_pipelineParam[refIdx].surface_color_standard = VAProcColorStandardBT601;
2092             break;
2093         }
2094 
2095         mfxU32  targetFourcc = pParams->targetSurface.frameInfo.FourCC;
2096         switch (targetFourcc)
2097         {
2098         case MFX_FOURCC_RGB4:
2099             m_pipelineParam[refIdx].output_color_standard = VAProcColorStandardNone;
2100             break;
2101         case MFX_FOURCC_NV12:
2102         default:
2103             m_pipelineParam[refIdx].output_color_standard = VAProcColorStandardBT601;
2104             break;
2105         }
2106 
2107         if(refIdx > 0 && pParams->VideoSignalInfo[refIdx-1].enabled)
2108         {
2109             if(pParams->VideoSignalInfo[refIdx-1].TransferMatrix != MFX_TRANSFERMATRIX_UNKNOWN)
2110             {
2111                 m_pipelineParam[refIdx].surface_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfo[refIdx-1].TransferMatrix) ? VAProcColorStandardBT709 : VAProcColorStandardBT601;
2112             }
2113 
2114             if(pParams->VideoSignalInfo[refIdx-1].NominalRange != MFX_NOMINALRANGE_UNKNOWN)
2115             {
2116                 m_pipelineParam[refIdx].input_color_properties.color_range = (MFX_NOMINALRANGE_0_255 == pParams->VideoSignalInfo[refIdx-1].NominalRange) ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
2117             }
2118         }
2119 
2120         if (pParams->VideoSignalInfoOut.enabled)
2121         {
2122             if(pParams->VideoSignalInfoOut.TransferMatrix != MFX_TRANSFERMATRIX_UNKNOWN)
2123             {
2124                 m_pipelineParam[refIdx].output_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfoOut.TransferMatrix ? VAProcColorStandardBT709 : VAProcColorStandardBT601);
2125             }
2126 
2127             if(pParams->VideoSignalInfoOut.NominalRange != MFX_NOMINALRANGE_UNKNOWN)
2128             {
2129                 m_pipelineParam[refIdx].output_color_properties.color_range = (MFX_NOMINALRANGE_0_255 == pParams->VideoSignalInfoOut.NominalRange) ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
2130             }
2131         }
2132         m_pipelineParam[refIdx].input_color_properties.chroma_sample_location  = VA_CHROMA_SITING_UNKNOWN;
2133         m_pipelineParam[refIdx].output_color_properties.chroma_sample_location = VA_CHROMA_SITING_UNKNOWN;
2134 
2135         switch (pRefSurf->frameInfo.PicStruct)
2136         {
2137             case MFX_PICSTRUCT_PROGRESSIVE:
2138             default:
2139                 m_pipelineParam[refIdx].filter_flags = VA_FRAME_PICTURE;
2140                 break;
2141         }
2142 
2143         m_pipelineParam[refIdx].filters  = m_filterBufs;
2144         m_pipelineParam[refIdx].num_filters  = m_numFilterBufs;
2145         /* Special case for composition:
2146          * as primary surface processed as sub-stream
2147          * pipeline and filter properties should be *_FAST */
2148         if (pParams->bComposite)
2149         {
2150             m_pipelineParam[refIdx].num_filters  = 0;
2151 
2152             if (m_pipelineCaps.pipeline_flags & VA_PROC_PIPELINE_FAST)
2153                 m_pipelineParam[refIdx].pipeline_flags  |= VA_PROC_PIPELINE_FAST;
2154             else
2155                 m_pipelineParam[refIdx].pipeline_flags |= VA_PROC_PIPELINE_SUBPICTURES;
2156 
2157             if (m_pipelineCaps.filter_flags & VA_FILTER_SCALING_HQ)
2158                 m_pipelineParam[refIdx].filter_flags |= VA_FILTER_SCALING_HQ;
2159         }
2160     }
2161 
2162     {
2163         MFX_LTRACE_2(MFX_TRACE_LEVEL_HOTSPOTS, "A|VPP|COMP|PACKET_START|", "%d|%d", m_vaContextVPP, 0);
2164         {
2165             MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_SCHED, "vaBeginPicture");
2166             vaSts = vaBeginPicture(m_vaDisplay,
2167                                 m_vaContextVPP,
2168                                 *outputSurface);
2169             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2170         }
2171     }
2172 
2173     if (pParams->bBackgroundRequired)
2174     {
2175         refIdx = 0;
2176         vaSts = vaCreateBuffer(m_vaDisplay,
2177                             m_vaContextVPP,
2178                             VAProcPipelineParameterBufferType,
2179                             sizeof(VAProcPipelineParameterBuffer),
2180                             1,
2181                             &m_pipelineParam[refIdx],
2182                             &m_pipelineParamID[refIdx]);
2183         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2184 
2185         {
2186             MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_SCHED, "vaRenderPicture");
2187             for( refIdx = 0; refIdx < SampleCount; refIdx++ )
2188             {
2189                 vaSts = vaRenderPicture(m_vaDisplay, m_vaContextVPP, &m_pipelineParamID[refIdx], 1);
2190                 MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2191             }
2192         }
2193     } // if (pParams->bBackgroundRequired)
2194 
2195     unsigned int uBeginPictureCounter = 0;
2196     std::vector<VAProcPipelineParameterBuffer> m_pipelineParamComp;
2197     std::vector<VABufferID> m_pipelineParamCompID;
2198     /* for new buffers for Begin Picture*/
2199     m_pipelineParamComp.resize(pParams->fwdRefCount/7);
2200     m_pipelineParamCompID.resize(pParams->fwdRefCount/7, VA_INVALID_ID);
2201 
2202     /* pParams->fwdRefCount actually is number of sub stream*/
2203     for( refIdx = 1; refIdx <= (refCount + 1); refIdx++ )
2204     {
2205         /*for frames 8, 15, 22, 29,... */
2206         if ((refIdx != 1) && ((refIdx %7) == 1) )
2207         {
2208             {
2209                 vaSts = vaBeginPicture(m_vaDisplay,
2210                                     m_vaContextVPP,
2211                                     *outputSurface);
2212             }
2213             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2214             /*to copy initial properties of primary surface... */
2215             m_pipelineParamComp[uBeginPictureCounter] = m_pipelineParam[0];
2216             /* ... and to In-place output*/
2217             //m_pipelineParamComp[uBeginPictureCounter].surface = m_primarySurface4Composition[uInputIndex];
2218             m_pipelineParamComp[uBeginPictureCounter].surface = *outputSurface;
2219             //m_pipelineParam[0].surface = *outputSurface;
2220             /* As used IN-PLACE variant of Composition
2221              * this values does not used*/
2222             //uOutputIndex++;
2223             //uInputIndex++;
2224             //if (uOutputIndex > 2)
2225             //    uOutputIndex = 0;
2226             //if (uInputIndex > 2)
2227             //    uInputIndex = 0;
2228 
2229             switch (pParams->targetSurface.frameInfo.FourCC)
2230             {
2231             case MFX_FOURCC_RGB4:
2232                 m_pipelineParamComp[uBeginPictureCounter].surface_color_standard = VAProcColorStandardNone;
2233                 break;
2234             case MFX_FOURCC_NV12:
2235             default:
2236                 m_pipelineParamComp[uBeginPictureCounter].surface_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfoOut.TransferMatrix) ? VAProcColorStandardBT709 : VAProcColorStandardBT601;
2237                 break;
2238             }
2239 
2240             vaSts = vaCreateBuffer(m_vaDisplay,
2241                                 m_vaContextVPP,
2242                                 VAProcPipelineParameterBufferType,
2243                                 sizeof(VAProcPipelineParameterBuffer),
2244                                 1,
2245                                 &m_pipelineParamComp[uBeginPictureCounter],
2246                                 &m_pipelineParamCompID[uBeginPictureCounter]);
2247             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2248 
2249             MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_SCHED, "vaBeginPicture");
2250             vaSts = vaRenderPicture(m_vaDisplay, m_vaContextVPP, &m_pipelineParamCompID[uBeginPictureCounter], 1);
2251             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2252 
2253             uBeginPictureCounter++;
2254         }
2255 
2256         m_pipelineParam[refIdx] = m_pipelineParam[0];
2257 
2258         mfxDrvSurface* pRefSurf = &(pParams->pRefSurfaces[refIdx-1]);
2259 
2260         VASurfaceID* srf_2 = (VASurfaceID*)(pRefSurf->hdl.first);
2261 
2262         m_pipelineParam[refIdx].surface = *srf_2;
2263 
2264         mfxU32  refFourcc = pRefSurf->frameInfo.FourCC;
2265         switch (refFourcc)
2266         {
2267         case MFX_FOURCC_RGB4:
2268             m_pipelineParam[refIdx].surface_color_standard = VAProcColorStandardNone;
2269             break;
2270         case MFX_FOURCC_NV12:
2271         default:
2272             m_pipelineParam[refIdx].surface_color_standard = VAProcColorStandardBT601;
2273             break;
2274         }
2275 
2276         if(refIdx > 0 && pParams->VideoSignalInfo[refIdx-1].enabled)
2277         {
2278             if(pParams->VideoSignalInfo[refIdx-1].TransferMatrix != MFX_TRANSFERMATRIX_UNKNOWN)
2279             {
2280                 m_pipelineParam[refIdx].surface_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfo[refIdx-1].TransferMatrix ? VAProcColorStandardBT709 : VAProcColorStandardBT601);
2281             }
2282 
2283             if(pParams->VideoSignalInfo[refIdx-1].NominalRange != MFX_NOMINALRANGE_UNKNOWN)
2284             {
2285                 m_pipelineParam[refIdx].input_color_properties.color_range = (MFX_NOMINALRANGE_0_255 == pParams->VideoSignalInfo[refIdx-1].NominalRange) ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
2286             }
2287         }
2288 
2289         if (pParams->VideoSignalInfoOut.enabled)
2290         {
2291             if(pParams->VideoSignalInfoOut.TransferMatrix != MFX_TRANSFERMATRIX_UNKNOWN)
2292             {
2293                 m_pipelineParam[refIdx].output_color_standard = (MFX_TRANSFERMATRIX_BT709 == pParams->VideoSignalInfoOut.TransferMatrix ? VAProcColorStandardBT709 : VAProcColorStandardBT601);
2294             }
2295 
2296             if(pParams->VideoSignalInfoOut.NominalRange != MFX_NOMINALRANGE_UNKNOWN)
2297             {
2298                 m_pipelineParam[refIdx].output_color_properties.color_range = (MFX_NOMINALRANGE_0_255 == pParams->VideoSignalInfoOut.NominalRange) ? VA_SOURCE_RANGE_FULL : VA_SOURCE_RANGE_REDUCED;
2299             }
2300         }
2301         m_pipelineParam[refIdx].input_color_properties.chroma_sample_location  = VA_CHROMA_SITING_UNKNOWN;
2302         m_pipelineParam[refIdx].output_color_properties.chroma_sample_location = VA_CHROMA_SITING_UNKNOWN;
2303 
2304         /* to process input parameters of sub stream:
2305          * crop info and original size*/
2306         mfxFrameInfo *inInfo = &(pRefSurf->frameInfo);
2307         input_region[refIdx].y   = inInfo->CropY;
2308         input_region[refIdx].x   = inInfo->CropX;
2309         input_region[refIdx].height = inInfo->CropH;
2310         input_region[refIdx].width  = inInfo->CropW;
2311         m_pipelineParam[refIdx].surface_region = &input_region[refIdx];
2312 
2313         /* to process output parameters of sub stream:
2314          *  position and destination size */
2315         output_region[refIdx].y  = pParams->dstRects[refIdx-1].DstY;
2316         output_region[refIdx].x   = pParams->dstRects[refIdx-1].DstX;
2317         output_region[refIdx].height= pParams->dstRects[refIdx-1].DstH;
2318         output_region[refIdx].width  = pParams->dstRects[refIdx-1].DstW;
2319         m_pipelineParam[refIdx].output_region = &output_region[refIdx];
2320 
2321         /* Global alpha and luma key can not be enabled together*/
2322         /* Global alpha and luma key can not be enabled together*/
2323         if (pParams->dstRects[refIdx-1].GlobalAlphaEnable !=0)
2324         {
2325             blend_state[refIdx].flags = VA_BLEND_GLOBAL_ALPHA;
2326             blend_state[refIdx].global_alpha = ((float)pParams->dstRects[refIdx-1].GlobalAlpha) /255;
2327         }
2328         /* Luma color key  for YUV surfaces only.
2329          * And Premultiplied alpha blending for RGBA surfaces only.
2330          * So, these two flags can't combine together  */
2331         if ((pParams->dstRects[refIdx-1].LumaKeyEnable != 0) &&
2332             (pParams->dstRects[refIdx-1].PixelAlphaEnable == 0) )
2333         {
2334             blend_state[refIdx].flags |= VA_BLEND_LUMA_KEY;
2335             blend_state[refIdx].min_luma = ((float)pParams->dstRects[refIdx-1].LumaKeyMin/255);
2336             blend_state[refIdx].max_luma = ((float)pParams->dstRects[refIdx-1].LumaKeyMax/255);
2337         }
2338         if ((pParams->dstRects[refIdx-1].LumaKeyEnable == 0 ) &&
2339             (pParams->dstRects[refIdx-1].PixelAlphaEnable != 0 ) )
2340         {
2341             /* Per-pixel alpha case. Having VA_BLEND_PREMULTIPLIED_ALPHA as a parameter
2342              * leads to using BLEND_PARTIAL approach by driver that may produce
2343              * "white line"-like artifacts on transparent-opaque borders.
2344              * Setting nothing here triggers using a BLEND_SOURCE approach that is used on
2345              * Windows and looks to be free of such kind of artifacts */
2346             blend_state[refIdx].flags |= 0;
2347         }
2348         if ((pParams->dstRects[refIdx-1].GlobalAlphaEnable != 0) ||
2349                 (pParams->dstRects[refIdx-1].LumaKeyEnable != 0) ||
2350                 (pParams->dstRects[refIdx-1].PixelAlphaEnable != 0))
2351         {
2352             m_pipelineParam[refIdx].blend_state = &blend_state[refIdx];
2353         }
2354 
2355         //m_pipelineParam[refIdx].pipeline_flags = ?? //VA_PROC_PIPELINE_FAST or VA_PROC_PIPELINE_SUBPICTURES
2356         m_pipelineParam[refIdx].pipeline_flags  |= VA_PROC_PIPELINE_FAST;
2357         m_pipelineParam[refIdx].filter_flags    |= VA_FILTER_SCALING_FAST;
2358 
2359         m_pipelineParam[refIdx].filters  = m_filterBufs;
2360         m_pipelineParam[refIdx].num_filters  = 0;
2361 
2362         vaSts = vaCreateBuffer(m_vaDisplay,
2363                             m_vaContextVPP,
2364                             VAProcPipelineParameterBufferType,
2365                             sizeof(VAProcPipelineParameterBuffer),
2366                             1,
2367                             &m_pipelineParam[refIdx],
2368                             &m_pipelineParamID[refIdx]);
2369         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2370 
2371         MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_SCHED, "vaRenderPicture");
2372         vaSts = vaRenderPicture(m_vaDisplay, m_vaContextVPP, &m_pipelineParamID[refIdx], 1);
2373         MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2374 
2375         /*for frames 7, 14, 21, ...
2376          * or for the last frame*/
2377         if ( ((refIdx % 7) ==0) || ((refCount + 1) == refIdx) )
2378         {
2379             MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_SCHED, "vaEndPicture");
2380             vaSts = vaEndPicture(m_vaDisplay, m_vaContextVPP);
2381             MFX_CHECK_WITH_ASSERT(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2382         }
2383     } /* for( refIdx = 1; refIdx <= (pParams->fwdRefCount); refIdx++ )*/
2384     MFX_LTRACE_2(MFX_TRACE_LEVEL_HOTSPOTS, "A|VPP|COMP|PACKET_END|", "%d|%d", m_vaContextVPP, 0);
2385 
2386     mfxStatus sts;
2387     for (VABufferID& id : m_pipelineParamCompID)
2388     {
2389         sts = CheckAndDestroyVAbuffer(m_vaDisplay, id);
2390         MFX_CHECK_STS(sts);
2391     }
2392 
2393     for (VABufferID& id : m_pipelineParamID)
2394     {
2395         sts = CheckAndDestroyVAbuffer(m_vaDisplay, id);
2396         MFX_CHECK_STS(sts);
2397     }
2398 
2399     // (3) info needed for sync operation
2400     //-------------------------------------------------------
2401     {
2402         UMC::AutomaticUMCMutex guard(m_guard);
2403 
2404         ExtVASurface currentFeedback; // {surface & number_of_task}
2405         currentFeedback.surface = *outputSurface;
2406         currentFeedback.number = pParams->statusReportID;
2407         m_feedbackCache.push_back(currentFeedback);
2408     }
2409 
2410     return MFX_ERR_NONE;
2411 } // mfxStatus VAAPIVideoProcessing::Execute_Composition(mfxExecuteParams *pParams)
2412 #else
Execute_Composition_TiledVideoWall(mfxExecuteParams * pParams)2413 mfxStatus VAAPIVideoProcessing::Execute_Composition_TiledVideoWall(mfxExecuteParams *pParams)
2414 {
2415     return MFX_ERR_UNSUPPORTED;
2416 }
2417 
Execute_Composition(mfxExecuteParams * pParams)2418 mfxStatus VAAPIVideoProcessing::Execute_Composition(mfxExecuteParams *pParams)
2419 {
2420     return MFX_ERR_UNSUPPORTED;
2421 }
2422 #endif //#ifdef MFX_ENABLE_VPP_COMPOSITION
2423 
QueryTaskStatus(mfxU32 taskIndex)2424 mfxStatus VAAPIVideoProcessing::QueryTaskStatus(mfxU32 taskIndex)
2425 {
2426     VASurfaceID waitSurface = VA_INVALID_SURFACE;
2427     mfxU32 indxSurf = 0;
2428 
2429     // (1) find params (sutface & number) are required by feedbackNumber
2430     //-----------------------------------------------
2431     {
2432         UMC::AutomaticUMCMutex guard(m_guard);
2433 
2434         for (indxSurf = 0; indxSurf < m_feedbackCache.size(); indxSurf++)
2435         {
2436             if (m_feedbackCache[indxSurf].number == taskIndex)
2437             {
2438                 waitSurface = m_feedbackCache[indxSurf].surface;
2439                 break;
2440             }
2441         }
2442         if (VA_INVALID_SURFACE == waitSurface)
2443         {
2444             return MFX_ERR_UNKNOWN;
2445         }
2446 
2447         m_feedbackCache.erase(m_feedbackCache.begin() + indxSurf);
2448     }
2449 
2450 #if !defined(ANDROID)
2451     {
2452         MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_EXTCALL, "vaSyncSurface");
2453         VAStatus vaSts = vaSyncSurface(m_vaDisplay, waitSurface);
2454         if (vaSts == VA_STATUS_ERROR_HW_BUSY)
2455             return MFX_ERR_GPU_HANG;
2456         else
2457             MFX_CHECK(VA_STATUS_SUCCESS == vaSts, MFX_ERR_DEVICE_FAILED);
2458     }
2459 #endif
2460 
2461     return MFX_TASK_DONE;
2462 } // mfxStatus VAAPIVideoProcessing::QueryTaskStatus(mfxU32 taskIndex)
2463 
2464 #endif // #if defined (MFX_VA_LINUX)
2465 #endif // #if defined (MFX_VPP_ENABLE)
2466 /* EOF */
2467