libx265.c 12.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 Libav.
 *
 * Libav 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.
 *
 * Libav 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 Libav; 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
    if (!ctx->api)
        ctx->api = x265_api_get(0);

86
    if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL &&
87
        !av_pix_fmt_desc_get(avctx->pix_fmt)->log2_chroma_w) {
88
        av_log(avctx, AV_LOG_ERROR,
89
               "4:2:2 and 4:4:4 support is not fully defined for HEVC yet. "
90 91 92 93
               "Set -strict experimental to encode anyway.\n");
        return AVERROR(ENOSYS);
    }

94
    ctx->params = ctx->api->param_alloc();
Derek Buitenhuis's avatar
Derek Buitenhuis committed
95 96 97 98 99
    if (!ctx->params) {
        av_log(avctx, AV_LOG_ERROR, "Could not allocate x265 param structure.\n");
        return AVERROR(ENOMEM);
    }

100
    if (ctx->api->param_default_preset(ctx->params, ctx->preset, ctx->tune) < 0) {
101 102 103 104 105 106 107 108 109 110 111 112 113 114
        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
115 116 117 118
        return AVERROR(EINVAL);
    }

    ctx->params->frameNumThreads = avctx->thread_count;
119 120
    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
121 122
    ctx->params->sourceWidth     = avctx->width;
    ctx->params->sourceHeight    = avctx->height;
123
    ctx->params->bEnablePsnr     = !!(avctx->flags & AV_CODEC_FLAG_PSNR);
124

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    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;
    }

141
    if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) {
142 143 144
        char sar[12];
        int sar_num, sar_den;

145 146 147 148
        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);
149
        if (ctx->api->param_parse(ctx->params, "sar", sar) == X265_PARAM_BAD_VALUE) {
150 151 152
            av_log(avctx, AV_LOG_ERROR, "Invalid SAR: %d:%d.\n", sar_num, sar_den);
            return AVERROR_INVALIDDATA;
        }
153
    }
Derek Buitenhuis's avatar
Derek Buitenhuis committed
154

155 156 157 158 159
    switch (avctx->pix_fmt) {
    case AV_PIX_FMT_YUV420P:
    case AV_PIX_FMT_YUV420P10:
        ctx->params->internalCsp = X265_CSP_I420;
        break;
160 161 162 163
    case AV_PIX_FMT_YUV422P:
    case AV_PIX_FMT_YUV422P10:
        ctx->params->internalCsp = X265_CSP_I422;
        break;
164 165 166 167 168 169
    case AV_PIX_FMT_YUV444P:
    case AV_PIX_FMT_YUV444P10:
        ctx->params->internalCsp = X265_CSP_I444;
        break;
    }

170 171 172 173
    if (ctx->crf >= 0) {
        char crf[6];

        snprintf(crf, sizeof(crf), "%2.2f", ctx->crf);
174
        if (ctx->api->param_parse(ctx->params, "crf", crf) == X265_PARAM_BAD_VALUE) {
175 176 177 178
            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
179 180 181 182
        ctx->params->rc.bitrate         = avctx->bit_rate / 1000;
        ctx->params->rc.rateControlMode = X265_RC_ABR;
    }

183
    if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER))
184 185
        ctx->params->bRepeatHeaders = 1;

Derek Buitenhuis's avatar
Derek Buitenhuis committed
186 187 188 189 190 191
    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))) {
192
                int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

                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);
        }
    }

211
    ctx->encoder = ctx->api->encoder_open(ctx->params);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
212 213 214 215 216 217
    if (!ctx->encoder) {
        av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n");
        libx265_encode_close(avctx);
        return AVERROR_INVALIDDATA;
    }

218
    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
219 220 221
        x265_nal *nal;
        int nnal;

222
        avctx->extradata_size = ctx->api->encoder_headers(ctx->encoder, &nal, &nnal);
223 224 225 226 227
        if (avctx->extradata_size <= 0) {
            av_log(avctx, AV_LOG_ERROR, "Cannot encode headers.\n");
            libx265_encode_close(avctx);
            return AVERROR_INVALIDDATA;
        }
228

229
        avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
