3 * Copyright (c) 2011-2012 Paul B Mahol
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
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/imgutils.h"
28 #define BIT_PLANAR 0x00
29 #define BYTE_PLANAR 0x20
32 #define BYTE_LINE 0xC0
35 AVCodecContext
*avctx
;
40 const uint8_t *palette
;
48 static av_cold
int cdxl_decode_init(AVCodecContext
*avctx
)
50 CDXLVideoContext
*c
= avctx
->priv_data
;
52 avcodec_get_frame_defaults(&c
->frame
);
53 c
->new_video_size
= 0;
59 static void import_palette(CDXLVideoContext
*c
, uint32_t *new_palette
)
63 for (i
= 0; i
< c
->palette_size
/ 2; i
++) {
64 unsigned rgb
= AV_RB16(&c
->palette
[i
* 2]);
65 unsigned r
= ((rgb
>> 8) & 0xF) * 0x11;
66 unsigned g
= ((rgb
>> 4) & 0xF) * 0x11;
67 unsigned b
= (rgb
& 0xF) * 0x11;
68 AV_WN32(&new_palette
[i
], (r
<< 16) | (g
<< 8) | b
);
72 static void bitplanar2chunky(CDXLVideoContext
*c
, int linesize
, uint8_t *out
)
77 init_get_bits(&gb
, c
->video
, c
->video_size
* 8);
78 for (plane
= 0; plane
< c
->bpp
; plane
++) {
79 for (y
= 0; y
< c
->avctx
->height
; y
++) {
80 for (x
= 0; x
< c
->avctx
->width
; x
++)
81 out
[linesize
* y
+ x
] |= get_bits1(&gb
) << plane
;
82 skip_bits(&gb
, c
->padded_bits
);
87 static void bitline2chunky(CDXLVideoContext
*c
, int linesize
, uint8_t *out
)
92 init_get_bits(&gb
, c
->video
, c
->video_size
* 8);
93 for (y
= 0; y
< c
->avctx
->height
; y
++) {
94 for (plane
= 0; plane
< c
->bpp
; plane
++) {
95 for (x
= 0; x
< c
->avctx
->width
; x
++)
96 out
[linesize
* y
+ x
] |= get_bits1(&gb
) << plane
;
97 skip_bits(&gb
, c
->padded_bits
);
102 static void import_format(CDXLVideoContext
*c
, int linesize
, uint8_t *out
)
104 memset(out
, 0, linesize
* c
->avctx
->height
);
108 bitplanar2chunky(c
, linesize
, out
);
111 bitline2chunky(c
, linesize
, out
);
116 static void cdxl_decode_rgb(CDXLVideoContext
*c
)
118 uint32_t *new_palette
= (uint32_t *)c
->frame
.data
[1];
120 import_palette(c
, new_palette
);
121 import_format(c
, c
->frame
.linesize
[0], c
->frame
.data
[0]);
124 static void cdxl_decode_ham6(CDXLVideoContext
*c
)
126 AVCodecContext
*avctx
= c
->avctx
;
127 uint32_t new_palette
[16], r
, g
, b
;
128 uint8_t *ptr
, *out
, index
, op
;
132 out
= c
->frame
.data
[0];
134 import_palette(c
, new_palette
);
135 import_format(c
, avctx
->width
, c
->new_video
);
137 for (y
= 0; y
< avctx
->height
; y
++) {
138 r
= new_palette
[0] & 0xFF0000;
139 g
= new_palette
[0] & 0xFF00;
140 b
= new_palette
[0] & 0xFF;
141 for (x
= 0; x
< avctx
->width
; x
++) {
147 r
= new_palette
[index
] & 0xFF0000;
148 g
= new_palette
[index
] & 0xFF00;
149 b
= new_palette
[index
] & 0xFF;
155 r
= index
* 0x11 << 16;
158 g
= index
* 0x11 << 8;
161 AV_WL24(out
+ x
* 3, r
| g
| b
);
163 out
+= c
->frame
.linesize
[0];
167 static void cdxl_decode_ham8(CDXLVideoContext
*c
)
169 AVCodecContext
*avctx
= c
->avctx
;
170 uint32_t new_palette
[64], r
, g
, b
;
171 uint8_t *ptr
, *out
, index
, op
;
175 out
= c
->frame
.data
[0];
177 import_palette(c
, new_palette
);
178 import_format(c
, avctx
->width
, c
->new_video
);
180 for (y
= 0; y
< avctx
->height
; y
++) {
181 r
= new_palette
[0] & 0xFF0000;
182 g
= new_palette
[0] & 0xFF00;
183 b
= new_palette
[0] & 0xFF;
184 for (x
= 0; x
< avctx
->width
; x
++) {
190 r
= new_palette
[index
] & 0xFF0000;
191 g
= new_palette
[index
] & 0xFF00;
192 b
= new_palette
[index
] & 0xFF;
195 b
= (index
<< 2) | (b
& 3);
198 r
= (index
<< 18) | (r
& (3 << 16));
201 g
= (index
<< 10) | (g
& (3 << 8));
204 AV_WL24(out
+ x
* 3, r
| g
| b
);
206 out
+= c
->frame
.linesize
[0];
210 static int cdxl_decode_frame(AVCodecContext
*avctx
, void *data
,
211 int *got_frame
, AVPacket
*pkt
)
213 CDXLVideoContext
*c
= avctx
->priv_data
;
214 AVFrame
* const p
= &c
->frame
;
215 int ret
, w
, h
, encoding
, aligned_width
, buf_size
= pkt
->size
;
216 const uint8_t *buf
= pkt
->data
;
219 return AVERROR_INVALIDDATA
;
220 encoding
= buf
[1] & 7;
221 c
->format
= buf
[1] & 0xE0;
222 w
= AV_RB16(&buf
[14]);
223 h
= AV_RB16(&buf
[16]);
225 c
->palette_size
= AV_RB16(&buf
[20]);
226 c
->palette
= buf
+ 32;
227 c
->video
= c
->palette
+ c
->palette_size
;
228 c
->video_size
= buf_size
- c
->palette_size
- 32;
230 if (c
->palette_size
> 512)
231 return AVERROR_INVALIDDATA
;
232 if (buf_size
< c
->palette_size
+ 32)
233 return AVERROR_INVALIDDATA
;
235 return AVERROR_INVALIDDATA
;
236 if (c
->format
!= BIT_PLANAR
&& c
->format
!= BIT_LINE
) {
237 av_log_ask_for_sample(avctx
, "unsupported pixel format: 0x%0x\n", c
->format
);
238 return AVERROR_PATCHWELCOME
;
241 if ((ret
= av_image_check_size(w
, h
, 0, avctx
)) < 0)
243 if (w
!= avctx
->width
|| h
!= avctx
->height
)
244 avcodec_set_dimensions(avctx
, w
, h
);
246 aligned_width
= FFALIGN(c
->avctx
->width
, 16);
247 c
->padded_bits
= aligned_width
- c
->avctx
->width
;
248 if (c
->video_size
< aligned_width
* avctx
->height
* c
->bpp
/ 8)
249 return AVERROR_INVALIDDATA
;
250 if (!encoding
&& c
->palette_size
&& c
->bpp
<= 8) {
251 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
252 } else if (encoding
== 1 && (c
->bpp
== 6 || c
->bpp
== 8)) {
253 if (c
->palette_size
!= (1 << (c
->bpp
- 1)))
254 return AVERROR_INVALIDDATA
;
255 avctx
->pix_fmt
= AV_PIX_FMT_BGR24
;
257 av_log_ask_for_sample(avctx
, "unsupported encoding %d and bpp %d\n",
259 return AVERROR_PATCHWELCOME
;
263 avctx
->release_buffer(avctx
, p
);
266 if ((ret
= ff_get_buffer(avctx
, p
)) < 0) {
267 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
270 p
->pict_type
= AV_PICTURE_TYPE_I
;
273 av_fast_padded_malloc(&c
->new_video
, &c
->new_video_size
,
274 h
* w
+ FF_INPUT_BUFFER_PADDING_SIZE
);
276 return AVERROR(ENOMEM
);
285 *(AVFrame
*)data
= c
->frame
;
290 static av_cold
int cdxl_decode_end(AVCodecContext
*avctx
)
292 CDXLVideoContext
*c
= avctx
->priv_data
;
294 av_free(c
->new_video
);
295 if (c
->frame
.data
[0])
296 avctx
->release_buffer(avctx
, &c
->frame
);
301 AVCodec ff_cdxl_decoder
= {
303 .type
= AVMEDIA_TYPE_VIDEO
,
304 .id
= AV_CODEC_ID_CDXL
,
305 .priv_data_size
= sizeof(CDXLVideoContext
),
306 .init
= cdxl_decode_init
,
307 .close
= cdxl_decode_end
,
308 .decode
= cdxl_decode_frame
,
309 .capabilities
= CODEC_CAP_DR1
,
310 .long_name
= NULL_IF_CONFIG_SMALL("Commodore CDXL video"),