Coverage Report

Created: 2025-07-23 08:18

/src/x265/source/encoder/api.cpp
Line
Count
Source (jump to first uncovered line)
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
0
{
77
0
    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
0
    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
0
    Encoder* encoder = new Encoder;
95
0
    encoder->m_paramBase[0] = PARAM_NS::x265_param_alloc();
96
0
    encoder->m_paramBase[1] = PARAM_NS::x265_param_alloc();
97
0
    encoder->m_paramBase[2] = PARAM_NS::x265_param_alloc();
98
99
0
    x265_param* param = encoder->m_paramBase[0];
100
0
    x265_param* latestParam = encoder->m_paramBase[1];
101
0
    x265_param* zoneParam = encoder->m_paramBase[2];
102
103
0
    if(param) PARAM_NS::x265_param_default(param);
104
0
    if(latestParam) PARAM_NS::x265_param_default(latestParam);
105
0
    if(zoneParam) PARAM_NS::x265_param_default(zoneParam);
106
  
107
0
    if (!param || !latestParam || !zoneParam)
108
0
        goto fail;
109
0
    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
0
    x265_copy_params(param, p);
118
0
    x265_copy_params(latestParam, p);
119
0
    x265_copy_params(zoneParam, p);
120
0
    x265_log(param, X265_LOG_INFO, "HEVC encoder version %s\n", PFX(version_str));
121
0
    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
0
    x265_setup_primitives(param);
171
172
0
    if (x265_check_params(param))
173
0
        goto fail;
174
175
0
    if (!param->rc.bEnableSlowFirstPass)
176
0
        PARAM_NS::x265_param_apply_fastfirstpass(param);
177
178
    // may change params for auto-detect, etc
179
0
    encoder->configure(param);
180
0
    if (encoder->m_aborted)
181
0
        goto fail;
182
    // may change rate control and CPB params
183
0
    if (!enforceLevel(*param, encoder->m_vps))
184
0
        goto fail;
185
186
    // will detect and set profile/tier/level in VPS
187
0
    determineLevel(*param, encoder->m_vps);
188
189
0
    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
0
    encoder->create();
196
0
    p->frameNumThreads = encoder->m_param->frameNumThreads;
197
198
0
    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
0
    x265_copy_params(zoneParam, param);
210
0
    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
0
    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
0
    encoder->m_latestParam = latestParam;
227
0
    encoder->m_zoneParam = zoneParam;
228
0
    x265_copy_params(latestParam, param);
229
0
    if (encoder->m_aborted)
230
0
        goto fail;
231
232
0
    x265_print_params(param);
233
0
    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
0
}
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
0
{
424
0
    if (!enc)
425
0
        return -1;
426
427
0
    Encoder *encoder = static_cast<Encoder*>(enc);
428
0
    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
0
    do
592
0
    {
593
0
        numEncoded = encoder->encode(pic_in, pic_out);
594
0
    }
595
0
    while ((numEncoded == 0 && !pic_in && encoder->m_numDelayedPic && !encoder->m_latestParam->forceFlush) && !encoder->m_externalFlush);
596
0
    if (numEncoded)
597
0
        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
0
    if (pic_in)
602
0
    {
603
0
        pic_in->analysisData.wt = NULL;
604
0
        pic_in->analysisData.intraData = NULL;
605
0
        pic_in->analysisData.interData = NULL;
606
0
        pic_in->analysisData.distortionData = NULL;
607
0
    }
608
609
0
    if (pp_nal && numEncoded > 0 && encoder->m_outputCount >= encoder->m_latestParam->chunkStart)
610
0
    {
611
0
        *pp_nal = &encoder->m_nalList.m_nal[0];
612
0
        if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
613
0
    }
614
0
    else if (pi_nal)
615
0
        *pi_nal = 0;
616
617
0
    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
0
    if (numEncoded < 0)
624
0
        encoder->m_aborted = true;
625
626
0
    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
0
    return numEncoded;
635
0
}
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
0
{
703
0
    if (enc)
704
0
    {
705
0
        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
0
        encoder->stopJobs();
737
0
        encoder->printSummary();
738
0
        encoder->destroy();
739
0
        delete encoder;
740
0
    }
741
0
}
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
0
{
995
0
}
996
997
x265_picture *x265_picture_alloc()
998
0
{
999
0
    return (x265_picture*)x265_malloc(sizeof(x265_picture));
1000
0
}
1001
1002
void x265_picture_init(x265_param *param, x265_picture *pic)
1003
0
{
1004
0
    memset(pic, 0, sizeof(x265_picture));
1005
1006
0
    pic->bitDepth = param->internalBitDepth;
1007
0
    pic->colorSpace = param->internalCsp;
1008
0
    pic->forceqp = X265_QP_AUTO;
1009
0
    pic->quantOffsets = NULL;
1010
0
    pic->userSEI.payloads = NULL;
1011
0
    pic->userSEI.numPayloads = 0;
1012
0
    pic->rpu.payloadSize = 0;
1013
0
    pic->rpu.payload = NULL;
1014
0
    pic->picStruct = 0;
1015
0
    pic->vbvEndFlag = 0;
1016
1017
0
    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
0
}
1027
1028
void x265_picture_free(x265_picture *p)
1029
0
{
1030
0
    return x265_free(p);
1031
0
}
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
0
{
1045
0
    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
0
}
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
0
{
1131
0
    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
0
    return &libapi;
1204
0
}
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
#if ENABLE_LIBVMAF
1407
                    fprintf(csvfp, ", VMAF Frame Score");
1408
#endif
1409
0
                    if (param->bConfigRCFrame)
1410
0
                    {
1411
0
                        if (param->rc.rateControlMode == X265_RC_ABR)
1412
0
                            fprintf(csvfp, ", Target bitrate");
1413
0
                        else if (param->rc.rateControlMode == X265_RC_CRF)
1414
0
                            fprintf(csvfp, ", Target CRF");
1415
0
                        else if (param->rc.rateControlMode == X265_RC_CQP)
1416
0
                            fprintf(csvfp, ", Target QP");
1417
0
                    }