230 231 232 233 234 235 236 237
        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);
238 239
    }

Derek Buitenhuis's avatar
Derek Buitenhuis committed
240 241 242 243 244 245 246 247
    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;
248
    x265_picture x265pic_out = { 0 };
Derek Buitenhuis's avatar
Derek Buitenhuis committed
249 250 251 252 253 254 255
    x265_nal *nal;
    uint8_t *dst;
    int payload = 0;
    int nnal;
    int ret;
    int i;

256
    ctx->api->picture_init(ctx->params, &x265pic);
257

Derek Buitenhuis's avatar
Derek Buitenhuis committed
258 259 260 261 262 263
    if (pic) {
        for (i = 0; i < 3; i++) {
           x265pic.planes[i] = pic->data[i];
           x265pic.stride[i] = pic->linesize[i];
        }

264
        x265pic.pts      = pic->pts;
265
        x265pic.bitDepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
266

267 268
        x265pic.sliceType = pic->pict_type == AV_PICTURE_TYPE_I ?
                                              (ctx->forced_idr ? X265_TYPE_IDR : X265_TYPE_I) :
269 270 271
                            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
272 273
    }

274 275
    ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal,
                                   pic ? &x265pic : NULL, &x265pic_out);
Derek Buitenhuis's avatar
Derek Buitenhuis committed
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
    if (ret < 0)
        return AVERROR_UNKNOWN;

    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;

303 304
#if FF_API_CODED_FRAME
FF_DISABLE_DEPRECATION_WARNINGS
305 306 307 308 309 310 311 312 313 314 315 316
    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;
    }
317 318
FF_ENABLE_DEPRECATION_WARNINGS
#endif
319

Derek Buitenhuis's avatar
Derek Buitenhuis committed
320 321 322 323 324 325
    *got_packet = 1;
    return 0;
}

static const enum AVPixelFormat x265_csp_eight[] = {
    AV_PIX_FMT_YUV420P,
326
    AV_PIX_FMT_YUV422P,
327
    AV_PIX_FMT_YUV444P,
Derek Buitenhuis's avatar
Derek Buitenhuis committed
328 329 330 331 332
    AV_PIX_FMT_NONE
};

static const enum AVPixelFormat x265_csp_twelve[] = {
    AV_PIX_FMT_YUV420P,
333
    AV_PIX_FMT_YUV422P,
334
    AV_PIX_FMT_YUV444P,
Derek Buitenhuis's avatar
Derek Buitenhuis committed
335
    AV_PIX_FMT_YUV420P10,
336
    AV_PIX_FMT_YUV422P10,
337
    AV_PIX_FMT_YUV444P10,
Derek Buitenhuis's avatar
Derek Buitenhuis committed
338 339 340 341 342 343 344 345 346 347 348 349 350 351
    AV_PIX_FMT_NONE
};

static av_cold void libx265_encode_init_csp(AVCodec *codec)
{
    if (x265_max_bit_depth == 8)
        codec->pix_fmts = x265_csp_eight;
    else if (x265_max_bit_depth == 12)
        codec->pix_fmts = x265_csp_twelve;
}

#define OFFSET(x) offsetof(libx265Context, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
352
    { "crf",         "set the x265 crf",                                                            OFFSET(crf),       AV_OPT_TYPE_FLOAT,  { .dbl = -1 }, -1, FLT_MAX, VE },
353
    { "forced-idr",  "if forcing keyframes, force them as IDR frames",                              OFFSET(forced_idr),AV_OPT_TYPE_INT,    { .i64 =  0 },  0,       1, VE },
Derek Buitenhuis's avatar
Derek Buitenhuis committed
354 355 356 357 358 359 360 361 362 363 364 365 366
    { "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,
};

367 368 369 370 371
static const AVCodecDefault x265_defaults[] = {
    { "b", "0" },
    { NULL },
};

Derek Buitenhuis's avatar
Derek Buitenhuis committed
372 373 374 375 376 377 378 379 380 381 382
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,
383
    .defaults         = x265_defaults,
384
    .capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
Derek Buitenhuis's avatar
Derek Buitenhuis committed
385
};