/src/x265/source/encoder/api.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * Copyright (C) 2013-2020 MulticoreWare, Inc |
3 | | * |
4 | | * Authors: Steve Borho <steve@borho.org> |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. |
19 | | * |
20 | | * This program is also available under a commercial proprietary license. |
21 | | * For more information, contact us at license @ x265.com. |
22 | | *****************************************************************************/ |
23 | | #include "common.h" |
24 | | #include "bitstream.h" |
25 | | #include "param.h" |
26 | | |
27 | | #include "encoder.h" |
28 | | #include "entropy.h" |
29 | | #include "level.h" |
30 | | #include "nal.h" |
31 | | #include "bitcost.h" |
32 | | #include "svt.h" |
33 | | |
34 | | #if ENABLE_LIBVMAF |
35 | | #include "libvmaf/libvmaf.h" |
36 | | #endif |
37 | | |
38 | | /* multilib namespace reflectors */ |
39 | | #if LINKED_8BIT |
40 | | namespace x265_8bit { |
41 | | const x265_api* x265_api_get(int bitDepth); |
42 | | const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err); |
43 | | } |
44 | | #endif |
45 | | |
46 | | #if LINKED_10BIT |
47 | | namespace x265_10bit { |
48 | | const x265_api* x265_api_get(int bitDepth); |
49 | | const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err); |
50 | | } |
51 | | #endif |
52 | | |
53 | | #if LINKED_12BIT |
54 | | namespace x265_12bit { |
55 | | const x265_api* x265_api_get(int bitDepth); |
56 | | const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err); |
57 | | } |
58 | | #endif |
59 | | |
60 | | #if EXPORT_C_API |
61 | | /* these functions are exported as C functions (default) */ |
62 | | using namespace X265_NS; |
63 | | extern "C" { |
64 | | #else |
65 | | /* these functions exist within private namespace (multilib) */ |
66 | | namespace X265_NS { |
67 | | #endif |
68 | | |
69 | | static const char* summaryCSVHeader = |
70 | | "Command, Date/Time, Elapsed Time, FPS, Bitrate, " |
71 | | "Y PSNR, U PSNR, V PSNR, Global PSNR, SSIM, SSIM (dB), " |
72 | | "I count, I ave-QP, I kbps, I-PSNR Y, I-PSNR U, I-PSNR V, I-SSIM (dB), " |
73 | | "P count, P ave-QP, P kbps, P-PSNR Y, P-PSNR U, P-PSNR V, P-SSIM (dB), " |
74 | | "B count, B ave-QP, B kbps, B-PSNR Y, B-PSNR U, B-PSNR V, B-SSIM (dB), "; |
75 | | x265_encoder *x265_encoder_open(x265_param *p) |
76 | 0 | { |
77 | 0 | if (!p) |
78 | 0 | return NULL; |
79 | | |
80 | | #if _MSC_VER |
81 | | #pragma warning(disable: 4127) // conditional expression is constant, yes I know |
82 | | #endif |
83 | | |
84 | | #if HIGH_BIT_DEPTH |
85 | | if (X265_DEPTH != 10 && X265_DEPTH != 12) |
86 | | #else |
87 | 0 | if (X265_DEPTH != 8) |
88 | 0 | #endif |
89 | 0 | { |
90 | 0 | x265_log(p, X265_LOG_ERROR, "Build error, internal bit depth mismatch\n"); |
91 | 0 | return NULL; |
92 | 0 | } |
93 | | |
94 | 0 | Encoder* encoder = new Encoder; |
95 | 0 | encoder->m_paramBase[0] = PARAM_NS::x265_param_alloc(); |
96 | 0 | encoder->m_paramBase[1] = PARAM_NS::x265_param_alloc(); |
97 | 0 | encoder->m_paramBase[2] = PARAM_NS::x265_param_alloc(); |
98 | |
|
99 | 0 | x265_param* param = encoder->m_paramBase[0]; |
100 | 0 | x265_param* latestParam = encoder->m_paramBase[1]; |
101 | 0 | x265_param* zoneParam = encoder->m_paramBase[2]; |
102 | |
|
103 | 0 | if(param) PARAM_NS::x265_param_default(param); |
104 | 0 | if(latestParam) PARAM_NS::x265_param_default(latestParam); |
105 | 0 | if(zoneParam) PARAM_NS::x265_param_default(zoneParam); |
106 | | |
107 | 0 | if (!param || !latestParam || !zoneParam) |
108 | 0 | goto fail; |
109 | 0 | if (p->rc.zoneCount || p->rc.zonefileCount) |
110 | 0 | { |
111 | 0 | int zoneCount = p->rc.zonefileCount ? p->rc.zonefileCount : p->rc.zoneCount; |
112 | 0 | param->rc.zones = x265_zone_alloc(zoneCount, !!p->rc.zonefileCount); |
113 | 0 | latestParam->rc.zones = x265_zone_alloc(zoneCount, !!p->rc.zonefileCount); |
114 | 0 | zoneParam->rc.zones = x265_zone_alloc(zoneCount, !!p->rc.zonefileCount); |
115 | 0 | } |
116 | |
|
117 | 0 | x265_copy_params(param, p); |
118 | 0 | x265_copy_params(latestParam, p); |
119 | 0 | x265_copy_params(zoneParam, p); |
120 | 0 | x265_log(param, X265_LOG_INFO, "HEVC encoder version %s\n", PFX(version_str)); |
121 | 0 | x265_log(param, X265_LOG_INFO, "build info %s\n", PFX(build_info_str)); |
122 | |
|
123 | | #ifdef SVT_HEVC |
124 | | |
125 | | if (param->bEnableSvtHevc) |
126 | | { |
127 | | EB_ERRORTYPE return_error = EB_ErrorNone; |
128 | | int ret = 0; |
129 | | |
130 | | svt_initialise_app_context(encoder); |
131 | | ret = svt_initialise_input_buffer(encoder); |
132 | | if (!ret) |
133 | | { |
134 | | x265_log(param, X265_LOG_ERROR, "SVT-HEVC Encoder: Unable to allocate input buffer \n"); |
135 | | goto fail; |
136 | | } |
137 | | |
138 | | // Create Encoder Handle |
139 | | return_error = EbInitHandle(&encoder->m_svtAppData->svtEncoderHandle, encoder->m_svtAppData, encoder->m_svtAppData->svtHevcParams); |
140 | | if (return_error != EB_ErrorNone) |
141 | | { |
142 | | x265_log(param, X265_LOG_ERROR, "SVT-HEVC Encoder: Unable to initialise encoder handle \n"); |
143 | | goto fail; |
144 | | } |
145 | | |
146 | | memcpy(encoder->m_svtAppData->svtHevcParams, param->svtHevcParam, sizeof(EB_H265_ENC_CONFIGURATION)); |
147 | | |
148 | | // Send over all configuration parameters |
149 | | return_error = EbH265EncSetParameter(encoder->m_svtAppData->svtEncoderHandle, encoder->m_svtAppData->svtHevcParams); |
150 | | if (return_error != EB_ErrorNone) |
151 | | { |
152 | | x265_log(param, X265_LOG_ERROR, "SVT-HEVC Encoder: Error while configuring encoder parameters \n"); |
153 | | goto fail; |
154 | | } |
155 | | |
156 | | // Init Encoder |
157 | | return_error = EbInitEncoder(encoder->m_svtAppData->svtEncoderHandle); |
158 | | if (return_error != EB_ErrorNone) |
159 | | { |
160 | | x265_log(param, X265_LOG_ERROR, "SVT-HEVC Encoder: Encoder init failed \n"); |
161 | | goto fail; |
162 | | } |
163 | | |
164 | | memcpy(param->svtHevcParam, encoder->m_svtAppData->svtHevcParams, sizeof(EB_H265_ENC_CONFIGURATION)); |
165 | | encoder->m_param = param; |
166 | | return encoder; |
167 | | } |
168 | | #endif |
169 | |
|
170 | 0 | x265_setup_primitives(param); |
171 | |
|
172 | 0 | if (x265_check_params(param)) |
173 | 0 | goto fail; |
174 | | |
175 | 0 | if (!param->rc.bEnableSlowFirstPass) |
176 | 0 | PARAM_NS::x265_param_apply_fastfirstpass(param); |
177 | | |
178 | | // may change params for auto-detect, etc |
179 | 0 | encoder->configure(param); |
180 | 0 | if (encoder->m_aborted) |
181 | 0 | goto fail; |
182 | | // may change rate control and CPB params |
183 | 0 | if (!enforceLevel(*param, encoder->m_vps)) |
184 | 0 | goto fail; |
185 | | |
186 | | // will detect and set profile/tier/level in VPS |
187 | 0 | determineLevel(*param, encoder->m_vps); |
188 | |
|
189 | 0 | if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc[0] == Profile::NONE) |
190 | 0 | { |
191 | 0 | x265_log(param, X265_LOG_INFO, "non-conformant bitstreams not allowed (--allow-non-conformance)\n"); |
192 | 0 | goto fail; |
193 | 0 | } |
194 | | |
195 | 0 | encoder->create(); |
196 | 0 | p->frameNumThreads = encoder->m_param->frameNumThreads; |
197 | |
|
198 | 0 | if (!param->bResetZoneConfig) |
199 | 0 | { |
200 | | // TODO: Memory pointer broken if both (p->rc.zoneCount || p->rc.zonefileCount) and (!param->bResetZoneConfig) |
201 | 0 | param->rc.zones = x265_zone_alloc(param->rc.zonefileCount, 1); |
202 | 0 | for (int i = 0; i < param->rc.zonefileCount; i++) |
203 | 0 | { |
204 | 0 | memcpy(param->rc.zones[i].zoneParam, param, sizeof(x265_param)); |
205 | 0 | param->rc.zones[i].relativeComplexity = X265_MALLOC(double, param->reconfigWindowSize); |
206 | 0 | } |
207 | 0 | } |
208 | |
|
209 | 0 | x265_copy_params(zoneParam, param); |
210 | 0 | for (int i = 0; i < param->rc.zonefileCount; i++) |
211 | 0 | { |
212 | 0 | encoder->configureZone(zoneParam, param->rc.zones[i].zoneParam); |
213 | 0 | } |
214 | | |
215 | | /* Try to open CSV file handle */ |
216 | 0 | if (strlen(encoder->m_param->csvfn)) |
217 | 0 | { |
218 | 0 | encoder->m_param->csvfpt = x265_csvlog_open(encoder->m_param); |
219 | 0 | if (!encoder->m_param->csvfpt) |
220 | 0 | { |
221 | 0 | x265_log(encoder->m_param, X265_LOG_ERROR, "Unable to open CSV log file <%s>, aborting\n", encoder->m_param->csvfn); |
222 | 0 | encoder->m_aborted = true; |
223 | 0 | } |
224 | 0 | } |
225 | |
|
226 | 0 | encoder->m_latestParam = latestParam; |
227 | 0 | encoder->m_zoneParam = zoneParam; |
228 | 0 | x265_copy_params(latestParam, param); |
229 | 0 | if (encoder->m_aborted) |
230 | 0 | goto fail; |
231 | | |
232 | 0 | x265_print_params(param); |
233 | 0 | return encoder; |
234 | | |
235 | 0 | fail: |
236 | 0 | delete encoder; |
237 | 0 | PARAM_NS::x265_param_free(param); |
238 | 0 | PARAM_NS::x265_param_free(latestParam); |
239 | 0 | PARAM_NS::x265_param_free(zoneParam); |
240 | 0 | return NULL; |
241 | 0 | } |
242 | | |
243 | | int x265_encoder_headers(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal) |
244 | 0 | { |
245 | 0 | if (pp_nal && enc) |
246 | 0 | { |
247 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
248 | | #ifdef SVT_HEVC |
249 | | if (encoder->m_param->bEnableSvtHevc) |
250 | | { |
251 | | EB_ERRORTYPE return_error; |
252 | | EB_BUFFERHEADERTYPE* outputPtr; |
253 | | return_error = EbH265EncStreamHeader(encoder->m_svtAppData->svtEncoderHandle, &outputPtr); |
254 | | if (return_error != EB_ErrorNone) |
255 | | { |
256 | | x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while generating stream headers \n"); |
257 | | encoder->m_aborted = true; |
258 | | return -1; |
259 | | } |
260 | | |
261 | | //Copy data from output packet to NAL |
262 | | encoder->m_nalList.m_nal[0].payload = outputPtr->pBuffer; |
263 | | encoder->m_nalList.m_nal[0].sizeBytes = outputPtr->nFilledLen; |
264 | | *pp_nal = &encoder->m_nalList.m_nal[0]; |
265 | | *pi_nal = 1; |
266 | | encoder->m_svtAppData->byteCount += outputPtr->nFilledLen; |
267 | | |
268 | | // Release the output buffer |
269 | | EbH265ReleaseOutBuffer(&outputPtr); |
270 | | |
271 | | return pp_nal[0]->sizeBytes; |
272 | | } |
273 | | #endif |
274 | |
|
275 | 0 | Entropy sbacCoder; |
276 | 0 | Bitstream bs; |
277 | 0 | if (encoder->m_param->rc.bStatRead && encoder->m_param->bMultiPassOptRPS) |
278 | 0 | { |
279 | 0 | if (!encoder->computeSPSRPSIndex()) |
280 | 0 | { |
281 | 0 | encoder->m_aborted = true; |
282 | 0 | return -1; |
283 | 0 | } |
284 | 0 | } |
285 | 0 | encoder->getStreamHeaders(encoder->m_nalList, sbacCoder, bs); |
286 | 0 | *pp_nal = &encoder->m_nalList.m_nal[0]; |
287 | 0 | if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal; |
288 | 0 | return encoder->m_nalList.m_occupancy; |
289 | 0 | } |
290 | | |
291 | 0 | if (enc) |
292 | 0 | { |
293 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
294 | 0 | encoder->m_aborted = true; |
295 | 0 | } |
296 | 0 | return -1; |
297 | 0 | } |
298 | | |
299 | | void x265_encoder_parameters(x265_encoder *enc, x265_param *out) |
300 | 0 | { |
301 | 0 | if (enc && out) |
302 | 0 | { |
303 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
304 | 0 | x265_copy_params(out, encoder->m_param); |
305 | 0 | } |
306 | 0 | } |
307 | | |
308 | | int x265_encoder_reconfig(x265_encoder* enc, x265_param* param_in) |
309 | 0 | { |
310 | 0 | if (!enc || !param_in) |
311 | 0 | return -1; |
312 | 0 | x265_param save = {}; |
313 | 0 | Encoder* encoder = static_cast<Encoder*>(enc); |
314 | 0 | if (strlen(encoder->m_param->csvfn) && param_in->csvfpt != NULL) |
315 | 0 | encoder->m_param->csvfpt = param_in->csvfpt; |
316 | 0 | if (encoder->m_latestParam->forceFlush != param_in->forceFlush) |
317 | 0 | return encoder->reconfigureParam(encoder->m_latestParam, param_in); |
318 | 0 | bool isReconfigureRc = encoder->isReconfigureRc(encoder->m_latestParam, param_in); |
319 | 0 | if ((encoder->m_reconfigure && !isReconfigureRc) || (encoder->m_reconfigureRc && isReconfigureRc)) /* Reconfigure in progress */ |
320 | 0 | return 1; |
321 | 0 | if (encoder->m_latestParam->rc.zoneCount || encoder->m_latestParam->rc.zonefileCount) |
322 | 0 | { |
323 | 0 | int zoneCount = encoder->m_latestParam->rc.zonefileCount ? encoder->m_latestParam->rc.zonefileCount : encoder->m_latestParam->rc.zoneCount; |
324 | 0 | save.rc.zones = x265_zone_alloc(zoneCount, !!encoder->m_latestParam->rc.zonefileCount); |
325 | 0 | } |
326 | 0 | x265_copy_params(&save, encoder->m_latestParam); |
327 | 0 | int ret = encoder->reconfigureParam(encoder->m_latestParam, param_in); |
328 | 0 | if (ret) |
329 | 0 | { |
330 | | /* reconfigure failed, recover saved param set */ |
331 | 0 | x265_copy_params(encoder->m_latestParam, &save); |
332 | 0 | x265_zone_free(&save); |
333 | 0 | ret = -1; |
334 | 0 | } |
335 | 0 | else |
336 | 0 | { |
337 | 0 | encoder->configure(encoder->m_latestParam); |
338 | 0 | if (strlen(encoder->m_latestParam->scalingLists) && strcmp(encoder->m_latestParam->scalingLists, encoder->m_param->scalingLists)) |
339 | 0 | { |
340 | 0 | if (encoder->m_param->bRepeatHeaders) |
341 | 0 | { |
342 | 0 | if (encoder->m_scalingList.parseScalingList(encoder->m_latestParam->scalingLists)) |
343 | 0 | { |
344 | 0 | x265_copy_params(encoder->m_latestParam, &save); |
345 | 0 | x265_zone_free(&save); |
346 | 0 | return -1; |
347 | 0 | } |
348 | 0 | encoder->m_scalingList.setupQuantMatrices(encoder->m_param->internalCsp); |
349 | 0 | } |
350 | 0 | else |
351 | 0 | { |
352 | 0 | x265_log(encoder->m_param, X265_LOG_ERROR, "Repeat headers is turned OFF, cannot reconfigure scalinglists\n"); |
353 | 0 | x265_copy_params(encoder->m_latestParam, &save); |
354 | 0 | x265_zone_free(&save); |
355 | 0 | return -1; |
356 | 0 | } |
357 | 0 | } |
358 | 0 | if (!isReconfigureRc) |
359 | 0 | encoder->m_reconfigure = true; |
360 | 0 | else if (encoder->m_reconfigureRc || encoder->m_latestParam->bConfigRCFrame) |
361 | 0 | { |
362 | 0 | VPS saveVPS; |
363 | 0 | memcpy(&saveVPS.ptl, &encoder->m_vps.ptl, sizeof(saveVPS.ptl)); |
364 | 0 | determineLevel(*encoder->m_latestParam, encoder->m_vps); |
365 | 0 | if (saveVPS.ptl.profileIdc[0] != encoder->m_vps.ptl.profileIdc[0] || saveVPS.ptl.levelIdc != encoder->m_vps.ptl.levelIdc |
366 | 0 | || saveVPS.ptl.tierFlag != encoder->m_vps.ptl.tierFlag) |
367 | 0 | { |
368 | 0 | x265_log(encoder->m_param, X265_LOG_WARNING, "Profile/Level/Tier has changed from %d/%d/%s to %d/%d/%s.Cannot reconfigure rate-control.\n", |
369 | 0 | saveVPS.ptl.profileIdc[0], saveVPS.ptl.levelIdc, saveVPS.ptl.tierFlag ? "High" : "Main", encoder->m_vps.ptl.profileIdc[0], |
370 | 0 | encoder->m_vps.ptl.levelIdc, encoder->m_vps.ptl.tierFlag ? "High" : "Main"); |
371 | 0 | x265_copy_params(encoder->m_latestParam, &save); |
372 | 0 | memcpy(&encoder->m_vps.ptl, &saveVPS.ptl, sizeof(saveVPS.ptl)); |
373 | 0 | encoder->m_reconfigureRc = false; |
374 | 0 | } |
375 | 0 | } |
376 | 0 | encoder->printReconfigureParams(); |
377 | 0 | } |
378 | | /* Zones support modifying num of Refs. Requires determining level at each zone start*/ |
379 | 0 | if (encoder->m_param->rc.zonefileCount) |
380 | 0 | determineLevel(*encoder->m_latestParam, encoder->m_vps); |
381 | 0 | x265_zone_free(&save); |
382 | 0 | return ret; |
383 | 0 | } |
384 | | |
385 | | |
386 | | int x265_encoder_reconfig_zone(x265_encoder* enc, x265_zone* zone_in) |
387 | 0 | { |
388 | 0 | if (!enc || !zone_in) |
389 | 0 | return -1; |
390 | | |
391 | 0 | Encoder* encoder = static_cast<Encoder*>(enc); |
392 | 0 | int read = encoder->zoneReadCount[encoder->m_zoneIndex].get(); |
393 | 0 | int write = encoder->zoneWriteCount[encoder->m_zoneIndex].get(); |
394 | |
|
395 | 0 | x265_zone* zone = &(encoder->m_param->rc).zones[encoder->m_zoneIndex]; |
396 | 0 | x265_param* zoneParam = zone->zoneParam; |
397 | |
|
398 | 0 | if (write && (read < write)) |
399 | 0 | { |
400 | 0 | read = encoder->zoneReadCount[encoder->m_zoneIndex].waitForChange(read); |
401 | 0 | } |
402 | |
|
403 | 0 | zone->startFrame = zone_in->startFrame; |
404 | 0 | zoneParam->rc.bitrate = zone_in->zoneParam->rc.bitrate; |
405 | 0 | zoneParam->rc.vbvMaxBitrate = zone_in->zoneParam->rc.vbvMaxBitrate; |
406 | 0 | memcpy(zone->relativeComplexity, zone_in->relativeComplexity, sizeof(double) * encoder->m_param->reconfigWindowSize); |
407 | | |
408 | 0 | encoder->zoneWriteCount[encoder->m_zoneIndex].incr(); |
409 | 0 | encoder->m_zoneIndex++; |
410 | 0 | encoder->m_zoneIndex %= encoder->m_param->rc.zonefileCount; |
411 | |
|
412 | 0 | return 0; |
413 | 0 | } |
414 | | void x265_configure_vbv_end(x265_encoder* enc, x265_picture* picture, double totalstreamduration) |
415 | 0 | { |
416 | 0 | Encoder* encoder = static_cast<Encoder*>(enc); |
417 | 0 | if ((totalstreamduration > 0) && (picture->poc) > ((encoder->m_param->vbvEndFrameAdjust)*(totalstreamduration)*((double)(encoder->m_param->fpsNum / encoder->m_param->fpsDenom)))) |
418 | 0 | { |
419 | 0 | picture->vbvEndFlag = 1; |
420 | 0 | } |
421 | 0 | } |
422 | | int x265_encoder_encode(x265_encoder* enc, x265_nal** pp_nal, uint32_t* pi_nal, x265_picture* pic_in, x265_picture* pic_out) |
423 | 0 | { |
424 | 0 | if (!enc) |
425 | 0 | return -1; |
426 | | |
427 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
428 | 0 | int numEncoded; |
429 | |
|
430 | | #ifdef SVT_HEVC |
431 | | EB_ERRORTYPE return_error; |
432 | | if (encoder->m_param->bEnableSvtHevc) |
433 | | { |
434 | | static unsigned char picSendDone = 0; |
435 | | numEncoded = 0; |
436 | | static int codedNal = 0, eofReached = 0; |
437 | | EB_H265_ENC_CONFIGURATION* svtParam = (EB_H265_ENC_CONFIGURATION*)encoder->m_svtAppData->svtHevcParams; |
438 | | if (pic_in) |
439 | | { |
440 | | if (pic_in->colorSpace == X265_CSP_I420) // SVT-HEVC supports only yuv420p color space |
441 | | { |
442 | | EB_BUFFERHEADERTYPE *inputPtr = encoder->m_svtAppData->inputPictureBuffer; |
443 | | |
444 | | if (pic_in->framesize) inputPtr->nFilledLen = (uint32_t)pic_in->framesize; |
445 | | inputPtr->nFlags = 0; |
446 | | inputPtr->pts = pic_in->pts; |
447 | | inputPtr->dts = pic_in->dts; |
448 | | inputPtr->sliceType = EB_INVALID_PICTURE; |
449 | | |
450 | | EB_H265_ENC_INPUT *inputData = (EB_H265_ENC_INPUT*) inputPtr->pBuffer; |
451 | | inputData->luma = (unsigned char*) pic_in->planes[0]; |
452 | | inputData->cb = (unsigned char*) pic_in->planes[1]; |
453 | | inputData->cr = (unsigned char*) pic_in->planes[2]; |
454 | | |
455 | | inputData->yStride = encoder->m_param->sourceWidth; |
456 | | inputData->cbStride = encoder->m_param->sourceWidth >> 1; |
457 | | inputData->crStride = encoder->m_param->sourceWidth >> 1; |
458 | | |
459 | | inputData->lumaExt = NULL; |
460 | | inputData->cbExt = NULL; |
461 | | inputData->crExt = NULL; |
462 | | |
463 | | if (pic_in->rpu.payloadSize) |
464 | | { |
465 | | inputData->dolbyVisionRpu.payload = X265_MALLOC(uint8_t, 1024); |
466 | | memcpy(inputData->dolbyVisionRpu.payload, pic_in->rpu.payload, pic_in->rpu.payloadSize); |
467 | | inputData->dolbyVisionRpu.payloadSize = pic_in->rpu.payloadSize; |
468 | | inputData->dolbyVisionRpu.payloadType = NAL_UNIT_UNSPECIFIED; |
469 | | } |
470 | | else |
471 | | { |
472 | | inputData->dolbyVisionRpu.payload = NULL; |
473 | | inputData->dolbyVisionRpu.payloadSize = 0; |
474 | | } |
475 | | |
476 | | // Send the picture to the encoder |
477 | | return_error = EbH265EncSendPicture(encoder->m_svtAppData->svtEncoderHandle, inputPtr); |
478 | | |
479 | | if (return_error != EB_ErrorNone) |
480 | | { |
481 | | x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while encoding \n"); |
482 | | numEncoded = -1; |
483 | | goto fail; |
484 | | } |
485 | | } |
486 | | else |
487 | | { |
488 | | x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC Encoder accepts only yuv420p input \n"); |
489 | | numEncoded = -1; |
490 | | goto fail; |
491 | | } |
492 | | } |
493 | | else if (!picSendDone) //Encoder flush |
494 | | { |
495 | | picSendDone = 1; |
496 | | EB_BUFFERHEADERTYPE inputPtrLast; |
497 | | inputPtrLast.nAllocLen = 0; |
498 | | inputPtrLast.nFilledLen = 0; |
499 | | inputPtrLast.nTickCount = 0; |
500 | | inputPtrLast.pAppPrivate = NULL; |
501 | | inputPtrLast.nFlags = EB_BUFFERFLAG_EOS; |
502 | | inputPtrLast.pBuffer = NULL; |
503 | | |
504 | | return_error = EbH265EncSendPicture(encoder->m_svtAppData->svtEncoderHandle, &inputPtrLast); |
505 | | if (return_error != EB_ErrorNone) |
506 | | { |
507 | | x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while encoding \n"); |
508 | | numEncoded = -1; |
509 | | goto fail; |
510 | | } |
511 | | } |
512 | | |
513 | | if (eofReached && svtParam->codeEosNal == 0 && !codedNal) |
514 | | { |
515 | | EB_BUFFERHEADERTYPE *outputStreamPtr = 0; |
516 | | return_error = EbH265EncEosNal(encoder->m_svtAppData->svtEncoderHandle, &outputStreamPtr); |
517 | | if (return_error == EB_ErrorMax) |
518 | | { |
519 | | x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while encoding \n"); |
520 | | numEncoded = -1; |
521 | | goto fail; |
522 | | } |
523 | | if (return_error != EB_NoErrorEmptyQueue) |
524 | | { |
525 | | if (outputStreamPtr->pBuffer) |
526 | | { |
527 | | //Copy data from output packet to NAL |
528 | | encoder->m_nalList.m_nal[0].payload = outputStreamPtr->pBuffer; |
529 | | encoder->m_nalList.m_nal[0].sizeBytes = outputStreamPtr->nFilledLen; |
530 | | encoder->m_svtAppData->byteCount += outputStreamPtr->nFilledLen; |
531 | | *pp_nal = &encoder->m_nalList.m_nal[0]; |
532 | | *pi_nal = 1; |
533 | | numEncoded = 0; |
534 | | codedNal = 1; |
535 | | return numEncoded; |
536 | | } |
537 | | |
538 | | // Release the output buffer |
539 | | EbH265ReleaseOutBuffer(&outputStreamPtr); |
540 | | } |
541 | | } |
542 | | else if (eofReached) |
543 | | { |
544 | | *pi_nal = 0; |
545 | | return numEncoded; |
546 | | } |
547 | | |
548 | | //Receive Packet |
549 | | EB_BUFFERHEADERTYPE *outputPtr; |
550 | | return_error = EbH265GetPacket(encoder->m_svtAppData->svtEncoderHandle, &outputPtr, picSendDone); |
551 | | if (return_error == EB_ErrorMax) |
552 | | { |
553 | | x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while encoding \n"); |
554 | | numEncoded = -1; |
555 | | goto fail; |
556 | | } |
557 | | |
558 | | if (return_error != EB_NoErrorEmptyQueue) |
559 | | { |
560 | | if (outputPtr->pBuffer) |
561 | | { |
562 | | //Copy data from output packet to NAL |
563 | | encoder->m_nalList.m_nal[0].payload = outputPtr->pBuffer; |
564 | | encoder->m_nalList.m_nal[0].sizeBytes = outputPtr->nFilledLen; |
565 | | encoder->m_svtAppData->byteCount += outputPtr->nFilledLen; |
566 | | encoder->m_svtAppData->outFrameCount++; |
567 | | *pp_nal = &encoder->m_nalList.m_nal[0]; |
568 | | *pi_nal = 1; |
569 | | numEncoded = 1; |
570 | | } |
571 | | |
572 | | eofReached = outputPtr->nFlags & EB_BUFFERFLAG_EOS; |
573 | | |
574 | | // Release the output buffer |
575 | | EbH265ReleaseOutBuffer(&outputPtr); |
576 | | } |
577 | | else if (pi_nal) |
578 | | *pi_nal = 0; |
579 | | |
580 | | pic_out = NULL; |
581 | | |
582 | | fail: |
583 | | if (numEncoded < 0) |
584 | | encoder->m_aborted = true; |
585 | | |
586 | | return numEncoded; |
587 | | } |
588 | | #endif |
589 | | |
590 | | // While flushing, we cannot return 0 until the entire stream is flushed |
591 | 0 | do |
592 | 0 | { |
593 | 0 | numEncoded = encoder->encode(pic_in, pic_out); |
594 | 0 | } |
595 | 0 | while ((numEncoded == 0 && !pic_in && encoder->m_numDelayedPic && !encoder->m_latestParam->forceFlush) && !encoder->m_externalFlush); |
596 | 0 | if (numEncoded) |
597 | 0 | encoder->m_externalFlush = false; |
598 | | |
599 | | // do not allow reuse of these buffers for more than one picture. The |
600 | | // encoder now owns these analysisData buffers. |
601 | 0 | if (pic_in) |
602 | 0 | { |
603 | 0 | pic_in->analysisData.wt = NULL; |
604 | 0 | pic_in->analysisData.intraData = NULL; |
605 | 0 | pic_in->analysisData.interData = NULL; |
606 | 0 | pic_in->analysisData.distortionData = NULL; |
607 | 0 | } |
608 | |
|
609 | 0 | if (pp_nal && numEncoded > 0 && encoder->m_outputCount >= encoder->m_latestParam->chunkStart) |
610 | 0 | { |
611 | 0 | *pp_nal = &encoder->m_nalList.m_nal[0]; |
612 | 0 | if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal; |
613 | 0 | } |
614 | 0 | else if (pi_nal) |
615 | 0 | *pi_nal = 0; |
616 | |
|
617 | 0 | if (numEncoded && encoder->m_param->csvLogLevel && encoder->m_outputCount >= encoder->m_latestParam->chunkStart) |
618 | 0 | { |
619 | 0 | for (int layer = 0; layer < encoder->m_param->numLayers; layer++) |
620 | 0 | x265_csvlog_frame(encoder->m_param, pic_out + layer); |
621 | 0 | } |
622 | |
|
623 | 0 | if (numEncoded < 0) |
624 | 0 | encoder->m_aborted = true; |
625 | |
|
626 | 0 | if ((!encoder->m_numDelayedPic && !numEncoded) && (encoder->m_param->bEnableEndOfSequence || encoder->m_param->bEnableEndOfBitstream)) |
627 | 0 | { |
628 | 0 | Bitstream bs; |
629 | 0 | encoder->getEndNalUnits(encoder->m_nalList, bs); |
630 | 0 | *pp_nal = &encoder->m_nalList.m_nal[0]; |
631 | 0 | if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal; |
632 | 0 | } |
633 | |
|
634 | 0 | return numEncoded; |
635 | 0 | } |
636 | | |
637 | | void x265_encoder_get_stats(x265_encoder *enc, x265_stats *outputStats, uint32_t statsSizeBytes) |
638 | 0 | { |
639 | 0 | if (enc && outputStats) |
640 | 0 | { |
641 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
642 | 0 | encoder->fetchStats(outputStats, statsSizeBytes); |
643 | 0 | } |
644 | 0 | } |
645 | | #if ENABLE_LIBVMAF |
646 | | void x265_vmaf_encoder_log(x265_encoder* enc, int argc, char **argv, x265_param *param, x265_vmaf_data *vmafdata) |
647 | | { |
648 | | if (enc) |
649 | | { |
650 | | Encoder *encoder = static_cast<Encoder*>(enc); |
651 | | x265_stats stats; |
652 | | stats.aggregateVmafScore = x265_calculate_vmafscore(param, vmafdata); |
653 | | if(vmafdata->reference_file) |
654 | | fclose(vmafdata->reference_file); |
655 | | if(vmafdata->distorted_file) |
656 | | fclose(vmafdata->distorted_file); |
657 | | if(vmafdata) |
658 | | x265_free(vmafdata); |
659 | | encoder->fetchStats(&stats, sizeof(stats)); |
660 | | int padx = encoder->m_sps.conformanceWindow.rightOffset; |
661 | | int pady = encoder->m_sps.conformanceWindow.bottomOffset; |
662 | | x265_csvlog_encode(encoder->m_param, &stats, padx, pady, argc, argv); |
663 | | } |
664 | | } |
665 | | #endif |
666 | | |
667 | | void x265_encoder_log(x265_encoder* enc, int argc, char **argv) |
668 | 0 | { |
669 | 0 | if (enc) |
670 | 0 | { |
671 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
672 | 0 | x265_stats stats[MAX_LAYERS]; |
673 | 0 | int padx = encoder->m_sps.conformanceWindow.rightOffset; |
674 | 0 | int pady = encoder->m_sps.conformanceWindow.bottomOffset; |
675 | 0 | for (int layer = 0; layer < encoder->m_param->numLayers; layer++) |
676 | 0 | { |
677 | 0 | encoder->fetchStats(stats, sizeof(stats[layer]), layer); |
678 | 0 | x265_csvlog_encode(encoder->m_param, &stats[0], padx, pady, argc, argv); |
679 | 0 | } |
680 | 0 | } |
681 | 0 | } |
682 | | |
683 | | #ifdef SVT_HEVC |
684 | | static void svt_print_summary(x265_encoder *enc) |
685 | | { |
686 | | Encoder *encoder = static_cast<Encoder*>(enc); |
687 | | double frameRate = 0, bitrate = 0; |
688 | | EB_H265_ENC_CONFIGURATION *svtParam = (EB_H265_ENC_CONFIGURATION*)encoder->m_svtAppData->svtHevcParams; |
689 | | if (svtParam->frameRateNumerator && svtParam->frameRateDenominator && (svtParam->frameRateNumerator != 0 && svtParam->frameRateDenominator != 0)) |
690 | | { |
691 | | frameRate = ((double)svtParam->frameRateNumerator) / ((double)svtParam->frameRateDenominator); |
692 | | if(encoder->m_svtAppData->outFrameCount) |
693 | | bitrate = ((double)(encoder->m_svtAppData->byteCount << 3) * frameRate / (encoder->m_svtAppData->outFrameCount * 1000)); |
694 | | |
695 | | printf("Total Frames\t\tFrame Rate\t\tByte Count\t\tBitrate\n"); |
696 | | printf("%12d\t\t%4.2f fps\t\t%10.0f\t\t%5.2f kbps\n", (int32_t)encoder->m_svtAppData->outFrameCount, (double)frameRate, (double)encoder->m_svtAppData->byteCount, bitrate); |
697 | | } |
698 | | } |
699 | | #endif |
700 | | |
701 | | void x265_encoder_close(x265_encoder *enc) |
702 | 0 | { |
703 | 0 | if (enc) |
704 | 0 | { |
705 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
706 | |
|
707 | | #ifdef SVT_HEVC |
708 | | if (encoder->m_param->bEnableSvtHevc) |
709 | | { |
710 | | EB_ERRORTYPE return_value; |
711 | | return_value = EbDeinitEncoder(encoder->m_svtAppData->svtEncoderHandle); |
712 | | if (return_value != EB_ErrorNone) |
713 | | { |
714 | | x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while closing the encoder \n"); |
715 | | } |
716 | | return_value = EbDeinitHandle(encoder->m_svtAppData->svtEncoderHandle); |
717 | | if (return_value != EB_ErrorNone) |
718 | | { |
719 | | x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while closing the Handle \n"); |
720 | | } |
721 | | |
722 | | svt_print_summary(enc); |
723 | | EB_H265_ENC_INPUT *inputData = (EB_H265_ENC_INPUT*)encoder->m_svtAppData->inputPictureBuffer->pBuffer; |
724 | | if (inputData->dolbyVisionRpu.payload) X265_FREE(inputData->dolbyVisionRpu.payload); |
725 | | |
726 | | X265_FREE(inputData); |
727 | | X265_FREE(encoder->m_svtAppData->inputPictureBuffer); |
728 | | X265_FREE(encoder->m_svtAppData->svtHevcParams); |
729 | | encoder->stopJobs(); |
730 | | encoder->destroy(); |
731 | | delete encoder; |
732 | | return; |
733 | | } |
734 | | #endif |
735 | |
|
736 | 0 | encoder->stopJobs(); |
737 | 0 | encoder->printSummary(); |
738 | 0 | encoder->destroy(); |
739 | 0 | delete encoder; |
740 | 0 | } |
741 | 0 | } |
742 | | |
743 | | int x265_encoder_intra_refresh(x265_encoder *enc) |
744 | 0 | { |
745 | 0 | if (!enc) |
746 | 0 | return -1; |
747 | | |
748 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
749 | 0 | encoder->m_bQueuedIntraRefresh = 1; |
750 | 0 | return 0; |
751 | 0 | } |
752 | | int x265_encoder_ctu_info(x265_encoder *enc, int poc, x265_ctu_info_t** ctu) |
753 | 0 | { |
754 | 0 | if (!ctu || !enc) |
755 | 0 | return -1; |
756 | 0 | Encoder* encoder = static_cast<Encoder*>(enc); |
757 | 0 | encoder->copyCtuInfo(ctu, poc); |
758 | 0 | return 0; |
759 | 0 | } |
760 | | |
761 | | int x265_get_slicetype_poc_and_scenecut(x265_encoder *enc, int *slicetype, int *poc, int *sceneCut) |
762 | 0 | { |
763 | 0 | if (!enc) |
764 | 0 | return -1; |
765 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
766 | 0 | if (!encoder->copySlicetypePocAndSceneCut(slicetype, poc, sceneCut, 0)) |
767 | 0 | return 0; |
768 | 0 | return -1; |
769 | 0 | } |
770 | | |
771 | | int x265_get_ref_frame_list(x265_encoder *enc, x265_picyuv** l0, x265_picyuv** l1, int sliceType, int poc, int* pocL0, int* pocL1) |
772 | 0 | { |
773 | 0 | if (!enc) |
774 | 0 | return -1; |
775 | | |
776 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
777 | 0 | return encoder->getRefFrameList((PicYuv**)l0, (PicYuv**)l1, sliceType, poc, pocL0, pocL1); |
778 | 0 | } |
779 | | |
780 | | int x265_set_analysis_data(x265_encoder *enc, x265_analysis_data *analysis_data, int poc, uint32_t cuBytes) |
781 | 0 | { |
782 | 0 | if (!enc) |
783 | 0 | return -1; |
784 | | |
785 | 0 | Encoder *encoder = static_cast<Encoder*>(enc); |
786 | 0 | if (!encoder->setAnalysisData(analysis_data, poc, cuBytes)) |
787 | 0 | return 0; |
788 | | |
789 | 0 | return -1; |
790 | 0 | } |
791 | | |
792 | | void x265_alloc_analysis_data(x265_param *param, x265_analysis_data* analysis) |
793 | 0 | { |
794 | 0 | x265_analysis_inter_data *interData = analysis->interData = NULL; |
795 | 0 | x265_analysis_intra_data *intraData = analysis->intraData = NULL; |
796 | 0 | x265_analysis_distortion_data *distortionData = analysis->distortionData = NULL; |
797 | |
|
798 | 0 | bool isVbv = param->rc.vbvMaxBitrate > 0 && param->rc.vbvBufferSize > 0; |
799 | 0 | int numDir = 2; //irrespective of P or B slices set direction as 2 |
800 | 0 | uint32_t numPlanes = param->internalCsp == X265_CSP_I400 ? 1 : 3; |
801 | |
|
802 | 0 | int maxReuseLevel = X265_MAX(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel); |
803 | 0 | int minReuseLevel = (param->analysisSaveReuseLevel && param->analysisLoadReuseLevel) ? |
804 | 0 | X265_MIN(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel) : maxReuseLevel; |
805 | |
|
806 | 0 | bool isMultiPassOpt = param->analysisMultiPassRefine || param->analysisMultiPassDistortion; |
807 | | |
808 | | #if X265_DEPTH < 10 && (LINKED_10BIT || LINKED_12BIT) |
809 | | uint32_t numCUs_sse_t = param->internalBitDepth > 8 ? analysis->numCUsInFrame << 1 : analysis->numCUsInFrame; |
810 | | #elif X265_DEPTH >= 10 && LINKED_8BIT |
811 | | uint32_t numCUs_sse_t = param->internalBitDepth > 8 ? analysis->numCUsInFrame : (analysis->numCUsInFrame + 1U) >> 1; |
812 | | #else |
813 | 0 | uint32_t numCUs_sse_t = analysis->numCUsInFrame; |
814 | 0 | #endif |
815 | 0 | if (isMultiPassOpt || param->ctuDistortionRefine) |
816 | 0 | { |
817 | | //Allocate memory for distortionData pointer |
818 | 0 | CHECKED_MALLOC_ZERO(distortionData, x265_analysis_distortion_data, 1); |
819 | 0 | CHECKED_MALLOC_ZERO(distortionData->ctuDistortion, sse_t, analysis->numPartitions * numCUs_sse_t); |
820 | 0 | if (param->analysisLoad[0] || param->rc.bStatRead) |
821 | 0 | { |
822 | 0 | CHECKED_MALLOC_ZERO(distortionData->scaledDistortion, double, analysis->numCUsInFrame); |
823 | 0 | CHECKED_MALLOC_ZERO(distortionData->offset, double, analysis->numCUsInFrame); |
824 | 0 | CHECKED_MALLOC_ZERO(distortionData->threshold, double, analysis->numCUsInFrame); |
825 | 0 | } |
826 | 0 | analysis->distortionData = distortionData; |
827 | 0 | } |
828 | | |
829 | 0 | if (!isMultiPassOpt && param->bDisableLookahead && isVbv) |
830 | 0 | { |
831 | 0 | CHECKED_MALLOC_ZERO(analysis->lookahead.intraSatdForVbv, uint32_t, analysis->numCuInHeight); |
832 | 0 | CHECKED_MALLOC_ZERO(analysis->lookahead.satdForVbv, uint32_t, analysis->numCuInHeight); |
833 | 0 | CHECKED_MALLOC_ZERO(analysis->lookahead.intraVbvCost, uint32_t, analysis->numCUsInFrame); |
834 | 0 | CHECKED_MALLOC_ZERO(analysis->lookahead.vbvCost, uint32_t, analysis->numCUsInFrame); |
835 | 0 | } |
836 | | |
837 | | //Allocate memory for weightParam pointer |
838 | 0 | if (!isMultiPassOpt && !(param->bAnalysisType == AVC_INFO)) |
839 | 0 | CHECKED_MALLOC_ZERO(analysis->wt, x265_weight_param, numPlanes * numDir); |
840 | | |
841 | | //Allocate memory for intraData pointer |
842 | 0 | if ((maxReuseLevel > 1) || isMultiPassOpt) |
843 | 0 | { |
844 | 0 | CHECKED_MALLOC_ZERO(intraData, x265_analysis_intra_data, 1); |
845 | 0 | CHECKED_MALLOC(intraData->depth, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
846 | 0 | } |
847 | | |
848 | 0 | if (maxReuseLevel > 1) |
849 | 0 | { |
850 | 0 | CHECKED_MALLOC_ZERO(intraData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
851 | 0 | CHECKED_MALLOC_ZERO(intraData->partSizes, char, analysis->numPartitions * analysis->numCUsInFrame); |
852 | 0 | CHECKED_MALLOC_ZERO(intraData->chromaModes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
853 | 0 | if (param->rc.cuTree) |
854 | 0 | CHECKED_MALLOC_ZERO(intraData->cuQPOff, int8_t, analysis->numPartitions * analysis->numCUsInFrame); |
855 | 0 | } |
856 | 0 | analysis->intraData = intraData; |
857 | |
|
858 | 0 | if ((maxReuseLevel > 1) || isMultiPassOpt) |
859 | 0 | { |
860 | | //Allocate memory for interData pointer based on ReuseLevels |
861 | 0 | CHECKED_MALLOC_ZERO(interData, x265_analysis_inter_data, 1); |
862 | 0 | CHECKED_MALLOC(interData->depth, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
863 | 0 | CHECKED_MALLOC_ZERO(interData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
864 | |
|
865 | 0 | if (param->rc.cuTree && !isMultiPassOpt) |
866 | 0 | CHECKED_MALLOC_ZERO(interData->cuQPOff, int8_t, analysis->numPartitions * analysis->numCUsInFrame); |
867 | 0 | CHECKED_MALLOC_ZERO(interData->mvpIdx[0], uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
868 | 0 | CHECKED_MALLOC_ZERO(interData->mvpIdx[1], uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
869 | 0 | CHECKED_MALLOC_ZERO(interData->mv[0], x265_analysis_MV, analysis->numPartitions * analysis->numCUsInFrame); |
870 | 0 | CHECKED_MALLOC_ZERO(interData->mv[1], x265_analysis_MV, analysis->numPartitions * analysis->numCUsInFrame); |
871 | 0 | } |
872 | | |
873 | 0 | if (maxReuseLevel > 4) |
874 | 0 | { |
875 | 0 | CHECKED_MALLOC_ZERO(interData->partSize, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
876 | 0 | CHECKED_MALLOC_ZERO(interData->mergeFlag, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
877 | 0 | } |
878 | 0 | if (maxReuseLevel >= 7) |
879 | 0 | { |
880 | 0 | CHECKED_MALLOC_ZERO(interData->interDir, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
881 | 0 | CHECKED_MALLOC_ZERO(interData->sadCost, int64_t, analysis->numPartitions * analysis->numCUsInFrame); |
882 | 0 | for (int dir = 0; dir < numDir; dir++) |
883 | 0 | { |
884 | 0 | CHECKED_MALLOC_ZERO(interData->refIdx[dir], int8_t, analysis->numPartitions * analysis->numCUsInFrame); |
885 | 0 | CHECKED_MALLOC_ZERO(analysis->modeFlag[dir], uint8_t, analysis->numPartitions * analysis->numCUsInFrame); |
886 | 0 | } |
887 | 0 | } |
888 | 0 | if ((minReuseLevel >= 2) && (minReuseLevel <= 6)) |
889 | 0 | { |
890 | 0 | CHECKED_MALLOC_ZERO(interData->ref, int32_t, analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * numDir); |
891 | 0 | } |
892 | 0 | if (isMultiPassOpt) |
893 | 0 | CHECKED_MALLOC_ZERO(interData->ref, int32_t, 2 * analysis->numPartitions * analysis->numCUsInFrame); |
894 | |
|
895 | 0 | analysis->interData = interData; |
896 | |
|
897 | 0 | return; |
898 | | |
899 | 0 | fail: |
900 | 0 | x265_free_analysis_data(param, analysis); |
901 | 0 | } |
902 | | |
903 | | void x265_free_analysis_data(x265_param *param, x265_analysis_data* analysis) |
904 | 0 | { |
905 | 0 | int maxReuseLevel = X265_MAX(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel); |
906 | 0 | int minReuseLevel = (param->analysisSaveReuseLevel && param->analysisLoadReuseLevel) ? |
907 | 0 | X265_MIN(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel) : maxReuseLevel; |
908 | |
|
909 | 0 | bool isVbv = param->rc.vbvMaxBitrate > 0 && param->rc.vbvBufferSize > 0; |
910 | 0 | bool isMultiPassOpt = param->analysisMultiPassRefine || param->analysisMultiPassDistortion; |
911 | | |
912 | | //Free memory for Lookahead pointers |
913 | 0 | if (!isMultiPassOpt && param->bDisableLookahead && isVbv) |
914 | 0 | { |
915 | 0 | X265_FREE(analysis->lookahead.satdForVbv); |
916 | 0 | X265_FREE(analysis->lookahead.intraSatdForVbv); |
917 | 0 | X265_FREE(analysis->lookahead.vbvCost); |
918 | 0 | X265_FREE(analysis->lookahead.intraVbvCost); |
919 | 0 | } |
920 | | |
921 | | //Free memory for distortionData pointers |
922 | 0 | if (analysis->distortionData) |
923 | 0 | { |
924 | 0 | X265_FREE((analysis->distortionData)->ctuDistortion); |
925 | 0 | if (param->rc.bStatRead || param->analysisLoad[0]) |
926 | 0 | { |
927 | 0 | X265_FREE((analysis->distortionData)->scaledDistortion); |
928 | 0 | X265_FREE((analysis->distortionData)->offset); |
929 | 0 | X265_FREE((analysis->distortionData)->threshold); |
930 | 0 | } |
931 | 0 | X265_FREE(analysis->distortionData); |
932 | 0 | } |
933 | | |
934 | | /* Early exit freeing weights alone if level is 1 (when there is no analysis inter/intra) */ |
935 | 0 | if (!isMultiPassOpt && analysis->wt && !(param->bAnalysisType == AVC_INFO)) |
936 | 0 | X265_FREE_ZERO(analysis->wt); |
937 | | |
938 | | //Free memory for intraData pointers |
939 | 0 | if (analysis->intraData) |
940 | 0 | { |
941 | 0 | X265_FREE((analysis->intraData)->depth); |
942 | 0 | if (!isMultiPassOpt) |
943 | 0 | { |
944 | 0 | X265_FREE((analysis->intraData)->modes); |
945 | 0 | X265_FREE((analysis->intraData)->partSizes); |
946 | 0 | X265_FREE((analysis->intraData)->chromaModes); |
947 | 0 | if (param->rc.cuTree) |
948 | 0 | X265_FREE((analysis->intraData)->cuQPOff); |
949 | 0 | } |
950 | 0 | X265_FREE(analysis->intraData); |
951 | 0 | analysis->intraData = NULL; |
952 | 0 | } |
953 | | |
954 | | //Free interData pointers |
955 | 0 | if (analysis->interData) |
956 | 0 | { |
957 | 0 | X265_FREE((analysis->interData)->depth); |
958 | 0 | X265_FREE((analysis->interData)->modes); |
959 | 0 | if (!isMultiPassOpt && param->rc.cuTree) |
960 | 0 | X265_FREE((analysis->interData)->cuQPOff); |
961 | 0 | X265_FREE((analysis->interData)->mvpIdx[0]); |
962 | 0 | X265_FREE((analysis->interData)->mvpIdx[1]); |
963 | 0 | X265_FREE((analysis->interData)->mv[0]); |
964 | 0 | X265_FREE((analysis->interData)->mv[1]); |
965 | |
|
966 | 0 | if (maxReuseLevel > 4) |
967 | 0 | { |
968 | 0 | X265_FREE((analysis->interData)->mergeFlag); |
969 | 0 | X265_FREE((analysis->interData)->partSize); |
970 | 0 | } |
971 | 0 | if (maxReuseLevel >= 7) |
972 | 0 | { |
973 | 0 | int numDir = 2; |
974 | 0 | X265_FREE((analysis->interData)->interDir); |
975 | 0 | X265_FREE((analysis->interData)->sadCost); |
976 | 0 | for (int dir = 0; dir < numDir; dir++) |
977 | 0 | { |
978 | 0 | X265_FREE((analysis->interData)->refIdx[dir]); |
979 | 0 | if (analysis->modeFlag[dir] != NULL) |
980 | 0 | { |
981 | 0 | X265_FREE(analysis->modeFlag[dir]); |
982 | 0 | analysis->modeFlag[dir] = NULL; |
983 | 0 | } |
984 | 0 | } |
985 | 0 | } |
986 | 0 | if (((minReuseLevel >= 2) && (minReuseLevel <= 6)) || isMultiPassOpt) |
987 | 0 | X265_FREE((analysis->interData)->ref); |
988 | 0 | X265_FREE(analysis->interData); |
989 | 0 | analysis->interData = NULL; |
990 | 0 | } |
991 | 0 | } |
992 | | |
993 | | void x265_cleanup(void) |
994 | 0 | { |
995 | 0 | } |
996 | | |
997 | | x265_picture *x265_picture_alloc() |
998 | 0 | { |
999 | 0 | return (x265_picture*)x265_malloc(sizeof(x265_picture)); |
1000 | 0 | } |
1001 | | |
1002 | | void x265_picture_init(x265_param *param, x265_picture *pic) |
1003 | 0 | { |
1004 | 0 | memset(pic, 0, sizeof(x265_picture)); |
1005 | |
|
1006 | 0 | pic->bitDepth = param->internalBitDepth; |
1007 | 0 | pic->colorSpace = param->internalCsp; |
1008 | 0 | pic->forceqp = X265_QP_AUTO; |
1009 | 0 | pic->quantOffsets = NULL; |
1010 | 0 | pic->userSEI.payloads = NULL; |
1011 | 0 | pic->userSEI.numPayloads = 0; |
1012 | 0 | pic->rpu.payloadSize = 0; |
1013 | 0 | pic->rpu.payload = NULL; |
1014 | 0 | pic->picStruct = 0; |
1015 | 0 | pic->vbvEndFlag = 0; |
1016 | |
|
1017 | 0 | if ((strlen(param->analysisSave) || strlen(param->analysisLoad)) || (param->bAnalysisType == AVC_INFO)) |
1018 | 0 | { |
1019 | 0 | uint32_t widthInCU = (param->sourceWidth + param->maxCUSize - 1) >> param->maxLog2CUSize; |
1020 | 0 | uint32_t heightInCU = (param->sourceHeight + param->maxCUSize - 1) >> param->maxLog2CUSize; |
1021 | |
|
1022 | 0 | uint32_t numCUsInFrame = widthInCU * heightInCU; |
1023 | 0 | pic->analysisData.numCUsInFrame = numCUsInFrame; |
1024 | 0 | pic->analysisData.numPartitions = param->num4x4Partitions; |
1025 | 0 | } |
1026 | 0 | } |
1027 | | |
1028 | | void x265_picture_free(x265_picture *p) |
1029 | 0 | { |
1030 | 0 | return x265_free(p); |
1031 | 0 | } |
1032 | | |
1033 | | x265_zone *x265_zone_alloc(int zoneCount, int isZoneFile) |
1034 | 0 | { |
1035 | 0 | x265_zone* zone = (x265_zone*)x265_malloc(sizeof(x265_zone) * zoneCount); |
1036 | 0 | if (isZoneFile) { |
1037 | 0 | for (int i = 0; i < zoneCount; i++) |
1038 | 0 | zone[i].zoneParam = (x265_param*)x265_malloc(sizeof(x265_param)); |
1039 | 0 | } |
1040 | 0 | return zone; |
1041 | 0 | } |
1042 | | |
1043 | | void x265_zone_free(x265_param *param) |
1044 | 0 | { |
1045 | 0 | if (param && param->rc.zones && (param->rc.zoneCount || param->rc.zonefileCount)) |
1046 | 0 | { |
1047 | 0 | for (int i = 0; i < param->rc.zonefileCount; i++) |
1048 | 0 | x265_free(param->rc.zones[i].zoneParam); |
1049 | 0 | param->rc.zonefileCount = 0; |
1050 | 0 | param->rc.zoneCount = 0; |
1051 | 0 | x265_free(param->rc.zones); |
1052 | 0 | } |
1053 | 0 | } |
1054 | | |
1055 | | static const x265_api libapi = |
1056 | | { |
1057 | | X265_MAJOR_VERSION, |
1058 | | X265_BUILD, |
1059 | | sizeof(x265_param), |
1060 | | sizeof(x265_picture), |
1061 | | sizeof(x265_analysis_data), |
1062 | | sizeof(x265_zone), |
1063 | | sizeof(x265_stats), |
1064 | | |
1065 | | PFX(max_bit_depth), |
1066 | | PFX(version_str), |
1067 | | PFX(build_info_str), |
1068 | | |
1069 | | &PARAM_NS::x265_param_alloc, |
1070 | | &PARAM_NS::x265_param_free, |
1071 | | &PARAM_NS::x265_param_default, |
1072 | | &PARAM_NS::x265_param_parse, |
1073 | | &PARAM_NS::x265_scenecut_aware_qp_param_parse, |
1074 | | &PARAM_NS::x265_param_apply_profile, |
1075 | | &PARAM_NS::x265_param_default_preset, |
1076 | | &x265_picture_alloc, |
1077 | | &x265_picture_free, |
1078 | | &x265_picture_init, |
1079 | | &x265_encoder_open, |
1080 | | &x265_encoder_parameters, |
1081 | | &x265_encoder_reconfig, |
1082 | | &x265_encoder_reconfig_zone, |
1083 | | &x265_encoder_headers, |
1084 | | &x265_configure_vbv_end, |
1085 | | &x265_encoder_encode, |
1086 | | &x265_encoder_get_stats, |
1087 | | &x265_encoder_log, |
1088 | | &x265_encoder_close, |
1089 | | &x265_cleanup, |
1090 | | |
1091 | | sizeof(x265_frame_stats), |
1092 | | &x265_encoder_intra_refresh, |
1093 | | &x265_encoder_ctu_info, |
1094 | | &x265_get_slicetype_poc_and_scenecut, |
1095 | | &x265_get_ref_frame_list, |
1096 | | &x265_csvlog_open, |
1097 | | &x265_csvlog_frame, |
1098 | | &x265_csvlog_encode, |
1099 | | &x265_dither_image, |
1100 | | &x265_set_analysis_data, |
1101 | | #if ENABLE_LIBVMAF |
1102 | | &x265_calculate_vmafscore, |
1103 | | &x265_calculate_vmaf_framelevelscore, |
1104 | | &x265_vmaf_encoder_log, |
1105 | | #endif |
1106 | | &PARAM_NS::x265_zone_param_parse |
1107 | | }; |
1108 | | |
1109 | | typedef const x265_api* (*api_get_func)(int bitDepth); |
1110 | | typedef const x265_api* (*api_query_func)(int bitDepth, int apiVersion, int* err); |
1111 | | |
1112 | 0 | #define xstr(s) str(s) |
1113 | 0 | #define str(s) #s |
1114 | | |
1115 | | #if _WIN32 |
1116 | | #define ext ".dll" |
1117 | | #elif MACOS |
1118 | | #include <dlfcn.h> |
1119 | | #define ext ".dylib" |
1120 | | #else |
1121 | | #include <dlfcn.h> |
1122 | 0 | #define ext ".so" |
1123 | | #endif |
1124 | | #if defined(__GNUC__) && __GNUC__ >= 8 |
1125 | | #pragma GCC diagnostic ignored "-Wcast-function-type" |
1126 | | #endif |
1127 | | |
1128 | | static int g_recursion /* = 0 */; |
1129 | | const x265_api* x265_api_get(int bitDepth) |
1130 | 0 | { |
1131 | 0 | if (bitDepth && bitDepth != X265_DEPTH) |
1132 | 0 | { |
1133 | | #if LINKED_8BIT |
1134 | | if (bitDepth == 8) return x265_8bit::x265_api_get(0); |
1135 | | #endif |
1136 | | #if LINKED_10BIT |
1137 | | if (bitDepth == 10) return x265_10bit::x265_api_get(0); |
1138 | | #endif |
1139 | | #if LINKED_12BIT |
1140 | | if (bitDepth == 12) return x265_12bit::x265_api_get(0); |
1141 | | #endif |
1142 | |
|
1143 | 0 | const char* libname = NULL; |
1144 | 0 | const char* method = "x265_api_get_" xstr(X265_BUILD); |
1145 | 0 | const char* multilibname = "libx265" ext; |
1146 | |
|
1147 | 0 | if (bitDepth == 12) |
1148 | 0 | libname = "libx265_main12" ext; |
1149 | 0 | else if (bitDepth == 10) |
1150 | 0 | libname = "libx265_main10" ext; |
1151 | 0 | else if (bitDepth == 8) |
1152 | 0 | libname = "libx265_main" ext; |
1153 | 0 | else |
1154 | 0 | return NULL; |
1155 | | |
1156 | 0 | const x265_api* api = NULL; |
1157 | 0 | int reqDepth = 0; |
1158 | |
|
1159 | 0 | if (g_recursion > 1) |
1160 | 0 | return NULL; |
1161 | 0 | else |
1162 | 0 | g_recursion++; |
1163 | | |
1164 | | #if _WIN32 |
1165 | | HMODULE h = LoadLibraryA(libname); |
1166 | | if (!h) |
1167 | | { |
1168 | | h = LoadLibraryA(multilibname); |
1169 | | reqDepth = bitDepth; |
1170 | | } |
1171 | | if (h) |
1172 | | { |
1173 | | api_get_func get = (api_get_func)GetProcAddress(h, method); |
1174 | | if (get) |
1175 | | api = get(reqDepth); |
1176 | | } |
1177 | | #else |
1178 | 0 | void* h = dlopen(libname, RTLD_LAZY | RTLD_LOCAL); |
1179 | 0 | if (!h) |
1180 | 0 | { |
1181 | 0 | h = dlopen(multilibname, RTLD_LAZY | RTLD_LOCAL); |
1182 | 0 | reqDepth = bitDepth; |
1183 | 0 | } |
1184 | 0 | if (h) |
1185 | 0 | { |
1186 | 0 | api_get_func get = (api_get_func)dlsym(h, method); |
1187 | 0 | if (get) |
1188 | 0 | api = get(reqDepth); |
1189 | 0 | } |
1190 | 0 | #endif |
1191 | |
|
1192 | 0 | g_recursion--; |
1193 | |
|
1194 | 0 | if (api && bitDepth != api->bit_depth) |
1195 | 0 | { |
1196 | 0 | x265_log(NULL, X265_LOG_WARNING, "%s does not support requested bitDepth %d\n", libname, bitDepth); |
1197 | 0 | return NULL; |
1198 | 0 | } |
1199 | | |
1200 | 0 | return api; |
1201 | 0 | } |
1202 | | |
1203 | 0 | return &libapi; |
1204 | 0 | } |
1205 | | |
1206 | | const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err) |
1207 | 0 | { |
1208 | 0 | if (apiVersion < 51) |
1209 | 0 | { |
1210 | | /* builds before 1.6 had re-ordered public structs */ |
1211 | 0 | if (err) *err = X265_API_QUERY_ERR_VER_REFUSED; |
1212 | 0 | return NULL; |
1213 | 0 | } |
1214 | | |
1215 | 0 | if (err) *err = X265_API_QUERY_ERR_NONE; |
1216 | |
|
1217 | 0 | if (bitDepth && bitDepth != X265_DEPTH) |
1218 | 0 | { |
1219 | | #if LINKED_8BIT |
1220 | | if (bitDepth == 8) return x265_8bit::x265_api_query(0, apiVersion, err); |
1221 | | #endif |
1222 | | #if LINKED_10BIT |
1223 | | if (bitDepth == 10) return x265_10bit::x265_api_query(0, apiVersion, err); |
1224 | | #endif |
1225 | | #if LINKED_12BIT |
1226 | | if (bitDepth == 12) return x265_12bit::x265_api_query(0, apiVersion, err); |
1227 | | #endif |
1228 | |
|
1229 | 0 | const char* libname = NULL; |
1230 | 0 | const char* method = "x265_api_query"; |
1231 | 0 | const char* multilibname = "libx265" ext; |
1232 | |
|
1233 | 0 | if (bitDepth == 12) |
1234 | 0 | libname = "libx265_main12" ext; |
1235 | 0 | else if (bitDepth == 10) |
1236 | 0 | libname = "libx265_main10" ext; |
1237 | 0 | else if (bitDepth == 8) |
1238 | 0 | libname = "libx265_main" ext; |
1239 | 0 | else |
1240 | 0 | { |
1241 | 0 | if (err) *err = X265_API_QUERY_ERR_LIB_NOT_FOUND; |
1242 | 0 | return NULL; |
1243 | 0 | } |
1244 | | |
1245 | 0 | const x265_api* api = NULL; |
1246 | 0 | int reqDepth = 0; |
1247 | 0 | int e = X265_API_QUERY_ERR_LIB_NOT_FOUND; |
1248 | |
|
1249 | 0 | if (g_recursion > 1) |
1250 | 0 | { |
1251 | 0 | if (err) *err = X265_API_QUERY_ERR_LIB_NOT_FOUND; |
1252 | 0 | return NULL; |
1253 | 0 | } |
1254 | 0 | else |
1255 | 0 | g_recursion++; |
1256 | | |
1257 | | #if _WIN32 |
1258 | | HMODULE h = LoadLibraryA(libname); |
1259 | | if (!h) |
1260 | | { |
1261 | | h = LoadLibraryA(multilibname); |
1262 | | reqDepth = bitDepth; |
1263 | | } |
1264 | | if (h) |
1265 | | { |
1266 | | e = X265_API_QUERY_ERR_FUNC_NOT_FOUND; |
1267 | | api_query_func query = (api_query_func)GetProcAddress(h, method); |
1268 | | if (query) |
1269 | | api = query(reqDepth, apiVersion, err); |
1270 | | } |
1271 | | #else |
1272 | 0 | void* h = dlopen(libname, RTLD_LAZY | RTLD_LOCAL); |
1273 | 0 | if (!h) |
1274 | 0 | { |
1275 | 0 | h = dlopen(multilibname, RTLD_LAZY | RTLD_LOCAL); |
1276 | 0 | reqDepth = bitDepth; |
1277 | 0 | } |
1278 | 0 | if (h) |
1279 | 0 | { |
1280 | 0 | e = X265_API_QUERY_ERR_FUNC_NOT_FOUND; |
1281 | 0 | api_query_func query = (api_query_func)dlsym(h, method); |
1282 | 0 | if (query) |
1283 | 0 | api = query(reqDepth, apiVersion, err); |
1284 | 0 | } |
1285 | 0 | #endif |
1286 | |
|
1287 | 0 | g_recursion--; |
1288 | |
|
1289 | 0 | if (api && bitDepth != api->bit_depth) |
1290 | 0 | { |
1291 | 0 | x265_log(NULL, X265_LOG_WARNING, "%s does not support requested bitDepth %d\n", libname, bitDepth); |
1292 | 0 | if (err) *err = X265_API_QUERY_ERR_WRONG_BITDEPTH; |
1293 | 0 | return NULL; |
1294 | 0 | } |
1295 | | |
1296 | 0 | if (err) *err = api ? X265_API_QUERY_ERR_NONE : e; |
1297 | 0 | return api; |
1298 | 0 | } |
1299 | | |
1300 | 0 | return &libapi; |
1301 | 0 | } |
1302 | | |
1303 | | FILE* x265_csvlog_open(const x265_param* param) |
1304 | 0 | { |
1305 | 0 | FILE *csvfp = x265_fopen(param->csvfn, "r"); |
1306 | 0 | if (csvfp) |
1307 | 0 | { |
1308 | | /* file already exists, re-open for append */ |
1309 | 0 | fclose(csvfp); |
1310 | 0 | return x265_fopen(param->csvfn, "ab"); |
1311 | 0 | } |
1312 | 0 | else |
1313 | 0 | { |
1314 | | /* new CSV file, write header */ |
1315 | 0 | csvfp = x265_fopen(param->csvfn, "wb"); |
1316 | 0 | if (csvfp) |
1317 | 0 | { |
1318 | 0 | if (param->csvLogLevel) |
1319 | 0 | { |
1320 | 0 | fprintf(csvfp, "Layer , Encode Order, Type, POC, QP, Bits, Scenecut, "); |
1321 | 0 | if (!!param->bEnableTemporalSubLayers) |
1322 | 0 | fprintf(csvfp, "Temporal Sub Layer ID, "); |
1323 | 0 | if (param->csvLogLevel >= 2) |
1324 | 0 | fprintf(csvfp, "I/P cost ratio, "); |
1325 | 0 | if (param->rc.rateControlMode == X265_RC_CRF) |
1326 | 0 | fprintf(csvfp, "RateFactor, "); |
1327 | 0 | if (param->rc.vbvBufferSize) |
1328 | 0 | fprintf(csvfp, "BufferFill, BufferFillFinal, "); |
1329 | 0 | if (param->rc.vbvBufferSize && param->csvLogLevel >= 2) |
1330 | 0 | fprintf(csvfp, "UnclippedBufferFillFinal, "); |
1331 | 0 | if (param->bEnablePsnr) |
1332 | 0 | fprintf(csvfp, "Y PSNR, U PSNR, V PSNR, YUV PSNR, "); |
1333 | 0 | if (param->bEnableSsim) |
1334 | 0 | fprintf(csvfp, "SSIM, SSIM(dB), "); |
1335 | 0 | fprintf(csvfp, "Latency, "); |
1336 | 0 | fprintf(csvfp, "List 0, List 1"); |
1337 | 0 | uint32_t size = param->maxCUSize; |
1338 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1339 | 0 | { |
1340 | 0 | fprintf(csvfp, ", Intra %dx%d DC, Intra %dx%d Planar, Intra %dx%d Ang", size, size, size, size, size, size); |
1341 | 0 | size /= 2; |
1342 | 0 | } |
1343 | 0 | fprintf(csvfp, ", 4x4"); |
1344 | 0 | size = param->maxCUSize; |
1345 | 0 | if (param->bEnableRectInter) |
1346 | 0 | { |
1347 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1348 | 0 | { |
1349 | 0 | fprintf(csvfp, ", Inter %dx%d, Inter %dx%d (Rect)", size, size, size, size); |
1350 | 0 | if (param->bEnableAMP) |
1351 | 0 | fprintf(csvfp, ", Inter %dx%d (Amp)", size, size); |
1352 | 0 | size /= 2; |
1353 | 0 | } |
1354 | 0 | } |
1355 | 0 | else |
1356 | 0 | { |
1357 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1358 | 0 | { |
1359 | 0 | fprintf(csvfp, ", Inter %dx%d", size, size); |
1360 | 0 | size /= 2; |
1361 | 0 | } |
1362 | 0 | } |
1363 | 0 | size = param->maxCUSize; |
1364 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1365 | 0 | { |
1366 | 0 | fprintf(csvfp, ", Skip %dx%d", size, size); |
1367 | 0 | size /= 2; |
1368 | 0 | } |
1369 | 0 | size = param->maxCUSize; |
1370 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1371 | 0 | { |
1372 | 0 | fprintf(csvfp, ", Merge %dx%d", size, size); |
1373 | 0 | size /= 2; |
1374 | 0 | } |
1375 | |
|
1376 | 0 | if (param->csvLogLevel >= 2) |
1377 | 0 | { |
1378 | 0 | fprintf(csvfp, ", Avg Luma Distortion, Avg Chroma Distortion, Avg psyEnergy, Avg Residual Energy," |
1379 | 0 | " Min Luma Level, Max Luma Level, Avg Luma Level"); |
1380 | |
|
1381 | 0 | if (param->internalCsp != X265_CSP_I400) |
1382 | 0 | fprintf(csvfp, ", Min Cb Level, Max Cb Level, Avg Cb Level, Min Cr Level, Max Cr Level, Avg Cr Level"); |
1383 | | |
1384 | | /* PU statistics */ |
1385 | 0 | size = param->maxCUSize; |
1386 | 0 | for (uint32_t i = 0; i< param->maxLog2CUSize - (uint32_t)g_log2Size[param->minCUSize] + 1; i++) |
1387 | 0 | { |
1388 | 0 | fprintf(csvfp, ", Intra %dx%d", size, size); |
1389 | 0 | fprintf(csvfp, ", Skip %dx%d", size, size); |
1390 | 0 | fprintf(csvfp, ", AMP %d", size); |
1391 | 0 | fprintf(csvfp, ", Inter %dx%d", size, size); |
1392 | 0 | fprintf(csvfp, ", Merge %dx%d", size, size); |
1393 | 0 | fprintf(csvfp, ", Inter %dx%d", size, size / 2); |
1394 | 0 | fprintf(csvfp, ", Merge %dx%d", size, size / 2); |
1395 | 0 | fprintf(csvfp, ", Inter %dx%d", size / 2, size); |
1396 | 0 | fprintf(csvfp, ", Merge %dx%d", size / 2, size); |
1397 | 0 | size /= 2; |
1398 | 0 | } |
1399 | |
|
1400 | 0 | if ((uint32_t)g_log2Size[param->minCUSize] == 3) |
1401 | 0 | fprintf(csvfp, ", 4x4"); |
1402 | | |
1403 | | /* detailed performance statistics */ |
1404 | 0 | fprintf(csvfp, ", DecideWait (ms), Row0Wait (ms), Wall time (ms), Ref Wait Wall (ms), Total CTU time (ms)," |
1405 | 0 | "Stall Time (ms), Total frame time (ms), Avg WPP, Row Blocks"); |
1406 | | #if ENABLE_LIBVMAF |
1407 | | fprintf(csvfp, ", VMAF Frame Score"); |
1408 | | #endif |
1409 | 0 | if (param->bConfigRCFrame) |
1410 | 0 | { |
1411 | 0 | if (param->rc.rateControlMode == X265_RC_ABR) |
1412 | 0 | fprintf(csvfp, ", Target bitrate"); |
1413 | 0 | else if (param->rc.rateControlMode == X265_RC_CRF) |
1414 | 0 | fprintf(csvfp, ", Target CRF"); |
1415 | 0 | else if (param->rc.rateControlMode == X265_RC_CQP) |
1416 | 0 | fprintf(csvfp, ", Target QP"); |
1417 | 0 | } |
1418 | 0 | } |
1419 | 0 | fprintf(csvfp, "\n"); |
1420 | 0 | } |
1421 | 0 | else |
1422 | 0 | { |
1423 | 0 | fputs(summaryCSVHeader, csvfp); |
1424 | 0 | if (param->csvLogLevel >= 2 || param->maxCLL || param->maxFALL) |
1425 | 0 | fputs("MaxCLL, MaxFALL,", csvfp); |
1426 | | #if ENABLE_LIBVMAF |
1427 | | fputs(" Aggregate VMAF Score,", csvfp); |
1428 | | #endif |
1429 | 0 | fputs(" Version\n", csvfp); |
1430 | 0 | } |
1431 | 0 | } |
1432 | 0 | return csvfp; |
1433 | 0 | } |
1434 | 0 | } |
1435 | | |
1436 | | // per frame CSV logging |
1437 | | void x265_csvlog_frame(const x265_param* param, const x265_picture* pic) |
1438 | 0 | { |
1439 | 0 | if (!param->csvfpt) |
1440 | 0 | return; |
1441 | | |
1442 | 0 | const x265_frame_stats* frameStats = &pic->frameData; |
1443 | 0 | fprintf(param->csvfpt, "%d, %d, %c-SLICE, %4d, %2.2lf, %10d, %d,", pic->layerID, frameStats->encoderOrder, frameStats->sliceType, frameStats->poc, |
1444 | 0 | frameStats->qp, (int)frameStats->bits, frameStats->bScenecut); |
1445 | 0 | if (!!param->bEnableTemporalSubLayers) |
1446 | 0 | fprintf(param->csvfpt, "%d,", frameStats->tLayer); |
1447 | 0 | if (param->csvLogLevel >= 2) |
1448 | 0 | fprintf(param->csvfpt, "%.2f,", frameStats->ipCostRatio); |
1449 | 0 | if (param->rc.rateControlMode == X265_RC_CRF) |
1450 | 0 | fprintf(param->csvfpt, "%.3lf,", frameStats->rateFactor); |
1451 | 0 | if (param->rc.vbvBufferSize) |
1452 | 0 | fprintf(param->csvfpt, "%.3lf, %.3lf,", frameStats->bufferFill, frameStats->bufferFillFinal); |
1453 | 0 | if (param->rc.vbvBufferSize && param->csvLogLevel >= 2) |
1454 | 0 | fprintf(param->csvfpt, "%.3lf,", frameStats->unclippedBufferFillFinal); |
1455 | 0 | if (param->bEnablePsnr) |
1456 | 0 | fprintf(param->csvfpt, "%.3lf, %.3lf, %.3lf, %.3lf,", frameStats->psnrY, frameStats->psnrU, frameStats->psnrV, frameStats->psnr); |
1457 | 0 | if (param->bEnableSsim) |
1458 | 0 | fprintf(param->csvfpt, " %.6f, %6.3f,", frameStats->ssim, x265_ssim2dB(frameStats->ssim)); |
1459 | 0 | fprintf(param->csvfpt, "%d, ", frameStats->frameLatency); |
1460 | 0 | if (frameStats->sliceType == 'I' || frameStats->sliceType == 'i') |
1461 | 0 | fputs(" -, -,", param->csvfpt); |
1462 | 0 | else |
1463 | 0 | { |
1464 | 0 | int i = 0; |
1465 | 0 | while (frameStats->list0POC[i] != -1) |
1466 | 0 | fprintf(param->csvfpt, "%d ", frameStats->list0POC[i++]); |
1467 | 0 | fprintf(param->csvfpt, ","); |
1468 | 0 | if (frameStats->sliceType != 'P') |
1469 | 0 | { |
1470 | 0 | i = 0; |
1471 | 0 | while (frameStats->list1POC[i] != -1) |
1472 | 0 | fprintf(param->csvfpt, "%d ", frameStats->list1POC[i++]); |
1473 | 0 | fprintf(param->csvfpt, ","); |
1474 | 0 | } |
1475 | 0 | else |
1476 | 0 | fputs(" -,", param->csvfpt); |
1477 | 0 | } |
1478 | |
|
1479 | 0 | if (param->csvLogLevel) |
1480 | 0 | { |
1481 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1482 | 0 | fprintf(param->csvfpt, "%5.2lf%%, %5.2lf%%, %5.2lf%%,", frameStats->cuStats.percentIntraDistribution[depth][0], |
1483 | 0 | frameStats->cuStats.percentIntraDistribution[depth][1], |
1484 | 0 | frameStats->cuStats.percentIntraDistribution[depth][2]); |
1485 | 0 | fprintf(param->csvfpt, "%5.2lf%%", frameStats->cuStats.percentIntraNxN); |
1486 | 0 | if (param->bEnableRectInter) |
1487 | 0 | { |
1488 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1489 | 0 | { |
1490 | 0 | fprintf(param->csvfpt, ", %5.2lf%%, %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][0], |
1491 | 0 | frameStats->cuStats.percentInterDistribution[depth][1]); |
1492 | 0 | if (param->bEnableAMP) |
1493 | 0 | fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][2]); |
1494 | 0 | } |
1495 | 0 | } |
1496 | 0 | else |
1497 | 0 | { |
1498 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1499 | 0 | fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][0]); |
1500 | 0 | } |
1501 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1502 | 0 | fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentSkipCu[depth]); |
1503 | 0 | for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++) |
1504 | 0 | fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentMergeCu[depth]); |
1505 | 0 | } |
1506 | |
|
1507 | 0 | if (param->csvLogLevel >= 2) |
1508 | 0 | { |
1509 | 0 | fprintf(param->csvfpt, ", %.2lf, %.2lf, %.2lf, %.2lf ", frameStats->avgLumaDistortion, |
1510 | 0 | frameStats->avgChromaDistortion, |
1511 | 0 | frameStats->avgPsyEnergy, |
1512 | 0 | frameStats->avgResEnergy); |
1513 | |
|
1514 | 0 | fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minLumaLevel, frameStats->maxLumaLevel, frameStats->avgLumaLevel); |
1515 | |
|
1516 | 0 | if (param->internalCsp != X265_CSP_I400) |
1517 | 0 | { |
1518 | 0 | fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minChromaULevel, frameStats->maxChromaULevel, frameStats->avgChromaULevel); |
1519 | 0 | fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minChromaVLevel, frameStats->maxChromaVLevel, frameStats->avgChromaVLevel); |
1520 | 0 | } |
1521 | |
|
1522 | 0 | for (uint32_t i = 0; i < param->maxLog2CUSize - (uint32_t)g_log2Size[param->minCUSize] + 1; i++) |
1523 | 0 | { |
1524 | 0 | fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentIntraPu[i]); |
1525 | 0 | fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentSkipPu[i]); |
1526 | 0 | fprintf(param->csvfpt, ",%.2lf%%", frameStats->puStats.percentAmpPu[i]); |
1527 | 0 | for (uint32_t j = 0; j < 3; j++) |
1528 | 0 | { |
1529 | 0 | fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentInterPu[i][j]); |
1530 | 0 | fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentMergePu[i][j]); |
1531 | 0 | } |
1532 | 0 | } |
1533 | 0 | if ((uint32_t)g_log2Size[param->minCUSize] == 3) |
1534 | 0 | fprintf(param->csvfpt, ",%.2lf%%", frameStats->puStats.percentNxN); |
1535 | |
|
1536 | 0 | fprintf(param->csvfpt, ", %.1lf, %.1lf, %.1lf, %.1lf, %.1lf, %.1lf, %.1lf,", frameStats->decideWaitTime, frameStats->row0WaitTime, |
1537 | 0 | frameStats->wallTime, frameStats->refWaitWallTime, |
1538 | 0 | frameStats->totalCTUTime, frameStats->stallTime, |
1539 | 0 | frameStats->totalFrameTime); |
1540 | |
|
1541 | 0 | fprintf(param->csvfpt, " %.3lf, %d", frameStats->avgWPP, frameStats->countRowBlocks); |
1542 | | #if ENABLE_LIBVMAF |
1543 | | fprintf(param->csvfpt, ", %lf", frameStats->vmafFrameScore); |
1544 | | #endif |
1545 | 0 | if (param->bConfigRCFrame) |
1546 | 0 | { |
1547 | 0 | if(param->rc.rateControlMode == X265_RC_ABR) |
1548 | 0 | fprintf(param->csvfpt, ", %ld", (long)frameStats->currTrBitrate); |
1549 | 0 | else if (param->rc.rateControlMode == X265_RC_CRF) |
1550 | 0 | fprintf(param->csvfpt, ", %f", frameStats->currTrCRF); |
1551 | 0 | else if (param->rc.rateControlMode == X265_RC_CQP) |
1552 | 0 | fprintf(param->csvfpt, ", %d", frameStats->currTrQP); |
1553 | 0 | } |
1554 | 0 | } |
1555 | 0 | fprintf(param->csvfpt, "\n"); |
1556 | 0 | fflush(stderr); |
1557 | 0 | } |
1558 | | |
1559 | | void x265_csvlog_encode(const x265_param *p, const x265_stats *stats, int padx, int pady, int argc, char** argv) |
1560 | 0 | { |
1561 | 0 | if (p && p->csvfpt) |
1562 | 0 | { |
1563 | 0 | const x265_api * api = x265_api_get(0); |
1564 | |
|
1565 | 0 | if (p->csvLogLevel) |
1566 | 0 | { |
1567 | | // adding summary to a per-frame csv log file, so it needs a summary header |
1568 | 0 | fprintf(p->csvfpt, "\nSummary\n"); |
1569 | 0 | fputs(summaryCSVHeader, p->csvfpt); |
1570 | 0 | if (p->csvLogLevel >= 2 || p->maxCLL || p->maxFALL) |
1571 | 0 | fputs("MaxCLL, MaxFALL,", p->csvfpt); |
1572 | | #if ENABLE_LIBVMAF |
1573 | | fputs(" Aggregate VMAF score,", p->csvfpt); |
1574 | | #endif |
1575 | 0 | fputs(" Version\n",p->csvfpt); |
1576 | |
|
1577 | 0 | } |
1578 | | // CLI arguments or other |
1579 | 0 | if (argc) |
1580 | 0 | { |
1581 | 0 | fputc('"', p->csvfpt); |
1582 | 0 | for (int i = 1; i < argc; i++) |
1583 | 0 | { |
1584 | 0 | fputc(' ', p->csvfpt); |
1585 | 0 | fputs(argv[i], p->csvfpt); |
1586 | 0 | } |
1587 | 0 | fputc('"', p->csvfpt); |
1588 | 0 | } |
1589 | 0 | else |
1590 | 0 | { |
1591 | 0 | char *opts = x265_param2string((x265_param*)p, padx, pady); |
1592 | 0 | if (opts) |
1593 | 0 | { |
1594 | 0 | fputc('"', p->csvfpt); |
1595 | 0 | fputs(opts, p->csvfpt); |
1596 | 0 | fputc('"', p->csvfpt); |
1597 | 0 | X265_FREE(opts); |
1598 | 0 | } |
1599 | 0 | } |
1600 | | |
1601 | | // current date and time |
1602 | 0 | time_t now; |
1603 | 0 | struct tm* timeinfo; |
1604 | 0 | time(&now); |
1605 | 0 | timeinfo = localtime(&now); |
1606 | 0 | char buffer[200]; |
1607 | 0 | strftime(buffer, 128, "%c", timeinfo); |
1608 | 0 | fprintf(p->csvfpt, ", %s, ", buffer); |
1609 | | // elapsed time, fps, bitrate |
1610 | 0 | fprintf(p->csvfpt, "%.2f, %.2f, %.2f,", |
1611 | 0 | stats->elapsedEncodeTime, stats->encodedPictureCount / stats->elapsedEncodeTime, stats->bitrate); |
1612 | |
|
1613 | 0 | if (p->bEnablePsnr) |
1614 | 0 | fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf, %.3lf,", |
1615 | 0 | stats->globalPsnrY / stats->encodedPictureCount, stats->globalPsnrU / stats->encodedPictureCount, |
1616 | 0 | stats->globalPsnrV / stats->encodedPictureCount, stats->globalPsnr); |
1617 | 0 | else |
1618 | 0 | fprintf(p->csvfpt, " -, -, -, -,"); |
1619 | 0 | if (p->bEnableSsim) |
1620 | 0 | fprintf(p->csvfpt, " %.6f, %6.3f,", stats->globalSsim, x265_ssim2dB(stats->globalSsim)); |
1621 | 0 | else |
1622 | 0 | fprintf(p->csvfpt, " -, -,"); |
1623 | |
|
1624 | 0 | if (stats->statsI.numPics) |
1625 | 0 | { |
1626 | 0 | fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsI.numPics, stats->statsI.avgQp, stats->statsI.bitrate); |
1627 | 0 | if (p->bEnablePsnr) |
1628 | 0 | fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsI.psnrY, stats->statsI.psnrU, stats->statsI.psnrV); |
1629 | 0 | else |
1630 | 0 | fprintf(p->csvfpt, " -, -, -,"); |
1631 | 0 | if (p->bEnableSsim) |
1632 | 0 | fprintf(p->csvfpt, " %.3lf,", stats->statsI.ssim); |
1633 | 0 | else |
1634 | 0 | fprintf(p->csvfpt, " -,"); |
1635 | 0 | } |
1636 | 0 | else |
1637 | 0 | fprintf(p->csvfpt, " -, -, -, -, -, -, -,"); |
1638 | |
|
1639 | 0 | if (stats->statsP.numPics) |
1640 | 0 | { |
1641 | 0 | fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsP.numPics, stats->statsP.avgQp, stats->statsP.bitrate); |
1642 | 0 | if (p->bEnablePsnr) |
1643 | 0 | fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsP.psnrY, stats->statsP.psnrU, stats->statsP.psnrV); |
1644 | 0 | else |
1645 | 0 | fprintf(p->csvfpt, " -, -, -,"); |
1646 | 0 | if (p->bEnableSsim) |
1647 | 0 | fprintf(p->csvfpt, " %.3lf,", stats->statsP.ssim); |
1648 | 0 | else |
1649 | 0 | fprintf(p->csvfpt, " -,"); |
1650 | 0 | } |
1651 | 0 | else |
1652 | 0 | fprintf(p->csvfpt, " -, -, -, -, -, -, -,"); |
1653 | |
|
1654 | 0 | if (stats->statsB.numPics) |
1655 | 0 | { |
1656 | 0 | fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsB.numPics, stats->statsB.avgQp, stats->statsB.bitrate); |
1657 | 0 | if (p->bEnablePsnr) |
1658 | 0 | fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsB.psnrY, stats->statsB.psnrU, stats->statsB.psnrV); |
1659 | 0 | else |
1660 | 0 | fprintf(p->csvfpt, " -, -, -,"); |
1661 | 0 | if (p->bEnableSsim) |
1662 | 0 | fprintf(p->csvfpt, " %.3lf,", stats->statsB.ssim); |
1663 | 0 | else |
1664 | 0 | fprintf(p->csvfpt, " -,"); |
1665 | 0 | } |
1666 | 0 | else |
1667 | 0 | fprintf(p->csvfpt, " -, -, -, -, -, -, -,"); |
1668 | 0 | if (p->csvLogLevel >= 2 || p->maxCLL || p->maxFALL) |
1669 | 0 | fprintf(p->csvfpt, " %-6u, %-6u,", stats->maxCLL, stats->maxFALL); |
1670 | | #if ENABLE_LIBVMAF |
1671 | | fprintf(p->csvfpt, " %lf,", stats->aggregateVmafScore); |
1672 | | #endif |
1673 | 0 | fprintf(p->csvfpt, " %s\n", api->version_str); |
1674 | |
|
1675 | 0 | } |
1676 | 0 | } |
1677 | | |
1678 | | /* The dithering algorithm is based on Sierra-2-4A error diffusion. |
1679 | | * We convert planes in place (without allocating a new buffer). */ |
1680 | | static void ditherPlane(uint16_t *src, int srcStride, int width, int height, int16_t *errors, int bitDepth) |
1681 | 0 | { |
1682 | 0 | const int lShift = 16 - bitDepth; |
1683 | 0 | const int rShift = 16 - bitDepth + 2; |
1684 | 0 | const int half = (1 << (16 - bitDepth + 1)); |
1685 | 0 | const int pixelMax = (1 << bitDepth) - 1; |
1686 | |
|
1687 | 0 | memset(errors, 0, (width + 1) * sizeof(int16_t)); |
1688 | |
|
1689 | 0 | if (bitDepth == 8) |
1690 | 0 | { |
1691 | 0 | for (int y = 0; y < height; y++, src += srcStride) |
1692 | 0 | { |
1693 | 0 | uint8_t* dst = (uint8_t *)src; |
1694 | 0 | int16_t err = 0; |
1695 | 0 | for (int x = 0; x < width; x++) |
1696 | 0 | { |
1697 | 0 | err = err * 2 + errors[x] + errors[x + 1]; |
1698 | 0 | int tmpDst = x265_clip3(0, pixelMax, ((src[x] << 2) + err + half) >> rShift); |
1699 | 0 | errors[x] = err = (int16_t)(src[x] - (tmpDst << lShift)); |
1700 | 0 | dst[x] = (uint8_t)tmpDst; |
1701 | 0 | } |
1702 | 0 | } |
1703 | 0 | } |
1704 | 0 | else |
1705 | 0 | { |
1706 | 0 | for (int y = 0; y < height; y++, src += srcStride) |
1707 | 0 | { |
1708 | 0 | int16_t err = 0; |
1709 | 0 | for (int x = 0; x < width; x++) |
1710 | 0 | { |
1711 | 0 | err = err * 2 + errors[x] + errors[x + 1]; |
1712 | 0 | int tmpDst = x265_clip3(0, pixelMax, ((src[x] << 2) + err + half) >> rShift); |
1713 | 0 | errors[x] = err = (int16_t)(src[x] - (tmpDst << lShift)); |
1714 | 0 | src[x] = (uint16_t)tmpDst; |
1715 | 0 | } |
1716 | 0 | } |
1717 | 0 | } |
1718 | 0 | } |
1719 | | |
1720 | | void x265_dither_image(x265_picture* picIn, int picWidth, int picHeight, int16_t *errorBuf, int bitDepth) |
1721 | 0 | { |
1722 | 0 | const x265_api* api = x265_api_get(0); |
1723 | |
|
1724 | 0 | if (sizeof(x265_picture) != api->sizeof_picture) |
1725 | 0 | { |
1726 | 0 | fprintf(stderr, "extras [error]: structure size skew, unable to dither\n"); |
1727 | 0 | return; |
1728 | 0 | } |
1729 | | |
1730 | 0 | if (picIn->bitDepth <= 8) |
1731 | 0 | { |
1732 | 0 | fprintf(stderr, "extras [error]: dither support enabled only for input bitdepth > 8\n"); |
1733 | 0 | return; |
1734 | 0 | } |
1735 | | |
1736 | 0 | if (picIn->bitDepth == bitDepth) |
1737 | 0 | { |
1738 | 0 | fprintf(stderr, "extras[error]: dither support enabled only if encoder depth is different from picture depth\n"); |
1739 | 0 | return; |
1740 | 0 | } |
1741 | | |
1742 | | /* This portion of code is from readFrame in x264. */ |
1743 | 0 | for (int i = 0; i < x265_cli_csps[picIn->colorSpace].planes; i++) |
1744 | 0 | { |
1745 | 0 | if (picIn->bitDepth < 16) |
1746 | 0 | { |
1747 | | /* upconvert non 16bit high depth planes to 16bit */ |
1748 | 0 | uint16_t *plane = (uint16_t*)picIn->planes[i]; |
1749 | 0 | uint32_t pixelCount = x265_picturePlaneSize(picIn->colorSpace, picWidth, picHeight, i); |
1750 | 0 | int lShift = 16 - picIn->bitDepth; |
1751 | | |
1752 | | /* This loop assumes width is equal to stride which |
1753 | | * happens to be true for file reader outputs */ |
1754 | 0 | for (uint32_t j = 0; j < pixelCount; j++) |
1755 | 0 | plane[j] = plane[j] << lShift; |
1756 | 0 | } |
1757 | |
|
1758 | 0 | int height = (int)(picHeight >> x265_cli_csps[picIn->colorSpace].height[i]); |
1759 | 0 | int width = (int)(picWidth >> x265_cli_csps[picIn->colorSpace].width[i]); |
1760 | |
|
1761 | 0 | ditherPlane(((uint16_t*)picIn->planes[i]), picIn->stride[i] / 2, width, height, errorBuf, bitDepth); |
1762 | 0 | } |
1763 | 0 | } |
1764 | | |
1765 | | #if ENABLE_LIBVMAF |
1766 | | /* Read y values of single frame for 8-bit input */ |
1767 | | int read_image_byte(FILE *file, float *buf, int width, int height, int stride) |
1768 | | { |
1769 | | char *byte_ptr = (char *)buf; |
1770 | | unsigned char *tmp_buf = 0; |
1771 | | int i, j; |
1772 | | int ret = 1; |
1773 | | |
1774 | | if (width <= 0 || height <= 0) |
1775 | | { |
1776 | | goto fail_or_end; |
1777 | | } |
1778 | | |
1779 | | if (!(tmp_buf = (unsigned char*)malloc(width))) |
1780 | | { |
1781 | | goto fail_or_end; |
1782 | | } |
1783 | | |
1784 | | for (i = 0; i < height; ++i) |
1785 | | { |
1786 | | float *row_ptr = (float *)byte_ptr; |
1787 | | |
1788 | | if (fread(tmp_buf, 1, width, file) != (size_t)width) |
1789 | | { |
1790 | | goto fail_or_end; |
1791 | | } |
1792 | | |
1793 | | for (j = 0; j < width; ++j) |
1794 | | { |
1795 | | row_ptr[j] = tmp_buf[j]; |
1796 | | } |
1797 | | |
1798 | | byte_ptr += stride; |
1799 | | } |
1800 | | |
1801 | | ret = 0; |
1802 | | |
1803 | | fail_or_end: |
1804 | | free(tmp_buf); |
1805 | | return ret; |
1806 | | } |
1807 | | /* Read y values of single frame for 10-bit input */ |
1808 | | int read_image_word(FILE *file, float *buf, int width, int height, int stride) |
1809 | | { |
1810 | | char *byte_ptr = (char *)buf; |
1811 | | unsigned short *tmp_buf = 0; |
1812 | | int i, j; |
1813 | | int ret = 1; |
1814 | | |
1815 | | if (width <= 0 || height <= 0) |
1816 | | { |
1817 | | goto fail_or_end; |
1818 | | } |
1819 | | |
1820 | | if (!(tmp_buf = (unsigned short*)malloc(width * 2))) // '*2' to accommodate words |
1821 | | { |
1822 | | goto fail_or_end; |
1823 | | } |
1824 | | |
1825 | | for (i = 0; i < height; ++i) |
1826 | | { |
1827 | | float *row_ptr = (float *)byte_ptr; |
1828 | | |
1829 | | if (fread(tmp_buf, 2, width, file) != (size_t)width) // '2' for word |
1830 | | { |
1831 | | goto fail_or_end; |
1832 | | } |
1833 | | |
1834 | | for (j = 0; j < width; ++j) |
1835 | | { |
1836 | | row_ptr[j] = tmp_buf[j] / 4.0; // '/4' to convert from 10 to 8-bit |
1837 | | } |
1838 | | |
1839 | | byte_ptr += stride; |
1840 | | } |
1841 | | |
1842 | | ret = 0; |
1843 | | |
1844 | | fail_or_end: |
1845 | | free(tmp_buf); |
1846 | | return ret; |
1847 | | } |
1848 | | |
1849 | | static enum VmafOutputFormat log_fmt_map(const char *log_fmt) |
1850 | | { |
1851 | | if (log_fmt) { |
1852 | | if (!strcmp(log_fmt, "xml")) |
1853 | | return VMAF_OUTPUT_FORMAT_XML; |
1854 | | if (!strcmp(log_fmt, "json")) |
1855 | | return VMAF_OUTPUT_FORMAT_JSON; |
1856 | | if (!strcmp(log_fmt, "csv")) |
1857 | | return VMAF_OUTPUT_FORMAT_CSV; |
1858 | | if (!strcmp(log_fmt, "sub")) |
1859 | | return VMAF_OUTPUT_FORMAT_SUB; |
1860 | | } |
1861 | | |
1862 | | return VMAF_OUTPUT_FORMAT_NONE; |
1863 | | } |
1864 | | |
1865 | | static enum VmafPoolingMethod pool_method_map(const char *pool_method) |
1866 | | { |
1867 | | if (pool_method) { |
1868 | | if (!strcmp(pool_method, "min")) |
1869 | | return VMAF_POOL_METHOD_MIN; |
1870 | | if (!strcmp(pool_method, "mean")) |
1871 | | return VMAF_POOL_METHOD_MEAN; |
1872 | | if (!strcmp(pool_method, "harmonic_mean")) |
1873 | | return VMAF_POOL_METHOD_HARMONIC_MEAN; |
1874 | | } |
1875 | | return VMAF_POOL_METHOD_MEAN; |
1876 | | } |
1877 | | |
1878 | | static enum VmafPixelFormat pix_fmt_map(const char *fmt) |
1879 | | { |
1880 | | if (fmt) { |
1881 | | if (!strcmp(fmt, "yuv420p") || !strcmp(fmt, "yuv420p10le") || !strcmp(fmt, "yuv420p12le") || !strcmp(fmt, "yuv420p16le")) |
1882 | | return VMAF_PIX_FMT_YUV420P; |
1883 | | if (!strcmp(fmt, "yuv422p") || !strcmp(fmt, "yuv422p10le")) |
1884 | | return VMAF_PIX_FMT_YUV422P; |
1885 | | if (!strcmp(fmt, "yuv444p") || !strcmp(fmt, "yuv444p10le")) |
1886 | | return VMAF_PIX_FMT_YUV444P; |
1887 | | } |
1888 | | return VMAF_PIX_FMT_UNKNOWN; |
1889 | | } |
1890 | | |
1891 | | static void copy_picture(float *src, VmafPicture *dst, unsigned width, unsigned height, int src_stride, unsigned bpc) |
1892 | | { |
1893 | | const int bytes_per_value = bpc > 8 ? 2 : 1; |
1894 | | const int dst_stride = dst->stride[0] / bytes_per_value; |
1895 | | const unsigned b_shift = (bpc > 8) ? (bpc - 8) : 0; |
1896 | | |
1897 | | uint8_t *dst_data = static_cast<uint8_t*>(dst->data[0]); |
1898 | | |
1899 | | for (unsigned i = 0; i < height; i++) { |
1900 | | if (bpc > 8) { |
1901 | | uint16_t *dst_row = reinterpret_cast<uint16_t*>(dst_data); |
1902 | | for (unsigned j = 0; j < width; j++) { |
1903 | | dst_row[j] = static_cast<uint16_t>(src[j] * (1 << b_shift)); |
1904 | | } |
1905 | | } else { |
1906 | | for (unsigned j = 0; j < width; j++) { |
1907 | | dst_data[j] = static_cast<uint8_t>(src[j]); |
1908 | | } |
1909 | | } |
1910 | | src += src_stride / sizeof(float); |
1911 | | dst_data += dst_stride * bytes_per_value; |
1912 | | } |
1913 | | } |
1914 | | |
1915 | | int load_feature(VmafContext *vmaf, const char *feature_name, VmafFeatureDictionary *d) { |
1916 | | int err = vmaf_use_feature(vmaf, feature_name, d); |
1917 | | if (err) { |
1918 | | printf("problem loading feature extractor: %s\n", feature_name); |
1919 | | } |
1920 | | return err; |
1921 | | } |
1922 | | |
1923 | | int compute_vmaf(double* vmaf_score, char* fmt, int width, int height, int bitdepth, int(*read_frame)(float *ref_data, float *main_data, float *temp_data, int stride_byte, void *user_data), |
1924 | | void *user_data, char *model_path, char *log_path, char *log_fmt, int disable_clip, int disable_avx, int enable_transform, int phone_model, int do_psnr, int do_ssim, int do_ms_ssim, |
1925 | | char *pool_method, int n_thread, int n_subsample) |
1926 | | { |
1927 | | int err = 0; |
1928 | | |
1929 | | VmafConfiguration cfg = { |
1930 | | .log_level = VMAF_LOG_LEVEL_INFO, |
1931 | | .n_threads = static_cast<unsigned int>(n_thread), |
1932 | | .n_subsample = static_cast<unsigned int>(n_subsample), |
1933 | | .cpumask = static_cast<uint64_t>(disable_avx), |
1934 | | .gpumask = 0, |
1935 | | }; |
1936 | | |
1937 | | VmafContext *vmaf; |
1938 | | err = vmaf_init(&vmaf, cfg); |
1939 | | if (err) { |
1940 | | printf("problem initializing VMAF context\n"); |
1941 | | return -1; |
1942 | | } |
1943 | | |
1944 | | uint64_t flags = VMAF_MODEL_FLAGS_DEFAULT; |
1945 | | if (disable_clip) |
1946 | | flags |= VMAF_MODEL_FLAG_DISABLE_CLIP; |
1947 | | if (enable_transform || phone_model) |
1948 | | flags |= VMAF_MODEL_FLAG_ENABLE_TRANSFORM; |
1949 | | |
1950 | | VmafModelConfig model_cfg = { |
1951 | | .name = "vmaf", |
1952 | | .flags = flags, |
1953 | | }; |
1954 | | |
1955 | | VmafModel *model = NULL; |
1956 | | VmafModelCollection *model_collection = NULL; |
1957 | | |
1958 | | int stride = width * sizeof(float); |
1959 | | float *ref_data = new float[height * stride]; |
1960 | | float *main_data = new float[height * stride]; |
1961 | | float *temp_data = new float[height * stride]; |
1962 | | enum VmafOutputFormat output_fmt = log_fmt_map(log_fmt); |
1963 | | |
1964 | | err = vmaf_model_load_from_path(&model, &model_cfg, model_path); |
1965 | | if (err) { |
1966 | | printf("problem loading model file: %s\n", model_path); |
1967 | | goto end; |
1968 | | } |
1969 | | err = vmaf_use_features_from_model(vmaf, model); |
1970 | | if (err) { |
1971 | | printf("problem loading feature extractors from model file: %s\n", model_path); |
1972 | | goto end; |
1973 | | } |
1974 | | |
1975 | | if (do_psnr) { |
1976 | | VmafFeatureDictionary *d = NULL; |
1977 | | vmaf_feature_dictionary_set(&d, "enable_chroma", "false"); |
1978 | | err = load_feature(vmaf, "psnr", d); |
1979 | | if (err) goto end; |
1980 | | } |
1981 | | |
1982 | | if (do_ssim) { |
1983 | | err = load_feature(vmaf, "float_ssim", NULL); |
1984 | | if (err) goto end; |
1985 | | } |
1986 | | |
1987 | | if (do_ms_ssim) { |
1988 | | err = load_feature(vmaf, "float_ms_ssim", NULL); |
1989 | | if (err) goto end; |
1990 | | } |
1991 | | |
1992 | | if (!ref_data || !main_data || !temp_data) { |
1993 | | printf("problem allocating picture memory\n"); |
1994 | | err = -1; |
1995 | | goto free_data; |
1996 | | } |
1997 | | unsigned picture_index; |
1998 | | for (picture_index = 0;; picture_index++) { |
1999 | | err = read_frame(ref_data, main_data, temp_data, stride, user_data); |
2000 | | if (err == 1) { |
2001 | | printf("problem during read_frame\n"); |
2002 | | goto free_data; |
2003 | | } |
2004 | | else if (err == 2) break; |
2005 | | |
2006 | | VmafPicture pic_ref, pic_dist; |
2007 | | err = vmaf_picture_alloc(&pic_ref, pix_fmt_map(fmt), bitdepth, width, height); |
2008 | | err |= vmaf_picture_alloc(&pic_dist, pix_fmt_map(fmt), bitdepth, width, height); |
2009 | | if (err) { |
2010 | | printf("problem allocating picture memory\n"); |
2011 | | vmaf_picture_unref(&pic_ref); |
2012 | | vmaf_picture_unref(&pic_dist); |
2013 | | goto free_data; |
2014 | | } |
2015 | | |
2016 | | const unsigned bpc = bitdepth; |
2017 | | copy_picture(ref_data, &pic_ref, width, height, stride, bpc); |
2018 | | copy_picture(main_data, &pic_dist, width, height, stride, bpc); |
2019 | | |
2020 | | err = vmaf_read_pictures(vmaf, &pic_ref, &pic_dist, picture_index); |
2021 | | if (err) { |
2022 | | printf("problem reading pictures\n"); |
2023 | | break; |
2024 | | } |
2025 | | } |
2026 | | |
2027 | | err = vmaf_read_pictures(vmaf, NULL, NULL, 0); |
2028 | | if (err) { |
2029 | | printf("problem flushing context\n"); |
2030 | | return err; |
2031 | | } |
2032 | | |
2033 | | err = vmaf_score_pooled(vmaf, model, pool_method_map(pool_method), vmaf_score, 0, picture_index - 1); |
2034 | | if (err) { |
2035 | | printf("problem generating pooled VMAF score\n"); |
2036 | | goto free_data; |
2037 | | } |
2038 | | |
2039 | | if (output_fmt == VMAF_OUTPUT_FORMAT_NONE && log_path) { |
2040 | | output_fmt = VMAF_OUTPUT_FORMAT_XML; |
2041 | | printf("use default log_fmt xml"); |
2042 | | } |
2043 | | if (output_fmt) { |
2044 | | err = vmaf_write_output(vmaf, log_path, output_fmt); |
2045 | | if (err) { |
2046 | | printf("could not write output: %s\n", log_path); |
2047 | | goto free_data; |
2048 | | } |
2049 | | } |
2050 | | |
2051 | | free_data: |
2052 | | delete[] ref_data; |
2053 | | delete[] main_data; |
2054 | | delete[] temp_data; |
2055 | | end: |
2056 | | vmaf_model_destroy(model); |
2057 | | vmaf_model_collection_destroy(model_collection); |
2058 | | vmaf_close(vmaf); |
2059 | | return err; |
2060 | | } |
2061 | | |
2062 | | int read_frame(float *reference_data, float *distorted_data, float *temp_data, int stride_byte, void *s) |
2063 | | { |
2064 | | x265_vmaf_data *user_data = (x265_vmaf_data *)s; |
2065 | | int ret; |
2066 | | |
2067 | | // read reference y |
2068 | | if (user_data->internalBitDepth == 8) |
2069 | | { |
2070 | | ret = read_image_byte(user_data->reference_file, reference_data, user_data->width, user_data->height, stride_byte); |
2071 | | } |
2072 | | else if (user_data->internalBitDepth == 10) |
2073 | | { |
2074 | | ret = read_image_word(user_data->reference_file, reference_data, user_data->width, user_data->height, stride_byte); |
2075 | | } |
2076 | | else |
2077 | | { |
2078 | | x265_log(NULL, X265_LOG_ERROR, "Invalid bitdepth\n"); |
2079 | | return 1; |
2080 | | } |
2081 | | if (ret) |
2082 | | { |
2083 | | if (feof(user_data->reference_file)) |
2084 | | { |
2085 | | ret = 2; // OK if end of file |
2086 | | } |
2087 | | return ret; |
2088 | | } |
2089 | | |
2090 | | // read distorted y |
2091 | | if (user_data->internalBitDepth == 8) |
2092 | | { |
2093 | | ret = read_image_byte(user_data->distorted_file, distorted_data, user_data->width, user_data->height, stride_byte); |
2094 | | } |
2095 | | else if (user_data->internalBitDepth == 10) |
2096 | | { |
2097 | | ret = read_image_word(user_data->distorted_file, distorted_data, user_data->width, user_data->height, stride_byte); |
2098 | | } |
2099 | | else |
2100 | | { |
2101 | | x265_log(NULL, X265_LOG_ERROR, "Invalid bitdepth\n"); |
2102 | | return 1; |
2103 | | } |
2104 | | if (ret) |
2105 | | { |
2106 | | if (feof(user_data->distorted_file)) |
2107 | | { |
2108 | | ret = 2; // OK if end of file |
2109 | | } |
2110 | | return ret; |
2111 | | } |
2112 | | |
2113 | | // reference skip u and v |
2114 | | if (user_data->internalBitDepth == 8) |
2115 | | { |
2116 | | if (fread(temp_data, 1, user_data->offset, user_data->reference_file) != (size_t)user_data->offset) |
2117 | | { |
2118 | | x265_log(NULL, X265_LOG_ERROR, "reference fread to skip u and v failed.\n"); |
2119 | | goto fail_or_end; |
2120 | | } |
2121 | | } |
2122 | | else if (user_data->internalBitDepth == 10) |
2123 | | { |
2124 | | if (fread(temp_data, 2, user_data->offset, user_data->reference_file) != (size_t)user_data->offset) |
2125 | | { |
2126 | | x265_log(NULL, X265_LOG_ERROR, "reference fread to skip u and v failed.\n"); |
2127 | | goto fail_or_end; |
2128 | | } |
2129 | | } |
2130 | | else |
2131 | | { |
2132 | | x265_log(NULL, X265_LOG_ERROR, "Invalid format\n"); |
2133 | | goto fail_or_end; |
2134 | | } |
2135 | | |
2136 | | // distorted skip u and v |
2137 | | if (user_data->internalBitDepth == 8) |
2138 | | { |
2139 | | if (fread(temp_data, 1, user_data->offset, user_data->distorted_file) != (size_t)user_data->offset) |
2140 | | { |
2141 | | x265_log(NULL, X265_LOG_ERROR, "distorted fread to skip u and v failed.\n"); |
2142 | | goto fail_or_end; |
2143 | | } |
2144 | | } |
2145 | | else if (user_data->internalBitDepth == 10) |
2146 | | { |
2147 | | if (fread(temp_data, 2, user_data->offset, user_data->distorted_file) != (size_t)user_data->offset) |
2148 | | { |
2149 | | x265_log(NULL, X265_LOG_ERROR, "distorted fread to skip u and v failed.\n"); |
2150 | | goto fail_or_end; |
2151 | | } |
2152 | | } |
2153 | | else |
2154 | | { |
2155 | | x265_log(NULL, X265_LOG_ERROR, "Invalid format\n"); |
2156 | | goto fail_or_end; |
2157 | | } |
2158 | | |
2159 | | |
2160 | | fail_or_end: |
2161 | | return ret; |
2162 | | } |
2163 | | |
2164 | | double x265_calculate_vmafscore(x265_param *param, x265_vmaf_data *data) |
2165 | | { |
2166 | | double score; |
2167 | | const char* pix_format; |
2168 | | |
2169 | | data->width = param->sourceWidth; |
2170 | | data->height = param->sourceHeight; |
2171 | | data->internalBitDepth = param->internalBitDepth; |
2172 | | |
2173 | | if (param->internalCsp == X265_CSP_I420) |
2174 | | { |
2175 | | if ((param->sourceWidth * param->sourceHeight) % 2 != 0) |
2176 | | x265_log(NULL, X265_LOG_ERROR, "Invalid file size\n"); |
2177 | | data->offset = param->sourceWidth * param->sourceHeight / 2; |
2178 | | pix_format = "yuv420p"; |
2179 | | } |
2180 | | else if (param->internalCsp == X265_CSP_I422) |
2181 | | { |
2182 | | data->offset = param->sourceWidth * param->sourceHeight; |
2183 | | pix_format = "yuv422p10le"; |
2184 | | } |
2185 | | else if (param->internalCsp == X265_CSP_I444) |
2186 | | { |
2187 | | data->offset = param->sourceWidth * param->sourceHeight * 2; |
2188 | | pix_format = "yuv444p10le"; |
2189 | | } |
2190 | | else |
2191 | | x265_log(NULL, X265_LOG_ERROR, "Invalid format\n"); |
2192 | | |
2193 | | compute_vmaf(&score, (char*)pix_format, data->width, data->height, param->sourceBitDepth, read_frame, data, vcd->model_path, vcd->log_path, vcd->log_fmt, vcd->disable_clip, vcd->disable_avx, vcd->enable_transform, vcd->phone_model, vcd->psnr, vcd->ssim, vcd->ms_ssim, vcd->pool, vcd->thread, vcd->subsample); |
2194 | | |
2195 | | return score; |
2196 | | } |
2197 | | |
2198 | | int read_frame_10bit(float *reference_data, float *distorted_data, float *temp_data, int stride, void *s) |
2199 | | { |
2200 | | x265_vmaf_framedata *user_data = (x265_vmaf_framedata *)s; |
2201 | | |
2202 | | PicYuv *reference_frame = (PicYuv *)user_data->reference_frame; |
2203 | | PicYuv *distorted_frame = (PicYuv *)user_data->distorted_frame; |
2204 | | |
2205 | | if(!user_data->frame_set) { |
2206 | | |
2207 | | int reference_stride = reference_frame->m_stride; |
2208 | | int distorted_stride = distorted_frame->m_stride; |
2209 | | |
2210 | | const uint16_t *reference_ptr = (const uint16_t *)reference_frame->m_picOrg[0]; |
2211 | | const uint16_t *distorted_ptr = (const uint16_t *)distorted_frame->m_picOrg[0]; |
2212 | | |
2213 | | temp_data = reference_data; |
2214 | | |
2215 | | int height = user_data->height; |
2216 | | int width = user_data->width; |
2217 | | |
2218 | | int i,j; |
2219 | | for (i = 0; i < height; i++) { |
2220 | | for ( j = 0; j < width; j++) { |
2221 | | temp_data[j] = ((float)reference_ptr[j] / 4.0); |
2222 | | } |
2223 | | reference_ptr += reference_stride; |
2224 | | temp_data += stride / sizeof(*temp_data); |
2225 | | } |
2226 | | |
2227 | | temp_data = distorted_data; |
2228 | | for (i = 0; i < height; i++) { |
2229 | | for (j = 0; j < width; j++) { |
2230 | | temp_data[j] = ((float)distorted_ptr[j] / 4.0); |
2231 | | } |
2232 | | distorted_ptr += distorted_stride; |
2233 | | temp_data += stride / sizeof(*temp_data); |
2234 | | } |
2235 | | |
2236 | | user_data->frame_set = 1; |
2237 | | return 0; |
2238 | | } |
2239 | | return 2; |
2240 | | } |
2241 | | |
2242 | | int read_frame_8bit(float *reference_data, float *distorted_data, float *temp_data, int stride, void *s) |
2243 | | { |
2244 | | x265_vmaf_framedata *user_data = (x265_vmaf_framedata *)s; |
2245 | | |
2246 | | PicYuv *reference_frame = (PicYuv *)user_data->reference_frame; |
2247 | | PicYuv *distorted_frame = (PicYuv *)user_data->distorted_frame; |
2248 | | |
2249 | | if(!user_data->frame_set) { |
2250 | | |
2251 | | int reference_stride = reference_frame->m_stride; |
2252 | | int distorted_stride = distorted_frame->m_stride; |
2253 | | |
2254 | | const uint8_t *reference_ptr = (const uint8_t *)reference_frame->m_picOrg[0]; |
2255 | | const uint8_t *distorted_ptr = (const uint8_t *)distorted_frame->m_picOrg[0]; |
2256 | | |
2257 | | temp_data = reference_data; |
2258 | | |
2259 | | int height = user_data->height; |
2260 | | int width = user_data->width; |
2261 | | |
2262 | | int i,j; |
2263 | | for (i = 0; i < height; i++) { |
2264 | | for ( j = 0; j < width; j++) { |
2265 | | temp_data[j] = (float)reference_ptr[j]; |
2266 | | } |
2267 | | reference_ptr += reference_stride; |
2268 | | temp_data += stride / sizeof(*temp_data); |
2269 | | } |
2270 | | |
2271 | | temp_data = distorted_data; |
2272 | | for (i = 0; i < height; i++) { |
2273 | | for (j = 0; j < width; j++) { |
2274 | | temp_data[j] = (float)distorted_ptr[j]; |
2275 | | } |
2276 | | distorted_ptr += distorted_stride; |
2277 | | temp_data += stride / sizeof(*temp_data); |
2278 | | } |
2279 | | |
2280 | | user_data->frame_set = 1; |
2281 | | return 0; |
2282 | | } |
2283 | | return 2; |
2284 | | } |
2285 | | |
2286 | | double x265_calculate_vmaf_framelevelscore(x265_param *param, x265_vmaf_framedata *vmafframedata) |
2287 | | { |
2288 | | double score; |
2289 | | const char* pix_format; |
2290 | | |
2291 | | if (param->internalCsp == X265_CSP_I420) |
2292 | | pix_format = "yuv420p"; |
2293 | | else if (param->internalCsp == X265_CSP_I422) |
2294 | | pix_format = "yuv422p10le"; |
2295 | | else |
2296 | | pix_format = "yuv444p10le"; |
2297 | | |
2298 | | int (*read_frame)(float *reference_data, float *distorted_data, float *temp_data, |
2299 | | int stride, void *s); |
2300 | | if (vmafframedata->internalBitDepth == 8) |
2301 | | read_frame = read_frame_8bit; |
2302 | | else |
2303 | | read_frame = read_frame_10bit; |
2304 | | compute_vmaf(&score, (char*)pix_format, vmafframedata->width, vmafframedata->height, param->sourceBitDepth, read_frame, vmafframedata, vcd->model_path, vcd->log_path, vcd->log_fmt, vcd->disable_clip, vcd->disable_avx, vcd->enable_transform, vcd->phone_model, vcd->psnr, vcd->ssim, vcd->ms_ssim, vcd->pool, vcd->thread, vcd->subsample); |
2305 | | |
2306 | | return score; |
2307 | | } |
2308 | | #endif |
2309 | | |
2310 | | } /* end namespace or extern "C" */ |
2311 | | |
2312 | | namespace X265_NS { |
2313 | | #ifdef SVT_HEVC |
2314 | | |
2315 | | void svt_initialise_app_context(x265_encoder *enc) |
2316 | | { |
2317 | | Encoder *encoder = static_cast<Encoder*>(enc); |
2318 | | |
2319 | | //Initialise Application Context |
2320 | | encoder->m_svtAppData = (SvtAppContext*)x265_malloc(sizeof(SvtAppContext)); |
2321 | | encoder->m_svtAppData->svtHevcParams = (EB_H265_ENC_CONFIGURATION*)x265_malloc(sizeof(EB_H265_ENC_CONFIGURATION)); |
2322 | | encoder->m_svtAppData->byteCount = 0; |
2323 | | encoder->m_svtAppData->outFrameCount = 0; |
2324 | | } |
2325 | | |
2326 | | int svt_initialise_input_buffer(x265_encoder *enc) |
2327 | | { |
2328 | | Encoder *encoder = static_cast<Encoder*>(enc); |
2329 | | |
2330 | | //Initialise Input Buffer |
2331 | | encoder->m_svtAppData->inputPictureBuffer = (EB_BUFFERHEADERTYPE*)x265_malloc(sizeof(EB_BUFFERHEADERTYPE)); |
2332 | | EB_BUFFERHEADERTYPE *inputPtr = encoder->m_svtAppData->inputPictureBuffer; |
2333 | | inputPtr->pBuffer = (unsigned char*)x265_malloc(sizeof(EB_H265_ENC_INPUT)); |
2334 | | |
2335 | | EB_H265_ENC_INPUT *inputData = (EB_H265_ENC_INPUT*)inputPtr->pBuffer; |
2336 | | inputData->dolbyVisionRpu.payload = NULL; |
2337 | | inputData->dolbyVisionRpu.payloadSize = 0; |
2338 | | |
2339 | | |
2340 | | if (!inputPtr->pBuffer) |
2341 | | return 0; |
2342 | | |
2343 | | inputPtr->nSize = sizeof(EB_BUFFERHEADERTYPE); |
2344 | | inputPtr->pAppPrivate = NULL; |
2345 | | return 1; |
2346 | | } |
2347 | | #endif // ifdef SVT_HEVC |
2348 | | |
2349 | | } // end namespace X265_NS |