On 2/16/2021 5:24 PM, Anton Khirnov wrote:
It shares very little code with pngdec, so keeping them together only
makes the code harder to read.
---
libavcodec/Makefile | 2 +-
libavcodec/lscrdec.c | 279 +++++++++++++++++++++++++++++++++++++++++++
libavcodec/png.h | 5 +
libavcodec/pngdec.c | 174 +--------------------------
4 files changed, 291 insertions(+), 169 deletions(-)
create mode 100644 libavcodec/lscrdec.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3341801b97..b0c6d675d0 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -439,7 +439,7 @@ OBJS-$(CONFIG_KMVC_DECODER) += kmvc.o
OBJS-$(CONFIG_LAGARITH_DECODER) += lagarith.o lagarithrac.o
OBJS-$(CONFIG_LJPEG_ENCODER) += ljpegenc.o mjpegenc_common.o
OBJS-$(CONFIG_LOCO_DECODER) += loco.o
-OBJS-$(CONFIG_LSCR_DECODER) += png.o pngdec.o pngdsp.o
+OBJS-$(CONFIG_LSCR_DECODER) += lscrdec.o png.o pngdec.o pngdsp.o
OBJS-$(CONFIG_M101_DECODER) += m101.o
OBJS-$(CONFIG_MACE3_DECODER) += mace.o
OBJS-$(CONFIG_MACE6_DECODER) += mace.o
diff --git a/libavcodec/lscrdec.c b/libavcodec/lscrdec.c
new file mode 100644
index 0000000000..242ae8fcb2
--- /dev/null
+++ b/libavcodec/lscrdec.c
@@ -0,0 +1,279 @@
+/*
+ * 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 <stdint.h>
+#include <zlib.h>
+
+#include "libavutil/frame.h"
+#include "libavutil/error.h"
+#include "libavutil/log.h"
+
+#include "avcodec.h"
+#include "bytestream.h"
+#include "codec.h"
+#include "internal.h"
+#include "packet.h"
+#include "png.h"
+#include "pngdsp.h"
+
+typedef struct LSCRContext {
+ PNGDSPContext dsp;
+ AVCodecContext *avctx;
+
+ AVFrame *last_picture;
+ uint8_t *buffer;
+ int buffer_size;
+ uint8_t *crow_buf;
+ int crow_size;
+ uint8_t *last_row;
+ unsigned int last_row_size;
+
+ GetByteContext gb;
+ uint8_t *image_buf;
+ int image_linesize;
+ int row_size;
+ int cur_h;
+ int y;
+
+ z_stream zstream;
+} LSCRContext;
+
+static void handle_row(LSCRContext *s, AVFrame *frame)
Unused frame argument.
+{
+ uint8_t *ptr, *last_row;
+
+ ptr = s->image_buf + s->image_linesize * s->y;
+ if (s->y == 0)
+ last_row = s->last_row;
+ else
+ last_row = ptr - s->image_linesize;
+
+ ff_png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1,
+ last_row, s->row_size, 3);
+
+ s->y++;
+}
+
+static int decode_idat(LSCRContext *s, AVFrame *frame, int length)
+{
+ int ret;
+ s->zstream.avail_in = FFMIN(length, bytestream2_get_bytes_left(&s->gb));
+ s->zstream.next_in = s->gb.buffer;
+ bytestream2_skip(&s->gb, length);
+
+ /* decode one line if possible */
+ while (s->zstream.avail_in > 0) {
+ ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END) {
+ av_log(s->avctx, AV_LOG_ERROR, "inflate returned error %d\n", ret);
+ return AVERROR_EXTERNAL;
+ }
+ if (s->zstream.avail_out == 0) {
+ if (s->y < s->cur_h) {
+ handle_row(s, frame);
+ }
+ s->zstream.avail_out = s->crow_size;
+ s->zstream.next_out = s->crow_buf;
+ }
+ if (ret == Z_STREAM_END && s->zstream.avail_in > 0) {
+ av_log(s->avctx, AV_LOG_WARNING,
+ "%d undecompressed bytes left in buffer\n",
s->zstream.avail_in);
+ return 0;
+ }
+ }
+ return 0;
+}
+
+static int decode_frame_lscr(AVCodecContext *avctx,
+ void *data, int *got_frame,
+ AVPacket *avpkt)
+{
+ LSCRContext *const s = avctx->priv_data;
+ GetByteContext *gb = &s->gb;
+ AVFrame *frame = data;
+ int ret, nb_blocks, offset = 0;
+
+ if (avpkt->size < 2)
+ return AVERROR_INVALIDDATA;
+ if (avpkt->size == 2)
+ return 0;
+
+ bytestream2_init(gb, avpkt->data, avpkt->size);
+
+ if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+
+ nb_blocks = bytestream2_get_le16(gb);
+ if (bytestream2_get_bytes_left(gb) < 2 + nb_blocks * (12 + 8))
+ return AVERROR_INVALIDDATA;
+
+ if (s->last_picture->data[0]) {
+ ret = av_frame_copy(frame, s->last_picture);
You could use ff_reget_buf() instead. And if nb_blocks can be 0 (meaning
no changes since the previous frame), you could even use the
FF_REGET_BUFFER_FLAG_READONLY flag and completely avoid any memcpy.
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".