[vlc-devel] [PATCH 4/4] Add rav1e encoder module

Tristan Matthews tmatth at videolan.org
Tue Jul 21 16:09:27 CEST 2020


Hi,

On Tue, Jul 21, 2020 at 5:34 AM rustyc <kartikohri13 at gmail.com> wrote:
>
> Co-Authored-By: Thomas Guillem <thomas at gllm.fr>
> ---
>  configure.ac              |   5 +
>  modules/codec/Makefile.am |   8 ++
>  modules/codec/rav1e.c     | 284 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 297 insertions(+)
>  create mode 100644 modules/codec/rav1e.c
>
> diff --git a/configure.ac b/configure.ac
> index 89fc36cdf4..a30e86bf37 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -2872,6 +2872,11 @@ dnl  AOM decoder plugin
>  dnl
>  PKG_ENABLE_MODULES_VLC([AOM], [], [aom], [experimental AV1 codec (default auto)])
>
> +dnl
> +dnl  Rav1e encoder plugin
> +dnl
> +PKG_ENABLE_MODULES_VLC([RAV1E], [], [rav1e], [rav1e encoder module codec (default auto)])
> +
>  dnl
>  dnl  Dav1d decoder plugin
>  dnl
> diff --git a/modules/codec/Makefile.am b/modules/codec/Makefile.am
> index dc0bda07dc..5c4ad53074 100644
> --- a/modules/codec/Makefile.am
> +++ b/modules/codec/Makefile.am
> @@ -545,6 +545,14 @@ libaom_plugin_la_LIBADD = $(AOM_LIBS)
>  EXTRA_LTLIBRARIES += libaom_plugin.la
>  codec_LTLIBRARIES += $(LTLIBaom)
>
> +librav1e_plugin_la_SOURCES = codec/rav1e.c
> +librav1e_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)
> +librav1e_plugin_la_CFLAGS = $(AM_CFLAGS) $(RAV1E_CFLAGS)
> +librav1e_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
> +librav1e_plugin_la_LIBADD = $(RAV1E_LIBS)
> +EXTRA_LTLIBRARIES += librav1e_plugin.la
> +codec_LTLIBRARIES += $(LTLIBrav1e)
> +
>  libtwolame_plugin_la_SOURCES = codec/twolame.c
>  libtwolame_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DLIBTWOLAME_STATIC
>  libtwolame_plugin_la_CFLAGS = $(AM_CFLAGS) $(TWOLAME_CFLAGS)
> diff --git a/modules/codec/rav1e.c b/modules/codec/rav1e.c
> new file mode 100644
> index 0000000000..238db450f0
> --- /dev/null
> +++ b/modules/codec/rav1e.c
> @@ -0,0 +1,284 @@
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <vlc_common.h>
> +#include <vlc_plugin.h>
> +#include <vlc_codec.h>
> +#include <rav1e/rav1e.h>
> +
> +#define SOUT_CFG_PREFIX "sout-rav1e-"
> +
> +typedef struct
> +{
> +    struct RaContext *ra_context;
> +    date_t date;
> +    bool date_set;
> +} encoder_sys_t;
> +
> +static block_t *Encode(encoder_t *enc, picture_t *p_pict)
> +{
> +    encoder_sys_t *sys = enc->p_sys;
> +    RaContext *ctx = sys->ra_context;
> +    block_t *p_out = NULL;
> +
> +    RaFrame *frame;
> +    if (p_pict != NULL)
> +    {
> +        if (!sys->date_set && p_pict->date != VLC_TICK_INVALID)
> +        {
> +            date_Set(&sys->date, p_pict->date);
> +            sys->date_set = true;
> +        }
> +
> +        frame = rav1e_frame_new(ctx);
> +        if (frame == NULL) {
> +            msg_Err(enc, "Unable to create new frame\n");
> +            goto error;
> +        }
> +
> +        for(int idx = 0; idx < p_pict->i_planes; idx++)
> +            rav1e_frame_fill_plane(frame, idx,
> +                                   p_pict->p[idx].p_pixels,
> +                                   p_pict->p[idx].i_pitch * p_pict->p[idx].i_visible_lines,
> +                                   p_pict->p[idx].i_pitch,
> +                                   p_pict->p[idx].i_pixel_pitch);
> +    }
> +    else
> +        frame = NULL; /* Drain with a NULL frame */
> +
> +    int ret = rav1e_send_frame(ctx, frame);
> +    if (ret != 0)
> +    {
> +        msg_Err(enc, "rav1e_send_frame failed: %d: %s", ret,
> +                rav1e_status_to_str(ret));
> +        goto error;

Won't this leak the frame on error (missing an unref?)

> +    }
> +    rav1e_frame_unref(frame);
> +
> +    bool again;
> +    do
> +    {
> +        RaPacket *pkt = NULL;
> +        ret = rav1e_receive_packet(ctx, &pkt);
> +
> +        switch (ret)
> +        {
> +            case RA_ENCODER_STATUS_SUCCESS:
> +            {
> +                block_t *p_block = block_Alloc(pkt->len);
> +                if (unlikely(p_block == NULL))
> +                {
> +                    block_ChainRelease(p_out);
> +                    p_out = NULL;
> +                    break;
> +                }
> +
> +                memcpy(p_block->p_buffer, pkt->data, pkt->len);
> +                p_block->i_dts = p_block->i_pts = date_Get(&sys->date);
> +                p_block->i_length =
> +                    vlc_tick_from_samples(enc->fmt_in.video.i_frame_rate_base,
> +                                          enc->fmt_in.video.i_frame_rate);
> +                date_Increment(&sys->date, 1);
> +
> +                if (pkt->frame_type == RA_FRAME_TYPE_KEY)
> +                    p_block->i_flags |= BLOCK_FLAG_TYPE_I;
> +                block_ChainAppend(&p_out, p_block);
> +                rav1e_packet_unref(pkt);
> +            }
> +            /* fall-through */
> +            case RA_ENCODER_STATUS_ENCODED:
> +                again = true;
> +                break;
> +            case RA_ENCODER_STATUS_LIMIT_REACHED:
> +            case RA_ENCODER_STATUS_NEED_MORE_DATA:
> +                again = false;
> +                break;
> +            default:
> +                msg_Err(enc, "rav1e_receive_packet() failed: %d: %s", ret,
> +                        rav1e_status_to_str(ret));
> +                goto error;
> +        }
> +    } while (again);
> +
> +    return p_out;
> +
> +error:
> +    free(p_out);
> +    return NULL;
> +}
> +
> +static int OpenEncoder(vlc_object_t *this)
> +{
> +    encoder_t *enc = (encoder_t *) this;
> +    encoder_sys_t *sys;
> +
> +    if (enc->fmt_out.i_codec != VLC_CODEC_AV1)
> +        return VLC_EGENERIC;
> +
> +    static const char *const ppsz_rav1e_options[] = {
> +        "bitdepth", "tile-rows", "tile-columns", NULL
> +    };
> +
> +    config_ChainParse(enc, SOUT_CFG_PREFIX, ppsz_rav1e_options, enc->p_cfg);
> +
> +    sys = malloc(sizeof(*sys));
> +    if (sys == NULL)
> +        return VLC_ENOMEM;
> +
> +    enc->p_sys = sys;
> +
> +    struct RaConfig *ra_config = rav1e_config_default();
> +    if (ra_config == NULL)
> +    {
> +        msg_Err(enc, "Unable to initialize configuration\n");
> +        free(sys);
> +        return VLC_EGENERIC;
> +    }
> +
> +    int ret;
> +
> +    ret = rav1e_config_parse_int(ra_config, "height", enc->fmt_in.video.i_visible_height);
> +    if (ret < 0)
> +    {
> +        msg_Err(enc, "Unable to set height\n");
> +        goto error;
> +    }
> +
> +    ret = rav1e_config_parse_int(ra_config, "width", enc->fmt_in.video.i_visible_width);
> +    if (ret < 0) {
> +        msg_Err(enc, "Unable to set width\n");
> +        goto error;
> +    }
> +
> +    RaRational *timebase = malloc(sizeof(RaRational));
> +    if (timebase == NULL)
> +    {
> +        msg_Err(enc, "%s", "Unable to set width\n");
> +        goto error;
> +    }
> +
> +    timebase->num = enc->fmt_in.video.i_frame_rate_base;
> +    timebase->den = enc->fmt_in.video.i_frame_rate;
> +    rav1e_config_set_time_base(ra_config, *timebase);
> +
> +    int tile_rows = var_InheritInteger(enc, SOUT_CFG_PREFIX "tile-rows");
> +    int tile_columns = var_InheritInteger(enc, SOUT_CFG_PREFIX "tile-columns");
> +    tile_rows = 1 << tile_rows;
> +    tile_columns = 1 << tile_columns;
> +
> +    ret = rav1e_config_parse_int(ra_config, "tile_rows", tile_rows);
> +    if (ret < 0)
> +    {
> +        msg_Err(enc, "Unable to set tile rows\n");
> +        goto error;
> +    }
> +
> +    ret = rav1e_config_parse_int(ra_config, "tile_cols", tile_columns);
> +    if (ret < 0)
> +    {
> +        msg_Err(enc, "Unable to set tile columns\n");
> +        goto error;
> +    }
> +
> +    int bitdepth = var_InheritInteger(enc, SOUT_CFG_PREFIX "bitdepth");
> +    int profile = var_InheritInteger(enc, SOUT_CFG_PREFIX "profile");
> +
> +    RaChromaSampling chroma_sampling;
> +    switch (profile)
> +    {
> +        case 2:
> +            chroma_sampling = RA_CHROMA_SAMPLING_CS422;
> +            enc->fmt_in.i_codec = bitdepth == 8 ? VLC_CODEC_I422 : VLC_CODEC_I422_10L;
> +            break;
> +        case 1:
> +            chroma_sampling = RA_CHROMA_SAMPLING_CS444;
> +            enc->fmt_in.i_codec = bitdepth == 8 ? VLC_CODEC_I444 : VLC_CODEC_I444_10L;
> +            break;
> +        default:
> +        case 0:
> +            chroma_sampling = RA_CHROMA_SAMPLING_CS420;
> +            enc->fmt_in.i_codec = bitdepth == 8 ? VLC_CODEC_I420 : VLC_CODEC_I420_10L;
> +            break;
> +    }
> +
> +    RaChromaSamplePosition sample_pos;
> +    switch (enc->fmt_in.video.chroma_location)
> +    {
> +        case CHROMA_LOCATION_LEFT:
> +            sample_pos = RA_CHROMA_SAMPLE_POSITION_VERTICAL;
> +            break;
> +        case CHROMA_LOCATION_TOP_LEFT:
> +            sample_pos = RA_CHROMA_SAMPLE_POSITION_COLOCATED;
> +            break;
> +        default:
> +            sample_pos = RA_CHROMA_SAMPLE_POSITION_UNKNOWN;
> +            break;
> +    }
> +
> +    RaPixelRange pixel_range;
> +    switch (enc->fmt_in.video.color_range)
> +    {
> +        case COLOR_RANGE_FULL:
> +            pixel_range = RA_PIXEL_RANGE_FULL;
> +            break;
> +        case COLOR_RANGE_LIMITED:
> +        default:
> +            pixel_range = RA_PIXEL_RANGE_LIMITED;
> +            break;
> +    }
> +    ret = rav1e_config_set_pixel_format(ra_config, bitdepth, chroma_sampling,
> +                                        sample_pos, pixel_range);
> +    if (ret < 0)
> +    {
> +        msg_Err(enc, "Unable to set pixel format\n");
> +        goto error;
> +    }
> +
> +
> +    sys->ra_context = rav1e_context_new(ra_config);
> +    if (!sys->ra_context)
> +    {
> +        msg_Err(enc, "Unable to allocate a new context\n");
> +        goto error;
> +    }
> +    rav1e_config_unref(ra_config);
> +
> +    date_Init(&sys->date, enc->fmt_out.video.i_frame_rate,
> +              enc->fmt_out.video.i_frame_rate_base);
> +    sys->date_set = false;
> +
> +    enc->pf_encode_video = Encode;
> +    return VLC_SUCCESS;
> +
> +error:
> +    rav1e_config_unref(ra_config);
> +    free(sys);
> +    return VLC_EGENERIC;
> +}
> +
> +static void CloseEncoder(vlc_object_t* this)
> +{
> +    encoder_t *enc = (encoder_t *) this;
> +    encoder_sys_t *sys = enc->p_sys;
> +    rav1e_context_unref(sys->ra_context);
> +    free(sys);
> +}
> +
> +static const int bitdepth_values_list[] = {8, 10};
> +static const char *bitdepth_values_name_list[] = {N_("8 bpp"), N_("10 bpp")};
> +
> +vlc_module_begin()
> +    set_shortname("rav1e")
> +    set_description(N_("rav1e video encoder"))
> +    set_capability("encoder", 101)
> +    set_callbacks(OpenEncoder, CloseEncoder)
> +    add_integer(SOUT_CFG_PREFIX "profile", 0, "Profile", NULL, true)
> +        change_integer_range(0, 3)
> +    add_integer(SOUT_CFG_PREFIX "bitdepth", 8, "Bit Depth", NULL, true)
> +        change_integer_list(bitdepth_values_list, bitdepth_values_name_list)
> +    add_integer(SOUT_CFG_PREFIX "tile-rows", 0, "Tile Rows (in log2 units)", NULL, true)
> +        change_integer_range(0, 6)
> +    add_integer(SOUT_CFG_PREFIX "tile-columns", 0, "Tile Columns (in log2 units)", NULL, true)
> +        change_integer_range(0, 6)
> +vlc_module_end()
> --
> 2.25.1
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list