2 * PC Paintbrush PCX (.pcx) image decoder
3 * Copyright (c) 2007, 2008 Ivo van Poorten
5 * This decoder does not support CGA palettes. I am unable to find samples
6 * and Netpbm cannot generate them.
8 * This file is part of FFmpeg.
10 * FFmpeg is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * FFmpeg is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with FFmpeg; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "bytestream.h"
27 #include "bitstream.h"
29 typedef struct PCXContext
{
33 static av_cold
int pcx_init(AVCodecContext
*avctx
) {
34 PCXContext
*s
= avctx
->priv_data
;
36 avcodec_get_frame_defaults(&s
->picture
);
37 avctx
->coded_frame
= &s
->picture
;
43 * @return advanced src pointer
45 static const uint8_t *pcx_rle_decode(const uint8_t *src
, uint8_t *dst
,
46 unsigned int bytes_per_scanline
) {
48 unsigned char run
, value
;
50 while (i
<bytes_per_scanline
) {
57 while (i
<bytes_per_scanline
&& run
--)
64 static void pcx_palette(const uint8_t **src
, uint32_t *dst
, unsigned int pallen
) {
67 for (i
=0; i
<pallen
; i
++)
68 *dst
++ = bytestream_get_be24(src
);
69 memset(dst
, 0, (256 - pallen
) * sizeof(*dst
));
72 static int pcx_decode_frame(AVCodecContext
*avctx
, void *data
, int *data_size
,
73 const uint8_t *buf
, int buf_size
) {
74 PCXContext
* const s
= avctx
->priv_data
;
75 AVFrame
*picture
= data
;
76 AVFrame
* const p
= &s
->picture
;
77 int xmin
, ymin
, xmax
, ymax
;
78 unsigned int w
, h
, bits_per_pixel
, bytes_per_line
, nplanes
, stride
, y
, x
,
81 uint8_t const *bufstart
= buf
;
83 if (buf
[0] != 0x0a || buf
[1] > 5 || buf
[1] == 1 || buf
[2] != 1) {
84 av_log(avctx
, AV_LOG_ERROR
, "this is not PCX encoded data\n");
88 xmin
= AV_RL16(buf
+ 4);
89 ymin
= AV_RL16(buf
+ 6);
90 xmax
= AV_RL16(buf
+ 8);
91 ymax
= AV_RL16(buf
+10);
93 if (xmax
< xmin
|| ymax
< ymin
) {
94 av_log(avctx
, AV_LOG_ERROR
, "invalid image dimensions\n");
101 bits_per_pixel
= buf
[3];
102 bytes_per_line
= AV_RL16(buf
+66);
104 bytes_per_scanline
= nplanes
* bytes_per_line
;
106 if (bytes_per_scanline
< w
* bits_per_pixel
* nplanes
/ 8) {
107 av_log(avctx
, AV_LOG_ERROR
, "PCX data is corrupted\n");
111 switch ((nplanes
<<8) + bits_per_pixel
) {
113 avctx
->pix_fmt
= PIX_FMT_RGB24
;
122 avctx
->pix_fmt
= PIX_FMT_PAL8
;
125 av_log(avctx
, AV_LOG_ERROR
, "invalid PCX file\n");
132 avctx
->release_buffer(avctx
, p
);
134 if (avcodec_check_dimensions(avctx
, w
, h
))
136 if (w
!= avctx
->width
|| h
!= avctx
->height
)
137 avcodec_set_dimensions(avctx
, w
, h
);
138 if (avctx
->get_buffer(avctx
, p
) < 0) {
139 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
143 p
->pict_type
= FF_I_TYPE
;
146 stride
= p
->linesize
[0];
148 if (nplanes
== 3 && bits_per_pixel
== 8) {
149 uint8_t scanline
[bytes_per_scanline
];
151 for (y
=0; y
<h
; y
++) {
152 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
);
154 for (x
=0; x
<w
; x
++) {
155 ptr
[3*x
] = scanline
[x
];
156 ptr
[3*x
+1] = scanline
[x
+ bytes_per_line
];
157 ptr
[3*x
+2] = scanline
[x
+(bytes_per_line
<<1)];
163 } else if (nplanes
== 1 && bits_per_pixel
== 8) {
164 uint8_t scanline
[bytes_per_scanline
];
165 const uint8_t *palstart
= bufstart
+ buf_size
- 769;
167 for (y
=0; y
<h
; y
++, ptr
+=stride
) {
168 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
);
169 memcpy(ptr
, scanline
, w
);
172 if (buf
!= palstart
) {
173 av_log(avctx
, AV_LOG_WARNING
, "image data possibly corrupted\n");
177 av_log(avctx
, AV_LOG_ERROR
, "expected palette after image data\n");
181 } else if (nplanes
== 1) { /* all packed formats, max. 16 colors */
182 uint8_t scanline
[bytes_per_scanline
];
185 for (y
=0; y
<h
; y
++) {
186 init_get_bits(&s
, scanline
, bytes_per_scanline
<<3);
188 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
);
191 ptr
[x
] = get_bits(&s
, bits_per_pixel
);
195 } else { /* planar, 4, 8 or 16 colors */
196 uint8_t scanline
[bytes_per_scanline
];
199 for (y
=0; y
<h
; y
++) {
200 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
);
202 for (x
=0; x
<w
; x
++) {
203 int m
= 0x80 >> (x
&7), v
= 0;
204 for (i
=nplanes
- 1; i
>=0; i
--) {
206 v
+= !!(scanline
[i
*bytes_per_line
+ (x
>>3)] & m
);
214 if (nplanes
== 1 && bits_per_pixel
== 8) {
215 pcx_palette(&buf
, (uint32_t *) p
->data
[1], 256);
216 } else if (bits_per_pixel
< 8) {
217 const uint8_t *palette
= bufstart
+16;
218 pcx_palette(&palette
, (uint32_t *) p
->data
[1], 16);
221 *picture
= s
->picture
;
222 *data_size
= sizeof(AVFrame
);
224 return buf
- bufstart
;
227 static av_cold
int pcx_end(AVCodecContext
*avctx
) {
228 PCXContext
*s
= avctx
->priv_data
;
230 if(s
->picture
.data
[0])
231 avctx
->release_buffer(avctx
, &s
->picture
);
236 AVCodec pcx_decoder
= {
247 .long_name
= NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),