2 * Interplay C93 video decoder
3 * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
5 * This file is part of Libav.
7 * Libav 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 * Libav 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 Libav; 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_init(AVCodecContext
*avctx
)
51 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
55 static av_cold
int decode_end(AVCodecContext
*avctx
)
57 C93DecoderContext
* const c93
= avctx
->priv_data
;
59 av_frame_unref(&c93
->pictures
[0]);
60 av_frame_unref(&c93
->pictures
[1]);
65 static inline int copy_block(AVCodecContext
*avctx
, uint8_t *to
,
66 uint8_t *from
, int offset
, int height
, int stride
)
70 int from_x
= offset
% WIDTH
;
71 int from_y
= offset
/ WIDTH
;
72 int overflow
= from_x
+ width
- WIDTH
;
75 /* silently ignoring predictive blocks in first frame */
79 if (from_y
+ height
> HEIGHT
) {
80 av_log(avctx
, AV_LOG_ERROR
, "invalid offset %d during C93 decoding\n",
82 return AVERROR_INVALIDDATA
;
87 for (i
= 0; i
< height
; i
++) {
88 memcpy(&to
[i
*stride
+width
], &from
[(from_y
+i
)*stride
], overflow
);
92 for (i
= 0; i
< height
; i
++) {
93 memcpy(&to
[i
*stride
], &from
[(from_y
+i
)*stride
+from_x
], width
);
99 static inline void draw_n_color(uint8_t *out
, int stride
, int width
,
100 int height
, int bpp
, uint8_t cols
[4], uint8_t grps
[4], uint32_t col
)
103 for (y
= 0; y
< height
; y
++) {
105 cols
[0] = grps
[3 * (y
>> 1)];
106 for (x
= 0; x
< width
; x
++) {
108 cols
[1]= grps
[(x
>> 1) + 1];
109 out
[x
+ y
*stride
] = cols
[col
& ((1 << bpp
) - 1)];
115 static int decode_frame(AVCodecContext
*avctx
, void *data
,
116 int *got_frame
, AVPacket
*avpkt
)
118 const uint8_t *buf
= avpkt
->data
;
119 int buf_size
= avpkt
->size
;
120 C93DecoderContext
* const c93
= avctx
->priv_data
;
121 AVFrame
* const newpic
= &c93
->pictures
[c93
->currentpic
];
122 AVFrame
* const oldpic
= &c93
->pictures
[c93
->currentpic
^1];
125 int stride
, ret
, i
, x
, y
, b
, bt
= 0;
127 c93
->currentpic
^= 1;
129 if ((ret
= ff_reget_buffer(avctx
, newpic
)) < 0) {
130 av_log(avctx
, AV_LOG_ERROR
, "reget_buffer() failed\n");
134 stride
= newpic
->linesize
[0];
136 bytestream2_init(&gb
, buf
, buf_size
);
137 b
= bytestream2_get_byte(&gb
);
138 if (b
& C93_FIRST_FRAME
) {
139 newpic
->pict_type
= AV_PICTURE_TYPE_I
;
140 newpic
->key_frame
= 1;
142 newpic
->pict_type
= AV_PICTURE_TYPE_P
;
143 newpic
->key_frame
= 0;
146 for (y
= 0; y
< HEIGHT
; y
+= 8) {
147 out
= newpic
->data
[0] + y
* stride
;
148 for (x
= 0; x
< WIDTH
; x
+= 8) {
149 uint8_t *copy_from
= oldpic
->data
[0];
150 unsigned int offset
, j
;
151 uint8_t cols
[4], grps
[4];
152 C93BlockType block_type
;
155 bt
= bytestream2_get_byte(&gb
);
157 block_type
= bt
& 0x0F;
158 switch (block_type
) {
159 case C93_8X8_FROM_PREV
:
160 offset
= bytestream2_get_le16(&gb
);
161 if ((ret
= copy_block(avctx
, out
, copy_from
, offset
, 8, stride
)) < 0)
165 case C93_4X4_FROM_CURR
:
166 copy_from
= newpic
->data
[0];
167 case C93_4X4_FROM_PREV
:
168 for (j
= 0; j
< 8; j
+= 4) {
169 for (i
= 0; i
< 8; i
+= 4) {
170 offset
= bytestream2_get_le16(&gb
);
171 if ((ret
= copy_block(avctx
, &out
[j
*stride
+i
],
172 copy_from
, offset
, 4, stride
)) < 0)
179 bytestream2_get_buffer(&gb
, cols
, 2);
180 for (i
= 0; i
< 8; i
++) {
181 draw_n_color(out
+ i
*stride
, stride
, 8, 1, 1, cols
,
182 NULL
, bytestream2_get_byte(&gb
));
189 case C93_4X4_4COLOR_GRP
:
190 for (j
= 0; j
< 8; j
+= 4) {
191 for (i
= 0; i
< 8; i
+= 4) {
192 if (block_type
== C93_4X4_2COLOR
) {
193 bytestream2_get_buffer(&gb
, cols
, 2);
194 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
195 1, cols
, NULL
, bytestream2_get_le16(&gb
));
196 } else if (block_type
== C93_4X4_4COLOR
) {
197 bytestream2_get_buffer(&gb
, cols
, 4);
198 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
199 2, cols
, NULL
, bytestream2_get_le32(&gb
));
201 bytestream2_get_buffer(&gb
, grps
, 4);
202 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
203 1, cols
, grps
, bytestream2_get_le16(&gb
));
213 for (j
= 0; j
< 8; j
++)
214 bytestream2_get_buffer(&gb
, out
+ j
*stride
, 8);
218 av_log(avctx
, AV_LOG_ERROR
, "unexpected type %x at %dx%d\n",
220 return AVERROR_INVALIDDATA
;
227 if (b
& C93_HAS_PALETTE
) {
228 uint32_t *palette
= (uint32_t *) newpic
->data
[1];
229 for (i
= 0; i
< 256; i
++) {
230 palette
[i
] = bytestream2_get_be24(&gb
);
232 newpic
->palette_has_changed
= 1;
235 memcpy(newpic
->data
[1], oldpic
->data
[1], 256 * 4);
238 if ((ret
= av_frame_ref(data
, newpic
)) < 0)
245 AVCodec ff_c93_decoder
= {
247 .type
= AVMEDIA_TYPE_VIDEO
,
248 .id
= AV_CODEC_ID_C93
,
249 .priv_data_size
= sizeof(C93DecoderContext
),
252 .decode
= decode_frame
,
253 .capabilities
= CODEC_CAP_DR1
,
254 .long_name
= NULL_IF_CONFIG_SMALL("Interplay C93"),