1418
0
                }
1419
0
                fprintf(csvfp, "\n");
1420
0
            }
1421
0
            else
1422
0
            {
1423
0
                fputs(summaryCSVHeader, csvfp);
1424
0
                if (param->csvLogLevel >= 2 || param->maxCLL || param->maxFALL)
1425
0
                    fputs("MaxCLL, MaxFALL,", csvfp);
1426
#if ENABLE_LIBVMAF
1427
                fputs(" Aggregate VMAF Score,", csvfp);
1428
#endif
1429
0
                fputs(" Version\n", csvfp);
1430
0
            }
1431
0
        }
1432
0
        return csvfp;
1433
0
    }
1434
0
}
1435
1436
// per frame CSV logging
1437
void x265_csvlog_frame(const x265_param* param, const x265_picture* pic)
1438
0
{
1439
0
    if (!param->csvfpt)
1440
0
        return;
1441
1442
0
    const x265_frame_stats* frameStats = &pic->frameData;
1443
0
    fprintf(param->csvfpt, "%d, %d, %c-SLICE, %4d, %2.2lf, %10d, %d,", pic->layerID, frameStats->encoderOrder, frameStats->sliceType, frameStats->poc,
1444
0
                                                                   frameStats->qp, (int)frameStats->bits, frameStats->bScenecut);
1445
0
    if (!!param->bEnableTemporalSubLayers)
1446
0
        fprintf(param->csvfpt, "%d,", frameStats->tLayer);
1447
0
    if (param->csvLogLevel >= 2)
1448
0
        fprintf(param->csvfpt, "%.2f,", frameStats->ipCostRatio);
1449
0
    if (param->rc.rateControlMode == X265_RC_CRF)
1450
0
        fprintf(param->csvfpt, "%.3lf,", frameStats->rateFactor);
1451
0
    if (param->rc.vbvBufferSize)
1452
0
        fprintf(param->csvfpt, "%.3lf, %.3lf,", frameStats->bufferFill, frameStats->bufferFillFinal);
1453
0
    if (param->rc.vbvBufferSize && param->csvLogLevel >= 2)
1454
0
        fprintf(param->csvfpt, "%.3lf,", frameStats->unclippedBufferFillFinal);
1455
0
    if (param->bEnablePsnr)
1456
0
        fprintf(param->csvfpt, "%.3lf, %.3lf, %.3lf, %.3lf,", frameStats->psnrY, frameStats->psnrU, frameStats->psnrV, frameStats->psnr);
1457
0
    if (param->bEnableSsim)
1458
0
        fprintf(param->csvfpt, " %.6f, %6.3f,", frameStats->ssim, x265_ssim2dB(frameStats->ssim));
1459
0
    fprintf(param->csvfpt, "%d, ", frameStats->frameLatency);
1460
0
    if (frameStats->sliceType == 'I' || frameStats->sliceType == 'i')
1461
0
        fputs(" -, -,", param->csvfpt);
1462
0
    else
1463
0
    {
1464
0
        int i = 0;
1465
0
        while (frameStats->list0POC[i] != -1)
1466
0
            fprintf(param->csvfpt, "%d ", frameStats->list0POC[i++]);
1467
0
        fprintf(param->csvfpt, ",");
1468
0
        if (frameStats->sliceType != 'P')
1469
0
        {
1470
0
            i = 0;
1471
0
            while (frameStats->list1POC[i] != -1)
1472
0
                fprintf(param->csvfpt, "%d ", frameStats->list1POC[i++]);
1473
0
            fprintf(param->csvfpt, ",");
1474
0
        }
1475
0
        else
1476
0
            fputs(" -,", param->csvfpt);
1477
0
    }
1478
1479
0
    if (param->csvLogLevel)
1480
0
    {
1481
0
        for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1482
0
            fprintf(param->csvfpt, "%5.2lf%%, %5.2lf%%, %5.2lf%%,", frameStats->cuStats.percentIntraDistribution[depth][0],
1483
0
                                                                    frameStats->cuStats.percentIntraDistribution[depth][1],
1484
0
                                                                    frameStats->cuStats.percentIntraDistribution[depth][2]);
1485
0
        fprintf(param->csvfpt, "%5.2lf%%", frameStats->cuStats.percentIntraNxN);
1486
0
        if (param->bEnableRectInter)
1487
0
        {
1488
0
            for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1489
0
            {
1490
0
                fprintf(param->csvfpt, ", %5.2lf%%, %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][0],
1491
0
                                                               frameStats->cuStats.percentInterDistribution[depth][1]);
1492
0
                if (param->bEnableAMP)
1493
0
                    fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][2]);
1494
0
            }
1495
0
        }
1496
0
        else
1497
0
        {
1498
0
            for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1499
0
                fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentInterDistribution[depth][0]);
1500
0
        }
1501
0
        for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1502
0
            fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentSkipCu[depth]);
1503
0
        for (uint32_t depth = 0; depth <= param->maxCUDepth; depth++)
1504
0
            fprintf(param->csvfpt, ", %5.2lf%%", frameStats->cuStats.percentMergeCu[depth]);
1505
0
    }
1506
1507
0
    if (param->csvLogLevel >= 2)
1508
0
    {
1509
0
        fprintf(param->csvfpt, ", %.2lf, %.2lf, %.2lf, %.2lf ", frameStats->avgLumaDistortion,
1510
0
                                                                frameStats->avgChromaDistortion,
1511
0
                                                                frameStats->avgPsyEnergy,
1512
0
                                                                frameStats->avgResEnergy);
1513
1514
0
        fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minLumaLevel, frameStats->maxLumaLevel, frameStats->avgLumaLevel);
1515
1516
0
        if (param->internalCsp != X265_CSP_I400)
1517
0
        {
1518
0
            fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minChromaULevel, frameStats->maxChromaULevel, frameStats->avgChromaULevel);
1519
0
            fprintf(param->csvfpt, ", %d, %d, %.2lf", frameStats->minChromaVLevel, frameStats->maxChromaVLevel, frameStats->avgChromaVLevel);
