blob: f45d019a79200f2440f961529f12beb1c1d892f6
1 | /* |
2 | * Chronomaster DFA Video Decoder |
3 | * Copyright (c) 2011 Konstantin Shishkov |
4 | * based on work by Vladimir "VAG" Gneushev |
5 | * |
6 | * This file is part of FFmpeg. |
7 | * |
8 | * FFmpeg is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2.1 of the License, or (at your option) any later version. |
12 | * |
13 | * FFmpeg is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with FFmpeg; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | */ |
22 | |
23 | #include <inttypes.h> |
24 | |
25 | #include "avcodec.h" |
26 | #include "bytestream.h" |
27 | #include "internal.h" |
28 | |
29 | #include "libavutil/avassert.h" |
30 | #include "libavutil/imgutils.h" |
31 | #include "libavutil/mem.h" |
32 | |
33 | typedef struct DfaContext { |
34 | uint32_t pal[256]; |
35 | uint8_t *frame_buf; |
36 | } DfaContext; |
37 | |
38 | static av_cold int dfa_decode_init(AVCodecContext *avctx) |
39 | { |
40 | DfaContext *s = avctx->priv_data; |
41 | |
42 | avctx->pix_fmt = AV_PIX_FMT_PAL8; |
43 | |
44 | if (!avctx->width || !avctx->height) |
45 | return AVERROR_INVALIDDATA; |
46 | |
47 | av_assert0(av_image_check_size(avctx->width, avctx->height, 0, avctx) >= 0); |
48 | |
49 | s->frame_buf = av_mallocz(avctx->width * avctx->height); |
50 | if (!s->frame_buf) |
51 | return AVERROR(ENOMEM); |
52 | |
53 | return 0; |
54 | } |
55 | |
56 | static int decode_copy(GetByteContext *gb, uint8_t *frame, int width, int height) |
57 | { |
58 | const int size = width * height; |
59 | |
60 | if (bytestream2_get_buffer(gb, frame, size) != size) |
61 | return AVERROR_INVALIDDATA; |
62 | return 0; |
63 | } |
64 | |
65 | static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height) |
66 | { |
67 | const uint8_t *frame_start = frame; |
68 | const uint8_t *frame_end = frame + width * height; |
69 | int mask = 0x10000, bitbuf = 0; |
70 | int v, count, segments; |
71 | unsigned offset; |
72 | |
73 | segments = bytestream2_get_le32(gb); |
74 | offset = bytestream2_get_le32(gb); |
75 | if (segments == 0 && offset == frame_end - frame) |
76 | return 0; // skip frame |
77 | if (frame_end - frame <= offset) |
78 | return AVERROR_INVALIDDATA; |
79 | frame += offset; |
80 | while (segments--) { |
81 | if (bytestream2_get_bytes_left(gb) < 2) |
82 | return AVERROR_INVALIDDATA; |
83 | if (mask == 0x10000) { |
84 | bitbuf = bytestream2_get_le16u(gb); |
85 | mask = 1; |
86 | } |
87 | if (frame_end - frame < 2) |
88 | return AVERROR_INVALIDDATA; |
89 | if (bitbuf & mask) { |
90 | v = bytestream2_get_le16(gb); |
91 | offset = (v & 0x1FFF) << 1; |
92 | count = ((v >> 13) + 2) << 1; |
93 | if (frame - frame_start < offset || frame_end - frame < count) |
94 | return AVERROR_INVALIDDATA; |
95 | av_memcpy_backptr(frame, offset, count); |
96 | frame += count; |
97 | } else { |
98 | *frame++ = bytestream2_get_byte(gb); |
99 | *frame++ = bytestream2_get_byte(gb); |
100 | } |
101 | mask <<= 1; |
102 | } |
103 | |
104 | return 0; |
105 | } |
106 | |
107 | static int decode_dsw1(GetByteContext *gb, uint8_t *frame, int width, int height) |
108 | { |
109 | const uint8_t *frame_start = frame; |
110 | const uint8_t *frame_end = frame + width * height; |
111 | int mask = 0x10000, bitbuf = 0; |
112 | int v, offset, count, segments; |
113 | |
114 | segments = bytestream2_get_le16(gb); |
115 | while (segments--) { |
116 | if (bytestream2_get_bytes_left(gb) < 2) |
117 | return AVERROR_INVALIDDATA; |
118 | if (mask == 0x10000) { |
119 | bitbuf = bytestream2_get_le16u(gb); |
120 | mask = 1; |
121 | } |
122 | if (frame_end - frame < 2) |
123 | return AVERROR_INVALIDDATA; |
124 | if (bitbuf & mask) { |
125 | v = bytestream2_get_le16(gb); |
126 | offset = (v & 0x1FFF) << 1; |
127 | count = ((v >> 13) + 2) << 1; |
128 | if (frame - frame_start < offset || frame_end - frame < count) |
129 | return AVERROR_INVALIDDATA; |
130 | av_memcpy_backptr(frame, offset, count); |
131 | frame += count; |
132 | } else if (bitbuf & (mask << 1)) { |
133 | frame += bytestream2_get_le16(gb); |
134 | } else { |
135 | *frame++ = bytestream2_get_byte(gb); |
136 | *frame++ = bytestream2_get_byte(gb); |
137 | } |
138 | mask <<= 2; |
139 | } |
140 | |
141 | return 0; |
142 | } |
143 | |
144 | static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height) |
145 | { |
146 | const uint8_t *frame_start = frame; |
147 | const uint8_t *frame_end = frame + width * height; |
148 | int mask = 0x10000, bitbuf = 0; |
149 | int i, v, offset, count, segments; |
150 | |
151 | segments = bytestream2_get_le16(gb); |
152 | while (segments--) { |
153 | if (bytestream2_get_bytes_left(gb) < 2) |
154 | return AVERROR_INVALIDDATA; |
155 | if (mask == 0x10000) { |
156 | bitbuf = bytestream2_get_le16u(gb); |
157 | mask = 1; |
158 | } |
159 | |
160 | if (bitbuf & mask) { |
161 | v = bytestream2_get_le16(gb); |
162 | offset = (v & 0x1FFF) << 2; |
163 | count = ((v >> 13) + 2) << 1; |
164 | if (frame - frame_start < offset || frame_end - frame < count*2 + width) |
165 | return AVERROR_INVALIDDATA; |
166 | for (i = 0; i < count; i++) { |
167 | frame[0] = frame[1] = |
168 | frame[width] = frame[width + 1] = frame[-offset]; |
169 | |
170 | frame += 2; |
171 | } |
172 | } else if (bitbuf & (mask << 1)) { |
173 | v = bytestream2_get_le16(gb)*2; |
174 | if (frame - frame_end < v) |
175 | return AVERROR_INVALIDDATA; |
176 | frame += v; |
177 | } else { |
178 | if (frame_end - frame < width + 3) |
179 | return AVERROR_INVALIDDATA; |
180 | frame[0] = frame[1] = |
181 | frame[width] = frame[width + 1] = bytestream2_get_byte(gb); |
182 | frame += 2; |
183 | frame[0] = frame[1] = |
184 | frame[width] = frame[width + 1] = bytestream2_get_byte(gb); |
185 | frame += 2; |
186 | } |
187 | mask <<= 2; |
188 | } |
189 | |
190 | return 0; |
191 | } |
192 | |
193 | static int decode_bdlt(GetByteContext *gb, uint8_t *frame, int width, int height) |
194 | { |
195 | uint8_t *line_ptr; |
196 | int count, lines, segments; |
197 | |
198 | count = bytestream2_get_le16(gb); |
199 | if (count >= height) |
200 | return AVERROR_INVALIDDATA; |
201 | frame += width * count; |
202 | lines = bytestream2_get_le16(gb); |
203 | if (count + lines > height) |
204 | return AVERROR_INVALIDDATA; |
205 | |
206 | while (lines--) { |
207 | if (bytestream2_get_bytes_left(gb) < 1) |
208 | return AVERROR_INVALIDDATA; |
209 | line_ptr = frame; |
210 | frame += width; |
211 | segments = bytestream2_get_byteu(gb); |
212 | while (segments--) { |
213 | if (frame - line_ptr <= bytestream2_peek_byte(gb)) |
214 | return AVERROR_INVALIDDATA; |
215 | line_ptr += bytestream2_get_byte(gb); |
216 | count = (int8_t)bytestream2_get_byte(gb); |
217 | if (count >= 0) { |
218 | if (frame - line_ptr < count) |
219 | return AVERROR_INVALIDDATA; |
220 | if (bytestream2_get_buffer(gb, line_ptr, count) != count) |
221 | return AVERROR_INVALIDDATA; |
222 | } else { |
223 | count = -count; |
224 | if (frame - line_ptr < count) |
225 | return AVERROR_INVALIDDATA; |
226 | memset(line_ptr, bytestream2_get_byte(gb), count); |
227 | } |
228 | line_ptr += count; |
229 | } |
230 | } |
231 | |
232 | return 0; |
233 | } |
234 | |
235 | static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height) |
236 | { |
237 | const uint8_t *frame_end = frame + width * height; |
238 | uint8_t *line_ptr; |
239 | int count, i, v, lines, segments; |
240 | int y = 0; |
241 | |
242 | lines = bytestream2_get_le16(gb); |
243 | if (lines > height) |
244 | return AVERROR_INVALIDDATA; |
245 | |
246 | while (lines--) { |
247 | if (bytestream2_get_bytes_left(gb) < 2) |
248 | return AVERROR_INVALIDDATA; |
249 | segments = bytestream2_get_le16u(gb); |
250 | while ((segments & 0xC000) == 0xC000) { |
251 | unsigned skip_lines = -(int16_t)segments; |
252 | unsigned delta = -((int16_t)segments * width); |
253 | if (frame_end - frame <= delta || y + lines + skip_lines > height) |
254 | return AVERROR_INVALIDDATA; |
255 | frame += delta; |
256 | y += skip_lines; |
257 | segments = bytestream2_get_le16(gb); |
258 | } |
259 | |
260 | if (frame_end <= frame) |
261 | return AVERROR_INVALIDDATA; |
262 | if (segments & 0x8000) { |
263 | frame[width - 1] = segments & 0xFF; |
264 | segments = bytestream2_get_le16(gb); |
265 | } |
266 | line_ptr = frame; |
267 | if (frame_end - frame < width) |
268 | return AVERROR_INVALIDDATA; |
269 | frame += width; |
270 | y++; |
271 | while (segments--) { |
272 | if (frame - line_ptr <= bytestream2_peek_byte(gb)) |
273 | return AVERROR_INVALIDDATA; |
274 | line_ptr += bytestream2_get_byte(gb); |
275 | count = (int8_t)bytestream2_get_byte(gb); |
276 | if (count >= 0) { |
277 | if (frame - line_ptr < count * 2) |
278 | return AVERROR_INVALIDDATA; |
279 | if (bytestream2_get_buffer(gb, line_ptr, count * 2) != count * 2) |
280 | return AVERROR_INVALIDDATA; |
281 | line_ptr += count * 2; |
282 | } else { |
283 | count = -count; |
284 | if (frame - line_ptr < count * 2) |
285 | return AVERROR_INVALIDDATA; |
286 | v = bytestream2_get_le16(gb); |
287 | for (i = 0; i < count; i++) |
288 | bytestream_put_le16(&line_ptr, v); |
289 | } |
290 | } |
291 | } |
292 | |
293 | return 0; |
294 | } |
295 | |
296 | static int decode_tdlt(GetByteContext *gb, uint8_t *frame, int width, int height) |
297 | { |
298 | const uint8_t *frame_end = frame + width * height; |
299 | uint32_t segments = bytestream2_get_le32(gb); |
300 | int skip, copy; |
301 | |
302 | while (segments--) { |
303 | if (bytestream2_get_bytes_left(gb) < 2) |
304 | return AVERROR_INVALIDDATA; |
305 | copy = bytestream2_get_byteu(gb) * 2; |
306 | skip = bytestream2_get_byteu(gb) * 2; |
307 | if (frame_end - frame < copy + skip || |
308 | bytestream2_get_bytes_left(gb) < copy) |
309 | return AVERROR_INVALIDDATA; |
310 | frame += skip; |
311 | bytestream2_get_buffer(gb, frame, copy); |
312 | frame += copy; |
313 | } |
314 | |
315 | return 0; |
316 | } |
317 | |
318 | static int decode_blck(GetByteContext *gb, uint8_t *frame, int width, int height) |
319 | { |
320 | memset(frame, 0, width * height); |
321 | return 0; |
322 | } |
323 | |
324 | |
325 | typedef int (*chunk_decoder)(GetByteContext *gb, uint8_t *frame, int width, int height); |
326 | |
327 | static const chunk_decoder decoder[8] = { |
328 | decode_copy, decode_tsw1, decode_bdlt, decode_wdlt, |
329 | decode_tdlt, decode_dsw1, decode_blck, decode_dds1, |
330 | }; |
331 | |
332 | static const char* chunk_name[8] = { |
333 | "COPY", "TSW1", "BDLT", "WDLT", "TDLT", "DSW1", "BLCK", "DDS1" |
334 | }; |
335 | |
336 | static int dfa_decode_frame(AVCodecContext *avctx, |
337 | void *data, int *got_frame, |
338 | AVPacket *avpkt) |
339 | { |
340 | AVFrame *frame = data; |
341 | DfaContext *s = avctx->priv_data; |
342 | GetByteContext gb; |
343 | const uint8_t *buf = avpkt->data; |
344 | uint32_t chunk_type, chunk_size; |
345 | uint8_t *dst; |
346 | int ret; |
347 | int i, pal_elems; |
348 | int version = avctx->extradata_size==2 ? AV_RL16(avctx->extradata) : 0; |
349 | |
350 | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
351 | return ret; |
352 | |
353 | bytestream2_init(&gb, avpkt->data, avpkt->size); |
354 | while (bytestream2_get_bytes_left(&gb) > 0) { |
355 | bytestream2_skip(&gb, 4); |
356 | chunk_size = bytestream2_get_le32(&gb); |
357 | chunk_type = bytestream2_get_le32(&gb); |
358 | if (!chunk_type) |
359 | break; |
360 | if (chunk_type == 1) { |
361 | pal_elems = FFMIN(chunk_size / 3, 256); |
362 | for (i = 0; i < pal_elems; i++) { |
363 | s->pal[i] = bytestream2_get_be24(&gb) << 2; |
364 | s->pal[i] |= 0xFFU << 24 | (s->pal[i] >> 6) & 0x30303; |
365 | } |
366 | frame->palette_has_changed = 1; |
367 | } else if (chunk_type <= 9) { |
368 | if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) { |
369 | av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n", |
370 | chunk_name[chunk_type - 2]); |
371 | return AVERROR_INVALIDDATA; |
372 | } |
373 | } else { |
374 | av_log(avctx, AV_LOG_WARNING, |
375 | "Ignoring unknown chunk type %"PRIu32"\n", |
376 | chunk_type); |
377 | } |
378 | buf += chunk_size; |
379 | } |
380 | |
381 | buf = s->frame_buf; |
382 | dst = frame->data[0]; |
383 | for (i = 0; i < avctx->height; i++) { |
384 | if(version == 0x100) { |
385 | int j; |
386 | for(j = 0; j < avctx->width; j++) { |
387 | dst[j] = buf[ (i&3)*(avctx->width /4) + (j/4) + |
388 | ((j&3)*(avctx->height/4) + (i/4))*avctx->width]; |
389 | } |
390 | } else { |
391 | memcpy(dst, buf, avctx->width); |
392 | buf += avctx->width; |
393 | } |
394 | dst += frame->linesize[0]; |
395 | } |
396 | memcpy(frame->data[1], s->pal, sizeof(s->pal)); |
397 | |
398 | *got_frame = 1; |
399 | |
400 | return avpkt->size; |
401 | } |
402 | |
403 | static av_cold int dfa_decode_end(AVCodecContext *avctx) |
404 | { |
405 | DfaContext *s = avctx->priv_data; |
406 | |
407 | av_freep(&s->frame_buf); |
408 | |
409 | return 0; |
410 | } |
411 | |
412 | AVCodec ff_dfa_decoder = { |
413 | .name = "dfa", |
414 | .long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), |
415 | .type = AVMEDIA_TYPE_VIDEO, |
416 | .id = AV_CODEC_ID_DFA, |
417 | .priv_data_size = sizeof(DfaContext), |
418 | .init = dfa_decode_init, |
419 | .close = dfa_decode_end, |
420 | .decode = dfa_decode_frame, |
421 | .capabilities = AV_CODEC_CAP_DR1, |
422 | }; |
423 |