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