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