• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "codec_internal.h"
28 #include "internal.h"
29 
30 #include "libavutil/avassert.h"
31 #include "libavutil/imgutils.h"
32 #include "libavutil/mem.h"
33 
34 typedef struct DfaContext {
35     uint32_t pal[256];
36     uint8_t *frame_buf;
37 } DfaContext;
38 
dfa_decode_init(AVCodecContext * avctx)39 static av_cold int dfa_decode_init(AVCodecContext *avctx)
40 {
41     DfaContext *s = avctx->priv_data;
42 
43     avctx->pix_fmt = AV_PIX_FMT_PAL8;
44 
45     if (!avctx->width || !avctx->height || FFMAX(avctx->width, avctx->height) >= (1<<16))
46         return AVERROR_INVALIDDATA;
47 
48     av_assert0(av_image_check_size(avctx->width, avctx->height, 0, avctx) >= 0);
49 
50     s->frame_buf = av_mallocz(avctx->width * avctx->height);
51     if (!s->frame_buf)
52         return AVERROR(ENOMEM);
53 
54     return 0;
55 }
56 
decode_copy(GetByteContext * gb,uint8_t * frame,int width,int height)57 static int decode_copy(GetByteContext *gb, uint8_t *frame, int width, int height)
58 {
59     const int size = width * height;
60 
61     if (bytestream2_get_buffer(gb, frame, size) != size)
62         return AVERROR_INVALIDDATA;
63     return 0;
64 }
65 
decode_tsw1(GetByteContext * gb,uint8_t * frame,int width,int height)66 static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height)
67 {
68     const uint8_t *frame_start = frame;
69     const uint8_t *frame_end   = frame + width * height;
70     int mask = 0x10000, bitbuf = 0;
71     int v, count;
72     unsigned segments;
73     unsigned offset;
74 
75     segments = bytestream2_get_le32(gb);
76     offset   = bytestream2_get_le32(gb);
77     if (segments == 0 && offset == frame_end - frame)
78         return 0; // skip frame
79     if (frame_end - frame <= offset)
80         return AVERROR_INVALIDDATA;
81     frame += offset;
82     while (segments--) {
83         if (bytestream2_get_bytes_left(gb) < 2)
84             return AVERROR_INVALIDDATA;
85         if (mask == 0x10000) {
86             bitbuf = bytestream2_get_le16u(gb);
87             mask = 1;
88         }
89         if (frame_end - frame < 2)
90             return AVERROR_INVALIDDATA;
91         if (bitbuf & mask) {
92             v = bytestream2_get_le16(gb);
93             offset = (v & 0x1FFF) << 1;
94             count = ((v >> 13) + 2) << 1;
95             if (frame - frame_start < offset || frame_end - frame < count)
96                 return AVERROR_INVALIDDATA;
97             av_memcpy_backptr(frame, offset, count);
98             frame += count;
99         } else {
100             *frame++ = bytestream2_get_byte(gb);
101             *frame++ = bytestream2_get_byte(gb);
102         }
103         mask <<= 1;
104     }
105 
106     return 0;
107 }
108 
decode_dsw1(GetByteContext * gb,uint8_t * frame,int width,int height)109 static int decode_dsw1(GetByteContext *gb, uint8_t *frame, int width, int height)
110 {
111     const uint8_t *frame_start = frame;
112     const uint8_t *frame_end   = frame + width * height;
113     int mask = 0x10000, bitbuf = 0;
114     int v, offset, count, segments;
115 
116     segments = bytestream2_get_le16(gb);
117     while (segments--) {
118         if (bytestream2_get_bytes_left(gb) < 2)
119             return AVERROR_INVALIDDATA;
120         if (mask == 0x10000) {
121             bitbuf = bytestream2_get_le16u(gb);
122             mask = 1;
123         }
124         if (frame_end - frame < 2)
125             return AVERROR_INVALIDDATA;
126         if (bitbuf & mask) {
127             v = bytestream2_get_le16(gb);
128             offset = (v & 0x1FFF) << 1;
129             count = ((v >> 13) + 2) << 1;
130             if (frame - frame_start < offset || frame_end - frame < count)
131                 return AVERROR_INVALIDDATA;
132             av_memcpy_backptr(frame, offset, count);
133             frame += count;
134         } else if (bitbuf & (mask << 1)) {
135             frame += bytestream2_get_le16(gb);
136         } else {
137             *frame++ = bytestream2_get_byte(gb);
138             *frame++ = bytestream2_get_byte(gb);
139         }
140         mask <<= 2;
141     }
142 
143     return 0;
144 }
145 
decode_dds1(GetByteContext * gb,uint8_t * frame,int width,int height)146 static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height)
147 {
148     const uint8_t *frame_start = frame;
149     const uint8_t *frame_end   = frame + width * height;
150     int mask = 0x10000, bitbuf = 0;
151     int i, v, offset, count, segments;
152 
153     if ((width | height) & 1)
154         return AVERROR_INVALIDDATA;
155     segments = bytestream2_get_le16(gb);
156     while (segments--) {
157         if (bytestream2_get_bytes_left(gb) < 2)
158             return AVERROR_INVALIDDATA;
159         if (mask == 0x10000) {
160             bitbuf = bytestream2_get_le16u(gb);
161             mask = 1;
162         }
163 
164         if (bitbuf & mask) {
165             v = bytestream2_get_le16(gb);
166             offset = (v & 0x1FFF) << 2;
167             count = ((v >> 13) + 2) << 1;
168             if (frame - frame_start < offset || frame_end - frame < count*2 + width)
169                 return AVERROR_INVALIDDATA;
170             for (i = 0; i < count; i++) {
171                 frame[0] = frame[1] =
172                 frame[width] = frame[width + 1] = frame[-offset];
173 
174                 frame += 2;
175             }
176         } else if (bitbuf & (mask << 1)) {
177             v = bytestream2_get_le16(gb)*2;
178             if (frame - frame_end < v)
179                 return AVERROR_INVALIDDATA;
180             frame += v;
181         } else {
182             if (width < 4 || frame_end - frame < width + 4)
183                 return AVERROR_INVALIDDATA;
184             frame[0] = frame[1] =
185             frame[width] = frame[width + 1] =  bytestream2_get_byte(gb);
186             frame += 2;
187             frame[0] = frame[1] =
188             frame[width] = frame[width + 1] =  bytestream2_get_byte(gb);
189             frame += 2;
190         }
191         mask <<= 2;
192     }
193 
194     return 0;
195 }
196 
decode_bdlt(GetByteContext * gb,uint8_t * frame,int width,int height)197 static int decode_bdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
198 {
199     uint8_t *line_ptr;
200     int count, lines, segments;
201 
202     count = bytestream2_get_le16(gb);
203     if (count >= height)
204         return AVERROR_INVALIDDATA;
205     frame += width * count;
206     lines = bytestream2_get_le16(gb);
207     if (count + lines > height)
208         return AVERROR_INVALIDDATA;
209 
210     while (lines--) {
211         if (bytestream2_get_bytes_left(gb) < 1)
212             return AVERROR_INVALIDDATA;
213         line_ptr = frame;
214         frame += width;
215         segments = bytestream2_get_byteu(gb);
216         while (segments--) {
217             if (frame - line_ptr <= bytestream2_peek_byte(gb))
218                 return AVERROR_INVALIDDATA;
219             line_ptr += bytestream2_get_byte(gb);
220             count = (int8_t)bytestream2_get_byte(gb);
221             if (count >= 0) {
222                 if (frame - line_ptr < count)
223                     return AVERROR_INVALIDDATA;
224                 if (bytestream2_get_buffer(gb, line_ptr, count) != count)
225                     return AVERROR_INVALIDDATA;
226             } else {
227                 count = -count;
228                 if (frame - line_ptr < count)
229                     return AVERROR_INVALIDDATA;
230                 memset(line_ptr, bytestream2_get_byte(gb), count);
231             }
232             line_ptr += count;
233         }
234     }
235 
236     return 0;
237 }
238 
decode_wdlt(GetByteContext * gb,uint8_t * frame,int width,int height)239 static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
240 {
241     const uint8_t *frame_end   = frame + width * height;
242     uint8_t *line_ptr;
243     int count, i, v, lines, segments;
244     int y = 0;
245 
246     lines = bytestream2_get_le16(gb);
247     if (lines > height)
248         return AVERROR_INVALIDDATA;
249 
250     while (lines--) {
251         if (bytestream2_get_bytes_left(gb) < 2)
252             return AVERROR_INVALIDDATA;
253         segments = bytestream2_get_le16u(gb);
254         while ((segments & 0xC000) == 0xC000) {
255             unsigned skip_lines = -(int16_t)segments;
256             int64_t delta = -((int16_t)segments * (int64_t)width);
257             if (frame_end - frame <= delta || y + lines + skip_lines > height)
258                 return AVERROR_INVALIDDATA;
259             frame    += delta;
260             y        += skip_lines;
261             segments = bytestream2_get_le16(gb);
262         }
263 
264         if (frame_end <= frame)
265             return AVERROR_INVALIDDATA;
266         if (segments & 0x8000) {
267             frame[width - 1] = segments & 0xFF;
268             segments = bytestream2_get_le16(gb);
269         }
270         line_ptr = frame;
271         if (frame_end - frame < width)
272             return AVERROR_INVALIDDATA;
273         frame += width;
274         y++;
275         while (segments--) {
276             if (frame - line_ptr <= bytestream2_peek_byte(gb))
277                 return AVERROR_INVALIDDATA;
278             line_ptr += bytestream2_get_byte(gb);
279             count = (int8_t)bytestream2_get_byte(gb);
280             if (count >= 0) {
281                 if (frame - line_ptr < count * 2)
282                     return AVERROR_INVALIDDATA;
283                 if (bytestream2_get_buffer(gb, line_ptr, count * 2) != count * 2)
284                     return AVERROR_INVALIDDATA;
285                 line_ptr += count * 2;
286             } else {
287                 count = -count;
288                 if (frame - line_ptr < count * 2)
289                     return AVERROR_INVALIDDATA;
290                 v = bytestream2_get_le16(gb);
291                 for (i = 0; i < count; i++)
292                     bytestream_put_le16(&line_ptr, v);
293             }
294         }
295     }
296 
297     return 0;
298 }
299 
decode_tdlt(GetByteContext * gb,uint8_t * frame,int width,int height)300 static int decode_tdlt(GetByteContext *gb, uint8_t *frame, int width, int height)
301 {
302     const uint8_t *frame_end = frame + width * height;
303     uint32_t segments = bytestream2_get_le32(gb);
304     int skip, copy;
305 
306     while (segments--) {
307         if (bytestream2_get_bytes_left(gb) < 2)
308             return AVERROR_INVALIDDATA;
309         copy = bytestream2_get_byteu(gb) * 2;
310         skip = bytestream2_get_byteu(gb) * 2;
311         if (frame_end - frame < copy + skip ||
312             bytestream2_get_bytes_left(gb) < copy)
313             return AVERROR_INVALIDDATA;
314         frame += skip;
315         bytestream2_get_buffer(gb, frame, copy);
316         frame += copy;
317     }
318 
319     return 0;
320 }
321 
decode_blck(GetByteContext * gb,uint8_t * frame,int width,int height)322 static int decode_blck(GetByteContext *gb, uint8_t *frame, int width, int height)
323 {
324     memset(frame, 0, width * height);
325     return 0;
326 }
327 
328 
329 typedef int (*chunk_decoder)(GetByteContext *gb, uint8_t *frame, int width, int height);
330 
331 static const chunk_decoder decoder[8] = {
332     decode_copy, decode_tsw1, decode_bdlt, decode_wdlt,
333     decode_tdlt, decode_dsw1, decode_blck, decode_dds1,
334 };
335 
336 static const char chunk_name[8][5] = {
337     "COPY", "TSW1", "BDLT", "WDLT", "TDLT", "DSW1", "BLCK", "DDS1"
338 };
339 
dfa_decode_frame(AVCodecContext * avctx,AVFrame * frame,int * got_frame,AVPacket * avpkt)340 static int dfa_decode_frame(AVCodecContext *avctx, AVFrame *frame,
341                             int *got_frame, AVPacket *avpkt)
342 {
343     DfaContext *s = avctx->priv_data;
344     GetByteContext gb;
345     const uint8_t *buf = avpkt->data;
346     uint32_t chunk_type, chunk_size;
347     uint8_t *dst;
348     int ret;
349     int i, pal_elems;
350     int version = avctx->extradata_size==2 ? AV_RL16(avctx->extradata) : 0;
351 
352     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
353         return ret;
354 
355     bytestream2_init(&gb, avpkt->data, avpkt->size);
356     while (bytestream2_get_bytes_left(&gb) > 0) {
357         if (bytestream2_get_bytes_left(&gb) < 12)
358             return AVERROR_INVALIDDATA;
359         bytestream2_skip(&gb, 4);
360         chunk_size = bytestream2_get_le32(&gb);
361         chunk_type = bytestream2_get_le32(&gb);
362         if (!chunk_type)
363             break;
364         if (chunk_type == 1) {
365             pal_elems = FFMIN(chunk_size / 3, 256);
366             for (i = 0; i < pal_elems; i++) {
367                 s->pal[i] = bytestream2_get_be24(&gb) << 2;
368                 s->pal[i] |= 0xFFU << 24 | (s->pal[i] >> 6) & 0x30303;
369             }
370             frame->palette_has_changed = 1;
371         } else if (chunk_type <= 9) {
372             if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) {
373                 av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n",
374                        chunk_name[chunk_type - 2]);
375                 return AVERROR_INVALIDDATA;
376             }
377         } else {
378             av_log(avctx, AV_LOG_WARNING,
379                    "Ignoring unknown chunk type %"PRIu32"\n",
380                    chunk_type);
381         }
382         buf += chunk_size;
383     }
384 
385     buf = s->frame_buf;
386     dst = frame->data[0];
387     if (version == 0x100) {
388         for (i = 0; i < avctx->height; i++) {
389             int j;
390             const uint8_t *buf1 = buf + (i&3)*(avctx->width/4) + (i/4)*avctx->width;
391             int stride = (avctx->height/4)*avctx->width;
392             for(j = 0; j < avctx->width/4; j++) {
393                 dst[4*j+0] = buf1[j + 0*stride];
394                 dst[4*j+1] = buf1[j + 1*stride];
395                 dst[4*j+2] = buf1[j + 2*stride];
396                 dst[4*j+3] = buf1[j + 3*stride];
397             }
398             j *= 4;
399             for(; j < avctx->width; j++) {
400                 dst[j] = buf1[(j/4) + (j&3)*stride];
401             }
402             dst += frame->linesize[0];
403         }
404     } else
405         av_image_copy_plane(dst, frame->linesize[0], buf, avctx->width,
406                             avctx->width, avctx->height);
407 
408     memcpy(frame->data[1], s->pal, sizeof(s->pal));
409 
410     *got_frame = 1;
411 
412     return avpkt->size;
413 }
414 
dfa_decode_end(AVCodecContext * avctx)415 static av_cold int dfa_decode_end(AVCodecContext *avctx)
416 {
417     DfaContext *s = avctx->priv_data;
418 
419     av_freep(&s->frame_buf);
420 
421     return 0;
422 }
423 
424 const FFCodec ff_dfa_decoder = {
425     .p.name         = "dfa",
426     .p.long_name    = NULL_IF_CONFIG_SMALL("Chronomaster DFA"),
427     .p.type         = AVMEDIA_TYPE_VIDEO,
428     .p.id           = AV_CODEC_ID_DFA,
429     .priv_data_size = sizeof(DfaContext),
430     .init           = dfa_decode_init,
431     .close          = dfa_decode_end,
432     FF_CODEC_DECODE_CB(dfa_decode_frame),
433     .p.capabilities = AV_CODEC_CAP_DR1,
434     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
435 };
436