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"
31 C93_8X8_FROM_PREV
= 0x02,
32 C93_4X4_FROM_PREV
= 0x06,
33 C93_4X4_FROM_CURR
= 0x07,
34 C93_8X8_2COLOR
= 0x08,
35 C93_4X4_2COLOR
= 0x0A,
36 C93_4X4_4COLOR_GRP
= 0x0B,
37 C93_4X4_4COLOR
= 0x0D,
45 #define C93_HAS_PALETTE 0x01
46 #define C93_FIRST_FRAME 0x02
48 static av_cold
int decode_init(AVCodecContext
*avctx
)
50 avctx
->pix_fmt
= PIX_FMT_PAL8
;
54 static av_cold
int decode_end(AVCodecContext
*avctx
)
56 C93DecoderContext
* const c93
= avctx
->priv_data
;
58 if (c93
->pictures
[0].data
[0])
59 avctx
->release_buffer(avctx
, &c93
->pictures
[0]);
60 if (c93
->pictures
[1].data
[0])
61 avctx
->release_buffer(avctx
, &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",
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 *data_size
, const uint8_t * buf
, int buf_size
)
118 C93DecoderContext
* const c93
= avctx
->priv_data
;
119 AVFrame
* const newpic
= &c93
->pictures
[c93
->currentpic
];
120 AVFrame
* const oldpic
= &c93
->pictures
[c93
->currentpic
^1];
121 AVFrame
*picture
= data
;
123 int stride
, i
, x
, y
, bt
= 0;
125 c93
->currentpic
^= 1;
127 newpic
->reference
= 1;
128 newpic
->buffer_hints
= FF_BUFFER_HINTS_VALID
| FF_BUFFER_HINTS_PRESERVE
|
129 FF_BUFFER_HINTS_REUSABLE
| FF_BUFFER_HINTS_READABLE
;
130 if (avctx
->reget_buffer(avctx
, newpic
)) {
131 av_log(avctx
, AV_LOG_ERROR
, "reget_buffer() failed\n");
135 stride
= newpic
->linesize
[0];
137 if (buf
[0] & C93_FIRST_FRAME
) {
138 newpic
->pict_type
= FF_I_TYPE
;
139 newpic
->key_frame
= 1;
141 newpic
->pict_type
= FF_P_TYPE
;
142 newpic
->key_frame
= 0;
145 if (*buf
++ & C93_HAS_PALETTE
) {
146 uint32_t *palette
= (uint32_t *) newpic
->data
[1];
147 const uint8_t *palbuf
= buf
+ buf_size
- 768 - 1;
148 for (i
= 0; i
< 256; i
++) {
149 palette
[i
] = bytestream_get_be24(&palbuf
);
153 memcpy(newpic
->data
[1], oldpic
->data
[1], 256 * 4);
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
;
167 block_type
= bt
& 0x0F;
168 switch (block_type
) {
169 case C93_8X8_FROM_PREV
:
170 offset
= bytestream_get_le16(&buf
);
171 if (copy_block(avctx
, out
, copy_from
, offset
, 8, stride
))
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 offset
= bytestream_get_le16(&buf
);
181 if (copy_block(avctx
, &out
[j
*stride
+i
],
182 copy_from
, offset
, 4, stride
))
189 bytestream_get_buffer(&buf
, cols
, 2);
190 for (i
= 0; i
< 8; i
++) {
191 draw_n_color(out
+ i
*stride
, stride
, 8, 1, 1, cols
,
199 case C93_4X4_4COLOR_GRP
:
200 for (j
= 0; j
< 8; j
+= 4) {
201 for (i
= 0; i
< 8; i
+= 4) {
202 if (block_type
== C93_4X4_2COLOR
) {
203 bytestream_get_buffer(&buf
, cols
, 2);
204 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
205 1, cols
, NULL
, bytestream_get_le16(&buf
));
206 } else if (block_type
== C93_4X4_4COLOR
) {
207 bytestream_get_buffer(&buf
, cols
, 4);
208 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
209 2, cols
, NULL
, bytestream_get_le32(&buf
));
211 bytestream_get_buffer(&buf
, grps
, 4);
212 draw_n_color(out
+ i
+ j
*stride
, stride
, 4, 4,
213 1, cols
, grps
, bytestream_get_le16(&buf
));
223 for (j
= 0; j
< 8; j
++)
224 bytestream_get_buffer(&buf
, out
+ j
*stride
, 8);
228 av_log(avctx
, AV_LOG_ERROR
, "unexpected type %x at %dx%d\n",
238 *data_size
= sizeof(AVFrame
);
243 AVCodec c93_decoder
= {
247 sizeof(C93DecoderContext
),
253 .long_name
= NULL_IF_CONFIG_SMALL("Interplay C93"),