From ee50cc18b3943405aa476e31c8553aa098350b1e Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Tue, 22 Mar 2022 02:29:29 +0100 Subject: avcodec/vbnenc: add VBN encoder Signed-off-by: Marton Balint --- Changelog | 2 +- configure | 1 + doc/encoders.texi | 16 +++++ doc/general_contents.texi | 2 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/vbnenc.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/version.h | 4 +- libavformat/img2enc.c | 2 +- libavformat/version.h | 4 +- 10 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 libavcodec/vbnenc.c diff --git a/Changelog b/Changelog index 55512c8e03..29754be4c9 100644 --- a/Changelog +++ b/Changelog @@ -7,7 +7,7 @@ version 5.1: - pcm-bluray encoder - DFPWM audio encoder/decoder and raw muxer/demuxer - SITI filter -- Vizrt Binary Image decoder +- Vizrt Binary Image encoder/decoder version 5.0: diff --git a/configure b/configure index 90c99ff85e..9c8965852b 100755 --- a/configure +++ b/configure @@ -2960,6 +2960,7 @@ utvideo_decoder_select="bswapdsp llviddsp" utvideo_encoder_select="bswapdsp huffman llvidencdsp" vble_decoder_select="llviddsp" vbn_decoder_select="texturedsp" +vbn_encoder_select="texturedspenc" vc1_decoder_select="blockdsp h263_decoder h264qpel intrax8 mpegvideodec vc1dsp" vc1image_decoder_select="vc1_decoder" vorbis_decoder_select="mdct" diff --git a/doc/encoders.texi b/doc/encoders.texi index 806cc430d4..aac9f25e55 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -3773,6 +3773,22 @@ required to produce a stream usable with all decoders. @end table +@section vbn + +Vizrt Binary Image encoder. + +This format is used by the broadcast vendor Vizrt for quick texture streaming. +Advanced features of the format such as LZW compression of texture data or +generation of mipmaps are not supported. + +@subsection Options + +@table @option +@item format @var{string} +Sets the texture compression used by the VBN file. Can be @var{dxt1}, +@var{dxt5} or @var{raw}. Default is @var{dxt5}. +@end table + @section vc2 SMPTE VC-2 (previously BBC Dirac Pro). This codec was primarily aimed at diff --git a/doc/general_contents.texi b/doc/general_contents.texi index fcd9da1b34..238568f2bb 100644 --- a/doc/general_contents.texi +++ b/doc/general_contents.texi @@ -786,6 +786,8 @@ following image formats are supported: @tab YUV, JPEG and some extension is not supported yet. @item Truevision Targa @tab X @tab X @tab Targa (.TGA) image format +@item VBN @tab X @tab X + @tab Vizrt Binary Image format @item WebP @tab E @tab X @tab WebP image format, encoding supported through external library libwebp @item XBM @tab X @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 90700085b8..90f46035d9 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -709,6 +709,7 @@ OBJS-$(CONFIG_V410_DECODER) += v410dec.o OBJS-$(CONFIG_V410_ENCODER) += v410enc.o OBJS-$(CONFIG_VB_DECODER) += vb.o OBJS-$(CONFIG_VBN_DECODER) += vbndec.o +OBJS-$(CONFIG_VBN_ENCODER) += vbnenc.o OBJS-$(CONFIG_VBLE_DECODER) += vble.o OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1_block.o vc1_loopfilter.o \ vc1_mc.o vc1_pred.o vc1.o vc1data.o \ diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index f0a7ea7fd4..585918da93 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -347,6 +347,7 @@ extern const FFCodec ff_v408_decoder; extern const FFCodec ff_v410_encoder; extern const FFCodec ff_v410_decoder; extern const FFCodec ff_vb_decoder; +extern const FFCodec ff_vbn_encoder; extern const FFCodec ff_vbn_decoder; extern const FFCodec ff_vble_decoder; extern const FFCodec ff_vc1_decoder; diff --git a/libavcodec/vbnenc.c b/libavcodec/vbnenc.c new file mode 100644 index 0000000000..5c855bcd73 --- /dev/null +++ b/libavcodec/vbnenc.c @@ -0,0 +1,173 @@ +/* + * Vizrt Binary Image encoder + * + * 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 + */ + +/** + * @file + * Vizrt Binary Image encoder + */ + +#include "avcodec.h" +#include "bytestream.h" +#include "codec_internal.h" +#include "encode.h" +#include "texturedsp.h" +#include "vbn.h" + +#include "libavutil/imgutils.h" +#include "libavutil/frame.h" +#include "libavutil/opt.h" + +typedef struct VBNContext { + AVClass *class; + TextureDSPContext dxtc; + PutByteContext pb; + int format; + TextureDSPThreadContext enc; +} VBNContext; + +static int vbn_encode(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + VBNContext *ctx = avctx->priv_data; + PutByteContext *pb = &ctx->pb; + int ret; + ptrdiff_t linesize; + int64_t pkt_size; + + ret = av_image_check_size2(frame->width, frame->height, INT_MAX, frame->format, 0, avctx); + if (ret < 0) + return ret; + + if (ctx->format == VBN_FORMAT_DXT1 || ctx->format == VBN_FORMAT_DXT5) { + if (frame->width % TEXTURE_BLOCK_W || frame->height % TEXTURE_BLOCK_H) { + av_log(avctx, AV_LOG_ERROR, "Video size %dx%d is not multiple of 4\n", frame->width, frame->height); + return AVERROR(EINVAL); + } + if (frame->format != AV_PIX_FMT_RGBA) { + av_log(avctx, AV_LOG_ERROR, "DXT formats only support RGBA pixel format\n"); + return AVERROR(EINVAL); + } + ctx->enc.raw_ratio = 16; + ctx->enc.slice_count = av_clip(avctx->thread_count, 1, avctx->height / TEXTURE_BLOCK_H); + } + + switch (ctx->format) { + case VBN_FORMAT_DXT1: + linesize = frame->width / 2; + ctx->enc.tex_funct = ctx->dxtc.dxt1_block; + ctx->enc.tex_ratio = 8; + break; + case VBN_FORMAT_DXT5: + linesize = frame->width; + ctx->enc.tex_funct = ctx->dxtc.dxt5_block; + ctx->enc.tex_ratio = 16; + break; + case VBN_FORMAT_RAW: + linesize = av_image_get_linesize(frame->format, frame->width, 0); + if (linesize < 0) + return linesize; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid format %02X\n", ctx->format); + return AVERROR(EINVAL); + } + + pkt_size = VBN_HEADER_SIZE + linesize * frame->height; + if (pkt_size > INT_MAX) + return AVERROR(EINVAL); + + if ((ret = ff_get_encode_buffer(avctx, pkt, pkt_size, 0)) < 0) + return ret; + + memset(pkt->data, 0, VBN_HEADER_SIZE); + bytestream2_init_writer(pb, pkt->data, pkt_size); + bytestream2_put_le32(pb, VBN_MAGIC); + bytestream2_put_le32(pb, VBN_MAJOR); + bytestream2_put_le32(pb, VBN_MINOR); + bytestream2_put_le32(pb, frame->width); + bytestream2_put_le32(pb, frame->height); + bytestream2_put_le32(pb, frame->format == AV_PIX_FMT_RGBA ? 4 : 3); + bytestream2_put_le32(pb, ctx->format); + bytestream2_put_le32(pb, frame->format == AV_PIX_FMT_RGBA ? VBN_PIX_RGBA : VBN_PIX_RGB); + bytestream2_put_le32(pb, 0); // mipmaps + bytestream2_put_le32(pb, pkt_size - VBN_HEADER_SIZE); + bytestream2_seek_p(pb, 64, SEEK_SET); + bytestream2_put_le32(pb, pkt_size - VBN_HEADER_SIZE); + + if (ctx->format == VBN_FORMAT_DXT1 || ctx->format == VBN_FORMAT_DXT5) { + ctx->enc.frame_data.in = (frame->height - 1) * frame->linesize[0] + frame->data[0]; + ctx->enc.stride = -frame->linesize[0]; + ctx->enc.tex_data.out = pkt->data + VBN_HEADER_SIZE; + avctx->execute2(avctx, ff_texturedsp_compress_thread, &ctx->enc, NULL, ctx->enc.slice_count); + } else { + uint8_t *flipped = frame->data[0] + frame->linesize[0] * (frame->height - 1); + av_image_copy_plane(pkt->data + VBN_HEADER_SIZE, linesize, flipped, -frame->linesize[0], linesize, frame->height); + } + + *got_packet = 1; + return 0; +} + +static av_cold int vbn_init(AVCodecContext *avctx) +{ + VBNContext *ctx = avctx->priv_data; + ff_texturedspenc_init(&ctx->dxtc); + return 0; +} + +static av_cold int vbn_close(AVCodecContext *avctx) +{ + return 0; +} + +#define OFFSET(x) offsetof(VBNContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "format", "Texture format", OFFSET(format), AV_OPT_TYPE_INT, { .i64 = VBN_FORMAT_DXT5 }, VBN_FORMAT_RAW, VBN_FORMAT_DXT5, FLAGS, "format" }, + { "raw", "RAW texture", 0, AV_OPT_TYPE_CONST, { .i64 = VBN_FORMAT_RAW }, 0, 0, FLAGS, "format" }, + { "dxt1", "DXT1 texture", 0, AV_OPT_TYPE_CONST, { .i64 = VBN_FORMAT_DXT1 }, 0, 0, FLAGS, "format" }, + { "dxt5", "DXT5 texture", 0, AV_OPT_TYPE_CONST, { .i64 = VBN_FORMAT_DXT5 }, 0, 0, FLAGS, "format" }, + { NULL }, +}; + +static const AVClass vbnenc_class = { + .class_name = "VBN encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_vbn_encoder = { + .p.name = "vbn", + .p.long_name = NULL_IF_CONFIG_SMALL("Vizrt Binary Image"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_VBN, + .p.capabilities = AV_CODEC_CAP_SLICE_THREADS, + .p.priv_class = &vbnenc_class, + .init = vbn_init, + FF_CODEC_ENCODE_CB(vbn_encode), + .close = vbn_close, + .priv_data_size = sizeof(VBNContext), + .p.pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE, + }, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index aa3a484c51..26ee41eb1f 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 25 -#define LIBAVCODEC_VERSION_MICRO 101 +#define LIBAVCODEC_VERSION_MINOR 26 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c index 9b3b8741c8..ae351963d9 100644 --- a/libavformat/img2enc.c +++ b/libavformat/img2enc.c @@ -265,7 +265,7 @@ const AVOutputFormat ff_image2_muxer = { .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"), .extensions = "bmp,dpx,exr,jls,jpeg,jpg,ljpg,pam,pbm,pcx,pfm,pgm,pgmyuv,png," "ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8,im24," - "sunras,xbm,xface,pix,y", + "sunras,vbn,xbm,xface,pix,y", .priv_data_size = sizeof(VideoMuxData), .video_codec = AV_CODEC_ID_MJPEG, .write_header = write_header, diff --git a/libavformat/version.h b/libavformat/version.h index f4a26c2870..683184d5da 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,8 +31,8 @@ #include "version_major.h" -#define LIBAVFORMAT_VERSION_MINOR 20 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MINOR 21 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ -- cgit v1.2.3