1520
0
        }
1521
1522
0
        for (uint32_t i = 0; i < param->maxLog2CUSize - (uint32_t)g_log2Size[param->minCUSize] + 1; i++)
1523
0
        {
1524
0
            fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentIntraPu[i]);
1525
0
            fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentSkipPu[i]);
1526
0
            fprintf(param->csvfpt, ",%.2lf%%", frameStats->puStats.percentAmpPu[i]);
1527
0
            for (uint32_t j = 0; j < 3; j++)
1528
0
            {
1529
0
                fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentInterPu[i][j]);
1530
0
                fprintf(param->csvfpt, ", %.2lf%%", frameStats->puStats.percentMergePu[i][j]);
1531
0
            }
1532
0
        }
1533
0
        if ((uint32_t)g_log2Size[param->minCUSize] == 3)
1534
0
            fprintf(param->csvfpt, ",%.2lf%%", frameStats->puStats.percentNxN);
1535
1536
0
        fprintf(param->csvfpt, ", %.1lf, %.1lf, %.1lf, %.1lf, %.1lf, %.1lf, %.1lf,", frameStats->decideWaitTime, frameStats->row0WaitTime,
1537
0
                                                                                     frameStats->wallTime, frameStats->refWaitWallTime,
1538
0
                                                                                     frameStats->totalCTUTime, frameStats->stallTime,
1539
0
                                                                                     frameStats->totalFrameTime);
1540
1541
0
        fprintf(param->csvfpt, " %.3lf, %d", frameStats->avgWPP, frameStats->countRowBlocks);
1542
#if ENABLE_LIBVMAF
1543
        fprintf(param->csvfpt, ", %lf", frameStats->vmafFrameScore);
1544
#endif
1545
0
        if (param->bConfigRCFrame)
1546
0
        {
1547
0
            if(param->rc.rateControlMode == X265_RC_ABR)
1548
0
                fprintf(param->csvfpt, ", %ld", (long)frameStats->currTrBitrate);
1549
0
            else if (param->rc.rateControlMode == X265_RC_CRF)
1550
0
                fprintf(param->csvfpt, ", %f", frameStats->currTrCRF);
1551
0
            else if (param->rc.rateControlMode == X265_RC_CQP)
1552
0
                fprintf(param->csvfpt, ", %d", frameStats->currTrQP);
1553
0
        }
1554
0
    }
1555
0
    fprintf(param->csvfpt, "\n");
1556
0
    fflush(stderr);
1557
0
}
1558
1559
void x265_csvlog_encode(const x265_param *p, const x265_stats *stats, int padx, int pady, int argc, char** argv)
1560
0
{
1561
0
    if (p && p->csvfpt)
1562
0
    {
1563
0
        const x265_api * api = x265_api_get(0);
1564
1565
0
        if (p->csvLogLevel)
1566
0
        {
1567
            // adding summary to a per-frame csv log file, so it needs a summary header
1568
0
            fprintf(p->csvfpt, "\nSummary\n");
1569
0
            fputs(summaryCSVHeader, p->csvfpt);
1570
0
            if (p->csvLogLevel >= 2 || p->maxCLL || p->maxFALL)
1571
0
                fputs("MaxCLL, MaxFALL,", p->csvfpt);
1572
#if ENABLE_LIBVMAF
1573
            fputs(" Aggregate VMAF score,", p->csvfpt);
1574
#endif
1575
0
            fputs(" Version\n",p->csvfpt);
1576
1577
0
        }
1578
        // CLI arguments or other
1579
0
        if (argc)
1580
0
        {
1581
0
            fputc('"', p->csvfpt);
1582
0
            for (int i = 1; i < argc; i++)
1583
0
            {
1584
0
                fputc(' ', p->csvfpt);
1585
0
                fputs(argv[i], p->csvfpt);
1586
0
            }
1587
0
            fputc('"', p->csvfpt);
1588
0
        }
1589
0
        else
1590
0
        {
1591
0
            char *opts = x265_param2string((x265_param*)p, padx, pady);
1592
0
            if (opts)
1593
0
            {
1594
0
                fputc('"', p->csvfpt);
1595
0
                fputs(opts, p->csvfpt);
1596
0
                fputc('"', p->csvfpt);
1597
0
                X265_FREE(opts);
1598
0
            }
1599
0
        }
1600
1601
        // current date and time
1602
0
        time_t now;
1603
0
        struct tm* timeinfo;
1604
0
        time(&now);
1605
0
        timeinfo = localtime(&now);
1606
0
        char buffer[200];
1607
0
        strftime(buffer, 128, "%c", timeinfo);
1608
0
        fprintf(p->csvfpt, ", %s, ", buffer);
1609
        // elapsed time, fps, bitrate
1610
0
        fprintf(p->csvfpt, "%.2f, %.2f, %.2f,",
1611
0
            stats->elapsedEncodeTime, stats->encodedPictureCount / stats->elapsedEncodeTime, stats->bitrate);
1612
1613
0
        if (p->bEnablePsnr)
1614
0
            fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf, %.3lf,",
1615
0
            stats->globalPsnrY / stats->encodedPictureCount, stats->globalPsnrU / stats->encodedPictureCount,
1616
0
            stats->globalPsnrV / stats->encodedPictureCount, stats->globalPsnr);
1617
0
        else
1618
0
            fprintf(p->csvfpt, " -, -, -, -,");
1619
0
        if (p->bEnableSsim)
1620
0
            fprintf(p->csvfpt, " %.6f, %6.3f,", stats->globalSsim, x265_ssim2dB(stats->globalSsim));
1621
0
        else
1622
0
            fprintf(p->csvfpt, " -, -,");
1623
1624
0
        if (stats->statsI.numPics)
1625
0
        {
1626
0
            fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsI.numPics, stats->statsI.avgQp, stats->statsI.bitrate);
1627
0
            if (p->bEnablePsnr)
1628
0
                fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsI.psnrY, stats->statsI.psnrU, stats->statsI.psnrV);
1629
0
            else
1630
0
                fprintf(p->csvfpt, " -, -, -,");
