/***************************************************************************** * Copyright (C) 2013-2020 MulticoreWare, Inc * * Author: Steve Borho * Min Chen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. * * This program is also available under a commercial proprietary license. * For more information, contact us at license @ x265.com. *****************************************************************************/ #include "common.h" #include "frame.h" #include "picyuv.h" #include "framedata.h" using namespace X265_NS; Frame::Frame() { m_bChromaExtended = false; m_lowresInit = false; m_reconRowFlag = NULL; m_reconColCount = NULL; m_countRefEncoders = 0; m_encData = NULL; for (int i = 0; i < NUM_RECON_VERSION; i++) m_reconPic[i] = NULL; m_quantOffsets = NULL; m_next = NULL; m_prev = NULL; m_param = NULL; m_userSEI.numPayloads = 0; m_userSEI.payloads = NULL; m_rpu.payloadSize = 0; m_rpu.payload = NULL; memset(&m_lowres, 0, sizeof(m_lowres)); m_rcData = NULL; m_encodeStartTime = 0; m_reconfigureRc = false; m_ctuInfo = NULL; m_prevCtuInfoChange = NULL; m_addOnDepth = NULL; m_addOnCtuInfo = NULL; m_addOnPrevChange = NULL; m_classifyFrame = false; m_fieldNum = 0; m_picStruct = 0; m_edgePic = NULL; m_gaussianPic = NULL; m_thetaPic = NULL; m_edgeBitPlane = NULL; m_edgeBitPic = NULL; m_isInsideWindow = 0; // mcstf m_isSubSampled = NULL; m_mcstf = NULL; m_refPicCnt[0] = 0; m_refPicCnt[1] = 0; m_nextMCSTF = NULL; m_prevMCSTF = NULL; m_tempLayer = 0; m_sameLayerRefPic = false; m_viewId = 0; m_valid = 0; m_nextSubDPB = NULL; m_prevSubDPB = NULL; } bool Frame::create(x265_param *param, float* quantOffsets) { m_fencPic = new PicYuv; m_param = param; if (m_param->bEnableTemporalFilter) { m_mcstf = new TemporalFilter; m_mcstf->m_range = param->mcstfFrameRange; m_mcstf->init(param); m_fencPicSubsampled2 = new PicYuv; m_fencPicSubsampled4 = new PicYuv; if (!m_fencPicSubsampled2->createScaledPicYUV(param, 2)) return false; if (!m_fencPicSubsampled4->createScaledPicYUV(param, 4)) return false; CHECKED_MALLOC_ZERO(m_isSubSampled, int, 1); } CHECKED_MALLOC_ZERO(m_rcData, RcStats, 1); if (param->bCTUInfo) { uint32_t widthInCTU = (m_param->sourceWidth + param->maxCUSize - 1) >> m_param->maxLog2CUSize; uint32_t heightInCTU = (m_param->sourceHeight + param->maxCUSize - 1) >> m_param->maxLog2CUSize; uint32_t numCTUsInFrame = widthInCTU * heightInCTU; CHECKED_MALLOC_ZERO(m_addOnDepth, uint8_t *, numCTUsInFrame); CHECKED_MALLOC_ZERO(m_addOnCtuInfo, uint8_t *, numCTUsInFrame); CHECKED_MALLOC_ZERO(m_addOnPrevChange, int *, numCTUsInFrame); for (uint32_t i = 0; i < numCTUsInFrame; i++) { CHECKED_MALLOC_ZERO(m_addOnDepth[i], uint8_t, uint32_t(param->num4x4Partitions)); CHECKED_MALLOC_ZERO(m_addOnCtuInfo[i], uint8_t, uint32_t(param->num4x4Partitions)); CHECKED_MALLOC_ZERO(m_addOnPrevChange[i], int, uint32_t(param->num4x4Partitions)); } } if (param->bAnalysisType == AVC_INFO) { m_analysisData.wt = NULL; m_analysisData.intraData = NULL; m_analysisData.interData = NULL; m_analysisData.distortionData = NULL; } if (param->bDynamicRefine) { int size = m_param->maxCUDepth * X265_REFINE_INTER_LEVELS; CHECKED_MALLOC_ZERO(m_classifyRd, uint64_t, size); CHECKED_MALLOC_ZERO(m_classifyVariance, uint64_t, size); CHECKED_MALLOC_ZERO(m_classifyCount, uint32_t, size); } if (param->rc.aqMode == X265_AQ_EDGE || (param->rc.zonefileCount && param->rc.aqMode != 0)) { uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize; uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize; uint32_t m_lumaMarginX = param->maxCUSize + 32; // search margin and 8-tap filter half-length, padded for 32-byte alignment uint32_t m_lumaMarginY = param->maxCUSize + 16; // margin for 8-tap filter and infinite padding intptr_t m_stride = (numCuInWidth * param->maxCUSize) + (m_lumaMarginX << 1); int maxHeight = numCuInHeight * param->maxCUSize; m_edgePic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); m_gaussianPic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); m_thetaPic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); } if (param->recursionSkipMode == EDGE_BASED_RSKIP) { uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize; uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize; uint32_t lumaMarginX = param->maxCUSize + 32; uint32_t lumaMarginY = param->maxCUSize + 16; uint32_t stride = (numCuInWidth * param->maxCUSize) + (lumaMarginX << 1); uint32_t maxHeight = numCuInHeight * param->maxCUSize; uint32_t bitPlaneSize = stride * (maxHeight + (lumaMarginY * 2)); CHECKED_MALLOC_ZERO(m_edgeBitPlane, pixel, bitPlaneSize); m_edgeBitPic = m_edgeBitPlane + lumaMarginY * stride + lumaMarginX; } if (m_fencPic->create(param, !!m_param->bCopyPicToFrame) && m_lowres.create(param, m_fencPic, param->rc.qgSize)) { X265_CHECK((m_reconColCount == NULL), "m_reconColCount was initialized"); m_numRows = (m_fencPic->m_picHeight + param->maxCUSize - 1) / param->maxCUSize; m_reconRowFlag = new ThreadSafeInteger[m_numRows]; m_reconColCount = new ThreadSafeInteger[m_numRows]; if (quantOffsets) { int32_t cuCount = (param->rc.qgSize == 8) ? m_lowres.maxBlocksInRowFullRes * m_lowres.maxBlocksInColFullRes : m_lowres.maxBlocksInRow * m_lowres.maxBlocksInCol; m_quantOffsets = new float[cuCount]; } return true; } return false; fail: return false; } bool Frame::createSubSample() { m_fencPicSubsampled2 = new PicYuv; m_fencPicSubsampled4 = new PicYuv; if (!m_fencPicSubsampled2->createScaledPicYUV(m_param, 2)) return false; if (!m_fencPicSubsampled4->createScaledPicYUV(m_param, 4)) return false; CHECKED_MALLOC_ZERO(m_isSubSampled, int, 1); return true; fail: return false; } bool Frame::allocEncodeData(x265_param *param, const SPS& sps) { m_encData = new FrameData; m_param = param; for (int i = 0; i < !!m_param->bEnableSCC + 1; i++) { m_reconPic[i] = new PicYuv; m_encData->m_reconPic[i] = m_reconPic[i]; } bool ok = m_encData->create(*param, sps, m_fencPic->m_picCsp) && m_reconPic[0]->create(param) && (param->bEnableSCC ? (param->bEnableSCC && m_reconPic[1]->create(param)) : 1); if (ok) { /* initialize right border of m_reconPicYuv as SAO may read beyond the * end of the picture accessing uninitialized pixels */ int maxHeight = sps.numCuInHeight * param->maxCUSize; memset(m_reconPic[0]->m_picOrg[0], 0, sizeof(pixel)* m_reconPic[0]->m_stride * maxHeight); for (int i = 0; i < !!m_param->bEnableSCC + 1; i++) { /* use pre-calculated cu/pu offsets cached in the SPS structure */ m_reconPic[i]->m_cuOffsetY = sps.cuOffsetY; m_reconPic[i]->m_buOffsetY = sps.buOffsetY; if (param->internalCsp != X265_CSP_I400) { memset(m_reconPic[i]->m_picOrg[1], 0, sizeof(pixel) * m_reconPic[i]->m_strideC * (maxHeight >> m_reconPic[i]->m_vChromaShift)); memset(m_reconPic[i]->m_picOrg[2], 0, sizeof(pixel) * m_reconPic[i]->m_strideC * (maxHeight >> m_reconPic[i]->m_vChromaShift)); /* use pre-calculated cu/pu offsets cached in the SPS structure */ m_reconPic[i]->m_cuOffsetC = sps.cuOffsetC; m_reconPic[i]->m_buOffsetC = sps.buOffsetC; } } } return ok; } /* prepare to re-use a FrameData instance to encode a new picture */ void Frame::reinit(const SPS& sps) { m_bChromaExtended = false; for (int i = 0; i < !!m_param->bEnableSCC + 1; i++) m_reconPic[i] = m_encData->m_reconPic[i]; m_encData->reinit(sps); } void Frame::destroy() { if (m_encData) { m_encData->destroy(); delete m_encData; m_encData = NULL; } #if ENABLE_MULTIVIEW //Destroy interlayer References if (refPicSetInterLayer0.size()) { Frame* iterFrame = refPicSetInterLayer0.first(); while (iterFrame) { Frame* curFrame = iterFrame; iterFrame = iterFrame->m_nextSubDPB; refPicSetInterLayer0.removeSubDPB(*curFrame); iterFrame = refPicSetInterLayer0.first(); } } if (refPicSetInterLayer1.size()) { Frame* iterFrame = refPicSetInterLayer1.first(); while (iterFrame) { Frame* curFrame = iterFrame; iterFrame = iterFrame->m_nextSubDPB; refPicSetInterLayer1.removeSubDPB(*curFrame); iterFrame = refPicSetInterLayer1.first(); } } #endif if (m_fencPic) { if (m_param->bCopyPicToFrame) m_fencPic->destroy(); delete m_fencPic; m_fencPic = NULL; } if (m_param->bEnableTemporalFilter) { if (m_fencPicSubsampled2) { m_fencPicSubsampled2->destroy(); delete m_fencPicSubsampled2; m_fencPicSubsampled2 = NULL; } if (m_fencPicSubsampled4) { m_fencPicSubsampled4->destroy(); delete m_fencPicSubsampled4; m_fencPicSubsampled4 = NULL; } delete m_mcstf; X265_FREE(m_isSubSampled); } for (int i = 0; i < !!m_param->bEnableSCC + 1; i++) { if (m_reconPic[i]) { m_reconPic[i]->destroy(); delete m_reconPic[i]; m_reconPic[i] = NULL; } } if (m_reconRowFlag) { delete[] m_reconRowFlag; m_reconRowFlag = NULL; } if (m_reconColCount) { delete[] m_reconColCount; m_reconColCount = NULL; } if (m_quantOffsets) { delete[] m_quantOffsets; } if (m_userSEI.numPayloads) { for (int i = 0; i < m_userSEI.numPayloads; i++) delete[] m_userSEI.payloads[i].payload; delete[] m_userSEI.payloads; } if (m_ctuInfo) { uint32_t widthInCU = (m_param->sourceWidth + m_param->maxCUSize - 1) >> m_param->maxLog2CUSize; uint32_t heightInCU = (m_param->sourceHeight + m_param->maxCUSize - 1) >> m_param->maxLog2CUSize; uint32_t numCUsInFrame = widthInCU * heightInCU; for (uint32_t i = 0; i < numCUsInFrame; i++) { X265_FREE((*m_ctuInfo + i)->ctuInfo); (*m_ctuInfo + i)->ctuInfo = NULL; X265_FREE(m_addOnDepth[i]); m_addOnDepth[i] = NULL; X265_FREE(m_addOnCtuInfo[i]); m_addOnCtuInfo[i] = NULL; X265_FREE(m_addOnPrevChange[i]); m_addOnPrevChange[i] = NULL; } X265_FREE(*m_ctuInfo); *m_ctuInfo = NULL; X265_FREE(m_ctuInfo); m_ctuInfo = NULL; X265_FREE(m_prevCtuInfoChange); m_prevCtuInfoChange = NULL; X265_FREE(m_addOnDepth); m_addOnDepth = NULL; X265_FREE(m_addOnCtuInfo); m_addOnCtuInfo = NULL; X265_FREE(m_addOnPrevChange); m_addOnPrevChange = NULL; } m_lowres.destroy(m_param); X265_FREE(m_rcData); if (m_param->bDynamicRefine) { X265_FREE_ZERO(m_classifyRd); X265_FREE_ZERO(m_classifyVariance); X265_FREE_ZERO(m_classifyCount); } if (m_param->rc.aqMode == X265_AQ_EDGE || (m_param->rc.zonefileCount && m_param->rc.aqMode != 0)) { X265_FREE(m_edgePic); X265_FREE(m_gaussianPic); X265_FREE(m_thetaPic); } if (m_param->recursionSkipMode == EDGE_BASED_RSKIP) { X265_FREE_ZERO(m_edgeBitPlane); m_edgeBitPic = NULL; } }