I do not like this. On Tue, Feb 16, 2021 at 9:26 PM Anton Khirnov <an...@khirnov.net> 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) > +{ > + 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); > + if (ret < 0) > + return ret; > + } > + > + for (int b = 0; b < nb_blocks; b++) { > + int x, y, x2, y2, w, h, left; > + uint32_t csize, size; > + > + s->zstream.zalloc = ff_png_zalloc; > + s->zstream.zfree = ff_png_zfree; > + s->zstream.opaque = NULL; > + > + if ((ret = inflateInit(&s->zstream)) != Z_OK) { > + av_log(avctx, AV_LOG_ERROR, "inflateInit returned error > %d\n", ret); > + ret = AVERROR_EXTERNAL; > + goto end; > + } > + > + bytestream2_seek(gb, 2 + b * 12, SEEK_SET); > + > + x = bytestream2_get_le16(gb); > + y = bytestream2_get_le16(gb); > + x2 = bytestream2_get_le16(gb); > + y2 = bytestream2_get_le16(gb); > + w = x2-x; > + s->cur_h = h = y2-y; > + > + if (w <= 0 || x < 0 || x >= avctx->width || w + x > avctx->width > || > + h <= 0 || y < 0 || y >= avctx->height || h + y > > avctx->height) { > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + > + size = bytestream2_get_le32(gb); > + > + frame->key_frame = (nb_blocks == 1) && > + (w == avctx->width) && > + (h == avctx->height) && > + (x == 0) && (y == 0); > + > + bytestream2_seek(gb, 2 + nb_blocks * 12 + offset, SEEK_SET); > + csize = bytestream2_get_be32(gb); > + if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) { > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + > + offset += size; > + left = size; > + > + s->y = 0; > + s->row_size = w * 3; > + > + av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + > 16); > + if (!s->buffer) { > + ret = AVERROR(ENOMEM); > + goto end; > + } > + > + av_fast_padded_malloc(&s->last_row, &s->last_row_size, > s->row_size); > + if (!s->last_row) { > + ret = AVERROR(ENOMEM); > + goto end; > + } > + > + s->crow_size = w * 3 + 1; > + s->crow_buf = s->buffer + 15; > + s->zstream.avail_out = s->crow_size; > + s->zstream.next_out = s->crow_buf; > + s->image_buf = frame->data[0] + (avctx->height - y - 1) * > frame->linesize[0] + x * 3; > + s->image_linesize =-frame->linesize[0]; > + > + while (left > 16) { > + ret = decode_idat(s, frame, csize); > + if (ret < 0) > + goto end; > + left -= csize + 16; > + if (left > 16) { > + bytestream2_skip(gb, 4); > + csize = bytestream2_get_be32(gb); > + if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', > 'T')) { > + ret = AVERROR_INVALIDDATA; > + goto end; > + } > + } > + } > + > + inflateEnd(&s->zstream); > + } > + > + frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : > AV_PICTURE_TYPE_P; > + > + av_frame_unref(s->last_picture); > + if ((ret = av_frame_ref(s->last_picture, frame)) < 0) > + return ret; > + > + *got_frame = 1; > +end: > + inflateEnd(&s->zstream); > + > + if (ret < 0) > + return ret; > + return avpkt->size; > +} > + > +static int lscr_decode_close(AVCodecContext *avctx) > +{ > + LSCRContext *s = avctx->priv_data; > + > + av_frame_free(&s->last_picture); > + av_freep(&s->buffer); > + av_freep(&s->last_row); > + > + return 0; > +} > + > +static int lscr_decode_init(AVCodecContext *avctx) > +{ > + LSCRContext *s = avctx->priv_data; > + > + avctx->color_range = AVCOL_RANGE_JPEG; > + avctx->pix_fmt = AV_PIX_FMT_BGR24; > + > + s->avctx = avctx; > + s->last_picture = av_frame_alloc(); > + if (!s->last_picture) > + return AVERROR(ENOMEM); > + > + ff_pngdsp_init(&s->dsp); > + > + return 0; > +} > + > +static void lscr_decode_flush(AVCodecContext *avctx) > +{ > + LSCRContext *s = avctx->priv_data; > + av_frame_unref(s->last_picture); > +} > + > +AVCodec ff_lscr_decoder = { > + .name = "lscr", > + .long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"), > + .type = AVMEDIA_TYPE_VIDEO, > + .id = AV_CODEC_ID_LSCR, > + .priv_data_size = sizeof(LSCRContext), > + .init = lscr_decode_init, > + .close = lscr_decode_close, > + .decode = decode_frame_lscr, > + .flush = lscr_decode_flush, > + .capabilities = AV_CODEC_CAP_DR1, > + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | > FF_CODEC_CAP_INIT_THREADSAFE | > + FF_CODEC_CAP_ALLOCATE_PROGRESS, > +}; > diff --git a/libavcodec/png.h b/libavcodec/png.h > index e967fcf38f..a15560131f 100644 > --- a/libavcodec/png.h > +++ b/libavcodec/png.h > @@ -24,6 +24,8 @@ > > #include <stdint.h> > > +#include "pngdsp.h" > + > #define PNG_COLOR_MASK_PALETTE 1 > #define PNG_COLOR_MASK_COLOR 2 > #define PNG_COLOR_MASK_ALPHA 4 > @@ -61,4 +63,7 @@ int ff_png_pass_row_size(int pass, int bits_per_pixel, > int width); > > void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t > *top, int w, int bpp); > > +void ff_png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, > + uint8_t *src, uint8_t *last, int size, int bpp); > + > #endif /* AVCODEC_PNG_H */ > diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c > index 61642b7cbe..e05e44f564 100644 > --- a/libavcodec/pngdec.c > +++ b/libavcodec/pngdec.c > @@ -250,8 +250,8 @@ void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t > *src, uint8_t *top, > } > > /* NOTE: 'dst' can be equal to 'last' */ > -static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int > filter_type, > - uint8_t *src, uint8_t *last, int size, int bpp) > +void ff_png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, > + uint8_t *src, uint8_t *last, int size, int bpp) > { > int i, p, r, g, b, a; > > @@ -343,8 +343,8 @@ static void png_handle_row(PNGDecContext *s) > else > last_row = ptr - s->image_linesize; > > - png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1, > - last_row, s->row_size, s->bpp); > + ff_png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1, > + last_row, s->row_size, s->bpp); > /* loco lags by 1 row so that it doesn't interfere with top > prediction */ > if (s->filter_type == PNG_FILTER_TYPE_LOCO && s->y > 0) { > if (s->bit_depth == 16) { > @@ -377,8 +377,8 @@ static void png_handle_row(PNGDecContext *s) > * wait for the next one */ > if (got_line) > break; > - png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], > s->crow_buf + 1, > - s->last_row, s->pass_row_size, s->bpp); > + ff_png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], > s->crow_buf + 1, > + s->last_row, s->pass_row_size, s->bpp); > FFSWAP(uint8_t *, s->last_row, s->tmp_row); > FFSWAP(unsigned int, s->last_row_size, s->tmp_row_size); > got_line = 1; > @@ -1585,148 +1585,6 @@ end: > } > #endif > > -#if CONFIG_LSCR_DECODER > -static int decode_frame_lscr(AVCodecContext *avctx, > - void *data, int *got_frame, > - AVPacket *avpkt) > -{ > - PNGDecContext *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.f->data[0]) { > - ret = av_frame_copy(frame, s->last_picture.f); > - if (ret < 0) > - return ret; > - } > - > - for (int b = 0; b < nb_blocks; b++) { > - int x, y, x2, y2, w, h, left; > - uint32_t csize, size; > - > - s->zstream.zalloc = ff_png_zalloc; > - s->zstream.zfree = ff_png_zfree; > - s->zstream.opaque = NULL; > - > - if ((ret = inflateInit(&s->zstream)) != Z_OK) { > - av_log(avctx, AV_LOG_ERROR, "inflateInit returned error > %d\n", ret); > - ret = AVERROR_EXTERNAL; > - goto end; > - } > - > - bytestream2_seek(gb, 2 + b * 12, SEEK_SET); > - > - x = bytestream2_get_le16(gb); > - y = bytestream2_get_le16(gb); > - x2 = bytestream2_get_le16(gb); > - y2 = bytestream2_get_le16(gb); > - s->width = s->cur_w = w = x2-x; > - s->height = s->cur_h = h = y2-y; > - > - if (w <= 0 || x < 0 || x >= avctx->width || w + x > avctx->width > || > - h <= 0 || y < 0 || y >= avctx->height || h + y > > avctx->height) { > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - > - size = bytestream2_get_le32(gb); > - > - frame->key_frame = (nb_blocks == 1) && > - (w == avctx->width) && > - (h == avctx->height) && > - (x == 0) && (y == 0); > - > - bytestream2_seek(gb, 2 + nb_blocks * 12 + offset, SEEK_SET); > - csize = bytestream2_get_be32(gb); > - if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) { > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - > - offset += size; > - left = size; > - > - s->y = 0; > - s->row_size = w * 3; > - > - av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + > 16); > - if (!s->buffer) { > - ret = AVERROR(ENOMEM); > - goto end; > - } > - > - av_fast_padded_malloc(&s->last_row, &s->last_row_size, > s->row_size); > - if (!s->last_row) { > - ret = AVERROR(ENOMEM); > - goto end; > - } > - > - s->crow_size = w * 3 + 1; > - s->crow_buf = s->buffer + 15; > - s->zstream.avail_out = s->crow_size; > - s->zstream.next_out = s->crow_buf; > - s->image_buf = frame->data[0] + (avctx->height - y - 1) * > frame->linesize[0] + x * 3; > - s->image_linesize =-frame->linesize[0]; > - s->bpp = 3; > - s->pic_state = 0; > - > - while (left > 16) { > - ret = png_decode_idat(s, csize); > - if (ret < 0) > - goto end; > - left -= csize + 16; > - if (left > 16) { > - bytestream2_skip(gb, 4); > - csize = bytestream2_get_be32(gb); > - if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', > 'T')) { > - ret = AVERROR_INVALIDDATA; > - goto end; > - } > - } > - } > - > - inflateEnd(&s->zstream); > - } > - > - frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : > AV_PICTURE_TYPE_P; > - > - av_frame_unref(s->last_picture.f); > - if ((ret = av_frame_ref(s->last_picture.f, frame)) < 0) > - return ret; > - > - *got_frame = 1; > -end: > - inflateEnd(&s->zstream); > - > - if (ret < 0) > - return ret; > - return avpkt->size; > -} > - > -static void decode_flush(AVCodecContext *avctx) > -{ > - PNGDecContext *s = avctx->priv_data; > - > - av_frame_unref(s->last_picture.f); > -} > - > -#endif > - > #if HAVE_THREADS > static int update_thread_context(AVCodecContext *dst, const > AVCodecContext *src) > { > @@ -1783,9 +1641,6 @@ static av_cold int png_dec_init(AVCodecContext > *avctx) > > avctx->color_range = AVCOL_RANGE_JPEG; > > - if (avctx->codec_id == AV_CODEC_ID_LSCR) > - avctx->pix_fmt = AV_PIX_FMT_BGR24; > - > s->avctx = avctx; > s->previous_picture.f = av_frame_alloc(); > s->last_picture.f = av_frame_alloc(); > @@ -1855,20 +1710,3 @@ AVCodec ff_png_decoder = { > FF_CODEC_CAP_ALLOCATE_PROGRESS, > }; > #endif > - > -#if CONFIG_LSCR_DECODER > -AVCodec ff_lscr_decoder = { > - .name = "lscr", > - .long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"), > - .type = AVMEDIA_TYPE_VIDEO, > - .id = AV_CODEC_ID_LSCR, > - .priv_data_size = sizeof(PNGDecContext), > - .init = png_dec_init, > - .close = png_dec_end, > - .decode = decode_frame_lscr, > - .flush = decode_flush, > - .capabilities = AV_CODEC_CAP_DR1 /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/, > - .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | > FF_CODEC_CAP_INIT_THREADSAFE | > - FF_CODEC_CAP_ALLOCATE_PROGRESS, > -}; > -#endif > -- > 2.28.0 > > _______________________________________________ > 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". _______________________________________________ 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".