1631
0
            if (p->bEnableSsim)
1632
0
                fprintf(p->csvfpt, " %.3lf,", stats->statsI.ssim);
1633
0
            else
1634
0
                fprintf(p->csvfpt, " -,");
1635
0
        }
1636
0
        else
1637
0
            fprintf(p->csvfpt, " -, -, -, -, -, -, -,");
1638
1639
0
        if (stats->statsP.numPics)
1640
0
        {
1641
0
            fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsP.numPics, stats->statsP.avgQp, stats->statsP.bitrate);
1642
0
            if (p->bEnablePsnr)
1643
0
                fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsP.psnrY, stats->statsP.psnrU, stats->statsP.psnrV);
1644
0
            else
1645
0
                fprintf(p->csvfpt, " -, -, -,");
1646
0
            if (p->bEnableSsim)
1647
0
                fprintf(p->csvfpt, " %.3lf,", stats->statsP.ssim);
1648
0
            else
1649
0
                fprintf(p->csvfpt, " -,");
1650
0
        }
1651
0
        else
1652
0
            fprintf(p->csvfpt, " -, -, -, -, -, -, -,");
1653
1654
0
        if (stats->statsB.numPics)
1655
0
        {
1656
0
            fprintf(p->csvfpt, " %-6u, %2.2lf, %-8.2lf,", stats->statsB.numPics, stats->statsB.avgQp, stats->statsB.bitrate);
1657
0
            if (p->bEnablePsnr)
1658
0
                fprintf(p->csvfpt, " %.3lf, %.3lf, %.3lf,", stats->statsB.psnrY, stats->statsB.psnrU, stats->statsB.psnrV);
1659
0
            else
1660
0
                fprintf(p->csvfpt, " -, -, -,");
1661
0
            if (p->bEnableSsim)
1662
0
                fprintf(p->csvfpt, " %.3lf,", stats->statsB.ssim);
1663
0
            else
1664
0
                fprintf(p->csvfpt, " -,");
1665
0
        }
1666
0
        else
1667
0
            fprintf(p->csvfpt, " -, -, -, -, -, -, -,");
1668
0
        if (p->csvLogLevel >= 2 || p->maxCLL || p->maxFALL)
1669
0
            fprintf(p->csvfpt, " %-6u, %-6u,", stats->maxCLL, stats->maxFALL);
1670
#if ENABLE_LIBVMAF
1671
        fprintf(p->csvfpt, " %lf,", stats->aggregateVmafScore);
1672
#endif
1673
0
        fprintf(p->csvfpt, " %s\n", api->version_str);
1674
1675
0
    }
1676
0
}
1677
1678
/* The dithering algorithm is based on Sierra-2-4A error diffusion.
1679
 * We convert planes in place (without allocating a new buffer). */
