Re: [FFmpeg-devel] [PATCH 2/2] lavc/msrleenc: Add msrle encoder
Tomas Härdin: > +typedef struct MSRLEContext { > +const AVClass *class; > +int curframe; > +AVFrame *last_frame; > +} MSRLEContext; > + > +static av_cold int msrle_encode_init(AVCodecContext *avctx) > +{ > +avctx->bits_per_coded_sample = 8; > +return 0; > +} > + > +static void write_run(AVCodecContext *avctx, uint8_t **data, int len, int > value) > +{ > +// we're allowed to write odd runs > +while (len >= 255) { > +bytestream_put_byte(data, 255); > +bytestream_put_byte(data, value); > +len -= 255; > +} > +if (len >= 1) { > +// this is wasteful when len == 1 and sometimes when len == 2 > +// but sometimes we have no choice. also write_absolute() > +// relies on this > +bytestream_put_byte(data, len); > +bytestream_put_byte(data, value); > +} > +} > + > +static void write_absolute(AVCodecContext *avctx, uint8_t **data, uint8_t > *line, int len) > +{ > +// writing 255 would be wasteful here due to the padding requirement > +while (len >= 254) { > +bytestream_put_byte(data, 0); > +bytestream_put_byte(data, 254); > +bytestream_put_buffer(data, line, 254); > +line += 254; > +len -= 254; > +} > +if (len == 1) { > +// it's less wasteful to write single pixels as runs > +// not to mention that absolute mode requires >= 3 pixels > +write_run(avctx, data, 1, line[0]); > +} else if (len == 2) { > +write_run(avctx, data, 1, line[0]); > +write_run(avctx, data, 1, line[1]); > +} else if (len > 0) { > +bytestream_put_byte(data, 0); > +bytestream_put_byte(data, len); > +bytestream_put_buffer(data, line, len); > +if (len & 1) > +bytestream_put_byte(data, 0); > +} > +} > + > +static void write_delta(AVCodecContext *avctx, uint8_t **data, int delta) > +{ > +// we let the yskip logic handle the case where we want to delta > +// to following lines. it's not perfect but it's easier than finding > +// the optimal combination of end-of-lines and deltas to reach any > +// following position including places where dx < 0 > +while (delta >= 255) { > +bytestream_put_byte(data, 0); > +bytestream_put_byte(data, 2); > +bytestream_put_byte(data, 255); > +bytestream_put_byte(data, 0); > +delta -= 255; > +} > +if (delta > 0) { > +bytestream_put_byte(data, 0); > +bytestream_put_byte(data, 2); > +bytestream_put_byte(data, delta); > +bytestream_put_byte(data, 0); > +} > +} > + > +static void write_yskip(AVCodecContext *avctx, uint8_t **data, int yskip) > +{ > +if (yskip < 4) > +return; > +// we have yskip*2 nul bytess > +*data -= 2*yskip; > +// the end-of-line counts as one skip > +yskip--; > +while (yskip >= 255) { > +bytestream_put_byte(data, 0); > +bytestream_put_byte(data, 2); > +bytestream_put_byte(data, 0); > +bytestream_put_byte(data, 255); > +yskip -= 255; > +} > +if (yskip > 0) { > +bytestream_put_byte(data, 0); > +bytestream_put_byte(data, 2); > +bytestream_put_byte(data, 0); > +bytestream_put_byte(data, yskip); > +} > +bytestream_put_be16(data, 0x); > +} > + > +// used both to encode lines in keyframes and to encode lines between deltas > +static void encode_line(AVCodecContext *avctx, uint8_t **data, uint8_t > *line, int length) > +{ > +int run = 0, last = -1, absstart = 0; > +if (length == 0) > +return; > +for (int x = 0; x < length; x++) { > +if (last == line[x]) { > +run++; > +if (run == 3) > +write_absolute(avctx, data, [absstart], x - absstart - > 2); > +} else { > +if (run >= 3) { > +write_run(avctx, data, run, last); > +absstart = x; > +} > +run = 1; > +} > +last = line[x]; > +} > +if (run >= 3) > +write_run(avctx, data, run, last); > +else > +write_absolute(avctx, data, [absstart], length - absstart); > +} > + > +static int encode(AVCodecContext *avctx, AVPacket *pkt, > + const AVFrame *pict, int keyframe, int *got_keyframe) > +{ > +MSRLEContext *s = avctx->priv_data; > +uint8_t *data = pkt->data; > + > +/* Compare the current frame to the last frame, or code the entire frame > +if keyframe != 0. We're continually outputting pairs of bytes: > + > +00 00 end of line > +00 01 end of bitmap > +00 02 dx dy delta. move pointer to x+dx, y+dy > +00 ll dd dd .. absolute (verbatim) mode. ll >= 3 > +rr dd run. rr >= 1 > + > +For keyframes we only have absolute mode and runs at our disposal, > and > +we are not allowed
[FFmpeg-devel] [PATCH 2/2] lavc/msrleenc: Add msrle encoder
Please check that I got the palette handling correct. Else this producing output of similar size to the VfW encoder. /Tomas From ab9bb1aca7ddda8f4788b0a63460470fce021e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Thu, 8 Jun 2023 11:57:53 +0200 Subject: [PATCH 2/2] lavc/msrleenc: Add msrle encoder Keyframes are marked automagically --- MAINTAINERS| 1 + doc/encoders.texi | 14 ++ libavcodec/Makefile| 1 + libavcodec/allcodecs.c | 1 + libavcodec/msrleenc.c | 303 + tests/fate/vcodec.mak | 3 + tests/ref/vsynth/vsynth1-msrle | 4 + tests/ref/vsynth/vsynth2-msrle | 4 + tests/ref/vsynth/vsynth3-msrle | 4 + tests/ref/vsynth/vsynth_lena-msrle | 4 + 10 files changed, 339 insertions(+) create mode 100644 libavcodec/msrleenc.c create mode 100644 tests/ref/vsynth/vsynth1-msrle create mode 100644 tests/ref/vsynth/vsynth2-msrle create mode 100644 tests/ref/vsynth/vsynth3-msrle create mode 100644 tests/ref/vsynth/vsynth_lena-msrle diff --git a/MAINTAINERS b/MAINTAINERS index 07852486e4..3584a68442 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -210,6 +210,7 @@ Codecs: mqc* Nicolas Bertrand msmpeg4.c, msmpeg4data.h Michael Niedermayer msrle.c Mike Melanson + msrleenc.cTomas Härdin msvideo1.cMike Melanson nuv.c Reimar Doeffinger nvdec*, nvenc*Timo Rothenpieler diff --git a/doc/encoders.texi b/doc/encoders.texi index 20cb8a1421..25d6b7f09e 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -3061,6 +3061,20 @@ Video encoders can take input in either of nv12 or yuv420p form (some encoders support both, some support only either - in practice, nv12 is the safer choice, especially among HW encoders). +@section Microsoft RLE + +Microsoft RLE aka MSRLE encoder. +Only 8-bit palette mode supported. +Compatible with Windows 3.1 and Windows 95. + +@subsection Options + +@table @option +@item g @var{integer} +Keyframe interval. +A keyframe is inserted at least every @code{-g} frames, sometimes sooner. +@end table + @section mpeg2 MPEG-2 video encoder. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 87a8b90037..2c88dd65d5 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -552,6 +552,7 @@ OBJS-$(CONFIG_MSA1_DECODER)+= mss3.o OBJS-$(CONFIG_MSCC_DECODER)+= mscc.o OBJS-$(CONFIG_MSNSIREN_DECODER)+= siren.o OBJS-$(CONFIG_MSP2_DECODER)+= msp2dec.o +OBJS-$(CONFIG_MSRLE_ENCODER) += msrleenc.o OBJS-$(CONFIG_MSRLE_DECODER) += msrle.o msrledec.o OBJS-$(CONFIG_MSS1_DECODER)+= mss1.o mss12.o OBJS-$(CONFIG_MSS2_DECODER)+= mss2.o mss12.o mss2dsp.o wmv2data.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index a98c300da4..5d4889b968 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -228,6 +228,7 @@ extern const FFCodec ff_msmpeg4v3_encoder; extern const FFCodec ff_msmpeg4v3_decoder; extern const FFCodec ff_msmpeg4_crystalhd_decoder; extern const FFCodec ff_msp2_decoder; +extern const FFCodec ff_msrle_encoder; extern const FFCodec ff_msrle_decoder; extern const FFCodec ff_mss1_decoder; extern const FFCodec ff_mss2_decoder; diff --git a/libavcodec/msrleenc.c b/libavcodec/msrleenc.c new file mode 100644 index 00..17d40cbd6a --- /dev/null +++ b/libavcodec/msrleenc.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2023 Tomas Härdin + * + * 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 + * MSRLE encoder + * @see https://wiki.multimedia.cx/index.php?title=Microsoft_RLE + */ + +// TODO: pal4 mode? + +#include "bytestream.h" +#include "codec_internal.h" +#include "encode.h" + +typedef struct MSRLEContext { +const AVClass *class; +int curframe; +AVFrame *last_frame; +} MSRLEContext; + +static av_cold int msrle_encode_init(AVCodecContext *avctx) +{ +avctx->bits_per_coded_sample = 8; +return 0; +} + +static void write_run(AVCodecContext *avctx, uint8_t