1 /*!
2 * \copy
3 * Copyright (c) 2013, Cisco Systems
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33 #include "wels_preprocess.h"
34 #include "picture_handle.h"
35 #include "encoder_context.h"
36 #include "utils.h"
37 #include "encoder.h"
38
39 namespace {
40
ClearEndOfLinePadding(uint8_t * pData,int32_t iStride,int32_t iWidth,int32_t iHeight)41 void ClearEndOfLinePadding (uint8_t* pData, int32_t iStride, int32_t iWidth, int32_t iHeight) {
42 if (iWidth < iStride) {
43 for (int32_t i = 0; i < iHeight; ++i)
44 memset (pData + i * iStride + iWidth, 0, iStride - iWidth);
45 }
46 }
47
48 } // anon ns.
49
50 namespace WelsEnc {
51
52
53
54 //***** entry API declaration ************************************************************************//
55
56 int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPic, CMemoryAlign* pMemoryAlign);
57 bool JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPic);
58 void FreeScaledPic (Scaled_Picture* pScaledPic, CMemoryAlign* pMemoryAlign);
59 void WelsMoveMemory_c (uint8_t* pDstY, uint8_t* pDstU, uint8_t* pDstV, int32_t iDstStrideY, int32_t iDstStrideUV,
60 uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iSrcStrideY, int32_t iSrcStrideUV, int32_t iWidth,
61 int32_t iHeight);
62
63 //******* table definition ***********************************************************************//
64 const uint8_t g_kuiRefTemporalIdx[MAX_TEMPORAL_LEVEL][MAX_GOP_SIZE] = {
65 { 0, }, // 0
66 { 0, 0, }, // 1
67 { 0, 0, 0, 1, }, // 2
68 { 0, 0, 0, 2, 0, 1, 1, 2, }, // 3
69 };
70
71 const int32_t g_kiPixMapSizeInBits = sizeof (uint8_t) * 8;
72
73
WelsUpdateSpatialIdxMap(sWelsEncCtx * pEncCtx,const int32_t iPos,SPicture * const pPic,const int32_t iDidx)74 inline void WelsUpdateSpatialIdxMap (sWelsEncCtx* pEncCtx, const int32_t iPos, SPicture* const pPic,
75 const int32_t iDidx) {
76 pEncCtx->sSpatialIndexMap[iPos].pSrc = pPic;
77 pEncCtx->sSpatialIndexMap[iPos].iDid = iDidx;
78 }
79
80
81 /***************************************************************************
82 *
83 * implement of the interface
84 *
85 ***************************************************************************/
86
87
88
CreatePreProcess(sWelsEncCtx * pEncCtx)89 CWelsPreProcess* CWelsPreProcess::CreatePreProcess (sWelsEncCtx* pEncCtx) {
90
91 CWelsPreProcess* pPreProcess = NULL;
92 switch (pEncCtx->pSvcParam->iUsageType) {
93 case SCREEN_CONTENT_REAL_TIME:
94 pPreProcess = WELS_NEW_OP (CWelsPreProcessScreen (pEncCtx),
95 CWelsPreProcessScreen);
96 break;
97 default:
98 pPreProcess = WELS_NEW_OP (CWelsPreProcessVideo (pEncCtx),
99 CWelsPreProcessVideo);
100 break;
101
102 }
103 WELS_VERIFY_RETURN_IF (NULL, NULL == pPreProcess)
104 return pPreProcess;
105 }
106
107
CWelsPreProcess(sWelsEncCtx * pEncCtx)108 CWelsPreProcess::CWelsPreProcess (sWelsEncCtx* pEncCtx) {
109 m_pInterfaceVp = NULL;
110 m_bInitDone = false;
111 m_pEncCtx = pEncCtx;
112 memset (&m_sScaledPicture, 0, sizeof (m_sScaledPicture));
113 memset (m_pSpatialPic, 0, sizeof (m_pSpatialPic));
114 memset (m_uiSpatialLayersInTemporal, 0, sizeof (m_uiSpatialLayersInTemporal));
115 memset (m_uiSpatialPicNum, 0, sizeof (m_uiSpatialPicNum));
116 }
117
~CWelsPreProcess()118 CWelsPreProcess::~CWelsPreProcess() {
119 FreeScaledPic (&m_sScaledPicture, m_pEncCtx->pMemAlign);
120 WelsPreprocessDestroy();
121 }
122
WelsPreprocessCreate()123 int32_t CWelsPreProcess::WelsPreprocessCreate() {
124 if (m_pInterfaceVp == NULL) {
125 WelsCreateVpInterface ((void**) &m_pInterfaceVp, WELSVP_INTERFACE_VERION);
126 if (!m_pInterfaceVp)
127 goto exit;
128 } else
129 goto exit;
130
131 return 0;
132
133 exit:
134 WelsPreprocessDestroy();
135 return 1;
136 }
137
WelsPreprocessDestroy()138 int32_t CWelsPreProcess::WelsPreprocessDestroy() {
139 WelsDestroyVpInterface (m_pInterfaceVp, WELSVP_INTERFACE_VERION);
140 m_pInterfaceVp = NULL;
141
142 return 0;
143 }
144
WelsPreprocessReset(sWelsEncCtx * pCtx,int32_t iWidth,int32_t iHeight)145 int32_t CWelsPreProcess::WelsPreprocessReset (sWelsEncCtx* pCtx, int32_t iWidth, int32_t iHeight) {
146 int32_t iRet = -1;
147 SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
148 //init source width and height
149 pSvcParam->SUsedPicRect.iLeft = 0;
150 pSvcParam->SUsedPicRect.iTop = 0;
151 pSvcParam->SUsedPicRect.iWidth = iWidth;
152 pSvcParam->SUsedPicRect.iHeight = iHeight;
153 if ((iWidth < 16) || ((iHeight < 16))) {
154 WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "Don't support width(%d) or height(%d) which is less than 16 ", iWidth,
155 iHeight);
156 return iRet;
157 }
158 if (pCtx) {
159 FreeScaledPic (&m_sScaledPicture, pCtx->pMemAlign);
160 iRet = InitLastSpatialPictures (pCtx);
161 iRet = WelsInitScaledPic (pCtx->pSvcParam, &m_sScaledPicture, pCtx->pMemAlign);
162 }
163
164 return iRet;
165 }
166
AllocSpatialPictures(sWelsEncCtx * pCtx,SWelsSvcCodingParam * pParam)167 int32_t CWelsPreProcess::AllocSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam) {
168 CMemoryAlign* pMa = pCtx->pMemAlign;
169 const int32_t kiDlayerCount = pParam->iSpatialLayerNum;
170 int32_t iDlayerIndex = 0;
171
172 // spatial pictures
173 iDlayerIndex = 0;
174 do {
175 const int32_t kiPicWidth = pParam->sSpatialLayers[iDlayerIndex].iVideoWidth;
176 const int32_t kiPicHeight = pParam->sSpatialLayers[iDlayerIndex].iVideoHeight;
177 const uint8_t kuiLayerInTemporal = 2 + WELS_MAX (pParam->sDependencyLayers[iDlayerIndex].iHighestTemporalId, 1);
178 const uint8_t kuiRefNumInTemporal = kuiLayerInTemporal + pParam->iLTRRefNum;
179 uint8_t i = 0;
180
181 m_uiSpatialPicNum[iDlayerIndex] = kuiRefNumInTemporal;
182 do {
183 SPicture* pPic = AllocPicture (pMa, kiPicWidth, kiPicHeight, false, 0);
184 WELS_VERIFY_RETURN_IF (1, (NULL == pPic))
185 m_pSpatialPic[iDlayerIndex][i] = pPic;
186 ++ i;
187 } while (i < kuiRefNumInTemporal);
188
189 if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME)
190 m_uiSpatialLayersInTemporal[iDlayerIndex] = 1;
191 else
192 m_uiSpatialLayersInTemporal[iDlayerIndex] = kuiLayerInTemporal;
193
194 ++ iDlayerIndex;
195 } while (iDlayerIndex < kiDlayerCount);
196
197 return 0;
198 }
199
FreeSpatialPictures(sWelsEncCtx * pCtx)200 void CWelsPreProcess::FreeSpatialPictures (sWelsEncCtx* pCtx) {
201 CMemoryAlign* pMa = pCtx->pMemAlign;
202 int32_t j = 0;
203 while (j < pCtx->pSvcParam->iSpatialLayerNum) {
204 uint8_t i = 0;
205 uint8_t uiRefNumInTemporal = m_uiSpatialPicNum[j];
206
207 while (i < uiRefNumInTemporal) {
208 if (NULL != m_pSpatialPic[j][i]) {
209 FreePicture (pMa, &m_pSpatialPic[j][i]);
210 }
211 ++ i;
212 }
213 m_uiSpatialLayersInTemporal[j] = 0;
214 ++ j;
215 }
216 }
217
BuildSpatialPicList(sWelsEncCtx * pCtx,const SSourcePicture * kpSrcPic)218 int32_t CWelsPreProcess::BuildSpatialPicList (sWelsEncCtx* pCtx, const SSourcePicture* kpSrcPic) {
219 SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
220 int32_t iSpatialNum = 0;
221 int32_t iWidth = ((kpSrcPic->iPicWidth >> 1) << 1);
222 int32_t iHeight = ((kpSrcPic->iPicHeight >> 1) << 1);
223
224 if (!m_bInitDone) {
225 if (WelsPreprocessCreate() != 0)
226 return -1;
227
228 if (WelsPreprocessReset (pCtx, iWidth, iHeight) != 0)
229 return -1;
230
231 m_iAvaliableRefInSpatialPicList = pSvcParam->iNumRefFrame;
232
233 m_bInitDone = true;
234 } else {
235 if ((iWidth != pSvcParam->SUsedPicRect.iWidth) || (iHeight != pSvcParam->SUsedPicRect.iHeight)) {
236 if (WelsPreprocessReset (pCtx, iWidth, iHeight) != 0)
237 return -1;
238 }
239 }
240
241 if (m_pInterfaceVp == NULL)
242 return -1;
243
244 pCtx->pVaa->bSceneChangeFlag = pCtx->pVaa->bIdrPeriodFlag = false;
245
246 iSpatialNum = SingleLayerPreprocess (pCtx, kpSrcPic, &m_sScaledPicture);
247
248 return iSpatialNum;
249 }
250
GetBestRefPic(EUsageType iUsageType,bool bSceneLtr,EWelsSliceType eSliceType,int32_t kiDidx,int32_t iRefTemporalIdx)251 SPicture* CWelsPreProcess::GetBestRefPic (EUsageType iUsageType, bool bSceneLtr, EWelsSliceType eSliceType,
252 int32_t kiDidx, int32_t iRefTemporalIdx) {
253 assert (iUsageType == SCREEN_CONTENT_REAL_TIME);
254 SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (m_pEncCtx->pVaa);
255 SRefInfoParam* BestRefCandidateParam = (bSceneLtr) ? (& (pVaaExt->sVaaLtrBestRefCandidate[0])) :
256 (& (pVaaExt->sVaaStrBestRefCandidate[0]));
257 return m_pSpatialPic[0][BestRefCandidateParam->iSrcListIdx];
258
259 }
GetBestRefPic(const int32_t kiDidx,const int32_t iRefTemporalIdx)260 SPicture* CWelsPreProcess::GetBestRefPic (const int32_t kiDidx, const int32_t iRefTemporalIdx) {
261
262 return m_pSpatialPic[kiDidx][iRefTemporalIdx];
263 }
264
AnalyzeSpatialPic(sWelsEncCtx * pCtx,const int32_t kiDidx)265 int32_t CWelsPreProcess::AnalyzeSpatialPic (sWelsEncCtx* pCtx, const int32_t kiDidx) {
266 SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
267 bool bNeededMbAq = (pSvcParam->bEnableAdaptiveQuant && (pCtx->eSliceType == P_SLICE));
268 bool bCalculateBGD = (pCtx->eSliceType == P_SLICE && pSvcParam->bEnableBackgroundDetection);
269 SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[kiDidx];
270 int32_t iCurTemporalIdx = m_uiSpatialLayersInTemporal[kiDidx] - 1;
271
272 int32_t iRefTemporalIdx = (int32_t)g_kuiRefTemporalIdx[pSvcParam->iDecompStages][pParamInternal->iCodingIndex &
273 (pSvcParam->uiGopSize - 1)];
274 if (pCtx->uiTemporalId == 0 && pCtx->pLtr[pCtx->uiDependencyId].bReceivedT0LostFlag)
275 iRefTemporalIdx = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiValidLongTermPicIdx;
276
277 SPicture* pCurPic = m_pSpatialPic[kiDidx][iCurTemporalIdx];
278 bool bCalculateVar = (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == I_SLICE);
279
280 if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
281 SPicture* pRefPic = GetBestRefPic (pSvcParam->iUsageType, pCtx->bCurFrameMarkedAsSceneLtr, pCtx->eSliceType, kiDidx,
282 iRefTemporalIdx);
283
284 VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, false, bCalculateVar, bCalculateBGD);
285
286 if (pSvcParam->bEnableBackgroundDetection) {
287 BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE);
288 }
289 if (bNeededMbAq) {
290 AdaptiveQuantCalculation (pCtx->pVaa, pCurPic, pRefPic);
291 }
292 } else {
293 SPicture* pRefPic = GetBestRefPic (kiDidx, iRefTemporalIdx);
294 SPicture* pLastPic = m_pLastSpatialPicture[kiDidx][0];
295 bool bCalculateSQDiff = ((pLastPic->pData[0] == pRefPic->pData[0]) && bNeededMbAq);
296
297 VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, bCalculateSQDiff, bCalculateVar, bCalculateBGD);
298
299 if (pSvcParam->bEnableBackgroundDetection) {
300 BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE);
301 }
302
303 if (bNeededMbAq) {
304 AdaptiveQuantCalculation (pCtx->pVaa, m_pLastSpatialPicture[kiDidx][1], m_pLastSpatialPicture[kiDidx][0]);
305 }
306 }
307 return 0;
308 }
309
GetCurPicPosition(const int32_t kiDidx)310 int32_t CWelsPreProcess::GetCurPicPosition (const int32_t kiDidx) {
311 return (m_uiSpatialLayersInTemporal[kiDidx] - 1);
312 }
313
UpdateSpatialPictures(sWelsEncCtx * pCtx,SWelsSvcCodingParam * pParam,const int8_t iCurTid,const int32_t kiDidx)314 int32_t CWelsPreProcess::UpdateSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam,
315 const int8_t iCurTid, const int32_t kiDidx) {
316 if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME)
317 return 0;
318
319 WelsExchangeSpatialPictures (&m_pLastSpatialPicture[kiDidx][1], &m_pLastSpatialPicture[kiDidx][0]);
320
321 const int32_t kiCurPos = GetCurPicPosition (kiDidx);
322 if (iCurTid < kiCurPos || pParam->iDecompStages == 0) {
323 if ((iCurTid >= MAX_TEMPORAL_LEVEL) || (kiCurPos > MAX_TEMPORAL_LEVEL)) {
324 InitLastSpatialPictures (pCtx);
325 return 1;
326 }
327 if (pCtx->bRefOfCurTidIsLtr[kiDidx][iCurTid]) {
328 const int32_t kiAvailableLtrPos = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiMarkLongTermPicIdx;
329 WelsExchangeSpatialPictures (&m_pSpatialPic[kiDidx][kiAvailableLtrPos],
330 &m_pSpatialPic[kiDidx][iCurTid]);
331 pCtx->bRefOfCurTidIsLtr[kiDidx][iCurTid] = false;
332 }
333 WelsExchangeSpatialPictures (&m_pSpatialPic[kiDidx][kiCurPos],
334 &m_pSpatialPic[kiDidx][iCurTid]);
335
336
337 }
338 return 0;
339 }
340
341
342 /*
343 * SingleLayerPreprocess: down sampling if applicable
344 * @return: exact number of spatial layers need to encoder indeed
345 */
SingleLayerPreprocess(sWelsEncCtx * pCtx,const SSourcePicture * kpSrc,Scaled_Picture * pScaledPicture)346 int32_t CWelsPreProcess::SingleLayerPreprocess (sWelsEncCtx* pCtx, const SSourcePicture* kpSrc,
347 Scaled_Picture* pScaledPicture) {
348 SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
349 int8_t iDependencyId = pSvcParam->iSpatialLayerNum - 1;
350
351 SPicture* pSrcPic = NULL; // large
352 SPicture* pDstPic = NULL; // small
353 SSpatialLayerConfig* pDlayerParam = NULL;
354 SSpatialLayerInternal* pDlayerParamInternal = NULL;
355 int32_t iSpatialNum = 0;
356 int32_t iSrcWidth = 0;
357 int32_t iSrcHeight = 0;
358 int32_t iTargetWidth = 0;
359 int32_t iTargetHeight = 0;
360 int32_t iTemporalId = 0;
361 int32_t iClosestDid = iDependencyId;
362 pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId];
363 pDlayerParam = &pSvcParam->sSpatialLayers[iDependencyId];
364 iTargetWidth = pDlayerParam->iVideoWidth;
365 iTargetHeight = pDlayerParam->iVideoHeight;
366
367 iSrcWidth = pSvcParam->SUsedPicRect.iWidth;
368 iSrcHeight = pSvcParam->SUsedPicRect.iHeight;
369 if (pSvcParam->uiIntraPeriod) {
370 pCtx->pVaa->bIdrPeriodFlag = (1 + pDlayerParamInternal->iFrameIndex >= (int32_t)pSvcParam->uiIntraPeriod) ? true :
371 false;
372 if (pCtx->pVaa->bIdrPeriodFlag) {
373 WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG,
374 "pSvcParam->uiIntraPeriod=%d, pCtx->pVaa->bIdrPeriodFlag=%d",
375 pSvcParam->uiIntraPeriod,
376 pCtx->pVaa->bIdrPeriodFlag);
377 }
378 }
379
380 pSrcPic = pScaledPicture->pScaledInputPicture ? pScaledPicture->pScaledInputPicture : GetCurrentOrigFrame (
381 iDependencyId);
382
383 WelsMoveMemoryWrapper (pSvcParam, pSrcPic, kpSrc, iSrcWidth, iSrcHeight);
384
385 if (pSvcParam->bEnableDenoise)
386 BilateralDenoising (pSrcPic, iSrcWidth, iSrcHeight);
387
388 // different scaling in between input picture and dst highest spatial picture.
389 int32_t iShrinkWidth = iSrcWidth;
390 int32_t iShrinkHeight = iSrcHeight;
391 pDstPic = pSrcPic;
392 if (pScaledPicture->pScaledInputPicture) {
393 // for highest downsampling
394 pDstPic = GetCurrentOrigFrame (iDependencyId);
395 iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId];
396 iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId];
397 }
398 DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight,
399 false);
400
401 if (pSvcParam->bEnableSceneChangeDetect && !pCtx->pVaa->bIdrPeriodFlag) {
402 if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
403 pCtx->pVaa->eSceneChangeIdc = (pDlayerParamInternal->bEncCurFrmAsIdrFlag ? LARGE_CHANGED_SCENE :
404 DetectSceneChange (pDstPic));
405 pCtx->pVaa->bSceneChangeFlag = (LARGE_CHANGED_SCENE == pCtx->pVaa->eSceneChangeIdc);
406 } else {
407 if ((!pDlayerParamInternal->bEncCurFrmAsIdrFlag)
408 && ! (pDlayerParamInternal->iCodingIndex & (pSvcParam->uiGopSize - 1))) {
409 SPicture* pRefPic = pCtx->pLtr[iDependencyId].bReceivedT0LostFlag ?
410 m_pSpatialPic[iDependencyId][m_uiSpatialLayersInTemporal[iDependencyId] +
411 pCtx->pVaa->uiValidLongTermPicIdx] : m_pLastSpatialPicture[iDependencyId][0];
412 //pCtx->pVaa->eSceneChangeIdc = DetectSceneChange (pDstPic, pRefPic);
413 pCtx->pVaa->bSceneChangeFlag = GetSceneChangeFlag (DetectSceneChange (pDstPic, pRefPic));
414 }
415 }
416 }
417
418 for (int32_t i = 0; i < pSvcParam->iSpatialLayerNum; i++) {
419 pDlayerParamInternal = &pSvcParam->sDependencyLayers[i];
420 iTemporalId = pDlayerParamInternal->uiCodingIdx2TemporalId[pDlayerParamInternal->iCodingIndex &
421 (pSvcParam->uiGopSize - 1)];
422 if (iTemporalId != INVALID_TEMPORAL_ID) {
423 ++ iSpatialNum;
424 }
425 }
426 pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId];
427 iTemporalId = pDlayerParamInternal->uiCodingIdx2TemporalId[pDlayerParamInternal->iCodingIndex &
428 (pSvcParam->uiGopSize - 1)];
429 int iActualSpatialNum = iSpatialNum - 1;
430 if (iTemporalId != INVALID_TEMPORAL_ID) {
431 WelsUpdateSpatialIdxMap (pCtx, iActualSpatialNum, pDstPic, iDependencyId);
432 -- iActualSpatialNum;
433 }
434
435 m_pLastSpatialPicture[iDependencyId][1] = GetCurrentOrigFrame (iDependencyId);
436 -- iDependencyId;
437
438
439 // generate other spacial layer
440 // pSrc is
441 // -- padded input pic, if downsample should be applied to generate highest layer, [if] block above
442 // -- highest layer, if no downsampling, [else] block above
443 if (pSvcParam->iSpatialLayerNum > 1) {
444 while (iDependencyId >= 0) {
445 pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId];
446 pDlayerParam = &pSvcParam->sSpatialLayers[iDependencyId];
447 SPicture* pSrcPic = m_pLastSpatialPicture[iClosestDid][1]; // large
448 iTargetWidth = pDlayerParam->iVideoWidth;
449 iTargetHeight = pDlayerParam->iVideoHeight;
450 iTemporalId = pDlayerParamInternal->uiCodingIdx2TemporalId[pDlayerParamInternal->iCodingIndex &
451 (pSvcParam->uiGopSize - 1)];
452
453 // down sampling performed
454 int32_t iSrcWidth = pScaledPicture->iScaledWidth[iClosestDid];
455 int32_t iSrcHeight = pScaledPicture->iScaledHeight[iClosestDid];
456 pDstPic = GetCurrentOrigFrame (iDependencyId); // small
457 iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId];
458 iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId];
459 DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight,
460 true);
461
462 if ((iTemporalId != INVALID_TEMPORAL_ID)) {
463 WelsUpdateSpatialIdxMap (pCtx, iActualSpatialNum, pDstPic, iDependencyId);
464 iActualSpatialNum--;
465 }
466
467 m_pLastSpatialPicture[iDependencyId][1] = pDstPic;
468
469 iClosestDid = iDependencyId;
470 -- iDependencyId;
471
472 }
473 }
474 return iSpatialNum;
475
476 }
477
478
479 /*!
480 * \brief Whether input picture need be scaled?
481 */
JudgeNeedOfScaling(SWelsSvcCodingParam * pParam,Scaled_Picture * pScaledPicture)482 bool JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture) {
483 const int32_t kiInputPicWidth = pParam->SUsedPicRect.iWidth;
484 const int32_t kiInputPicHeight = pParam->SUsedPicRect.iHeight;
485 const int32_t kiDstPicWidth = pParam->sDependencyLayers[pParam->iSpatialLayerNum - 1].iActualWidth;
486 const int32_t kiDstPicHeight = pParam->sDependencyLayers[pParam->iSpatialLayerNum - 1].iActualHeight;
487 bool bNeedDownsampling = true;
488
489 int32_t iSpatialIdx = pParam->iSpatialLayerNum - 1;
490
491 if (kiDstPicWidth >= kiInputPicWidth && kiDstPicHeight >= kiInputPicHeight) {
492 bNeedDownsampling = false;
493 }
494
495 for (; iSpatialIdx >= 0; iSpatialIdx --) {
496 SSpatialLayerInternal* pCurLayer = &pParam->sDependencyLayers[iSpatialIdx];
497 int32_t iCurDstWidth = pCurLayer->iActualWidth;
498 int32_t iCurDstHeight = pCurLayer->iActualHeight;
499 int32_t iInputWidthXDstHeight = kiInputPicWidth * iCurDstHeight;
500 int32_t iInputHeightXDstWidth = kiInputPicHeight * iCurDstWidth;
501
502 if (iInputWidthXDstHeight > iInputHeightXDstWidth) {
503 pScaledPicture->iScaledWidth[iSpatialIdx] = WELS_MAX (iCurDstWidth, 4);
504 pScaledPicture->iScaledHeight[iSpatialIdx] = WELS_MAX (iInputHeightXDstWidth / kiInputPicWidth, 4);
505 } else {
506 pScaledPicture->iScaledWidth[iSpatialIdx] = WELS_MAX (iInputWidthXDstHeight / kiInputPicHeight, 4);
507 pScaledPicture->iScaledHeight[iSpatialIdx] = WELS_MAX (iCurDstHeight, 4);
508 }
509 }
510
511 return bNeedDownsampling;
512 }
513
WelsInitScaledPic(SWelsSvcCodingParam * pParam,Scaled_Picture * pScaledPicture,CMemoryAlign * pMemoryAlign)514 int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture, CMemoryAlign* pMemoryAlign) {
515 bool bInputPicNeedScaling = JudgeNeedOfScaling (pParam, pScaledPicture);
516 if (bInputPicNeedScaling) {
517 pScaledPicture->pScaledInputPicture = AllocPicture (pMemoryAlign, pParam->SUsedPicRect.iWidth,
518 pParam->SUsedPicRect.iHeight, false, 0);
519 if (pScaledPicture->pScaledInputPicture == NULL)
520 return -1;
521
522 // Avoid valgrind false positives.
523 //
524 // X86 SIMD downsampling routines may, for convenience, read slightly beyond
525 // the input data and into the alignment padding area beyond each line. This
526 // causes valgrind to warn about uninitialized values even if these values
527 // only affect lanes of a SIMD vector that are effectively never used.
528 //
529 // Avoid these false positives by zero-initializing the padding area beyond
530 // each line of the source buffer used for downsampling.
531 SPicture* pPic = pScaledPicture->pScaledInputPicture;
532 ClearEndOfLinePadding (pPic->pData[0], pPic->iLineSize[0], pPic->iWidthInPixel, pPic->iHeightInPixel);
533 ClearEndOfLinePadding (pPic->pData[1], pPic->iLineSize[1], pPic->iWidthInPixel >> 1, pPic->iHeightInPixel >> 1);
534 ClearEndOfLinePadding (pPic->pData[2], pPic->iLineSize[2], pPic->iWidthInPixel >> 1, pPic->iHeightInPixel >> 1);
535 }
536 return 0;
537 }
538
FreeScaledPic(Scaled_Picture * pScaledPicture,CMemoryAlign * pMemoryAlign)539 void FreeScaledPic (Scaled_Picture* pScaledPicture, CMemoryAlign* pMemoryAlign) {
540 if (pScaledPicture->pScaledInputPicture) {
541 FreePicture (pMemoryAlign, &pScaledPicture->pScaledInputPicture);
542 pScaledPicture->pScaledInputPicture = NULL;
543 }
544 }
545
InitLastSpatialPictures(sWelsEncCtx * pCtx)546 int32_t CWelsPreProcess::InitLastSpatialPictures (sWelsEncCtx* pCtx) {
547 SWelsSvcCodingParam* pParam = pCtx->pSvcParam;
548 const int32_t kiDlayerCount = pParam->iSpatialLayerNum;
549 int32_t iDlayerIndex = 0;
550 if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
551 for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) {
552 m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL;
553 }
554 } else {
555 for (; iDlayerIndex < kiDlayerCount; iDlayerIndex++) {
556 const int32_t kiLayerInTemporal = m_uiSpatialLayersInTemporal[iDlayerIndex];
557 m_pLastSpatialPicture[iDlayerIndex][0] = m_pSpatialPic[iDlayerIndex][kiLayerInTemporal - 2];
558 m_pLastSpatialPicture[iDlayerIndex][1] = NULL;
559 }
560 for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) {
561 m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL;
562 }
563 }
564 return 0;
565 }
566 //*********************************************************************************************************/
567
ColorspaceConvert(SWelsSvcCodingParam * pSvcParam,SPicture * pDstPic,const SSourcePicture * kpSrc,const int32_t kiWidth,const int32_t kiHeight)568 int32_t CWelsPreProcess::ColorspaceConvert (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic,
569 const SSourcePicture* kpSrc, const int32_t kiWidth, const int32_t kiHeight) {
570 return 1;
571 //not support yet
572 }
573
BilateralDenoising(SPicture * pSrc,const int32_t kiWidth,const int32_t kiHeight)574 void CWelsPreProcess::BilateralDenoising (SPicture* pSrc, const int32_t kiWidth, const int32_t kiHeight) {
575 int32_t iMethodIdx = METHOD_DENOISE;
576 SPixMap sSrcPixMap;
577 memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
578 sSrcPixMap.pPixel[0] = pSrc->pData[0];
579 sSrcPixMap.pPixel[1] = pSrc->pData[1];
580 sSrcPixMap.pPixel[2] = pSrc->pData[2];
581 sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
582 sSrcPixMap.sRect.iRectWidth = kiWidth;
583 sSrcPixMap.sRect.iRectHeight = kiHeight;
584 sSrcPixMap.iStride[0] = pSrc->iLineSize[0];
585 sSrcPixMap.iStride[1] = pSrc->iLineSize[1];
586 sSrcPixMap.iStride[2] = pSrc->iLineSize[2];
587 sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
588
589 m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, NULL);
590 }
591
DetectSceneChange(SPicture * pCurPicture,SPicture * pRefPicture)592 ESceneChangeIdc CWelsPreProcessVideo::DetectSceneChange (SPicture* pCurPicture, SPicture* pRefPicture) {
593 int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION_VIDEO;
594 SSceneChangeResult sSceneChangeDetectResult = { SIMILAR_SCENE };
595 SPixMap sSrcPixMap;
596 SPixMap sRefPixMap;
597 memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
598 memset (&sRefPixMap, 0, sizeof (sRefPixMap));
599 sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
600 sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
601 sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
602 sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
603 sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
604 sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
605
606 sRefPixMap.pPixel[0] = pRefPicture->pData[0];
607 sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
608 sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
609 sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
610 sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
611 sRefPixMap.eFormat = VIDEO_FORMAT_I420;
612
613 int32_t iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
614 if (iRet == 0) {
615 m_pInterfaceVp->Get (iMethodIdx, (void*)&sSceneChangeDetectResult);
616 //bSceneChangeFlag = (sSceneChangeDetectResult.eSceneChangeIdc == LARGE_CHANGED_SCENE) ? true : false;
617 }
618 return sSceneChangeDetectResult.eSceneChangeIdc;
619 }
620
GetCurrentOrigFrame(int32_t iDIdx)621 SPicture* CWelsPreProcessVideo::GetCurrentOrigFrame (int32_t iDIdx) {
622 return m_pSpatialPic[iDIdx][GetCurPicPosition (iDIdx)];
623 }
624
DownsamplePadding(SPicture * pSrc,SPicture * pDstPic,int32_t iSrcWidth,int32_t iSrcHeight,int32_t iShrinkWidth,int32_t iShrinkHeight,int32_t iTargetWidth,int32_t iTargetHeight,bool bForceCopy)625 int32_t CWelsPreProcess::DownsamplePadding (SPicture* pSrc, SPicture* pDstPic, int32_t iSrcWidth, int32_t iSrcHeight,
626 int32_t iShrinkWidth, int32_t iShrinkHeight, int32_t iTargetWidth, int32_t iTargetHeight, bool bForceCopy) {
627 int32_t iRet = 0;
628 SPixMap sSrcPixMap;
629 SPixMap sDstPicMap;
630 memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
631 memset (&sDstPicMap, 0, sizeof (sDstPicMap));
632 sSrcPixMap.pPixel[0] = pSrc->pData[0];
633 sSrcPixMap.pPixel[1] = pSrc->pData[1];
634 sSrcPixMap.pPixel[2] = pSrc->pData[2];
635 sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
636 sSrcPixMap.sRect.iRectWidth = iSrcWidth;
637 sSrcPixMap.sRect.iRectHeight = iSrcHeight;
638 sSrcPixMap.iStride[0] = pSrc->iLineSize[0];
639 sSrcPixMap.iStride[1] = pSrc->iLineSize[1];
640 sSrcPixMap.iStride[2] = pSrc->iLineSize[2];
641 sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
642
643 if (iSrcWidth != iShrinkWidth || iSrcHeight != iShrinkHeight || bForceCopy) {
644 int32_t iMethodIdx = METHOD_DOWNSAMPLE;
645 sDstPicMap.pPixel[0] = pDstPic->pData[0];
646 sDstPicMap.pPixel[1] = pDstPic->pData[1];
647 sDstPicMap.pPixel[2] = pDstPic->pData[2];
648 sDstPicMap.iSizeInBits = g_kiPixMapSizeInBits;
649 sDstPicMap.sRect.iRectWidth = iShrinkWidth;
650 sDstPicMap.sRect.iRectHeight = iShrinkHeight;
651 sDstPicMap.iStride[0] = pDstPic->iLineSize[0];
652 sDstPicMap.iStride[1] = pDstPic->iLineSize[1];
653 sDstPicMap.iStride[2] = pDstPic->iLineSize[2];
654 sDstPicMap.eFormat = VIDEO_FORMAT_I420;
655
656 if (iSrcWidth != iShrinkWidth || iSrcHeight != iShrinkHeight) {
657 iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sDstPicMap);
658 } else {
659 WelsMoveMemory_c (pDstPic->pData[0], pDstPic->pData[1], pDstPic->pData[2], pDstPic->iLineSize[0], pDstPic->iLineSize[1],
660 pSrc->pData[0], pSrc->pData[1], pSrc->pData[2], pSrc->iLineSize[0], pSrc->iLineSize[1],
661 iSrcWidth, iSrcHeight);
662 }
663 } else {
664 memcpy (&sDstPicMap, &sSrcPixMap, sizeof (sDstPicMap)); // confirmed_safe_unsafe_usage
665 }
666
667 // get rid of odd line
668 iShrinkWidth -= (iShrinkWidth & 1);
669 iShrinkHeight -= (iShrinkHeight & 1);
670 Padding ((uint8_t*)sDstPicMap.pPixel[0], (uint8_t*)sDstPicMap.pPixel[1], (uint8_t*)sDstPicMap.pPixel[2],
671 sDstPicMap.iStride[0], sDstPicMap.iStride[1], iShrinkWidth, iTargetWidth, iShrinkHeight, iTargetHeight);
672
673 return iRet;
674 }
675
676 //*********************************************************************************************************/
VaaCalculation(SVAAFrameInfo * pVaaInfo,SPicture * pCurPicture,SPicture * pRefPicture,bool bCalculateSQDiff,bool bCalculateVar,bool bCalculateBGD)677 void CWelsPreProcess::VaaCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
678 bool bCalculateSQDiff, bool bCalculateVar, bool bCalculateBGD) {
679 pVaaInfo->sVaaCalcInfo.pCurY = pCurPicture->pData[0];
680 pVaaInfo->sVaaCalcInfo.pRefY = pRefPicture->pData[0];
681 {
682 int32_t iMethodIdx = METHOD_VAA_STATISTICS;
683 SPixMap sCurPixMap;
684 SPixMap sRefPixMap;
685 memset (&sCurPixMap, 0, sizeof (sCurPixMap));
686 memset (&sRefPixMap, 0, sizeof (sRefPixMap));
687 SVAACalcParam calc_param = {0};
688
689 sCurPixMap.pPixel[0] = pCurPicture->pData[0];
690 sCurPixMap.iSizeInBits = g_kiPixMapSizeInBits;
691 sCurPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
692 sCurPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
693 sCurPixMap.iStride[0] = pCurPicture->iLineSize[0];
694 sCurPixMap.eFormat = VIDEO_FORMAT_I420;
695
696 sRefPixMap.pPixel[0] = pRefPicture->pData[0];
697 sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
698 sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
699 sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
700 sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
701 sRefPixMap.eFormat = VIDEO_FORMAT_I420;
702
703 calc_param.iCalcVar = bCalculateVar;
704 calc_param.iCalcBgd = bCalculateBGD;
705 calc_param.iCalcSsd = bCalculateSQDiff;
706 calc_param.pCalcResult = &pVaaInfo->sVaaCalcInfo;
707
708 m_pInterfaceVp->Set (iMethodIdx, &calc_param);
709 m_pInterfaceVp->Process (iMethodIdx, &sCurPixMap, &sRefPixMap);
710 }
711 }
712
BackgroundDetection(SVAAFrameInfo * pVaaInfo,SPicture * pCurPicture,SPicture * pRefPicture,bool bDetectFlag)713 void CWelsPreProcess::BackgroundDetection (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
714 bool bDetectFlag) {
715 if (bDetectFlag) {
716 pVaaInfo->iPicWidth = pCurPicture->iWidthInPixel;
717 pVaaInfo->iPicHeight = pCurPicture->iHeightInPixel;
718
719 pVaaInfo->iPicStride = pCurPicture->iLineSize[0];
720 pVaaInfo->iPicStrideUV = pCurPicture->iLineSize[1];
721 pVaaInfo->pCurY = pCurPicture->pData[0];
722 pVaaInfo->pRefY = pRefPicture->pData[0];
723 pVaaInfo->pCurU = pCurPicture->pData[1];
724 pVaaInfo->pRefU = pRefPicture->pData[1];
725 pVaaInfo->pCurV = pCurPicture->pData[2];
726 pVaaInfo->pRefV = pRefPicture->pData[2];
727
728 int32_t iMethodIdx = METHOD_BACKGROUND_DETECTION;
729 SPixMap sSrcPixMap;
730 SPixMap sRefPixMap;
731 memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
732 memset (&sRefPixMap, 0, sizeof (sRefPixMap));
733 SBGDInterface BGDParam = {0};
734
735 sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
736 sSrcPixMap.pPixel[1] = pCurPicture->pData[1];
737 sSrcPixMap.pPixel[2] = pCurPicture->pData[2];
738 sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
739 sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
740 sSrcPixMap.iStride[1] = pCurPicture->iLineSize[1];
741 sSrcPixMap.iStride[2] = pCurPicture->iLineSize[2];
742 sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
743 sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
744 sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
745
746 sRefPixMap.pPixel[0] = pRefPicture->pData[0];
747 sRefPixMap.pPixel[1] = pRefPicture->pData[1];
748 sRefPixMap.pPixel[2] = pRefPicture->pData[2];
749 sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
750 sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
751 sRefPixMap.iStride[1] = pRefPicture->iLineSize[1];
752 sRefPixMap.iStride[2] = pRefPicture->iLineSize[2];
753 sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
754 sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
755 sRefPixMap.eFormat = VIDEO_FORMAT_I420;
756
757 BGDParam.pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
758 BGDParam.pCalcRes = & (pVaaInfo->sVaaCalcInfo);
759 m_pInterfaceVp->Set (iMethodIdx, (void*)&BGDParam);
760 m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
761 } else {
762 int32_t iPicWidthInMb = (pCurPicture->iWidthInPixel + 15) >> 4;
763 int32_t iPicHeightInMb = (pCurPicture->iHeightInPixel + 15) >> 4;
764 memset (pVaaInfo->pVaaBackgroundMbFlag, 0, iPicWidthInMb * iPicHeightInMb);
765 }
766 }
767
AdaptiveQuantCalculation(SVAAFrameInfo * pVaaInfo,SPicture * pCurPicture,SPicture * pRefPicture)768 void CWelsPreProcess::AdaptiveQuantCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture) {
769 pVaaInfo->sAdaptiveQuantParam.pCalcResult = & (pVaaInfo->sVaaCalcInfo);
770 pVaaInfo->sAdaptiveQuantParam.iAverMotionTextureIndexToDeltaQp = 0;
771
772 {
773 int32_t iMethodIdx = METHOD_ADAPTIVE_QUANT;
774 SPixMap pSrc;
775 SPixMap pRef;
776 memset (&pSrc, 0, sizeof (pSrc));
777 memset (&pRef, 0, sizeof (pRef));
778 int32_t iRet = 0;
779
780 pSrc.pPixel[0] = pCurPicture->pData[0];
781 pSrc.iSizeInBits = g_kiPixMapSizeInBits;
782 pSrc.iStride[0] = pCurPicture->iLineSize[0];
783 pSrc.sRect.iRectWidth = pCurPicture->iWidthInPixel;
784 pSrc.sRect.iRectHeight = pCurPicture->iHeightInPixel;
785 pSrc.eFormat = VIDEO_FORMAT_I420;
786
787 pRef.pPixel[0] = pRefPicture->pData[0];
788 pRef.iSizeInBits = g_kiPixMapSizeInBits;
789 pRef.iStride[0] = pRefPicture->iLineSize[0];
790 pRef.sRect.iRectWidth = pRefPicture->iWidthInPixel;
791 pRef.sRect.iRectHeight = pRefPicture->iHeightInPixel;
792 pRef.eFormat = VIDEO_FORMAT_I420;
793
794 iRet = m_pInterfaceVp->Set (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
795 iRet = m_pInterfaceVp->Process (iMethodIdx, &pSrc, &pRef);
796 if (iRet == 0)
797 m_pInterfaceVp->Get (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
798 }
799 }
800
SetRefMbType(sWelsEncCtx * pCtx,uint32_t ** pRefMbTypeArray,int32_t iRefPicType)801 void CWelsPreProcess::SetRefMbType (sWelsEncCtx* pCtx, uint32_t** pRefMbTypeArray, int32_t iRefPicType) {
802 const uint8_t uiTid = pCtx->uiTemporalId;
803 const uint8_t uiDid = pCtx->uiDependencyId;
804 SRefList* pRefPicLlist = pCtx->ppRefPicListExt[uiDid];
805 SLTRState* pLtr = &pCtx->pLtr[uiDid];
806 uint8_t i = 0;
807
808 if (pCtx->pSvcParam->bEnableLongTermReference && pLtr->bReceivedT0LostFlag && uiTid == 0) {
809 for (i = 0; i < pRefPicLlist->uiLongRefCount; i++) {
810 SPicture* pRef = pRefPicLlist->pLongRefList[i];
811 if (pRef != NULL && pRef->uiRecieveConfirmed == 1/*RECIEVE_SUCCESS*/) {
812 *pRefMbTypeArray = pRef->uiRefMbType;
813 break;
814 }
815 }
816 } else {
817 for (i = 0; i < pRefPicLlist->uiShortRefCount; i++) {
818 SPicture* pRef = pRefPicLlist->pShortRefList[i];
819 if (pRef != NULL && pRef->bUsedAsRef && pRef->iFramePoc >= 0 && pRef->uiTemporalId <= uiTid) {
820 *pRefMbTypeArray = pRef->uiRefMbType;
821 break;
822 }
823 }
824 }
825 }
826
827
AnalyzePictureComplexity(sWelsEncCtx * pCtx,SPicture * pCurPicture,SPicture * pRefPicture,const int32_t kiDependencyId,const bool bCalculateBGD)828 void CWelsPreProcess::AnalyzePictureComplexity (sWelsEncCtx* pCtx, SPicture* pCurPicture, SPicture* pRefPicture,
829 const int32_t kiDependencyId, const bool bCalculateBGD) {
830 SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
831 int32_t iComplexityAnalysisMode = 0;
832
833 if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
834 SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
835 SComplexityAnalysisScreenParam* sComplexityAnalysisParam = &pVaaExt->sComplexityScreenParam;
836 SWelsSvcRc* pWelsSvcRc = &pCtx->pWelsSvcRc[kiDependencyId];
837
838 if (pCtx->eSliceType == P_SLICE)
839 iComplexityAnalysisMode = GOM_SAD;
840 else if (pCtx->eSliceType == I_SLICE)
841 iComplexityAnalysisMode = GOM_VAR;
842 else
843 return;
844
845 memset (pWelsSvcRc->pGomForegroundBlockNum, 0, pWelsSvcRc->iGomSize * sizeof (int32_t));
846 memset (pWelsSvcRc->pCurrentFrameGomSad, 0, pWelsSvcRc->iGomSize * sizeof (int32_t));
847
848 sComplexityAnalysisParam->iFrameComplexity = 0;
849 sComplexityAnalysisParam->pGomComplexity = pWelsSvcRc->pCurrentFrameGomSad;
850 sComplexityAnalysisParam->iGomNumInFrame = pWelsSvcRc->iGomSize;
851 sComplexityAnalysisParam->iIdrFlag = (pCtx->eSliceType == I_SLICE);
852 sComplexityAnalysisParam->iMbRowInGom = GOM_H_SCC;
853 sComplexityAnalysisParam->sScrollResult.bScrollDetectFlag = false;
854 sComplexityAnalysisParam->sScrollResult.iScrollMvX = 0;
855 sComplexityAnalysisParam->sScrollResult.iScrollMvY = 0;
856
857 const int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS_SCREEN;
858 SPixMap sSrcPixMap;
859 SPixMap sRefPixMap;
860 memset (&sSrcPixMap, 0, sizeof (SPixMap));
861 memset (&sRefPixMap, 0, sizeof (SPixMap));
862 int32_t iRet = 0;
863
864 sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
865 sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
866 sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
867 sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
868 sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
869 sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
870
871 if (pRefPicture != NULL) {
872 sRefPixMap.pPixel[0] = pRefPicture->pData[0];
873 sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
874 sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
875 sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
876 sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
877 sRefPixMap.eFormat = VIDEO_FORMAT_I420;
878 }
879
880 iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
881 iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
882 if (iRet == 0)
883 m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
884
885 } else {
886 SVAAFrameInfo* pVaaInfo = pCtx->pVaa;
887 SComplexityAnalysisParam* sComplexityAnalysisParam = & (pVaaInfo->sComplexityAnalysisParam);
888 SWelsSvcRc* SWelsSvcRc = &pCtx->pWelsSvcRc[kiDependencyId];
889
890 if (pSvcParam->iRCMode == RC_QUALITY_MODE && pCtx->eSliceType == P_SLICE) {
891 iComplexityAnalysisMode = FRAME_SAD;
892 } else if (((pSvcParam->iRCMode == RC_BITRATE_MODE) || (pSvcParam->iRCMode == RC_TIMESTAMP_MODE))
893 && pCtx->eSliceType == P_SLICE) {
894 iComplexityAnalysisMode = GOM_SAD;
895 } else if (((pSvcParam->iRCMode == RC_BITRATE_MODE) || (pSvcParam->iRCMode == RC_TIMESTAMP_MODE))
896 && pCtx->eSliceType == I_SLICE) {
897 iComplexityAnalysisMode = GOM_VAR;
898 } else {
899 return;
900 }
901
902 sComplexityAnalysisParam->iComplexityAnalysisMode = iComplexityAnalysisMode;
903 sComplexityAnalysisParam->pCalcResult = & (pVaaInfo->sVaaCalcInfo);
904 sComplexityAnalysisParam->pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
905 if (pRefPicture)
906 SetRefMbType (pCtx, & (sComplexityAnalysisParam->uiRefMbType), pRefPicture->iPictureType);
907 sComplexityAnalysisParam->iCalcBgd = bCalculateBGD;
908 sComplexityAnalysisParam->iFrameComplexity = 0;
909
910 memset (SWelsSvcRc->pGomForegroundBlockNum, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
911 if (iComplexityAnalysisMode != FRAME_SAD)
912 memset (SWelsSvcRc->pCurrentFrameGomSad, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
913
914 sComplexityAnalysisParam->pGomComplexity = SWelsSvcRc->pCurrentFrameGomSad;
915 sComplexityAnalysisParam->pGomForegroundBlockNum = SWelsSvcRc->pGomForegroundBlockNum;
916 sComplexityAnalysisParam->iMbNumInGom = SWelsSvcRc->iNumberMbGom;
917
918 {
919 int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS;
920 SPixMap sSrcPixMap;
921 SPixMap sRefPixMap;
922 memset (&sSrcPixMap, 0, sizeof (SPixMap));
923 memset (&sRefPixMap, 0, sizeof (SPixMap));
924 int32_t iRet = 0;
925
926 sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
927 sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
928 sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
929 sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
930 sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
931 sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
932
933 if (pRefPicture) {
934 sRefPixMap.pPixel[0] = pRefPicture->pData[0];
935 sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
936 sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
937 sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
938 sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
939 }
940 sRefPixMap.eFormat = VIDEO_FORMAT_I420;
941
942 iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
943 iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
944 if (iRet == 0)
945 m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
946 }
947 }
948 }
949
950
InitPixMap(const SPicture * pPicture,SPixMap * pPixMap)951 void CWelsPreProcess::InitPixMap (const SPicture* pPicture, SPixMap* pPixMap) {
952 pPixMap->pPixel[0] = pPicture->pData[0];
953 pPixMap->pPixel[1] = pPicture->pData[1];
954 pPixMap->pPixel[2] = pPicture->pData[2];
955 pPixMap->iSizeInBits = sizeof (uint8_t);
956 pPixMap->iStride[0] = pPicture->iLineSize[0];
957 pPixMap->iStride[1] = pPicture->iLineSize[1];
958 pPixMap->sRect.iRectWidth = pPicture->iWidthInPixel;
959 pPixMap->sRect.iRectHeight = pPicture->iHeightInPixel;
960
961 pPixMap->eFormat = VIDEO_FORMAT_I420;
962 }
963
GetReferenceSrcPicList(int32_t iTargetDid)964 SPicture** CWelsPreProcessScreen::GetReferenceSrcPicList (int32_t iTargetDid) {
965 return (&m_pSpatialPic[iTargetDid][1]);
966 }
967
GetAvailableRefListLosslessScreenRefSelection(SPicture ** pRefPicList,uint8_t iCurTid,const int32_t iClosestLtrFrameNum,SRefInfoParam * pAvailableRefParam,int32_t & iAvailableRefNum,int32_t & iAvailableSceneRefNum)968 void CWelsPreProcessScreen::GetAvailableRefListLosslessScreenRefSelection (SPicture** pRefPicList, uint8_t iCurTid,
969 const int32_t iClosestLtrFrameNum,
970 SRefInfoParam* pAvailableRefParam, int32_t& iAvailableRefNum, int32_t& iAvailableSceneRefNum) {
971 const int32_t iSourcePicNum = m_iAvaliableRefInSpatialPicList;
972 if (0 >= iSourcePicNum) {
973 iAvailableRefNum = 0;
974 iAvailableSceneRefNum = 0;
975 return ;
976 }
977 const bool bCurFrameMarkedAsSceneLtr = m_pEncCtx->bCurFrameMarkedAsSceneLtr;
978 SPicture* pRefPic = NULL;
979 uint8_t uiRefTid = 0;
980 bool bRefRealLtr = false;
981
982 iAvailableRefNum = 1; //zero is left for the closest frame
983 iAvailableSceneRefNum = 0;
984
985 //the saving order will be depend on pSrcPicList
986 //TODO: use a frame_idx to find the closer ref in time distance, and correctly sort the ref list
987 for (int32_t i = iSourcePicNum - 1; i >= 0; --i) {
988 pRefPic = pRefPicList[i];
989 if (NULL == pRefPic || !pRefPic->bUsedAsRef || !pRefPic->bIsLongRef || (bCurFrameMarkedAsSceneLtr
990 && (!pRefPic->bIsSceneLTR))) {
991 continue;
992 }
993 uiRefTid = pRefPic->uiTemporalId;
994 bRefRealLtr = pRefPic->bIsSceneLTR;
995
996 if (bRefRealLtr || (0 == iCurTid && 0 == uiRefTid) || (uiRefTid < iCurTid)) {
997 int32_t idx = (pRefPic->iLongTermPicNum == iClosestLtrFrameNum) ? (0) : (iAvailableRefNum++);
998 pAvailableRefParam[idx].pRefPicture = pRefPic;
999 pAvailableRefParam[idx].iSrcListIdx = i + 1; //in SrcList, the idx 0 is reserved for CurPic
1000 iAvailableSceneRefNum += bRefRealLtr;
1001 }
1002 }
1003
1004 if (pAvailableRefParam[0].pRefPicture == NULL) {
1005 for (int32_t i = 1; i < iAvailableRefNum ; ++i) {
1006 pAvailableRefParam[i - 1].pRefPicture = pAvailableRefParam[i].pRefPicture;
1007 pAvailableRefParam[i - 1].iSrcListIdx = pAvailableRefParam[i].iSrcListIdx;
1008 }
1009
1010 pAvailableRefParam[iAvailableRefNum - 1].pRefPicture = NULL;
1011 pAvailableRefParam[iAvailableRefNum - 1].iSrcListIdx = 0;
1012 --iAvailableRefNum;
1013 }
1014 }
1015
1016
GetAvailableRefList(SPicture ** pSrcPicList,uint8_t iCurTid,const int32_t iClosestLtrFrameNum,SRefInfoParam * pAvailableRefList,int32_t & iAvailableRefNum,int32_t & iAvailableSceneRefNum)1017 void CWelsPreProcessScreen::GetAvailableRefList (SPicture** pSrcPicList, uint8_t iCurTid,
1018 const int32_t iClosestLtrFrameNum,
1019 SRefInfoParam* pAvailableRefList, int32_t& iAvailableRefNum, int32_t& iAvailableSceneRefNum) {
1020 const int32_t iSourcePicNum = m_iAvaliableRefInSpatialPicList;
1021 if (0 >= iSourcePicNum) {
1022 iAvailableRefNum = 0;
1023 iAvailableSceneRefNum = 0;
1024 return ;
1025 }
1026 SPicture* pRefPic = NULL;
1027 uint8_t uiRefTid = 0;
1028 iAvailableRefNum = 0;
1029 iAvailableSceneRefNum = 0;
1030
1031 //the saving order will be depend on pSrcPicList
1032 //TODO: use a frame_idx to find the closer ref in time distance, and correctly sort the ref list
1033 for (int32_t i = iSourcePicNum - 1; i >= 0; --i) {
1034 pRefPic = pSrcPicList[i];
1035 if (NULL == pRefPic || !pRefPic->bUsedAsRef) {
1036 continue;
1037 }
1038 uiRefTid = pRefPic->uiTemporalId;
1039
1040 if (uiRefTid <= iCurTid) {
1041 pAvailableRefList[iAvailableRefNum].pRefPicture = pRefPic;
1042 pAvailableRefList[iAvailableRefNum].iSrcListIdx = i + 1; //in SrcList, the idx 0 is reserved for CurPic
1043 iAvailableRefNum ++;
1044 }
1045 }
1046 }
1047
1048
InitRefJudgement(SRefJudgement * pRefJudgement)1049 void CWelsPreProcessScreen::InitRefJudgement (SRefJudgement* pRefJudgement) {
1050 pRefJudgement->iMinFrameComplexity = INT_MAX;
1051 pRefJudgement->iMinFrameComplexity08 = INT_MAX;
1052 pRefJudgement->iMinFrameComplexity11 = INT_MAX;
1053
1054 pRefJudgement->iMinFrameNumGap = INT_MAX;
1055 pRefJudgement->iMinFrameQp = INT_MAX;
1056 }
JudgeBestRef(SPicture * pRefPic,const SRefJudgement & sRefJudgement,const int64_t iFrameComplexity,const bool bIsClosestLtrFrame)1057 bool CWelsPreProcessScreen::JudgeBestRef (SPicture* pRefPic, const SRefJudgement& sRefJudgement,
1058 const int64_t iFrameComplexity, const bool bIsClosestLtrFrame) {
1059 return (bIsClosestLtrFrame ? (iFrameComplexity < sRefJudgement.iMinFrameComplexity11) :
1060 ((iFrameComplexity < sRefJudgement.iMinFrameComplexity08) || ((iFrameComplexity <= sRefJudgement.iMinFrameComplexity11)
1061 && (pRefPic->iFrameAverageQp < sRefJudgement.iMinFrameQp))));
1062 }
1063
SaveBestRefToJudgement(const int32_t iRefPictureAvQP,const int64_t iComplexity,SRefJudgement * pRefJudgement)1064 void CWelsPreProcessScreen::SaveBestRefToJudgement (const int32_t iRefPictureAvQP, const int64_t iComplexity,
1065 SRefJudgement* pRefJudgement) {
1066 pRefJudgement->iMinFrameQp = iRefPictureAvQP;
1067 pRefJudgement->iMinFrameComplexity = iComplexity;
1068 pRefJudgement->iMinFrameComplexity08 = static_cast<int32_t> (iComplexity * 0.8);
1069 pRefJudgement->iMinFrameComplexity11 = static_cast<int32_t> (iComplexity * 1.1);
1070 }
SaveBestRefToLocal(SRefInfoParam * pRefPicInfo,const SSceneChangeResult & sSceneChangeResult,SRefInfoParam * pRefSaved)1071 void CWelsPreProcessScreen::SaveBestRefToLocal (SRefInfoParam* pRefPicInfo,
1072 const SSceneChangeResult& sSceneChangeResult,
1073 SRefInfoParam* pRefSaved) {
1074 memcpy (pRefSaved, pRefPicInfo, sizeof (SRefInfoParam));
1075 pRefSaved->pBestBlockStaticIdc = sSceneChangeResult.pStaticBlockIdc;
1076 }
1077
SaveBestRefToVaa(SRefInfoParam & sRefSaved,SRefInfoParam * pVaaBestRef)1078 void CWelsPreProcessScreen::SaveBestRefToVaa (SRefInfoParam& sRefSaved, SRefInfoParam* pVaaBestRef) {
1079 (*pVaaBestRef) = sRefSaved;
1080 }
1081
GetCurrentOrigFrame(int32_t iDIdx)1082 SPicture* CWelsPreProcessScreen::GetCurrentOrigFrame (int32_t iDIdx) {
1083 return m_pSpatialPic[iDIdx][0];
1084 }
1085
DetectSceneChange(SPicture * pCurPicture,SPicture * pRef)1086 ESceneChangeIdc CWelsPreProcessScreen::DetectSceneChange (SPicture* pCurPicture, SPicture* pRef) {
1087 sWelsEncCtx* pCtx = m_pEncCtx;
1088 #define STATIC_SCENE_MOTION_RATIO 0.01f
1089 SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
1090 SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
1091 SSpatialLayerInternal* pParamInternal = &pSvcParam->sDependencyLayers[0];
1092 if (NULL == pCtx || NULL == pVaaExt || NULL == pCurPicture) {
1093 return LARGE_CHANGED_SCENE;
1094 }
1095
1096 const int32_t iTargetDid = pSvcParam->iSpatialLayerNum - 1;
1097 if (0 != iTargetDid) {
1098 return LARGE_CHANGED_SCENE;
1099 }
1100
1101 ESceneChangeIdc iVaaFrameSceneChangeIdc = LARGE_CHANGED_SCENE;
1102 SPicture** pRefPicList = GetReferenceSrcPicList (iTargetDid);
1103 if (NULL == pRefPicList) {
1104 return LARGE_CHANGED_SCENE;
1105 }
1106
1107 SRefInfoParam sAvailableRefParam[MAX_REF_PIC_COUNT] = { { 0 } };
1108 int32_t iAvailableRefNum = 0;
1109 int32_t iAvailableSceneRefNum = 0;
1110
1111 int32_t iSceneChangeMethodIdx = METHOD_SCENE_CHANGE_DETECTION_SCREEN;
1112 SSceneChangeResult sSceneChangeResult = {SIMILAR_SCENE, 0, 0, NULL};
1113
1114 SPixMap sSrcMap = { { 0 } };
1115 SPixMap sRefMap = { { 0 } };
1116 SRefJudgement sLtrJudgement;
1117 SRefJudgement sSceneLtrJudgement;
1118 SRefInfoParam sLtrSaved = {0};
1119 SRefInfoParam sSceneLtrSaved = {0};
1120
1121 int32_t iNumOfLargeChange = 0, iNumOfMediumChangeToLtr = 0;
1122
1123 bool bIsClosestLtrFrame = false;
1124 int32_t ret = 1, iScdIdx = 0;
1125
1126 SPicture* pRefPic = NULL;
1127 SRefInfoParam* pRefPicInfo = NULL;
1128 uint8_t* pCurBlockStaticPointer = NULL;
1129 SLogContext* pLogCtx = & (pCtx->sLogCtx);
1130 const int32_t iNegligibleMotionBlocks = (static_cast<int32_t> ((pCurPicture->iWidthInPixel >> 3) *
1131 (pCurPicture->iHeightInPixel >> 3) * STATIC_SCENE_MOTION_RATIO));
1132 const uint8_t iCurTid = GetTemporalLevel (&pSvcParam->sDependencyLayers[m_pEncCtx->sSpatialIndexMap[0].iDid],
1133 pParamInternal->iCodingIndex, pSvcParam->uiGopSize);
1134 if (iCurTid == INVALID_TEMPORAL_ID) {
1135 return LARGE_CHANGED_SCENE;
1136 }
1137 const int32_t iClosestLtrFrameNum = pCtx->pLtr[iTargetDid].iLastLtrIdx[iCurTid];
1138 if (pSvcParam->bEnableLongTermReference) {
1139 GetAvailableRefListLosslessScreenRefSelection (pRefPicList, iCurTid, iClosestLtrFrameNum, &sAvailableRefParam[0],
1140 iAvailableRefNum,
1141 iAvailableSceneRefNum);
1142 } else {
1143 GetAvailableRefList (pRefPicList, iCurTid, iClosestLtrFrameNum, &sAvailableRefParam[0], iAvailableRefNum,
1144 iAvailableSceneRefNum);
1145 }
1146 //after this build, pAvailableRefList[idx].iSrcListIdx is the idx of the ref in h->spatial_pic
1147 if (0 == iAvailableRefNum) {
1148 WelsLog (pLogCtx, WELS_LOG_ERROR, "SceneChangeDetect() iAvailableRefNum=0 but not I.");
1149 return LARGE_CHANGED_SCENE;
1150 }
1151
1152 InitPixMap (pCurPicture, &sSrcMap);
1153 InitRefJudgement (&sLtrJudgement);
1154 InitRefJudgement (&sSceneLtrJudgement);
1155
1156 for (iScdIdx = 0; iScdIdx < iAvailableRefNum; iScdIdx ++) {
1157 pCurBlockStaticPointer = pVaaExt->pVaaBlockStaticIdc[iScdIdx];
1158 sSceneChangeResult.eSceneChangeIdc = SIMILAR_SCENE;
1159 sSceneChangeResult.pStaticBlockIdc = pCurBlockStaticPointer;
1160 sSceneChangeResult.sScrollResult.bScrollDetectFlag = false;
1161
1162 pRefPicInfo = & (sAvailableRefParam[iScdIdx]);
1163 assert (NULL != pRefPicInfo);
1164 pRefPic = pRefPicInfo->pRefPicture;
1165 InitPixMap (pRefPic, &sRefMap);
1166
1167 bIsClosestLtrFrame = (pRefPic->iLongTermPicNum == iClosestLtrFrameNum);
1168 if (0 == iScdIdx) {
1169 int32_t ret = 1;
1170 SScrollDetectionParam* pScrollDetectInfo = & (pVaaExt->sScrollDetectInfo);
1171 memset (pScrollDetectInfo, 0, sizeof (SScrollDetectionParam));
1172
1173 int32_t iMethodIdx = METHOD_SCROLL_DETECTION;
1174
1175 m_pInterfaceVp->Set (iMethodIdx, (void*) (pScrollDetectInfo));
1176 ret = m_pInterfaceVp->Process (iMethodIdx, &sSrcMap, &sRefMap);
1177
1178 if (ret == 0) {
1179 m_pInterfaceVp->Get (iMethodIdx, (void*) (pScrollDetectInfo));
1180 }
1181 sSceneChangeResult.sScrollResult = pVaaExt->sScrollDetectInfo;
1182 }
1183
1184 m_pInterfaceVp->Set (iSceneChangeMethodIdx, (void*) (&sSceneChangeResult));
1185 ret = m_pInterfaceVp->Process (iSceneChangeMethodIdx, &sSrcMap, &sRefMap);
1186
1187 if (ret == 0) {
1188 m_pInterfaceVp->Get (iSceneChangeMethodIdx, (void*)&sSceneChangeResult);
1189
1190 const int64_t iFrameComplexity = sSceneChangeResult.iFrameComplexity;
1191 const int32_t iSceneDetectIdc = sSceneChangeResult.eSceneChangeIdc;
1192 const int32_t iMotionBlockNum = sSceneChangeResult.iMotionBlockNum;
1193
1194 const bool bCurRefIsSceneLtr = pRefPic->bIsSceneLTR;
1195 const int32_t iRefPicAvQP = pRefPic->iFrameAverageQp;
1196
1197 //for scene change detection
1198 iNumOfLargeChange += (static_cast<int32_t> (LARGE_CHANGED_SCENE == iSceneDetectIdc));
1199 iNumOfMediumChangeToLtr += (static_cast<int32_t> ((bCurRefIsSceneLtr) && (iSceneDetectIdc != SIMILAR_SCENE)));
1200
1201 //for reference selection
1202 //this judge can only be saved when iAvailableRefNum==1, which is very limit
1203 //when LTR is OFF, it can still judge from all available STR
1204 if (JudgeBestRef (pRefPic, sLtrJudgement, iFrameComplexity, bIsClosestLtrFrame)) {
1205 SaveBestRefToJudgement (iRefPicAvQP, iFrameComplexity, &sLtrJudgement);
1206 SaveBestRefToLocal (pRefPicInfo, sSceneChangeResult, &sLtrSaved);
1207 }
1208 if (bCurRefIsSceneLtr && JudgeBestRef (pRefPic, sSceneLtrJudgement, iFrameComplexity, bIsClosestLtrFrame)) {
1209 SaveBestRefToJudgement (iRefPicAvQP, iFrameComplexity, &sSceneLtrJudgement);
1210 SaveBestRefToLocal (pRefPicInfo, sSceneChangeResult, &sSceneLtrSaved);
1211 }
1212
1213 if (iMotionBlockNum <= iNegligibleMotionBlocks) {
1214 break;
1215 }
1216 }
1217 }
1218
1219 if (iNumOfLargeChange == iAvailableRefNum) {
1220 iVaaFrameSceneChangeIdc = LARGE_CHANGED_SCENE;
1221 } else if ((iNumOfMediumChangeToLtr == iAvailableSceneRefNum) && (0 != iAvailableSceneRefNum)) {
1222 iVaaFrameSceneChangeIdc = MEDIUM_CHANGED_SCENE;
1223 } else {
1224 iVaaFrameSceneChangeIdc = SIMILAR_SCENE;
1225 }
1226
1227 WelsLog (pLogCtx, WELS_LOG_DEBUG, "iVaaFrameSceneChangeIdc = %d,codingIdx = %d", iVaaFrameSceneChangeIdc,
1228 pParamInternal->iCodingIndex);
1229
1230 SaveBestRefToVaa (sLtrSaved, & (pVaaExt->sVaaStrBestRefCandidate[0]));
1231 pVaaExt->iVaaBestRefFrameNum = sLtrSaved.pRefPicture->iFrameNum;
1232 pVaaExt->pVaaBestBlockStaticIdc = sLtrSaved.pBestBlockStaticIdc;
1233
1234 if (0 < iAvailableSceneRefNum) {
1235 SaveBestRefToVaa (sSceneLtrSaved, & (pVaaExt->sVaaLtrBestRefCandidate[0]));
1236 }
1237
1238 pVaaExt->iNumOfAvailableRef = 1;
1239 return static_cast<ESceneChangeIdc> (iVaaFrameSceneChangeIdc);
1240 }
1241
GetRefFrameInfo(int32_t iRefIdx,bool bCurrentFrameIsSceneLtr,SPicture * & pRefOri)1242 int32_t CWelsPreProcess::GetRefFrameInfo (int32_t iRefIdx, bool bCurrentFrameIsSceneLtr, SPicture*& pRefOri) {
1243 const int32_t iTargetDid = m_pEncCtx->pSvcParam->iSpatialLayerNum - 1;
1244 SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (m_pEncCtx->pVaa);
1245 SRefInfoParam* pBestRefCandidateParam = (bCurrentFrameIsSceneLtr) ? (& (pVaaExt->sVaaLtrBestRefCandidate[iRefIdx])) :
1246 (& (pVaaExt->sVaaStrBestRefCandidate[iRefIdx]));
1247 pRefOri = m_pSpatialPic[iTargetDid][pBestRefCandidateParam->iSrcListIdx];
1248 return (m_pSpatialPic[iTargetDid][pBestRefCandidateParam->iSrcListIdx]->iLongTermPicNum);
1249 }
Padding(uint8_t * pSrcY,uint8_t * pSrcU,uint8_t * pSrcV,int32_t iStrideY,int32_t iStrideUV,int32_t iActualWidth,int32_t iPaddingWidth,int32_t iActualHeight,int32_t iPaddingHeight)1250 void CWelsPreProcess::Padding (uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iStrideY, int32_t iStrideUV,
1251 int32_t iActualWidth, int32_t iPaddingWidth, int32_t iActualHeight, int32_t iPaddingHeight) {
1252 int32_t i;
1253
1254 if (iPaddingHeight > iActualHeight) {
1255 for (i = iActualHeight; i < iPaddingHeight; i++) {
1256 memset (pSrcY + i * iStrideY, 0, iActualWidth);
1257
1258 if (! (i & 1)) {
1259 memset (pSrcU + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
1260 memset (pSrcV + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
1261 }
1262 }
1263 }
1264
1265 if (iPaddingWidth > iActualWidth) {
1266 for (i = 0; i < iPaddingHeight; i++) {
1267 memset (pSrcY + i * iStrideY + iActualWidth, 0, iPaddingWidth - iActualWidth);
1268 if (! (i & 1)) {
1269 memset (pSrcU + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
1270 memset (pSrcV + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
1271 }
1272 }
1273 }
1274 }
1275
1276
UpdateBlockIdcForScreen(uint8_t * pCurBlockStaticPointer,const SPicture * kpRefPic,const SPicture * kpSrcPic)1277 int32_t CWelsPreProcess::UpdateBlockIdcForScreen (uint8_t* pCurBlockStaticPointer, const SPicture* kpRefPic,
1278 const SPicture* kpSrcPic) {
1279 int32_t iSceneChangeMethodIdx = METHOD_SCENE_CHANGE_DETECTION_SCREEN;
1280 SSceneChangeResult sSceneChangeResult = {SIMILAR_SCENE, 0, 0, NULL};
1281 sSceneChangeResult.pStaticBlockIdc = pCurBlockStaticPointer;
1282 sSceneChangeResult.sScrollResult.bScrollDetectFlag = false;
1283
1284 SPixMap sSrcMap = { { 0 } };
1285 SPixMap sRefMap = { { 0 } };
1286 InitPixMap (kpSrcPic, &sSrcMap);
1287 InitPixMap (kpRefPic, &sRefMap);
1288
1289 m_pInterfaceVp->Set (iSceneChangeMethodIdx, (void*) (&sSceneChangeResult));
1290 int32_t iRet = m_pInterfaceVp->Process (iSceneChangeMethodIdx, &sSrcMap, &sRefMap);
1291 if (iRet == 0) {
1292 m_pInterfaceVp->Get (iSceneChangeMethodIdx, (void*)&sSceneChangeResult);
1293 return 0;
1294 }
1295 return iRet;
1296 }
1297
1298 /*!
1299 * \brief exchange two picture pData planes
1300 * \param ppPic1 picture pointer to picture 1
1301 * \param ppPic2 picture pointer to picture 2
1302 * \return none
1303 */
WelsExchangeSpatialPictures(SPicture ** ppPic1,SPicture ** ppPic2)1304 void CWelsPreProcess::WelsExchangeSpatialPictures (SPicture** ppPic1, SPicture** ppPic2) {
1305 SPicture* tmp = *ppPic1;
1306
1307 assert (*ppPic1 != *ppPic2);
1308
1309 *ppPic1 = *ppPic2;
1310 *ppPic2 = tmp;
1311 }
1312
UpdateSrcListLosslessScreenRefSelectionWithLtr(SPicture * pCurPicture,const int32_t kiCurDid,const int32_t kuiMarkLongTermPicIdx,SPicture ** pLongRefList)1313 void CWelsPreProcess::UpdateSrcListLosslessScreenRefSelectionWithLtr (SPicture* pCurPicture, const int32_t kiCurDid,
1314 const int32_t kuiMarkLongTermPicIdx, SPicture** pLongRefList) {
1315 SPicture** pLongRefSrcList = &m_pSpatialPic[kiCurDid][0];
1316 for (int32_t i = 0; i < MAX_REF_PIC_COUNT; ++i) {
1317 if (NULL == pLongRefSrcList[i + 1] || (NULL != pLongRefList[i] && pLongRefList[i]->bUsedAsRef
1318 && pLongRefList[i]->bIsLongRef)) {
1319 continue;
1320 } else {
1321 pLongRefSrcList[i + 1]->SetUnref();
1322 }
1323 }
1324 WelsExchangeSpatialPictures (&m_pSpatialPic[kiCurDid][0],
1325 &m_pSpatialPic[kiCurDid][1 + kuiMarkLongTermPicIdx]);
1326 m_iAvaliableRefInSpatialPicList = MAX_REF_PIC_COUNT;
1327 (GetCurrentOrigFrame (kiCurDid))->SetUnref();
1328 }
UpdateSrcList(SPicture * pCurPicture,const int32_t kiCurDid,SPicture ** pShortRefList,const uint32_t kuiShortRefCount)1329 void CWelsPreProcess::UpdateSrcList (SPicture* pCurPicture, const int32_t kiCurDid, SPicture** pShortRefList,
1330 const uint32_t kuiShortRefCount) {
1331 SPicture** pRefSrcList = &m_pSpatialPic[kiCurDid][0];
1332
1333 //pRefSrcList[0] is for current frame
1334 if (pCurPicture->bUsedAsRef || pCurPicture->bIsLongRef) {
1335 if (pCurPicture->iPictureType == P_SLICE && pCurPicture->uiTemporalId != 0) {
1336 for (int iRefIdx = kuiShortRefCount - 1; iRefIdx >= 0; --iRefIdx) {
1337 WelsExchangeSpatialPictures (&pRefSrcList[iRefIdx + 1],
1338 &pRefSrcList[iRefIdx]);
1339 }
1340 m_iAvaliableRefInSpatialPicList = kuiShortRefCount;
1341 } else {
1342 WelsExchangeSpatialPictures (&pRefSrcList[0], &pRefSrcList[1]);
1343 for (int32_t i = MAX_SHORT_REF_COUNT - 1; i > 0 ; --i) {
1344 if (pRefSrcList[i + 1] != NULL) {
1345 pRefSrcList[i + 1]->SetUnref();
1346 }
1347 }
1348 m_iAvaliableRefInSpatialPicList = 1;
1349 }
1350 }
1351 (GetCurrentOrigFrame (kiCurDid))->SetUnref();
1352 }
1353
1354 //TODO: may opti later
1355 //TODO: not use this func?
WelsMemcpy(void * dst,const void * kpSrc,uint32_t uiSize)1356 void* WelsMemcpy (void* dst, const void* kpSrc, uint32_t uiSize) {
1357 return ::memcpy (dst, kpSrc, uiSize);
1358 }
WelsMemset(void * p,int32_t val,uint32_t uiSize)1359 void* WelsMemset (void* p, int32_t val, uint32_t uiSize) {
1360 return ::memset (p, val, uiSize);
1361 }
1362
1363 //i420_to_i420_c
WelsMoveMemory_c(uint8_t * pDstY,uint8_t * pDstU,uint8_t * pDstV,int32_t iDstStrideY,int32_t iDstStrideUV,uint8_t * pSrcY,uint8_t * pSrcU,uint8_t * pSrcV,int32_t iSrcStrideY,int32_t iSrcStrideUV,int32_t iWidth,int32_t iHeight)1364 void WelsMoveMemory_c (uint8_t* pDstY, uint8_t* pDstU, uint8_t* pDstV, int32_t iDstStrideY, int32_t iDstStrideUV,
1365 uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iSrcStrideY, int32_t iSrcStrideUV, int32_t iWidth,
1366 int32_t iHeight) {
1367 int32_t iWidth2 = iWidth >> 1;
1368 int32_t iHeight2 = iHeight >> 1;
1369 int32_t j;
1370
1371 for (j = iHeight; j; j--) {
1372 WelsMemcpy (pDstY, pSrcY, iWidth);
1373 pDstY += iDstStrideY;
1374 pSrcY += iSrcStrideY;
1375 }
1376
1377 for (j = iHeight2; j; j--) {
1378 WelsMemcpy (pDstU, pSrcU, iWidth2);
1379 WelsMemcpy (pDstV, pSrcV, iWidth2);
1380 pDstU += iDstStrideUV;
1381 pDstV += iDstStrideUV;
1382 pSrcU += iSrcStrideUV;
1383 pSrcV += iSrcStrideUV;
1384 }
1385 }
1386
WelsMoveMemoryWrapper(SWelsSvcCodingParam * pSvcParam,SPicture * pDstPic,const SSourcePicture * kpSrc,const int32_t kiTargetWidth,const int32_t kiTargetHeight)1387 void CWelsPreProcess::WelsMoveMemoryWrapper (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic,
1388 const SSourcePicture* kpSrc,
1389 const int32_t kiTargetWidth, const int32_t kiTargetHeight) {
1390 if (VIDEO_FORMAT_I420 != (kpSrc->iColorFormat & (~VIDEO_FORMAT_VFlip)))
1391 return;
1392
1393 int32_t iSrcWidth = kpSrc->iPicWidth;
1394 int32_t iSrcHeight = kpSrc->iPicHeight;
1395
1396 if (iSrcHeight > kiTargetHeight) iSrcHeight = kiTargetHeight;
1397 if (iSrcWidth > kiTargetWidth) iSrcWidth = kiTargetWidth;
1398
1399 // copy from fr26 to fix the odd uiSize failed issue
1400 if (iSrcWidth & 0x1) -- iSrcWidth;
1401 if (iSrcHeight & 0x1) -- iSrcHeight;
1402
1403 const int32_t kiSrcTopOffsetY = pSvcParam->SUsedPicRect.iTop;
1404 const int32_t kiSrcTopOffsetUV = (kiSrcTopOffsetY >> 1);
1405 const int32_t kiSrcLeftOffsetY = pSvcParam->SUsedPicRect.iLeft;
1406 const int32_t kiSrcLeftOffsetUV = (kiSrcLeftOffsetY >> 1);
1407 int32_t iSrcOffset[3] = {0, 0, 0};
1408 iSrcOffset[0] = kpSrc->iStride[0] * kiSrcTopOffsetY + kiSrcLeftOffsetY;
1409 iSrcOffset[1] = kpSrc->iStride[1] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV ;
1410 iSrcOffset[2] = kpSrc->iStride[2] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV;
1411
1412 uint8_t* pSrcY = kpSrc->pData[0] + iSrcOffset[0];
1413 uint8_t* pSrcU = kpSrc->pData[1] + iSrcOffset[1];
1414 uint8_t* pSrcV = kpSrc->pData[2] + iSrcOffset[2];
1415 const int32_t kiSrcStrideY = kpSrc->iStride[0];
1416 const int32_t kiSrcStrideUV = kpSrc->iStride[1];
1417
1418 uint8_t* pDstY = pDstPic->pData[0];
1419 uint8_t* pDstU = pDstPic->pData[1];
1420 uint8_t* pDstV = pDstPic->pData[2];
1421 const int32_t kiDstStrideY = pDstPic->iLineSize[0];
1422 const int32_t kiDstStrideUV = pDstPic->iLineSize[1];
1423
1424 if (pSrcY) {
1425 if (iSrcWidth <= 0 || iSrcHeight <= 0 || (iSrcWidth * iSrcHeight > (MAX_MBS_PER_FRAME << 8)))
1426 return;
1427 if (kiSrcTopOffsetY >= iSrcHeight || kiSrcLeftOffsetY >= iSrcWidth || iSrcWidth > kiSrcStrideY)
1428 return;
1429 }
1430 if (pDstY) {
1431 if (kiTargetWidth <= 0 || kiTargetHeight <= 0 || (kiTargetWidth * kiTargetHeight > (MAX_MBS_PER_FRAME << 8)))
1432 return;
1433 if (kiTargetWidth > kiDstStrideY)
1434 return;
1435 }
1436
1437 if (pSrcY == NULL || pSrcU == NULL || pSrcV == NULL || pDstY == NULL || pDstU == NULL || pDstV == NULL
1438 || (iSrcWidth & 1) || (iSrcHeight & 1)) {
1439 } else {
1440 //i420_to_i420_c
1441 WelsMoveMemory_c (pDstY, pDstU, pDstV, kiDstStrideY, kiDstStrideUV,
1442 pSrcY, pSrcU, pSrcV, kiSrcStrideY, kiSrcStrideUV, iSrcWidth, iSrcHeight);
1443
1444 //in VP Process
1445 if (kiTargetWidth > iSrcWidth || kiTargetHeight > iSrcHeight) {
1446 Padding (pDstY, pDstU, pDstV, kiDstStrideY, kiDstStrideUV, iSrcWidth, kiTargetWidth, iSrcHeight, kiTargetHeight);
1447 }
1448 }
1449
1450 }
1451
GetSceneChangeFlag(ESceneChangeIdc eSceneChangeIdc)1452 bool CWelsPreProcess::GetSceneChangeFlag (ESceneChangeIdc eSceneChangeIdc) {
1453 return ((eSceneChangeIdc == LARGE_CHANGED_SCENE) ? true : false);
1454 }
1455
1456
1457 //*********************************************************************************************************/
1458 } // namespace WelsEnc
1459