1680
static void ditherPlane(uint16_t *src, int srcStride, int width, int height, int16_t *errors, int bitDepth)
1681
0
{
1682
0
    const int lShift = 16 - bitDepth;
1683
0
    const int rShift = 16 - bitDepth + 2;
1684
0
    const int half = (1 << (16 - bitDepth + 1));
1685
0
    const int pixelMax = (1 << bitDepth) - 1;
1686
1687
0
    memset(errors, 0, (width + 1) * sizeof(int16_t));
1688
1689
0
    if (bitDepth == 8)
1690
0
    {
1691
0
        for (int y = 0; y < height; y++, src += srcStride)
1692
0
        {
1693
0
            uint8_t* dst = (uint8_t *)src;
1694
0
            int16_t err = 0;
1695
0
            for (int x = 0; x < width; x++)
1696
0
            {
1697
0
                err = err * 2 + errors[x] + errors[x + 1];
1698
0
                int tmpDst = x265_clip3(0, pixelMax, ((src[x] << 2) + err + half) >> rShift);
1699
0
                errors[x] = err = (int16_t)(src[x] - (tmpDst << lShift));
1700
0
                dst[x] = (uint8_t)tmpDst;
1701
0
            }
1702
0
        }
1703
0
    }
1704
0
    else
1705
0
    {
1706
0
        for (int y = 0; y < height; y++, src += srcStride)
1707
0
        {
1708
0
            int16_t err = 0;
1709
0
            for (int x = 0; x < width; x++)
1710
0
            {
1711
0
                err = err * 2 + errors[x] + errors[x + 1];
1712
0
                int tmpDst = x265_clip3(0, pixelMax, ((src[x] << 2) + err + half) >> rShift);
1713
0
                errors[x] = err = (int16_t)(src[x] - (tmpDst << lShift));
1714
0
                src[x] = (uint16_t)tmpDst;
1715
0
            }
1716
0
        }
1717
0
    }
1718
0
}
1719
1720
void x265_dither_image(x265_picture* picIn, int picWidth, int picHeight, int16_t *errorBuf, int bitDepth)
1721
0
{
1722
0
    const x265_api* api = x265_api_get(0);
1723
1724
0
    if (sizeof(x265_picture) != api->sizeof_picture)
1725
0
    {
1726
0
        fprintf(stderr, "extras [error]: structure size skew, unable to dither\n");
1727
0
        return;
1728
0
    }
1729
1730
0
    if (picIn->bitDepth <= 8)
1731
0
    {
1732
0
        fprintf(stderr, "extras [error]: dither support enabled only for input bitdepth > 8\n");
1733
0
        return;
1734
0
    }
1735
1736
0
    if (picIn->bitDepth == bitDepth)
1737
0
    {
1738
0
        fprintf(stderr, "extras[error]: dither support enabled only if encoder depth is different from picture depth\n");
1739
0
        return;
1740
0
    }
1741
1742
    /* This portion of code is from readFrame in x264. */
1743
0
    for (int i = 0; i < x265_cli_csps[picIn->colorSpace].planes; i++)
1744
0
    {
1745
0
        if (picIn->bitDepth < 16)
1746
0
        {
1747
            /* upconvert non 16bit high depth planes to 16bit */
1748
0
            uint16_t *plane = (uint16_t*)picIn->planes[i];
1749
0
            uint32_t pixelCount = x265_picturePlaneSize(picIn->colorSpace, picWidth, picHeight, i);
1750
0
            int lShift = 16 - picIn->bitDepth;
1751
1752
            /* This loop assumes width is equal to stride which
1753
             * happens to be true for file reader outputs */
1754
0
            for (uint32_t j = 0; j < pixelCount; j++)
1755
0
                plane[j] = plane[j] << lShift;
1756
0
        }
1757
1758
0
        int height = (int)(picHeight >> x265_cli_csps[picIn->colorSpace].height[i]);
1759
0
        int width = (int)(picWidth >> x265_cli_csps[picIn->colorSpace].width[i]);
1760
1761
0
        ditherPlane(((uint16_t*)picIn->planes[i]), picIn->stride[i] / 2, width, height, errorBuf, bitDepth);
1762
0
    }
1763
0
}
1764
1765
#if ENABLE_LIBVMAF
1766
/* Read y values of single frame for 8-bit input */
1767
int read_image_byte(FILE *file, float *buf, int width, int height, int stride)
1768
{
1769
    char *byte_ptr = (char *)buf;
1770
    unsigned char *tmp_buf = 0;
1771
    int i, j;
1772
    int ret = 1;
1773
1774
    if (width <= 0 || height <= 0)
1775
    {
1776
        goto fail_or_end;
1777
    }
1778
1779
    if (!(tmp_buf = (unsigned char*)malloc(width)))
1780
    {
1781
        goto fail_or_end;
1782
    }
1783
1784
    for (i = 0; i < height; ++i)
1785
    {
1786
        float *row_ptr = (float *)byte_ptr;
1787
1788
        if (fread(tmp_buf, 1, width, file) != (size_t)width)
1789
        {
1790
            goto fail_or_end;
1791
        }
1792
1793
        for (j = 0; j < width; ++j)
1794
        {
1795
            row_ptr[j] = tmp_buf[j];
1796
        }
1797
1798
        byte_ptr += stride;
1799
    }
1800
1801
    ret = 0;
1802
1803
fail_or_end:
1804
    free(tmp_buf);
1805
    return ret;
1806
}
1807
/* Read y values of single frame for 10-bit input */
1808
int read_image_word(FILE *file, float *buf, int width, int height, int stride)
1809
{
1810
    char *byte_ptr = (char *)buf;
1811
    unsigned short *tmp_buf = 0;
1812
    int i, j;
1813
    int ret = 1;
1814
1815
    if (width <= 0 || height <= 0)
1816
    {
1817
        goto fail_or_end;
1818
    }
1819
1820
    if (!(tmp_buf = (unsigned short*)malloc(width * 2))) // '*2' to accommodate words
1821
    {
1822
        goto fail_or_end;
1823
    }
1824
1825
    for (i = 0; i < height; ++i)
1826
    {
1827
        float *row_ptr = (float *)byte_ptr;
1828
1829
        if (fread(tmp_buf, 2, width, file) != (size_t)width) // '2' for word
1830
        {
1831
            goto fail_or_end;
1832
        }
1833
1834
        for (j = 0; j < width; ++j)
1835
        {
1836
            row_ptr[j] = tmp_buf[j] / 4.0; // '/4' to convert from 10 to 8-bit
1837
        }
1838
1839
        byte_ptr += stride;
1840
    }
1841
1842
    ret = 0;
1843
1844
fail_or_end:
1845
    free(tmp_buf);
1846
    return ret;
1847
}
1848
1849
static enum VmafOutputFormat log_fmt_map(const char *log_fmt)
1850
{
1851
  if (log_fmt) {
1852
    if (!strcmp(log_fmt, "xml"))
1853
      return VMAF_OUTPUT_FORMAT_XML;
1854
    if (!strcmp(log_fmt, "json"))
1855
      return VMAF_OUTPUT_FORMAT_JSON;
1856
    if (!strcmp(log_fmt, "csv"))
1857
      return VMAF_OUTPUT_FORMAT_CSV;
1858
    if (!strcmp(log_fmt, "sub"))
1859
      return VMAF_OUTPUT_FORMAT_SUB;
1860
  }
1861
1862
  return VMAF_OUTPUT_FORMAT_NONE;
1863
}
1864
1865
static enum VmafPoolingMethod pool_method_map(const char *pool_method)
1866
{
1867
  if (pool_method) {
1868
    if (!strcmp(pool_method, "min"))
1869
      return VMAF_POOL_METHOD_MIN;
1870
    if (!strcmp(pool_method, "mean"))
1871
      return VMAF_POOL_METHOD_MEAN;
1872
    if (!strcmp(pool_method, "harmonic_mean"))
1873
      return VMAF_POOL_METHOD_HARMONIC_MEAN;
1874
  }
1875
  return VMAF_POOL_METHOD_MEAN;
1876
}
1877
1878
static enum VmafPixelFormat pix_fmt_map(const char *fmt)
1879
{
1880
  if (fmt) {
1881
    if (!strcmp(fmt, "yuv420p") || !strcmp(fmt, "yuv420p10le") || !strcmp(fmt, "yuv420p12le") || !strcmp(fmt, "yuv420p16le"))
1882
            return VMAF_PIX_FMT_YUV420P;
1883
        if (!strcmp(fmt, "yuv422p") || !strcmp(fmt, "yuv422p10le"))
1884
            return VMAF_PIX_FMT_YUV422P;
1885
        if (!strcmp(fmt, "yuv444p") || !strcmp(fmt, "yuv444p10le"))
1886
            return VMAF_PIX_FMT_YUV444P;
1887
  }
1888
  return VMAF_PIX_FMT_UNKNOWN;
1889
}
1890
1891
static void copy_picture(float *src, VmafPicture *dst, unsigned width, unsigned height, int src_stride, unsigned bpc)
1892
{
1893
    const int bytes_per_value = bpc > 8 ? 2 : 1;
1894
    const int dst_stride = dst->stride[0] / bytes_per_value;
1895
    const unsigned b_shift = (bpc > 8) ? (bpc - 8) : 0;
1896
1897
    uint8_t *dst_data = static_cast<uint8_t*>(dst->data[0]);
1898
1899
    for (unsigned i = 0; i < height; i++) {
1900
        if (bpc > 8) {
1901
            uint16_t *dst_row = reinterpret_cast<uint16_t*>(dst_data);
1902
            for (unsigned j = 0; j < width; j++) {
1903
                dst_row[j] = static_cast<uint16_t>(src[j] * (1 << b_shift));
1904
            }
1905
        } else {
1906
            for (unsigned j = 0; j < width; j++) {
1907
                dst_data[j] = static_cast<uint8_t>(src[j]);
1908
            }
1909
        }
1910
        src += src_stride / sizeof(float);
1911
        dst_data += dst_stride * bytes_per_value;
1912
    }
1913
}
1914
1915
int load_feature(VmafContext *vmaf, const char *feature_name, VmafFeatureDictionary *d) {
1916
    int err = vmaf_use_feature(vmaf, feature_name, d);
1917
    if (err) {
1918
        printf("problem loading feature extractor: %s\n", feature_name);
1919
    }
1920
    return err;
1921
}
1922
1923
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),
1924
  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,
