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