libx265.c 13.4 KB
Newer Older
Derek Buitenhuis's avatar
Derek Buitenhuis committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * libx265 encoder
 *
 * Copyright (c) 2013-2014 Derek Buitenhuis
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

23 24 25 26
#if defined(_MSC_VER)
#define X265_API_IMPORTS 1
#endif

Derek Buitenhuis's avatar
Derek Buitenhuis committed
27
#include <x265.h>
28
#include <float.h>
Derek Buitenhuis's avatar
Derek Buitenhuis committed
29 30 31 32 33 34 35 36 37 38 39 40 41

#include "libavutil/internal.h"
#include "libavutil/common.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "avcodec.h"
#include "internal.h"

typedef struct libx265Context {
    const AVClass *class;

    x265_encoder *encoder;
    x265_param   *params;
42
    const x265_api *api;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
43

44
    float crf;
45
    int   forced_idr;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    char *preset;
    char *tune;
    char *x265_opts;
} libx265Context;

static int is_keyframe(NalUnitType naltype)
{
    switch (naltype) {
    case NAL_UNIT_CODED_SLICE_BLA_W_LP:
    case NAL_UNIT_CODED_SLICE_BLA_W_RADL:
    case NAL_UNIT_CODED_SLICE_BLA_N_LP:
    case NAL_UNIT_CODED_SLICE_IDR_W_RADL:
    case NAL_UNIT_CODED_SLICE_IDR_N_LP:
    case NAL_UNIT_CODED_SLICE_CRA:
        return 1;
    default:
        return 0;
    }
}

static av_cold int libx265_encode_close(AVCodecContext *avctx)
{
    libx265Context *ctx = avctx->priv_data;

70
    ctx->api->param_free(ctx->params);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
71 72

    if (ctx->encoder)
73
        ctx->api->encoder_close(ctx->encoder);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
74 75 76 77 78 79 80 81

    return 0;
}

