Coverage Report

Created: 2026-03-08 06:41

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