/src/ffmpeg/libavcodec/lscrdec.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2019 Paul B Mahol |
3 | | * |
4 | | * This file is part of FFmpeg. |
5 | | * |
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. |
10 | | * |
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. |
15 | | * |
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 |
19 | | */ |
20 | | |
21 | | #include <stdint.h> |
22 | | #include <zlib.h> |
23 | | |
24 | | #include "libavutil/frame.h" |
25 | | #include "libavutil/error.h" |
26 | | #include "libavutil/log.h" |
27 | | #include "libavutil/mem.h" |
28 | | |
29 | | #include "avcodec.h" |
30 | | #include "bytestream.h" |
31 | | #include "codec.h" |
32 | | #include "codec_internal.h" |
33 | | #include "decode.h" |
34 | | #include "packet.h" |
35 | | #include "png.h" |
36 | | #include "pngdsp.h" |
37 | | #include "zlib_wrapper.h" |
38 | | |
39 | | typedef struct LSCRContext { |
40 | | PNGDSPContext dsp; |
41 | | AVCodecContext *avctx; |
42 | | |
43 | | AVFrame *last_picture; |
44 | | uint8_t *buffer; |
45 | | int buffer_size; |
46 | | uint8_t *crow_buf; |
47 | | int crow_size; |
48 | | uint8_t *last_row; |
49 | | unsigned int last_row_size; |
50 | | |
51 | | GetByteContext gb; |
52 | | uint8_t *image_buf; |
53 | | int image_linesize; |
54 | | int row_size; |
55 | | int cur_h; |
56 | | int y; |
57 | | |
58 | | FFZStream zstream; |
59 | | } LSCRContext; |
60 | | |
61 | | static void handle_row(LSCRContext *s) |
62 | 113k | { |
63 | 113k | uint8_t *ptr, *last_row; |
64 | | |
65 | 113k | ptr = s->image_buf + s->image_linesize * s->y; |
66 | 113k | if (s->y == 0) |
67 | 4.26k | last_row = s->last_row; |
68 | 109k | else |
69 | 109k | last_row = ptr - s->image_linesize; |
70 | | |
71 | 113k | ff_png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1, |
72 | 113k | last_row, s->row_size, 3); |
73 | | |
74 | 113k | s->y++; |
75 | 113k | } |
76 | | |
77 | | static int decode_idat(LSCRContext *s, z_stream *zstream, int length) |
78 | 25.6k | { |
79 | 25.6k | int ret; |
80 | 25.6k | zstream->avail_in = FFMIN(length, bytestream2_get_bytes_left(&s->gb)); |
81 | 25.6k | zstream->next_in = s->gb.buffer; |
82 | | |
83 | 25.6k | if (length <= 0) |
84 | 294 | return AVERROR_INVALIDDATA; |
85 | | |
86 | 25.3k | bytestream2_skip(&s->gb, length); |
87 | | |
88 | | /* decode one line if possible */ |
89 | 2.99M | while (zstream->avail_in > 0) { |
90 | 2.98M | ret = inflate(zstream, Z_PARTIAL_FLUSH); |
91 | 2.98M | if (ret != Z_OK && ret != Z_STREAM_END) { |
92 | 13.6k | av_log(s->avctx, AV_LOG_ERROR, "inflate returned error %d\n", ret); |
93 | 13.6k | return AVERROR_EXTERNAL; |
94 | 13.6k | } |
95 | 2.97M | if (zstream->avail_out == 0) { |
96 | 2.96M | if (s->y < s->cur_h) { |
97 | 113k | handle_row(s); |
98 | 113k | } |
99 | 2.96M | zstream->avail_out = s->crow_size; |
100 | 2.96M | zstream->next_out = s->crow_buf; |
101 | 2.96M | } |
102 | 2.97M | if (ret == Z_STREAM_END && zstream->avail_in > 0) { |
103 | 944 | av_log(s->avctx, AV_LOG_WARNING, |
104 | 944 | "%d undecompressed bytes left in buffer\n", zstream->avail_in); |
105 | 944 | return 0; |
106 | 944 | } |
107 | 2.97M | } |
108 | 10.6k | return 0; |
109 | 25.3k | } |
110 | | |
111 | | static int decode_frame_lscr(AVCodecContext *avctx, AVFrame *rframe, |
112 | | int *got_frame, AVPacket *avpkt) |
113 | 171k | { |
114 | 171k | LSCRContext *const s = avctx->priv_data; |
115 | 171k | GetByteContext *gb = &s->gb; |
116 | 171k | AVFrame *frame = s->last_picture; |
117 | 171k | int ret, nb_blocks, offset = 0; |
118 | | |
119 | 171k | if (avpkt->size < 2) |
120 | 15.8k | return AVERROR_INVALIDDATA; |
121 | 155k | if (avpkt->size == 2) |
122 | 99.1k | return 0; |
123 | | |
124 | 56.2k | bytestream2_init(gb, avpkt->data, avpkt->size); |
125 | | |
126 | 56.2k | nb_blocks = bytestream2_get_le16(gb); |
127 | 56.2k | if (bytestream2_get_bytes_left(gb) < 2 + nb_blocks * (12 + 8)) |
128 | 18.3k | return AVERROR_INVALIDDATA; |
129 | | |
130 | 37.9k | ret = ff_reget_buffer(avctx, frame, |
131 | 37.9k | nb_blocks ? 0 : FF_REGET_BUFFER_FLAG_READONLY); |
132 | 37.9k | if (ret < 0) |
133 | 1.95k | return ret; |
134 | | |
135 | 43.2k | for (int b = 0; b < nb_blocks; b++) { |
136 | 37.2k | z_stream *const zstream = &s->zstream.zstream; |
137 | 37.2k | int x, y, x2, y2, w, h, left; |
138 | 37.2k | uint32_t csize, size; |
139 | | |
140 | 37.2k | if (inflateReset(zstream) != Z_OK) |
141 | 0 | return AVERROR_EXTERNAL; |
142 | | |
143 | 37.2k | bytestream2_seek(gb, 2 + b * 12, SEEK_SET); |
144 | | |
145 | 37.2k | x = bytestream2_get_le16(gb); |
146 | 37.2k | y = bytestream2_get_le16(gb); |
147 | 37.2k | x2 = bytestream2_get_le16(gb); |
148 | 37.2k | y2 = bytestream2_get_le16(gb); |
149 | 37.2k | w = x2-x; |
150 | 37.2k | s->cur_h = h = y2-y; |
151 | | |
152 | 37.2k | if (w <= 0 || x < 0 || x >= avctx->width || w + x > avctx->width || |
153 | 31.1k | h <= 0 || y < 0 || y >= avctx->height || h + y > avctx->height) |
154 | 8.85k | return AVERROR_INVALIDDATA; |
155 | | |
156 | 28.3k | size = bytestream2_get_le32(gb); |
157 | | |
158 | 28.3k | if ((nb_blocks == 1) && |
159 | 1.86k | (w == avctx->width) && |
160 | 412 | (h == avctx->height) && |
161 | 204 | (x == 0) && (y == 0)) |
162 | 204 | frame->flags |= AV_FRAME_FLAG_KEY; |
163 | 28.1k | else |
164 | 28.1k | frame->flags &= ~AV_FRAME_FLAG_KEY; |
165 | | |
166 | 28.3k | bytestream2_seek(gb, 2 + nb_blocks * 12 + offset, SEEK_SET); |
167 | 28.3k | csize = bytestream2_get_be32(gb); |
168 | 28.3k | if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) |
169 | 4.77k | return AVERROR_INVALIDDATA; |
170 | | |
171 | 23.6k | offset += size; |
172 | 23.6k | left = size; |
173 | | |
174 | 23.6k | s->y = 0; |
175 | 23.6k | s->row_size = w * 3; |
176 | | |
177 | 23.6k | av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16); |
178 | 23.6k | if (!s->buffer) |
179 | 0 | return AVERROR(ENOMEM); |
180 | | |
181 | 23.6k | av_fast_padded_malloc(&s->last_row, &s->last_row_size, s->row_size); |
182 | 23.6k | if (!s->last_row) |
183 | 0 | return AVERROR(ENOMEM); |
184 | | |
185 | 23.6k | s->crow_size = w * 3 + 1; |
186 | 23.6k | s->crow_buf = s->buffer + 15; |
187 | 23.6k | zstream->avail_out = s->crow_size; |
188 | 23.6k | zstream->next_out = s->crow_buf; |
189 | 23.6k | s->image_buf = frame->data[0] + (avctx->height - y - 1) * frame->linesize[0] + x * 3; |
190 | 23.6k | s->image_linesize =-frame->linesize[0]; |
191 | | |
192 | 32.8k | while (left > 16) { |
193 | 25.6k | ret = decode_idat(s, zstream, csize); |
194 | 25.6k | if (ret < 0) |
195 | 13.9k | return ret; |
196 | 11.6k | left -= csize + 16; |
197 | 11.6k | if (left > 16) { |
198 | 6.19k | bytestream2_skip(gb, 4); |
199 | 6.19k | csize = bytestream2_get_be32(gb); |
200 | 6.19k | if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) |
201 | 2.33k | return AVERROR_INVALIDDATA; |
202 | 6.19k | } |
203 | 11.6k | } |
204 | 23.6k | } |
205 | | |
206 | 6.05k | frame->pict_type = (frame->flags & AV_FRAME_FLAG_KEY) ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; |
207 | | |
208 | 6.05k | if ((ret = av_frame_ref(rframe, frame)) < 0) |
209 | 0 | return ret; |
210 | | |
211 | 6.05k | *got_frame = 1; |
212 | | |
213 | 6.05k | return avpkt->size; |
214 | 6.05k | } |
215 | | |
216 | | static av_cold int lscr_decode_close(AVCodecContext *avctx) |
217 | 1.90k | { |
218 | 1.90k | LSCRContext *s = avctx->priv_data; |
219 | | |
220 | 1.90k | av_frame_free(&s->last_picture); |
221 | 1.90k | av_freep(&s->buffer); |
222 | 1.90k | av_freep(&s->last_row); |
223 | 1.90k | ff_inflate_end(&s->zstream); |
224 | | |
225 | 1.90k | return 0; |
226 | 1.90k | } |
227 | | |
228 | | static av_cold int lscr_decode_init(AVCodecContext *avctx) |
229 | 1.90k | { |
230 | 1.90k | LSCRContext *s = avctx->priv_data; |
231 | | |
232 | 1.90k | avctx->color_range = AVCOL_RANGE_JPEG; |
233 | 1.90k | avctx->pix_fmt = AV_PIX_FMT_BGR24; |
234 | | |
235 | 1.90k | s->avctx = avctx; |
236 | 1.90k | s->last_picture = av_frame_alloc(); |
237 | 1.90k | if (!s->last_picture) |
238 | 0 | return AVERROR(ENOMEM); |
239 | | |
240 | 1.90k | ff_pngdsp_init(&s->dsp); |
241 | | |
242 | 1.90k | return ff_inflate_init(&s->zstream, avctx); |
243 | 1.90k | } |
244 | | |
245 | | static av_cold void lscr_decode_flush(AVCodecContext *avctx) |
246 | 45.1k | { |
247 | 45.1k | LSCRContext *s = avctx->priv_data; |
248 | 45.1k | av_frame_unref(s->last_picture); |
249 | 45.1k | } |
250 | | |
251 | | const FFCodec ff_lscr_decoder = { |
252 | | .p.name = "lscr", |
253 | | CODEC_LONG_NAME("LEAD Screen Capture"), |
254 | | .p.type = AVMEDIA_TYPE_VIDEO, |
255 | | .p.id = AV_CODEC_ID_LSCR, |
256 | | .p.capabilities = AV_CODEC_CAP_DR1, |
257 | | .priv_data_size = sizeof(LSCRContext), |
258 | | .init = lscr_decode_init, |
259 | | .close = lscr_decode_close, |
260 | | FF_CODEC_DECODE_CB(decode_frame_lscr), |
261 | | .flush = lscr_decode_flush, |
262 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
263 | | }; |