1 // Copyright (c) 2017-2019 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 <mfxvideo.h>
22 
23 #include <mfx_session.h>
24 #include <mfx_tools.h>
25 #include <mfx_common.h>
26 #include <mfx_user_plugin.h>
27 
28 // sheduling and threading stuff
29 #include <mfx_task.h>
30 
31 #ifdef MFX_ENABLE_VPP
32 // VPP include files here
33 #include "mfx_vpp_main.h"       // this VideoVPP class builds VPP pipeline and run the VPP pipeline
34 #endif
35 
36 template<>
Create(mfxVideoParam &)37 VideoVPP* _mfxSession::Create<VideoVPP>(mfxVideoParam& /*par*/)
38 {
39     VideoVPP *pVPP = nullptr;
40 
41 #ifdef MFX_ENABLE_VPP
42     VideoCORE* core = m_pCORE.get();
43     mfxStatus mfxRes = MFX_ERR_MEMORY_ALLOC;
44 
45     pVPP = new VideoVPPMain(core, &mfxRes);
46     if (MFX_ERR_NONE != mfxRes)
47     {
48         delete pVPP;
49         pVPP = nullptr;
50     }
51 #endif // MFX_ENABLE_VPP
52 
53     return pVPP;
54 }
55 
MFXVideoVPP_Query(mfxSession session,mfxVideoParam * in,mfxVideoParam * out)56 mfxStatus MFXVideoVPP_Query(mfxSession session, mfxVideoParam *in, mfxVideoParam *out)
57 {
58     MFX_AUTO_LTRACE_FUNC(MFX_TRACE_LEVEL_API);
59     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, in);
60 
61     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
62     MFX_CHECK(out, MFX_ERR_NULL_PTR);
63 
64     if ((0 != in) && (MFX_HW_VAAPI == session->m_pCORE->GetVAType()))
65     {
66         // protected content not supported on Linux
67         if(0 != in->Protected)
68         {
69             out->Protected = 0;
70             return MFX_ERR_UNSUPPORTED;
71         }
72     }
73 
74     mfxStatus mfxRes = MFX_ERR_UNSUPPORTED;
75     try
76     {
77 #ifdef MFX_ENABLE_USER_VPP
78         if (session->m_plgVPP.get())
79         {
80             mfxRes = session->m_plgVPP->Query(session->m_pCORE.get(), in, out);
81         }
82         else
83         {
84 #endif
85 
86 #ifdef MFX_ENABLE_VPP
87             mfxRes = VideoVPPMain::Query(session->m_pCORE.get(), in, out);
88 #endif // MFX_ENABLE_VPP
89 
90 #ifdef MFX_ENABLE_USER_VPP
91         }
92 #endif
93     }
94     // handle error(s)
95     catch(...)
96     {
97         mfxRes = MFX_ERR_NULL_PTR;
98     }
99 
100     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, out);
101     MFX_LTRACE_I(MFX_TRACE_LEVEL_PARAMS, mfxRes);
102     return mfxRes;
103 }
104 
MFXVideoVPP_QueryIOSurf(mfxSession session,mfxVideoParam * par,mfxFrameAllocRequest * request)105 mfxStatus MFXVideoVPP_QueryIOSurf(mfxSession session, mfxVideoParam *par, mfxFrameAllocRequest *request)
106 {
107     MFX_AUTO_LTRACE_FUNC(MFX_TRACE_LEVEL_API);
108     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, par);
109 
110     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
111     MFX_CHECK(par, MFX_ERR_NULL_PTR);
112     MFX_CHECK(request, MFX_ERR_NULL_PTR);
113 
114     mfxStatus mfxRes = MFX_ERR_UNSUPPORTED;
115     try
116     {
117 #ifdef MFX_ENABLE_USER_VPP
118         if (session->m_plgVPP.get())
119         {
120             mfxRes = session->m_plgVPP->QueryIOSurf(session->m_pCORE.get(), par, &(request[0]),  &(request[1]) );
121         }
122         else
123         {
124 #endif
125 
126 #ifdef MFX_ENABLE_VPP
127             mfxRes = VideoVPPMain::QueryIOSurf(session->m_pCORE.get(), par, request/*, session->m_adapterNum*/);
128 #endif // MFX_ENABLE_VPP
129 
130 #ifdef MFX_ENABLE_USER_VPP
131         }
132 #endif
133     }
134     // handle error(s)
135     catch(...)
136     {
137         mfxRes = MFX_ERR_NULL_PTR;
138     }
139 
140     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, request);
141     MFX_LTRACE_I(MFX_TRACE_LEVEL_PARAMS, mfxRes);
142     return mfxRes;
143 }
144 
MFXVideoVPP_Init(mfxSession session,mfxVideoParam * par)145 mfxStatus MFXVideoVPP_Init(mfxSession session, mfxVideoParam *par)
146 {
147     mfxStatus mfxRes = MFX_ERR_UNSUPPORTED;
148 
149     MFX_AUTO_LTRACE_FUNC(MFX_TRACE_LEVEL_API);
150     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, par);
151 
152     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
153     MFX_CHECK(par, MFX_ERR_NULL_PTR);
154 
155     try
156     {
157         // check existence of component
158         if (!session->m_pVPP)
159         {
160             // create a new instance
161             session->m_pVPP.reset(session->Create<VideoVPP>(*par));
162 #ifdef MFX_ENABLE_VPP
163             MFX_CHECK(session->m_pVPP.get(), MFX_ERR_INVALID_VIDEO_PARAM);
164 #else
165             MFX_CHECK(session->m_pVPP.get(), MFX_ERR_UNSUPPORTED);
166 #endif
167         }
168 
169         // create a new instance
170         mfxRes = session->m_pVPP->Init(par);
171     }
172     // handle error(s)
173     catch(...)
174     {
175         // set the default error value
176         mfxRes = MFX_ERR_UNKNOWN;
177     }
178 
179     MFX_LTRACE_I(MFX_TRACE_LEVEL_PARAMS, mfxRes);
180     return mfxRes;
181 }
182 
MFXVideoVPP_Close(mfxSession session)183 mfxStatus MFXVideoVPP_Close(mfxSession session)
184 {
185     mfxStatus mfxRes;
186 
187     MFX_AUTO_LTRACE_FUNC(MFX_TRACE_LEVEL_API);
188 
189     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
190     MFX_CHECK(session->m_pScheduler, MFX_ERR_NOT_INITIALIZED);
191 
192     try
193     {
194         if (!session->m_pVPP)
195         {
196             return MFX_ERR_NOT_INITIALIZED;
197         }
198 
199         // wait until all tasks are processed
200         session->m_pScheduler->WaitForAllTasksCompletion(session->m_pVPP.get());
201 
202         mfxRes = session->m_pVPP->Close();
203         // delete the codec's instance if not plugin
204         if (!session->m_plgVPP)
205         {
206             session->m_pVPP.reset(nullptr);
207         }
208     }
209     // handle error(s)
210     catch(...)
211     {
212         // set the default error value
213         mfxRes = MFX_ERR_UNKNOWN;
214     }
215 
216     MFX_LTRACE_I(MFX_TRACE_LEVEL_PARAMS, mfxRes);
217     return mfxRes;
218 }
219 
220 static
MFXVideoVPPLegacyRoutine(void * pState,void * pParam,mfxU32 threadNumber,mfxU32)221 mfxStatus MFXVideoVPPLegacyRoutine(void *pState, void *pParam,
222                                    mfxU32 threadNumber, mfxU32 /* callNumber */)
223 {
224     MFX_AUTO_LTRACE_FUNC(MFX_TRACE_LEVEL_API);
225     VideoVPP *pVPP = (VideoVPP *) pState;
226     MFX_THREAD_TASK_PARAMETERS *pTaskParam = (MFX_THREAD_TASK_PARAMETERS *) pParam;
227     mfxStatus mfxRes;
228 
229     // check error(s)
230     if ((NULL == pState) ||
231         (NULL == pParam) ||
232         (0 != threadNumber))
233     {
234         return MFX_ERR_NULL_PTR;
235     }
236 
237     // call the obsolete method
238     mfxRes = pVPP->RunFrameVPP(pTaskParam->vpp.in,
239                                pTaskParam->vpp.out,
240                                pTaskParam->vpp.aux);
241 
242     return mfxRes;
243 
244 } // mfxStatus MFXVideoVPPLegacyRoutine(void *pState, void *pParam,
245 
246 enum
247 {
248     MFX_NUM_ENTRY_POINTS = 2
249 };
250 
MFXVideoVPP_RunFrameVPPAsync(mfxSession session,mfxFrameSurface1 * in,mfxFrameSurface1 * out,mfxExtVppAuxData * aux,mfxSyncPoint * syncp)251 mfxStatus MFXVideoVPP_RunFrameVPPAsync(mfxSession session, mfxFrameSurface1 *in, mfxFrameSurface1 *out, mfxExtVppAuxData *aux, mfxSyncPoint *syncp)
252 {
253     mfxStatus mfxRes;
254 
255     MFX_AUTO_LTRACE_WITHID(MFX_TRACE_LEVEL_API, "MFX_RunFrameVPPAsync");
256     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, aux);
257     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, in);
258 
259     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
260     MFX_CHECK(session->m_pVPP.get(), MFX_ERR_NOT_INITIALIZED);
261     MFX_CHECK(syncp, MFX_ERR_NULL_PTR);
262 
263     try
264     {
265 #ifdef MFX_ENABLE_USER_VPP
266       if (session->m_plgVPP.get())
267       {
268           MFX_TASK task;
269           mfxSyncPoint syncPoint = NULL;
270           *syncp = NULL;
271           memset(&task, 0, sizeof(MFX_TASK));
272 
273           mfxRes = session->m_plgVPP->VPPFrameCheck(in, out, aux, &task.entryPoint);
274 
275           if (task.entryPoint.pRoutine)
276           {
277               mfxStatus mfxAddRes;
278 
279               task.pOwner = session->m_plgVPP.get();
280               task.priority = session->m_priority;
281               task.threadingPolicy = session->m_plgVPP->GetThreadingPolicy();
282               // fill dependencies
283               task.pSrc[0] = in;
284               task.pDst[0] = out;
285               if (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes))
286                 task.pDst[0] = NULL;
287 
288               #ifdef MFX_TRACE_ENABLE
289               task.nParentId = MFX_AUTO_TRACE_GETID();
290               task.nTaskId = MFX::CreateUniqId() + MFX_TRACE_ID_VPP;
291               #endif
292 
293               // register input and call the task
294               mfxAddRes = session->m_pScheduler->AddTask(task, &syncPoint);
295               if (MFX_ERR_NONE != mfxAddRes)
296               {
297                   return mfxAddRes;
298               }
299               *syncp = syncPoint;
300           }
301       }
302       else
303       {
304 #endif
305         mfxSyncPoint syncPoint = NULL;
306         MFX_ENTRY_POINT entryPoints[MFX_NUM_ENTRY_POINTS];
307         mfxU32 numEntryPoints = MFX_NUM_ENTRY_POINTS;
308 
309         memset(&entryPoints, 0, sizeof(entryPoints));
310         mfxRes = session->m_pVPP->VppFrameCheck(in, out, aux, entryPoints, numEntryPoints);
311         // source data is OK, go forward
312         if ((MFX_ERR_NONE == mfxRes) ||
313             (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes)) ||
314             (MFX_ERR_MORE_SURFACE == mfxRes) ||
315             (MFX_WRN_INCOMPATIBLE_VIDEO_PARAM == mfxRes))
316         {
317             // prepare the absolete kind of task.
318             // it is absolete and must be removed.
319             if (NULL == entryPoints[0].pRoutine)
320             {
321                 MFX_TASK task;
322 
323                 memset(&task, 0, sizeof(task));
324                 // BEGIN OF OBSOLETE PART
325                 task.bObsoleteTask = true;
326                 // fill task info
327                 task.pOwner = session->m_pVPP.get();
328                 task.entryPoint.pRoutine = &MFXVideoVPPLegacyRoutine;
329                 task.entryPoint.pState = session->m_pVPP.get();
330                 task.entryPoint.requiredNumThreads = 1;
331 
332                 // fill legacy parameters
333                 task.obsolete_params.vpp.in = in;
334                 task.obsolete_params.vpp.out = out;
335                 task.obsolete_params.vpp.aux = aux;
336                 // END OF OBSOLETE PART
337 
338                 task.priority = session->m_priority;
339                 task.threadingPolicy = session->m_pVPP->GetThreadingPolicy();
340                 // fill dependencies
341                 task.pSrc[0] = in;
342                 task.pDst[0] = out;
343 
344                 if (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes))
345                     task.pDst[0] = NULL;
346 
347 #ifdef MFX_TRACE_ENABLE
348                 task.nParentId = MFX_AUTO_TRACE_GETID();
349                 task.nTaskId = MFX::CreateUniqId() + MFX_TRACE_ID_VPP;
350 #endif // MFX_TRACE_ENABLE
351 
352                 // register input and call the task
353                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
354             }
355             else if (1 == numEntryPoints)
356             {
357                 MFX_TASK task;
358 
359                 memset(&task, 0, sizeof(task));
360                 task.pOwner = session->m_pVPP.get();
361                 task.entryPoint = entryPoints[0];
362                 task.priority = session->m_priority;
363                 task.threadingPolicy = session->m_pVPP->GetThreadingPolicy();
364                 // fill dependencies
365                 task.pSrc[0] = in;
366                 task.pDst[0] = out;
367                 if (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes))
368                     task.pDst[0] = NULL;
369 
370 
371 #ifdef MFX_TRACE_ENABLE
372                 task.nParentId = MFX_AUTO_TRACE_GETID();
373                 task.nTaskId = MFX::CreateUniqId() + MFX_TRACE_ID_VPP;
374 #endif
375                 // register input and call the task
376                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
377             }
378             else
379             {
380                 MFX_TASK task;
381 
382                 memset(&task, 0, sizeof(task));
383                 task.pOwner = session->m_pVPP.get();
384                 task.entryPoint = entryPoints[0];
385                 task.priority = session->m_priority;
386                 task.threadingPolicy = session->m_pVPP->GetThreadingPolicy();
387                 // fill dependencies
388                 task.pSrc[0] = in;
389                 task.pDst[0] = entryPoints[0].pParam;
390 
391 
392 #ifdef MFX_TRACE_ENABLE
393                 task.nParentId = MFX_AUTO_TRACE_GETID();
394                 task.nTaskId = MFX::CreateUniqId() + MFX_TRACE_ID_VPP;
395 #endif
396                 // register input and call the task
397                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
398 
399                 memset(&task, 0, sizeof(task));
400                 task.pOwner = session->m_pVPP.get();
401                 task.entryPoint = entryPoints[1];
402                 task.priority = session->m_priority;
403                 task.threadingPolicy = session->m_pVPP->GetThreadingPolicy();
404 
405                 // fill dependencies
406                 task.pSrc[0] = entryPoints[0].pParam;
407                 task.pDst[0] = out;
408                 task.pDst[1] = aux;
409                 if (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes))
410                 {
411                     task.pDst[0] = NULL;
412                     task.pDst[1] = NULL;
413                 }
414 
415 #ifdef MFX_TRACE_ENABLE
416                 task.nParentId = MFX_AUTO_TRACE_GETID();
417                 task.nTaskId = MFX::CreateUniqId() + MFX_TRACE_ID_VPP2;
418 #endif
419                 // register input and call the task
420                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
421             }
422 
423             if (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes))
424             {
425                 mfxRes = MFX_ERR_MORE_DATA;
426                 syncPoint = NULL;
427             }
428         }
429 
430         // return pointer to synchronization point
431         *syncp = syncPoint;
432 #ifdef MFX_ENABLE_USER_VPP
433       }
434 #endif
435     }
436     // handle error(s)
437     catch(...)
438     {
439         // set the default error value
440         mfxRes = MFX_ERR_UNKNOWN;
441     }
442 
443     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, out);
444     if (mfxRes == MFX_ERR_NONE && syncp)
445     {
446         MFX_LTRACE_P(MFX_TRACE_LEVEL_PARAMS, *syncp);
447     }
448     MFX_LTRACE_I(MFX_TRACE_LEVEL_PARAMS, mfxRes);
449     return mfxRes;
450 
451 } // mfxStatus MFXVideoVPP_RunFrameVPPAsync(mfxSession session, mfxFrameSurface1 *in, mfxFrameSurface1 *out, mfxExtVppAuxData *aux, mfxSyncPoint *syncp)
452 
MFXVideoVPP_RunFrameVPPAsyncEx(mfxSession session,mfxFrameSurface1 * in,mfxFrameSurface1 * surface_work,mfxFrameSurface1 ** surface_out,mfxSyncPoint * syncp)453 mfxStatus MFXVideoVPP_RunFrameVPPAsyncEx(mfxSession session, mfxFrameSurface1 *in, mfxFrameSurface1 *surface_work, mfxFrameSurface1 **surface_out, mfxSyncPoint *syncp)
454 {
455 #if !defined(MFX_ENABLE_USER_VPP)
456     (void)in;
457     (void)surface_work;
458     (void)surface_out;
459 #endif
460 
461     mfxStatus mfxRes;
462 
463     MFX_AUTO_LTRACE_WITHID(MFX_TRACE_LEVEL_API, "MFX_RunFrameVPPAsyncEx");
464     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, in);
465 
466     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
467     MFX_CHECK(session->m_pVPP.get(), MFX_ERR_NOT_INITIALIZED);
468     MFX_CHECK(syncp, MFX_ERR_NULL_PTR);
469 
470     try
471     {
472 #ifdef MFX_ENABLE_USER_VPP
473       if (session->m_plgVPP.get())
474       {
475           MFX_TASK task;
476           mfxSyncPoint syncPoint = NULL;
477           *syncp = NULL;
478           memset(&task, 0, sizeof(MFX_TASK));
479 
480           mfxRes = session->m_plgVPP->VPPFrameCheckEx(in, surface_work, surface_out, &task.entryPoint);
481 
482           if (task.entryPoint.pRoutine)
483           {
484               mfxStatus mfxAddRes;
485 
486               task.pOwner = session->m_plgVPP.get();
487               task.priority = session->m_priority;
488               task.threadingPolicy = session->m_plgVPP->GetThreadingPolicy();
489               // fill dependencies
490               task.pSrc[0] = in;
491               task.pDst[0] = surface_work;
492               if (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes))
493                 task.pDst[0] = NULL;
494 
495               #ifdef MFX_TRACE_ENABLE
496               task.nParentId = MFX_AUTO_TRACE_GETID();
497               task.nTaskId = MFX::CreateUniqId() + MFX_TRACE_ID_VPP;
498               #endif
499 
500               // register input and call the task
501               mfxAddRes = session->m_pScheduler->AddTask(task, &syncPoint);
502               if (MFX_ERR_NONE != mfxAddRes)
503               {
504                   return mfxAddRes;
505               }
506               *syncp = syncPoint;
507           }
508       }
509       else
510       {
511 #endif
512         //MediaSDK's VPP should not work through Ex function
513         return MFX_ERR_UNDEFINED_BEHAVIOR;
514 
515 #ifdef MFX_ENABLE_USER_VPP
516       }
517 #endif
518     }
519     // handle error(s)
520     catch(...)
521     {
522         // set the default error value
523         mfxRes = MFX_ERR_UNKNOWN;
524     }
525 
526     MFX_LTRACE_BUFFER(MFX_TRACE_LEVEL_PARAMS, surface_work);
527     if (mfxRes == MFX_ERR_NONE && syncp)
528     {
529         MFX_LTRACE_P(MFX_TRACE_LEVEL_PARAMS, *syncp);
530     }
531     MFX_LTRACE_I(MFX_TRACE_LEVEL_PARAMS, mfxRes);
532     return mfxRes;
533 
534 } // mfxStatus MFXVideoVPP_RunFrameVPPAsyncEx(mfxSession session, mfxFrameSurface1 *in, mfxFrameSurface1 *surface_work, mfxFrameSurface1 **surface_out, mfxThreadTask *task);
535 
536 //
537 // THE OTHER VPP FUNCTIONS HAVE IMPLICIT IMPLEMENTATION
538 //
539 
540 FUNCTION_RESET_IMPL(VPP, Reset, (mfxSession session, mfxVideoParam *par), (par))
541 
542 FUNCTION_IMPL(VPP, GetVideoParam, (mfxSession session, mfxVideoParam *par), (par))
543 FUNCTION_IMPL(VPP, GetVPPStat, (mfxSession session, mfxVPPStat *stat), (stat))
544