| 1 | /*
|
|---|
| 2 | * libx265 encoder
|
|---|
| 3 | *
|
|---|
| 4 | * Copyright (c) 2013-2014 Derek Buitenhuis
|
|---|
| 5 | *
|
|---|
| 6 | * This file is part of FFmpeg.
|
|---|
| 7 | *
|
|---|
| 8 | * FFmpeg is free software; you can redistribute it and/or
|
|---|
| 9 | * modify it under the terms of the GNU Lesser General Public
|
|---|
| 10 | * License as published by the Free Software Foundation; either
|
|---|
| 11 | * version 2.1 of the License, or (at your option) any later version.
|
|---|
| 12 | *
|
|---|
| 13 | * FFmpeg is distributed in the hope that it will be useful,
|
|---|
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|---|
| 16 | * Lesser General Public License for more details.
|
|---|
| 17 | *
|
|---|
| 18 | * You should have received a copy of the GNU Lesser General Public
|
|---|
| 19 | * License along with FFmpeg; if not, write to the Free Software
|
|---|
| 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|---|
| 21 | */
|
|---|
| 22 |
|
|---|
| 23 | #if defined(_MSC_VER)
|
|---|
| 24 | #define X265_API_IMPORTS 1
|
|---|
| 25 | #endif
|
|---|
| 26 |
|
|---|
| 27 | #include <x265.h>
|
|---|
| 28 | #include <float.h>
|
|---|
| 29 |
|
|---|
| 30 | #include "libavutil/internal.h"
|
|---|
| 31 | #include "libavutil/common.h"
|
|---|
| 32 | #include "libavutil/opt.h"
|
|---|
| 33 | #include "libavutil/pixdesc.h"
|
|---|
| 34 | #include "avcodec.h"
|
|---|
| 35 | #include "codec_internal.h"
|
|---|
| 36 | #include "encode.h"
|
|---|
| 37 | #include "internal.h"
|
|---|
| 38 | #include "packet_internal.h"
|
|---|
| 39 | #include "sei.h"
|
|---|
| 40 |
|
|---|
| 41 | typedef struct AVSeiData {
|
|---|
| 42 | uint8_t info[4096];
|
|---|
| 43 | int size;
|
|---|
| 44 | } AVSeiData;
|
|---|
| 45 |
|
|---|
| 46 | typedef struct libx265Context {
|
|---|
| 47 | const AVClass *class;
|
|---|
| 48 |
|
|---|
| 49 | x265_encoder *encoder;
|
|---|
| 50 | x265_param *params;
|
|---|
| 51 | const x265_api *api;
|
|---|
| 52 |
|
|---|
| 53 | float crf;
|
|---|
| 54 | int cqp;
|
|---|
| 55 | int forced_idr;
|
|---|
| 56 | char *preset;
|
|---|
| 57 | char *tune;
|
|---|
| 58 | char *profile;
|
|---|
| 59 | AVDictionary *x265_opts;
|
|---|
| 60 |
|
|---|
| 61 | void *sei_data;
|
|---|
| 62 | int sei_data_size;
|
|---|
| 63 | int udu_sei;
|
|---|
| 64 |
|
|---|
| 65 | /**
|
|---|
| 66 | * If the encoder does not support ROI then warn the first time we
|
|---|
| 67 | * encounter a frame with ROI side data.
|
|---|
| 68 | */
|
|---|
| 69 | int roi_warned;
|
|---|
| 70 | } libx265Context;
|
|---|
| 71 |
|
|---|
| 72 | static int is_keyframe(NalUnitType naltype)
|
|---|
| 73 | {
|
|---|
| 74 | switch (naltype) {
|
|---|
| 75 | case NAL_UNIT_CODED_SLICE_BLA_W_LP:
|
|---|
| 76 | case NAL_UNIT_CODED_SLICE_BLA_W_RADL:
|
|---|
| 77 | case NAL_UNIT_CODED_SLICE_BLA_N_LP:
|
|---|
| 78 | case NAL_UNIT_CODED_SLICE_IDR_W_RADL:
|
|---|
| 79 | case NAL_UNIT_CODED_SLICE_IDR_N_LP:
|
|---|
| 80 | case NAL_UNIT_CODED_SLICE_CRA:
|
|---|
| 81 | return 1;
|
|---|
| 82 | default:
|
|---|
| 83 | return 0;
|
|---|
| 84 | }
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | static av_cold int libx265_encode_close(AVCodecContext *avctx)
|
|---|
| 88 | {
|
|---|
| 89 | libx265Context *ctx = avctx->priv_data;
|
|---|
| 90 |
|
|---|
| 91 | ctx->api->param_free(ctx->params);
|
|---|
| 92 | av_freep(&ctx->sei_data);
|
|---|
| 93 |
|
|---|
| 94 | if (ctx->encoder)
|
|---|
| 95 | ctx->api->encoder_close(ctx->encoder);
|
|---|
| 96 |
|
|---|
| 97 | return 0;
|
|---|
| 98 | }
|
|---|
| 99 |
|
|---|
| 100 | static av_cold int libx265_param_parse_float(AVCodecContext *avctx,
|
|---|
| 101 | const char *key, float value)
|
|---|
| 102 | {
|
|---|
| 103 | libx265Context *ctx = avctx->priv_data;
|
|---|
| 104 | char buf[256];
|
|---|
| 105 |
|
|---|
| 106 | snprintf(buf, sizeof(buf), "%2.2f", value);
|
|---|
| 107 | if (ctx->api->param_parse(ctx->params, key, buf) == X265_PARAM_BAD_VALUE) {
|
|---|
| 108 | av_log(avctx, AV_LOG_ERROR, "Invalid value %2.2f for param \"%s\".\n", value, key);
|
|---|
| 109 | return AVERROR(EINVAL);
|
|---|
| 110 | }
|
|---|
| 111 |
|
|---|
| 112 | return 0;
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | static av_cold int libx265_param_parse_int(AVCodecContext *avctx,
|
|---|
| 116 | const char *key, int value)
|
|---|
| 117 | {
|
|---|
| 118 | libx265Context *ctx = avctx->priv_data;
|
|---|
| 119 | char buf[256];
|
|---|
| 120 |
|
|---|
| 121 | snprintf(buf, sizeof(buf), "%d", value);
|
|---|
| 122 | if (ctx->api->param_parse(ctx->params, key, buf) == X265_PARAM_BAD_VALUE) {
|
|---|
| 123 | av_log(avctx, AV_LOG_ERROR, "Invalid value %d for param \"%s\".\n", value, key);
|
|---|
| 124 | return AVERROR(EINVAL);
|
|---|
| 125 | }
|
|---|
| 126 |
|
|---|
| 127 | return 0;
|
|---|
| 128 | }
|
|---|
| 129 |
|
|---|
| 130 | static av_cold int libx265_encode_init(AVCodecContext *avctx)
|
|---|
| 131 | {
|
|---|
| 132 | libx265Context *ctx = avctx->priv_data;
|
|---|
| 133 | AVCPBProperties *cpb_props = NULL;
|
|---|
| 134 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
|
|---|
| 135 | int ret;
|
|---|
| 136 |
|
|---|
| 137 | ctx->api = x265_api_get(desc->comp[0].depth);
|
|---|
| 138 | if (!ctx->api)
|
|---|
| 139 | ctx->api = x265_api_get(0);
|
|---|
| 140 |
|
|---|
| 141 | ctx->params = ctx->api->param_alloc();
|
|---|
| 142 | if (!ctx->params) {
|
|---|
| 143 | av_log(avctx, AV_LOG_ERROR, "Could not allocate x265 param structure.\n");
|
|---|
| 144 | return AVERROR(ENOMEM);
|
|---|
| 145 | }
|
|---|
| 146 |
|
|---|
| 147 | if (ctx->api->param_default_preset(ctx->params, ctx->preset, ctx->tune) < 0) {
|
|---|
| 148 | int i;
|
|---|
| 149 |
|
|---|
| 150 | av_log(avctx, AV_LOG_ERROR, "Error setting preset/tune %s/%s.\n", ctx->preset, ctx->tune);
|
|---|
| 151 | av_log(avctx, AV_LOG_INFO, "Possible presets:");
|
|---|
| 152 | for (i = 0; x265_preset_names[i]; i++)
|
|---|
| 153 | av_log(avctx, AV_LOG_INFO, " %s", x265_preset_names[i]);
|
|---|
| 154 |
|
|---|
| 155 | av_log(avctx, AV_LOG_INFO, "\n");
|
|---|
| 156 | av_log(avctx, AV_LOG_INFO, "Possible tunes:");
|
|---|
| 157 | for (i = 0; x265_tune_names[i]; i++)
|
|---|
| 158 | av_log(avctx, AV_LOG_INFO, " %s", x265_tune_names[i]);
|
|---|
| 159 |
|
|---|
| 160 | av_log(avctx, AV_LOG_INFO, "\n");
|
|---|
| 161 |
|
|---|
| 162 | return AVERROR(EINVAL);
|
|---|
| 163 | }
|
|---|
| 164 |
|
|---|
| 165 | ctx->params->frameNumThreads = avctx->thread_count;
|
|---|
| 166 | if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
|
|---|
| 167 | ctx->params->fpsNum = avctx->framerate.num;
|
|---|
| 168 | ctx->params->fpsDenom = avctx->framerate.den;
|
|---|
| 169 | } else {
|
|---|
| 170 | ctx->params->fpsNum = avctx->time_base.den;
|
|---|
| 171 | ctx->params->fpsDenom = avctx->time_base.num * avctx->ticks_per_frame;
|
|---|
| 172 | }
|
|---|
| 173 | ctx->params->sourceWidth = avctx->width;
|
|---|
| 174 | ctx->params->sourceHeight = avctx->height;
|
|---|
| 175 | ctx->params->bEnablePsnr = !!(avctx->flags & AV_CODEC_FLAG_PSNR);
|
|---|
| 176 | ctx->params->bOpenGOP = !(avctx->flags & AV_CODEC_FLAG_CLOSED_GOP);
|
|---|
| 177 |
|
|---|
| 178 | /* Tune the CTU size based on input resolution. */
|
|---|
| 179 | if (ctx->params->sourceWidth < 64 || ctx->params->sourceHeight < 64)
|
|---|
| 180 | ctx->params->maxCUSize = 32;
|
|---|
| 181 | if (ctx->params->sourceWidth < 32 || ctx->params->sourceHeight < 32)
|
|---|
| 182 | ctx->params->maxCUSize = 16;
|
|---|
| 183 | if (ctx->params->sourceWidth < 16 || ctx->params->sourceHeight < 16) {
|
|---|
| 184 | av_log(avctx, AV_LOG_ERROR, "Image size is too small (%dx%d).\n",
|
|---|
| 185 | ctx->params->sourceWidth, ctx->params->sourceHeight);
|
|---|
| 186 | return AVERROR(EINVAL);
|
|---|
| 187 | }
|
|---|
| 188 |
|
|---|
| 189 |
|
|---|
| 190 | ctx->params->vui.bEnableVideoSignalTypePresentFlag = 1;
|
|---|
| 191 |
|
|---|
| 192 | if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED)
|
|---|
| 193 | ctx->params->vui.bEnableVideoFullRangeFlag =
|
|---|
| 194 | avctx->color_range == AVCOL_RANGE_JPEG;
|
|---|
| 195 | else
|
|---|
| 196 | ctx->params->vui.bEnableVideoFullRangeFlag =
|
|---|
| 197 | (desc->flags & AV_PIX_FMT_FLAG_RGB) ||
|
|---|
| 198 | avctx->pix_fmt == AV_PIX_FMT_YUVJ420P ||
|
|---|
| 199 | avctx->pix_fmt == AV_PIX_FMT_YUVJ422P ||
|
|---|
| 200 | avctx->pix_fmt == AV_PIX_FMT_YUVJ444P;
|
|---|
| 201 |
|
|---|
| 202 | if ((avctx->color_primaries <= AVCOL_PRI_SMPTE432 &&
|
|---|
| 203 | avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) ||
|
|---|
| 204 | (avctx->color_trc <= AVCOL_TRC_ARIB_STD_B67 &&
|
|---|
| 205 | avctx->color_trc != AVCOL_TRC_UNSPECIFIED) ||
|
|---|
| 206 | (avctx->colorspace <= AVCOL_SPC_ICTCP &&
|
|---|
| 207 | avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) {
|
|---|
| 208 |
|
|---|
| 209 | ctx->params->vui.bEnableColorDescriptionPresentFlag = 1;
|
|---|
| 210 |
|
|---|
| 211 | // x265 validates the parameters internally
|
|---|
| 212 | ctx->params->vui.colorPrimaries = avctx->color_primaries;
|
|---|
| 213 | ctx->params->vui.transferCharacteristics = avctx->color_trc;
|
|---|
| 214 | #if X265_BUILD >= 159
|
|---|
| 215 | if (avctx->color_trc == AVCOL_TRC_ARIB_STD_B67)
|
|---|
| 216 | ctx->params->preferredTransferCharacteristics = ctx->params->vui.transferCharacteristics;
|
|---|
| 217 | #endif
|
|---|
| 218 | ctx->params->vui.matrixCoeffs = avctx->colorspace;
|
|---|
| 219 | }
|
|---|
| 220 |
|
|---|
| 221 | // chroma sample location values are to be ignored in case of non-4:2:0
|
|---|
| 222 | // according to the specification, so we only write them out in case of
|
|---|
| 223 | // 4:2:0 (log2_chroma_{w,h} == 1).
|
|---|
| 224 | ctx->params->vui.bEnableChromaLocInfoPresentFlag =
|
|---|
| 225 | avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED &&
|
|---|
| 226 | desc->log2_chroma_w == 1 && desc->log2_chroma_h == 1;
|
|---|
| 227 |
|
|---|
| 228 | if (ctx->params->vui.bEnableChromaLocInfoPresentFlag) {
|
|---|
| 229 | ctx->params->vui.chromaSampleLocTypeTopField =
|
|---|
| 230 | ctx->params->vui.chromaSampleLocTypeBottomField =
|
|---|
| 231 | avctx->chroma_sample_location - 1;
|
|---|
| 232 | }
|
|---|
| 233 |
|
|---|
| 234 | if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) {
|
|---|
| 235 | char sar[12];
|
|---|
| 236 | int sar_num, sar_den;
|
|---|
| 237 |
|
|---|
| 238 | av_reduce(&sar_num, &sar_den,
|
|---|
| 239 | avctx->sample_aspect_ratio.num,
|
|---|
| 240 | avctx->sample_aspect_ratio.den, 65535);
|
|---|
| 241 | snprintf(sar, sizeof(sar), "%d:%d", sar_num, sar_den);
|
|---|
| 242 | if (ctx->api->param_parse(ctx->params, "sar", sar) == X265_PARAM_BAD_VALUE) {
|
|---|
| 243 | av_log(avctx, AV_LOG_ERROR, "Invalid SAR: %d:%d.\n", sar_num, sar_den);
|
|---|
| 244 | return AVERROR_INVALIDDATA;
|
|---|
| 245 | }
|
|---|
| 246 | }
|
|---|
| 247 |
|
|---|
| 248 | switch (desc->log2_chroma_w) {
|
|---|
| 249 | // 4:4:4, RGB. gray
|
|---|
| 250 | case 0:
|
|---|
| 251 | // gray
|
|---|
| 252 | if (desc->nb_components == 1) {
|
|---|
| 253 | if (ctx->api->api_build_number < 85) {
|
|---|
| 254 | av_log(avctx, AV_LOG_ERROR,
|
|---|
| 255 | "libx265 version is %d, must be at least 85 for gray encoding.\n",
|
|---|
| 256 | ctx->api->api_build_number);
|
|---|
| 257 | return AVERROR_INVALIDDATA;
|
|---|
| 258 | }
|
|---|
| 259 | ctx->params->internalCsp = X265_CSP_I400;
|
|---|
| 260 | break;
|
|---|
| 261 | }
|
|---|
| 262 |
|
|---|
| 263 | // set identity matrix for RGB
|
|---|
| 264 | if (desc->flags & AV_PIX_FMT_FLAG_RGB) {
|
|---|
| 265 | ctx->params->vui.matrixCoeffs = AVCOL_SPC_RGB;
|
|---|
| 266 | ctx->params->vui.bEnableVideoSignalTypePresentFlag = 1;
|
|---|
| 267 | ctx->params->vui.bEnableColorDescriptionPresentFlag = 1;
|
|---|
| 268 | }
|
|---|
| 269 |
|
|---|
| 270 | ctx->params->internalCsp = X265_CSP_I444;
|
|---|
| 271 | break;
|
|---|
| 272 | // 4:2:0, 4:2:2
|
|---|
| 273 | case 1:
|
|---|
| 274 | ctx->params->internalCsp = desc->log2_chroma_h == 1 ?
|
|---|
| 275 | X265_CSP_I420 : X265_CSP_I422;
|
|---|
| 276 | break;
|
|---|
| 277 | default:
|
|---|
| 278 | av_log(avctx, AV_LOG_ERROR,
|
|---|
| 279 | "Pixel format '%s' cannot be mapped to a libx265 CSP!\n",
|
|---|
| 280 | desc->name);
|
|---|
| 281 | return AVERROR_BUG;
|
|---|
| 282 | }
|
|---|
| 283 |
|
|---|
| 284 | if (ctx->crf >= 0) {
|
|---|
| 285 | char crf[6];
|
|---|
| 286 |
|
|---|
| 287 | snprintf(crf, sizeof(crf), "%2.2f", ctx->crf);
|
|---|
| 288 | if (ctx->api->param_parse(ctx->params, "crf", crf) == X265_PARAM_BAD_VALUE) {
|
|---|
| 289 | av_log(avctx, AV_LOG_ERROR, "Invalid crf: %2.2f.\n", ctx->crf);
|
|---|
| 290 | return AVERROR(EINVAL);
|
|---|
| 291 | }
|
|---|
| 292 | } else if (avctx->bit_rate > 0) {
|
|---|
| 293 | ctx->params->rc.bitrate = avctx->bit_rate / 1000;
|
|---|
| 294 | ctx->params->rc.rateControlMode = X265_RC_ABR;
|
|---|
| 295 | } else if (ctx->cqp >= 0) {
|
|---|
| 296 | ret = libx265_param_parse_int(avctx, "qp", ctx->cqp);
|
|---|
| 297 | if (ret < 0)
|
|---|
| 298 | return ret;
|
|---|
| 299 | }
|
|---|
| 300 |
|
|---|
| 301 | #if X265_BUILD >= 89
|
|---|
| 302 | if (avctx->qmin >= 0) {
|
|---|
| 303 | ret = libx265_param_parse_int(avctx, "qpmin", avctx->qmin);
|
|---|
| 304 | if (ret < 0)
|
|---|
| 305 | return ret;
|
|---|
| 306 | }
|
|---|
| 307 | if (avctx->qmax >= 0) {
|
|---|
| 308 | ret = libx265_param_parse_int(avctx, "qpmax", avctx->qmax);
|
|---|
| 309 | if (ret < 0)
|
|---|
| 310 | return ret;
|
|---|
| 311 | }
|
|---|
| 312 | #endif
|
|---|
| 313 | if (avctx->max_qdiff >= 0) {
|
|---|
| 314 | ret = libx265_param_parse_int(avctx, "qpstep", avctx->max_qdiff);
|
|---|
| 315 | if (ret < 0)
|
|---|
| 316 | return ret;
|
|---|
| 317 | }
|
|---|
| 318 | if (avctx->qblur >= 0) {
|
|---|
| 319 | ret = libx265_param_parse_float(avctx, "qblur", avctx->qblur);
|
|---|
| 320 | if (ret < 0)
|
|---|
| 321 | return ret;
|
|---|
| 322 | }
|
|---|
| 323 | if (avctx->qcompress >= 0) {
|
|---|
| 324 | ret = libx265_param_parse_float(avctx, "qcomp", avctx->qcompress);
|
|---|
| 325 | if (ret < 0)
|
|---|
| 326 | return ret;
|
|---|
| 327 | }
|
|---|
| 328 | if (avctx->i_quant_factor >= 0) {
|
|---|
| 329 | ret = libx265_param_parse_float(avctx, "ipratio", avctx->i_quant_factor);
|
|---|
| 330 | if (ret < 0)
|
|---|
| 331 | return ret;
|
|---|
| 332 | }
|
|---|
| 333 | if (avctx->b_quant_factor >= 0) {
|
|---|
| 334 | ret = libx265_param_parse_float(avctx, "pbratio", avctx->b_quant_factor);
|
|---|
| 335 | if (ret < 0)
|
|---|
| 336 | return ret;
|
|---|
| 337 | }
|
|---|
| 338 |
|
|---|
| 339 | ctx->params->rc.vbvBufferSize = avctx->rc_buffer_size / 1000;
|
|---|
| 340 | ctx->params->rc.vbvMaxBitrate = avctx->rc_max_rate / 1000;
|
|---|
| 341 |
|
|---|
| 342 | cpb_props = ff_add_cpb_side_data(avctx);
|
|---|
| 343 | if (!cpb_props)
|
|---|
| 344 | return AVERROR(ENOMEM);
|
|---|
| 345 | cpb_props->buffer_size = ctx->params->rc.vbvBufferSize * 1000;
|
|---|
| 346 | cpb_props->max_bitrate = ctx->params->rc.vbvMaxBitrate * 1000LL;
|
|---|
| 347 | cpb_props->avg_bitrate = ctx->params->rc.bitrate * 1000LL;
|
|---|
| 348 |
|
|---|
| 349 | if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER))
|
|---|
| 350 | ctx->params->bRepeatHeaders = 1;
|
|---|
| 351 |
|
|---|
| 352 | if (avctx->gop_size >= 0) {
|
|---|
| 353 | ret = libx265_param_parse_int(avctx, "keyint", avctx->gop_size);
|
|---|
| 354 | if (ret < 0)
|
|---|
| 355 | return ret;
|
|---|
| 356 | }
|
|---|
| 357 | if (avctx->keyint_min > 0) {
|
|---|
| 358 | ret = libx265_param_parse_int(avctx, "min-keyint", avctx->keyint_min);
|
|---|
| 359 | if (ret < 0)
|
|---|
| 360 | return ret;
|
|---|
| 361 | }
|
|---|
| 362 | if (avctx->max_b_frames >= 0) {
|
|---|
| 363 | ret = libx265_param_parse_int(avctx, "bframes", avctx->max_b_frames);
|
|---|
| 364 | if (ret < 0)
|
|---|
| 365 | return ret;
|
|---|
| 366 | }
|
|---|
| 367 | if (avctx->refs >= 0) {
|
|---|
| 368 | ret = libx265_param_parse_int(avctx, "ref", avctx->refs);
|
|---|
| 369 | if (ret < 0)
|
|---|
| 370 | return ret;
|
|---|
| 371 | }
|
|---|
| 372 |
|
|---|
| 373 | {
|
|---|
| 374 | AVDictionaryEntry *en = NULL;
|
|---|
| 375 | while ((en = av_dict_get(ctx->x265_opts, "", en, AV_DICT_IGNORE_SUFFIX))) {
|
|---|
| 376 | int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value);
|
|---|
| 377 |
|
|---|
| 378 | switch (parse_ret) {
|
|---|
| 379 | case X265_PARAM_BAD_NAME:
|
|---|
| 380 | av_log(avctx, AV_LOG_WARNING,
|
|---|
| 381 | "Unknown option: %s.\n", en->key);
|
|---|
| 382 | break;
|
|---|
| 383 | case X265_PARAM_BAD_VALUE:
|
|---|
| 384 | av_log(avctx, AV_LOG_WARNING,
|
|---|
| 385 | "Invalid value for %s: %s.\n", en->key, en->value);
|
|---|
| 386 | break;
|
|---|
| 387 | default:
|
|---|
| 388 | break;
|
|---|
| 389 | }
|
|---|
| 390 | }
|
|---|
| 391 | }
|
|---|
| 392 |
|
|---|
| 393 | if (ctx->params->rc.vbvBufferSize && avctx->rc_initial_buffer_occupancy > 1000 &&
|
|---|
| 394 | ctx->params->rc.vbvBufferInit == 0.9) {
|
|---|
| 395 | ctx->params->rc.vbvBufferInit = (float)avctx->rc_initial_buffer_occupancy / 1000;
|
|---|
| 396 | }
|
|---|
| 397 |
|
|---|
| 398 | if (ctx->profile) {
|
|---|
| 399 | if (ctx->api->param_apply_profile(ctx->params, ctx->profile) < 0) {
|
|---|
| 400 | int i;
|
|---|
| 401 | av_log(avctx, AV_LOG_ERROR, "Invalid or incompatible profile set: %s.\n", ctx->profile);
|
|---|
| 402 | av_log(avctx, AV_LOG_INFO, "Possible profiles:");
|
|---|
| 403 | for (i = 0; x265_profile_names[i]; i++)
|
|---|
| 404 | av_log(avctx, AV_LOG_INFO, " %s", x265_profile_names[i]);
|
|---|
| 405 | av_log(avctx, AV_LOG_INFO, "\n");
|
|---|
| 406 | return AVERROR(EINVAL);
|
|---|
| 407 | }
|
|---|
| 408 | }
|
|---|
| 409 |
|
|---|
| 410 | ctx->encoder = ctx->api->encoder_open(ctx->params);
|
|---|
| 411 | if (!ctx->encoder) {
|
|---|
| 412 | av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n");
|
|---|
| 413 | libx265_encode_close(avctx);
|
|---|
| 414 | return AVERROR_INVALIDDATA;
|
|---|
| 415 | }
|
|---|
| 416 |
|
|---|
| 417 | if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
|
|---|
| 418 | x265_nal *nal;
|
|---|
| 419 | int nnal;
|
|---|
| 420 |
|
|---|
| 421 | avctx->extradata_size = ctx->api->encoder_headers(ctx->encoder, &nal, &nnal);
|
|---|
| 422 | if (avctx->extradata_size <= 0) {
|
|---|
| 423 | av_log(avctx, AV_LOG_ERROR, "Cannot encode headers.\n");
|
|---|
| 424 | libx265_encode_close(avctx);
|
|---|
| 425 | return AVERROR_INVALIDDATA;
|
|---|
| 426 | }
|
|---|
| 427 |
|
|---|
| 428 | avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
|
|---|
| 429 | if (!avctx->extradata) {
|
|---|
| 430 | av_log(avctx, AV_LOG_ERROR,
|
|---|
| 431 | "Cannot allocate HEVC header of size %d.\n", avctx->extradata_size);
|
|---|
| 432 | libx265_encode_close(avctx);
|
|---|
| 433 | return AVERROR(ENOMEM);
|
|---|
| 434 | }
|
|---|
| 435 |
|
|---|
| 436 | memcpy(avctx->extradata, nal[0].payload, avctx->extradata_size);
|
|---|
| 437 | memset(avctx->extradata + avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
|---|
| 438 | }
|
|---|
| 439 |
|
|---|
| 440 | return 0;
|
|---|
| 441 | }
|
|---|
| 442 |
|
|---|
| 443 | static av_cold int libx265_encode_set_roi(libx265Context *ctx, const AVFrame *frame, x265_picture* pic)
|
|---|
| 444 | {
|
|---|
| 445 | AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST);
|
|---|
| 446 | if (sd) {
|
|---|
| 447 | if (ctx->params->rc.aqMode == X265_AQ_NONE) {
|
|---|
| 448 | if (!ctx->roi_warned) {
|
|---|
| 449 | ctx->roi_warned = 1;
|
|---|
| 450 | av_log(ctx, AV_LOG_WARNING, "Adaptive quantization must be enabled to use ROI encoding, skipping ROI.\n");
|
|---|
| 451 | }
|
|---|
| 452 | } else {
|
|---|
| 453 | /* 8x8 block when qg-size is 8, 16*16 block otherwise. */
|
|---|
| 454 | int mb_size = (ctx->params->rc.qgSize == 8) ? 8 : 16;
|
|---|
| 455 | int mbx = (frame->width + mb_size - 1) / mb_size;
|
|---|
| 456 | int mby = (frame->height + mb_size - 1) / mb_size;
|
|---|
| 457 | int qp_range = 51 + 6 * (pic->bitDepth - 8);
|
|---|
| 458 | int nb_rois;
|
|---|
| 459 | const AVRegionOfInterest *roi;
|
|---|
| 460 | uint32_t roi_size;
|
|---|
| 461 | float *qoffsets; /* will be freed after encode is called. */
|
|---|
| 462 |
|
|---|
| 463 | roi = (const AVRegionOfInterest*)sd->data;
|
|---|
| 464 | roi_size = roi->self_size;
|
|---|
| 465 | if (!roi_size || sd->size % roi_size != 0) {
|
|---|
| 466 | av_log(ctx, AV_LOG_ERROR, "Invalid AVRegionOfInterest.self_size.\n");
|
|---|
| 467 | return AVERROR(EINVAL);
|
|---|
| 468 | }
|
|---|
| 469 | nb_rois = sd->size / roi_size;
|
|---|
| 470 |
|
|---|
| 471 | qoffsets = av_calloc(mbx * mby, sizeof(*qoffsets));
|
|---|
| 472 | if (!qoffsets)
|
|---|
| 473 | return AVERROR(ENOMEM);
|
|---|
| 474 |
|
|---|
| 475 | // This list must be iterated in reverse because the first
|
|---|
| 476 | // region in the list applies when regions overlap.
|
|---|
| 477 | for (int i = nb_rois - 1; i >= 0; i--) {
|
|---|
| 478 | int startx, endx, starty, endy;
|
|---|
| 479 | float qoffset;
|
|---|
| 480 |
|
|---|
| 481 | roi = (const AVRegionOfInterest*)(sd->data + roi_size * i);
|
|---|
| 482 |
|
|---|
| 483 | starty = FFMIN(mby, roi->top / mb_size);
|
|---|
| 484 | endy = FFMIN(mby, (roi->bottom + mb_size - 1)/ mb_size);
|
|---|
| 485 | startx = FFMIN(mbx, roi->left / mb_size);
|
|---|
| 486 | endx = FFMIN(mbx, (roi->right + mb_size - 1)/ mb_size);
|
|---|
| 487 |
|
|---|
| 488 | if (roi->qoffset.den == 0) {
|
|---|
| 489 | av_free(qoffsets);
|
|---|
| 490 | av_log(ctx, AV_LOG_ERROR, "AVRegionOfInterest.qoffset.den must not be zero.\n");
|
|---|
| 491 | return AVERROR(EINVAL);
|
|---|
| 492 | }
|
|---|
| 493 | qoffset = roi->qoffset.num * 1.0f / roi->qoffset.den;
|
|---|
| 494 | qoffset = av_clipf(qoffset * qp_range, -qp_range, +qp_range);
|
|---|
| 495 |
|
|---|
| 496 | for (int y = starty; y < endy; y++)
|
|---|
| 497 | for (int x = startx; x < endx; x++)
|
|---|
| 498 | qoffsets[x + y*mbx] = qoffset;
|
|---|
| 499 | }
|
|---|
| 500 |
|
|---|
| 501 | pic->quantOffsets = qoffsets;
|
|---|
| 502 | }
|
|---|
| 503 | }
|
|---|
| 504 | return 0;
|
|---|
| 505 | }
|
|---|
| 506 | static int record = 0;
|
|---|
| 507 | static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
|
|---|
| 508 | const AVFrame *pic, int *got_packet)
|
|---|
| 509 | {
|
|---|
| 510 | libx265Context *ctx = avctx->priv_data;
|
|---|
| 511 | x265_picture x265pic;
|
|---|
| 512 | x265_picture x265pic_out = { 0 };
|
|---|
| 513 | x265_nal *nal;
|
|---|
| 514 | uint8_t *dst;
|
|---|
| 515 | int pict_type;
|
|---|
| 516 | int payload = 0;
|
|---|
| 517 | int nnal;
|
|---|
| 518 | int ret;
|
|---|
| 519 | int i;
|
|---|
| 520 |
|
|---|
| 521 | ctx->api->picture_init(ctx->params, &x265pic);
|
|---|
| 522 |
|
|---|
| 523 | if (pic) {
|
|---|
| 524 | x265_sei *sei = &x265pic.userSEI;
|
|---|
| 525 | sei->numPayloads = 0;
|
|---|
| 526 | for (i = 0; i < 3; i++) {
|
|---|
| 527 | x265pic.planes[i] = pic->data[i];
|
|---|
| 528 | x265pic.stride[i] = pic->linesize[i];
|
|---|
| 529 | }
|
|---|
| 530 |
|
|---|
| 531 | x265pic.pts = pic->pts;
|
|---|
| 532 | x265pic.bitDepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
|
|---|
| 533 |
|
|---|
| 534 | x265pic.sliceType = pic->pict_type == AV_PICTURE_TYPE_I ?
|
|---|
| 535 | (ctx->forced_idr ? X265_TYPE_IDR : X265_TYPE_I) :
|
|---|
| 536 | pic->pict_type == AV_PICTURE_TYPE_P ? X265_TYPE_P :
|
|---|
| 537 | pic->pict_type == AV_PICTURE_TYPE_B ? X265_TYPE_B :
|
|---|
| 538 | X265_TYPE_AUTO;
|
|---|
| 539 |
|
|---|
| 540 | ret = libx265_encode_set_roi(ctx, pic, &x265pic);
|
|---|
| 541 | if (ret < 0)
|
|---|
| 542 | return ret;
|
|---|
| 543 |
|
|---|
| 544 | if (pic->reordered_opaque) {
|
|---|
| 545 | x265pic.userData = av_malloc(sizeof(pic->reordered_opaque));
|
|---|
| 546 | if (!x265pic.userData) {
|
|---|
| 547 | av_freep(&x265pic.quantOffsets);
|
|---|
| 548 | return AVERROR(ENOMEM);
|
|---|
| 549 | }
|
|---|
| 550 |
|
|---|
| 551 | memcpy(x265pic.userData, &pic->reordered_opaque, sizeof(pic->reordered_opaque));
|
|---|
| 552 | }
|
|---|
| 553 |
|
|---|
| 554 | if (ctx->udu_sei) {
|
|---|
| 555 | for (i = 0; i < pic->nb_side_data; i++) {
|
|---|
| 556 | AVFrameSideData *side_data = pic->side_data[i];
|
|---|
| 557 | void *tmp;
|
|---|
| 558 | x265_sei_payload *sei_payload;
|
|---|
| 559 |
|
|---|
| 560 | if (side_data->type != AV_FRAME_DATA_SEI_UNREGISTERED)
|
|---|
| 561 | continue;
|
|---|
| 562 |
|
|---|
| 563 | tmp = av_fast_realloc(ctx->sei_data,
|
|---|
| 564 | &ctx->sei_data_size,
|
|---|
| 565 | (sei->numPayloads + 1) * sizeof(*sei_payload));
|
|---|
| 566 | if (!tmp) {
|
|---|
| 567 | av_freep(&x265pic.userData);
|
|---|
| 568 | av_freep(&x265pic.quantOffsets);
|
|---|
| 569 | return AVERROR(ENOMEM);
|
|---|
| 570 | }
|
|---|
| 571 | ctx->sei_data = tmp;
|
|---|
| 572 | sei->payloads = ctx->sei_data;
|
|---|
| 573 | sei_payload = &sei->payloads[sei->numPayloads];
|
|---|
| 574 | sei_payload->payload = side_data->data;
|
|---|
| 575 | sei_payload->payloadSize = side_data->size;
|
|---|
| 576 | /* Equal to libx265 USER_DATA_UNREGISTERED */
|
|---|
| 577 | sei_payload->payloadType = SEI_TYPE_USER_DATA_UNREGISTERED;
|
|---|
| 578 | sei->numPayloads++;
|
|---|
| 579 | }
|
|---|
| 580 | }
|
|---|
| 581 | }
|
|---|
| 582 |
|
|---|
| 583 | AVSeiData seiData;
|
|---|
| 584 | memset(&seiData, 0, sizeof(AVSeiData));
|
|---|
| 585 | if (x265pic.sliceType == X265_TYPE_IDR || x265pic.sliceType == X265_TYPE_I)
|
|---|
| 586 | {
|
|---|
| 587 | if (record < 2)
|
|---|
| 588 | {
|
|---|
| 589 | seiData.size = 10;
|
|---|
| 590 | }
|
|---|
| 591 | if (record >= 2)
|
|---|
| 592 | {
|
|---|
| 593 | seiData.size = 100;
|
|---|
| 594 | }
|
|---|
| 595 | uint8_t d = 1;
|
|---|
| 596 | for (int j = 0; j < seiData.size; j++)
|
|---|
| 597 | {
|
|---|
| 598 | seiData.info[j] = d++;
|
|---|
| 599 | }
|
|---|
| 600 | seiData.info[seiData.size - 1] = 0x0;
|
|---|
| 601 |
|
|---|
| 602 | if (seiData.size > 0)
|
|---|
| 603 | {
|
|---|
| 604 | x265pic.userSEI.numPayloads = 1;
|
|---|
| 605 |
|
|---|
| 606 | printf("hevc seidata = %s,size= %d, size2=%d, size3=%d\n", seiData.info, sizeof(x265_sei_payload), sizeof(x265pic.userSEI.payloads[0]), seiData.size);
|
|---|
| 607 |
|
|---|
| 608 | x265pic.userSEI.payloads = av_mallocz(sizeof(x265_sei_payload));
|
|---|
| 609 | x265pic.userSEI.payloads[0].payloadSize = seiData.size;
|
|---|
| 610 | x265pic.userSEI.payloads[0].payload = av_mallocz(seiData.size);
|
|---|
| 611 | memcpy(x265pic.userSEI.payloads[0].payload, seiData.info, seiData.size);
|
|---|
| 612 | x265pic.userSEI.payloads[0].payloadType = USER_DATA_UNREGISTERED;
|
|---|
| 613 | record++;
|
|---|
| 614 | }
|
|---|
| 615 | }
|
|---|
| 616 |
|
|---|
| 617 | ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal,
|
|---|
| 618 | pic ? &x265pic : NULL, &x265pic_out);
|
|---|
| 619 |
|
|---|
| 620 | av_freep(&x265pic.quantOffsets);
|
|---|
| 621 | if (x265pic.userSEI.numPayloads > 0) {
|
|---|
| 622 | for (int i = 0; i < x265pic.userSEI.numPayloads; i++) {
|
|---|
| 623 | av_free(x265pic.userSEI.payloads[i].payload);
|
|---|
| 624 | }
|
|---|
| 625 | av_free(x265pic.userSEI.payloads);
|
|---|
| 626 | }
|
|---|
| 627 | if (ret < 0)
|
|---|
| 628 | return AVERROR_EXTERNAL;
|
|---|
| 629 |
|
|---|
| 630 | if (!nnal)
|
|---|
| 631 | return 0;
|
|---|
| 632 |
|
|---|
| 633 | for (i = 0; i < nnal; i++)
|
|---|
| 634 | payload += nal[i].sizeBytes;
|
|---|
| 635 |
|
|---|
| 636 | ret = ff_get_encode_buffer(avctx, pkt, payload, 0);
|
|---|
| 637 | if (ret < 0) {
|
|---|
| 638 | av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
|
|---|
| 639 | return ret;
|
|---|
| 640 | }
|
|---|
| 641 | dst = pkt->data;
|
|---|
| 642 |
|
|---|
| 643 | for (i = 0; i < nnal; i++) {
|
|---|
| 644 | memcpy(dst, nal[i].payload, nal[i].sizeBytes);
|
|---|
| 645 | dst += nal[i].sizeBytes;
|
|---|
| 646 |
|
|---|
| 647 | if (is_keyframe(nal[i].type))
|
|---|
| 648 | pkt->flags |= AV_PKT_FLAG_KEY;
|
|---|
| 649 | }
|
|---|
| 650 |
|
|---|
| 651 | pkt->pts = x265pic_out.pts;
|
|---|
| 652 | pkt->dts = x265pic_out.dts;
|
|---|
| 653 |
|
|---|
| 654 | switch (x265pic_out.sliceType) {
|
|---|
| 655 | case X265_TYPE_IDR:
|
|---|
| 656 | case X265_TYPE_I:
|
|---|
| 657 | pict_type = AV_PICTURE_TYPE_I;
|
|---|
| 658 | break;
|
|---|
| 659 | case X265_TYPE_P:
|
|---|
| 660 | pict_type = AV_PICTURE_TYPE_P;
|
|---|
| 661 | break;
|
|---|
| 662 | case X265_TYPE_B:
|
|---|
| 663 | case X265_TYPE_BREF:
|
|---|
| 664 | pict_type = AV_PICTURE_TYPE_B;
|
|---|
| 665 | break;
|
|---|
| 666 | default:
|
|---|
| 667 | av_log(avctx, AV_LOG_ERROR, "Unknown picture type encountered.\n");
|
|---|
| 668 | return AVERROR_EXTERNAL;
|
|---|
| 669 | }
|
|---|
| 670 |
|
|---|
| 671 | #if X265_BUILD >= 130
|
|---|
| 672 | if (x265pic_out.sliceType == X265_TYPE_B)
|
|---|
| 673 | #else
|
|---|
| 674 | if (x265pic_out.frameData.sliceType == 'b')
|
|---|
| 675 | #endif
|
|---|
| 676 | pkt->flags |= AV_PKT_FLAG_DISPOSABLE;
|
|---|
| 677 |
|
|---|
| 678 | ff_side_data_set_encoder_stats(pkt, x265pic_out.frameData.qp * FF_QP2LAMBDA, NULL, 0, pict_type);
|
|---|
| 679 |
|
|---|
| 680 | if (x265pic_out.userData) {
|
|---|
| 681 | memcpy(&avctx->reordered_opaque, x265pic_out.userData, sizeof(avctx->reordered_opaque));
|
|---|
| 682 | av_freep(&x265pic_out.userData);
|
|---|
| 683 | } else
|
|---|
| 684 | avctx->reordered_opaque = 0;
|
|---|
| 685 |
|
|---|
| 686 | *got_packet = 1;
|
|---|
| 687 | return 0;
|
|---|
| 688 | }
|
|---|
| 689 |
|
|---|
| 690 | static const enum AVPixelFormat x265_csp_eight[] = {
|
|---|
| 691 | AV_PIX_FMT_YUV420P,
|
|---|
| 692 | AV_PIX_FMT_YUVJ420P,
|
|---|
| 693 | AV_PIX_FMT_YUV422P,
|
|---|
| 694 | AV_PIX_FMT_YUVJ422P,
|
|---|
| 695 | AV_PIX_FMT_YUV444P,
|
|---|
| 696 | AV_PIX_FMT_YUVJ444P,
|
|---|
| 697 | AV_PIX_FMT_GBRP,
|
|---|
| 698 | AV_PIX_FMT_GRAY8,
|
|---|
| 699 | AV_PIX_FMT_NONE
|
|---|
| 700 | };
|
|---|
| 701 |
|
|---|
| 702 | static const enum AVPixelFormat x265_csp_ten[] = {
|
|---|
| 703 | AV_PIX_FMT_YUV420P,
|
|---|
| 704 | AV_PIX_FMT_YUVJ420P,
|
|---|
| 705 | AV_PIX_FMT_YUV422P,
|
|---|
| 706 | AV_PIX_FMT_YUVJ422P,
|
|---|
| 707 | AV_PIX_FMT_YUV444P,
|
|---|
| 708 | AV_PIX_FMT_YUVJ444P,
|
|---|
| 709 | AV_PIX_FMT_GBRP,
|
|---|
| 710 | AV_PIX_FMT_YUV420P10,
|
|---|
| 711 | AV_PIX_FMT_YUV422P10,
|
|---|
| 712 | AV_PIX_FMT_YUV444P10,
|
|---|
| 713 | AV_PIX_FMT_GBRP10,
|
|---|
| 714 | AV_PIX_FMT_GRAY8,
|
|---|
| 715 | AV_PIX_FMT_GRAY10,
|
|---|
| 716 | AV_PIX_FMT_NONE
|
|---|
| 717 | };
|
|---|
| 718 |
|
|---|
| 719 | static const enum AVPixelFormat x265_csp_twelve[] = {
|
|---|
| 720 | AV_PIX_FMT_YUV420P,
|
|---|
| 721 | AV_PIX_FMT_YUVJ420P,
|
|---|
| 722 | AV_PIX_FMT_YUV422P,
|
|---|
| 723 | AV_PIX_FMT_YUVJ422P,
|
|---|
| 724 | AV_PIX_FMT_YUV444P,
|
|---|
| 725 | AV_PIX_FMT_YUVJ444P,
|
|---|
| 726 | AV_PIX_FMT_GBRP,
|
|---|
| 727 | AV_PIX_FMT_YUV420P10,
|
|---|
| 728 | AV_PIX_FMT_YUV422P10,
|
|---|
| 729 | AV_PIX_FMT_YUV444P10,
|
|---|
| 730 | AV_PIX_FMT_GBRP10,
|
|---|
| 731 | AV_PIX_FMT_YUV420P12,
|
|---|
| 732 | AV_PIX_FMT_YUV422P12,
|
|---|
| 733 | AV_PIX_FMT_YUV444P12,
|
|---|
| 734 | AV_PIX_FMT_GBRP12,
|
|---|
| 735 | AV_PIX_FMT_GRAY8,
|
|---|
| 736 | AV_PIX_FMT_GRAY10,
|
|---|
| 737 | AV_PIX_FMT_GRAY12,
|
|---|
| 738 | AV_PIX_FMT_NONE
|
|---|
| 739 | };
|
|---|
| 740 |
|
|---|
| 741 | static av_cold void libx265_encode_init_csp(FFCodec *codec)
|
|---|
| 742 | {
|
|---|
| 743 | if (x265_api_get(12))
|
|---|
| 744 | codec->p.pix_fmts = x265_csp_twelve;
|
|---|
| 745 | else if (x265_api_get(10))
|
|---|
| 746 | codec->p.pix_fmts = x265_csp_ten;
|
|---|
| 747 | else if (x265_api_get(8))
|
|---|
| 748 | codec->p.pix_fmts = x265_csp_eight;
|
|---|
| 749 | }
|
|---|
| 750 |
|
|---|
| 751 | #define OFFSET(x) offsetof(libx265Context, x)
|
|---|
| 752 | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
|
|---|
| 753 | static const AVOption options[] = {
|
|---|
| 754 | { "crf", "set the x265 crf", OFFSET(crf), AV_OPT_TYPE_FLOAT, { .dbl = -1 }, -1, FLT_MAX, VE },
|
|---|
| 755 | { "qp", "set the x265 qp", OFFSET(cqp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE },
|
|---|
| 756 | { "forced-idr", "if forcing keyframes, force them as IDR frames", OFFSET(forced_idr),AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
|
|---|
| 757 | { "preset", "set the x265 preset", OFFSET(preset), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
|
|---|
| 758 | { "tune", "set the x265 tune parameter", OFFSET(tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
|
|---|
| 759 | { "profile", "set the x265 profile", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
|
|---|
| 760 | { "udu_sei", "Use user data unregistered SEI if available", OFFSET(udu_sei), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
|
|---|
| 761 | { "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE },
|
|---|
| 762 | { NULL }
|
|---|
| 763 | };
|
|---|
| 764 |
|
|---|
| 765 | static const AVClass class = {
|
|---|
| 766 | .class_name = "libx265",
|
|---|
| 767 | .item_name = av_default_item_name,
|
|---|
| 768 | .option = options,
|
|---|
| 769 | .version = LIBAVUTIL_VERSION_INT,
|
|---|
| 770 | };
|
|---|
| 771 |
|
|---|
| 772 | static const FFCodecDefault x265_defaults[] = {
|
|---|
| 773 | { "b", "0" },
|
|---|
| 774 | { "bf", "-1" },
|
|---|
| 775 | { "g", "-1" },
|
|---|
| 776 | { "keyint_min", "-1" },
|
|---|
| 777 | { "refs", "-1" },
|
|---|
| 778 | { "qmin", "-1" },
|
|---|
| 779 | { "qmax", "-1" },
|
|---|
| 780 | { "qdiff", "-1" },
|
|---|
| 781 | { "qblur", "-1" },
|
|---|
| 782 | { "qcomp", "-1" },
|
|---|
| 783 | { "i_qfactor", "-1" },
|
|---|
| 784 | { "b_qfactor", "-1" },
|
|---|
| 785 | { NULL },
|
|---|
| 786 | };
|
|---|
| 787 |
|
|---|
| 788 | FFCodec ff_libx265_encoder = {
|
|---|
| 789 | .p.name = "libx265",
|
|---|
| 790 | .p.long_name = NULL_IF_CONFIG_SMALL("libx265 H.265 / HEVC"),
|
|---|
| 791 | .p.type = AVMEDIA_TYPE_VIDEO,
|
|---|
| 792 | .p.id = AV_CODEC_ID_HEVC,
|
|---|
| 793 | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
|
|---|
| 794 | AV_CODEC_CAP_OTHER_THREADS |
|
|---|
| 795 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
|
|---|
| 796 | .p.priv_class = &class,
|
|---|
| 797 | .p.wrapper_name = "libx265",
|
|---|
| 798 | .init = libx265_encode_init,
|
|---|
| 799 | .init_static_data = libx265_encode_init_csp,
|
|---|
| 800 | FF_CODEC_ENCODE_CB(libx265_encode_frame),
|
|---|
| 801 | .close = libx265_encode_close,
|
|---|
| 802 | .priv_data_size = sizeof(libx265Context),
|
|---|
| 803 | .defaults = x265_defaults,
|
|---|
| 804 | .caps_internal = FF_CODEC_CAP_AUTO_THREADS,
|
|---|
| 805 | };
|
|---|