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_common.h>
25 
26 // sheduling and threading stuff
27 #include <mfx_task.h>
28 
29 #include "mfxenc.h"
30 #include "mfx_enc_ext.h"
31 
32 
33 
34 #if defined(MFX_ENABLE_H264_VIDEO_ENCODE_HW) && defined(MFX_ENABLE_LA_H264_VIDEO_HW)
35 #include "mfx_h264_la.h"
36 #endif
37 
38 #if defined(MFX_ENABLE_H264_VIDEO_ENCODE_HW) && defined(MFX_ENABLE_H264_VIDEO_FEI_PREENC)
39 #include "mfx_h264_preenc.h"
40 #endif
41 
42 #if defined(MFX_ENABLE_H264_VIDEO_ENCODE_HW) && defined(MFX_ENABLE_H264_VIDEO_FEI_ENC)
43 #include "mfx_h264_enc.h"
44 #endif
45 
46 template<>
Create(mfxVideoParam & par)47 VideoENC* _mfxSession::Create<VideoENC>(mfxVideoParam& par)
48 {
49     VideoENC* pENC = nullptr;
50     mfxStatus mfxRes = MFX_ERR_MEMORY_ALLOC;
51     mfxU32 codecId = par.mfx.CodecId;
52 
53     switch (codecId)
54     {
55 #if ( defined(MFX_ENABLE_LA_H264_VIDEO_HW) || defined(MFX_ENABLE_H264_VIDEO_FEI_PREENC) || defined(MFX_ENABLE_H264_VIDEO_FEI_ENC))
56     case MFX_CODEC_AVC:
57 #if defined(MFX_ENABLE_LA_H264_VIDEO_HW)
58         if (bEnc_LA(&par))
59             pENC = (VideoENC*) new VideoENC_LA(m_pCORE.get(), &mfxRes);
60 #endif
61 #if defined(MFX_ENABLE_H264_VIDEO_FEI_PREENC)
62         if (bEnc_PREENC(&par))
63             pENC = (VideoENC*) new VideoENC_PREENC(m_pCORE.get(), &mfxRes);
64 #endif
65 #if defined(MFX_ENABLE_H264_VIDEO_FEI_ENC) && defined(MFX_ENABLE_H264_VIDEO_ENCODE_HW)
66         if (bEnc_ENC(&par))
67             pENC = (VideoENC*) new VideoENC_ENC(m_pCORE.get(), &mfxRes);
68 #endif
69         break;
70 #endif
71 
72     default:
73         break;
74     }
75 
76     // check error(s)
77     if (MFX_ERR_NONE != mfxRes)
78     {
79         delete pENC;
80         pENC = nullptr;
81     }
82 
83     return pENC;
84 }
85 
MFXVideoENC_Query(mfxSession session,mfxVideoParam * in,mfxVideoParam * out)86 mfxStatus MFXVideoENC_Query(mfxSession session, mfxVideoParam *in, mfxVideoParam *out)
87 {
88     (void)in;
89 
90     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
91     MFX_CHECK(out, MFX_ERR_NULL_PTR);
92 
93     mfxStatus mfxRes = MFX_ERR_UNSUPPORTED;
94     try
95     {
96 
97 #ifdef MFX_ENABLE_USER_ENC
98         mfxRes = MFX_ERR_UNSUPPORTED;
99 
100         _mfxSession_1_10 * versionedSession = (_mfxSession_1_10 *)(session);
101         MFXIPtr<MFXISession_1_10> newSession(versionedSession->QueryInterface(MFXISession_1_10_GUID));
102 
103         if (newSession && newSession->GetPreEncPlugin().get())
104         {
105             mfxRes = newSession->GetPreEncPlugin()->Query(session->m_pCORE.get(), in, out);
106         }
107         // unsupported reserved to codecid != requested codecid
108         if (MFX_ERR_UNSUPPORTED == mfxRes)
109 #endif
110         switch (out->mfx.CodecId)
111         {
112 #if  defined(MFX_ENABLE_LA_H264_VIDEO_HW) || defined(MFX_ENABLE_H264_VIDEO_FEI_PREENC)
113         case MFX_CODEC_AVC:
114 #if defined(MFX_ENABLE_LA_H264_VIDEO_HW)
115         if (bEnc_LA(in))
116             mfxRes = VideoENC_LA::Query(session->m_pCORE.get(), in, out);
117 #endif
118 
119 #if defined(MFX_ENABLE_H264_VIDEO_FEI_PREENC)
120         if (bEnc_PREENC(out))
121             mfxRes = VideoENC_PREENC::Query(session->m_pCORE.get(),in, out);
122 #endif
123             break;
124 #endif // MFX_ENABLE_H264_VIDEO_ENC || MFX_ENABLE_H264_VIDEO_ENC_H
125 
126 
127 
128         case 0:
129         default:
130             mfxRes = MFX_ERR_UNSUPPORTED;
131         }
132     }
133     // handle error(s)
134     catch(...)
135     {
136         mfxRes = MFX_ERR_NULL_PTR;
137     }
138     return mfxRes;
139 }
140 
MFXVideoENC_QueryIOSurf(mfxSession session,mfxVideoParam * par,mfxFrameAllocRequest * request)141 mfxStatus MFXVideoENC_QueryIOSurf(mfxSession session, mfxVideoParam *par, mfxFrameAllocRequest *request)
142 {
143     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
144     MFX_CHECK(par, MFX_ERR_NULL_PTR);
145     MFX_CHECK(request, MFX_ERR_NULL_PTR);
146 
147     mfxStatus mfxRes = MFX_ERR_UNSUPPORTED;
148     try
149     {
150 #ifdef MFX_ENABLE_USER_ENC
151         mfxRes = MFX_ERR_UNSUPPORTED;
152         _mfxSession_1_10 * versionedSession = (_mfxSession_1_10 *)(session);
153         MFXIPtr<MFXISession_1_10> newSession(versionedSession->QueryInterface(MFXISession_1_10_GUID));
154         if (newSession && newSession->GetPreEncPlugin().get())
155         {
156             mfxRes = newSession->GetPreEncPlugin()->QueryIOSurf(session->m_pCORE.get(), par, request, 0);
157         }
158         // unsupported reserved to codecid != requested codecid
159         if (MFX_ERR_UNSUPPORTED == mfxRes)
160 #endif
161         switch (par->mfx.CodecId)
162         {
163 
164 #if  ( defined(MFX_ENABLE_LA_H264_VIDEO_HW) ||  defined (MFX_ENABLE_H264_VIDEO_FEI_PREENC) || defined(MFX_ENABLE_H264_VIDEO_FEI_ENC))
165         case MFX_CODEC_AVC:
166 
167 #if defined(MFX_ENABLE_LA_H264_VIDEO_HW)
168         if (bEnc_LA(par))
169             mfxRes = VideoENC_LA::QueryIOSurf(session->m_pCORE.get(), par, request);
170 #endif
171 #if defined(MFX_ENABLE_H264_VIDEO_FEI_ENC) && defined(MFX_ENABLE_H264_VIDEO_ENCODE_HW)
172         if (bEnc_ENC(par))
173             mfxRes = VideoENC_ENC::QueryIOSurf(session->m_pCORE.get(), par, request);
174 #endif
175 
176             break;
177 #endif // MFX_ENABLE_H264_VIDEO_ENC || MFX_ENABLE_H264_VIDEO_ENC_HW
178 
179 
180 
181         case 0:
182         default:
183             mfxRes = MFX_ERR_UNSUPPORTED;
184         }
185     }
186     // handle error(s)
187     catch(...)
188     {
189         mfxRes = MFX_ERR_NULL_PTR;
190     }
191     return mfxRes;
192 }
193 
MFXVideoENC_Init(mfxSession session,mfxVideoParam * par)194 mfxStatus MFXVideoENC_Init(mfxSession session, mfxVideoParam *par)
195 {
196     mfxStatus mfxRes;
197 
198     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
199     MFX_CHECK(par, MFX_ERR_NULL_PTR);
200 
201     try
202     {
203         // check existence of component
204         if (!session->m_pENC)
205         {
206             // create a new instance
207             session->m_pENC.reset(session->Create<VideoENC>(*par));
208             MFX_CHECK(session->m_pENC.get(), MFX_ERR_INVALID_VIDEO_PARAM);
209         }
210 
211         mfxRes = session->m_pENC->Init(par);
212     }
213     // handle error(s)
214     catch(...)
215     {
216         // set the default error value
217         mfxRes = MFX_ERR_UNKNOWN;
218     }
219 
220     return mfxRes;
221 }
222 
MFXVideoENC_Close(mfxSession session)223 mfxStatus MFXVideoENC_Close(mfxSession session)
224 {
225     mfxStatus mfxRes;
226 
227     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
228     MFX_CHECK(session->m_pScheduler, MFX_ERR_NOT_INITIALIZED);
229 
230     try
231     {
232         if (!session->m_pENC)
233         {
234             return MFX_ERR_NOT_INITIALIZED;
235         }
236 
237         // wait until all tasks are processed
238         session->m_pScheduler->WaitForAllTasksCompletion(session->m_pENC.get());
239 
240         mfxRes = session->m_pENC->Close();
241         // delete the codec's instance
242         session->m_pENC.reset(nullptr);
243     }
244     // handle error(s)
245     catch(...)
246     {
247         // set the default error value
248         mfxRes = MFX_ERR_UNKNOWN;
249     }
250 
251     return mfxRes;
252 }
253 
254 static
MFXVideoENCLegacyRoutineExt(void * pState,void * pParam,mfxU32 threadNumber,mfxU32)255 mfxStatus MFXVideoENCLegacyRoutineExt(void *pState, void *pParam,
256                                    mfxU32 threadNumber, mfxU32 /* callNumber */)
257 {
258     VideoENC_Ext * pENC = (VideoENC_Ext  *) pState;
259     MFX_THREAD_TASK_PARAMETERS *pTaskParam = (MFX_THREAD_TASK_PARAMETERS *) pParam;
260 
261     // check error(s)
262     if ((NULL == pState) ||
263         (NULL == pParam) ||
264         (0 != threadNumber))
265     {
266         return MFX_ERR_NULL_PTR;
267     }
268     return pENC->RunFrameVmeENC(pTaskParam->enc.in, pTaskParam->enc.out);
269 }
270 
271 enum
272 {
273     MFX_NUM_ENTRY_POINTS = 2
274 };
275 
276 
MFXVideoENC_ProcessFrameAsync(mfxSession session,mfxENCInput * in,mfxENCOutput * out,mfxSyncPoint * syncp)277 mfxStatus  MFXVideoENC_ProcessFrameAsync(mfxSession session, mfxENCInput *in, mfxENCOutput *out, mfxSyncPoint *syncp)
278 {
279     mfxStatus mfxRes;
280 
281     MFX_CHECK(session, MFX_ERR_INVALID_HANDLE);
282     MFX_CHECK(session->m_pENC.get(), MFX_ERR_NOT_INITIALIZED);
283     MFX_CHECK(syncp, MFX_ERR_NULL_PTR);
284 
285     VideoENC_Ext *pEnc = dynamic_cast<VideoENC_Ext *>(session->m_pENC.get());
286     MFX_CHECK(pEnc, MFX_ERR_INVALID_HANDLE);
287 
288     try
289     {
290         mfxSyncPoint syncPoint = NULL;
291         MFX_ENTRY_POINT entryPoints[MFX_NUM_ENTRY_POINTS];
292         mfxU32 numEntryPoints = MFX_NUM_ENTRY_POINTS;
293         memset(&entryPoints, 0, sizeof(entryPoints));
294 
295         mfxRes = pEnc->RunFrameVmeENCCheck(in,out,entryPoints,numEntryPoints);
296 
297         if ((MFX_ERR_NONE == mfxRes) ||
298             (MFX_WRN_INCOMPATIBLE_VIDEO_PARAM == mfxRes) ||
299             (MFX_WRN_OUT_OF_RANGE == mfxRes) ||
300             (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes)) ||
301             (MFX_ERR_MORE_BITSTREAM == mfxRes))
302         {
303             // prepare the absolete kind of task.
304             // it is absolete and must be removed.
305             if (NULL == entryPoints[0].pRoutine)
306             {
307                 MFX_TASK task;
308                 memset(&task, 0, sizeof(task));
309                 // BEGIN OF OBSOLETE PART
310                 task.bObsoleteTask = true;
311                 // fill task info
312                 task.entryPoint.pRoutine = &MFXVideoENCLegacyRoutineExt;
313                 task.entryPoint.pState = pEnc;
314                 task.entryPoint.requiredNumThreads = 1;
315 
316                 // fill legacy parameters
317                 task.obsolete_params.enc.in = in;
318                 task.obsolete_params.enc.out = out;
319 
320                 task.priority = session->m_priority;
321                 task.threadingPolicy = pEnc->GetThreadingPolicy();
322                 // fill dependencies
323                 task.pSrc[0] = in;
324                 task.pDst[0] = out;
325                 task.pOwner= pEnc;
326                 mfxRes = session->m_pScheduler->AddTask(task, &syncPoint);
327 
328             } // END OF OBSOLETE PART
329             else if (1 == numEntryPoints)
330             {
331                 MFX_TASK task;
332 
333                 memset(&task, 0, sizeof(task));
334                 task.pOwner = pEnc;
335                 task.entryPoint = entryPoints[0];
336                 task.priority = session->m_priority;
337                 task.threadingPolicy = pEnc->GetThreadingPolicy();
338                 // fill dependencies
339 
340                 task.pSrc[0] =  out; // for LA plugin
341                 task.pSrc[1] =  in->InSurface;
342                 task.pDst[0] =  out? out->ExtParam : 0;
343 
344                 // register input and call the task
345                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
346             }
347             else
348             {
349                 MFX_TASK task;
350 
351                 memset(&task, 0, sizeof(task));
352                 task.pOwner = pEnc;
353                 task.entryPoint = entryPoints[0];
354                 task.priority = session->m_priority;
355                 task.threadingPolicy = pEnc->GetThreadingPolicy();
356                 // fill dependencies
357 
358                 task.pSrc[0] = in->InSurface;
359                 task.pDst[0] = entryPoints[0].pParam;
360 
361                 // register input and call the task
362                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
363 
364                 memset(&task, 0, sizeof(task));
365                 task.pOwner = pEnc;
366                 task.entryPoint = entryPoints[1];
367                 task.priority = session->m_priority;
368                 task.threadingPolicy = pEnc->GetThreadingPolicy();
369                 // fill dependencies
370                 task.pSrc[0] = entryPoints[0].pParam;
371                 task.pDst[0] = (MFX_ERR_NONE == mfxRes) ? out:0; // sync point for LA plugin
372                 task.pDst[1] = in->InSurface;
373 
374 
375                 // register input and call the task
376                 MFX_CHECK_STS(session->m_pScheduler->AddTask(task, &syncPoint));
377             }
378 
379             // IT SHOULD BE REMOVED
380             if (MFX_ERR_MORE_DATA_SUBMIT_TASK == static_cast<int>(mfxRes))
381             {
382                 mfxRes = MFX_ERR_MORE_DATA;
383                 syncPoint = NULL;
384             }
385 
386         }
387 
388         // return pointer to synchronization point
389         *syncp = syncPoint;
390     }
391     // handle error(s)
392     catch(...)
393     {
394         // set the default error value
395         mfxRes = MFX_ERR_UNKNOWN;
396     }
397 
398     return mfxRes;
399 
400 } // MFXVideoENC_ProcessFrameAsync
401 
402 
403 //
404 // THE OTHER ENC FUNCTIONS HAVE IMPLICIT IMPLEMENTATION
405 //
406 
407 FUNCTION_RESET_IMPL(ENC, Reset, (mfxSession session, mfxVideoParam *par), (par))
408 
409 FUNCTION_IMPL(ENC, GetVideoParam, (mfxSession session, mfxVideoParam *par), (par))
410 FUNCTION_IMPL(ENC, GetFrameParam, (mfxSession session, mfxFrameParam *par), (par))
411