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 inputData->dolbyVisionRpu.payload = X265_MALLOC(uint8_t, 1024);
454 memcpy(inputData->dolbyVisionRpu.payload, pic_in->rpu.payload, pic_in->rpu.payloadSize);
455 inputData->dolbyVisionRpu.payloadSize = pic_in->rpu.payloadSize;
456 inputData->dolbyVisionRpu.payloadType = NAL_UNIT_UNSPECIFIED;
457 }
458 else
459 {
460 inputData->dolbyVisionRpu.payload = NULL;
461 inputData->dolbyVisionRpu.payloadSize = 0;
462 }
463
464 // Send the picture to the encoder
465 return_error = EbH265EncSendPicture(encoder->m_svtAppData->svtEncoderHandle, inputPtr);
466
467 if (return_error != EB_ErrorNone)
468 {
469 x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while encoding \n");
470 numEncoded = -1;
471 goto fail;
472 }
473 }
474 else
475 {
476 x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC Encoder accepts only yuv420p input \n");
477 numEncoded = -1;
478 goto fail;
479 }
480 }
481 else if (!picSendDone) //Encoder flush
482 {
483 picSendDone = 1;
484 EB_BUFFERHEADERTYPE inputPtrLast;
485 inputPtrLast.nAllocLen = 0;
486 inputPtrLast.nFilledLen = 0;
487 inputPtrLast.nTickCount = 0;
488 inputPtrLast.pAppPrivate = NULL;
489 inputPtrLast.nFlags = EB_BUFFERFLAG_EOS;
490 inputPtrLast.pBuffer = NULL;
491
492 return_error = EbH265EncSendPicture(encoder->m_svtAppData->svtEncoderHandle, &inputPtrLast);
493 if (return_error != EB_ErrorNone)
494 {
495 x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while encoding \n");
496 numEncoded = -1;
497 goto fail;
498 }
499 }
500
501 if (eofReached && svtParam->codeEosNal == 0 && !codedNal)
502 {
503 EB_BUFFERHEADERTYPE *outputStreamPtr = 0;
504 return_error = EbH265EncEosNal(encoder->m_svtAppData->svtEncoderHandle, &outputStreamPtr);
505 if (return_error == EB_ErrorMax)
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 if (return_error != EB_NoErrorEmptyQueue)
512 {
513 if (outputStreamPtr->pBuffer)
514 {
515 //Copy data from output packet to NAL
516 encoder->m_nalList.m_nal[0].payload = outputStreamPtr->pBuffer;
517 encoder->m_nalList.m_nal[0].sizeBytes = outputStreamPtr->nFilledLen;
518 encoder->m_svtAppData->byteCount += outputStreamPtr->nFilledLen;
519 *pp_nal = &encoder->m_nalList.m_nal[0];
520 *pi_nal = 1;
521 numEncoded = 0;
522 codedNal = 1;
523 return numEncoded;
524 }
525
526 // Release the output buffer
527 EbH265ReleaseOutBuffer(&outputStreamPtr);
528 }
529 }
530 else if (eofReached)
531 {
532 *pi_nal = 0;
533 return numEncoded;
534 }
535
536 //Receive Packet
537 EB_BUFFERHEADERTYPE *outputPtr;
538 return_error = EbH265GetPacket(encoder->m_svtAppData->svtEncoderHandle, &outputPtr, picSendDone);
539 if (return_error == EB_ErrorMax)
540 {
541 x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while encoding \n");
542 numEncoded = -1;
543 goto fail;
544 }
545
546 if (return_error != EB_NoErrorEmptyQueue)
547 {
548 if (outputPtr->pBuffer)
549 {
550 //Copy data from output packet to NAL
551 encoder->m_nalList.m_nal[0].payload = outputPtr->pBuffer;
552 encoder->m_nalList.m_nal[0].sizeBytes = outputPtr->nFilledLen;
553 encoder->m_svtAppData->byteCount += outputPtr->nFilledLen;
554 encoder->m_svtAppData->outFrameCount++;
555 *pp_nal = &encoder->m_nalList.m_nal[0];
556 *pi_nal = 1;
557 numEncoded = 1;
558 }
559
560 eofReached = outputPtr->nFlags & EB_BUFFERFLAG_EOS;
561
562 // Release the output buffer
563 EbH265ReleaseOutBuffer(&outputPtr);
564 }
565 else if (pi_nal)
566 *pi_nal = 0;
567
568 pic_out = NULL;
569
570 fail:
571 if (numEncoded < 0)
572 encoder->m_aborted = true;
573
574 return numEncoded;
575 }
576 #endif
577
578 // While flushing, we cannot return 0 until the entire stream is flushed
579 do
580 {
581 numEncoded = encoder->encode(pic_in, pic_out);
582 }
583 while ((numEncoded == 0 && !pic_in && encoder->m_numDelayedPic && !encoder->m_latestParam->forceFlush) && !encoder->m_externalFlush);
584 if (numEncoded)
585 encoder->m_externalFlush = false;
586
587 // do not allow reuse of these buffers for more than one picture. The
588 // encoder now owns these analysisData buffers.
589 if (pic_in)
590 {
591 pic_in->analysisData.wt = NULL;
592 pic_in->analysisData.intraData = NULL;
593 pic_in->analysisData.interData = NULL;
594 pic_in->analysisData.distortionData = NULL;
595 }
596
597 if (pp_nal && numEncoded > 0 && encoder->m_outputCount >= encoder->m_latestParam->chunkStart)
598 {
599 *pp_nal = &encoder->m_nalList.m_nal[0];
600 if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
601 }
602 else if (pi_nal)
603 *pi_nal = 0;
604
605 if (numEncoded && encoder->m_param->csvLogLevel && encoder->m_outputCount >= encoder->m_latestParam->chunkStart)
606 x265_csvlog_frame(encoder->m_param, pic_out);
607
608 if (numEncoded < 0)
609 encoder->m_aborted = true;
610
611 return numEncoded;
612 }
613
x265_encoder_get_stats(x265_encoder * enc,x265_stats * outputStats,uint32_t statsSizeBytes)614 void x265_encoder_get_stats(x265_encoder *enc, x265_stats *outputStats, uint32_t statsSizeBytes)
615 {
616 if (enc && outputStats)
617 {
618 Encoder *encoder = static_cast<Encoder*>(enc);
619 encoder->fetchStats(outputStats, statsSizeBytes);
620 }
621 }
622 #if ENABLE_LIBVMAF
x265_vmaf_encoder_log(x265_encoder * enc,int argc,char ** argv,x265_param * param,x265_vmaf_data * vmafdata)623 void x265_vmaf_encoder_log(x265_encoder* enc, int argc, char **argv, x265_param *param, x265_vmaf_data *vmafdata)
624 {
625 if (enc)
626 {
627 Encoder *encoder = static_cast<Encoder*>(enc);
628 x265_stats stats;
629 stats.aggregateVmafScore = x265_calculate_vmafscore(param, vmafdata);
630 if(vmafdata->reference_file)
631 fclose(vmafdata->reference_file);
632 if(vmafdata->distorted_file)
633 fclose(vmafdata->distorted_file);
634 if(vmafdata)
635 x265_free(vmafdata);
636 encoder->fetchStats(&stats, sizeof(stats));
637 int padx = encoder->m_sps.conformanceWindow.rightOffset;
638 int pady = encoder->m_sps.conformanceWindow.bottomOffset;
639 x265_csvlog_encode(encoder->m_param, &stats, padx, pady, argc, argv);
640 }
641 }
642 #endif
643
x265_encoder_log(x265_encoder * enc,int argc,char ** argv)644 void x265_encoder_log(x265_encoder* enc, int argc, char **argv)
645 {
646 if (enc)
647 {
648 Encoder *encoder = static_cast<Encoder*>(enc);
649 x265_stats stats;
650 encoder->fetchStats(&stats, sizeof(stats));
651 int padx = encoder->m_sps.conformanceWindow.rightOffset;
652 int pady = encoder->m_sps.conformanceWindow.bottomOffset;
653 x265_csvlog_encode(encoder->m_param, &stats, padx, pady, argc, argv);
654 }
655 }
656
657 #ifdef SVT_HEVC
svt_print_summary(x265_encoder * enc)658 static void svt_print_summary(x265_encoder *enc)
659 {
660 Encoder *encoder = static_cast<Encoder*>(enc);
661 double frameRate = 0, bitrate = 0;
662 EB_H265_ENC_CONFIGURATION *svtParam = (EB_H265_ENC_CONFIGURATION*)encoder->m_svtAppData->svtHevcParams;
663 if (svtParam->frameRateNumerator && svtParam->frameRateDenominator && (svtParam->frameRateNumerator != 0 && svtParam->frameRateDenominator != 0))
664 {
665 frameRate = ((double)svtParam->frameRateNumerator) / ((double)svtParam->frameRateDenominator);
666 if(encoder->m_svtAppData->outFrameCount)
667 bitrate = ((double)(encoder->m_svtAppData->byteCount << 3) * frameRate / (encoder->m_svtAppData->outFrameCount * 1000));
668
669 printf("Total Frames\t\tFrame Rate\t\tByte Count\t\tBitrate\n");
670 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);
671 }
672 }
673 #endif
674
x265_encoder_close(x265_encoder * enc)675 void x265_encoder_close(x265_encoder *enc)
676 {
677 if (enc)
678 {
679 Encoder *encoder = static_cast<Encoder*>(enc);
680
681 #ifdef SVT_HEVC
682 if (encoder->m_param->bEnableSvtHevc)
683 {
684 EB_ERRORTYPE return_value;
685 return_value = EbDeinitEncoder(encoder->m_svtAppData->svtEncoderHandle);
686 if (return_value != EB_ErrorNone)
687 {
688 x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while closing the encoder \n");
689 }
690 return_value = EbDeinitHandle(encoder->m_svtAppData->svtEncoderHandle);
691 if (return_value != EB_ErrorNone)
692 {
693 x265_log(encoder->m_param, X265_LOG_ERROR, "SVT HEVC encoder: Error while closing the Handle \n");
694 }
695
696 svt_print_summary(enc);
697 EB_H265_ENC_INPUT *inputData = (EB_H265_ENC_INPUT*)encoder->m_svtAppData->inputPictureBuffer->pBuffer;
698 if (inputData->dolbyVisionRpu.payload) X265_FREE(inputData->dolbyVisionRpu.payload);
699
700 X265_FREE(inputData);
701 X265_FREE(encoder->m_svtAppData->inputPictureBuffer);
702 X265_FREE(encoder->m_svtAppData->svtHevcParams);
703 encoder->stopJobs();
704 encoder->destroy();
705 delete encoder;
706 return;
707 }
708 #endif
709
710 encoder->stopJobs();
711 encoder->printSummary();
712 encoder->destroy();
713 delete encoder;
714 }
715 }
716
x265_encoder_intra_refresh(x265_encoder * enc)717 int x265_encoder_intra_refresh(x265_encoder *enc)
718 {
719 if (!enc)
720 return -1;
721
722 Encoder *encoder = static_cast<Encoder*>(enc);
723 encoder->m_bQueuedIntraRefresh = 1;
724 return 0;
725 }
x265_encoder_ctu_info(x265_encoder * enc,int poc,x265_ctu_info_t ** ctu)726 int x265_encoder_ctu_info(x265_encoder *enc, int poc, x265_ctu_info_t** ctu)
727 {
728 if (!ctu || !enc)
729 return -1;
730 Encoder* encoder = static_cast<Encoder*>(enc);
731 encoder->copyCtuInfo(ctu, poc);
732 return 0;
733 }
734
x265_get_slicetype_poc_and_scenecut(x265_encoder * enc,int * slicetype,int * poc,int * sceneCut)735 int x265_get_slicetype_poc_and_scenecut(x265_encoder *enc, int *slicetype, int *poc, int *sceneCut)
736 {
737 if (!enc)
738 return -1;
739 Encoder *encoder = static_cast<Encoder*>(enc);
740 if (!encoder->copySlicetypePocAndSceneCut(slicetype, poc, sceneCut))
741 return 0;
742 return -1;
743 }
744
x265_get_ref_frame_list(x265_encoder * enc,x265_picyuv ** l0,x265_picyuv ** l1,int sliceType,int poc,int * pocL0,int * pocL1)745 int x265_get_ref_frame_list(x265_encoder *enc, x265_picyuv** l0, x265_picyuv** l1, int sliceType, int poc, int* pocL0, int* pocL1)
746 {
747 if (!enc)
748 return -1;
749
750 Encoder *encoder = static_cast<Encoder*>(enc);
751 return encoder->getRefFrameList((PicYuv**)l0, (PicYuv**)l1, sliceType, poc, pocL0, pocL1);
752 }
753
x265_set_analysis_data(x265_encoder * enc,x265_analysis_data * analysis_data,int poc,uint32_t cuBytes)754 int x265_set_analysis_data(x265_encoder *enc, x265_analysis_data *analysis_data, int poc, uint32_t cuBytes)
755 {
756 if (!enc)
757 return -1;
758
759 Encoder *encoder = static_cast<Encoder*>(enc);
760 if (!encoder->setAnalysisData(analysis_data, poc, cuBytes))
761 return 0;
762
763 return -1;
764 }
765
x265_alloc_analysis_data(x265_param * param,x265_analysis_data * analysis)766 void x265_alloc_analysis_data(x265_param *param, x265_analysis_data* analysis)
767 {
768 x265_analysis_inter_data *interData = analysis->interData = NULL;
769 x265_analysis_intra_data *intraData = analysis->intraData = NULL;
770 x265_analysis_distortion_data *distortionData = analysis->distortionData = NULL;
771
772 bool isVbv = param->rc.vbvMaxBitrate > 0 && param->rc.vbvBufferSize > 0;
773 int numDir = 2; //irrespective of P or B slices set direction as 2
774 uint32_t numPlanes = param->internalCsp == X265_CSP_I400 ? 1 : 3;
775
776 int maxReuseLevel = X265_MAX(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel);
777 int minReuseLevel = (param->analysisSaveReuseLevel && param->analysisLoadReuseLevel) ?
778 X265_MIN(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel) : maxReuseLevel;
779
780 bool isMultiPassOpt = param->analysisMultiPassRefine || param->analysisMultiPassDistortion;
781
782 #if X265_DEPTH < 10 && (LINKED_10BIT || LINKED_12BIT)
783 uint32_t numCUs_sse_t = param->internalBitDepth > 8 ? analysis->numCUsInFrame << 1 : analysis->numCUsInFrame;
784 #elif X265_DEPTH >= 10 && LINKED_8BIT
785 uint32_t numCUs_sse_t = param->internalBitDepth > 8 ? analysis->numCUsInFrame : (analysis->numCUsInFrame + 1U) >> 1;
786 #else
787 uint32_t numCUs_sse_t = analysis->numCUsInFrame;
788 #endif
789 if (isMultiPassOpt || param->ctuDistortionRefine)
790 {
791 //Allocate memory for distortionData pointer
792 CHECKED_MALLOC_ZERO(distortionData, x265_analysis_distortion_data, 1);
793 CHECKED_MALLOC_ZERO(distortionData->ctuDistortion, sse_t, analysis->numPartitions * numCUs_sse_t);
794 if (param->analysisLoad || param->rc.bStatRead)
795 {
796 CHECKED_MALLOC_ZERO(distortionData->scaledDistortion, double, analysis->numCUsInFrame);
797 CHECKED_MALLOC_ZERO(distortionData->offset, double, analysis->numCUsInFrame);
798 CHECKED_MALLOC_ZERO(distortionData->threshold, double, analysis->numCUsInFrame);
799 }
800 analysis->distortionData = distortionData;
801 }
802
803 if (!isMultiPassOpt && param->bDisableLookahead && isVbv)
804 {
805 CHECKED_MALLOC_ZERO(analysis->lookahead.intraSatdForVbv, uint32_t, analysis->numCuInHeight);
806 CHECKED_MALLOC_ZERO(analysis->lookahead.satdForVbv, uint32_t, analysis->numCuInHeight);
807 CHECKED_MALLOC_ZERO(analysis->lookahead.intraVbvCost, uint32_t, analysis->numCUsInFrame);
808 CHECKED_MALLOC_ZERO(analysis->lookahead.vbvCost, uint32_t, analysis->numCUsInFrame);
809 }
810
811 //Allocate memory for weightParam pointer
812 if (!isMultiPassOpt && !(param->bAnalysisType == AVC_INFO))
813 CHECKED_MALLOC_ZERO(analysis->wt, x265_weight_param, numPlanes * numDir);
814
815 //Allocate memory for intraData pointer
816 if ((maxReuseLevel > 1) || isMultiPassOpt)
817 {
818 CHECKED_MALLOC_ZERO(intraData, x265_analysis_intra_data, 1);
819 CHECKED_MALLOC(intraData->depth, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
820 }
821
822 if (maxReuseLevel > 1)
823 {
824 CHECKED_MALLOC_ZERO(intraData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
825 CHECKED_MALLOC_ZERO(intraData->partSizes, char, analysis->numPartitions * analysis->numCUsInFrame);
826 CHECKED_MALLOC_ZERO(intraData->chromaModes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
827 if (param->rc.cuTree)
828 CHECKED_MALLOC_ZERO(intraData->cuQPOff, int8_t, analysis->numPartitions * analysis->numCUsInFrame);
829 }
830 analysis->intraData = intraData;
831
832 if ((maxReuseLevel > 1) || isMultiPassOpt)
833 {
834 //Allocate memory for interData pointer based on ReuseLevels
835 CHECKED_MALLOC_ZERO(interData, x265_analysis_inter_data, 1);
836 CHECKED_MALLOC(interData->depth, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
837 CHECKED_MALLOC_ZERO(interData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
838
839 if (param->rc.cuTree && !isMultiPassOpt)
840 CHECKED_MALLOC_ZERO(interData->cuQPOff, int8_t, analysis->numPartitions * analysis->numCUsInFrame);
841 CHECKED_MALLOC_ZERO(interData->mvpIdx[0], uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
842 CHECKED_MALLOC_ZERO(interData->mvpIdx[1], uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
843 CHECKED_MALLOC_ZERO(interData->mv[0], x265_analysis_MV, analysis->numPartitions * analysis->numCUsInFrame);
844 CHECKED_MALLOC_ZERO(interData->mv[1], x265_analysis_MV, analysis->numPartitions * analysis->numCUsInFrame);
845 }
846
847 if (maxReuseLevel > 4)
848 {
849 CHECKED_MALLOC_ZERO(interData->partSize, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
850 CHECKED_MALLOC_ZERO(interData->mergeFlag, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
851 }
852 if (maxReuseLevel >= 7)
853 {
854 CHECKED_MALLOC_ZERO(interData->interDir, uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
855 CHECKED_MALLOC_ZERO(interData->sadCost, int64_t, analysis->numPartitions * analysis->numCUsInFrame);
856 for (int dir = 0; dir < numDir; dir++)
857 {
858 CHECKED_MALLOC_ZERO(interData->refIdx[dir], int8_t, analysis->numPartitions * analysis->numCUsInFrame);
859 CHECKED_MALLOC_ZERO(analysis->modeFlag[dir], uint8_t, analysis->numPartitions * analysis->numCUsInFrame);
860 }
861 }
862 if ((minReuseLevel >= 2) && (minReuseLevel <= 6))
863 {
864 CHECKED_MALLOC_ZERO(interData->ref, int32_t, analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * numDir);
865 }
866 if (isMultiPassOpt)
867 CHECKED_MALLOC_ZERO(interData->ref, int32_t, 2 * analysis->numPartitions * analysis->numCUsInFrame);
868
869 analysis->interData = interData;
870
871 return;
872
873 fail:
874 x265_free_analysis_data(param, analysis);
875 }
876
x265_free_analysis_data(x265_param * param,x265_analysis_data * analysis)877 void x265_free_analysis_data(x265_param *param, x265_analysis_data* analysis)
878 {
879 int maxReuseLevel = X265_MAX(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel);
880 int minReuseLevel = (param->analysisSaveReuseLevel && param->analysisLoadReuseLevel) ?
881 X265_MIN(param->analysisSaveReuseLevel, param->analysisLoadReuseLevel) : maxReuseLevel;
882
883 bool isVbv = param->rc.vbvMaxBitrate > 0 && param->rc.vbvBufferSize > 0;
884 bool isMultiPassOpt = param->analysisMultiPassRefine || param->analysisMultiPassDistortion;
885
886 //Free memory for Lookahead pointers
887 if (!isMultiPassOpt && param->bDisableLookahead && isVbv)
888 {
889 X265_FREE(analysis->lookahead.satdForVbv);
890 X265_FREE(analysis->lookahead.intraSatdForVbv);
891 X265_FREE(analysis->lookahead.vbvCost);
892 X265_FREE(analysis->lookahead.intraVbvCost);
893 }
894
895 //Free memory for distortionData pointers
896 if (analysis->distortionData)
897 {
898 X265_FREE((analysis->distortionData)->ctuDistortion);
899 if (param->rc.bStatRead || param->analysisLoad)
900 {
901 X265_FREE((analysis->distortionData)->scaledDistortion);
902 X265_FREE((analysis->distortionData)->offset);
903 X265_FREE((analysis->distortionData)->threshold);
904 }
905 X265_FREE(analysis->distortionData);
906 }
907
908 /* Early exit freeing weights alone if level is 1 (when there is no analysis inter/intra) */
909 if (!isMultiPassOpt && analysis->wt && !(param->bAnalysisType == AVC_INFO))
910 X265_FREE(analysis->wt);
911
912 //Free memory for intraData pointers
913 if (analysis->intraData)
914 {
915 X265_FREE((analysis->intraData)->depth);
916 if (!isMultiPassOpt)
917 {
918 X265_FREE((analysis->intraData)->modes);
919 X265_FREE((analysis->intraData)->partSizes);
920 X265_FREE((analysis->intraData)->chromaModes);
921 if (param->rc.cuTree)
922 X265_FREE((analysis->intraData)->cuQPOff);
923 }
924 X265_FREE(analysis->intraData);
925 analysis->intraData = NULL;
926 }
927
928 //Free interData pointers
929 if (analysis->interData)
930 {
931 X265_FREE((analysis->interData)->depth);
932 X265_FREE((analysis->interData)->modes);
933 if (!isMultiPassOpt && param->rc.cuTree)
934 X265_FREE((analysis->interData)->cuQPOff);
935 X265_FREE((analysis->interData)->mvpIdx[0]);
936 X265_FREE((analysis->interData)->mvpIdx[1]);
937 X265_FREE((analysis->interData)->mv[0]);
938 X265_FREE((analysis->interData)->mv[1]);
939
940 if (maxReuseLevel > 4)
941 {
942 X265_FREE((analysis->interData)->mergeFlag);
943 X265_FREE((analysis->interData)->partSize);
944 }
945 if (maxReuseLevel >= 7)
946 {
947 int numDir = 2;
948 X265_FREE((analysis->interData)->interDir);
949 X265_FREE((analysis->interData)->sadCost);
950 for (int dir = 0; dir < numDir; dir++)
951 {
952 X265_FREE((analysis->interData)->refIdx[dir]);
953 if (analysis->modeFlag[dir] != NULL)
954 {
955 X265_FREE(analysis->modeFlag[dir]);
956 analysis->modeFlag[dir] = NULL;
957 }
958 }
959 }
960 if (((minReuseLevel >= 2) && (minReuseLevel <= 6)) || isMultiPassOpt)
961 X265_FREE((analysis->interData)->ref);
962 X265_FREE(analysis->interData);
963 analysis->interData = NULL;
964 }
965 }
966
x265_cleanup(void)967 void x265_cleanup(void)
968 {
969 BitCost::destroy();
970 }
971
x265_picture_alloc()972 x265_picture *x265_picture_alloc()
973 {
974 return (x265_picture*)x265_malloc(sizeof(x265_picture));
975 }
976
x265_picture_init(x265_param * param,x265_picture * pic)977 void x265_picture_init(x265_param *param, x265_picture *pic)
978 {
979 memset(pic, 0, sizeof(x265_picture));
980
981 pic->bitDepth = param->internalBitDepth;
982 pic->colorSpace = param->internalCsp;
983 pic->forceqp = X265_QP_AUTO;
984 pic->quantOffsets = NULL;
985 pic->userSEI.payloads = NULL;
986 pic->userSEI.numPayloads = 0;
987 pic->rpu.payloadSize = 0;
988 pic->rpu.payload = NULL;
989 pic->picStruct = 0;
990
991 if ((param->analysisSave || param->analysisLoad) || (param->bAnalysisType == AVC_INFO))
992 {
993 uint32_t widthInCU = (param->sourceWidth + param->maxCUSize - 1) >> param->maxLog2CUSize;
994 uint32_t heightInCU = (param->sourceHeight + param->maxCUSize - 1) >> param->maxLog2CUSize;
995
996 uint32_t numCUsInFrame = widthInCU * heightInCU;
997 pic->analysisData.numCUsInFrame = numCUsInFrame;
998 pic->analysisData.numPartitions = param->num4x4Partitions;
999 }
1000 }
1001
x265_picture_free(x265_picture * p)1002 void x265_picture_free(x265_picture *p)
1003 {
1004 return x265_free(p);
1005 }
1006
x265_zone_alloc(int zoneCount,int isZoneFile)1007 x265_zone *x265_zone_alloc(int zoneCount, int isZoneFile)
1008 {
1009 x265_zone* zone = (x265_zone*)x265_malloc(sizeof(x265_zone) * zoneCount);
1010 if (isZoneFile) {
1011 for (int i = 0; i < zoneCount; i++)
1012 zone[i].zoneParam = (x265_param*)x265_malloc(sizeof(x265_param));
1013 }
1014 return zone;
1015 }
1016
x265_zone_free(x265_param * param)1017 void x265_zone_free(x265_param *param)
1018 {
1019 if (param && param->rc.zones && (param->rc.zoneCount || param->rc.zonefileCount))
1020 {
1021 for (int i = 0; i < param->rc.zonefileCount; i++)
1022 x265_free(param->rc.zones[i].zoneParam);
1023 x265_free(param->rc.zones);
1024 }
1025 }
1026
1027 static const x265_api libapi =
1028 {
1029 X265_MAJOR_VERSION,
1030 X265_BUILD,
1031 sizeof(x265_param),
1032 sizeof(x265_picture),
1033 sizeof(x265_analysis_data),
1034 sizeof(x265_zone),
1035 sizeof(x265_stats),
1036
1037 PFX(max_bit_depth),
1038 PFX(version_str),
1039 PFX(build_info_str),
1040
1041 &PARAM_NS::x265_param_alloc,
1042 &PARAM_NS::x265_param_free,
1043 &PARAM_NS::x265_param_default,
1044 &PARAM_NS::x265_param_parse,
1045 &PARAM_NS::x265_param_apply_profile,
1046 &PARAM_NS::x265_param_default_preset,
1047 &x265_picture_alloc,
1048 &x265_picture_free,
1049 &x265_picture_init,
1050 &x265_encoder_open,
1051 &x265_encoder_parameters,
1052 &x265_encoder_reconfig,
1053 &x265_encoder_reconfig_zone,
1054 &x265_encoder_headers,
1055 &x265_encoder_encode,
1056 &x265_encoder_get_stats,
1057 &x265_encoder_log,
1058 &x265_encoder_close,
1059 &x265_cleanup,
1060
1061 sizeof(x265_frame_stats),
1062 &x265_encoder_intra_refresh,
1063 &x265_encoder_ctu_info,
1064 &x265_get_slicetype_poc_and_scenecut,
1065 &x265_get_ref_frame_list,
1066 &x265_csvlog_open,
1067 &x265_csvlog_frame,
1068 &x265_csvlog_encode,
1069 &x265_dither_image,
1070 &x265_set_analysis_data,
1071 #if ENABLE_LIBVMAF
1072 &x265_calculate_vmafscore,
1073 &x265_calculate_vmaf_framelevelscore,
1074 &x265_vmaf_encoder_log,
1075 #endif
1076 &PARAM_NS::x265_zone_param_parse
1077 };
1078
1079 typedef const x265_api* (*api_get_func)(int bitDepth);
1080 typedef const x265_api* (*api_query_func)(int bitDepth, int apiVersion, int* err);
1081
1082 #define xstr(s) str(s)
1083 #define str(s) #s
1084
1085 #if _WIN32
1086 #define ext ".dll"
1087 #elif MACOS
1088 #include <dlfcn.h>
1089 #define ext ".dylib"
1090 #else
1091 #include <dlfcn.h>
1092 #define ext ".so"
1093 #endif
1094 #if defined(__GNUC__) && __GNUC__ >= 8
1095 #pragma GCC diagnostic ignored "-Wcast-function-type"
1096 #endif
1097
1098 static int g_recursion /* = 0 */;
x265_api_get(int bitDepth)1099 const x265_api* x265_api_get(int bitDepth)
1100 {
1101 if (bitDepth && bitDepth != X265_DEPTH)
1102 {
1103 #if LINKED_8BIT
1104 if (bitDepth == 8) return x265_8bit::x265_api_get(0);
1105 #endif
1106 #if LINKED_10BIT
1107 if (bitDepth == 10) return x265_10bit::x265_api_get(0);
1108 #endif
1109 #if LINKED_12BIT
1110 if (bitDepth == 12) return x265_12bit::x265_api_get(0);
1111 #endif
1112
1113 const char* libname = NULL;
1114 const char* method = "x265_api_get_" xstr(X265_BUILD);
1115 const char* multilibname = "libx265" ext;
1116
1117 if (bitDepth == 12)
1118 libname = "libx265_main12" ext;
1119 else if (bitDepth == 10)
1120 libname = "libx265_main10" ext;
1121 else if (bitDepth == 8)
1122 libname = "libx265_main" ext;
1123 else
1124 return NULL;
1125
1126 const x265_api* api = NULL;
1127 int reqDepth = 0;
1128
1129 if (g_recursion > 1)
1130 return NULL;
1131 else
1132 g_recursion++;
1133
1134 #if _WIN32
1135 HMODULE h = LoadLibraryA(libname);
1136 if (!h)
1137 {
1138 h = LoadLibraryA(multilibname);
1139 reqDepth = bitDepth;
1140 }
1141 if (h)
1142 {
1143 api_get_func get = (api_get_func)GetProcAddress(h, method);
1144 if (get)
1145 api = get(reqDepth);
1146 }
1147 #else
1148 void* h = dlopen(libname, RTLD_LAZY | RTLD_LOCAL);
1149 if (!h)
1150 {
1151 h = dlopen(multilibname, RTLD_LAZY | RTLD_LOCAL);
1152 reqDepth = bitDepth;
1153 }
1154 if (h)
1155 {
1156 api_get_func get = (api_get_func)dlsym(h, method);
1157 if (get)
1158 api = get(reqDepth);
1159 }
1160 #endif
1161
1162 g_recursion--;
1163
1164 if (api && bitDepth != api->bit_depth)
1165 {
1166 x265_log(NULL, X265_LOG_WARNING, "%s does not support requested bitDepth %d\n", libname, bitDepth);
1167 return NULL;
1168 }
1169
1170 return api;
1171 }
1172
1173 return &libapi;
1174 }
1175
x265_api_query(int bitDepth,int apiVersion,int * err)1176 const x265_api* x265_api_query(int bitDepth, int apiVersion, int* err)
1177 {
1178 if (apiVersion < 51)
1179 {
1180 /* builds before 1.6 had re-ordered public structs */
1181 if (err) *err = X265_API_QUERY_ERR_VER_REFUSED;
1182 return NULL;
1183 }
1184
1185 if (err) *err = X265_API_QUERY_ERR_NONE;
1186
1187 if (bitDepth && bitDepth != X265_DEPTH)
1188 {
1189 #if LINKED_8BIT
1190 if (bitDepth == 8) return x265_8bit::x265_api_query(0, apiVersion, err);
1191 #endif
1192 #if LINKED_10BIT
1193 if (bitDepth == 10) return x265_10bit::x265_api_query(0, apiVersion, err);
1194 #endif
1195 #if LINKED_12BIT
1196 if (bitDepth == 12) return x265_12bit::x265_api_query(0, apiVersion, err);
1197 #endif
1198
1199 const char* libname = NULL;
1200 const char* method = "x265_api_query";
1201 const char* multilibname = "libx265" ext;
1202
1203 if (bitDepth == 12)
1204 libname = "libx265_main12" ext;
1205 else if (bitDepth == 10)
1206 libname = "libx265_main10" ext;
1207 else if (bitDepth == 8)
1208 libname = "libx265_main" ext;
1209 else
1210 {
1211 if (err) *err = X265_API_QUERY_ERR_LIB_NOT_FOUND;
1212 return NULL;
1213 }
1214
1215 const x265_api* api = NULL;
1216 int reqDepth = 0;
1217 int e = X265_API_QUERY_ERR_LIB_NOT_FOUND;
1218
1219 if (g_recursion > 1)
1220 {
1221 if (err) *err = X265_API_QUERY_ERR_LIB_NOT_FOUND;
1222 return NULL;
1223 }
1224 else
1225 g_recursion++;
1226
1227 #if _WIN32
1228 HMODULE h = LoadLibraryA(libname);
1229 if (!h)
1230 {
1231 h = LoadLibraryA(multilibname);
1232 reqDepth = bitDepth;
1233 }
1234 if (h)
1235 {
1236 e = X265_API_QUERY_ERR_FUNC_NOT_FOUND;
1237 api_query_func query = (api_query_func)GetProcAddress(h, method);
1238 if (query)
1239 api = query(reqDepth, apiVersion, err);
1240 }
1241 #else
1242 void* h = dlopen(libname, RTLD_LAZY | RTLD_LOCAL);
1243 if (!h)
1244 {
1245 h = dlopen(multilibname, RTLD_LAZY | RTLD_LOCAL);
1246 reqDepth = bitDepth;
1247 }
1248 if (h)
1249 {
1250 e = X265_API_QUERY_ERR_FUNC_NOT_FOUND;
1251 api_query_func query = (api_query_func)dlsym(h, method);
1252 if (query)
1253 api = query(reqDepth, apiVersion, err);
1254 }
1255 #endif
1256
1257 g_recursion--;
1258
1259 if (api && bitDepth != api->bit_depth)
1260 {
1261 x265_log(NULL, X265_LOG_WARNING, "%s does not support requested bitDepth %d\n", libname, bitDepth);
1262 if (err) *err = X265_API_QUERY_ERR_WRONG_BITDEPTH;
1263 return NULL;
1264 }
1265
1266 if (err) *err = api ? X265_API_QUERY_ERR_NONE : e;
1267 return api;
1268 }
1269
1270 return &libapi;
1271 }
1272
x265_csvlog_open(const x265_param * param)1273 FILE* x265_csvlog_open(const x265_param* param)
1274 {
1275 FILE *csvfp = x265_fopen(param->csvfn, "r");
1276 if (csvfp)
1277 {
1278 /* file already exists, re-open for append */
1279 fclose(csvfp);
1280 return x265_fopen(param->csvfn, "ab");
1281 }
1282 else
1283 {
1284 /* new CSV file, write header */
1285 csvfp = x265_fopen(param->csvfn, "wb");
1286 if (csvfp)
1287 {
1288 if (param->csvLogLevel)
1289 {
1290 fprintf(csvfp, "Encode Order, Type, POC, QP, Bits, Scenecut, ");
1291 if (param->csvLogLevel >= 2)
1292 fprintf(csvfp, "I/P cost ratio, ");
1293 if (param->rc.rateControlMode == X265_RC_CRF)
1294 fprintf(csvfp, "RateFactor, ");
1295 if (param->rc.vbvBufferSize)
1296 fprintf(csvfp, "BufferFill, BufferFillFinal, ");
1297 if (param->rc.vbvBufferSize && param->csvLogLevel >= 2)
1298 fprintf(csvfp, "UnclippedBufferFillFinal, ");
1299 if (param->bEnablePsnr)
1300 fprintf(csvfp, "Y PSNR, U PSNR, V PSNR, YUV PSNR, ");
1301 if (param->bEnableSsim)
1302 fprintf(csvfp, "SSIM, SSIM(dB), ");
1303 fprintf(csvfp, "Latency, ");
1304 fprintf(csvfp, "List 0, List 1");
1305 uint32_t size = param->maxCUSize;
1306 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1307 {
1308 fprintf(csvfp, ", Intra %dx%d DC, Intra %dx%d Planar, Intra %dx%d Ang", size, size, size, size, size, size);
1309 size /= 2;
1310 }
1311 fprintf(csvfp, ", 4x4");
1312 size = param->maxCUSize;
1313 if (param->bEnableRectInter)
1314 {
1315 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1316 {
1317 fprintf(csvfp, ", Inter %dx%d, Inter %dx%d (Rect)", size, size, size, size);
1318 if (param->bEnableAMP)
1319 fprintf(csvfp, ", Inter %dx%d (Amp)", size, size);
1320 size /= 2;
1321 }
1322 }
1323 else
1324 {
1325 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1326 {
1327 fprintf(csvfp, ", Inter %dx%d", size, size);
1328 size /= 2;
1329 }
1330 }
1331 size = param->maxCUSize;
1332 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1333 {
1334 fprintf(csvfp, ", Skip %dx%d", size, size);
1335 size /= 2;
1336 }
1337 size = param->maxCUSize;
1338 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1339 {
1340 fprintf(csvfp, ", Merge %dx%d", size, size);
1341 size /= 2;
1342 }
1343
1344 if (param->csvLogLevel >= 2)
1345 {
1346 fprintf(csvfp, ", Avg Luma Distortion, Avg Chroma Distortion, Avg psyEnergy, Avg Residual Energy,"
1347 " Min Luma Level, Max Luma Level, Avg Luma Level");
1348
1349 if (param->internalCsp != X265_CSP_I400)
1350 fprintf(csvfp, ", Min Cb Level, Max Cb Level, Avg Cb Level, Min Cr Level, Max Cr Level, Avg Cr Level");
1351
1352 /* PU statistics */
1353 size = param->maxCUSize;
1354 for (uint32_t i = 0; i< param->maxLog2CUSize - (uint32_t)g_log2Size[param->minCUSize] + 1; i++)
1355 {
1356 fprintf(csvfp, ", Intra %dx%d", size, size);
1357 fprintf(csvfp, ", Skip %dx%d", size, size);
1358 fprintf(csvfp, ", AMP %d", size);
1359 fprintf(csvfp, ", Inter %dx%d", size, size);
1360 fprintf(csvfp, ", Merge %dx%d", size, size);
1361 fprintf(csvfp, ", Inter %dx%d", size, size / 2);
1362 fprintf(csvfp, ", Merge %dx%d", size, size / 2);
1363 fprintf(csvfp, ", Inter %dx%d", size / 2, size);
1364 fprintf(csvfp, ", Merge %dx%d", size / 2, size);
1365 size /= 2;
1366 }
1367
1368 if ((uint32_t)g_log2Size[param->minCUSize] == 3)
1369 fprintf(csvfp, ", 4x4");
1370
1371 /* detailed performance statistics */
1372 fprintf(csvfp, ", DecideWait (ms), Row0Wait (ms), Wall time (ms), Ref Wait Wall (ms), Total CTU time (ms),"
1373 "Stall Time (ms), Total frame time (ms), Avg WPP, Row Blocks");
1374 #if ENABLE_LIBVMAF
1375 fprintf(csvfp, ", VMAF Frame Score");
1376 #endif
1377 }
1378 fprintf(csvfp, "\n");
1379 }
1380 else
1381 {
1382 fputs(summaryCSVHeader, csvfp);
1383 if (param->csvLogLevel >= 2 || param->maxCLL || param->maxFALL)
1384 fputs("MaxCLL, MaxFALL,", csvfp);
1385 #if ENABLE_LIBVMAF
1386 fputs(" Aggregate VMAF Score,", csvfp);
1387 #endif
1388 fputs(" Version\n", csvfp);
1389 }
1390 }
1391 return csvfp;
1392 }
1393 }
1394
1395 // per frame CSV logging
x265_csvlog_frame(const x265_param * param,const x265_picture * pic)1396 void x265_csvlog_frame(const x265_param* param, const x265_picture* pic)
1397 {
1398 if (!param->csvfpt)
1399 return;
1400
1401 const x265_frame_stats* frameStats = &pic->frameData;
1402 fprintf(param->csvfpt, "%d, %c-SLICE, %4d, %2.2lf, %10d, %d,", frameStats->encoderOrder, frameStats->sliceType, frameStats->poc,
1403 frameStats->qp, (int)frameStats->bits, frameStats->bScenecut);
1404 if (param->csvLogLevel >= 2)
1405 fprintf(param->csvfpt, "%.2f,", frameStats->ipCostRatio);
1406 if (param->rc.rateControlMode == X265_RC_CRF)
1407 fprintf(param->csvfpt, "%.3lf,", frameStats->rateFactor);
1408 if (param->rc.vbvBufferSize)
1409 fprintf(param->csvfpt, "%.3lf, %.3lf,", frameStats->bufferFill, frameStats->bufferFillFinal);
1410 if (param->rc.vbvBufferSize && param->csvLogLevel >= 2)
1411 fprintf(param->csvfpt, "%.3lf,", frameStats->unclippedBufferFillFinal);
1412 if (param->bEnablePsnr)
1413 fprintf(param->csvfpt, "%.3lf, %.3lf, %.3lf, %.3lf,", frameStats->psnrY, frameStats->psnrU, frameStats->psnrV, frameStats->psnr);
1414 if (param->bEnableSsim)
1415 fprintf(param->csvfpt, " %.6f, %6.3f,", frameStats->ssim, x265_ssim2dB(frameStats->ssim));
1416 fprintf(param->csvfpt, "%d, ", frameStats->frameLatency);
1417 if (frameStats->sliceType == 'I' || frameStats->sliceType == 'i')
1418 fputs(" -, -,", param->csvfpt);
1419 else
1420 {
1421 int i = 0;
1422 while (frameStats->list0POC[i] != -1)
1423 fprintf(param->csvfpt, "%d ", frameStats->list0POC[i++]);
1424 fprintf(param->csvfpt, ",");
1425 if (frameStats->sliceType != 'P')
1426 {
1427 i = 0;
1428 while (frameStats->list1POC[i] != -1)
1429 fprintf(param->csvfpt, "%d ", frameStats->list1POC[i++]);
1430 fprintf(param->csvfpt, ",");
1431 }
1432 else
1433 fputs(" -,", param->csvfpt);
1434 }
1435
1436 if (param->csvLogLevel)
1437 {
1438 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1439 fprintf(param->csvfpt, "%5.2lf%%, %5.2lf%%, %5.2lf%%,", frameStats->cuStats.percentIntraDistribution[depth][0],
1440 frameStats->cuStats.percentIntraDistribution[depth][1],
1441 frameStats->cuStats.percentIntraDistribution[depth][2]);
1442 fprintf(param->csvfpt, "%5.2lf%%", frameStats->cuStats.percentIntraNxN);
1443 if (param->bEnableRectInter)
1444 {
1445 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1446 {
1447 fprintf(param->csvfpt, ", %5.2lf%%, %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][0],
1448 frameStats->cuStats.percentInterDistribution[depth][1]);
1449 if (param->bEnableAMP)
1450 fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][2]);
1451 }
1452 }
1453 else
1454 {
1455 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1456 fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][0]);
1457 }
1458 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1459 fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentSkipCu[depth]);
1460 for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1461 fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentMergeCu[depth]);
1462 }
1463
1464 if (param->csvLogLevel >= 2)
1465 {
1466 fprintf(param->csvfpt, ", %.2lf, %.2lf, %.2lf, %.2lf ", frameStats->avgLumaDistortion,
1467 frameStats->avgChromaDistortion,
1468 frameStats->avgPsyEnergy,
1469 frameStats->avgResEnergy);
1470
1471 fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minLumaLevel, frameStats->maxLumaLevel, frameStats->avgLumaLevel);
1472
1473 if (param->internalCsp != X265_CSP_I400)
1474 {
1475 fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minChromaULevel, frameStats->maxChromaULevel, frameStats->avgChromaULevel);
1476 fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minChromaVLevel, frameStats->maxChromaVLevel, frameStats->avgChromaVLevel);
1477 }
1478
1479 for (uint32_t i = 0; i < param->maxLog2CUSize - (uint32_t)g_log2Size[param->minCUSize] + 1; i++)
1480 {
1481 fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentIntraPu[i]);
1482 fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentSkipPu[i]);
1483 fprintf(param->csvfpt, ",%.2lf%%", frameStats->puStats.percentAmpPu[i]);
1484 for (uint32_t j = 0; j < 3; j++)
1485 {
1486 fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentInterPu[i][j]);
1487 fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentMergePu[i][j]);
1488 }
1489 }
1490 if ((uint32_t)g_log2Size[param->minCUSize] == 3)
1491 fprintf(param->csvfpt, ",%.2lf%%", frameStats->puStats.percentNxN);
1492
1493 fprintf(param->csvfpt, ", %.1lf, %.1lf, %.1lf, %.1lf, %.1lf, %.1lf, %.1lf,", frameStats->decideWaitTime, frameStats->row0WaitTime,
1494 frameStats->wallTime, frameStats->refWaitWallTime,
1495 frameStats->totalCTUTime, frameStats->stallTime,
1496 frameStats->totalFrameTime);
1497
1498 fprintf(param->csvfpt, " %.3lf, %d", frameStats->avgWPP, frameStats->countRowBlocks);
1499 #if ENABLE_LIBVMAF
1500 fprintf(param->csvfpt, ", %lf", frameStats->vmafFrameScore);
1501 #endif
1502 }
1503 fprintf(param->csvfpt, "\n");
1504 fflush(stderr);
1505 }
1506
x265_csvlog_encode(const x265_param * p,const x265_stats * stats,int padx,int pady,int argc,char ** argv)1507 void x265_csvlog_encode(const x265_param *p, const x265_stats *stats, int padx, int pady, int argc, char** argv)
1508 {
1509 if (p && p->csvfpt)
1510 {
1511 const x265_api * api = x265_api_get(0);
1512
1513 if (p->csvLogLevel)
1514 {
1515 // adding summary to a per-frame csv log file, so it needs a summary header
1516 fprintf(p->csvfpt, "\nSummary\n");
1517 fputs(summaryCSVHeader, p->csvfpt);
1518 if (p->csvLogLevel >= 2 || p->maxCLL || p->maxFALL)
1519 fputs("MaxCLL, MaxFALL,", p->csvfpt);
1520 #if ENABLE_LIBVMAF
1521 fputs(" Aggregate VMAF score,", p->csvfpt);
1522 #endif
1523 fputs(" Version\n",p->csvfpt);
1524
1525 }
1526 // CLI arguments or other
1527 if (argc)
1528 {
1529 fputc('"', p->csvfpt);
1530 for (int i = 1; i < argc; i++)
1531 {
1532 fputc(' ', p->csvfpt);
1533 fputs(argv[i], p->csvfpt);
1534 }
1535 fputc('"', p->csvfpt);
1536 }
1537 else
1538 {
1539 char *opts = x265_param2string((x265_param*)p, padx, pady);
1540 if (opts)
1541 {
1542 fputc('"', p->csvfpt);
1543 fputs(opts, p->csvfpt);
1544 fputc('"', p->csvfpt);
1545 X265_FREE(opts);
1546 }
1547 }
1548
1549 // current date and time
1550 time_t now;
1551 struct tm* timeinfo;
1552 time(&now);
1553 timeinfo = localtime(&now);
1554 char buffer[200];
1555 strftime(buffer, 128, "%c", timeinfo);
1556 fprintf(p->csvfpt, ", %s, ", buffer);
1557 // elapsed time, fps, bitrate
1558 fprintf(p->csvfpt, "%.2f, %.2f, %.2f,",
1559 stats->elapsedEncodeTime, stats->encodedPictureCount / stats->elapsedEncodeTime, stats->bitrate);
1560
1561 if (p->bEnablePsnr)
1562 fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf, %.3lf,",
1563 stats->globalPsnrY / stats->encodedPictureCount, stats->globalPsnrU / stats->encodedPictureCount,
1564 stats->globalPsnrV / stats->encodedPictureCount, stats->globalPsnr);
1565 else
1566 fprintf(p->csvfpt, " -, -, -, -,");
1567 if (p->bEnableSsim)
1568 fprintf(p->csvfpt, " %.6f, %6.3f,", stats->globalSsim, x265_ssim2dB(stats->globalSsim));
1569 else
1570 fprintf(p->csvfpt, " -, -,");
1571
1572 if (stats->statsI.numPics)
1573 {
1574 fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsI.numPics, stats->statsI.avgQp, stats->statsI.bitrate);
1575 if (p->bEnablePsnr)
1576 fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsI.psnrY, stats->statsI.psnrU, stats->statsI.psnrV);
1577 else
1578 fprintf(p->csvfpt, " -, -, -,");
1579 if (p->bEnableSsim)
1580 fprintf(p->csvfpt, " %.3lf,", stats->statsI.ssim);
1581 else
1582 fprintf(p->csvfpt, " -,");
1583 }
1584 else
1585 fprintf(p->csvfpt, " -, -, -, -, -, -, -,");
1586
1587 if (stats->statsP.numPics)
1588 {
1589 fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsP.numPics, stats->statsP.avgQp, stats->statsP.bitrate);
1590 if (p->bEnablePsnr)
1591 fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsP.psnrY, stats->statsP.psnrU, stats->statsP.psnrV);
1592 else
1593 fprintf(p->csvfpt, " -, -, -,");
1594 if (p->bEnableSsim)
1595 fprintf(p->csvfpt, " %.3lf,", stats->statsP.ssim);
1596 else
1597 fprintf(p->csvfpt, " -,");
1598 }
1599 else
1600 fprintf(p->csvfpt, " -, -, -, -, -, -, -,");
1601
1602 if (stats->statsB.numPics)
1603 {
1604 fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsB.numPics, stats->statsB.avgQp, stats->statsB.bitrate);
1605 if (p->bEnablePsnr)
1606 fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsB.psnrY, stats->statsB.psnrU, stats->statsB.psnrV);
1607 else
1608 fprintf(p->csvfpt, " -, -, -,");
1609 if (p->bEnableSsim)
1610 fprintf(p->csvfpt, " %.3lf,", stats->statsB.ssim);
1611 else
1612 fprintf(p->csvfpt, " -,");
1613 }
1614 else
1615 fprintf(p->csvfpt, " -, -, -, -, -, -, -,");
1616 if (p->csvLogLevel >= 2 || p->maxCLL || p->maxFALL)
1617 fprintf(p->csvfpt, " %-6u, %-6u,", stats->maxCLL, stats->maxFALL);
1618 #if ENABLE_LIBVMAF
1619 fprintf(p->csvfpt, " %lf,", stats->aggregateVmafScore);
1620 #endif
1621 fprintf(p->csvfpt, " %s\n", api->version_str);
1622
1623 }
1624 }
1625
1626 /* The dithering algorithm is based on Sierra-2-4A error diffusion.
1627 * 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)1628 static void ditherPlane(uint16_t *src, int srcStride, int width, int height, int16_t *errors, int bitDepth)
1629 {
1630 const int lShift = 16 - bitDepth;
1631 const int rShift = 16 - bitDepth + 2;
1632 const int half = (1 << (16 - bitDepth + 1));
1633 const int pixelMax = (1 << bitDepth) - 1;
1634
1635 memset(errors, 0, (width + 1) * sizeof(int16_t));
1636
1637 if (bitDepth == 8)
1638 {
1639 for (int y = 0; y < height; y++, src += srcStride)
1640 {
1641 uint8_t* dst = (uint8_t *)src;
1642 int16_t err = 0;
1643 for (int x = 0; x < width; x++)
1644 {
1645 err = err * 2 + errors[x] + errors[x + 1];
1646 int tmpDst = x265_clip3(0, pixelMax, ((src[x] << 2) + err + half) >> rShift);
1647 errors[x] = err = (int16_t)(src[x] - (tmpDst << lShift));
1648 dst[x] = (uint8_t)tmpDst;
1649 }
1650 }
1651 }
1652 else
1653 {
1654 for (int y = 0; y < height; y++, src += srcStride)
1655 {
1656 int16_t err = 0;
1657 for (int x = 0; x < width; x++)
1658 {
1659 err = err * 2 + errors[x] + errors[x + 1];
1660 int tmpDst = x265_clip3(0, pixelMax, ((src[x] << 2) + err + half) >> rShift);
1661 errors[x] = err = (int16_t)(src[x] - (tmpDst << lShift));
1662 src[x] = (uint16_t)tmpDst;
1663 }
1664 }
1665 }
1666 }
1667
x265_dither_image(x265_picture * picIn,int picWidth,int picHeight,int16_t * errorBuf,int bitDepth)1668 void x265_dither_image(x265_picture* picIn, int picWidth, int picHeight, int16_t *errorBuf, int bitDepth)
1669 {
1670 const x265_api* api = x265_api_get(0);
1671
1672 if (sizeof(x265_picture) != api->sizeof_picture)
1673 {
1674 fprintf(stderr, "extras [error]: structure size skew, unable to dither\n");
1675 return;
1676 }
1677
1678 if (picIn->bitDepth <= 8)
1679 {
1680 fprintf(stderr, "extras [error]: dither support enabled only for input bitdepth > 8\n");
1681 return;
1682 }
1683
1684 if (picIn->bitDepth == bitDepth)
1685 {
1686 fprintf(stderr, "extras[error]: dither support enabled only if encoder depth is different from picture depth\n");
1687 return;
1688 }
1689
1690 /* This portion of code is from readFrame in x264. */
1691 for (int i = 0; i < x265_cli_csps[picIn->colorSpace].planes; i++)
1692 {
1693 if (picIn->bitDepth < 16)
1694 {
1695 /* upconvert non 16bit high depth planes to 16bit */
1696 uint16_t *plane = (uint16_t*)picIn->planes[i];
1697 uint32_t pixelCount = x265_picturePlaneSize(picIn->colorSpace, picWidth, picHeight, i);
1698 int lShift = 16 - picIn->bitDepth;
1699
1700 /* This loop assumes width is equal to stride which
1701 * happens to be true for file reader outputs */
1702 for (uint32_t j = 0; j < pixelCount; j++)
1703 plane[j] = plane[j] << lShift;
1704 }
1705
1706 int height = (int)(picHeight >> x265_cli_csps[picIn->colorSpace].height[i]);
1707 int width = (int)(picWidth >> x265_cli_csps[picIn->colorSpace].width[i]);
1708
1709 ditherPlane(((uint16_t*)picIn->planes[i]), picIn->stride[i] / 2, width, height, errorBuf, bitDepth);
1710 }
1711 }
1712
1713 #if ENABLE_LIBVMAF
1714 /* Read y values of single frame for 8-bit input */
read_image_byte(FILE * file,float * buf,int width,int height,int stride)1715 int read_image_byte(FILE *file, float *buf, int width, int height, int stride)
1716 {
1717 char *byte_ptr = (char *)buf;
1718 unsigned char *tmp_buf = 0;
1719 int i, j;
1720 int ret = 1;
1721
1722 if (width <= 0 || height <= 0)
1723 {
1724 goto fail_or_end;
1725 }
1726
1727 if (!(tmp_buf = (unsigned char*)malloc(width)))
1728 {
1729 goto fail_or_end;
1730 }
1731
1732 for (i = 0; i < height; ++i)
1733 {
1734 float *row_ptr = (float *)byte_ptr;
1735
1736 if (fread(tmp_buf, 1, width, file) != (size_t)width)
1737 {
1738 goto fail_or_end;
1739 }
1740
1741 for (j = 0; j < width; ++j)
1742 {
1743 row_ptr[j] = tmp_buf[j];
1744 }
1745
1746 byte_ptr += stride;
1747 }
1748
1749 ret = 0;
1750
1751 fail_or_end:
1752 free(tmp_buf);
1753 return ret;
1754 }
1755 /* Read y values of single frame for 10-bit input */
read_image_word(FILE * file,float * buf,int width,int height,int stride)1756 int read_image_word(FILE *file, float *buf, int width, int height, int stride)
1757 {
1758 char *byte_ptr = (char *)buf;
1759 unsigned short *tmp_buf = 0;
1760 int i, j;
1761 int ret = 1;
1762
1763 if (width <= 0 || height <= 0)
1764 {
1765 goto fail_or_end;
1766 }
1767
1768 if (!(tmp_buf = (unsigned short*)malloc(width * 2))) // '*2' to accommodate words
1769 {
1770 goto fail_or_end;
1771 }
1772
1773 for (i = 0; i < height; ++i)
1774 {
1775 float *row_ptr = (float *)byte_ptr;
1776
1777 if (fread(tmp_buf, 2, width, file) != (size_t)width) // '2' for word
1778 {
1779 goto fail_or_end;
1780 }
1781
1782 for (j = 0; j < width; ++j)
1783 {
1784 row_ptr[j] = tmp_buf[j] / 4.0; // '/4' to convert from 10 to 8-bit
1785 }
1786
1787 byte_ptr += stride;
1788 }
1789
1790 ret = 0;
1791
1792 fail_or_end:
1793 free(tmp_buf);
1794 return ret;
1795 }
1796
read_frame(float * reference_data,float * distorted_data,float * temp_data,int stride_byte,void * s)1797 int read_frame(float *reference_data, float *distorted_data, float *temp_data, int stride_byte, void *s)
1798 {
1799 x265_vmaf_data *user_data = (x265_vmaf_data *)s;
1800 int ret;
1801
1802 // read reference y
1803 if (user_data->internalBitDepth == 8)
1804 {
1805 ret = read_image_byte(user_data->reference_file, reference_data, user_data->width, user_data->height, stride_byte);
1806 }
1807 else if (user_data->internalBitDepth == 10)
1808 {
1809 ret = read_image_word(user_data->reference_file, reference_data, user_data->width, user_data->height, stride_byte);
1810 }
1811 else
1812 {
1813 x265_log(NULL, X265_LOG_ERROR, "Invalid bitdepth\n");
1814 return 1;
1815 }
1816 if (ret)
1817 {
1818 if (feof(user_data->reference_file))
1819 {
1820 ret = 2; // OK if end of file
1821 }
1822 return ret;
1823 }
1824
1825 // read distorted y
1826 if (user_data->internalBitDepth == 8)
1827 {
1828 ret = read_image_byte(user_data->distorted_file, distorted_data, user_data->width, user_data->height, stride_byte);
1829 }
1830 else if (user_data->internalBitDepth == 10)
1831 {
1832 ret = read_image_word(user_data->distorted_file, distorted_data, user_data->width, user_data->height, stride_byte);
1833 }
1834 else
1835 {
1836 x265_log(NULL, X265_LOG_ERROR, "Invalid bitdepth\n");
1837 return 1;
1838 }
1839 if (ret)
1840 {
1841 if (feof(user_data->distorted_file))
1842 {
1843 ret = 2; // OK if end of file
1844 }
1845 return ret;
1846 }
1847
1848 // reference skip u and v
1849 if (user_data->internalBitDepth == 8)
1850 {
1851 if (fread(temp_data, 1, user_data->offset, user_data->reference_file) != (size_t)user_data->offset)
1852 {
1853 x265_log(NULL, X265_LOG_ERROR, "reference fread to skip u and v failed.\n");
1854 goto fail_or_end;
1855 }
1856 }
1857 else if (user_data->internalBitDepth == 10)
1858 {
1859 if (fread(temp_data, 2, user_data->offset, user_data->reference_file) != (size_t)user_data->offset)
1860 {
1861 x265_log(NULL, X265_LOG_ERROR, "reference fread to skip u and v failed.\n");
1862 goto fail_or_end;
1863 }
1864 }
1865 else
1866 {
1867 x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");
1868 goto fail_or_end;
1869 }
1870
1871 // distorted skip u and v
1872 if (user_data->internalBitDepth == 8)
1873 {
1874 if (fread(temp_data, 1, user_data->offset, user_data->distorted_file) != (size_t)user_data->offset)
1875 {
1876 x265_log(NULL, X265_LOG_ERROR, "distorted fread to skip u and v failed.\n");
1877 goto fail_or_end;
1878 }
1879 }
1880 else if (user_data->internalBitDepth == 10)
1881 {
1882 if (fread(temp_data, 2, user_data->offset, user_data->distorted_file) != (size_t)user_data->offset)
1883 {
1884 x265_log(NULL, X265_LOG_ERROR, "distorted fread to skip u and v failed.\n");
1885 goto fail_or_end;
1886 }
1887 }
1888 else
1889 {
1890 x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");
1891 goto fail_or_end;
1892 }
1893
1894
1895 fail_or_end:
1896 return ret;
1897 }
1898
x265_calculate_vmafscore(x265_param * param,x265_vmaf_data * data)1899 double x265_calculate_vmafscore(x265_param *param, x265_vmaf_data *data)
1900 {
1901 double score;
1902
1903 data->width = param->sourceWidth;
1904 data->height = param->sourceHeight;
1905 data->internalBitDepth = param->internalBitDepth;
1906
1907 if (param->internalCsp == X265_CSP_I420)
1908 {
1909 if ((param->sourceWidth * param->sourceHeight) % 2 != 0)
1910 x265_log(NULL, X265_LOG_ERROR, "Invalid file size\n");
1911 data->offset = param->sourceWidth * param->sourceHeight / 2;
1912 }
1913 else if (param->internalCsp == X265_CSP_I422)
1914 data->offset = param->sourceWidth * param->sourceHeight;
1915 else if (param->internalCsp == X265_CSP_I444)
1916 data->offset = param->sourceWidth * param->sourceHeight * 2;
1917 else
1918 x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");
1919
1920 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);
1921
1922 return score;
1923 }
1924
read_frame_10bit(float * reference_data,float * distorted_data,float * temp_data,int stride,void * s)1925 int read_frame_10bit(float *reference_data, float *distorted_data, float *temp_data, int stride, void *s)
1926 {
1927 x265_vmaf_framedata *user_data = (x265_vmaf_framedata *)s;
1928
1929 PicYuv *reference_frame = (PicYuv *)user_data->reference_frame;
1930 PicYuv *distorted_frame = (PicYuv *)user_data->distorted_frame;
1931
1932 if(!user_data->frame_set) {
1933
1934 int reference_stride = reference_frame->m_stride;
1935 int distorted_stride = distorted_frame->m_stride;
1936
1937 const uint16_t *reference_ptr = (const uint16_t *)reference_frame->m_picOrg[0];
1938 const uint16_t *distorted_ptr = (const uint16_t *)distorted_frame->m_picOrg[0];
1939
1940 temp_data = reference_data;
1941
1942 int height = user_data->height;
1943 int width = user_data->width;
1944
1945 int i,j;
1946 for (i = 0; i < height; i++) {
1947 for ( j = 0; j < width; j++) {
1948 temp_data[j] = ((float)reference_ptr[j] / 4.0);
1949 }
1950 reference_ptr += reference_stride;
1951 temp_data += stride / sizeof(*temp_data);
1952 }
1953
1954 temp_data = distorted_data;
1955 for (i = 0; i < height; i++) {
1956 for (j = 0; j < width; j++) {
1957 temp_data[j] = ((float)distorted_ptr[j] / 4.0);
1958 }
1959 distorted_ptr += distorted_stride;
1960 temp_data += stride / sizeof(*temp_data);
1961 }
1962
1963 user_data->frame_set = 1;
1964 return 0;
1965 }
1966 return 2;
1967 }
1968
read_frame_8bit(float * reference_data,float * distorted_data,float * temp_data,int stride,void * s)1969 int read_frame_8bit(float *reference_data, float *distorted_data, float *temp_data, int stride, void *s)
1970 {
1971 x265_vmaf_framedata *user_data = (x265_vmaf_framedata *)s;
1972
1973 PicYuv *reference_frame = (PicYuv *)user_data->reference_frame;
1974 PicYuv *distorted_frame = (PicYuv *)user_data->distorted_frame;
1975
1976 if(!user_data->frame_set) {
1977
1978 int reference_stride = reference_frame->m_stride;
1979 int distorted_stride = distorted_frame->m_stride;
1980
1981 const uint8_t *reference_ptr = (const uint8_t *)reference_frame->m_picOrg[0];
1982 const uint8_t *distorted_ptr = (const uint8_t *)distorted_frame->m_picOrg[0];
1983
1984 temp_data = reference_data;
1985
1986 int height = user_data->height;
1987 int width = user_data->width;
1988
1989 int i,j;
1990 for (i = 0; i < height; i++) {
1991 for ( j = 0; j < width; j++) {
1992 temp_data[j] = (float)reference_ptr[j];
1993 }
1994 reference_ptr += reference_stride;
1995 temp_data += stride / sizeof(*temp_data);
1996 }
1997
1998 temp_data = distorted_data;
1999 for (i = 0; i < height; i++) {
2000 for (j = 0; j < width; j++) {
2001 temp_data[j] = (float)distorted_ptr[j];
2002 }
2003 distorted_ptr += distorted_stride;
2004 temp_data += stride / sizeof(*temp_data);
2005 }
2006
2007 user_data->frame_set = 1;
2008 return 0;
2009 }
2010 return 2;
2011 }
2012
x265_calculate_vmaf_framelevelscore(x265_vmaf_framedata * vmafframedata)2013 double x265_calculate_vmaf_framelevelscore(x265_vmaf_framedata *vmafframedata)
2014 {
2015 double score;
2016 int (*read_frame)(float *reference_data, float *distorted_data, float *temp_data,
2017 int stride, void *s);
2018 if (vmafframedata->internalBitDepth == 8)
2019 read_frame = read_frame_8bit;
2020 else
2021 read_frame = read_frame_10bit;
2022 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);
2023
2024 return score;
2025 }
2026 #endif
2027
2028 } /* end namespace or extern "C" */
2029
2030 namespace X265_NS {
2031 #ifdef SVT_HEVC
2032
svt_initialise_app_context(x265_encoder * enc)2033 void svt_initialise_app_context(x265_encoder *enc)
2034 {
2035 Encoder *encoder = static_cast<Encoder*>(enc);
2036
2037 //Initialise Application Context
2038 encoder->m_svtAppData = (SvtAppContext*)x265_malloc(sizeof(SvtAppContext));
2039 encoder->m_svtAppData->svtHevcParams = (EB_H265_ENC_CONFIGURATION*)x265_malloc(sizeof(EB_H265_ENC_CONFIGURATION));
2040 encoder->m_svtAppData->byteCount = 0;
2041 encoder->m_svtAppData->outFrameCount = 0;
2042 }
2043
svt_initialise_input_buffer(x265_encoder * enc)2044 int svt_initialise_input_buffer(x265_encoder *enc)
2045 {
2046 Encoder *encoder = static_cast<Encoder*>(enc);
2047
2048 //Initialise Input Buffer
2049 encoder->m_svtAppData->inputPictureBuffer = (EB_BUFFERHEADERTYPE*)x265_malloc(sizeof(EB_BUFFERHEADERTYPE));
2050 EB_BUFFERHEADERTYPE *inputPtr = encoder->m_svtAppData->inputPictureBuffer;
2051 inputPtr->pBuffer = (unsigned char*)x265_malloc(sizeof(EB_H265_ENC_INPUT));
2052
2053 EB_H265_ENC_INPUT *inputData = (EB_H265_ENC_INPUT*)inputPtr->pBuffer;
2054 inputData->dolbyVisionRpu.payload = NULL;
2055 inputData->dolbyVisionRpu.payloadSize = 0;
2056
2057
2058 if (!inputPtr->pBuffer)
2059 return 0;
2060
2061 inputPtr->nSize = sizeof(EB_BUFFERHEADERTYPE);
2062 inputPtr->pAppPrivate = NULL;
2063 return 1;
2064 }
2065 #endif // ifdef SVT_HEVC
2066
2067 } // end namespace X265_NS
2068