#endif
#include <x265.h>
+#include <float.h>
#include "libavutil/internal.h"
#include "libavutil/common.h"
x265_encoder *encoder;
x265_param *params;
+ const x265_api *api;
+ float crf;
+ int forced_idr;
char *preset;
char *tune;
char *x265_opts;
{
libx265Context *ctx = avctx->priv_data;
- av_frame_free(&avctx->coded_frame);
-
- x265_param_free(ctx->params);
+ ctx->api->param_free(ctx->params);
if (ctx->encoder)
- x265_encoder_close(ctx->encoder);
+ ctx->api->encoder_close(ctx->encoder);
return 0;
}
{
libx265Context *ctx = avctx->priv_data;
+ ctx->api = x265_api_get(av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth);
+ if (!ctx->api)
+ ctx->api = x265_api_get(0);
+
if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL &&
!av_pix_fmt_desc_get(avctx->pix_fmt)->log2_chroma_w) {
av_log(avctx, AV_LOG_ERROR,
return AVERROR(ENOSYS);
}
- avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame) {
- av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
- return AVERROR(ENOMEM);
- }
-
- ctx->params = x265_param_alloc();
+ ctx->params = ctx->api->param_alloc();
if (!ctx->params) {
av_log(avctx, AV_LOG_ERROR, "Could not allocate x265 param structure.\n");
return AVERROR(ENOMEM);
}
- if (x265_param_default_preset(ctx->params, ctx->preset, ctx->tune) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Invalid preset or tune.\n");
+ if (ctx->api->param_default_preset(ctx->params, ctx->preset, ctx->tune) < 0) {
+ 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");
+
return AVERROR(EINVAL);
}
ctx->params->fpsDenom = avctx->time_base.num * avctx->ticks_per_frame;
ctx->params->sourceWidth = avctx->width;
ctx->params->sourceHeight = avctx->height;
- ctx->params->bEnablePsnr = !!(avctx->flags & CODEC_FLAG_PSNR);
+ ctx->params->bEnablePsnr = !!(avctx->flags & AV_CODEC_FLAG_PSNR);
+
+ 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;
+ }
if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) {
char sar[12];
avctx->sample_aspect_ratio.num,
avctx->sample_aspect_ratio.den, 65535);
snprintf(sar, sizeof(sar), "%d:%d", sar_num, sar_den);
- if (x265_param_parse(ctx->params, "sar", sar) == X265_PARAM_BAD_VALUE) {
+ if (ctx->api->param_parse(ctx->params, "sar", sar) == X265_PARAM_BAD_VALUE) {
av_log(avctx, AV_LOG_ERROR, "Invalid SAR: %d:%d.\n", sar_num, sar_den);
return AVERROR_INVALIDDATA;
}
break;
}
- if (avctx->bit_rate > 0) {
+ if (ctx->crf >= 0) {
+ char crf[6];
+
+ snprintf(crf, sizeof(crf), "%2.2f", ctx->crf);
+ if (ctx->api->param_parse(ctx->params, "crf", crf) == X265_PARAM_BAD_VALUE) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid crf: %2.2f.\n", ctx->crf);
+ return AVERROR(EINVAL);
+ }
+ } else if (avctx->bit_rate > 0) {
ctx->params->rc.bitrate = avctx->bit_rate / 1000;
ctx->params->rc.rateControlMode = X265_RC_ABR;
}
- if (!(avctx->flags & CODEC_FLAG_GLOBAL_HEADER))
+ if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER))
ctx->params->bRepeatHeaders = 1;
if (ctx->x265_opts) {
if (!av_dict_parse_string(&dict, ctx->x265_opts, "=", ":", 0)) {
while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) {
- int parse_ret = x265_param_parse(ctx->params, en->key, en->value);
+ int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value);
switch (parse_ret) {
case X265_PARAM_BAD_NAME:
}
}
- ctx->encoder = x265_encoder_open(ctx->params);
+ ctx->encoder = ctx->api->encoder_open(ctx->params);
if (!ctx->encoder) {
av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n");
libx265_encode_close(avctx);
return AVERROR_INVALIDDATA;
}
- if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) {
+ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
x265_nal *nal;
int nnal;
- avctx->extradata_size = x265_encoder_headers(ctx->encoder, &nal, &nnal);
+ avctx->extradata_size = ctx->api->encoder_headers(ctx->encoder, &nal, &nnal);
if (avctx->extradata_size <= 0) {
av_log(avctx, AV_LOG_ERROR, "Cannot encode headers.\n");
libx265_encode_close(avctx);
return AVERROR_INVALIDDATA;
}
- avctx->extradata = av_malloc(avctx->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
+ avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!avctx->extradata) {
av_log(avctx, AV_LOG_ERROR,
"Cannot allocate HEVC header of size %d.\n", avctx->extradata_size);
{
libx265Context *ctx = avctx->priv_data;
x265_picture x265pic;
- x265_picture x265pic_out = { { 0 } };
+ x265_picture x265pic_out = { 0 };
x265_nal *nal;
uint8_t *dst;
int payload = 0;
int ret;
int i;
- x265_picture_init(ctx->params, &x265pic);
+ ctx->api->picture_init(ctx->params, &x265pic);
if (pic) {
for (i = 0; i < 3; i++) {
}
x265pic.pts = pic->pts;
- x265pic.bitDepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth_minus1 + 1;
+ x265pic.bitDepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth;
- x265pic.sliceType = pic->pict_type == AV_PICTURE_TYPE_I ? X265_TYPE_I :
+ x265pic.sliceType = pic->pict_type == AV_PICTURE_TYPE_I ?
+ (ctx->forced_idr ? X265_TYPE_IDR : X265_TYPE_I) :
pic->pict_type == AV_PICTURE_TYPE_P ? X265_TYPE_P :
pic->pict_type == AV_PICTURE_TYPE_B ? X265_TYPE_B :
X265_TYPE_AUTO;
}
- ret = x265_encoder_encode(ctx->encoder, &nal, &nnal,
- pic ? &x265pic : NULL, &x265pic_out);
+ ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal,
+ pic ? &x265pic : NULL, &x265pic_out);
if (ret < 0)
return AVERROR_UNKNOWN;
pkt->pts = x265pic_out.pts;
pkt->dts = x265pic_out.dts;
+#if FF_API_CODED_FRAME
+FF_DISABLE_DEPRECATION_WARNINGS
+ 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;
+ }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
*got_packet = 1;
return 0;
}
#define OFFSET(x) offsetof(libx265Context, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
+ { "crf", "set the x265 crf", OFFSET(crf), AV_OPT_TYPE_FLOAT, { .dbl = -1 }, -1, FLT_MAX, VE },
+ { "forced-idr", "if forcing keyframes, force them as IDR frames", OFFSET(forced_idr),AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
{ "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 },
.priv_data_size = sizeof(libx265Context),
.priv_class = &class,
.defaults = x265_defaults,
- .capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS,
+ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
};