static av_cold int libx265_encode_init(AVCodecContext *avctx)
{
    libx265Context *ctx = avctx->priv_data;

82
    ctx->api = x265_api_get(av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth);
83 84 85 86
    if (!ctx->api)
        ctx->api = x265_api_get(0);

    ctx->params = ctx->api->param_alloc();
Derek Buitenhuis's avatar
Derek Buitenhuis committed
87 88 89 90 91
    if (!ctx->params) {
        av_log(avctx, AV_LOG_ERROR, "Could not allocate x265 param structure.\n");
        return AVERROR(ENOMEM);
    }

92
    if (ctx->api->param_default_preset(ctx->params, ctx->preset, ctx->tune) < 0) {
93 94 95 96 97 98 99 100 101 102 103 104 105 106
        int i;

        av_log(avctx, AV_LOG_ERROR, "Error setting preset/tune %s/%s.\n", ctx->preset, ctx->tune);
        av_log(avctx, AV_LOG_INFO, "Possible presets:");
        for (i = 0; x265_preset_names[i]; i++)
            av_log(avctx, AV_LOG_INFO, " %s", x265_preset_names[i]);

        av_log(avctx, AV_LOG_INFO, "\n");
        av_log(avctx, AV_LOG_INFO, "Possible tunes:");
        for (i = 0; x265_tune_names[i]; i++)
            av_log(avctx, AV_LOG_INFO, " %s", x265_tune_names[i]);

        av_log(avctx, AV_LOG_INFO, "\n");

Derek Buitenhuis's avatar
Derek Buitenhuis committed
107 108 109 110
        return AVERROR(EINVAL);
    }

    ctx->params->frameNumThreads = avctx->thread_count;
111 112
    ctx->params->fpsNum          = avctx->time_base.den;
    ctx->params->fpsDenom        = avctx->time_base.num * avctx->ticks_per_frame;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
113 114
    ctx->params->sourceWidth     = avctx->width;
    ctx->params->sourceHeight    = avctx->height;
115
    ctx->params->bEnablePsnr     = !!(avctx->flags & AV_CODEC_FLAG_PSNR);
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    if ((avctx->color_primaries <= AVCOL_PRI_BT2020 &&
         avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) ||
        (avctx->color_trc <= AVCOL_TRC_BT2020_12 &&
         avctx->color_trc != AVCOL_TRC_UNSPECIFIED) ||
        (avctx->colorspace <= AVCOL_SPC_BT2020_CL &&
         avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) {

        ctx->params->vui.bEnableVideoSignalTypePresentFlag  = 1;
        ctx->params->vui.bEnableColorDescriptionPresentFlag = 1;

        // x265 validates the parameters internally
        ctx->params->vui.colorPrimaries          = avctx->color_primaries;
        ctx->params->vui.transferCharacteristics = avctx->color_trc;
        ctx->params->vui.matrixCoeffs            = avctx->colorspace;
    }

133
    if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) {
134 135 136
        char sar[12];
        int sar_num, sar_den;

137 138 139 140
        av_reduce(&sar_num, &sar_den,
                  avctx->sample_aspect_ratio.num,
                  avctx->sample_aspect_ratio.den, 65535);
        snprintf(sar, sizeof(sar), "%d:%d", sar_num, sar_den);
141
        if (ctx->api->param_parse(ctx->params, "sar", sar) == X265_PARAM_BAD_VALUE) {
142 143 144
            av_log(avctx, AV_LOG_ERROR, "Invalid SAR: %d:%d.\n", sar_num, sar_den);
            return AVERROR_INVALIDDATA;
        }
145
    }
Derek Buitenhuis's avatar
Derek Buitenhuis committed
146

147 148 149
    switch (avctx->pix_fmt) {
    case AV_PIX_FMT_YUV420P:
    case AV_PIX_FMT_YUV420P10:
150
    case AV_PIX_FMT_YUV420P12:
151 152
        ctx->params->internalCsp = X265_CSP_I420;
        break;
153 154
    case AV_PIX_FMT_YUV422P:
    case AV_PIX_FMT_YUV422P10:
155
    case AV_PIX_FMT_YUV422P12:
156 157
        ctx->params->internalCsp = X265_CSP_I422;
        break;
158 159 160 161 162 163
    case AV_PIX_FMT_GBRP:
    case AV_PIX_FMT_GBRP10:
    case AV_PIX_FMT_GBRP12:
        ctx->params->vui.matrixCoeffs = AVCOL_SPC_RGB;
        ctx->params->vui.bEnableVideoSignalTypePresentFlag  = 1;
        ctx->params->vui.bEnableColorDescriptionPresentFlag = 1;
164 165
    case AV_PIX_FMT_YUV444P:
    case AV_PIX_FMT_YUV444P10:
166
    case AV_PIX_FMT_YUV444P12:
167 168
        ctx->params->internalCsp = X265_CSP_I444;
        break;
169
    case AV_PIX_FMT_GRAY8:
170 171
    case AV_PIX_FMT_GRAY10:
    case AV_PIX_FMT_GRAY12:
172 173 174 175 176 177 178 179
        if (ctx->api->api_build_number < 85) {
            av_log(avctx, AV_LOG_ERROR,
                   "libx265 version is %d, must be at least 85 for gray encoding.\n",
                   ctx->api->api_build_number);
            return AVERROR_INVALIDDATA;
        }
        ctx->params->internalCsp = X265_CSP_I400;
        break;
180 181
    }

182 183 184 185
    if (ctx->crf >= 0) {
        char crf[6];

        snprintf(crf, sizeof(crf), "%2.2f", ctx->crf);
186
        if (ctx->api->param_parse(ctx->params, "crf", crf) == X265_PARAM_BAD_VALUE) {
187 188 189 190
            av_log(avctx, AV_LOG_ERROR, "Invalid crf: %2.2f.\n", ctx->crf);
            return AVERROR(EINVAL);
        }
    } else if (avctx->bit_rate > 0) {
Derek Buitenhuis's avatar
Derek Buitenhuis committed
191 192 193 194
        ctx->params->rc.bitrate         = avctx->bit_rate / 1000;
        ctx->params->rc.rateControlMode = X265_RC_ABR;
    }

195
    if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER))
196 197
        ctx->params->bRepeatHeaders = 1;

Derek Buitenhuis's avatar
Derek Buitenhuis committed
198 199 200 201 202 203
    if (ctx->x265_opts) {
        AVDictionary *dict    = NULL;
        AVDictionaryEntry *en = NULL;

        if (!av_dict_parse_string(&dict, ctx->x265_opts, "=", ":", 0)) {
            while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) {
204
                int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

                switch (parse_ret) {
                case X265_PARAM_BAD_NAME:
                    av_log(avctx, AV_LOG_WARNING,
                          "Unknown option: %s.\n", en->key);
                    break;
                case X265_PARAM_BAD_VALUE:
                    av_log(avctx, AV_LOG_WARNING,
                          "Invalid value for %s: %s.\n", en->key, en->value);
                    break;
                default:
                    break;
                }
            }
            av_dict_free(&dict);
        }
    }