1925
  char *pool_method, int n_thread, int n_subsample)
1926
{
1927
  int err = 0;
1928
1929
  VmafConfiguration cfg = {
1930
    .log_level = VMAF_LOG_LEVEL_INFO,
1931
    .n_threads = static_cast<unsigned int>(n_thread),
1932
    .n_subsample = static_cast<unsigned int>(n_subsample),
1933
    .cpumask = static_cast<uint64_t>(disable_avx),
1934
    .gpumask = 0,
1935
  };
1936
1937
  VmafContext *vmaf;
1938
  err = vmaf_init(&vmaf, cfg);
1939
  if (err) {
1940
    printf("problem initializing VMAF context\n");
1941
    return -1;
1942
  }
1943
1944
  uint64_t flags = VMAF_MODEL_FLAGS_DEFAULT;
1945
  if (disable_clip)
1946
    flags |= VMAF_MODEL_FLAG_DISABLE_CLIP;
1947
  if (enable_transform || phone_model)
1948
    flags |= VMAF_MODEL_FLAG_ENABLE_TRANSFORM;
1949
1950
  VmafModelConfig model_cfg = {
1951
    .name = "vmaf",
1952
    .flags = flags,
1953
  };
1954
1955
  VmafModel *model = NULL;
1956
  VmafModelCollection *model_collection = NULL;
1957
1958
    int stride = width * sizeof(float);
1959
    float *ref_data = new float[height * stride];
1960
    float *main_data = new float[height * stride];
1961
    float *temp_data = new float[height * stride];
1962
    enum VmafOutputFormat output_fmt = log_fmt_map(log_fmt);
1963
1964
  err = vmaf_model_load_from_path(&model, &model_cfg, model_path);
1965
  if (err) {
1966
    printf("problem loading model file: %s\n", model_path);
1967
    goto end;
1968
  }
1969
  err = vmaf_use_features_from_model(vmaf, model);
1970
  if (err) {
1971
    printf("problem loading feature extractors from model file: %s\n", model_path);
1972
    goto end;
1973
  }
1974
1975
  if (do_psnr) {
1976
    VmafFeatureDictionary *d = NULL;
1977
    vmaf_feature_dictionary_set(&d, "enable_chroma", "false");
1978
    err = load_feature(vmaf, "psnr", d);
1979
    if (err) goto end;
1980
  }
1981
1982
  if (do_ssim) {
1983
    err = load_feature(vmaf, "float_ssim", NULL);
1984
    if (err) goto end;
1985
  }
1986
1987
  if (do_ms_ssim) {
1988
    err = load_feature(vmaf, "float_ms_ssim", NULL);
1989
    if (err) goto end;
1990
  }
1991
1992
  if (!ref_data || !main_data || !temp_data) {
1993
    printf("problem allocating picture memory\n");
1994
    err = -1;
1995
    goto free_data;
1996
  }
1997
  unsigned picture_index;
1998
  for (picture_index = 0;; picture_index++) {
1999
    err = read_frame(ref_data, main_data, temp_data, stride, user_data);
2000
    if (err == 1) {
2001
      printf("problem during read_frame\n");
2002
      goto free_data;
2003
    }
2004
    else if (err == 2) break;
2005
2006
    VmafPicture pic_ref, pic_dist;
2007
    err = vmaf_picture_alloc(&pic_ref, pix_fmt_map(fmt), bitdepth, width, height);
2008
    err |= vmaf_picture_alloc(&pic_dist, pix_fmt_map(fmt), bitdepth, width, height);
2009
    if (err) {
2010
      printf("problem allocating picture memory\n");
2011
      vmaf_picture_unref(&pic_ref);
2012
      vmaf_picture_unref(&pic_dist);
2013
      goto free_data;
2014
    }
2015
2016
    const unsigned bpc = bitdepth;
2017
      copy_picture(ref_data, &pic_ref, width, height, stride, bpc);
2018
      copy_picture(main_data, &pic_dist, width, height, stride, bpc);
2019
2020
    err = vmaf_read_pictures(vmaf, &pic_ref, &pic_dist, picture_index);
2021
    if (err) {
2022
      printf("problem reading pictures\n");
2023
      break;
2024
    }
2025
  }
2026
2027
  err = vmaf_read_pictures(vmaf, NULL, NULL, 0);
2028
  if (err) {
2029
    printf("problem flushing context\n");
2030
    return err;
2031
  }
2032
2033
  err = vmaf_score_pooled(vmaf, model, pool_method_map(pool_method), vmaf_score, 0, picture_index - 1);
2034
  if (err) {
2035
    printf("problem generating pooled VMAF score\n");
2036
    goto free_data;
2037
  }
2038
2039
  if (output_fmt == VMAF_OUTPUT_FORMAT_NONE && log_path) {
2040
    output_fmt = VMAF_OUTPUT_FORMAT_XML;
2041
    printf("use default log_fmt xml");
2042
  }
2043
  if (output_fmt) {
2044
    err = vmaf_write_output(vmaf, log_path, output_fmt);
2045
    if (err) {
2046
      printf("could not write output: %s\n", log_path);
2047
      goto free_data;
2048
    }
2049
  }
2050
2051
free_data:
2052
    delete[] ref_data;
2053
    delete[] main_data;
2054
    delete[] temp_data;
2055
end:
2056
    vmaf_model_destroy(model);
2057
    vmaf_model_collection_destroy(model_collection);
2058
    vmaf_close(vmaf);
2059
    return err;
2060
}
2061
2062
int read_frame(float *reference_data, float *distorted_data, float *temp_data, int stride_byte, void *s)
2063
{
2064
    x265_vmaf_data *user_data = (x265_vmaf_data *)s;
2065
    int ret;
2066
2067
    // read reference y
2068
    if (user_data->internalBitDepth == 8)
2069
    {
2070
        ret = read_image_byte(user_data->reference_file, reference_data, user_data->width, user_data->height, stride_byte);
2071
    }
2072
    else if (user_data->internalBitDepth == 10)
2073
    {
2074
        ret = read_image_word(user_data->reference_file, reference_data, user_data->width, user_data->height, stride_byte);
2075
    }
2076
    else
2077
    {
2078
        x265_log(NULL, X265_LOG_ERROR, "Invalid bitdepth\n");
2079
        return 1;
2080
    }
2081
    if (ret)
2082
    {
2083
        if (feof(user_data->reference_file))
2084
        {
2085
            ret = 2; // OK if end of file
2086
        }
2087
        return ret;
2088
    }
2089
2090
    // read distorted y
2091
    if (user_data->internalBitDepth == 8)
2092
    {
2093
        ret = read_image_byte(user_data->distorted_file, distorted_data, user_data->width, user_data->height, stride_byte);
2094
    }
2095
    else if (user_data->internalBitDepth == 10)
2096
    {
2097
        ret = read_image_word(user_data->distorted_file, distorted_data, user_data->width, user_data->height, stride_byte);
2098
    }
2099
    else
2100
    {
2101
        x265_log(NULL, X265_LOG_ERROR, "Invalid bitdepth\n");
2102
        return 1;
2103
    }
2104
    if (ret)
2105
    {
2106
        if (feof(user_data->distorted_file))
2107
        {
2108
            ret = 2; // OK if end of file
2109
        }
2110
        return ret;
2111
    }
2112
2113
    // reference skip u and v
2114
    if (user_data->internalBitDepth == 8)
2115
    {
2116
        if (fread(temp_data, 1, user_data->offset, user_data->reference_file) != (size_t)user_data->offset)
2117
        {
2118
            x265_log(NULL, X265_LOG_ERROR, "reference fread to skip u and v failed.\n");
2119
            goto fail_or_end;
2120
        }
2121
    }
2122
    else if (user_data->internalBitDepth == 10)
2123
    {
2124
        if (fread(temp_data, 2, user_data->offset, user_data->reference_file) != (size_t)user_data->offset)
2125
        {
2126
            x265_log(NULL, X265_LOG_ERROR, "reference fread to skip u and v failed.\n");
2127
            goto fail_or_end;
2128
        }
2129
    }
2130
    else
2131
    {
2132
        x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");
2133
        goto fail_or_end;
2134
    }
2135
2136
    // distorted skip u and v
2137
    if (user_data->internalBitDepth == 8)
2138
    {
2139
        if (fread(temp_data, 1, user_data->offset, user_data->distorted_file) != (size_t)user_data->offset)
2140
        {
2141
            x265_log(NULL, X265_LOG_ERROR, "distorted fread to skip u and v failed.\n");
2142
            goto fail_or_end;
2143
        }
2144
    }
2145
    else if (user_data->internalBitDepth == 10)
2146
    {
2147
        if (fread(temp_data, 2, user_data->offset, user_data->distorted_file) != (size_t)user_data->offset)
2148
        {
2149
            x265_log(NULL, X265_LOG_ERROR, "distorted fread to skip u and v failed.\n");
2150
            goto fail_or_end;
2151
        }
2152
    }
2153
    else
2154
    {
2155
        x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");
2156
        goto fail_or_end;
2157
    }
2158
2159
2160
fail_or_end:
2161
    return ret;
2162
}
2163
2164
double x265_calculate_vmafscore(x265_param *param, x265_vmaf_data *data)
2165
{
2166
    double score;
2167
    const char* pix_format;
2168
2169
    data->width = param->sourceWidth;
2170
    data->height = param->sourceHeight;
2171
    data->internalBitDepth = param->internalBitDepth;
2172
2173
    if (param->internalCsp == X265_CSP_I420)
2174
    {
2175
        if ((param->sourceWidth * param->sourceHeight) % 2 != 0)
2176
            x265_log(NULL, X265_LOG_ERROR, "Invalid file size\n");
2177
        data->offset = param->sourceWidth * param->sourceHeight / 2;
2178
        pix_format = "yuv420p";
2179
    }
2180
    else if (param->internalCsp == X265_CSP_I422)
2181
    {
2182
        data->offset = param->sourceWidth * param->sourceHeight;
2183
        pix_format = "yuv422p10le";
2184
    }
2185
    else if (param->internalCsp == X265_CSP_I444)
2186
    {
2187
        data->offset = param->sourceWidth * param->sourceHeight * 2;
2188
        pix_format = "yuv444p10le";
2189
    }
2190
    else
2191
        x265_log(NULL, X265_LOG_ERROR, "Invalid format\n");
2192
2193
    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);
