diff mbox

[FFmpeg-devel,2/3] Add codec wrapper for librv11

Message ID 76fd6b26-c177-5d0c-1371-4b2754e4c43d@mail.de
State Superseded
Headers show

Commit Message

Thilo Borgmann Jan. 18, 2018, 6:37 p.m. UTC
From 0386c9e0a4c2ea1579378807ff5a7a04c508c50e Mon Sep 17 00:00:00 2001
From: Thilo Borgmann <thilo.borgmann@mail.de>
Date: Wed, 17 Jan 2018 23:13:53 +0100
Subject: [PATCH 2/3] Add codec wrapper for librv11

---
 MAINTAINERS             |   1 +
 configure               |   8 +
 libavcodec/Makefile     |   2 +
 libavcodec/allcodecs.c  |   2 +
 libavcodec/avcodec.h    |   1 +
 libavcodec/codec_desc.c |   7 +
 libavcodec/librv11.h    |  55 ++++
 libavcodec/librv11dec.c | 367 ++++++++++++++++++++++++
 libavcodec/librv11enc.c | 735 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/version.h    |   2 +-
 10 files changed, 1179 insertions(+), 1 deletion(-)
 create mode 100644 libavcodec/librv11.h
 create mode 100644 libavcodec/librv11dec.c
 create mode 100644 libavcodec/librv11enc.c

Comments

Carl Eugen Hoyos Jan. 18, 2018, 8:07 p.m. UTC | #1
2018-01-18 19:37 GMT+01:00 Thilo Borgmann <thilo.borgmann@mail.de>:

Needs non-free (and therefore cannot be auto-detected).
And please link at compile-time unless there are no
visible symbols except the lookup function.

Carl Eugen
James Almer Jan. 18, 2018, 8:16 p.m. UTC | #2
On 1/18/2018 3:37 PM, Thilo Borgmann wrote:
> From 0386c9e0a4c2ea1579378807ff5a7a04c508c50e Mon Sep 17 00:00:00 2001
> From: Thilo Borgmann <thilo.borgmann@mail.de>
> Date: Wed, 17 Jan 2018 23:13:53 +0100
> Subject: [PATCH 2/3] Add codec wrapper for librv11
> 
> ---
>  MAINTAINERS             |   1 +
>  configure               |   8 +
>  libavcodec/Makefile     |   2 +
>  libavcodec/allcodecs.c  |   2 +
>  libavcodec/avcodec.h    |   1 +
>  libavcodec/codec_desc.c |   7 +
>  libavcodec/librv11.h    |  55 ++++
>  libavcodec/librv11dec.c | 367 ++++++++++++++++++++++++
>  libavcodec/librv11enc.c | 735 ++++++++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/version.h    |   2 +-
>  10 files changed, 1179 insertions(+), 1 deletion(-)
>  create mode 100644 libavcodec/librv11.h
>  create mode 100644 libavcodec/librv11dec.c
>  create mode 100644 libavcodec/librv11enc.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index e583926..0067986 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -192,6 +192,7 @@ Codecs:
>    libkvazaar.c                          Arttu Ylä-Outinen
>    libopenjpeg.c                         Jaikrishnan Menon
>    libopenjpegenc.c                      Michael Bradshaw
> +  librv11*                              Thilo Borgmann, Qiang Luo
>    libtheoraenc.c                        David Conrad
>    libvorbis.c                           David Conrad
>    libvpx*                               James Zern
> diff --git a/configure b/configure
> index 5d53362..1c27852 100755
> --- a/configure
> +++ b/configure
> @@ -250,6 +250,8 @@ External library support:
>    --enable-librsvg         enable SVG rasterization via librsvg [no]
>    --enable-librubberband   enable rubberband needed for rubberband filter [no]
>    --enable-librtmp         enable RTMP[E] support via librtmp [no]
> +  --disable-librv11dec     enable RV11 decoding via rv11 [autodetect]
> +  --disable-librv11enc     enable RV11 encoding via rv11 [autodetect]

Single librv11 entry, please.

>    --enable-libshine        enable fixed-point MP3 encoding via libshine [no]
>    --enable-libsmbclient    enable Samba protocol via libsmbclient [no]
>    --enable-libsnappy       enable Snappy compression, needed for hap encoding [no]
> @@ -1535,6 +1537,8 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST="
>      bzlib
>      coreimage
>      iconv
> +    librv11enc
> +    librv11dec

This needs to be in EXTERNAL_LIBRARY_LIST, not in
EXTERNAL_AUTODETECT_LIBRARY_LIST. Also as i said above as a single entry.

>      libxcb
>      libxcb_shm
>      libxcb_shape
> @@ -2959,6 +2963,8 @@ libopus_decoder_deps="libopus"
>  libopus_encoder_deps="libopus"
>  libopus_encoder_select="audio_frame_queue"
>  librsvg_decoder_deps="librsvg"
> +librv11dec_decoder_deps="librv11dec"
> +librv11enc_encoder_deps="librv11enc"

librv11_decoder_deps="librv11"
librv11_encoder_deps="librv11"

>  libshine_encoder_deps="libshine"
>  libshine_encoder_select="audio_frame_queue"
>  libspeex_decoder_deps="libspeex"
> @@ -5890,6 +5896,8 @@ enabled libpulse          && require_pkg_config libpulse libpulse pulse/pulseaud
>  enabled librsvg           && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_render_cairo
>  enabled librtmp           && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket
>  enabled librubberband     && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++"
> +enabled librv11enc        && require_pkg_config librv11 librv11 librv11_sdk.h fpinit
> +enabled librv11dec        && require_pkg_config librv11 librv11 librv11_sdk.h fpinit

As is, these checks are not really enabling either of these two modules,
but a currently nonexistant one called librv11.

The only reason it worked like this is because you had them in the
autodetect list above.

enabled librv11           && require_pkg_config librv11 librv11
librv11_sdk.h fpinit

>  enabled libshine          && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer
>  enabled libsmbclient      && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init ||
>                                 require libsmbclient libsmbclient.h smbc_init -lsmbclient; }
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index cfacd6b..2e32815 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -948,6 +948,8 @@ OBJS-$(CONFIG_LIBOPUS_DECODER)            += libopusdec.o libopus.o     \
>                                               vorbis_data.o
>  OBJS-$(CONFIG_LIBOPUS_ENCODER)            += libopusenc.o libopus.o     \
>                                               vorbis_data.o
> +OBJS-$(CONFIG_LIBRV11DEC_DECODER)         += librv11dec.o
> +OBJS-$(CONFIG_LIBRV11ENC_ENCODER)         += librv11enc.o

OBJS-$(CONFIG_LIBRV11_DECODER)            += librv11dec.o
OBJS-$(CONFIG_LIBRV11_ENCODER)            += librv11enc.o

>  OBJS-$(CONFIG_LIBSHINE_ENCODER)           += libshine.o
>  OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
>  OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index ed1e7ab..8eb8610 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -548,6 +548,8 @@ static void register_all(void)
>      REGISTER_ENCDEC (LIBOPENJPEG,       libopenjpeg);
>      REGISTER_ENCDEC (LIBOPUS,           libopus);
>      REGISTER_DECODER(LIBRSVG,           librsvg);
> +    REGISTER_DECODER(LIBRV11DEC,        librv11dec);
> +    REGISTER_ENCODER(LIBRV11ENC,        librv11enc);

REGISTER_ENCDEC(LIBRV11, librv11)

