1 /*****************************************************************************
2 * Copyright (C) 2013-2020 MulticoreWare, Inc
3 *
4 * Author: Steve Borho <steve@borho.org>
5 *         Min Chen <chenm003@163.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
20 *
21 * This program is also available under a commercial proprietary license.
22 * For more information, contact us at license @ x265.com.
23 *****************************************************************************/
24 
25 #include "common.h"
26 #include "frame.h"
27 #include "picyuv.h"
28 #include "framedata.h"
29 
30 using namespace X265_NS;
31 
Frame()32 Frame::Frame()
33 {
34     m_bChromaExtended = false;
35     m_lowresInit = false;
36     m_reconRowFlag = NULL;
37     m_reconColCount = NULL;
38     m_countRefEncoders = 0;
39     m_encData = NULL;
40     m_reconPic = NULL;
41     m_quantOffsets = NULL;
42     m_next = NULL;
43     m_prev = NULL;
44     m_param = NULL;
45     m_userSEI.numPayloads = 0;
46     m_userSEI.payloads = NULL;
47     m_rpu.payloadSize = 0;
48     m_rpu.payload = NULL;
49     memset(&m_lowres, 0, sizeof(m_lowres));
50     m_rcData = NULL;
51     m_encodeStartTime = 0;
52     m_reconfigureRc = false;
53     m_ctuInfo = NULL;
54     m_prevCtuInfoChange = NULL;
55     m_addOnDepth = NULL;
56     m_addOnCtuInfo = NULL;
57     m_addOnPrevChange = NULL;
58     m_classifyFrame = false;
59     m_fieldNum = 0;
60     m_picStruct = 0;
61     m_edgePic = NULL;
62     m_gaussianPic = NULL;
63     m_thetaPic = NULL;
64     m_edgeBitPlane = NULL;
65     m_edgeBitPic = NULL;
66 }
67 
create(x265_param * param,float * quantOffsets)68 bool Frame::create(x265_param *param, float* quantOffsets)
69 {
70     m_fencPic = new PicYuv;
71     m_param = param;
72     CHECKED_MALLOC_ZERO(m_rcData, RcStats, 1);
73 
74     if (param->bCTUInfo)
75     {
76         uint32_t widthInCTU = (m_param->sourceWidth + param->maxCUSize - 1) >> m_param->maxLog2CUSize;
77         uint32_t heightInCTU = (m_param->sourceHeight +  param->maxCUSize - 1) >> m_param->maxLog2CUSize;
78         uint32_t numCTUsInFrame = widthInCTU * heightInCTU;
79         CHECKED_MALLOC_ZERO(m_addOnDepth, uint8_t *, numCTUsInFrame);
80         CHECKED_MALLOC_ZERO(m_addOnCtuInfo, uint8_t *, numCTUsInFrame);
81         CHECKED_MALLOC_ZERO(m_addOnPrevChange, int *, numCTUsInFrame);
82         for (uint32_t i = 0; i < numCTUsInFrame; i++)
83         {
84             CHECKED_MALLOC_ZERO(m_addOnDepth[i], uint8_t, uint32_t(param->num4x4Partitions));
85             CHECKED_MALLOC_ZERO(m_addOnCtuInfo[i], uint8_t, uint32_t(param->num4x4Partitions));
86             CHECKED_MALLOC_ZERO(m_addOnPrevChange[i], int, uint32_t(param->num4x4Partitions));
87         }
88     }
89 
90     if (param->bAnalysisType == AVC_INFO)
91     {
92         m_analysisData.wt = NULL;
93         m_analysisData.intraData = NULL;
94         m_analysisData.interData = NULL;
95         m_analysisData.distortionData = NULL;
96     }
97 
98     if (param->bDynamicRefine)
99     {
100         int size = m_param->maxCUDepth * X265_REFINE_INTER_LEVELS;
101         CHECKED_MALLOC_ZERO(m_classifyRd, uint64_t, size);
102         CHECKED_MALLOC_ZERO(m_classifyVariance, uint64_t, size);
103         CHECKED_MALLOC_ZERO(m_classifyCount, uint32_t, size);
104     }
105 
106     if (param->rc.aqMode == X265_AQ_EDGE || (param->rc.zonefileCount && param->rc.aqMode != 0))
107     {
108         uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize;
109         uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize;
110         uint32_t m_lumaMarginX = param->maxCUSize + 32; // search margin and 8-tap filter half-length, padded for 32-byte alignment
111         uint32_t m_lumaMarginY = param->maxCUSize + 16; // margin for 8-tap filter and infinite padding
112         intptr_t m_stride = (numCuInWidth * param->maxCUSize) + (m_lumaMarginX << 1);
113         int maxHeight = numCuInHeight * param->maxCUSize;
114 
115         m_edgePic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2)));
116         m_gaussianPic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2)));
117         m_thetaPic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2)));
118     }
119 
120     if (param->recursionSkipMode == EDGE_BASED_RSKIP)
121     {
122         uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize;
123         uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize;
124         uint32_t lumaMarginX = param->maxCUSize + 32;
125         uint32_t lumaMarginY = param->maxCUSize + 16;
126         uint32_t stride = (numCuInWidth * param->maxCUSize) + (lumaMarginX << 1);
127         uint32_t maxHeight = numCuInHeight * param->maxCUSize;
128         uint32_t bitPlaneSize = stride * (maxHeight + (lumaMarginY * 2));
129         CHECKED_MALLOC_ZERO(m_edgeBitPlane, pixel, bitPlaneSize);
130         m_edgeBitPic = m_edgeBitPlane + lumaMarginY * stride + lumaMarginX;
131     }
132 
133     if (m_fencPic->create(param, !!m_param->bCopyPicToFrame) && m_lowres.create(param, m_fencPic, param->rc.qgSize))
134     {
135         X265_CHECK((m_reconColCount == NULL), "m_reconColCount was initialized");
136         m_numRows = (m_fencPic->m_picHeight + param->maxCUSize - 1)  / param->maxCUSize;
137         m_reconRowFlag = new ThreadSafeInteger[m_numRows];
138         m_reconColCount = new ThreadSafeInteger[m_numRows];
139 
140         if (quantOffsets)
141         {
142             int32_t cuCount = (param->rc.qgSize == 8) ? m_lowres.maxBlocksInRowFullRes * m_lowres.maxBlocksInColFullRes :
143                                                         m_lowres.maxBlocksInRow * m_lowres.maxBlocksInCol;
144             m_quantOffsets = new float[cuCount];
145         }
146         return true;
147     }
148     return false;
149 fail:
150     return false;
151 }
152 
allocEncodeData(x265_param * param,const SPS & sps)153 bool Frame::allocEncodeData(x265_param *param, const SPS& sps)
154 {
155     m_encData = new FrameData;
156     m_reconPic = new PicYuv;
157     m_param = param;
158     m_encData->m_reconPic = m_reconPic;
159     bool ok = m_encData->create(*param, sps, m_fencPic->m_picCsp) && m_reconPic->create(param);
160     if (ok)
161     {
162         /* initialize right border of m_reconpicYuv as SAO may read beyond the
163          * end of the picture accessing uninitialized pixels */
164         int maxHeight = sps.numCuInHeight * param->maxCUSize;
165         memset(m_reconPic->m_picOrg[0], 0, sizeof(pixel)* m_reconPic->m_stride * maxHeight);
166 
167         /* use pre-calculated cu/pu offsets cached in the SPS structure */
168         m_reconPic->m_cuOffsetY = sps.cuOffsetY;
169         m_reconPic->m_buOffsetY = sps.buOffsetY;
170 
171         if (param->internalCsp != X265_CSP_I400)
172         {
173             memset(m_reconPic->m_picOrg[1], 0, sizeof(pixel) * m_reconPic->m_strideC * (maxHeight >> m_reconPic->m_vChromaShift));
174             memset(m_reconPic->m_picOrg[2], 0, sizeof(pixel) * m_reconPic->m_strideC * (maxHeight >> m_reconPic->m_vChromaShift));
175 
176             /* use pre-calculated cu/pu offsets cached in the SPS structure */
177             m_reconPic->m_cuOffsetC = sps.cuOffsetC;
178             m_reconPic->m_buOffsetC = sps.buOffsetC;
179         }
180     }
181     return ok;
182 }
183 
184 /* prepare to re-use a FrameData instance to encode a new picture */
reinit(const SPS & sps)185 void Frame::reinit(const SPS& sps)
186 {
187     m_bChromaExtended = false;
188     m_reconPic = m_encData->m_reconPic;
189     m_encData->reinit(sps);
190 }
191 
destroy()192 void Frame::destroy()
193 {
194     if (m_encData)
195     {
196         m_encData->destroy();
197         delete m_encData;
198         m_encData = NULL;
199     }
200 
201     if (m_fencPic)
202     {
203         if (m_param->bCopyPicToFrame)
204             m_fencPic->destroy();
205         delete m_fencPic;
206         m_fencPic = NULL;
207     }
208 
209     if (m_reconPic)
210     {
211         m_reconPic->destroy();
212         delete m_reconPic;
213         m_reconPic = NULL;
214     }
215 
216     if (m_reconRowFlag)
217     {
218         delete[] m_reconRowFlag;
219         m_reconRowFlag = NULL;
220     }
221 
222     if (m_reconColCount)
223     {
224         delete[] m_reconColCount;
225         m_reconColCount = NULL;
226     }
227 
228     if (m_quantOffsets)
229     {
230         delete[] m_quantOffsets;
231     }
232 
233     if (m_userSEI.numPayloads)
234     {
235         for (int i = 0; i < m_userSEI.numPayloads; i++)
236             delete[] m_userSEI.payloads[i].payload;
237         delete[] m_userSEI.payloads;
238     }
239 
240     if (m_ctuInfo)
241     {
242         uint32_t widthInCU = (m_param->sourceWidth + m_param->maxCUSize - 1) >> m_param->maxLog2CUSize;
243         uint32_t heightInCU = (m_param->sourceHeight + m_param->maxCUSize - 1) >> m_param->maxLog2CUSize;
244         uint32_t numCUsInFrame = widthInCU * heightInCU;
245         for (uint32_t i = 0; i < numCUsInFrame; i++)
246         {
247             X265_FREE((*m_ctuInfo + i)->ctuInfo);
248             (*m_ctuInfo + i)->ctuInfo = NULL;
249             X265_FREE(m_addOnDepth[i]);
250             m_addOnDepth[i] = NULL;
251             X265_FREE(m_addOnCtuInfo[i]);
252             m_addOnCtuInfo[i] = NULL;
253             X265_FREE(m_addOnPrevChange[i]);
254             m_addOnPrevChange[i] = NULL;
255         }
256         X265_FREE(*m_ctuInfo);
257         *m_ctuInfo = NULL;
258         X265_FREE(m_ctuInfo);
259         m_ctuInfo = NULL;
260         X265_FREE(m_prevCtuInfoChange);
261         m_prevCtuInfoChange = NULL;
262         X265_FREE(m_addOnDepth);
263         m_addOnDepth = NULL;
264         X265_FREE(m_addOnCtuInfo);
265         m_addOnCtuInfo = NULL;
266         X265_FREE(m_addOnPrevChange);
267         m_addOnPrevChange = NULL;
268     }
269     m_lowres.destroy();
270     X265_FREE(m_rcData);
271 
272     if (m_param->bDynamicRefine)
273     {
274         X265_FREE_ZERO(m_classifyRd);
275         X265_FREE_ZERO(m_classifyVariance);
276         X265_FREE_ZERO(m_classifyCount);
277     }
278 
279     if (m_param->rc.aqMode == X265_AQ_EDGE || (m_param->rc.zonefileCount && m_param->rc.aqMode != 0))
280     {
281         X265_FREE(m_edgePic);
282         X265_FREE(m_gaussianPic);
283         X265_FREE(m_thetaPic);
284     }
285 
286     if (m_param->recursionSkipMode == EDGE_BASED_RSKIP)
287     {
288         X265_FREE_ZERO(m_edgeBitPlane);
289         m_edgeBitPic = NULL;
290     }
291 }
292