2194
2195
    return score;
2196
}
2197
2198
int read_frame_10bit(float *reference_data, float *distorted_data, float *temp_data, int stride, void *s)
2199
{
2200
    x265_vmaf_framedata *user_data = (x265_vmaf_framedata *)s;
2201
2202
    PicYuv *reference_frame = (PicYuv *)user_data->reference_frame;
2203
    PicYuv *distorted_frame = (PicYuv *)user_data->distorted_frame;
2204
2205
    if(!user_data->frame_set) {
2206
2207
        int reference_stride = reference_frame->m_stride;
2208
        int distorted_stride = distorted_frame->m_stride;
2209
2210
        const uint16_t *reference_ptr = (const uint16_t *)reference_frame->m_picOrg[0];
2211
        const uint16_t *distorted_ptr = (const uint16_t *)distorted_frame->m_picOrg[0];
2212
2213
        temp_data = reference_data;
2214
2215
        int height = user_data->height;
2216
        int width = user_data->width; 
2217
2218
        int i,j;
2219
        for (i = 0; i < height; i++) {
2220
            for ( j = 0; j < width; j++) {
2221
                temp_data[j] = ((float)reference_ptr[j] / 4.0);
2222
            }
2223
            reference_ptr += reference_stride;
2224
            temp_data += stride / sizeof(*temp_data);
2225
        }
2226
2227
        temp_data = distorted_data;
2228
        for (i = 0; i < height; i++) {
2229
            for (j = 0; j < width; j++) {
2230
                 temp_data[j] = ((float)distorted_ptr[j] / 4.0);
2231
            }
2232
            distorted_ptr += distorted_stride;
2233
            temp_data += stride / sizeof(*temp_data);
2234
        }
2235
2236
        user_data->frame_set = 1;
2237
        return 0;
2238
    }
2239
    return 2;
2240
}
2241
2242
int read_frame_8bit(float *reference_data, float *distorted_data, float *temp_data, int stride, void *s)
2243
{
2244
    x265_vmaf_framedata *user_data = (x265_vmaf_framedata *)s;
2245
2246
    PicYuv *reference_frame = (PicYuv *)user_data->reference_frame;
2247
    PicYuv *distorted_frame = (PicYuv *)user_data->distorted_frame;
2248
2249
    if(!user_data->frame_set) {
2250
2251
        int reference_stride = reference_frame->m_stride;
2252
        int distorted_stride = distorted_frame->m_stride;
2253
2254
        const uint8_t *reference_ptr = (const uint8_t *)reference_frame->m_picOrg[0]; 
2255
        const uint8_t *distorted_ptr = (const uint8_t *)distorted_frame->m_picOrg[0];
2256
2257
        temp_data = reference_data;
2258
2259
        int height = user_data->height;
2260
        int width = user_data->width; 
2261
2262
        int i,j;
2263
        for (i = 0; i < height; i++) {
2264
            for ( j = 0; j < width; j++) {
2265
                temp_data[j] = (float)reference_ptr[j];
2266
            }
2267
            reference_ptr += reference_stride;
2268
            temp_data += stride / sizeof(*temp_data);
2269
        }
2270
2271
        temp_data = distorted_data;
2272
        for (i = 0; i < height; i++) {
2273
            for (j = 0; j < width; j++) {
2274
                 temp_data[j] = (float)distorted_ptr[j];
2275
            }
2276
            distorted_ptr += distorted_stride;
2277
            temp_data += stride / sizeof(*temp_data);
2278
        }
2279
2280
        user_data->frame_set = 1;
2281
        return 0;
2282
    }
2283
    return 2;
2284
}
2285
2286
double x265_calculate_vmaf_framelevelscore(x265_param *param, x265_vmaf_framedata *vmafframedata)
2287
{
2288
    double score;
2289
    const char* pix_format;
2290
2291
    if (param->internalCsp == X265_CSP_I420)
2292
        pix_format = "yuv420p";
2293
    else if (param->internalCsp == X265_CSP_I422)
2294
        pix_format = "yuv422p10le";
2295
    else
2296
        pix_format = "yuv444p10le";
2297
2298
    int (*read_frame)(float *reference_data, float *distorted_data, float *temp_data,
2299
        int stride, void *s);
2300
    if (vmafframedata->internalBitDepth == 8)
2301
        read_frame = read_frame_8bit;
2302
    else
2303
        read_frame = read_frame_10bit;
2304
    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);
