2 * Feeble Files/ScummVM DXA decoder
3 * Copyright (c) 2007 Konstantin Shishkov
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
37 typedef struct DxaDecContext
{
38 AVCodecContext
*avctx
;
46 static const int shift1
[6] = { 0, 8, 8, 8, 4, 4 };
47 static const int shift2
[6] = { 0, 0, 8, 4, 0, 4 };
49 static int decode_13(AVCodecContext
*avctx
, DxaDecContext
*c
, uint8_t* dst
, uint8_t *src
, uint8_t *ref
)
51 uint8_t *code
, *data
, *mv
, *msk
, *tmp
, *tmp2
;
53 int type
, x
, y
, d
, d2
;
54 int stride
= c
->pic
.linesize
[0];
58 data
= code
+ ((avctx
->width
* avctx
->height
) >> 4);
59 mv
= data
+ AV_RB32(src
+ 0);
60 msk
= mv
+ AV_RB32(src
+ 4);
62 for(j
= 0; j
< avctx
->height
; j
+= 4){
63 for(i
= 0; i
< avctx
->width
; i
+= 4){
68 case 4: // motion compensation
69 x
= (*mv
) >> 4; if(x
& 8) x
= 8 - x
;
70 y
= (*mv
++) & 0xF; if(y
& 8) y
= 8 - y
;
73 case 5: // skip in method 12
74 for(y
= 0; y
< 4; y
++){
80 case 1: // masked change
81 case 10: // masked change with only half of pixels changed
82 case 11: // cases 10-15 are for method 12 only
92 mask
= ((msk
[0] & 0xF0) << shift1
[type
]) | ((msk
[0] & 0xF) << shift2
[type
]);
95 for(y
= 0; y
< 4; y
++){
96 for(x
= 0; x
< 4; x
++){
97 tmp
[x
] = (mask
& 0x8000) ? *data
++ : tmp2
[x
];
104 case 2: // fill block
105 for(y
= 0; y
< 4; y
++){
106 memset(tmp
, data
[0], 4);
112 for(y
= 0; y
< 4; y
++){
113 memcpy(tmp
, data
, 4);
118 case 8: // subblocks - method 13 only
120 for(k
= 0; k
< 4; k
++){
121 d
= ((k
& 1) << 1) + ((k
& 2) * stride
);
122 d2
= ((k
& 1) << 1) + ((k
& 2) * stride
);
125 case 0x80: // motion compensation
126 x
= (*mv
) >> 4; if(x
& 8) x
= 8 - x
;
127 y
= (*mv
++) & 0xF; if(y
& 8) y
= 8 - y
;
128 tmp2
+= x
+ y
*stride
;
130 tmp
[d
+ 0 ] = tmp2
[0];
131 tmp
[d
+ 1 ] = tmp2
[1];
132 tmp
[d
+ 0 + stride
] = tmp2
[0 + stride
];
133 tmp
[d
+ 1 + stride
] = tmp2
[1 + stride
];
136 tmp
[d
+ 0 ] = data
[0];
137 tmp
[d
+ 1 ] = data
[0];
138 tmp
[d
+ 0 + stride
] = data
[0];
139 tmp
[d
+ 1 + stride
] = data
[0];
143 tmp
[d
+ 0 ] = *data
++;
144 tmp
[d
+ 1 ] = *data
++;
145 tmp
[d
+ 0 + stride
] = *data
++;
146 tmp
[d
+ 1 + stride
] = *data
++;
152 case 32: // vector quantization - 2 colors
155 for(y
= 0; y
< 4; y
++){
156 for(x
= 0; x
< 4; x
++){
157 tmp
[x
] = data
[mask
& 1];
165 case 33: // vector quantization - 3 or 4 colors
169 for(y
= 0; y
< 4; y
++){
170 for(x
= 0; x
< 4; x
++){
171 tmp
[x
] = data
[mask
& 3];
180 av_log(avctx
, AV_LOG_ERROR
, "Unknown opcode %d\n", type
);
190 static int decode_frame(AVCodecContext
*avctx
, void *data
, int *data_size
, const uint8_t *buf
, int buf_size
)
192 DxaDecContext
* const c
= avctx
->priv_data
;
193 uint8_t *outptr
, *srcptr
, *tmpptr
;
197 int orig_buf_size
= buf_size
;
200 /* make the palette available on the way out */
201 if(buf
[0]=='C' && buf
[1]=='M' && buf
[2]=='A' && buf
[3]=='P'){
205 for(i
= 0; i
< 256; i
++){
209 c
->pal
[i
] = (r
<< 16) | (g
<< 8) | b
;
215 if(avctx
->get_buffer(avctx
, &c
->pic
) < 0){
216 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
219 memcpy(c
->pic
.data
[1], c
->pal
, AVPALETTE_SIZE
);
220 c
->pic
.palette_has_changed
= pc
;
222 outptr
= c
->pic
.data
[0];
223 srcptr
= c
->decomp_buf
;
224 tmpptr
= c
->prev
.data
[0];
225 stride
= c
->pic
.linesize
[0];
227 if(buf
[0]=='N' && buf
[1]=='U' && buf
[2]=='L' && buf
[3]=='L')
233 if((compr
!= 4 && compr
!= -1) && uncompress(c
->decomp_buf
, &dsize
, buf
+ 9, buf_size
- 9) != Z_OK
){
234 av_log(avctx
, AV_LOG_ERROR
, "Uncompress failed!\n");
239 c
->pic
.key_frame
= 0;
240 c
->pic
.pict_type
= FF_P_TYPE
;
242 memcpy(c
->pic
.data
[0], c
->prev
.data
[0], c
->pic
.linesize
[0] * avctx
->height
);
243 else{ // Should happen only when first frame is 'NULL'
244 memset(c
->pic
.data
[0], 0, c
->pic
.linesize
[0] * avctx
->height
);
245 c
->pic
.key_frame
= 1;
246 c
->pic
.pict_type
= FF_I_TYPE
;
253 c
->pic
.key_frame
= !(compr
& 1);
254 c
->pic
.pict_type
= (compr
& 1) ? FF_P_TYPE
: FF_I_TYPE
;
255 for(j
= 0; j
< avctx
->height
; j
++){
257 for(i
= 0; i
< avctx
->width
; i
++)
258 outptr
[i
] = srcptr
[i
] ^ tmpptr
[i
];
261 memcpy(outptr
, srcptr
, avctx
->width
);
263 srcptr
+= avctx
->width
;
266 case 12: // ScummVM coding
268 c
->pic
.key_frame
= 0;
269 c
->pic
.pict_type
= FF_P_TYPE
;
270 decode_13(avctx
, c
, c
->pic
.data
[0], srcptr
, c
->prev
.data
[0]);
273 av_log(avctx
, AV_LOG_ERROR
, "Unknown/unsupported compression type %d\n", buf
[4]);
277 FFSWAP(AVFrame
, c
->pic
, c
->prev
);
279 avctx
->release_buffer(avctx
, &c
->pic
);
281 *data_size
= sizeof(AVFrame
);
282 *(AVFrame
*)data
= c
->prev
;
284 /* always report that the buffer was completely consumed */
285 return orig_buf_size
;
288 static av_cold
int decode_init(AVCodecContext
*avctx
)
290 DxaDecContext
* const c
= avctx
->priv_data
;
293 avctx
->pix_fmt
= PIX_FMT_PAL8
;
295 if (avcodec_check_dimensions(avctx
, avctx
->width
, avctx
->height
) < 0) {
299 c
->dsize
= avctx
->width
* avctx
->height
* 2;
300 if((c
->decomp_buf
= av_malloc(c
->dsize
)) == NULL
) {
301 av_log(avctx
, AV_LOG_ERROR
, "Can't allocate decompression buffer.\n");
308 static av_cold
int decode_end(AVCodecContext
*avctx
)
310 DxaDecContext
* const c
= avctx
->priv_data
;
312 av_freep(&c
->decomp_buf
);
314 avctx
->release_buffer(avctx
, &c
->prev
);
316 avctx
->release_buffer(avctx
, &c
->pic
);
321 AVCodec dxa_decoder
= {
325 sizeof(DxaDecContext
),
330 .long_name
= NULL_IF_CONFIG_SMALL("Feeble Files/ScummVM DXA"),