From 0386c9e0a4c2ea1579378807ff5a7a04c508c50e Mon Sep 17 00:00:00 2001
From: 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]
--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, \
--
2.9.3