/src/x265/source/common/frame.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
32 | | Frame::Frame() |
33 | 0 | { |
34 | 0 | m_bChromaExtended = false; |
35 | 0 | m_lowresInit = false; |
36 | 0 | m_reconRowFlag = NULL; |
37 | 0 | m_reconColCount = NULL; |
38 | 0 | m_countRefEncoders = 0; |
39 | 0 | m_encData = NULL; |
40 | 0 | m_reconPic = NULL; |
41 | 0 | m_quantOffsets = NULL; |
42 | 0 | m_next = NULL; |
43 | 0 | m_prev = NULL; |
44 | 0 | m_param = NULL; |
45 | 0 | m_userSEI.numPayloads = 0; |
46 | 0 | m_userSEI.payloads = NULL; |
47 | 0 | m_rpu.payloadSize = 0; |
48 | 0 | m_rpu.payload = NULL; |
49 | 0 | memset(&m_lowres, 0, sizeof(m_lowres)); |
50 | 0 | m_rcData = NULL; |
51 | 0 | m_encodeStartTime = 0; |
52 | 0 | m_reconfigureRc = false; |
53 | 0 | m_ctuInfo = NULL; |
54 | 0 | m_prevCtuInfoChange = NULL; |
55 | 0 | m_addOnDepth = NULL; |
56 | 0 | m_addOnCtuInfo = NULL; |
57 | 0 | m_addOnPrevChange = NULL; |
58 | 0 | m_classifyFrame = false; |
59 | 0 | m_fieldNum = 0; |
60 | 0 | m_picStruct = 0; |
61 | 0 | m_edgePic = NULL; |
62 | 0 | m_gaussianPic = NULL; |
63 | 0 | m_thetaPic = NULL; |
64 | 0 | m_edgeBitPlane = NULL; |
65 | 0 | m_edgeBitPic = NULL; |
66 | 0 | } |
67 | | |
68 | | bool Frame::create(x265_param *param, float* quantOffsets) |
69 | 0 | { |
70 | 0 | m_fencPic = new PicYuv; |
71 | 0 | m_param = param; |
72 | 0 | CHECKED_MALLOC_ZERO(m_rcData, RcStats, 1); |
73 | |
|
74 | 0 | if (param->bCTUInfo) |
75 | 0 | { |
76 | 0 | uint32_t widthInCTU = (m_param->sourceWidth + param->maxCUSize - 1) >> m_param->maxLog2CUSize; |
77 | 0 | uint32_t heightInCTU = (m_param->sourceHeight + param->maxCUSize - 1) >> m_param->maxLog2CUSize; |
78 | 0 | uint32_t numCTUsInFrame = widthInCTU * heightInCTU; |
79 | 0 | CHECKED_MALLOC_ZERO(m_addOnDepth, uint8_t *, numCTUsInFrame); |
80 | 0 | CHECKED_MALLOC_ZERO(m_addOnCtuInfo, uint8_t *, numCTUsInFrame); |
81 | 0 | CHECKED_MALLOC_ZERO(m_addOnPrevChange, int *, numCTUsInFrame); |
82 | 0 | for (uint32_t i = 0; i < numCTUsInFrame; i++) |
83 | 0 | { |
84 | 0 | CHECKED_MALLOC_ZERO(m_addOnDepth[i], uint8_t, uint32_t(param->num4x4Partitions)); |
85 | 0 | CHECKED_MALLOC_ZERO(m_addOnCtuInfo[i], uint8_t, uint32_t(param->num4x4Partitions)); |
86 | 0 | CHECKED_MALLOC_ZERO(m_addOnPrevChange[i], int, uint32_t(param->num4x4Partitions)); |
87 | 0 | } |
88 | 0 | } |
89 | | |
90 | 0 | if (param->bAnalysisType == AVC_INFO) |
91 | 0 | { |
92 | 0 | m_analysisData.wt = NULL; |
93 | 0 | m_analysisData.intraData = NULL; |
94 | 0 | m_analysisData.interData = NULL; |
95 | 0 | m_analysisData.distortionData = NULL; |
96 | 0 | } |
97 | |
|
98 | 0 | if (param->bDynamicRefine) |
99 | 0 | { |
100 | 0 | int size = m_param->maxCUDepth * X265_REFINE_INTER_LEVELS; |
101 | 0 | CHECKED_MALLOC_ZERO(m_classifyRd, uint64_t, size); |
102 | 0 | CHECKED_MALLOC_ZERO(m_classifyVariance, uint64_t, size); |
103 | 0 | CHECKED_MALLOC_ZERO(m_classifyCount, uint32_t, size); |
104 | 0 | } |
105 | | |
106 | 0 | if (param->rc.aqMode == X265_AQ_EDGE || (param->rc.zonefileCount && param->rc.aqMode != 0)) |
107 | 0 | { |
108 | 0 | uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize; |
109 | 0 | uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize; |
110 | 0 | uint32_t m_lumaMarginX = param->maxCUSize + 32; // search margin and 8-tap filter half-length, padded for 32-byte alignment |
111 | 0 | uint32_t m_lumaMarginY = param->maxCUSize + 16; // margin for 8-tap filter and infinite padding |
112 | 0 | intptr_t m_stride = (numCuInWidth * param->maxCUSize) + (m_lumaMarginX << 1); |
113 | 0 | int maxHeight = numCuInHeight * param->maxCUSize; |
114 | |
|
115 | 0 | m_edgePic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); |
116 | 0 | m_gaussianPic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); |
117 | 0 | m_thetaPic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); |
118 | 0 | } |
119 | |
|
120 | 0 | if (param->recursionSkipMode == EDGE_BASED_RSKIP) |
121 | 0 | { |
122 | 0 | uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize; |
123 | 0 | uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize; |
124 | 0 | uint32_t lumaMarginX = param->maxCUSize + 32; |
125 | 0 | uint32_t lumaMarginY = param->maxCUSize + 16; |
126 | 0 | uint32_t stride = (numCuInWidth * param->maxCUSize) + (lumaMarginX << 1); |
127 | 0 | uint32_t maxHeight = numCuInHeight * param->maxCUSize; |
128 | 0 | uint32_t bitPlaneSize = stride * (maxHeight + (lumaMarginY * 2)); |
129 | 0 | CHECKED_MALLOC_ZERO(m_edgeBitPlane, pixel, bitPlaneSize); |
130 | 0 | m_edgeBitPic = m_edgeBitPlane + lumaMarginY * stride + lumaMarginX; |
131 | 0 | } |
132 | | |
133 | 0 | if (m_fencPic->create(param, !!m_param->bCopyPicToFrame) && m_lowres.create(param, m_fencPic, param->rc.qgSize)) |
134 | 0 | { |
135 | 0 | X265_CHECK((m_reconColCount == NULL), "m_reconColCount was initialized"); |
136 | 0 | m_numRows = (m_fencPic->m_picHeight + param->maxCUSize - 1) / param->maxCUSize; |
137 | 0 | m_reconRowFlag = new ThreadSafeInteger[m_numRows]; |
138 | 0 | m_reconColCount = new ThreadSafeInteger[m_numRows]; |
139 | |
|
140 | 0 | if (quantOffsets) |
141 | 0 | { |
142 | 0 | int32_t cuCount = (param->rc.qgSize == 8) ? m_lowres.maxBlocksInRowFullRes * m_lowres.maxBlocksInColFullRes : |
143 | 0 | m_lowres.maxBlocksInRow * m_lowres.maxBlocksInCol; |
144 | 0 | m_quantOffsets = new float[cuCount]; |
145 | 0 | } |
146 | 0 | return true; |
147 | 0 | } |
148 | 0 | return false; |
149 | 0 | fail: |
150 | 0 | return false; |
151 | 0 | } |
152 | | |
153 | | bool Frame::allocEncodeData(x265_param *param, const SPS& sps) |
154 | 0 | { |
155 | 0 | m_encData = new FrameData; |
156 | 0 | m_reconPic = new PicYuv; |
157 | 0 | m_param = param; |
158 | 0 | m_encData->m_reconPic = m_reconPic; |
159 | 0 | bool ok = m_encData->create(*param, sps, m_fencPic->m_picCsp) && m_reconPic->create(param); |
160 | 0 | if (ok) |
161 | 0 | { |
162 | | /* initialize right border of m_reconpicYuv as SAO may read beyond the |
163 | | * end of the picture accessing uninitialized pixels */ |
164 | 0 | int maxHeight = sps.numCuInHeight * param->maxCUSize; |
165 | 0 | 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 | 0 | m_reconPic->m_cuOffsetY = sps.cuOffsetY; |
169 | 0 | m_reconPic->m_buOffsetY = sps.buOffsetY; |
170 | |
|
171 | 0 | if (param->internalCsp != X265_CSP_I400) |
172 | 0 | { |
173 | 0 | memset(m_reconPic->m_picOrg[1], 0, sizeof(pixel) * m_reconPic->m_strideC * (maxHeight >> m_reconPic->m_vChromaShift)); |
174 | 0 | 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 | 0 | m_reconPic->m_cuOffsetC = sps.cuOffsetC; |
178 | 0 | m_reconPic->m_buOffsetC = sps.buOffsetC; |
179 | 0 | } |
180 | 0 | } |
181 | 0 | return ok; |
182 | 0 | } |
183 | | |
184 | | /* prepare to re-use a FrameData instance to encode a new picture */ |
185 | | void Frame::reinit(const SPS& sps) |
186 | 0 | { |
187 | 0 | m_bChromaExtended = false; |
188 | 0 | m_reconPic = m_encData->m_reconPic; |
189 | 0 | m_encData->reinit(sps); |
190 | 0 | } |
191 | | |
192 | | void Frame::destroy() |
193 | 0 | { |
194 | 0 | if (m_encData) |
195 | 0 | { |
196 | 0 | m_encData->destroy(); |
197 | 0 | delete m_encData; |
198 | 0 | m_encData = NULL; |
199 | 0 | } |
200 | |
|
201 | 0 | if (m_fencPic) |
202 | 0 | { |
203 | 0 | if (m_param->bCopyPicToFrame) |
204 | 0 | m_fencPic->destroy(); |
205 | 0 | delete m_fencPic; |
206 | 0 | m_fencPic = NULL; |
207 | 0 | } |
208 | |
|
209 | 0 | if (m_reconPic) |
210 | 0 | { |
211 | 0 | m_reconPic->destroy(); |
212 | 0 | delete m_reconPic; |
213 | 0 | m_reconPic = NULL; |
214 | 0 | } |
215 | |
|
216 | 0 | if (m_reconRowFlag) |
217 | 0 | { |
218 | 0 | delete[] m_reconRowFlag; |
219 | 0 | m_reconRowFlag = NULL; |
220 | 0 | } |
221 | |
|
222 | 0 | if (m_reconColCount) |
223 | 0 | { |
224 | 0 | delete[] m_reconColCount; |
225 | 0 | m_reconColCount = NULL; |
226 | 0 | } |
227 | |
|
228 | 0 | if (m_quantOffsets) |
229 | 0 | { |
230 | 0 | delete[] m_quantOffsets; |
231 | 0 | } |
232 | |
|
233 | 0 | if (m_userSEI.numPayloads) |
234 | 0 | { |
235 | 0 | for (int i = 0; i < m_userSEI.numPayloads; i++) |
236 | 0 | delete[] m_userSEI.payloads[i].payload; |
237 | 0 | delete[] m_userSEI.payloads; |
238 | 0 | } |
239 | |
|
240 | 0 | if (m_ctuInfo) |
241 | 0 | { |
242 | 0 | uint32_t widthInCU = (m_param->sourceWidth + m_param->maxCUSize - 1) >> m_param->maxLog2CUSize; |
243 | 0 | uint32_t heightInCU = (m_param->sourceHeight + m_param->maxCUSize - 1) >> m_param->maxLog2CUSize; |
244 | 0 | uint32_t numCUsInFrame = widthInCU * heightInCU; |
245 | 0 | for (uint32_t i = 0; i < numCUsInFrame; i++) |
246 | 0 | { |
247 | 0 | X265_FREE((*m_ctuInfo + i)->ctuInfo); |
248 | 0 | (*m_ctuInfo + i)->ctuInfo = NULL; |
249 | 0 | X265_FREE(m_addOnDepth[i]); |
250 | 0 | m_addOnDepth[i] = NULL; |
251 | 0 | X265_FREE(m_addOnCtuInfo[i]); |
252 | 0 | m_addOnCtuInfo[i] = NULL; |
253 | 0 | X265_FREE(m_addOnPrevChange[i]); |
254 | 0 | m_addOnPrevChange[i] = NULL; |
255 | 0 | } |
256 | 0 | X265_FREE(*m_ctuInfo); |
257 | 0 | *m_ctuInfo = NULL; |
258 | 0 | X265_FREE(m_ctuInfo); |
259 | 0 | m_ctuInfo = NULL; |
260 | 0 | X265_FREE(m_prevCtuInfoChange); |
261 | 0 | m_prevCtuInfoChange = NULL; |
262 | 0 | X265_FREE(m_addOnDepth); |
263 | 0 | m_addOnDepth = NULL; |
264 | 0 | X265_FREE(m_addOnCtuInfo); |
265 | 0 | m_addOnCtuInfo = NULL; |
266 | 0 | X265_FREE(m_addOnPrevChange); |
267 | 0 | m_addOnPrevChange = NULL; |
268 | 0 | } |
269 | 0 | m_lowres.destroy(); |
270 | 0 | X265_FREE(m_rcData); |
271 | |
|
272 | 0 | if (m_param->bDynamicRefine) |
273 | 0 | { |
274 | 0 | X265_FREE_ZERO(m_classifyRd); |
275 | 0 | X265_FREE_ZERO(m_classifyVariance); |
276 | 0 | X265_FREE_ZERO(m_classifyCount); |
277 | 0 | } |
278 | |
|
279 | 0 | if (m_param->rc.aqMode == X265_AQ_EDGE || (m_param->rc.zonefileCount && m_param->rc.aqMode != 0)) |
280 | 0 | { |
281 | 0 | X265_FREE(m_edgePic); |
282 | 0 | X265_FREE(m_gaussianPic); |
283 | 0 | X265_FREE(m_thetaPic); |
284 | 0 | } |
285 | |
|
286 | 0 | if (m_param->recursionSkipMode == EDGE_BASED_RSKIP) |
287 | 0 | { |
288 | 0 | X265_FREE_ZERO(m_edgeBitPlane); |
289 | 0 | m_edgeBitPic = NULL; |
290 | 0 | } |
291 | 0 | } |