Coverage Report

Created: 2022-08-24 06:15

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