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