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"
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
, int compressed
) {
48 unsigned char run
, value
;
51 while (i
<bytes_per_scanline
) {
58 while (i
<bytes_per_scanline
&& run
--)
62 memcpy(dst
, src
, bytes_per_scanline
);
63 src
+= bytes_per_scanline
;
69 static void pcx_palette(const uint8_t **src
, uint32_t *dst
, unsigned int pallen
) {
72 for (i
=0; i
<pallen
; i
++)
73 *dst
++ = bytestream_get_be24(src
);
74 memset(dst
, 0, (256 - pallen
) * sizeof(*dst
));
77 static int pcx_decode_frame(AVCodecContext
*avctx
, void *data
, int *data_size
,
79 const uint8_t *buf
= avpkt
->data
;
80 int buf_size
= avpkt
->size
;
81 PCXContext
* const s
= avctx
->priv_data
;
82 AVFrame
*picture
= data
;
83 AVFrame
* const p
= &s
->picture
;
84 int compressed
, xmin
, ymin
, xmax
, ymax
;
85 unsigned int w
, h
, bits_per_pixel
, bytes_per_line
, nplanes
, stride
, y
, x
,
88 uint8_t const *bufstart
= buf
;
90 if (buf
[0] != 0x0a || buf
[1] > 5) {
91 av_log(avctx
, AV_LOG_ERROR
, "this is not PCX encoded data\n");
96 xmin
= AV_RL16(buf
+ 4);
97 ymin
= AV_RL16(buf
+ 6);
98 xmax
= AV_RL16(buf
+ 8);
99 ymax
= AV_RL16(buf
+10);
101 if (xmax
< xmin
|| ymax
< ymin
) {
102 av_log(avctx
, AV_LOG_ERROR
, "invalid image dimensions\n");
109 bits_per_pixel
= buf
[3];
110 bytes_per_line
= AV_RL16(buf
+66);
112 bytes_per_scanline
= nplanes
* bytes_per_line
;
114 if (bytes_per_scanline
< w
* bits_per_pixel
* nplanes
/ 8) {
115 av_log(avctx
, AV_LOG_ERROR
, "PCX data is corrupted\n");
119 switch ((nplanes
<<8) + bits_per_pixel
) {
121 avctx
->pix_fmt
= PIX_FMT_RGB24
;
130 avctx
->pix_fmt
= PIX_FMT_PAL8
;
133 av_log(avctx
, AV_LOG_ERROR
, "invalid PCX file\n");
140 avctx
->release_buffer(avctx
, p
);
142 if (avcodec_check_dimensions(avctx
, w
, h
))
144 if (w
!= avctx
->width
|| h
!= avctx
->height
)
145 avcodec_set_dimensions(avctx
, w
, h
);
146 if (avctx
->get_buffer(avctx
, p
) < 0) {
147 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
151 p
->pict_type
= FF_I_TYPE
;
154 stride
= p
->linesize
[0];
156 if (nplanes
== 3 && bits_per_pixel
== 8) {
157 uint8_t scanline
[bytes_per_scanline
];
159 for (y
=0; y
<h
; y
++) {
160 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
162 for (x
=0; x
<w
; x
++) {
163 ptr
[3*x
] = scanline
[x
];
164 ptr
[3*x
+1] = scanline
[x
+ bytes_per_line
];
165 ptr
[3*x
+2] = scanline
[x
+(bytes_per_line
<<1)];
171 } else if (nplanes
== 1 && bits_per_pixel
== 8) {
172 uint8_t scanline
[bytes_per_scanline
];
173 const uint8_t *palstart
= bufstart
+ buf_size
- 769;
175 for (y
=0; y
<h
; y
++, ptr
+=stride
) {
176 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
177 memcpy(ptr
, scanline
, w
);
180 if (buf
!= palstart
) {
181 av_log(avctx
, AV_LOG_WARNING
, "image data possibly corrupted\n");
185 av_log(avctx
, AV_LOG_ERROR
, "expected palette after image data\n");
189 } else if (nplanes
== 1) { /* all packed formats, max. 16 colors */
190 uint8_t scanline
[bytes_per_scanline
];
193 for (y
=0; y
<h
; y
++) {
194 init_get_bits(&s
, scanline
, bytes_per_scanline
<<3);
196 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
199 ptr
[x
] = get_bits(&s
, bits_per_pixel
);
203 } else { /* planar, 4, 8 or 16 colors */
204 uint8_t scanline
[bytes_per_scanline
];
207 for (y
=0; y
<h
; y
++) {
208 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
210 for (x
=0; x
<w
; x
++) {
211 int m
= 0x80 >> (x
&7), v
= 0;
212 for (i
=nplanes
- 1; i
>=0; i
--) {
214 v
+= !!(scanline
[i
*bytes_per_line
+ (x
>>3)] & m
);
222 if (nplanes
== 1 && bits_per_pixel
== 8) {
223 pcx_palette(&buf
, (uint32_t *) p
->data
[1], 256);
224 } else if (bits_per_pixel
< 8) {
225 const uint8_t *palette
= bufstart
+16;
226 pcx_palette(&palette
, (uint32_t *) p
->data
[1], 16);
229 *picture
= s
->picture
;
230 *data_size
= sizeof(AVFrame
);
232 return buf
- bufstart
;
235 static av_cold
int pcx_end(AVCodecContext
*avctx
) {
236 PCXContext
*s
= avctx
->priv_data
;
238 if(s
->picture
.data
[0])
239 avctx
->release_buffer(avctx
, &s
->picture
);
244 AVCodec pcx_decoder
= {
255 .long_name
= NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),