223
    ctx->encoder = ctx->api->encoder_open(ctx->params);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
224 225 226
    if (!ctx->encoder) {
        av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n");
        libx265_encode_close(avctx);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
227
        return AVERROR_INVALIDDATA;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
228 229
    }

230
    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
231 232 233
        x265_nal *nal;
        int nnal;

234
        avctx->extradata_size = ctx->api->encoder_headers(ctx->encoder, &nal, &nnal);
235 236 237 238 239
        if (avctx->extradata_size <= 0) {
            av_log(avctx, AV_LOG_ERROR, "Cannot encode headers.\n");
            libx265_encode_close(avctx);
            return AVERROR_INVALIDDATA;
        }
240

241
        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
242 243 244 245 246 247 248 249
        if (!avctx->extradata) {
            av_log(avctx, AV_LOG_ERROR,
                   "Cannot allocate HEVC header of size %d.\n", avctx->extradata_size);
            libx265_encode_close(avctx);
            return AVERROR(ENOMEM);
        }

        memcpy(avctx->extradata, nal[0].payload, avctx->extradata_size);
250 251
    }

Derek Buitenhuis's avatar
Derek Buitenhuis committed
252 253 254 255 256 257 258 259
    return 0;
}

static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                                const AVFrame *pic, int *got_packet)
{
    libx265Context *ctx = avctx->priv_data;
    x265_picture x265pic;
260
    x265_picture x265pic_out = { 0 };
Derek Buitenhuis's avatar
Derek Buitenhuis committed
261 262 263 264 265 266 267
    x265_nal *nal;
    uint8_t *dst;
    int payload = 0;
    int nnal;
    int ret;
    int i;

268
    ctx->api->picture_init(ctx->params, &x265pic);
269

Derek Buitenhuis's avatar
Derek Buitenhuis committed
270 271 272 273 274 275
    if (pic) {
        for (i = 0; i < 3; i++) {
           x265pic.planes[i] = pic->data[i];
           x265pic.stride[i] = pic->linesize[i];
        }

276
        x265pic.pts      = pic->pts;
277
        x265pic.bitDepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
278

279 280
        x265pic.sliceType = pic->pict_type == AV_PICTURE_TYPE_I ?
                                              (ctx->forced_idr ? X265_TYPE_IDR : X265_TYPE_I) :
281 282 283
                            pic->pict_type == AV_PICTURE_TYPE_P ? X265_TYPE_P :
                            pic->pict_type == AV_PICTURE_TYPE_B ? X265_TYPE_B :
                            X265_TYPE_AUTO;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
284 285
    }

286 287
    ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal,
                                   pic ? &x265pic : NULL, &x265pic_out);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
288
    if (ret < 0)
289
        return AVERROR_EXTERNAL;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314

    if (!nnal)
        return 0;

    for (i = 0; i < nnal; i++)
        payload += nal[i].sizeBytes;

    ret = ff_alloc_packet(pkt, payload);
    if (ret < 0) {
        av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
        return ret;
    }
    dst = pkt->data;

    for (i = 0; i < nnal; i++) {
        memcpy(dst, nal[i].payload, nal[i].sizeBytes);
        dst += nal[i].sizeBytes;

        if (is_keyframe(nal[i].type))
            pkt->flags |= AV_PKT_FLAG_KEY;
    }

    pkt->pts = x265pic_out.pts;
    pkt->dts = x265pic_out.dts;

315 316
#if FF_API_CODED_FRAME
FF_DISABLE_DEPRECATION_WARNINGS
317 318 319 320 321 322 323 324 325 326 327 328
    switch (x265pic_out.sliceType) {
    case X265_TYPE_IDR:
    case X265_TYPE_I:
        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
        break;
    case X265_TYPE_P:
        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_P;
        break;
    case X265_TYPE_B:
        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_B;
        break;
    }
329 330
FF_ENABLE_DEPRECATION_WARNINGS
#endif
331

Derek Buitenhuis's avatar
Derek Buitenhuis committed
332 333 334 335 336 337
    *got_packet = 1;
    return 0;
}

static const enum AVPixelFormat x265_csp_eight[] = {
    AV_PIX_FMT_YUV420P,
338
    AV_PIX_FMT_YUV422P,
339
    AV_PIX_FMT_YUV444P,
340
    AV_PIX_FMT_GBRP,
341
    AV_PIX_FMT_GRAY8,
Derek Buitenhuis's avatar
Derek Buitenhuis committed
342 343 344
    AV_PIX_FMT_NONE
};

