1 /*
2
3 This file is provided under a dual BSD/GPLv2 license. When using or
4 redistributing this file, you may do so under either license.
5
6 GPL LICENSE SUMMARY
7
8 Copyright(c) Oct. 2015 Intel Corporation.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of version 2 of the GNU General Public License as
12 published by the Free Software Foundation.
13
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 Contact Information:
20
21 Seung-Woo Kim, seung-woo.kim@intel.com
22 705 5th Ave S #500, Seattle, WA 98104
23
24 BSD LICENSE
25
26 Copyright(c) <date> Intel Corporation.
27
28 Redistribution and use in source and binary forms, with or without
29 modification, are permitted provided that the following conditions
30 are met:
31
32 * Redistributions of source code must retain the above copyright
33 notice, this list of conditions and the following disclaimer.
34
35 * Redistributions in binary form must reproduce the above copyright
36 notice, this list of conditions and the following disclaimer in
37 the documentation and/or other materials provided with the
38 distribution.
39
40 * Neither the name of Intel Corporation nor the names of its
41 contributors may be used to endorse or promote products derived
42 from this software without specific prior written permission.
43
44 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
45 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
46 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
47 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
48 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
54 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 */
56
57 #include "QSV_Encoder_Internal.h"
58 #include "QSV_Encoder.h"
59 #include "mfxastructures.h"
60 #include "mfxvideo++.h"
61 #include <VersionHelpers.h>
62 #include <obs-module.h>
63
64 #define do_log(level, format, ...) \
65 blog(level, "[qsv encoder: '%s'] " format, "msdk_impl", ##__VA_ARGS__)
66
67 #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
68 #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
69 #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
70
71 mfxHDL QSV_Encoder_Internal::g_DX_Handle = NULL;
72 mfxU16 QSV_Encoder_Internal::g_numEncodersOpen = 0;
73
QSV_Encoder_Internal(mfxIMPL & impl,mfxVersion & version)74 QSV_Encoder_Internal::QSV_Encoder_Internal(mfxIMPL &impl, mfxVersion &version)
75 : m_pmfxSurfaces(NULL),
76 m_pmfxENC(NULL),
77 m_nSPSBufferSize(1024),
78 m_nPPSBufferSize(1024),
79 m_nTaskPool(0),
80 m_pTaskPool(NULL),
81 m_nTaskIdx(0),
82 m_nFirstSyncTask(0),
83 m_outBitstream()
84 {
85 mfxIMPL tempImpl;
86 mfxStatus sts;
87
88 m_bIsWindows8OrGreater = IsWindows8OrGreater();
89 m_bUseD3D11 = false;
90 m_bD3D9HACK = true;
91
92 if (m_bIsWindows8OrGreater) {
93 tempImpl = impl | MFX_IMPL_VIA_D3D11;
94 sts = m_session.Init(tempImpl, &version);
95 if (sts == MFX_ERR_NONE) {
96 m_session.QueryVersion(&version);
97 m_session.Close();
98
99 // Use D3D11 surface
100 // m_bUseD3D11 = ((version.Major > 1) ||
101 // (version.Major == 1 && version.Minor >= 8));
102 m_bUseD3D11 = true;
103 if (m_bUseD3D11)
104 blog(LOG_INFO, "\timpl: D3D11\n"
105 "\tsurf: D3D11");
106 else
107 blog(LOG_INFO, "\timpl: D3D11\n"
108 "\tsurf: SysMem");
109
110 m_impl = tempImpl;
111 m_ver = version;
112 return;
113 }
114 } else if (m_bD3D9HACK) {
115 tempImpl = impl | MFX_IMPL_VIA_D3D9;
116 sts = m_session.Init(tempImpl, &version);
117 if (sts == MFX_ERR_NONE) {
118 m_session.QueryVersion(&version);
119 m_session.Close();
120
121 blog(LOG_INFO, "\timpl: D3D09\n"
122 "\tsurf: Hack");
123
124 m_impl = tempImpl;
125 m_ver = version;
126 return;
127 }
128 }
129
130 // Either windows 7 or D3D11 failed at this point.
131 tempImpl = impl | MFX_IMPL_VIA_D3D9;
132 sts = m_session.Init(tempImpl, &version);
133 if (sts == MFX_ERR_NONE) {
134 m_session.QueryVersion(&version);
135 m_session.Close();
136
137 blog(LOG_INFO, "\timpl: D3D09\n"
138 "\tsurf: SysMem");
139
140 m_impl = tempImpl;
141 m_ver = version;
142 }
143 }
144
~QSV_Encoder_Internal()145 QSV_Encoder_Internal::~QSV_Encoder_Internal()
146 {
147 if (m_pmfxENC)
148 ClearData();
149 }
150
Open(qsv_param_t * pParams)151 mfxStatus QSV_Encoder_Internal::Open(qsv_param_t *pParams)
152 {
153 mfxStatus sts = MFX_ERR_NONE;
154
155 if (m_bUseD3D11)
156 // Use D3D11 surface
157 sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator,
158 &g_DX_Handle, false, false);
159 else if (m_bD3D9HACK)
160 // Use hack
161 sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator,
162 &g_DX_Handle, false, true);
163 else
164 sts = Initialize(m_impl, m_ver, &m_session, NULL);
165
166 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
167
168 m_pmfxENC = new MFXVideoENCODE(m_session);
169
170 InitParams(pParams);
171
172 sts = m_pmfxENC->Query(&m_mfxEncParams, &m_mfxEncParams);
173 MSDK_IGNORE_MFX_STS(sts, MFX_WRN_INCOMPATIBLE_VIDEO_PARAM);
174 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
175
176 sts = AllocateSurfaces();
177 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
178
179 sts = m_pmfxENC->Init(&m_mfxEncParams);
180 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
181
182 sts = GetVideoParam();
183 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
184
185 sts = InitBitstream();
186 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
187
188 if (sts >= MFX_ERR_NONE) {
189 g_numEncodersOpen++;
190 }
191 return sts;
192 }
193
InitParams(qsv_param_t * pParams)194 bool QSV_Encoder_Internal::InitParams(qsv_param_t *pParams)
195 {
196 memset(&m_mfxEncParams, 0, sizeof(m_mfxEncParams));
197
198 m_mfxEncParams.mfx.CodecId = MFX_CODEC_AVC;
199 m_mfxEncParams.mfx.GopOptFlag = MFX_GOP_STRICT;
200 m_mfxEncParams.mfx.NumSlice = 1;
201 m_mfxEncParams.mfx.TargetUsage = pParams->nTargetUsage;
202 m_mfxEncParams.mfx.CodecProfile = pParams->nCodecProfile;
203 m_mfxEncParams.mfx.FrameInfo.FrameRateExtN = pParams->nFpsNum;
204 m_mfxEncParams.mfx.FrameInfo.FrameRateExtD = pParams->nFpsDen;
205 m_mfxEncParams.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
206 m_mfxEncParams.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
207 m_mfxEncParams.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
208 m_mfxEncParams.mfx.FrameInfo.CropX = 0;
209 m_mfxEncParams.mfx.FrameInfo.CropY = 0;
210 m_mfxEncParams.mfx.FrameInfo.CropW = pParams->nWidth;
211 m_mfxEncParams.mfx.FrameInfo.CropH = pParams->nHeight;
212 m_mfxEncParams.mfx.GopRefDist = pParams->nbFrames + 1;
213
214 enum qsv_cpu_platform qsv_platform = qsv_get_cpu_platform();
215 if ((qsv_platform >= QSV_CPU_PLATFORM_ICL) &&
216 (pParams->nbFrames == 0) &&
217 (m_ver.Major == 1 && m_ver.Minor >= 31)) {
218 m_mfxEncParams.mfx.LowPower = MFX_CODINGOPTION_ON;
219 if (pParams->nRateControl == MFX_RATECONTROL_LA_ICQ ||
220 pParams->nRateControl == MFX_RATECONTROL_LA_HRD ||
221 pParams->nRateControl == MFX_RATECONTROL_LA)
222 pParams->nRateControl = MFX_RATECONTROL_VBR;
223 }
224
225 m_mfxEncParams.mfx.RateControlMethod = pParams->nRateControl;
226
227 switch (pParams->nRateControl) {
228 case MFX_RATECONTROL_CBR:
229 m_mfxEncParams.mfx.TargetKbps = pParams->nTargetBitRate;
230 break;
231 case MFX_RATECONTROL_VBR:
232 case MFX_RATECONTROL_VCM:
233 m_mfxEncParams.mfx.TargetKbps = pParams->nTargetBitRate;
234 m_mfxEncParams.mfx.MaxKbps = pParams->nMaxBitRate;
235 break;
236 case MFX_RATECONTROL_CQP:
237 m_mfxEncParams.mfx.QPI = pParams->nQPI;
238 m_mfxEncParams.mfx.QPB = pParams->nQPB;
239 m_mfxEncParams.mfx.QPP = pParams->nQPP;
240 break;
241 case MFX_RATECONTROL_AVBR:
242 m_mfxEncParams.mfx.TargetKbps = pParams->nTargetBitRate;
243 m_mfxEncParams.mfx.Accuracy = pParams->nAccuracy;
244 m_mfxEncParams.mfx.Convergence = pParams->nConvergence;
245 break;
246 case MFX_RATECONTROL_ICQ:
247 m_mfxEncParams.mfx.ICQQuality = pParams->nICQQuality;
248 break;
249 case MFX_RATECONTROL_LA:
250 m_mfxEncParams.mfx.TargetKbps = pParams->nTargetBitRate;
251 break;
252 case MFX_RATECONTROL_LA_ICQ:
253 m_mfxEncParams.mfx.ICQQuality = pParams->nICQQuality;
254 break;
255 case MFX_RATECONTROL_LA_HRD:
256 m_mfxEncParams.mfx.TargetKbps = pParams->nTargetBitRate;
257 m_mfxEncParams.mfx.MaxKbps = pParams->nTargetBitRate;
258 break;
259 default:
260 break;
261 }
262
263 m_mfxEncParams.AsyncDepth = pParams->nAsyncDepth;
264 m_mfxEncParams.mfx.GopPicSize =
265 (mfxU16)(pParams->nKeyIntSec * pParams->nFpsNum /
266 (float)pParams->nFpsDen);
267
268 static mfxExtBuffer *extendedBuffers[3];
269 int iBuffers = 0;
270
271 if (m_ver.Major == 1 && m_ver.Minor >= 8) {
272 memset(&m_co2, 0, sizeof(mfxExtCodingOption2));
273 m_co2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
274 m_co2.Header.BufferSz = sizeof(m_co2);
275 if (pParams->nRateControl == MFX_RATECONTROL_LA_ICQ ||
276 pParams->nRateControl == MFX_RATECONTROL_LA)
277 m_co2.LookAheadDepth = pParams->nLADEPTH;
278 if (pParams->bMBBRC)
279 m_co2.MBBRC = MFX_CODINGOPTION_ON;
280 if (pParams->nbFrames > 1)
281 m_co2.BRefType = MFX_B_REF_PYRAMID;
282 if (m_mfxEncParams.mfx.LowPower == MFX_CODINGOPTION_ON) {
283 m_co2.RepeatPPS = MFX_CODINGOPTION_OFF;
284 if (pParams->nRateControl == MFX_RATECONTROL_CBR ||
285 pParams->nRateControl == MFX_RATECONTROL_VBR) {
286 m_co2.LookAheadDepth = pParams->nLADEPTH;
287 }
288 }
289 extendedBuffers[iBuffers++] = (mfxExtBuffer *)&m_co2;
290 }
291
292 if (m_mfxEncParams.mfx.LowPower == MFX_CODINGOPTION_ON) {
293 memset(&m_co3, 0, sizeof(mfxExtCodingOption3));
294 m_co3.Header.BufferId = MFX_EXTBUFF_CODING_OPTION3;
295 m_co3.Header.BufferSz = sizeof(m_co3);
296 m_co3.ScenarioInfo = MFX_SCENARIO_GAME_STREAMING;
297 extendedBuffers[iBuffers++] = (mfxExtBuffer *)&m_co3;
298 } else if (pParams->bCQM) {
299 if (m_ver.Major == 1 && m_ver.Minor >= 16) {
300 memset(&m_co3, 0, sizeof(mfxExtCodingOption3));
301 m_co3.Header.BufferId = MFX_EXTBUFF_CODING_OPTION3;
302 m_co3.Header.BufferSz = sizeof(m_co3);
303 m_co3.ScenarioInfo = 7; // MFX_SCENARIO_GAME_STREAMING
304 extendedBuffers[iBuffers++] = (mfxExtBuffer *)&m_co3;
305 }
306 }
307
308 if (iBuffers > 0) {
309 m_mfxEncParams.ExtParam = extendedBuffers;
310 m_mfxEncParams.NumExtParam = (mfxU16)iBuffers;
311 }
312
313 // Width must be a multiple of 16
314 // Height must be a multiple of 16 in case of frame picture and a
315 // multiple of 32 in case of field picture
316 m_mfxEncParams.mfx.FrameInfo.Width = MSDK_ALIGN16(pParams->nWidth);
317 m_mfxEncParams.mfx.FrameInfo.Height = MSDK_ALIGN16(pParams->nHeight);
318
319 if (m_bUseD3D11 || m_bD3D9HACK)
320 m_mfxEncParams.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
321 else
322 m_mfxEncParams.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
323
324 mfxStatus sts = m_pmfxENC->Query(&m_mfxEncParams, &m_mfxEncParams);
325 if (sts == MFX_ERR_UNSUPPORTED || sts == MFX_ERR_UNDEFINED_BEHAVIOR) {
326 if (m_mfxEncParams.mfx.LowPower == MFX_CODINGOPTION_ON) {
327 m_mfxEncParams.mfx.LowPower = MFX_CODINGOPTION_OFF;
328 m_co2.LookAheadDepth = 0;
329 }
330 }
331
332 return true;
333 }
334
AllocateSurfaces()335 mfxStatus QSV_Encoder_Internal::AllocateSurfaces()
336 {
337 // Query number of required surfaces for encoder
338 mfxFrameAllocRequest EncRequest;
339 memset(&EncRequest, 0, sizeof(EncRequest));
340 mfxStatus sts = m_pmfxENC->QueryIOSurf(&m_mfxEncParams, &EncRequest);
341 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
342
343 EncRequest.Type |= WILL_WRITE;
344
345 // SNB hack. On some SNB, it seems to require more surfaces
346 EncRequest.NumFrameSuggested += m_mfxEncParams.AsyncDepth;
347
348 // Allocate required surfaces
349 if (m_bUseD3D11 || m_bD3D9HACK) {
350 sts = m_mfxAllocator.Alloc(m_mfxAllocator.pthis, &EncRequest,
351 &m_mfxResponse);
352 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
353
354 m_nSurfNum = m_mfxResponse.NumFrameActual;
355
356 m_pmfxSurfaces = new mfxFrameSurface1 *[m_nSurfNum];
357 MSDK_CHECK_POINTER(m_pmfxSurfaces, MFX_ERR_MEMORY_ALLOC);
358
359 for (int i = 0; i < m_nSurfNum; i++) {
360 m_pmfxSurfaces[i] = new mfxFrameSurface1;
361 memset(m_pmfxSurfaces[i], 0, sizeof(mfxFrameSurface1));
362 memcpy(&(m_pmfxSurfaces[i]->Info),
363 &(m_mfxEncParams.mfx.FrameInfo),
364 sizeof(mfxFrameInfo));
365 m_pmfxSurfaces[i]->Data.MemId = m_mfxResponse.mids[i];
366 }
367 } else {
368 mfxU16 width = (mfxU16)MSDK_ALIGN32(EncRequest.Info.Width);
369 mfxU16 height = (mfxU16)MSDK_ALIGN32(EncRequest.Info.Height);
370 mfxU8 bitsPerPixel = 12;
371 mfxU32 surfaceSize = width * height * bitsPerPixel / 8;
372 m_nSurfNum = EncRequest.NumFrameSuggested;
373
374 m_pmfxSurfaces = new mfxFrameSurface1 *[m_nSurfNum];
375 for (int i = 0; i < m_nSurfNum; i++) {
376 m_pmfxSurfaces[i] = new mfxFrameSurface1;
377 memset(m_pmfxSurfaces[i], 0, sizeof(mfxFrameSurface1));
378 memcpy(&(m_pmfxSurfaces[i]->Info),
379 &(m_mfxEncParams.mfx.FrameInfo),
380 sizeof(mfxFrameInfo));
381
382 mfxU8 *pSurface = (mfxU8 *)new mfxU8[surfaceSize];
383 m_pmfxSurfaces[i]->Data.Y = pSurface;
384 m_pmfxSurfaces[i]->Data.U = pSurface + width * height;
385 m_pmfxSurfaces[i]->Data.V =
386 pSurface + width * height + 1;
387 m_pmfxSurfaces[i]->Data.Pitch = width;
388 }
389 }
390
391 blog(LOG_INFO, "\tm_nSurfNum: %d", m_nSurfNum);
392
393 return sts;
394 }
395
GetVideoParam()396 mfxStatus QSV_Encoder_Internal::GetVideoParam()
397 {
398 memset(&m_parameter, 0, sizeof(m_parameter));
399 mfxExtCodingOptionSPSPPS opt;
400 memset(&m_parameter, 0, sizeof(m_parameter));
401 opt.Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS;
402 opt.Header.BufferSz = sizeof(mfxExtCodingOptionSPSPPS);
403
404 static mfxExtBuffer *extendedBuffers[1];
405 extendedBuffers[0] = (mfxExtBuffer *)&opt;
406 m_parameter.ExtParam = extendedBuffers;
407 m_parameter.NumExtParam = 1;
408
409 opt.SPSBuffer = m_SPSBuffer;
410 opt.PPSBuffer = m_PPSBuffer;
411 opt.SPSBufSize = 1024; // m_nSPSBufferSize;
412 opt.PPSBufSize = 1024; // m_nPPSBufferSize;
413
414 mfxStatus sts = m_pmfxENC->GetVideoParam(&m_parameter);
415 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
416
417 m_nSPSBufferSize = opt.SPSBufSize;
418 m_nPPSBufferSize = opt.PPSBufSize;
419
420 return sts;
421 }
422
GetSPSPPS(mfxU8 ** pSPSBuf,mfxU8 ** pPPSBuf,mfxU16 * pnSPSBuf,mfxU16 * pnPPSBuf)423 void QSV_Encoder_Internal::GetSPSPPS(mfxU8 **pSPSBuf, mfxU8 **pPPSBuf,
424 mfxU16 *pnSPSBuf, mfxU16 *pnPPSBuf)
425 {
426 *pSPSBuf = m_SPSBuffer;
427 *pPPSBuf = m_PPSBuffer;
428 *pnSPSBuf = m_nSPSBufferSize;
429 *pnPPSBuf = m_nPPSBufferSize;
430 }
431
InitBitstream()432 mfxStatus QSV_Encoder_Internal::InitBitstream()
433 {
434 m_nTaskPool = m_parameter.AsyncDepth;
435 m_nFirstSyncTask = 0;
436
437 m_pTaskPool = new Task[m_nTaskPool];
438 memset(m_pTaskPool, 0, sizeof(Task) * m_nTaskPool);
439
440 for (int i = 0; i < m_nTaskPool; i++) {
441 m_pTaskPool[i].mfxBS.MaxLength =
442 m_parameter.mfx.BufferSizeInKB * 1000;
443 m_pTaskPool[i].mfxBS.Data =
444 new mfxU8[m_pTaskPool[i].mfxBS.MaxLength];
445 m_pTaskPool[i].mfxBS.DataOffset = 0;
446 m_pTaskPool[i].mfxBS.DataLength = 0;
447
448 MSDK_CHECK_POINTER(m_pTaskPool[i].mfxBS.Data,
449 MFX_ERR_MEMORY_ALLOC);
450 }
451
452 memset(&m_outBitstream, 0, sizeof(mfxBitstream));
453 m_outBitstream.MaxLength = m_parameter.mfx.BufferSizeInKB * 1000;
454 m_outBitstream.Data = new mfxU8[m_outBitstream.MaxLength];
455 m_outBitstream.DataOffset = 0;
456 m_outBitstream.DataLength = 0;
457
458 blog(LOG_INFO, "\tm_nTaskPool: %d", m_nTaskPool);
459
460 return MFX_ERR_NONE;
461 }
462
LoadNV12(mfxFrameSurface1 * pSurface,uint8_t * pDataY,uint8_t * pDataUV,uint32_t strideY,uint32_t strideUV)463 mfxStatus QSV_Encoder_Internal::LoadNV12(mfxFrameSurface1 *pSurface,
464 uint8_t *pDataY, uint8_t *pDataUV,
465 uint32_t strideY, uint32_t strideUV)
466 {
467 mfxU16 w, h, i, pitch;
468 mfxU8 *ptr;
469 mfxFrameInfo *pInfo = &pSurface->Info;
470 mfxFrameData *pData = &pSurface->Data;
471
472 if (pInfo->CropH > 0 && pInfo->CropW > 0) {
473 w = pInfo->CropW;
474 h = pInfo->CropH;
475 } else {
476 w = pInfo->Width;
477 h = pInfo->Height;
478 }
479
480 pitch = pData->Pitch;
481 ptr = pData->Y + pInfo->CropX + pInfo->CropY * pData->Pitch;
482
483 // load Y plane
484 for (i = 0; i < h; i++)
485 memcpy(ptr + i * pitch, pDataY + i * strideY, w);
486
487 // load UV plane
488 h /= 2;
489 ptr = pData->UV + pInfo->CropX + (pInfo->CropY / 2) * pitch;
490
491 for (i = 0; i < h; i++)
492 memcpy(ptr + i * pitch, pDataUV + i * strideUV, w);
493
494 return MFX_ERR_NONE;
495 }
496
GetFreeTaskIndex(Task * pTaskPool,mfxU16 nPoolSize)497 int QSV_Encoder_Internal::GetFreeTaskIndex(Task *pTaskPool, mfxU16 nPoolSize)
498 {
499 if (pTaskPool)
500 for (int i = 0; i < nPoolSize; i++)
501 if (!pTaskPool[i].syncp)
502 return i;
503 return MFX_ERR_NOT_FOUND;
504 }
505
Encode(uint64_t ts,uint8_t * pDataY,uint8_t * pDataUV,uint32_t strideY,uint32_t strideUV,mfxBitstream ** pBS)506 mfxStatus QSV_Encoder_Internal::Encode(uint64_t ts, uint8_t *pDataY,
507 uint8_t *pDataUV, uint32_t strideY,
508 uint32_t strideUV, mfxBitstream **pBS)
509 {
510 mfxStatus sts = MFX_ERR_NONE;
511 *pBS = NULL;
512 int nTaskIdx = GetFreeTaskIndex(m_pTaskPool, m_nTaskPool);
513
514 #if 0
515 info("MSDK Encode:\n"
516 "\tTaskIndex: %d",
517 nTaskIdx);
518 #endif
519
520 int nSurfIdx = GetFreeSurfaceIndex(m_pmfxSurfaces, m_nSurfNum);
521 #if 0
522 info("MSDK Encode:\n"
523 "\tnSurfIdx: %d",
524 nSurfIdx);
525 #endif
526
527 while (MFX_ERR_NOT_FOUND == nTaskIdx || MFX_ERR_NOT_FOUND == nSurfIdx) {
528 // No more free tasks or surfaces, need to sync
529 sts = m_session.SyncOperation(
530 m_pTaskPool[m_nFirstSyncTask].syncp, 60000);
531 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
532
533 mfxU8 *pTemp = m_outBitstream.Data;
534 memcpy(&m_outBitstream, &m_pTaskPool[m_nFirstSyncTask].mfxBS,
535 sizeof(mfxBitstream));
536
537 m_pTaskPool[m_nFirstSyncTask].mfxBS.Data = pTemp;
538 m_pTaskPool[m_nFirstSyncTask].mfxBS.DataLength = 0;
539 m_pTaskPool[m_nFirstSyncTask].mfxBS.DataOffset = 0;
540 m_pTaskPool[m_nFirstSyncTask].syncp = NULL;
541 nTaskIdx = m_nFirstSyncTask;
542 m_nFirstSyncTask = (m_nFirstSyncTask + 1) % m_nTaskPool;
543 *pBS = &m_outBitstream;
544
545 #if 0
546 info("MSDK Encode:\n"
547 "\tnew FirstSyncTask: %d\n"
548 "\tTaskIndex: %d",
549 m_nFirstSyncTask,
550 nTaskIdx);
551 #endif
552
553 nSurfIdx = GetFreeSurfaceIndex(m_pmfxSurfaces, m_nSurfNum);
554 #if 0
555 info("MSDK Encode:\n"
556 "\tnSurfIdx: %d",
557 nSurfIdx);
558 #endif
559 }
560
561 mfxFrameSurface1 *pSurface = m_pmfxSurfaces[nSurfIdx];
562 if (m_bUseD3D11 || m_bD3D9HACK) {
563 sts = m_mfxAllocator.Lock(m_mfxAllocator.pthis,
564 pSurface->Data.MemId,
565 &(pSurface->Data));
566 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
567 }
568
569 sts = LoadNV12(pSurface, pDataY, pDataUV, strideY, strideUV);
570 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
571 pSurface->Data.TimeStamp = ts;
572
573 if (m_bUseD3D11 || m_bD3D9HACK) {
574 sts = m_mfxAllocator.Unlock(m_mfxAllocator.pthis,
575 pSurface->Data.MemId,
576 &(pSurface->Data));
577 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
578 }
579
580 for (;;) {
581 // Encode a frame asynchronously (returns immediately)
582 sts = m_pmfxENC->EncodeFrameAsync(NULL, pSurface,
583 &m_pTaskPool[nTaskIdx].mfxBS,
584 &m_pTaskPool[nTaskIdx].syncp);
585
586 if (MFX_ERR_NONE < sts && !m_pTaskPool[nTaskIdx].syncp) {
587 // Repeat the call if warning and no output
588 if (MFX_WRN_DEVICE_BUSY == sts)
589 MSDK_SLEEP(
590 1); // Wait if device is busy, then repeat the same call
591 } else if (MFX_ERR_NONE < sts && m_pTaskPool[nTaskIdx].syncp) {
592 sts = MFX_ERR_NONE; // Ignore warnings if output is available
593 break;
594 } else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) {
595 // Allocate more bitstream buffer memory here if needed...
596 break;
597 } else
598 break;
599 }
600
601 return sts;
602 }
603
Encode_tex(uint64_t ts,uint32_t tex_handle,uint64_t lock_key,uint64_t * next_key,mfxBitstream ** pBS)604 mfxStatus QSV_Encoder_Internal::Encode_tex(uint64_t ts, uint32_t tex_handle,
605 uint64_t lock_key,
606 uint64_t *next_key,
607 mfxBitstream **pBS)
608 {
609 mfxStatus sts = MFX_ERR_NONE;
610 *pBS = NULL;
611 int nTaskIdx = GetFreeTaskIndex(m_pTaskPool, m_nTaskPool);
612 int nSurfIdx = GetFreeSurfaceIndex(m_pmfxSurfaces, m_nSurfNum);
613
614 while (MFX_ERR_NOT_FOUND == nTaskIdx || MFX_ERR_NOT_FOUND == nSurfIdx) {
615 // No more free tasks or surfaces, need to sync
616 sts = m_session.SyncOperation(
617 m_pTaskPool[m_nFirstSyncTask].syncp, 60000);
618 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
619
620 mfxU8 *pTemp = m_outBitstream.Data;
621 memcpy(&m_outBitstream, &m_pTaskPool[m_nFirstSyncTask].mfxBS,
622 sizeof(mfxBitstream));
623
624 m_pTaskPool[m_nFirstSyncTask].mfxBS.Data = pTemp;
625 m_pTaskPool[m_nFirstSyncTask].mfxBS.DataLength = 0;
626 m_pTaskPool[m_nFirstSyncTask].mfxBS.DataOffset = 0;
627 m_pTaskPool[m_nFirstSyncTask].syncp = NULL;
628 nTaskIdx = m_nFirstSyncTask;
629 m_nFirstSyncTask = (m_nFirstSyncTask + 1) % m_nTaskPool;
630 *pBS = &m_outBitstream;
631
632 nSurfIdx = GetFreeSurfaceIndex(m_pmfxSurfaces, m_nSurfNum);
633 }
634
635 mfxFrameSurface1 *pSurface = m_pmfxSurfaces[nSurfIdx];
636 //copy to default surface directly
637 pSurface->Data.TimeStamp = ts;
638 if (m_bUseD3D11 || m_bD3D9HACK) {
639 sts = simple_copytex(m_mfxAllocator.pthis, pSurface->Data.MemId,
640 tex_handle, lock_key, next_key);
641 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
642 }
643
644 for (;;) {
645 // Encode a frame asynchronously (returns immediately)
646 sts = m_pmfxENC->EncodeFrameAsync(NULL, pSurface,
647 &m_pTaskPool[nTaskIdx].mfxBS,
648 &m_pTaskPool[nTaskIdx].syncp);
649
650 if (MFX_ERR_NONE < sts && !m_pTaskPool[nTaskIdx].syncp) {
651 // Repeat the call if warning and no output
652 if (MFX_WRN_DEVICE_BUSY == sts)
653 MSDK_SLEEP(
654 1); // Wait if device is busy, then repeat the same call
655 } else if (MFX_ERR_NONE < sts && m_pTaskPool[nTaskIdx].syncp) {
656 sts = MFX_ERR_NONE; // Ignore warnings if output is available
657 break;
658 } else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) {
659 // Allocate more bitstream buffer memory here if needed...
660 break;
661 } else
662 break;
663 }
664
665 return sts;
666 }
667
Drain()668 mfxStatus QSV_Encoder_Internal::Drain()
669 {
670 mfxStatus sts = MFX_ERR_NONE;
671
672 while (m_pTaskPool && m_pTaskPool[m_nFirstSyncTask].syncp) {
673 sts = m_session.SyncOperation(
674 m_pTaskPool[m_nFirstSyncTask].syncp, 60000);
675 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
676
677 m_pTaskPool[m_nFirstSyncTask].syncp = NULL;
678 m_nFirstSyncTask = (m_nFirstSyncTask + 1) % m_nTaskPool;
679 }
680
681 return sts;
682 }
683
ClearData()684 mfxStatus QSV_Encoder_Internal::ClearData()
685 {
686 mfxStatus sts = MFX_ERR_NONE;
687 sts = Drain();
688
689 if (m_pmfxENC) {
690 sts = m_pmfxENC->Close();
691 delete m_pmfxENC;
692 m_pmfxENC = NULL;
693 }
694
695 if (m_bUseD3D11 || m_bD3D9HACK)
696 m_mfxAllocator.Free(m_mfxAllocator.pthis, &m_mfxResponse);
697
698 if (m_pmfxSurfaces) {
699 for (int i = 0; i < m_nSurfNum; i++) {
700 if (!m_bUseD3D11 && !m_bD3D9HACK)
701 delete m_pmfxSurfaces[i]->Data.Y;
702
703 delete m_pmfxSurfaces[i];
704 }
705 MSDK_SAFE_DELETE_ARRAY(m_pmfxSurfaces);
706 }
707
708 if (m_pTaskPool) {
709 for (int i = 0; i < m_nTaskPool; i++)
710 delete m_pTaskPool[i].mfxBS.Data;
711 MSDK_SAFE_DELETE_ARRAY(m_pTaskPool);
712 }
713
714 if (m_outBitstream.Data) {
715 delete m_outBitstream.Data;
716 m_outBitstream.Data = NULL;
717 }
718
719 if (sts >= MFX_ERR_NONE) {
720 g_numEncodersOpen--;
721 }
722
723 if ((m_bUseD3D11 || m_bD3D9HACK) && (g_numEncodersOpen <= 0)) {
724 Release();
725 g_DX_Handle = NULL;
726 }
727 m_session.Close();
728 return sts;
729 }
730
Reset(qsv_param_t * pParams)731 mfxStatus QSV_Encoder_Internal::Reset(qsv_param_t *pParams)
732 {
733 mfxStatus sts = ClearData();
734 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
735
736 sts = Open(pParams);
737 MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
738
739 return sts;
740 }
741