2 * Interplay C93 video decoder
3 * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
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
23 #include "bytestream.h"
32 C93_8X8_FROM_PREV
= 0x02,
33 C93_4X4_FROM_PREV
= 0x06,
34 C93_4X4_FROM_CURR
= 0x07,
35 C93_8X8_2COLOR
= 0x08,
36 C93_4X4_2COLOR
= 0x0A,
37 C93_4X4_4COLOR_GRP
= 0x0B,
38 C93_4X4_4COLOR
= 0x0D,
46 #define C93_HAS_PALETTE 0x01
47 #define C93_FIRST_FRAME 0x02
49 static av_cold
int decode_end(AVCodecContext
*avctx
)
51 C93DecoderContext
* const c93
= avctx
->priv_data
;
53 av_frame_free(&c93
->pictures
[0]);
54 av_frame_free(&c93
->pictures
[1]);
59 static av_cold
int decode_init(AVCodecContext
*avctx
)
61 C93DecoderContext
*s
= avctx
->priv_data
;
62 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
64 s
->pictures
[0] = av_frame_alloc();
65 s
->pictures
[1] = av_frame_alloc();
66 if (!s
->pictures
[0] || !s
->pictures
[1]) {
68 return AVERROR(ENOMEM
);
74 static inline int copy_block(AVCodecContext
*avctx
, uint8_t *to
,
75 uint8_t *from
, int offset
, int height
, int stride
)
79 int from_x
= offset
% WIDTH
;
80 int from_y
= offset
/ WIDTH
;
81 int overflow
= from_x
+ width
- WIDTH
;
84 /* silently ignoring predictive blocks in first frame */
88 if (from_y
+ height
> HEIGHT
) {
89 av_log(avctx
, AV_LOG_ERROR
, "invalid offset %d during C93 decoding\n",
91 return AVERROR_INVALIDDATA
;
96 for (i
= 0; i
< height
; i
++) {
97 memcpy(&to
[i
*stride
+width
], &from
[(from_y
+i
)*stride
], overflow
);
101 for (i
= 0; i
< height
; i
++) {
102 memcpy(&to
[i
*stride
], &from
[(from_y
+i
)*stride
+from_x
], width
);
108 static inline void draw_n_color(uint8_t *out
, int stride
, int width
,
109 int height
, int bpp
, uint8_t cols
[4], uint8_t grps
[4], uint32_t col
)
112 for (y
= 0; y
< height
; y
++) {
114 cols
[0] = grps
[3 * (y
>> 1)];
115 for (x
= 0; x
< width
; x
++) {
117 cols
[1]= grps
[(x
>> 1) + 1];
118 out
[x
+ y
*stride
] = cols
[col
& ((1 << bpp
) - 1)];
124 static int decode_frame(AVCodecContext
*avctx
, void *data
,
125 int *got_frame
, AVPacket
*avpkt
)
127 const uint8_t *buf
= avpkt
->data
;
128 int buf_size
= avpkt
->size
;
129 C93DecoderContext
* const c93
= avctx
->priv_data
;
130 AVFrame
* const newpic
= c93
->pictures
[c93
->currentpic
];
131 AVFrame
* const oldpic
= c93
->pictures
[c93
->currentpic
^1];
134 int stride
, ret
, i
, x
, y
, b
, bt
= 0;
136 if ((ret
= ff_set_dimensions(avctx
, WIDTH
, HEIGHT
)) < 0)
139 c93
->currentpic
^= 1;
141 if ((ret
= ff_reget_buffer(avctx
, newpic
)) < 0)
144 stride
= newpic
->linesize
[0];
146 bytestream2_init(&gb
, buf
, buf_size
);
147 b
= bytestream2_get_byte(&gb
);
148 if (b
& C93_FIRST_FRAME
) {
149 newpic
->pict_type
= AV_PICTURE_TYPE_I
;
150 newpic
->key_frame
= 1;
152 newpic
->pict_type
= AV_PICTURE_TYPE_P
;
153 newpic
->key_frame
= 0;
156 for (y
= 0; y
< HEIGHT
; y
+= 8) {
157 out
= newpic
->data
[0] + y
* stride
;
158 for (x
= 0; x
< WIDTH
; x
+= 8) {
159 uint8_t *copy_from
= oldpic
->data
[0];
160 unsigned int offset
, j
;
161 uint8_t cols
[4], grps
[4];
162 C93BlockType block_type
;
165 bt
= bytestream2_get_byte(&gb
);
167 block_type
= bt
& 0x0F;
168 switch (block_type
) {
169 case C93_8X8_FROM_PREV
:
170 offset
= bytestream2_get_le16(&gb
);
171 if ((ret
= copy_block(avctx
, out
, copy_from
, offset
, 8, stride
)) < 0)
175 case C93_4X4_FROM_CURR
:
176 copy_from
= newpic
->data
[0];
177 case C93_4X4_FROM_PREV
:
178 for (j
= 0; j
< 8; j
+= 4) {
179 for (i
= 0; i
< 8; i
+= 4) {
180 int offset
= bytestream2_get_le16(&gb
);
181 int from_x
= offset
% WIDTH
;
182 int from_y
= offset
/ WIDTH
;
183 if (block_type
== C93_4X4_FROM_CURR
&& from_y
== y
+j
&&
184 (FFABS(from_x
- x
-i
) < 4 || FFABS(from_x
- x
-i
) > WIDTH
-4)) {
185 avpriv_request_sample(avctx
, "block overlap %d %d %d %d\n", from_x
, x
+i
, from_y
, y
+j
);
186 return AVERROR_INVALIDDATA
;
188 if ((ret
= copy_block(avctx
, &out
[j
*stride
+i
],
189 copy_from
, offset
, 4, stride
)) < 0)
196 bytestream2_get_buffer(&gb
, cols
, 2);
197 for (i
= 0; i
< 8; i
++) {
198 draw_n_color(out
+ i
*stride
, stride
, 8, 1, 1, cols
,
199 NULL
, bytestream2_get_byte(&gb
));
206 case C93_4X4_4COLOR_GRP
:
207 for (j
= 0; j
< 8; j
+= 4) {
208 for (i
= 0; i
< 8; i
+= 4) {
209 if (block_type
== C93_4X4_2COLOR
) {
210 bytestream2_get_buffer(&gb
, cols
, 2);
211 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
212 1, cols
, NULL
, bytestream2_get_le16(&gb
));
213 } else if (block_type
== C93_4X4_4COLOR
) {
214 bytestream2_get_buffer(&gb
, cols
, 4);
215 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
216 2, cols
, NULL
, bytestream2_get_le32(&gb
));
218 bytestream2_get_buffer(&gb
, grps
, 4);
219 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
220 1, cols
, grps
, bytestream2_get_le16(&gb
));
230 for (j
= 0; j
< 8; j
++)
231 bytestream2_get_buffer(&gb
, out
+ j
*stride
, 8);
235 av_log(avctx
, AV_LOG_ERROR
, "unexpected type %x at %dx%d\n",
237 return AVERROR_INVALIDDATA
;
244 if (b
& C93_HAS_PALETTE
) {
245 uint32_t *palette
= (uint32_t *) newpic
->data
[1];
246 for (i
= 0; i
< 256; i
++) {
247 palette
[i
] = 0xFFU
<< 24 | bytestream2_get_be24(&gb
);
249 newpic
->palette_has_changed
= 1;
252 memcpy(newpic
->data
[1], oldpic
->data
[1], 256 * 4);
255 if ((ret
= av_frame_ref(data
, newpic
)) < 0)
262 AVCodec ff_c93_decoder
= {
264 .long_name
= NULL_IF_CONFIG_SMALL("Interplay C93"),
265 .type
= AVMEDIA_TYPE_VIDEO
,
266 .id
= AV_CODEC_ID_C93
,
267 .priv_data_size
= sizeof(C93DecoderContext
),
270 .decode
= decode_frame
,
271 .capabilities
= CODEC_CAP_DR1
,