345 346 347 348
static const enum AVPixelFormat x265_csp_ten[] = {
    AV_PIX_FMT_YUV420P,
    AV_PIX_FMT_YUV422P,
    AV_PIX_FMT_YUV444P,
349
    AV_PIX_FMT_GBRP,
350 351 352
    AV_PIX_FMT_YUV420P10,
    AV_PIX_FMT_YUV422P10,
    AV_PIX_FMT_YUV444P10,
353
    AV_PIX_FMT_GBRP10,
354
    AV_PIX_FMT_GRAY8,
355
    AV_PIX_FMT_GRAY10,
356 357 358
    AV_PIX_FMT_NONE
};

Derek Buitenhuis's avatar
Derek Buitenhuis committed
359 360
static const enum AVPixelFormat x265_csp_twelve[] = {
    AV_PIX_FMT_YUV420P,
361
    AV_PIX_FMT_YUV422P,
362
    AV_PIX_FMT_YUV444P,
363
    AV_PIX_FMT_GBRP,
Derek Buitenhuis's avatar
Derek Buitenhuis committed
364
    AV_PIX_FMT_YUV420P10,
365
    AV_PIX_FMT_YUV422P10,
366
    AV_PIX_FMT_YUV444P10,
367
    AV_PIX_FMT_GBRP10,
368 369 370
    AV_PIX_FMT_YUV420P12,
    AV_PIX_FMT_YUV422P12,
    AV_PIX_FMT_YUV444P12,
371
    AV_PIX_FMT_GBRP12,
372
    AV_PIX_FMT_GRAY8,
373 374
    AV_PIX_FMT_GRAY10,
    AV_PIX_FMT_GRAY12,
Derek Buitenhuis's avatar
Derek Buitenhuis committed
375 376 377 378 379
    AV_PIX_FMT_NONE
};

static av_cold void libx265_encode_init_csp(AVCodec *codec)
{
380
    if (x265_api_get(12))
Derek Buitenhuis's avatar
Derek Buitenhuis committed
381
        codec->pix_fmts = x265_csp_twelve;
382 383
    else if (x265_api_get(10))
        codec->pix_fmts = x265_csp_ten;
384 385
    else if (x265_api_get(8))
        codec->pix_fmts = x265_csp_eight;
Derek Buitenhuis's avatar
Derek Buitenhuis committed
386 387 388 389 390
}

#define OFFSET(x) offsetof(libx265Context, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
391
    { "crf",         "set the x265 crf",                                                            OFFSET(crf),       AV_OPT_TYPE_FLOAT,  { .dbl = -1 }, -1, FLT_MAX, VE },
392
    { "forced-idr",  "if forcing keyframes, force them as IDR frames",                              OFFSET(forced_idr),AV_OPT_TYPE_BOOL,   { .i64 =  0 },  0,       1, VE },
Derek Buitenhuis's avatar
Derek Buitenhuis committed
393 394 395 396 397 398 399 400 401 402 403 404 405
    { "preset",      "set the x265 preset",                                                         OFFSET(preset),    AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
    { "tune",        "set the x265 tune parameter",                                                 OFFSET(tune),      AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
    { "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
    { NULL }
};

static const AVClass class = {
    .class_name = "libx265",
    .item_name  = av_default_item_name,
    .option     = options,
    .version    = LIBAVUTIL_VERSION_INT,
};

406 407 408 409 410
static const AVCodecDefault x265_defaults[] = {
    { "b", "0" },
    { NULL },
};

Derek Buitenhuis's avatar
Derek Buitenhuis committed
411 412 413 414 415 416 417 418 419 420 421
AVCodec ff_libx265_encoder = {
    .name             = "libx265",
    .long_name        = NULL_IF_CONFIG_SMALL("libx265 H.265 / HEVC"),
    .type             = AVMEDIA_TYPE_VIDEO,
    .id               = AV_CODEC_ID_HEVC,
    .init             = libx265_encode_init,
    .init_static_data = libx265_encode_init_csp,
    .encode2          = libx265_encode_frame,
    .close            = libx265_encode_close,
    .priv_data_size   = sizeof(libx265Context),
    .priv_class       = &class,
422
    .defaults         = x265_defaults,
423
    .capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
Derek Buitenhuis's avatar
Derek Buitenhuis committed
424
};