2 * Copyright (c) 2019 Paul B Mahol
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/frame.h"
25 #include "libavutil/error.h"
26 #include "libavutil/log.h"
29 #include "bytestream.h"
36 typedef struct LSCRContext {
38 AVCodecContext *avctx;
40 AVFrame *last_picture;
46 unsigned int last_row_size;
58 static void handle_row(LSCRContext *s)
60 uint8_t *ptr, *last_row;
62 ptr = s->image_buf + s->image_linesize * s->y;
64 last_row = s->last_row;
66 last_row = ptr - s->image_linesize;
68 ff_png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1,
69 last_row, s->row_size, 3);
74 static int decode_idat(LSCRContext *s, int length)
77 s->zstream.avail_in = FFMIN(length, bytestream2_get_bytes_left(&s->gb));
78 s->zstream.next_in = s->gb.buffer;
79 bytestream2_skip(&s->gb, length);
81 /* decode one line if possible */
82 while (s->zstream.avail_in > 0) {
83 ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
84 if (ret != Z_OK && ret != Z_STREAM_END) {
85 av_log(s->avctx, AV_LOG_ERROR, "inflate returned error %d\n", ret);
86 return AVERROR_EXTERNAL;
88 if (s->zstream.avail_out == 0) {
89 if (s->y < s->cur_h) {
92 s->zstream.avail_out = s->crow_size;
93 s->zstream.next_out = s->crow_buf;
95 if (ret == Z_STREAM_END && s->zstream.avail_in > 0) {
96 av_log(s->avctx, AV_LOG_WARNING,
97 "%d undecompressed bytes left in buffer\n", s->zstream.avail_in);
104 static int decode_frame_lscr(AVCodecContext *avctx,
105 void *data, int *got_frame,
108 LSCRContext *const s = avctx->priv_data;
109 GetByteContext *gb = &s->gb;
110 AVFrame *frame = s->last_picture;
111 int ret, nb_blocks, offset = 0;
114 return AVERROR_INVALIDDATA;
115 if (avpkt->size == 2)
118 bytestream2_init(gb, avpkt->data, avpkt->size);
120 nb_blocks = bytestream2_get_le16(gb);
121 if (bytestream2_get_bytes_left(gb) < 2 + nb_blocks * (12 + 8))
122 return AVERROR_INVALIDDATA;
124 ret = ff_reget_buffer(avctx, frame,
125 nb_blocks ? 0 : FF_REGET_BUFFER_FLAG_READONLY);
129 for (int b = 0; b < nb_blocks; b++) {
130 int x, y, x2, y2, w, h, left;
131 uint32_t csize, size;
133 s->zstream.zalloc = ff_png_zalloc;
134 s->zstream.zfree = ff_png_zfree;
135 s->zstream.opaque = NULL;
137 if ((ret = inflateInit(&s->zstream)) != Z_OK) {
138 av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret);
139 ret = AVERROR_EXTERNAL;
143 bytestream2_seek(gb, 2 + b * 12, SEEK_SET);
145 x = bytestream2_get_le16(gb);
146 y = bytestream2_get_le16(gb);
147 x2 = bytestream2_get_le16(gb);
148 y2 = bytestream2_get_le16(gb);
152 if (w <= 0 || x < 0 || x >= avctx->width || w + x > avctx->width ||
153 h <= 0 || y < 0 || y >= avctx->height || h + y > avctx->height) {
154 ret = AVERROR_INVALIDDATA;
158 size = bytestream2_get_le32(gb);
160 frame->key_frame = (nb_blocks == 1) &&
161 (w == avctx->width) &&
162 (h == avctx->height) &&
163 (x == 0) && (y == 0);
165 bytestream2_seek(gb, 2 + nb_blocks * 12 + offset, SEEK_SET);
166 csize = bytestream2_get_be32(gb);
167 if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) {
168 ret = AVERROR_INVALIDDATA;
178 av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16);
180 ret = AVERROR(ENOMEM);
184 av_fast_padded_malloc(&s->last_row, &s->last_row_size, s->row_size);
186 ret = AVERROR(ENOMEM);
190 s->crow_size = w * 3 + 1;
191 s->crow_buf = s->buffer + 15;
192 s->zstream.avail_out = s->crow_size;
193 s->zstream.next_out = s->crow_buf;
194 s->image_buf = frame->data[0] + (avctx->height - y - 1) * frame->linesize[0] + x * 3;
195 s->image_linesize =-frame->linesize[0];
198 ret = decode_idat(s, csize);
203 bytestream2_skip(gb, 4);
204 csize = bytestream2_get_be32(gb);
205 if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) {
206 ret = AVERROR_INVALIDDATA;
212 inflateEnd(&s->zstream);
215 frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
217 if ((ret = av_frame_ref(data, frame)) < 0)
222 inflateEnd(&s->zstream);
229 static int lscr_decode_close(AVCodecContext *avctx)
231 LSCRContext *s = avctx->priv_data;
233 av_frame_free(&s->last_picture);
234 av_freep(&s->buffer);
235 av_freep(&s->last_row);
240 static int lscr_decode_init(AVCodecContext *avctx)
242 LSCRContext *s = avctx->priv_data;
244 avctx->color_range = AVCOL_RANGE_JPEG;
245 avctx->pix_fmt = AV_PIX_FMT_BGR24;
248 s->last_picture = av_frame_alloc();
249 if (!s->last_picture)
250 return AVERROR(ENOMEM);
252 ff_pngdsp_init(&s->dsp);
257 static void lscr_decode_flush(AVCodecContext *avctx)
259 LSCRContext *s = avctx->priv_data;
260 av_frame_unref(s->last_picture);
263 AVCodec ff_lscr_decoder = {
265 .long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"),
266 .type = AVMEDIA_TYPE_VIDEO,
267 .id = AV_CODEC_ID_LSCR,
268 .priv_data_size = sizeof(LSCRContext),
269 .init = lscr_decode_init,
270 .close = lscr_decode_close,
271 .decode = decode_frame_lscr,
272 .flush = lscr_decode_flush,
273 .capabilities = AV_CODEC_CAP_DR1,
274 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,