/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 | for (int i = 0; i < NUM_RECON_VERSION; i++) |
41 | 0 | m_reconPic[i] = NULL; |
42 | 0 | m_quantOffsets = NULL; |
43 | 0 | m_next = NULL; |
44 | 0 | m_prev = NULL; |
45 | 0 | m_param = NULL; |
46 | 0 | m_userSEI.numPayloads = 0; |
47 | 0 | m_userSEI.payloads = NULL; |
48 | 0 | m_rpu.payloadSize = 0; |
49 | 0 | m_rpu.payload = NULL; |
50 | 0 | memset(&m_lowres, 0, sizeof(m_lowres)); |
51 | 0 | m_rcData = NULL; |
52 | 0 | m_encodeStartTime = 0; |
53 | 0 | m_reconfigureRc = false; |
54 | 0 | m_ctuInfo = NULL; |
55 | 0 | m_prevCtuInfoChange = NULL; |
56 | 0 | m_addOnDepth = NULL; |
57 | 0 | m_addOnCtuInfo = NULL; |
58 | 0 | m_addOnPrevChange = NULL; |
59 | 0 | m_classifyFrame = false; |
60 | 0 | m_fieldNum = 0; |
61 | 0 | m_picStruct = 0; |
62 | 0 | m_edgePic = NULL; |
63 | 0 | m_gaussianPic = NULL; |
64 | 0 | m_thetaPic = NULL; |
65 | 0 | m_edgeBitPlane = NULL; |
66 | 0 | m_edgeBitPic = NULL; |
67 | 0 | m_isInsideWindow = 0; |
68 | | |
69 | | // mcstf |
70 | 0 | m_isSubSampled = NULL; |
71 | 0 | m_mcstf = NULL; |
72 | 0 | m_refPicCnt[0] = 0; |
73 | 0 | m_refPicCnt[1] = 0; |
74 | 0 | m_nextMCSTF = NULL; |
75 | 0 | m_prevMCSTF = NULL; |
76 | |
|
77 | 0 | m_tempLayer = 0; |
78 | 0 | m_sameLayerRefPic = false; |
79 | |
|
80 | 0 | m_viewId = 0; |
81 | 0 | m_valid = 0; |
82 | 0 | m_nextSubDPB = NULL; |
83 | 0 | m_prevSubDPB = NULL; |
84 | |
|
85 | 0 | m_targetBitrate = 0; |
86 | 0 | m_targetCrf = 0; |
87 | 0 | m_targetQp = 0; |
88 | 0 | } |
89 | | |
90 | | bool Frame::create(x265_param *param, float* quantOffsets) |
91 | 0 | { |
92 | 0 | m_fencPic = new PicYuv; |
93 | 0 | m_param = param; |
94 | |
|
95 | 0 | if (m_param->bEnableTemporalFilter) |
96 | 0 | { |
97 | 0 | m_mcstf = new TemporalFilter; |
98 | 0 | m_mcstffencPic = new PicYuv; |
99 | 0 | m_mcstf->m_range = param->mcstfFrameRange; |
100 | 0 | m_mcstf->init(param); |
101 | |
|
102 | 0 | for (int i = 0; i < (m_mcstf->m_range << 1); i++) |
103 | 0 | m_mcstf->createRefPicInfo(&m_mcstfRefList[i], m_param); |
104 | |
|
105 | 0 | m_fencPicSubsampled2 = new PicYuv; |
106 | 0 | m_fencPicSubsampled4 = new PicYuv; |
107 | |
|
108 | 0 | if (!m_fencPicSubsampled2->createScaledPicYUV(param, 2)) |
109 | 0 | return false; |
110 | 0 | if (!m_fencPicSubsampled4->createScaledPicYUV(param, 4)) |
111 | 0 | return false; |
112 | | |
113 | 0 | m_mcstffencPic->create(param, !!m_param->bCopyPicToFrame); |
114 | 0 | CHECKED_MALLOC_ZERO(m_isSubSampled, int, 1); |
115 | 0 | } |
116 | | |
117 | 0 | CHECKED_MALLOC_ZERO(m_rcData, RcStats, 1); |
118 | |
|
119 | 0 | if (param->bCTUInfo) |
120 | 0 | { |
121 | 0 | uint32_t widthInCTU = (m_param->sourceWidth + param->maxCUSize - 1) >> m_param->maxLog2CUSize; |
122 | 0 | uint32_t heightInCTU = (m_param->sourceHeight + param->maxCUSize - 1) >> m_param->maxLog2CUSize; |
123 | 0 | uint32_t numCTUsInFrame = widthInCTU * heightInCTU; |
124 | 0 | CHECKED_MALLOC_ZERO(m_addOnDepth, uint8_t *, numCTUsInFrame); |
125 | 0 | CHECKED_MALLOC_ZERO(m_addOnCtuInfo, uint8_t *, numCTUsInFrame); |
126 | 0 | CHECKED_MALLOC_ZERO(m_addOnPrevChange, int *, numCTUsInFrame); |
127 | 0 | for (uint32_t i = 0; i < numCTUsInFrame; i++) |
128 | 0 | { |
129 | 0 | CHECKED_MALLOC_ZERO(m_addOnDepth[i], uint8_t, uint32_t(param->num4x4Partitions)); |
130 | 0 | CHECKED_MALLOC_ZERO(m_addOnCtuInfo[i], uint8_t, uint32_t(param->num4x4Partitions)); |
131 | 0 | CHECKED_MALLOC_ZERO(m_addOnPrevChange[i], int, uint32_t(param->num4x4Partitions)); |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | //if (param->bAnalysisType == AVC_INFO) |
136 | 0 | { |
137 | 0 | m_analysisData.wt = NULL; |
138 | 0 | m_analysisData.intraData = NULL; |
139 | 0 | m_analysisData.interData = NULL; |
140 | 0 | m_analysisData.distortionData = NULL; |
141 | 0 | } |
142 | |
|
143 | 0 | if (param->bDynamicRefine) |
144 | 0 | { |
145 | 0 | int size = m_param->maxCUDepth * X265_REFINE_INTER_LEVELS; |
146 | 0 | CHECKED_MALLOC_ZERO(m_classifyRd, uint64_t, size); |
147 | 0 | CHECKED_MALLOC_ZERO(m_classifyVariance, uint64_t, size); |
148 | 0 | CHECKED_MALLOC_ZERO(m_classifyCount, uint32_t, size); |
149 | 0 | } |
150 | | |
151 | 0 | if (param->rc.aqMode == X265_AQ_EDGE || (param->rc.zonefileCount && param->rc.aqMode != 0)) |
152 | 0 | { |
153 | 0 | uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize; |
154 | 0 | uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize; |
155 | 0 | uint32_t m_lumaMarginX = param->maxCUSize + 32; // search margin and 8-tap filter half-length, padded for 32-byte alignment |
156 | 0 | uint32_t m_lumaMarginY = param->maxCUSize + 16; // margin for 8-tap filter and infinite padding |
157 | 0 | intptr_t m_stride = (numCuInWidth * param->maxCUSize) + (m_lumaMarginX << 1); |
158 | 0 | int maxHeight = numCuInHeight * param->maxCUSize; |
159 | |
|
160 | 0 | m_edgePic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); |
161 | 0 | m_gaussianPic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); |
162 | 0 | m_thetaPic = X265_MALLOC(pixel, m_stride * (maxHeight + (m_lumaMarginY * 2))); |
163 | 0 | } |
164 | |
|
165 | 0 | if (param->recursionSkipMode == EDGE_BASED_RSKIP) |
166 | 0 | { |
167 | 0 | uint32_t numCuInWidth = (param->sourceWidth + param->maxCUSize - 1) / param->maxCUSize; |
168 | 0 | uint32_t numCuInHeight = (param->sourceHeight + param->maxCUSize - 1) / param->maxCUSize; |
169 | 0 | uint32_t lumaMarginX = param->maxCUSize + 32; |
170 | 0 | uint32_t lumaMarginY = param->maxCUSize + 16; |
171 | 0 | uint32_t stride = (numCuInWidth * param->maxCUSize) + (lumaMarginX << 1); |
172 | 0 | uint32_t maxHeight = numCuInHeight * param->maxCUSize; |
173 | 0 | uint32_t bitPlaneSize = stride * (maxHeight + (lumaMarginY * 2)); |
174 | 0 | CHECKED_MALLOC_ZERO(m_edgeBitPlane, pixel, bitPlaneSize); |
175 | 0 | m_edgeBitPic = m_edgeBitPlane + lumaMarginY * stride + lumaMarginX; |
176 | 0 | } |
177 | | |
178 | 0 | if (m_fencPic->create(param, !!m_param->bCopyPicToFrame) && m_lowres.create(param, m_fencPic, param->rc.qgSize)) |
179 | 0 | { |
180 | 0 | X265_CHECK((m_reconColCount == NULL), "m_reconColCount was initialized"); |
181 | 0 | m_numRows = (m_fencPic->m_picHeight + param->maxCUSize - 1) / param->maxCUSize; |
182 | 0 | m_reconRowFlag = new ThreadSafeInteger[m_numRows]; |
183 | 0 | m_reconColCount = new ThreadSafeInteger[m_numRows]; |
184 | |
|
185 | 0 | if (quantOffsets) |
186 | 0 | { |
187 | 0 | int32_t cuCount = (param->rc.qgSize == 8) ? m_lowres.maxBlocksInRowFullRes * m_lowres.maxBlocksInColFullRes : |
188 | 0 | m_lowres.maxBlocksInRow * m_lowres.maxBlocksInCol; |
189 | 0 | m_quantOffsets = new float[cuCount]; |
190 | 0 | } |
191 | 0 | return true; |
192 | 0 | } |
193 | 0 | return false; |
194 | 0 | fail: |
195 | 0 | return false; |
196 | 0 | } |
197 | | |
198 | | bool Frame::createSubSample() |
199 | 0 | { |
200 | |
|
201 | 0 | m_fencPicSubsampled2 = new PicYuv; |
202 | 0 | m_fencPicSubsampled4 = new PicYuv; |
203 | |
|
204 | 0 | if (!m_fencPicSubsampled2->createScaledPicYUV(m_param, 2)) |
205 | 0 | return false; |
206 | 0 | if (!m_fencPicSubsampled4->createScaledPicYUV(m_param, 4)) |
207 | 0 | return false; |
208 | 0 | CHECKED_MALLOC_ZERO(m_isSubSampled, int, 1); |
209 | 0 | return true; |
210 | 0 | fail: |
211 | 0 | return false; |
212 | 0 | } |
213 | | |
214 | | bool Frame::allocEncodeData(x265_param *param, const SPS& sps) |
215 | 0 | { |
216 | 0 | m_encData = new FrameData; |
217 | 0 | m_param = param; |
218 | 0 | for (int i = 0; i < !!m_param->bEnableSCC + 1; i++) |
219 | 0 | { |
220 | 0 | m_reconPic[i] = new PicYuv; |
221 | 0 | m_encData->m_reconPic[i] = m_reconPic[i]; |
222 | 0 | } |
223 | 0 | 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); |
224 | 0 | if (ok) |
225 | 0 | { |
226 | | /* initialize right border of m_reconPicYuv as SAO may read beyond the |
227 | | * end of the picture accessing uninitialized pixels */ |
228 | 0 | int maxHeight = sps.numCuInHeight * param->maxCUSize; |
229 | 0 | memset(m_reconPic[0]->m_picOrg[0], 0, sizeof(pixel)* m_reconPic[0]->m_stride * maxHeight); |
230 | |
|
231 | 0 | for (int i = 0; i < !!m_param->bEnableSCC + 1; i++) |
232 | 0 | { |
233 | | /* use pre-calculated cu/pu offsets cached in the SPS structure */ |
234 | 0 | m_reconPic[i]->m_cuOffsetY = sps.cuOffsetY; |
235 | 0 | m_reconPic[i]->m_buOffsetY = sps.buOffsetY; |
236 | |
|
237 | 0 | if (param->internalCsp != X265_CSP_I400) |
238 | 0 | { |
239 | 0 | memset(m_reconPic[i]->m_picOrg[1], 0, sizeof(pixel) * m_reconPic[i]->m_strideC * (maxHeight >> m_reconPic[i]->m_vChromaShift)); |
240 | 0 | memset(m_reconPic[i]->m_picOrg[2], 0, sizeof(pixel) * m_reconPic[i]->m_strideC * (maxHeight >> m_reconPic[i]->m_vChromaShift)); |
241 | | |
242 | | /* use pre-calculated cu/pu offsets cached in the SPS structure */ |
243 | 0 | m_reconPic[i]->m_cuOffsetC = sps.cuOffsetC; |
244 | 0 | m_reconPic[i]->m_buOffsetC = sps.buOffsetC; |
245 | 0 | } |
246 | 0 | } |
247 | 0 | } |
248 | 0 | return ok; |
249 | 0 | } |
250 | | |
251 | | /* prepare to re-use a FrameData instance to encode a new picture */ |
252 | | void Frame::reinit(const SPS& sps) |
253 | 0 | { |
254 | 0 | m_bChromaExtended = false; |
255 | 0 | for (int i = 0; i < !!m_param->bEnableSCC + 1; i++) |
256 | 0 | m_reconPic[i] = m_encData->m_reconPic[i]; |
257 | 0 | m_encData->reinit(sps); |
258 | 0 | } |
259 | | |
260 | | void Frame::destroy() |
261 | 0 | { |
262 | 0 | if (m_encData) |
263 | 0 | { |
264 | 0 | m_encData->destroy(); |
265 | 0 | delete m_encData; |
266 | 0 | m_encData = NULL; |
267 | 0 | } |
268 | |
|
269 | | #if ENABLE_MULTIVIEW |
270 | | //Destroy interlayer References |
271 | | if (refPicSetInterLayer0.size()) |
272 | | { |
273 | | Frame* iterFrame = refPicSetInterLayer0.first(); |
274 | | |
275 | | while (iterFrame) |
276 | | { |
277 | | Frame* curFrame = iterFrame; |
278 | | iterFrame = iterFrame->m_nextSubDPB; |
279 | | refPicSetInterLayer0.removeSubDPB(*curFrame); |
280 | | iterFrame = refPicSetInterLayer0.first(); |
281 | | } |
282 | | } |
283 | | |
284 | | if (refPicSetInterLayer1.size()) |
285 | | { |
286 | | Frame* iterFrame = refPicSetInterLayer1.first(); |
287 | | |
288 | | while (iterFrame) |
289 | | { |
290 | | Frame* curFrame = iterFrame; |
291 | | iterFrame = iterFrame->m_nextSubDPB; |
292 | | refPicSetInterLayer1.removeSubDPB(*curFrame); |
293 | | iterFrame = refPicSetInterLayer1.first(); |
294 | | } |
295 | | } |
296 | | #endif |
297 | |
|
298 | 0 | if (m_fencPic) |
299 | 0 | { |
300 | 0 | if (m_param->bCopyPicToFrame) |
301 | 0 | m_fencPic->destroy(); |
302 | 0 | delete m_fencPic; |
303 | 0 | m_fencPic = NULL; |
304 | 0 | } |
305 | |
|
306 | 0 | if (m_param->bEnableTemporalFilter) |
307 | 0 | { |
308 | |
|
309 | 0 | if (m_fencPicSubsampled2) |
310 | 0 | { |
311 | 0 | m_fencPicSubsampled2->destroy(); |
312 | 0 | delete m_fencPicSubsampled2; |
313 | 0 | m_fencPicSubsampled2 = NULL; |
314 | 0 | } |
315 | |
|
316 | 0 | if (m_fencPicSubsampled4) |
317 | 0 | { |
318 | 0 | m_fencPicSubsampled4->destroy(); |
319 | 0 | delete m_fencPicSubsampled4; |
320 | 0 | m_fencPicSubsampled4 = NULL; |
321 | 0 | } |
322 | |
|
323 | 0 | delete m_mcstf->m_metld; |
324 | 0 | m_mcstf->m_metld = NULL; |
325 | 0 | for (int i = 0; i < (m_mcstf->m_range << 1); i++) |
326 | 0 | m_mcstf->destroyRefPicInfo(&m_mcstfRefList[i]); |
327 | |
|
328 | 0 | if (m_mcstffencPic) |
329 | 0 | { |
330 | 0 | m_mcstffencPic->destroy(); |
331 | 0 | delete m_mcstffencPic; |
332 | 0 | m_mcstffencPic = NULL; |
333 | 0 | } |
334 | |
|
335 | 0 | delete m_mcstf; |
336 | 0 | X265_FREE(m_isSubSampled); |
337 | 0 | } |
338 | |
|
339 | 0 | for (int i = 0; i < !!m_param->bEnableSCC + 1; i++) |
340 | 0 | { |
341 | 0 | if (m_reconPic[i]) |
342 | 0 | { |
343 | 0 | m_reconPic[i]->destroy(); |
344 | 0 | delete m_reconPic[i]; |
345 | 0 | m_reconPic[i] = NULL; |
346 | 0 | } |
347 | 0 | } |
348 | |
|
349 | 0 | if (m_reconRowFlag) |
350 | 0 | { |
351 | 0 | delete[] m_reconRowFlag; |
352 | 0 | m_reconRowFlag = NULL; |
353 | 0 | } |
354 | |
|
355 | 0 | if (m_reconColCount) |
356 | 0 | { |
357 | 0 | delete[] m_reconColCount; |
358 | 0 | m_reconColCount = NULL; |
359 | 0 | } |
360 | |
|
361 | 0 | if (m_quantOffsets) |
362 | 0 | { |
363 | 0 | delete[] m_quantOffsets; |
364 | 0 | } |
365 | |
|
366 | 0 | if (m_userSEI.numPayloads) |
367 | 0 | { |
368 | 0 | for (int i = 0; i < m_userSEI.numPayloads; i++) |
369 | 0 | delete[] m_userSEI.payloads[i].payload; |
370 | 0 | delete[] m_userSEI.payloads; |
371 | 0 | } |
372 | |
|
373 | 0 | if (m_ctuInfo) |
374 | 0 | { |
375 | 0 | uint32_t widthInCU = (m_param->sourceWidth + m_param->maxCUSize - 1) >> m_param->maxLog2CUSize; |
376 | 0 | uint32_t heightInCU = (m_param->sourceHeight + m_param->maxCUSize - 1) >> m_param->maxLog2CUSize; |
377 | 0 | uint32_t numCUsInFrame = widthInCU * heightInCU; |
378 | 0 | for (uint32_t i = 0; i < numCUsInFrame; i++) |
379 | 0 | { |
380 | 0 | X265_FREE((*m_ctuInfo + i)->ctuInfo); |
381 | 0 | (*m_ctuInfo + i)->ctuInfo = NULL; |
382 | 0 | X265_FREE(m_addOnDepth[i]); |
383 | 0 | m_addOnDepth[i] = NULL; |
384 | 0 | X265_FREE(m_addOnCtuInfo[i]); |
385 | 0 | m_addOnCtuInfo[i] = NULL; |
386 | 0 | X265_FREE(m_addOnPrevChange[i]); |
387 | 0 | m_addOnPrevChange[i] = NULL; |
388 | 0 | } |
389 | 0 | X265_FREE(*m_ctuInfo); |
390 | 0 | *m_ctuInfo = NULL; |
391 | 0 | X265_FREE(m_ctuInfo); |
392 | 0 | m_ctuInfo = NULL; |
393 | 0 | X265_FREE(m_prevCtuInfoChange); |
394 | 0 | m_prevCtuInfoChange = NULL; |
395 | 0 | X265_FREE(m_addOnDepth); |
396 | 0 | m_addOnDepth = NULL; |
397 | 0 | X265_FREE(m_addOnCtuInfo); |
398 | 0 | m_addOnCtuInfo = NULL; |
399 | 0 | X265_FREE(m_addOnPrevChange); |
400 | 0 | m_addOnPrevChange = NULL; |
401 | 0 | } |
402 | |
|
403 | 0 | m_lowres.destroy(m_param); |
404 | 0 | X265_FREE(m_rcData); |
405 | |
|
406 | 0 | if (m_param->bDynamicRefine) |
407 | 0 | { |
408 | 0 | X265_FREE_ZERO(m_classifyRd); |
409 | 0 | X265_FREE_ZERO(m_classifyVariance); |
410 | 0 | X265_FREE_ZERO(m_classifyCount); |
411 | 0 | } |
412 | |
|
413 | 0 | if (m_param->rc.aqMode == X265_AQ_EDGE || (m_param->rc.zonefileCount && m_param->rc.aqMode != 0)) |
414 | 0 | { |
415 | 0 | X265_FREE(m_edgePic); |
416 | 0 | X265_FREE(m_gaussianPic); |
417 | 0 | X265_FREE(m_thetaPic); |
418 | 0 | } |
419 | |
|
420 | 0 | if (m_param->recursionSkipMode == EDGE_BASED_RSKIP) |
421 | 0 | { |
422 | 0 | X265_FREE_ZERO(m_edgeBitPlane); |
423 | 0 | m_edgeBitPic = NULL; |
424 | 0 | } |
425 | 0 | } |