From f11515c77f0a2915b831d91f061fb11c4359601f Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sat, 3 Jun 2023 12:29:25 +0200 Subject: [PATCH] avcodec: add RTV1 decoder --- Changelog | 1 + configure | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 ++ libavcodec/codec_id.h | 1 + libavcodec/rtv1.c | 148 ++++++++++++++++++++++++++++++++++++++++ libavcodec/version.h | 4 +- libavformat/riff.c | 1 + 9 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 libavcodec/rtv1.c diff --git a/Changelog b/Changelog index 3d197f2b94..c7e71ecfd8 100644 --- a/Changelog +++ b/Changelog @@ -14,6 +14,7 @@ version : - color_vulkan filter - bwdif_vulkan filter - nlmeans_vulkan filter +- RivaTuner video decoder version 6.0: - Radiance HDR image support diff --git a/configure b/configure index 2992dae283..7e68d56ab0 100755 --- a/configure +++ b/configure @@ -2962,6 +2962,7 @@ ralf_decoder_select="golomb" rasc_decoder_select="inflate_wrapper" rawvideo_decoder_select="bswapdsp" rscc_decoder_deps="zlib" +rtv1_decoder_select="texturedsp" rv10_decoder_select="h263_decoder" rv10_encoder_select="h263_encoder" rv20_decoder_select="h263_decoder" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 9aacc1d477..87a8b90037 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -643,6 +643,7 @@ OBJS-$(CONFIG_ROQ_DPCM_ENCODER) += roqaudioenc.o OBJS-$(CONFIG_RPZA_DECODER) += rpza.o OBJS-$(CONFIG_RPZA_ENCODER) += rpzaenc.o OBJS-$(CONFIG_RSCC_DECODER) += rscc.o +OBJS-$(CONFIG_RTV1_DECODER) += rtv1.o OBJS-$(CONFIG_RV10_DECODER) += rv10.o OBJS-$(CONFIG_RV10_ENCODER) += rv10enc.o OBJS-$(CONFIG_RV20_DECODER) += rv10.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 184bb8521f..a98c300da4 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -295,6 +295,7 @@ extern const FFCodec ff_roq_decoder; extern const FFCodec ff_rpza_encoder; extern const FFCodec ff_rpza_decoder; extern const FFCodec ff_rscc_decoder; +extern const FFCodec ff_rtv1_decoder; extern const FFCodec ff_rv10_encoder; extern const FFCodec ff_rv10_decoder; extern const FFCodec ff_rv20_encoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 310ed66415..41293a78dc 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1946,6 +1946,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, .profiles = NULL_IF_CONFIG_SMALL(ff_evc_profiles), }, + { + .id = AV_CODEC_ID_RTV1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rtv1", + .long_name = NULL_IF_CONFIG_SMALL("RTV1 (RivaTuner Video)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, /* various PCM "codecs" */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 9f621afff0..9a78cfabe2 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -322,6 +322,7 @@ enum AVCodecID { AV_CODEC_ID_VQC, AV_CODEC_ID_PDV, AV_CODEC_ID_EVC, + AV_CODEC_ID_RTV1, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/rtv1.c b/libavcodec/rtv1.c new file mode 100644 index 0000000000..4b202e6a21 --- /dev/null +++ b/libavcodec/rtv1.c @@ -0,0 +1,148 @@ +/* + * RTV1 decoder + * Copyright (c) 2023 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "avcodec.h" +#include "bytestream.h" +#include "codec_internal.h" +#include "decode.h" +#include "texturedsp.h" +#include "thread.h" + +static av_cold int decode_init(AVCodecContext *avctx) +{ + TextureDSPContext *dsp = avctx->priv_data; + avctx->pix_fmt = AV_PIX_FMT_BGR0; + ff_texturedsp_init(dsp); + return 0; +} + +static int decode_rtv1(GetByteContext *gb, uint8_t *dst, ptrdiff_t linesize, + int width, int height, int flag, + int (*dxt1_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)) +{ + uint8_t block[8] = { 0 }; + int run = 0; + + for (int y = 0; y < height; y += 4) { + for (int x = 0; x < width * 4; x += 16) { + int mode = 0; + + if (run && --run > 0) { + dxt1_block(dst + x, linesize, block); + } else { + int a, b; + + if (bytestream2_get_bytes_left(gb) < 4) + break; + + a = bytestream2_get_le16u(gb); + b = bytestream2_get_le16u(gb); + if (a == b && flag) { + AV_WL32(block + 4, 0); + } else if (a == 1 && b == 0xffff) { + mode = 1; + } else if (b && a == 0) { + run = b; + } else { + AV_WL16(block, a); + AV_WL16(block + 2, b); + AV_WL32(block + 4, bytestream2_get_le32(gb)); + } + if (run && !mode) { + dxt1_block(dst + x, linesize, block); + } else if (!mode) { + AV_WL16(block, a); + AV_WL16(block + 2, b); + dxt1_block(dst + x, linesize, block); + } else { + if (bytestream2_get_bytes_left(gb) < 12 * 4) + break; + + for (int by = 0; by < 4; by++) { + for (int bx = 0; bx < 4; bx++) + AV_WL32(dst + x + bx * 4 + by * linesize, bytestream2_get_le24u(gb)); + } + } + } + } + + dst += linesize * 4; + } + + return 0; +} + +static int decode_frame(AVCodecContext *avctx, AVFrame *p, + int *got_frame, AVPacket *avpkt) +{ + int ret, width, height, flags; + TextureDSPContext *dsp = avctx->priv_data; + GetByteContext gb; + ptrdiff_t linesize; + uint8_t *dst; + + if (avpkt->size < 22) + return AVERROR_INVALIDDATA; + + bytestream2_init(&gb, avpkt->data, avpkt->size); + + if (bytestream2_get_le32(&gb) != MKTAG('D','X','T','1')) + return AVERROR_INVALIDDATA; + flags = bytestream2_get_le32(&gb); + + width = bytestream2_get_le32(&gb); + height = bytestream2_get_le32(&gb); + ret = ff_set_dimensions(avctx, FFALIGN(width, 4), FFALIGN(height, 4)); + if (ret < 0) + return ret; + + avctx->width = width; + avctx->height = height; + + if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0) + return ret; + + dst = p->data[0] + p->linesize[0] * (avctx->coded_height - 1); + linesize = -p->linesize[0]; + + decode_rtv1(&gb, dst, linesize, width, height, flags, dsp->dxt1_block); + + p->pict_type = AV_PICTURE_TYPE_I; + p->flags |= AV_FRAME_FLAG_KEY; + + *got_frame = 1; + + return avpkt->size; +} + +const FFCodec ff_rtv1_decoder = { + .p.name = "rtv1", + CODEC_LONG_NAME("RTV1 (RivaTuner Video)"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_RTV1, + .priv_data_size = sizeof(TextureDSPContext), + .init = decode_init, + FF_CODEC_DECODE_CB(decode_frame), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index 9d0485b068..2618016a83 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 16 -#define LIBAVCODEC_VERSION_MICRO 101 +#define LIBAVCODEC_VERSION_MINOR 17 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ diff --git a/libavformat/riff.c b/libavformat/riff.c index 7319406b39..4279071159 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -501,6 +501,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_NOTCHLC, MKTAG('n', 'l', 'c', '1') }, { AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '1') }, { AV_CODEC_ID_VQC, MKTAG('V', 'Q', 'C', '2') }, + { AV_CODEC_ID_RTV1, MKTAG('R', 'T', 'V', '1') }, { AV_CODEC_ID_NONE, 0 } };