[FFmpeg-devel] [PATCH 2/3] Add codec wrapper for librv11
James Almer
jamrial at gmail.com
Thu Jan 18 22:16:23 EET 2018
On 1/18/2018 3:37 PM, Thilo Borgmann wrote:
> From 0386c9e0a4c2ea1579378807ff5a7a04c508c50e Mon Sep 17 00:00:00 2001
> From: Thilo Borgmann <thilo.borgmann at 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.
More information about the ffmpeg-devel
mailing list