3 * Copyright (c) 2011-2012 Paul B Mahol
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
24 * Commodore CDXL video decoder
25 * @author Paul B Mahol
28 #define UNCHECKED_BITSTREAM_READER 1
30 #include "libavutil/intreadwrite.h"
31 #include "libavutil/imgutils.h"
36 #define BIT_PLANAR 0x00
38 #define BYTE_PLANAR 0x40
40 #define BYTE_LINE 0xC0
43 AVCodecContext
*avctx
;
47 const uint8_t *palette
;
55 static av_cold
int cdxl_decode_init(AVCodecContext
*avctx
)
57 CDXLVideoContext
*c
= avctx
->priv_data
;
59 c
->new_video_size
= 0;
65 static void import_palette(CDXLVideoContext
*c
, uint32_t *new_palette
)
69 for (i
= 0; i
< c
->palette_size
/ 2; i
++) {
70 unsigned rgb
= AV_RB16(&c
->palette
[i
* 2]);
71 unsigned r
= ((rgb
>> 8) & 0xF) * 0x11;
72 unsigned g
= ((rgb
>> 4) & 0xF) * 0x11;
73 unsigned b
= (rgb
& 0xF) * 0x11;
74 AV_WN32(&new_palette
[i
], (0xFFU
<< 24) | (r
<< 16) | (g
<< 8) | b
);
78 static void bitplanar2chunky(CDXLVideoContext
*c
, int linesize
, uint8_t *out
)
83 init_get_bits(&gb
, c
->video
, c
->video_size
* 8);
84 for (plane
= 0; plane
< c
->bpp
; plane
++) {
85 for (y
= 0; y
< c
->avctx
->height
; y
++) {
86 for (x
= 0; x
< c
->avctx
->width
; x
++)
87 out
[linesize
* y
+ x
] |= get_bits1(&gb
) << plane
;
88 skip_bits(&gb
, c
->padded_bits
);
93 static void bitline2chunky(CDXLVideoContext
*c
, int linesize
, uint8_t *out
)
98 init_get_bits(&gb
, c
->video
, c
->video_size
* 8);
99 for (y
= 0; y
< c
->avctx
->height
; y
++) {
100 for (plane
= 0; plane
< c
->bpp
; plane
++) {
101 for (x
= 0; x
< c
->avctx
->width
; x
++)
102 out
[linesize
* y
+ x
] |= get_bits1(&gb
) << plane
;
103 skip_bits(&gb
, c
->padded_bits
);
108 static void import_format(CDXLVideoContext
*c
, int linesize
, uint8_t *out
)
110 memset(out
, 0, linesize
* c
->avctx
->height
);
114 bitplanar2chunky(c
, linesize
, out
);
117 bitline2chunky(c
, linesize
, out
);
122 static void cdxl_decode_rgb(CDXLVideoContext
*c
, AVFrame
*frame
)
124 uint32_t *new_palette
= (uint32_t *)frame
->data
[1];
126 memset(frame
->data
[1], 0, AVPALETTE_SIZE
);
127 import_palette(c
, new_palette
);
128 import_format(c
, frame
->linesize
[0], frame
->data
[0]);
131 static void cdxl_decode_ham6(CDXLVideoContext
*c
, AVFrame
*frame
)
133 AVCodecContext
*avctx
= c
->avctx
;
134 uint32_t new_palette
[16], r
, g
, b
;
135 uint8_t *ptr
, *out
, index
, op
;
139 out
= frame
->data
[0];
141 import_palette(c
, new_palette
);
142 import_format(c
, avctx
->width
, c
->new_video
);
144 for (y
= 0; y
< avctx
->height
; y
++) {
145 r
= new_palette
[0] & 0xFF0000;
146 g
= new_palette
[0] & 0xFF00;
147 b
= new_palette
[0] & 0xFF;
148 for (x
= 0; x
< avctx
->width
; x
++) {
154 r
= new_palette
[index
] & 0xFF0000;
155 g
= new_palette
[index
] & 0xFF00;
156 b
= new_palette
[index
] & 0xFF;
162 r
= index
* 0x11 << 16;
165 g
= index
* 0x11 << 8;
168 AV_WL24(out
+ x
* 3, r
| g
| b
);
170 out
+= frame
->linesize
[0];
174 static void cdxl_decode_ham8(CDXLVideoContext
*c
, AVFrame
*frame
)
176 AVCodecContext
*avctx
= c
->avctx
;
177 uint32_t new_palette
[64], r
, g
, b
;
178 uint8_t *ptr
, *out
, index
, op
;
182 out
= frame
->data
[0];
184 import_palette(c
, new_palette
);
185 import_format(c
, avctx
->width
, c
->new_video
);
187 for (y
= 0; y
< avctx
->height
; y
++) {
188 r
= new_palette
[0] & 0xFF0000;
189 g
= new_palette
[0] & 0xFF00;
190 b
= new_palette
[0] & 0xFF;
191 for (x
= 0; x
< avctx
->width
; x
++) {
197 r
= new_palette
[index
] & 0xFF0000;
198 g
= new_palette
[index
] & 0xFF00;
199 b
= new_palette
[index
] & 0xFF;
202 b
= (index
<< 2) | (b
& 3);
205 r
= (index
<< 18) | (r
& (3 << 16));
208 g
= (index
<< 10) | (g
& (3 << 8));
211 AV_WL24(out
+ x
* 3, r
| g
| b
);
213 out
+= frame
->linesize
[0];
217 static int cdxl_decode_frame(AVCodecContext
*avctx
, void *data
,
218 int *got_frame
, AVPacket
*pkt
)
220 CDXLVideoContext
*c
= avctx
->priv_data
;
221 AVFrame
* const p
= data
;
222 int ret
, w
, h
, encoding
, aligned_width
, buf_size
= pkt
->size
;
223 const uint8_t *buf
= pkt
->data
;
226 return AVERROR_INVALIDDATA
;
227 encoding
= buf
[1] & 7;
228 c
->format
= buf
[1] & 0xE0;
229 w
= AV_RB16(&buf
[14]);
230 h
= AV_RB16(&buf
[16]);
232 c
->palette_size
= AV_RB16(&buf
[20]);
233 c
->palette
= buf
+ 32;
234 c
->video
= c
->palette
+ c
->palette_size
;
235 c
->video_size
= buf_size
- c
->palette_size
- 32;
237 if (c
->palette_size
> 512)
238 return AVERROR_INVALIDDATA
;
239 if (buf_size
< c
->palette_size
+ 32)
240 return AVERROR_INVALIDDATA
;
242 return AVERROR_INVALIDDATA
;
243 if (c
->format
!= BIT_PLANAR
&& c
->format
!= BIT_LINE
) {
244 avpriv_request_sample(avctx
, "Pixel format 0x%0x", c
->format
);
245 return AVERROR_PATCHWELCOME
;
248 if ((ret
= ff_set_dimensions(avctx
, w
, h
)) < 0)
251 aligned_width
= FFALIGN(c
->avctx
->width
, 16);
252 c
->padded_bits
= aligned_width
- c
->avctx
->width
;
253 if (c
->video_size
< aligned_width
* avctx
->height
* c
->bpp
/ 8)
254 return AVERROR_INVALIDDATA
;
255 if (!encoding
&& c
->palette_size
&& c
->bpp
<= 8) {
256 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
257 } else if (encoding
== 1 && (c
->bpp
== 6 || c
->bpp
== 8)) {
258 if (c
->palette_size
!= (1 << (c
->bpp
- 1)))
259 return AVERROR_INVALIDDATA
;
260 avctx
->pix_fmt
= AV_PIX_FMT_BGR24
;
262 avpriv_request_sample(avctx
, "Encoding %d and bpp %d",
264 return AVERROR_PATCHWELCOME
;
267 if ((ret
= ff_get_buffer(avctx
, p
, 0)) < 0)
269 p
->pict_type
= AV_PICTURE_TYPE_I
;
272 av_fast_padded_malloc(&c
->new_video
, &c
->new_video_size
,
273 h
* w
+ FF_INPUT_BUFFER_PADDING_SIZE
);
275 return AVERROR(ENOMEM
);
277 cdxl_decode_ham8(c
, p
);
279 cdxl_decode_ham6(c
, p
);
281 cdxl_decode_rgb(c
, p
);
288 static av_cold
int cdxl_decode_end(AVCodecContext
*avctx
)
290 CDXLVideoContext
*c
= avctx
->priv_data
;
292 av_freep(&c
->new_video
);
297 AVCodec ff_cdxl_decoder
= {
299 .long_name
= NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
300 .type
= AVMEDIA_TYPE_VIDEO
,
301 .id
= AV_CODEC_ID_CDXL
,
302 .priv_data_size
= sizeof(CDXLVideoContext
),
303 .init
= cdxl_decode_init
,
304 .close
= cdxl_decode_end
,
305 .decode
= cdxl_decode_frame
,
306 .capabilities
= CODEC_CAP_DR1
,