2305
2306
    return score;
2307
}
2308
#endif
2309
2310
} /* end namespace or extern "C" */
2311
2312
namespace X265_NS {
2313
#ifdef SVT_HEVC
2314
2315
void svt_initialise_app_context(x265_encoder *enc)
2316
{
2317
    Encoder *encoder = static_cast<Encoder*>(enc);
2318
2319
    //Initialise Application Context
2320
    encoder->m_svtAppData = (SvtAppContext*)x265_malloc(sizeof(SvtAppContext));
2321
    encoder->m_svtAppData->svtHevcParams = (EB_H265_ENC_CONFIGURATION*)x265_malloc(sizeof(EB_H265_ENC_CONFIGURATION));
2322
    encoder->m_svtAppData->byteCount = 0;
2323
    encoder->m_svtAppData->outFrameCount = 0;
2324
}
2325
2326
int svt_initialise_input_buffer(x265_encoder *enc)
2327
{
2328
    Encoder *encoder = static_cast<Encoder*>(enc);
2329
2330
    //Initialise Input Buffer
2331
    encoder->m_svtAppData->inputPictureBuffer = (EB_BUFFERHEADERTYPE*)x265_malloc(sizeof(EB_BUFFERHEADERTYPE));
2332
    EB_BUFFERHEADERTYPE *inputPtr = encoder->m_svtAppData->inputPictureBuffer;
2333
    inputPtr->pBuffer = (unsigned char*)x265_malloc(sizeof(EB_H265_ENC_INPUT));
2334
2335
    EB_H265_ENC_INPUT *inputData = (EB_H265_ENC_INPUT*)inputPtr->pBuffer;
2336
    inputData->dolbyVisionRpu.payload = NULL;
2337
    inputData->dolbyVisionRpu.payloadSize = 0;
2338
2339
2340
    if (!inputPtr->pBuffer)
2341
        return 0;
2342
2343
    inputPtr->nSize = sizeof(EB_BUFFERHEADERTYPE);
2344
    inputPtr->pAppPrivate = NULL;
2345
    return 1;
2346
}
2347
#endif // ifdef SVT_HEVC
2348
2349
} // end namespace X265_NS