>      REGISTER_ENCODER(LIBSHINE,          libshine);
>      REGISTER_ENCDEC (LIBSPEEX,          libspeex);
>      REGISTER_ENCODER(LIBTHEORA,         libtheora);
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 8fbbc79..b7c1fa1 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -409,6 +409,7 @@ enum AVCodecID {
>      AV_CODEC_ID_DXV,
>      AV_CODEC_ID_SCREENPRESSO,
>      AV_CODEC_ID_RSCC,
> +    AV_CODEC_ID_RV60,
>  
>      AV_CODEC_ID_Y41P = 0x8000,
>      AV_CODEC_ID_AVRP,
> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> index c3688de..1ad2c9c 100644
> --- a/libavcodec/codec_desc.c
> +++ b/libavcodec/codec_desc.c
> @@ -471,6 +471,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
>          .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
>      },
>      {
> +        .id        = AV_CODEC_ID_RV60,
> +        .type      = AVMEDIA_TYPE_VIDEO,
> +        .name      = "rv60",
> +        .long_name = NULL_IF_CONFIG_SMALL("RealVideo 11"),
> +        .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
> +    },
> +    {
>          .id        = AV_CODEC_ID_VC1,
>          .type      = AVMEDIA_TYPE_VIDEO,
>          .name      = "vc1",
> diff --git a/libavcodec/librv11.h b/libavcodec/librv11.h
> new file mode 100644
> index 0000000..44ec050
> --- /dev/null
> +++ b/libavcodec/librv11.h
> @@ -0,0 +1,55 @@
> +/*
> + * This copyright notice applies to this file only
> + * This Software is distributed under MIT License
> + *
> + * API software for using RealVideo 11 (RV60) Codec
> + *
> + *      * Copyright (c) 2017 Qiang Luo, RealNetworks, Inc. <qluo _at_ realnetworks.com>
> + *      * Copyright (c) 2017 Thilo Borgmann <thilo.borgmann _at_ mail.de>
> + *
> + * Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#ifndef AVCODEC_LIBRV11_H
> +#define AVCODEC_LIBRV11_H
> +
> +#include <librv11_sdk.h>
> +
> +#include "avcodec.h"
> +#include "libavutil/intreadwrite.h"
> +
> +#ifdef _WIN32
> +#include "compat/w32dlfcn.h"
> +#else
> +#include <dlfcn.h>
> +#endif
> +
> +#define RV_MAX_INPUT_FRAME_RATE 120
> +#define RV_NUM_OUT_FRAMES         6
> +
> +#define XSTR(s) STR(s)
> +#define STR(s) #s
> +#define LIBRV11DEC_FILE XSTR(RV_DEC_LIB_FILE)
> +#define LIBRV11ENC_FILE XSTR(RV_ENC_LIB_FILE)
> +
> +
> +#endif // AVCODEC_LIBRV11_H
> diff --git a/libavcodec/librv11dec.c b/libavcodec/librv11dec.c
> new file mode 100644
> index 0000000..269d684
> --- /dev/null
> +++ b/libavcodec/librv11dec.c
> @@ -0,0 +1,367 @@
> +/*
> + * This copyright notice applies to this file only
> + * This Software is distributed under MIT License
> + *
> + * API software for using RealVideo 11 (RV60) Decoder
> + *
> + *      * Copyright (c) 2017 Qiang Luo, RealNetworks, Inc. <qluo _at_ realnetworks.com>
> + *      * Copyright (c) 2017 Thilo Borgmann <thilo.borgmann _at_ mail.de>
> + *
> + * Permission is hereby granted, free of charge, to any person
> + * obtaining a copy of this software and associated documentation
> + * files (the "Software"), to deal in the Software without
> + * restriction, including without limitation the rights to use,
> + * copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following
> + * conditions:
> + *
> + * The above copyright notice and this permission notice shall be
> + * included in all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +#include "libavutil/imgutils.h"
> +#include "internal.h"
> +#include "get_bits.h"
> +
> +#include "librv11.h"
> +
> +typedef struct DecFnTable
> +{
> +    FPINIT      init;
> +    FPFREE      free;
> +    FPTRANSFORM transform;
> +    FPCUSTOMMSG custom_message;
> +    FPHIVEMSG   hive_message;
> +} DecFnTable;
> +
> +typedef struct LIBRV11DecContext {
> +    AVCodecContext *avctx;
> +    AVFrame        out_frame;
> +    void           *lib_handle;
> +    DecFnTable     *symbols;
> +    void           *codec_status;
> +    uint32_t       input_buf_size;
> +    uint32_t       input_buf_num;
> +    uint32_t       output_buf_size;
> +    uint32_t       output_buf_num;
> +    uint8_t        *output_buf[RV_NUM_OUT_FRAMES];
> +    int            frame_index;
> +    uint32_t       last_frame;
> +    uint32_t       more_frames;
> +} LIBRV11DecContext;
> +
> +static av_cold int librv11dec_load_symbols(AVCodecContext *avctx)
> +{
> +    LIBRV11DecContext *ctx = avctx->priv_data;
> +
> +    ctx->lib_handle = dlopen(LIBRV11DEC_FILE, RTLD_LAZY);
> +    if (!ctx->lib_handle) {
> +        av_log(avctx, AV_LOG_ERROR, "Cannot load dynamic library.\n");
> +        return AVERROR_EXTERNAL;
> +    }
> +
> +    ctx->symbols = av_mallocz(sizeof(DecFnTable));
> +    if (!ctx->symbols) {
> +        av_log(avctx, AV_LOG_ERROR, "Cannot allocate symbol table.\n");
> +        return AVERROR(ENOMEM);
> +    }
> +
> +#define LOAD_RV11_FUNC(handle, name) {                               \
> +    ctx->symbols->handle = dlsym(ctx->lib_handle, name);             \
> +    if (!ctx->symbols->handle) {                                     \
> +        av_log(avctx, AV_LOG_ERROR, "Cannot load symbol %s.", name); \
> +        return AVERROR_EXTERNAL;                                     \
> +    }                                                                \
> +}
> +
> +    LOAD_RV11_FUNC(init,           RV_CODEC_INIT);
> +    LOAD_RV11_FUNC(free,           RV_CODEC_FREE);
> +    LOAD_RV11_FUNC(transform,      RV_CODEC_TRANSFORM);
> +    LOAD_RV11_FUNC(custom_message, RV_CODEC_CUSTOM_MSG);
> +    LOAD_RV11_FUNC(hive_message,   RV_CODEC_HIVE_MSG);
> +
> +    return 0;
> +}

This should be linked at compile time.

> +
> +static av_cold int librv11dec_init(AVCodecContext *avctx)
> +{
> +    LIBRV11DecContext *ctx = avctx->priv_data;
> +    GetBitContext gb;
> +    RVInitParams init_params;
> +    RVMsgSimple msg;
> +    HX_RESULT res;
> +    uint32_t SPO_extra_flags;
> +    uint32_t version;
> +    int i;
> +    ctx->avctx = avctx;
> +
> +    if (!avctx->extradata || !avctx->extradata_size) {
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    init_get_bits(&gb, avctx->extradata, avctx->extradata_size * 8);
> +
> +    SPO_extra_flags = get_bits_long(&gb, 32);
> +    version         = get_bits_long(&gb, 32);

Use bytestream2 instead if you're reading full bytes. Or just AV_RB32()
and not bother with these APIs.

> +
> +    res = librv11dec_load_symbols(avctx);
> +    if (res) {
> +        av_freep(&ctx->symbols);
> +        return res;
> +    }
> +
> +    init_params.out_type   = 0;
> +    init_params.width      = avctx->width;
> +    init_params.height     = avctx->height;
> +    init_params.pad_width  = avctx->width;
> +    init_params.pad_height = avctx->height;
> +    init_params.pad_to_32  = 0;
> +    init_params.invariants = SPO_extra_flags;
> +    init_params.packetize  = 1;
> +    init_params.version    = version;
> +
> +    res = ctx->symbols->init(&init_params, &ctx->codec_status);
> +    if (res) {
> +        av_free(ctx->symbols);
> +        return res;
> +    }
> +
> +    msg.id     = RV_MSG_ID_SMOOTHING_POSTFILTER;
> +    msg.value1 = RV_MSG_DISABLE;
> +    msg.value2 = 0;
> +
> +    res = ctx->symbols->custom_message(&msg.id, ctx->codec_status);
> +    if (res) {
> +        return res;
> +    }
> +
> +    avctx->pix_fmt   = AV_PIX_FMT_YUV420P;
> +    ctx->last_frame  = 0;
> +    ctx->more_frames = 0;
> +    ctx->frame_index = 0;
> +
> +    ctx->output_buf_size = (avctx->width * avctx->height * 12) >> 3;
> +    for(i = 0; i < RV_NUM_OUT_FRAMES; i++) {
> +        ctx->output_buf[i] = av_mallocz(ctx->output_buf_size);
> +    }
> +    av_image_fill_arrays(ctx->out_frame.data, ctx->out_frame.linesize, ctx->output_buf[0], AV_PIX_FMT_YUV420P, avctx->width, avctx->height, 1);
> +
> +    return 0;
> +}
> +
> +static int librv11dec_decode_last(AVCodecContext *avctx, void *data,
> +                                    int *got_frame, AVPacket *avpkt)
> +{
> +    LIBRV11DecContext* ctx = avctx->priv_data;
> +    AVFrame *pict    = data;
> +    const int stride = avctx->width * avctx->height;
> +    RVInParams inParams;
> +    RVOutParams outParams;
> +    int32_t ret;
> +
> +    inParams.length       = 0;
> +    inParams.interpolate  = 0;
> +    inParams.num_segments = 0;
> +    inParams.segments     = NULL;
> +    inParams.timestamp    = 0;
> +    inParams.flags        = RV_DECODE_MORE_FRAMES;
> +
> +    pict->data[0] = ctx->output_buf[ctx->frame_index];
> +    pict->data[1] = ctx->output_buf[ctx->frame_index] + stride;
> +    pict->data[2] = ctx->output_buf[ctx->frame_index] + stride + (stride >> 2);
> +
> +    pict->linesize[0] = avctx->width;
> +    pict->linesize[1] = avctx->width >> 1;
> +    pict->linesize[2] = avctx->width >> 1;
> +
> +    ret = ctx->symbols->transform(NULL, ctx->output_buf[ctx->frame_index], &inParams, &outParams, ctx->codec_status);
> +    if (ret) {
> +        *got_frame = 0;
> +        return ret;
> +    }
> +
> +    if(outParams.notes & RV_DECODE_LAST_FRAME) {
> +        ctx->last_frame = 1;
> +    }
> +
> +    pict->pts       = outParams.timestamp;
> +#if FF_API_PKT_PTS
> +FF_DISABLE_DEPRECATION_WARNINGS
> +    pict->pkt_pts   = avpkt->pts;
> +FF_ENABLE_DEPRECATION_WARNINGS
> +#endif
> +    pict->pkt_dts   = avpkt->dts;

No need for this, it's the default behavior and handled by
AVCodec->decode2 when FF_CODEC_CAP_SETS_PKT_DTS is not set.

> +    pict->width     = avctx->width;
> +    pict->height    = avctx->height;
> +    pict->format    = AV_PIX_FMT_YUV420P;
> +    pict->key_frame = 0;
> +    pict->pict_type = AV_PICTURE_TYPE_P;
> +
> +    if (outParams.notes & RV_DECODE_KEY_FRAME) {
> +        pict->key_frame = 1;
> +        pict->pict_type = AV_PICTURE_TYPE_I;
> +    } else if (outParams.notes & RV_DECODE_B_FRAME ||
> +               outParams.notes & RV_DECODE_FRU_FRAME) {
> +        pict->key_frame = 0;
> +        pict->pict_type = AV_PICTURE_TYPE_B;
> +    }
> +
> +    *got_frame = !(outParams.notes & RV_DECODE_DONT_DRAW);
> +
> +    return 0;
> +
> +}
> +
> +static int librv11dec_decode_frame(AVCodecContext *avctx, void *data,
> +                                    int *got_frame, AVPacket *avpkt)
> +{
> +    LIBRV11DecContext* ctx = avctx->priv_data;
> +    const uint8_t *buf = avpkt->data;
> +    int buf_size       = avpkt->size;
> +    const int stride   = avctx->width * avctx->height;
> +    AVFrame *pict      = data;
> +    int slice_count    = 0;
> +    int consumed_bytes = 0;
> +    RVSegment *segment = NULL;
> +    RVInParams inParams;
> +    RVOutParams outParams;
> +    int32_t ret;
> +    int i;
> +
> +    ret = ff_get_buffer(avctx, pict, 0);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +
> +    ctx->frame_index++;
> +    ctx->frame_index %= RV_NUM_OUT_FRAMES;
> +
> +    if (!buf_size) { // maybe last frame
> +        if (ctx->last_frame) {
> +            *got_frame = 0;
> +            return 0;
> +        } else {
> +            return librv11dec_decode_last(avctx, data, got_frame, avpkt);
> +        }
> +    }
> +
> +    if (!avctx->slice_count) {
> +        slice_count = (*buf++) + 1;
> +        segment = av_mallocz(slice_count * sizeof(RVSegment));
> +        for (i = 0; i < slice_count; i++) {
> +            segment[i].is_valid = *buf;
> +            segment[i].offset   = *(buf + 4);
> +            buf += 8;
> +        }
> +        buf_size -= 1 + 8 * slice_count;
> +    } else {
> +        slice_count = avctx->slice_count;
> +    }
> +
> +    inParams.length       = buf_size;
> +    inParams.interpolate  = 0;
> +    inParams.num_segments = slice_count - 1;
> +    inParams.segments     = segment;
> +    inParams.timestamp    = avpkt->pts;
> +    inParams.flags        = 0;
> +
> +    pict->data[0] = ctx->output_buf[ctx->frame_index];
> +    pict->data[1] = ctx->output_buf[ctx->frame_index] + stride;
> +    pict->data[2] = ctx->output_buf[ctx->frame_index] + stride + (stride >> 2);
> +    pict->linesize[0] = avctx->width;
> +    pict->linesize[1] = avctx->width >> 1;
> +    pict->linesize[2] = avctx->width >> 1;
> +
> +    ret = ctx->symbols->transform((UCHAR*)buf, ctx->output_buf[ctx->frame_index], &inParams, &outParams, ctx->codec_status);
> +    if (ret) {
> +        consumed_bytes = 0;
> +        *got_frame     = 0;
> +        return ret;
> +    }
> +
> +    if (slice_count) {
> +        av_freep(&segment);
> +    }
> +
> +    consumed_bytes  = avpkt->size;
> +    *got_frame      = 1;
> +    pict->key_frame = 0;
> +    pict->pict_type = AV_PICTURE_TYPE_P;
> +
> +    if (outParams.notes & RV_DECODE_KEY_FRAME) {
> +        pict->pict_type = AV_PICTURE_TYPE_I;
> +        pict->key_frame = 1;
> +    } else if (outParams.notes & RV_DECODE_B_FRAME ||
> +               outParams.notes & RV_DECODE_FRU_FRAME) {
> +        pict->pict_type = AV_PICTURE_TYPE_B;
> +    } else if (outParams.notes & RV_DECODE_DONT_DRAW) {
> +        consumed_bytes  = 0;
> +        *got_frame      = 0;
> +    }
> +
> +    pict->pts     = outParams.timestamp;
> +#if FF_API_PKT_PTS
> +FF_DISABLE_DEPRECATION_WARNINGS
> +    pict->pkt_pts = avpkt->pts;
> +FF_ENABLE_DEPRECATION_WARNINGS
> +#endif
> +    pict->pkt_dts = avpkt->dts;

Same.
diff mbox

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index e583926..0067986 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -192,6 +192,7 @@  Codecs:
   libkvazaar.c                          Arttu Ylä-Outinen
   libopenjpeg.c                         Jaikrishnan Menon
   libopenjpegenc.c                      Michael Bradshaw
+  librv11*                              Thilo Borgmann, Qiang Luo
   libtheoraenc.c                        David Conrad
   libvorbis.c                           David Conrad
   libvpx*                               James Zern
diff --git a/configure b/configure
index 5d53362..1c27852 100755
--- a/configure
+++ b/configure
@@ -250,6 +250,8 @@  External library support:
   --enable-librsvg         enable SVG rasterization via librsvg [no]
   --enable-librubberband   enable rubberband needed for rubberband filter [no]
   --enable-librtmp         enable RTMP[E] support via librtmp [no]
+  --disable-librv11dec     enable RV11 decoding via rv11 [autodetect]
+  --disable-librv11enc     enable RV11 encoding via rv11 [autodetect]
   --enable-libshine        enable fixed-point MP3 encoding via libshine [no]
   --enable-libsmbclient    enable Samba protocol via libsmbclient [no]
   --enable-libsnappy       enable Snappy compression, needed for hap encoding [no]
@@ -1535,6 +1537,8 @@  EXTERNAL_AUTODETECT_LIBRARY_LIST="
     bzlib
     coreimage
     iconv
+    librv11enc
+    librv11dec
     libxcb
     libxcb_shm
     libxcb_shape
@@ -2959,6 +2963,8 @@  libopus_decoder_deps="libopus"
 libopus_encoder_deps="libopus"
 libopus_encoder_select="audio_frame_queue"
 librsvg_decoder_deps="librsvg"
+librv11dec_decoder_deps="librv11dec"
+librv11enc_encoder_deps="librv11enc"
 libshine_encoder_deps="libshine"
 libshine_encoder_select="audio_frame_queue"
 libspeex_decoder_deps="libspeex"
@@ -5890,6 +5896,8 @@  enabled libpulse          && require_pkg_config libpulse libpulse pulse/pulseaud
 enabled librsvg           && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_render_cairo
 enabled librtmp           && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket
 enabled librubberband     && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++"
+enabled librv11enc        && require_pkg_config librv11 librv11 librv11_sdk.h fpinit
+enabled librv11dec        && require_pkg_config librv11 librv11 librv11_sdk.h fpinit
 enabled libshine          && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer
 enabled libsmbclient      && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init ||
                                require libsmbclient libsmbclient.h smbc_init -lsmbclient; }
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index cfacd6b..2e32815 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -948,6 +948,8 @@  OBJS-$(CONFIG_LIBOPUS_DECODER)            += libopusdec.o libopus.o     \
                                              vorbis_data.o
 OBJS-$(CONFIG_LIBOPUS_ENCODER)            += libopusenc.o libopus.o     \
                                              vorbis_data.o
+OBJS-$(CONFIG_LIBRV11DEC_DECODER)         += librv11dec.o
+OBJS-$(CONFIG_LIBRV11ENC_ENCODER)         += librv11enc.o
 OBJS-$(CONFIG_LIBSHINE_ENCODER)           += libshine.o
 OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
 OBJS-$(CONFIG_LIBSPEEX_ENCODER)           += libspeexenc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index ed1e7ab..8eb8610 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -548,6 +548,8 @@  static void register_all(void)
     REGISTER_ENCDEC (LIBOPENJPEG,       libopenjpeg);
     REGISTER_ENCDEC (LIBOPUS,           libopus);
     REGISTER_DECODER(LIBRSVG,           librsvg);
+    REGISTER_DECODER(LIBRV11DEC,        librv11dec);
+    REGISTER_ENCODER(LIBRV11ENC,        librv11enc);
     REGISTER_ENCODER(LIBSHINE,          libshine);
     REGISTER_ENCDEC (LIBSPEEX,          libspeex);
     REGISTER_ENCODER(LIBTHEORA,         libtheora);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 8fbbc79..b7c1fa1 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -409,6 +409,7 @@  enum AVCodecID {
     AV_CODEC_ID_DXV,
     AV_CODEC_ID_SCREENPRESSO,
     AV_CODEC_ID_RSCC,
+    AV_CODEC_ID_RV60,
 
     AV_CODEC_ID_Y41P = 0x8000,
     AV_CODEC_ID_AVRP,
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index c3688de..1ad2c9c 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -471,6 +471,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
     },
     {
+        .id        = AV_CODEC_ID_RV60,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "rv60",
+        .long_name = NULL_IF_CONFIG_SMALL("RealVideo 11"),
+        .props     = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER,
+    },
+    {
         .id        = AV_CODEC_ID_VC1,
         .type      = AVMEDIA_TYPE_VIDEO,
         .name      = "vc1",
diff --git a/libavcodec/librv11.h b/libavcodec/librv11.h
new file mode 100644
index 0000000..44ec050
--- /dev/null
+++ b/libavcodec/librv11.h
@@ -0,0 +1,55 @@ 
+/*
+ * This copyright notice applies to this file only
+ * This Software is distributed under MIT License
+ *
+ * API software for using RealVideo 11 (RV60) Codec
+ *
+ *      * Copyright (c) 2017 Qiang Luo, RealNetworks, Inc. <qluo _at_ realnetworks.com>
+ *      * Copyright (c) 2017 Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef AVCODEC_LIBRV11_H
+#define AVCODEC_LIBRV11_H
+
+#include <librv11_sdk.h>
+
+#include "avcodec.h"
+#include "libavutil/intreadwrite.h"
+
+#ifdef _WIN32
+#include "compat/w32dlfcn.h"
+#else
+#include <dlfcn.h>
+#endif
+
+#define RV_MAX_INPUT_FRAME_RATE 120
+#define RV_NUM_OUT_FRAMES         6
+
+#define XSTR(s) STR(s)
+#define STR(s) #s
+#define LIBRV11DEC_FILE XSTR(RV_DEC_LIB_FILE)
+#define LIBRV11ENC_FILE XSTR(RV_ENC_LIB_FILE)
+
+
+#endif // AVCODEC_LIBRV11_H
diff --git a/libavcodec/librv11dec.c b/libavcodec/librv11dec.c
new file mode 100644
index 0000000..269d684
--- /dev/null
+++ b/libavcodec/librv11dec.c
@@ -0,0 +1,367 @@ 
+/*
+ * This copyright notice applies to this file only
+ * This Software is distributed under MIT License
+ *
+ * API software for using RealVideo 11 (RV60) Decoder
+ *
+ *      * Copyright (c) 2017 Qiang Luo, RealNetworks, Inc. <qluo _at_ realnetworks.com>
+ *      * Copyright (c) 2017 Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "libavutil/imgutils.h"
+#include "internal.h"
+#include "get_bits.h"
+
+#include "librv11.h"
+
+typedef struct DecFnTable
+{
+    FPINIT      init;
+    FPFREE      free;
+    FPTRANSFORM transform;
+    FPCUSTOMMSG custom_message;
+    FPHIVEMSG   hive_message;
+} DecFnTable;
+
+typedef struct LIBRV11DecContext {
+    AVCodecContext *avctx;
+    AVFrame        out_frame;
+    void           *lib_handle;
+    DecFnTable     *symbols;
+    void           *codec_status;
+    uint32_t       input_buf_size;
+    uint32_t       input_buf_num;
+    uint32_t       output_buf_size;
+    uint32_t       output_buf_num;
+    uint8_t        *output_buf[RV_NUM_OUT_FRAMES];
+    int            frame_index;
+    uint32_t       last_frame;
+    uint32_t       more_frames;
+} LIBRV11DecContext;
+
+static av_cold int librv11dec_load_symbols(AVCodecContext *avctx)
+{
+    LIBRV11DecContext *ctx = avctx->priv_data;
+
+    ctx->lib_handle = dlopen(LIBRV11DEC_FILE, RTLD_LAZY);
+    if (!ctx->lib_handle) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot load dynamic library.\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    ctx->symbols = av_mallocz(sizeof(DecFnTable));
+    if (!ctx->symbols) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot allocate symbol table.\n");
+        return AVERROR(ENOMEM);
+    }
+
+#define LOAD_RV11_FUNC(handle, name) {                               \
+    ctx->symbols->handle = dlsym(ctx->lib_handle, name);             \
+    if (!ctx->symbols->handle) {                                     \
+        av_log(avctx, AV_LOG_ERROR, "Cannot load symbol %s.", name); \
+        return AVERROR_EXTERNAL;                                     \
+    }                                                                \
+}
+
+    LOAD_RV11_FUNC(init,           RV_CODEC_INIT);
+    LOAD_RV11_FUNC(free,           RV_CODEC_FREE);
+    LOAD_RV11_FUNC(transform,      RV_CODEC_TRANSFORM);
+    LOAD_RV11_FUNC(custom_message, RV_CODEC_CUSTOM_MSG);
+    LOAD_RV11_FUNC(hive_message,   RV_CODEC_HIVE_MSG);
+
+    return 0;
+}
+
+static av_cold int librv11dec_init(AVCodecContext *avctx)
+{
+    LIBRV11DecContext *ctx = avctx->priv_data;
+    GetBitContext gb;
+    RVInitParams init_params;
+    RVMsgSimple msg;
+    HX_RESULT res;
+    uint32_t SPO_extra_flags;
+    uint32_t version;
+    int i;
+    ctx->avctx = avctx;
+
+    if (!avctx->extradata || !avctx->extradata_size) {
+        return AVERROR_INVALIDDATA;
+    }
+
+    init_get_bits(&gb, avctx->extradata, avctx->extradata_size * 8);
+
+    SPO_extra_flags = get_bits_long(&gb, 32);
+    version         = get_bits_long(&gb, 32);
+
+    res = librv11dec_load_symbols(avctx);
+    if (res) {
+        av_freep(&ctx->symbols);
+        return res;
+    }
+
+    init_params.out_type   = 0;
+    init_params.width      = avctx->width;
+    init_params.height     = avctx->height;
+    init_params.pad_width  = avctx->width;
+    init_params.pad_height = avctx->height;
+    init_params.pad_to_32  = 0;
+    init_params.invariants = SPO_extra_flags;
+    init_params.packetize  = 1;
+    init_params.version    = version;
+
+    res = ctx->symbols->init(&init_params, &ctx->codec_status);
+    if (res) {
+        av_free(ctx->symbols);
+        return res;
+    }
+
+    msg.id     = RV_MSG_ID_SMOOTHING_POSTFILTER;
+    msg.value1 = RV_MSG_DISABLE;
+    msg.value2 = 0;
+
+    res = ctx->symbols->custom_message(&msg.id, ctx->codec_status);
+    if (res) {
+        return res;
+    }
+
+    avctx->pix_fmt   = AV_PIX_FMT_YUV420P;
+    ctx->last_frame  = 0;
+    ctx->more_frames = 0;
+    ctx->frame_index = 0;
+
+    ctx->output_buf_size = (avctx->width * avctx->height * 12) >> 3;
+    for(i = 0; i < RV_NUM_OUT_FRAMES; i++) {
+        ctx->output_buf[i] = av_mallocz(ctx->output_buf_size);
+    }
+    av_image_fill_arrays(ctx->out_frame.data, ctx->out_frame.linesize, ctx->output_buf[0], AV_PIX_FMT_YUV420P, avctx->width, avctx->height, 1);
+
+    return 0;
+}
+
+static int librv11dec_decode_last(AVCodecContext *avctx, void *data,
+                                    int *got_frame, AVPacket *avpkt)
+{
+    LIBRV11DecContext* ctx = avctx->priv_data;
+    AVFrame *pict    = data;
+    const int stride = avctx->width * avctx->height;
+    RVInParams inParams;
+    RVOutParams outParams;
+    int32_t ret;
+
+    inParams.length       = 0;
+    inParams.interpolate  = 0;
+    inParams.num_segments = 0;
+    inParams.segments     = NULL;
+    inParams.timestamp    = 0;
+    inParams.flags        = RV_DECODE_MORE_FRAMES;
+
+    pict->data[0] = ctx->output_buf[ctx->frame_index];
+    pict->data[1] = ctx->output_buf[ctx->frame_index] + stride;
+    pict->data[2] = ctx->output_buf[ctx->frame_index] + stride + (stride >> 2);
+
+    pict->linesize[0] = avctx->width;
+    pict->linesize[1] = avctx->width >> 1;
+    pict->linesize[2] = avctx->width >> 1;
+
+    ret = ctx->symbols->transform(NULL, ctx->output_buf[ctx->frame_index], &inParams, &outParams, ctx->codec_status);
+    if (ret) {
+        *got_frame = 0;
+        return ret;
+    }
+
+    if(outParams.notes & RV_DECODE_LAST_FRAME) {
+        ctx->last_frame = 1;
+    }
+
+    pict->pts       = outParams.timestamp;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
+    pict->pkt_pts   = avpkt->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    pict->pkt_dts   = avpkt->dts;
+    pict->width     = avctx->width;
+    pict->height    = avctx->height;
+    pict->format    = AV_PIX_FMT_YUV420P;
+    pict->key_frame = 0;
+    pict->pict_type = AV_PICTURE_TYPE_P;
+
+    if (outParams.notes & RV_DECODE_KEY_FRAME) {
+        pict->key_frame = 1;
+        pict->pict_type = AV_PICTURE_TYPE_I;
+    } else if (outParams.notes & RV_DECODE_B_FRAME ||
+               outParams.notes & RV_DECODE_FRU_FRAME) {
+        pict->key_frame = 0;
+        pict->pict_type = AV_PICTURE_TYPE_B;
+    }
+
+    *got_frame = !(outParams.notes & RV_DECODE_DONT_DRAW);
+
+    return 0;
+
+}
+
+static int librv11dec_decode_frame(AVCodecContext *avctx, void *data,
+                                    int *got_frame, AVPacket *avpkt)
+{
+    LIBRV11DecContext* ctx = avctx->priv_data;
+    const uint8_t *buf = avpkt->data;
+    int buf_size       = avpkt->size;
+    const int stride   = avctx->width * avctx->height;
+    AVFrame *pict      = data;
+    int slice_count    = 0;
+    int consumed_bytes = 0;
+    RVSegment *segment = NULL;
+    RVInParams inParams;
+    RVOutParams outParams;
+    int32_t ret;
+    int i;
+
+    ret = ff_get_buffer(avctx, pict, 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ctx->frame_index++;
+    ctx->frame_index %= RV_NUM_OUT_FRAMES;
+
+    if (!buf_size) { // maybe last frame
+        if (ctx->last_frame) {
+            *got_frame = 0;
+            return 0;
+        } else {
+            return librv11dec_decode_last(avctx, data, got_frame, avpkt);
+        }
+    }
+
+    if (!avctx->slice_count) {
+        slice_count = (*buf++) + 1;
+        segment = av_mallocz(slice_count * sizeof(RVSegment));
+        for (i = 0; i < slice_count; i++) {
+            segment[i].is_valid = *buf;
+            segment[i].offset   = *(buf + 4);
+            buf += 8;
+        }
+        buf_size -= 1 + 8 * slice_count;
+    } else {
+        slice_count = avctx->slice_count;
+    }
+
+    inParams.length       = buf_size;
+    inParams.interpolate  = 0;
+    inParams.num_segments = slice_count - 1;
+    inParams.segments     = segment;
+    inParams.timestamp    = avpkt->pts;
+    inParams.flags        = 0;
+
+    pict->data[0] = ctx->output_buf[ctx->frame_index];
+    pict->data[1] = ctx->output_buf[ctx->frame_index] + stride;
+    pict->data[2] = ctx->output_buf[ctx->frame_index] + stride + (stride >> 2);
+    pict->linesize[0] = avctx->width;
+    pict->linesize[1] = avctx->width >> 1;
+    pict->linesize[2] = avctx->width >> 1;
+
+    ret = ctx->symbols->transform((UCHAR*)buf, ctx->output_buf[ctx->frame_index], &inParams, &outParams, ctx->codec_status);
+    if (ret) {
+        consumed_bytes = 0;
+        *got_frame     = 0;
+        return ret;
+    }
+
+    if (slice_count) {
+        av_freep(&segment);
+    }
+
+    consumed_bytes  = avpkt->size;
+    *got_frame      = 1;
+    pict->key_frame = 0;
+    pict->pict_type = AV_PICTURE_TYPE_P;
+
+    if (outParams.notes & RV_DECODE_KEY_FRAME) {
+        pict->pict_type = AV_PICTURE_TYPE_I;
+        pict->key_frame = 1;
+    } else if (outParams.notes & RV_DECODE_B_FRAME ||
+               outParams.notes & RV_DECODE_FRU_FRAME) {
+        pict->pict_type = AV_PICTURE_TYPE_B;
+    } else if (outParams.notes & RV_DECODE_DONT_DRAW) {
+        consumed_bytes  = 0;
+        *got_frame      = 0;
+    }
+
+    pict->pts     = outParams.timestamp;
+#if FF_API_PKT_PTS
+FF_DISABLE_DEPRECATION_WARNINGS
+    pict->pkt_pts = avpkt->pts;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+    pict->pkt_dts = avpkt->dts;
+    pict->width   = avctx->width;
+    pict->height  = avctx->height;
+    pict->format  = AV_PIX_FMT_YUV420P;
+
+    return consumed_bytes;
+}
+
+static av_cold int librv11dec_close(AVCodecContext *avctx)
+{
+    LIBRV11DecContext* ctx = avctx->priv_data;
+    int i;
+
+    ctx->symbols->free(ctx->codec_status);
+    dlclose(ctx->lib_handle);
+
+    if (ctx->symbols) {
+        av_freep(&ctx->symbols);
+    }
+
+    for(i = 0; i < RV_NUM_OUT_FRAMES; i++) {
+        if (ctx->output_buf[i]) {
+            av_freep(&ctx->output_buf[i]);
+        }
+    }
+
+    return 0;
+}
+
+static void librv11dec_flush(AVCodecContext *avctx)
+{
+    LIBRV11DecContext* ctx = avctx->priv_data;
+    if (ctx->symbols) {
+        uint32_t id = RV_MSG_ID_FLUSH;
+        ctx->symbols->hive_message(&id, ctx->codec_status);
+    }
+}
+
+AVCodec ff_librv11dec_decoder = {
+    .name           = "librv11dec",
+    .long_name      = NULL_IF_CONFIG_SMALL("librv11dec RealVideo 11 (RV60)"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_RV60,
+    .priv_data_size = sizeof(LIBRV11DecContext),
+    .init           = librv11dec_init,
+    .decode         = librv11dec_decode_frame,
+    .close          = librv11dec_close,
+    .flush          = librv11dec_flush,
+    .capabilities   = AV_CODEC_CAP_DELAY,
+};
diff --git a/libavcodec/librv11enc.c b/libavcodec/librv11enc.c
new file mode 100644
index 0000000..231a768
--- /dev/null
+++ b/libavcodec/librv11enc.c
@@ -0,0 +1,735 @@ 
+/*
+ * This copyright notice applies to this file only
+ * This Software is distributed under MIT License
+ *
+ * API software for using RealVideo 11 (RV60) Encoder
+ *
+ *      * Copyright (c) 2017 Qiang Luo, RealNetworks, Inc. <qluo _at_ realnetworks.com>
+ *      * Copyright (c) 2017 Thilo Borgmann <thilo.borgmann _at_ mail.de>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
+
+#include "librv11.h"
+
+typedef struct EncFnTable
+{
+    FPCODECOPEN                 Codec_Open;
+    FPCODECCLOSE                Codec_Close;
+    FPCODECINPUT                Codec_Input;
+    FPCODECSTREAMOPEN           Codec_StreamOpen;
+    FPCODECGETHYPERPROPERTY     Codec_GetHyperProperty;
+    FPSTREAMCLOSE               Stream_Close;
+    FPSTREAMSETDATACALLBACK     Stream_SetDataCallback;
+    FPSTREAMGETSTREAMHEADER     Stream_GetStreamHeader;
+    FPSTREAMINPUT               Stream_Input;
+    FPSTREAMSETOUTPUTPACKETSIZE Stream_SetOutputPacketSize;
+    FPSTREAMGETPROPERTY         Stream_GetProperty;
+    FPSTREAMSETPROPERTY         Stream_SetProperty;
+    FPSTREAMPOSTPROCESS         Stream_PostProcess;
+    FPSTREAMRELEASEFRAME        Stream_ReleaseFrame;
+    FPCODECGETUINAME            Codec_GetUIName;
+    FPCODECQUERYMEDIAFORMAT     Codec_QueryMediaFormat;
+    FPCODECSETPROPERTY          Codec_SetProperty;
+} EncFnTable;
+
+typedef struct CodedFrameList {
+    AVPacket pkt;
+    struct CodedFrameList* pNext;
+} CodedFrameList;
+
+typedef struct FrameRatioConverter {
+    uint32_t    count;
+    double      framerate;
+    uint8_t*    selected_map;
+    uint32_t    framerate_in;
+} FrameRatioConverter;
+
+typedef struct LIBRV11EncContext
+{
+    AVClass    *class;
+    void       *lib_handle;
+    EncFnTable *symbols;
+    void       *codec_ref;
+    void       *stream_ref;
+    RVEncodeParam rvenc_param;
+    uint32_t   codec_4cc;
+    uint32_t   frame_size;
+    uint8_t*   frame_buf;
+    CodedFrameList* coded_frame_list;
+    int        bitrate_vbr;           ///< 0:VBRQuality, 1:VBRBitrate
+    int        eos;                   ///< set to TURE when input frame was set to NULL
+    int        last_packet;           ///< set to 1 when the last codec frame was popped out
+    FrameRatioConverter fr_convert;
+    uint32_t   video_mode;
+} LIBRV11EncContext;
+
+static int32_t interval_search(uint8_t *buf, const uint32_t buf_size, const uint32_t num_frames)
+{
+    if (buf_size < num_frames || !num_frames) {
+        return -1;
+    }
+
+    if (!(buf_size % num_frames)) {
+        uint32_t i;
+        const uint32_t den = buf_size / num_frames;
+
+        for(i = 0; i < buf_size; i++) {
+            if (!((i+1) % den)) {
+                buf[i] = 1;
+            }
+        }
+    } else {
+        const uint32_t half  = buf_size >> 1;
+        const uint32_t left  = num_frames >> 1;
+        const uint32_t right = left + (num_frames & 1);
+
+        interval_search(buf, half, left);
+        interval_search(buf + half, buf_size - half, right);
+    }
+
+    return 0;
+}
+
+static av_cold int32_t fr_convert_init(FrameRatioConverter* fr_convert, double fr_in, double fr_max)
+{
+    if (fr_in < fr_max || fr_in > RV_MAX_INPUT_FRAME_RATE) {
+        return -1;
+    }
+
+    fr_convert->count        = 0;
+    fr_convert->framerate    = fr_max;
+    fr_convert->framerate_in = (int32_t)(fr_in + 0.5);
+    fr_convert->selected_map = av_mallocz(fr_convert->framerate_in);
+
+    return interval_search(fr_convert->selected_map, fr_convert->framerate_in, (int32_t)(fr_max + 0.5));
+}
+
+static av_always_inline int32_t use_frame(FrameRatioConverter *fr_convert)
+{
+    return fr_convert->selected_map[fr_convert->count];
+}
+
+static void next_frame(FrameRatioConverter* fr_convert)
+{
+    fr_convert->count++;
+    if (fr_convert->count >= fr_convert->framerate_in) {
+        fr_convert->count = 0;
+    }
+}
+
+static void coded_frame_add(void *list, CodedFrameList *cx_frame)
+{
+    CodedFrameList **p = list;
+
+    while(*p) {
+        p = &(*p)->pNext;
+    }
+
+    *p = cx_frame;
+    cx_frame->pNext = NULL;
+}
+
+static CodedFrameList* coded_frame_remove_header(CodedFrameList** list)
+{
+    CodedFrameList *p = *list;
+
+    if (p) {
+        *list = p->pNext;
+    }
+
+    return p;
+}
+
+static av_cold void free_coded_frame(CodedFrameList *cx_frame)
+{
+    av_packet_unref(&cx_frame->pkt);
+    av_freep(&cx_frame);
+}
+
+static av_cold void free_frame_list(CodedFrameList *list)
+{
+    CodedFrameList *p = list;
+
+    while(p) {
+        list = list->pNext;
+        free_coded_frame(p);
+        p = list;
+    }
+}
+
+static int librv11_num_segments(uint32_t data_length)
+{
+    int num_packet;
+
+    if (data_length < 1) {
+        return -1;
+    }
+
+    num_packet = data_length / RV_MAX_PACKET_SIZE;
+    if (data_length % RV_MAX_PACKET_SIZE) {
+        num_packet++;
+    }
+
+    return num_packet;
+}
+
+static int librv11_write_frame_header(uint8_t *data, int num_packet)
+{
+    int i;
+
+    if (num_packet < 1 || !data) {
+        return -1;
+    }
+
+    data[0] = num_packet -1;
+
+    for (i = 0; i < num_packet; i++) {
+        // the value of next 4 byte is the segment index
+        AV_WL32(data + 1 + 8 * i, i + 1);
+        // continuous 4 byte is the segment offset
+        AV_WL32(data + 5 + 8 * i, RV_MAX_PACKET_SIZE * i);
+    }
+
+    return 0;
+}
+
+static av_cold int CC librv11enc_data_callback(void *stream_ctx, void *stream_ref, HXCodecData* data)
+{
+    int ret = 0;
+    AVCodecContext *avctx = (AVCodecContext*) stream_ctx;
+    LIBRV11EncContext *enctx = avctx->priv_data;
+
+    if (data && data->length) {
+        int numPackets = 0;
+        int bufLength;
+
+        CodedFrameList* node = av_mallocz(sizeof(CodedFrameList));
+        if (!node) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to allocate memory.\n");
+            return AVERROR(ENOMEM);
+        }
+
+        // for rv11 num_segments should be 1
+        if (data->num_segments == 1) {
+            numPackets = librv11_num_segments(data->length);
+            if (numPackets > 127 || numPackets < 0) {
+                av_log(avctx, AV_LOG_WARNING, "Too many packets per frame (%d).\n", numPackets);
+            }
+        } else {
+            av_log(avctx, AV_LOG_WARNING, "Invalid number of segments (%u), should be 1.\n", data->num_segments);
+        }
+
+        // allocate extra numPackets*8+1  byte for real video head saving segment information
+        bufLength = data->length + numPackets * 8 + 1;
+        ret = av_new_packet(&node->pkt, bufLength);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to allocate packet.\n");
+            return ret;
+        }
+        librv11_write_frame_header(node->pkt.data, numPackets);
+        memcpy((node->pkt.data + numPackets * 8 + 1), data->data, data->length);
+
+        if (data->flags & HX_KEYFRAME_FLAG) {
+            node->pkt.flags |= AV_PKT_FLAG_KEY;
+        }
+
+        if (data->last_packet) {
+            node->pkt.flags |= RV_PKT_FLAG_END;
+        }
+
+        node->pkt.pts = data->timestamp * av_q2d(av_inv_q(avctx->time_base)) / 1000.0;
+        node->pkt.dts = data->timestamp;
+        coded_frame_add((void*)(&enctx->coded_frame_list), node);
+    }
+
+    return 0;
+}
+
+static av_cold int librv11enc_load_symbols(AVCodecContext *avctx)
+{
+    LIBRV11EncContext *enctx = avctx->priv_data;
+
+    enctx->lib_handle = dlopen(LIBRV11ENC_FILE, RTLD_LAZY);
+    if (!enctx->lib_handle) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot load dynamic library.\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    enctx->symbols = av_mallocz(sizeof(EncFnTable));
+    if (!enctx->symbols) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot allocate symbol table.\n");
+        return AVERROR(ENOMEM);
+    }
+
+#define LOAD_RV11_FUNC(handle, name) {                               \
+    enctx->symbols->handle = dlsym(enctx->lib_handle, name);         \
+    if (!enctx->symbols->handle) {                                   \
+        av_log(avctx, AV_LOG_ERROR, "Cannot load symbol %s.", name); \
+        return AVERROR_EXTERNAL;                                     \
+    }                                                                \
+}
+
+    LOAD_RV11_FUNC(Codec_Open,                 RV_CODEC_OPEN);
+    LOAD_RV11_FUNC(Codec_Close,                RV_CODEC_CLOSE);
+    LOAD_RV11_FUNC(Codec_StreamOpen,           RV_STREAM_OPEN);
+    LOAD_RV11_FUNC(Codec_GetHyperProperty,     RV_CODEC_GET_HYPER_PROPERTY);
+    LOAD_RV11_FUNC(Stream_Close,               RV_STREAM_CLOSE);
+    LOAD_RV11_FUNC(Stream_SetDataCallback,     RV_STREAM_SET_DATACALLBACK);
+    LOAD_RV11_FUNC(Stream_GetStreamHeader,     RV_STREAM_GET_STREAMHEADER);
+    LOAD_RV11_FUNC(Stream_Input,               RV_STREAM_INPUT);
+    LOAD_RV11_FUNC(Stream_SetOutputPacketSize, RV_STREAM_SET_OUTPUTPACKETSIZE);
+    LOAD_RV11_FUNC(Stream_GetProperty,         RV_STREAM_GET_PROPERTY);
+    LOAD_RV11_FUNC(Stream_SetProperty,         RV_STREAM_SET_PROPERTY);
+    LOAD_RV11_FUNC(Codec_GetUIName,            RV_CODEC_GET_UINAME);
+    LOAD_RV11_FUNC(Codec_Input,                RV_CODEC_INPUT);
+    LOAD_RV11_FUNC(Codec_QueryMediaFormat,     RV_CODEC_QUERY_MEDIAFORMAT);
+    LOAD_RV11_FUNC(Codec_SetProperty,          RV_CODEC_SET_PROPERTY);
+
+    return 0;
+}
+
+static av_cold int librv11enc_init(AVCodecContext *avctx)
+{
+    LIBRV11EncContext *enctx = avctx->priv_data;
+    HX_RESULT res;
+    HXMof hxInput, hxOutput;
+    HXFormatVideo mofin, mofout;
+    HXCodecInit ci;
+    double framerate;
+    uint32_t dummy_ui32;
+    float dummy_f;
+
+    // Width and height of the video are required to be multiples of 4
+    if (avctx->width % 4 || avctx->height % 4) {
+        av_log(avctx, AV_LOG_ERROR,
+        "Video dimensions have to be multiples of 4 (%dx%d).\n",
+        avctx->width, avctx->height);
+        return AVERROR(EINVAL);
+    }
+
+    res = librv11enc_load_symbols(avctx);
+    if (res) {
+        av_freep(&enctx->symbols);
+        return res;
+    }
+
+    res = enctx->symbols->Codec_QueryMediaFormat(NULL, &hxInput, &hxOutput, 0);
+    if (FAILED(res)) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to query in/out formats.\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    res = enctx->symbols->Codec_Open(hxOutput.submoftag, &enctx->codec_ref);
+    if (FAILED(res)) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to open the codec library.\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    enctx->codec_4cc = hxOutput.submoftag;
+
+    // init the librv11 encoder using default/user parameters
+    enctx->rvenc_param.in_width  = avctx->width;
+    enctx->rvenc_param.in_height = avctx->height;
+
+    if (!enctx->rvenc_param.out_width) {
+        enctx->rvenc_param.out_width = avctx->width;
+    }
+    if (!enctx->rvenc_param.out_height) {
+        enctx->rvenc_param.out_height = avctx->height;
+    }
+
+    if (enctx->bitrate_vbr) {
+        enctx->rvenc_param.encode_type = ENCODE_VBR_BITRATE;
+        if (avctx->flags & AV_CODEC_FLAG_PASS1) {
+            enctx->rvenc_param.vbr_quality = 25;
+        }
+    } else {
+        enctx->rvenc_param.encode_type = ENCODE_VBR_QUALITY;
+    }
+
+    if (avctx->flags & AV_CODEC_FLAG_PASS1) {
+        enctx->rvenc_param.encode_mode = ENCODE_CREATE_ANALYSIS;
+    } else if (avctx->flags & AV_CODEC_FLAG_PASS2){
+        enctx->rvenc_param.encode_mode = ENCODE_USING_ANALYSIS;
+    } else {
+        enctx->rvenc_param.encode_mode = ENCODE_SINGLE_PASS;
+    }
+
+    enctx->rvenc_param.avg_bitrate = avctx->bit_rate;
+    enctx->rvenc_param.max_bitrate = enctx->rvenc_param.avg_bitrate;
+
+    enctx->rvenc_param.max_packet_size = RV_MAX_PACKET_SIZE;
+
+    if (!avctx->framerate.den) {
+        return AVERROR(EINVAL);
+    }
+    framerate = av_q2d(avctx->framerate);
+
+    res = fr_convert_init(&enctx->fr_convert, framerate, enctx->rvenc_param.max_framerate);
+    if (res) {
+        fr_convert_init(&enctx->fr_convert, framerate, framerate);
+    }
+
+    // set input parameters for I420
+    memset(&mofin, 0, sizeof(mofin));
+    mofin.length     = sizeof(HXFormatVideo);
+    mofin.moftag     = HX_MEDIA_VIDEO;
+    mofin.submoftag  = HX_YUV420_ID;
+    mofin.width      = enctx->rvenc_param.in_width;
+    mofin.height     = enctx->rvenc_param.in_height;
+    mofin.bit_count  = 12;
+    mofin.pad_width  = 0;
+    mofin.pad_height = 0;
+    mofin.moftag     = HX_MEDIA_VIDEO;
+
+    mofin.fps = (int)(enctx->fr_convert.framerate * (1L << 16) + 0.5);
+
+    // set output parameters
+    memset(&mofout, 0, sizeof(mofout));
+    mofout.length     = sizeof(mofout);
+    mofout.moftag     = HX_MEDIA_VIDEO;
+    mofout.submoftag  = enctx->codec_4cc;
+    mofout.width      = enctx->rvenc_param.out_width;
+    mofout.height     = enctx->rvenc_param.out_height;
+    mofout.bit_count  = mofin.bit_count;
+    mofout.pad_width  = 0;
+    mofout.pad_height = 0;
+    mofout.moftag     = HX_MEDIA_VIDEO;
+    mofout.fps        = mofin.fps;
+
+    ci.in_mof  = (HXMof*)&mofin;
+    ci.out_mof = (HXMof*)&mofout;
+    ci.mem_ptr = NULL;
+
+#define SET_RV11_PROP(prop, value) {                                          \
+    res = enctx->symbols->Stream_SetProperty(enctx->stream_ref, prop, value); \
+    if (FAILED(res)) {                                                        \
+        av_log(avctx, AV_LOG_ERROR, "Failed to set property %s.\n", #prop);   \
+        return AVERROR_EXTERNAL;                                              \
+    }                                                                         \
+}
+
+    res = enctx->symbols->Codec_StreamOpen(enctx->codec_ref, &enctx->stream_ref, &ci);
+    if (FAILED(res)) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to open the stream.\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    if (enctx->bitrate_vbr && !(avctx->flags & AV_CODEC_FLAG_PASS1)) {
+        SET_RV11_PROP(SP_BITRATE, &enctx->rvenc_param.avg_bitrate);
+    } else {
+        SET_RV11_PROP(SP_QUALITY, &enctx->rvenc_param.vbr_quality);
+    }
+
+    SET_RV11_PROP(SP_MAXBITRATE, &enctx->rvenc_param.max_bitrate);
+
+    dummy_f = (float)(enctx->rvenc_param.max_framerate);
+    SET_RV11_PROP(SP_MAX_FRAMERATE, &dummy_f);
+
+    dummy_ui32 = 0;
+    SET_RV11_PROP(SP_CHECK_FRAME_SKIP, &dummy_ui32);
+    SET_RV11_PROP(SP_QUALITY_MOTION, &enctx->video_mode);
+
+    dummy_ui32 = 0;
+    SET_RV11_PROP(SP_LIVE, &dummy_ui32);
+
+    dummy_ui32 = enctx->rvenc_param.max_keyint * 1000;
+    SET_RV11_PROP(SP_KEYFRAMERATE, &dummy_ui32);
+
+    SET_RV11_PROP(SP_ECC, &enctx->rvenc_param.loss_protect);
+    SET_RV11_PROP(SP_SET_FAST_LEVEL, &enctx->rvenc_param.enc_complexity);
+
+    dummy_ui32 = (uint32_t) enctx->rvenc_param.max_start_latency * 1000;
+    SET_RV11_PROP(SP_TARGET_LATENCY, &dummy_ui32);
+    SET_RV11_PROP(SP_RESIZING_ACCURACY, &enctx->rvenc_param.resize_quality);
+
+    if (enctx->rvenc_param.pon > 0) {
+        SET_RV11_PROP(SP_SET_PON_START, &enctx->rvenc_param.pon);
+    }
+
+    res = enctx->symbols->Stream_SetDataCallback(enctx->stream_ref, avctx, NULL, librv11enc_data_callback);
+    if (FAILED(res)) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to set data callback.\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    if (avctx->flags & AV_CODEC_FLAG_PASS1) {
+        dummy_ui32 = SPCODINGMODE_ANALYSIS;
+    } else if (avctx->flags & AV_CODEC_FLAG_PASS2) {
+        dummy_ui32 = SPCODINGMODE_FROMFILE;
+    } else {
+        dummy_ui32 = SPCODINGMODE_ENCODE;
+    }
+    SET_RV11_PROP(SP_CODING_MODE, &dummy_ui32);
+
+    // if vbr_opt is set to true the encoder can override bitrate settings to remain subjective quality.
+    // default is false
+    SET_RV11_PROP(SP_RATECONTROL_PLUS, &enctx->rvenc_param.vbr_opt);
+
+    if (avctx->flags & AV_CODEC_FLAG_PASS1 ||
+        avctx->flags & AV_CODEC_FLAG_PASS2) {
+        if (!enctx->rvenc_param.passlog_file) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid passlogfile.\n");
+            return AVERROR(EINVAL);
+        }
+        SET_RV11_PROP(SP_ANALYSIS_FILENAME, (void*)enctx->rvenc_param.passlog_file);
+    }
+
+    dummy_ui32 = 1;
+    SET_RV11_PROP(SP_CODEC_SETUP_DONE, &dummy_ui32);
+
+    dummy_ui32 = enctx->rvenc_param.max_packet_size;
+    res = enctx->symbols->Stream_SetOutputPacketSize(enctx->stream_ref, dummy_ui32, dummy_ui32, &dummy_ui32);
+    if (FAILED(res)) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to set output packet size (%u).\n", dummy_ui32);
+        return AVERROR(EINVAL);
+    }
+
+#if FF_API_CODED_FRAME
+FF_DISABLE_DEPRECATION_WARNINGS
+    avctx->coded_frame = av_frame_alloc();
+    if (!avctx->coded_frame) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot allocate coded frame buffer.");
+        return AVERROR(ENOMEM);
+    }
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+    enctx->frame_size = av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1);
+
+    enctx->frame_buf = av_malloc(enctx->frame_size);
+    if (!enctx->frame_buf) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot allocate frame buffer.");
+        return AVERROR(ENOMEM);
+    }
+
+    if (!avctx->extradata_size) {
+        uint8_t *q;
+
+        avctx->extradata_size = 14;
+        avctx->extradata = av_mallocz(avctx->extradata_size);
+        if (!avctx->extradata) {
+            avctx->extradata_size = 0;
+            return AVERROR(ENOMEM);
+        }
+
+        q = avctx->extradata;
+        *q++ = 0x01; //spo_extra_flags
+        *q++ = 0x08;
+        *q++ = 0x10;
+        *q++ = 0x00;
+        *q++ = 0x40; //codec frontend version (NOT codec version!)
+        *q++ = 0x00;
+        *q++ = 0x00;
+        *q++ = 0x00;
+        enctx->symbols->Codec_GetHyperProperty(enctx->codec_ref, q);
+    }
+
+    return 0;
+}
+
+static int librv11enc_encode(AVCodecContext *avctx, AVPacket*pkt, const AVFrame* frame, int* got_packet)
+{
+    int ret = 0;
+    int nb;
+    HXCodecData cd;
+    HX_RESULT res;
+    LIBRV11EncContext *enctx = avctx->priv_data;
+    CodedFrameList* pCodedFrame;
+
+#define RETURN_PACKET(got_p, r) { \
+    *got_packet = got_p;          \
+    return r;                     \
+}
+
+    if (!frame && enctx->last_packet) {
+        RETURN_PACKET(0, 0);
+    }
+
+    if (frame && enctx->frame_buf && enctx->frame_size > 0) {
+        if (use_frame(&enctx->fr_convert)) {
+            nb = av_image_copy_to_buffer(enctx->frame_buf, enctx->frame_size,
+                                         (const uint8_t * const *)frame->data,
+                                         frame->linesize, avctx->pix_fmt,
+                                         avctx->width, avctx->height, 1);
+            if (nb < 0) {
+                RETURN_PACKET(0, nb);
+            }
+
+            cd.data         = enctx->frame_buf;
+            cd.length       = enctx->frame_size;
+            cd.timestamp    = frame->pts * 1000 * av_q2d(avctx->time_base);
+            cd.flags        = (frame->pict_type == AV_PICTURE_TYPE_I) ? HX_KEYFRAME_FLAG : 0;
+            cd.last_packet  = enctx->eos;
+            cd.num_segments = 1;
+            cd.segments[0].is_valid = 1;
+            cd.segments[0].segment_offset = 0;
+
+            res = enctx->symbols->Codec_Input(enctx->codec_ref, &cd);
+            if (FAILED(res)) {
+                av_log(avctx, AV_LOG_ERROR, "Failed to set input data.\n");
+                RETURN_PACKET(0, AVERROR_EXTERNAL);
+            }
+        }
+        next_frame(&enctx->fr_convert);
+    } else if (!frame && !enctx->eos) {
+        enctx->eos = 1;
+
+        cd.data         = NULL;
+        cd.length       = 0;
+        cd.timestamp    = 0;
+        cd.flags        = 0;
+        cd.last_packet  = 1;
+        cd.num_segments = 1;
+        cd.segments[0].is_valid = 1;
+        cd.segments[0].segment_offset = 0;
+
+        res = enctx->symbols->Codec_Input(enctx->codec_ref, &cd);
+        if (FAILED(res)) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to set input data.\n");
+            RETURN_PACKET(0, AVERROR_EXTERNAL);
+        }
+    }
+
+    pCodedFrame = coded_frame_remove_header(&enctx->coded_frame_list);
+    if (pCodedFrame) {
+        if (pCodedFrame->pkt.flags & RV_PKT_FLAG_END) {
+            pCodedFrame->pkt.flags &= ~RV_PKT_FLAG_END;
+            enctx->last_packet = 1;
+        }
+
+        ret = av_packet_ref(pkt, &pCodedFrame->pkt);
+        if (ret < 0) {
+            av_log(enctx, AV_LOG_INFO, "Failed to recieve frame reference.\n");
+            free_coded_frame(pCodedFrame);
+            RETURN_PACKET(0, ret);
+        } else {
+            pkt->pts = pCodedFrame->pkt.pts;
+            pkt->dts = pCodedFrame->pkt.dts;
+
+            if (pCodedFrame->pkt.flags&AV_PKT_FLAG_KEY) {
+                pkt->flags |= AV_PKT_FLAG_KEY;
+#if FF_API_CODED_FRAME
+FF_DISABLE_DEPRECATION_WARNINGS
+                avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+            }
+            free_coded_frame(pCodedFrame);
+            RETURN_PACKET(1, 0);
+        }
+    }
+
+    *got_packet = 0;
+    return ret;
+}
+
+static av_cold int librv11enc_close(AVCodecContext *avctx)
+{
+    LIBRV11EncContext *enctx = avctx->priv_data;
+
+    enctx->symbols->Stream_Close(enctx->stream_ref);
+    enctx->symbols->Codec_Close(enctx->codec_ref);
+    enctx->stream_ref = NULL;
+    enctx->codec_ref  = NULL;
+
+    dlclose(enctx->lib_handle);
+    free_frame_list(enctx->coded_frame_list);
+
+    av_freep(&enctx->frame_buf);
+    av_freep(&enctx->symbols);
+    av_freep(&enctx->fr_convert.selected_map);
+    av_freep(&avctx->extradata);
+
+#if FF_API_CODED_FRAME
+FF_DISABLE_DEPRECATION_WARNINGS
+    av_frame_free(&avctx->coded_frame);
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+    return 0;
+}
+
+#define OFFSET(x) offsetof(LIBRV11EncContext, x)
+#define OFFSETP(x) offsetof(RVEncodeParam, x)
+#define OFFSETBASE OFFSET(rvenc_param)
+#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+
+static const AVOption options[] = {
+    { "is_lossprotect", "enable loss protection feature",     OFFSETBASE+OFFSETP(loss_protect),      AV_OPT_TYPE_INT,    { .i64 = 0 }, 0,    1, VE },
+    { "output_width", "video encoded frame output width",     OFFSETBASE+OFFSETP(out_width),         AV_OPT_TYPE_INT,    { .i64 = 0 }, 0, 4096, VE },
+    { "output_height", "video encoded frame output height",   OFFSETBASE+OFFSETP(out_height),        AV_OPT_TYPE_INT,    { .i64 = 0 }, 0, 4096, VE },
+    { "rc_strategy", "which ratecontrol method to be used",   OFFSET(bitrate_vbr),                   AV_OPT_TYPE_INT,    { .i64 = 1 }, 0,    1, VE, "rc_strategy" },
+    { "bitrate", "", 0,    AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "rc_strategy" },
+    { "quality", "", 0,    AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "rc_strategy" },
+    { "complexity", "encoding complexity",                    OFFSETBASE+OFFSETP(enc_complexity),    AV_OPT_TYPE_INT,    { .i64 = 75 }, 55, 85, VE, "complexity" },
+    { "verylow",  "", 0,  AV_OPT_TYPE_CONST, {.i64=55}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "complexity" },
+    { "low",      "", 0,  AV_OPT_TYPE_CONST, {.i64=65}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "complexity" },
+    { "medium",   "", 0,  AV_OPT_TYPE_CONST, {.i64=75}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "complexity" },
+    { "high",     "", 0,  AV_OPT_TYPE_CONST, {.i64=85}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "complexity" },
+    { "framerate", "max frame rate value",                    OFFSETBASE+OFFSETP(max_framerate),     AV_OPT_TYPE_INT,    { .i64 = RV_MAX_INPUT_FRAME_RATE }, 0, RV_MAX_INPUT_FRAME_RATE, VE },
+    { "resize_quality", "video encoded frame resize quality", OFFSETBASE+OFFSETP(resize_quality),    AV_OPT_TYPE_INT,    { .i64 = 1 }, 0, 1, VE, "resize_quality" },
+    { "high", "", 0,       AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "resize_quality" },
+    { "fast", "", 0,       AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "resize_quality" },
+    { "video_mode", "motion quality",                         OFFSET(video_mode),                    AV_OPT_TYPE_INT,    { .i64 = 50 }, 1,  100, VE, "video_mode" },
+    { "normal", "", 0,   AV_OPT_TYPE_CONST, {.i64= 50}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "video_mode" },
+    { "sharp",  "", 0,   AV_OPT_TYPE_CONST, {.i64=  1}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "video_mode" },
+    { "smooth", "", 0,   AV_OPT_TYPE_CONST, {.i64=100}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "video_mode" },
+    { "max_keyint", "max keyframe interval",                  OFFSETBASE+OFFSETP(max_keyint),        AV_OPT_TYPE_INT,    { .i64 = 5   },   0,   10, VE },
+    { "max_latency", "max video latency on start",            OFFSETBASE+OFFSETP(max_start_latency), AV_OPT_TYPE_FLOAT,  { .dbl = 4.0 }, 0.5, 60.0, VE },
+    { "vbrquality", "vbr quality value",                      OFFSETBASE+OFFSETP(vbr_quality),       AV_OPT_TYPE_INT,    { .i64 = 60  },   0,  100, VE },
+    { "passlogfile", "filename for 2 pass encoding stats",    OFFSETBASE+OFFSETP(passlog_file),      AV_OPT_TYPE_STRING, { .str = "rv11passstats.log" }, 0, 0, VE },
+    { "pon", "picture order number",                          OFFSETBASE+OFFSETP(pon),               AV_OPT_TYPE_INT,    { .i64 = 0   },   0, INT_MAX, VE },
+    { "vbr_opt", "vbr enabled",                               OFFSETBASE+OFFSETP(vbr_opt),            AV_OPT_TYPE_INT,    { .i64 = 0   },   0,       1, VE, "vbr_opt" },
+    { "true",  "", 0,      AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "vbr_opt" },
+    { "false", "", 0,      AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "vbr_opt" },
+    { "cpulow", "cpu low mode on/off",                        OFFSETBASE+OFFSETP(cpu_low),           AV_OPT_TYPE_INT,    { .i64 = 0   }, 0, INT_MAX, VE },
+    { NULL },
+};
+
+static const AVClass librv11enc_class = {
+    .class_name = "librv11enc",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+AVCodec ff_librv11enc_encoder = {
+    .name           = "librv11enc",
+    .long_name      = NULL_IF_CONFIG_SMALL("librv11enc RealVideo 11 (RV60)"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_RV60,
+    .priv_data_size = sizeof(LIBRV11EncContext),
+    .init           = librv11enc_init,
+    .encode2        = librv11enc_encode,
+    .close          = librv11enc_close,
+    .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
+    .pix_fmts       = (const enum AVPixelFormat[]) {
+        AV_PIX_FMT_YUV420P,
+        AV_PIX_FMT_NONE
+    },
+    .priv_class     = &librv11enc_class,
+};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 47a15d5..1050f60 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@ 
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR  58
-#define LIBAVCODEC_VERSION_MINOR   9
+#define LIBAVCODEC_VERSION_MINOR  10
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \