[FFmpeg-devel] [PATCH v3] avcodec: Add librav1e encoder
James Almer
jamrial at gmail.com
Thu May 30 05:12:11 EEST 2019
On 5/29/2019 3:28 PM, Derek Buitenhuis wrote:
> Uses the crav1e C bindings for rav1e.
>
> Port to the new send/receive API by: James Almer <jamrial at gmail.com>.
>
> Signed-off-by: Derek Buitenhuis <derek.buitenhuis at gmail.com>
> ---
> Changes since v2:
>
> * Removed 4:0:0 support; seems broken in rav1e (ref: https://github.com/xiph/rav1e/issues/1312)
> * Moved to use FF_CODEC_CAP_INIT_CLEANUP.
> * Set time base for ratecontrol purposes (tested, as well).
> * Used desc->nb_components for loop.
> ---
> configure | 4 +
> doc/encoders.texi | 29 +++
> doc/general.texi | 7 +
> libavcodec/Makefile | 1 +
> libavcodec/allcodecs.c | 1 +
> libavcodec/librav1e.c | 415 +++++++++++++++++++++++++++++++++++++++++
> 6 files changed, 457 insertions(+)
> create mode 100644 libavcodec/librav1e.c
[...]
> +static av_cold int librav1e_encode_init(AVCodecContext *avctx)
> +{
> + librav1eContext *ctx = avctx->priv_data;
> + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
> + RaConfig *cfg = NULL;
> + int rret;
> + int ret = 0;
> +
> + cfg = rav1e_config_default();
> + if (!cfg) {
> + av_log(avctx, AV_LOG_ERROR, "Could not allocate rav1e config.\n");
> + ret = AVERROR_EXTERNAL;
You can return directly here.
> + goto end;
> + }
> +
> + rav1e_config_set_time_base(cfg, (RaRational) {
> + avctx->time_base.num * avctx->ticks_per_frame,
> + avctx->time_base.den
> + });
> +
> + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
> + const AVBitStreamFilter *filter = av_bsf_get_by_name("extract_extradata");
> + int bret;
> +
> + if (!filter) {
> + av_log(avctx, AV_LOG_ERROR, "extract_extradata bitstream filter "
> + "not found. This is a bug, please report it.\n");
> + ret = AVERROR_BUG;
> + goto end;
> + }
> +
> + bret = av_bsf_alloc(filter, &ctx->bsf);
> + if (bret < 0) {
> + ret = bret;
> + goto end;
> + }
> +
> + bret = avcodec_parameters_from_context(ctx->bsf->par_in, avctx);
> + if (bret < 0) {
> + ret = bret;
> + goto end;
> + }
> +
> + bret = av_bsf_init(ctx->bsf);
> + if (bret < 0) {
> + ret = bret;
> + goto end;
> + }
> + }
> +
> + if (ctx->rav1e_opts) {
> + AVDictionary *dict = NULL;
> + AVDictionaryEntry *en = NULL;
> +
> + if (!av_dict_parse_string(&dict, ctx->rav1e_opts, "=", ":", 0)) {
> + while (en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX)) {
> + int parse_ret = rav1e_config_parse(cfg, en->key, en->value);
> + if (parse_ret < 0)
> + av_log(avctx, AV_LOG_WARNING, "Invalid value for %s: %s.\n", en->key, en->value);
> + }
> + av_dict_free(&dict);
> + }
> + }
> +
> + rret = rav1e_config_parse_int(cfg, "width", avctx->width);
> + if (rret < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Invalid width passed to rav1e.\n");
> + ret = AVERROR_INVALIDDATA;
> + goto end;
> + }
> +
> + rret = rav1e_config_parse_int(cfg, "height", avctx->height);
> + if (rret < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Invalid width passed to rav1e.\n");
> + ret = AVERROR_INVALIDDATA;
> + goto end;
> + }
> +
> + rret = rav1e_config_parse_int(cfg, "threads", avctx->thread_count);
> + if (rret < 0)
> + av_log(avctx, AV_LOG_WARNING, "Invalid number of threads, defaulting to auto.\n");
> +
> + if (avctx->bit_rate && ctx->quantizer < 0) {
> + int max_quantizer = avctx->qmax >= 0 ? avctx->qmax : 255;
> +
> + rret = rav1e_config_parse_int(cfg, "quantizer", max_quantizer);
> + if (rret < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Could not set max quantizer.\n");
> + ret = AVERROR_EXTERNAL;
> + goto end;
> + }
> +
> + rret = rav1e_config_parse_int(cfg, "bitrate", avctx->bit_rate);
> + if (rret < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Could not set bitrate.\n");
> + ret = AVERROR_INVALIDDATA;
> + goto end;
> + }
> + } else if (ctx->quantizer >= 0) {
> + rret = rav1e_config_parse_int(cfg, "quantizer", ctx->quantizer);
> + if (rret < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Could not set quantizer.\n");
> + ret = AVERROR_EXTERNAL;
> + goto end;
> + }
> + }
> +
> + rret = rav1e_config_set_pixel_format(cfg, desc->comp[0].depth,
> + pix_fmt_map(avctx->pix_fmt),
> + chroma_loc_map(avctx->chroma_sample_location),
> + range_map(avctx->color_range));
> + if (rret < 0) {
> + av_log(avctx, AV_LOG_ERROR, "Failed to set pixel format properties.\n");
> + ret = AVERROR_INVALIDDATA;
> + goto end;
> + }
> +
> + /* rav1e's colorspace enums match standard values. */
> + rret = rav1e_config_set_color_description(cfg, (RaMatrixCoefficients) avctx->colorspace,
> + (RaColorPrimaries) avctx->color_primaries,
> + (RaTransferCharacteristics) avctx->color_trc);
> + if (rret < 0) {
> + av_log(avctx, AV_LOG_WARNING, "Failed to set color properties.\n");
> + if (avctx->err_recognition & AV_EF_EXPLODE) {
> + ret = AVERROR_INVALIDDATA;
> + goto end;
> + }
> + }
> +
> + ctx->ctx = rav1e_context_new(cfg);
> + if (!ctx->ctx) {
> + av_log(avctx, AV_LOG_ERROR, "Failed to create rav1e encode context.\n");
> + ret = AVERROR_EXTERNAL;
> + goto end;
> + }
> +
> + ret = 0;
> +
> +end:
> + if (cfg)
If you change the above then this check becomes unnecessary, as cfg will
never be NULL here.
> + rav1e_config_unref(cfg);
> +
> + return ret;
> +}
More information about the ffmpeg-devel
mailing list