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 Libav.
10 * Libav 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 * Libav 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 Libav; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "libavutil/imgutils.h"
27 #include "bytestream.h"
31 typedef struct PCXContext
{
35 static av_cold
int pcx_init(AVCodecContext
*avctx
) {
36 PCXContext
*s
= avctx
->priv_data
;
38 avcodec_get_frame_defaults(&s
->picture
);
39 avctx
->coded_frame
= &s
->picture
;
45 * @return advanced src pointer
47 static const uint8_t *pcx_rle_decode(const uint8_t *src
, uint8_t *dst
,
48 unsigned int bytes_per_scanline
, int compressed
) {
50 unsigned char run
, value
;
53 while (i
<bytes_per_scanline
) {
60 while (i
<bytes_per_scanline
&& run
--)
64 memcpy(dst
, src
, bytes_per_scanline
);
65 src
+= bytes_per_scanline
;
71 static void pcx_palette(const uint8_t **src
, uint32_t *dst
, unsigned int pallen
) {
74 for (i
=0; i
<pallen
; i
++)
75 *dst
++ = bytestream_get_be24(src
);
77 memset(dst
, 0, (256 - pallen
) * sizeof(*dst
));
80 static int pcx_decode_frame(AVCodecContext
*avctx
, void *data
, int *got_frame
,
82 const uint8_t *buf
= avpkt
->data
;
83 int buf_size
= avpkt
->size
;
84 PCXContext
* const s
= avctx
->priv_data
;
85 AVFrame
*picture
= data
;
86 AVFrame
* const p
= &s
->picture
;
87 int compressed
, xmin
, ymin
, xmax
, ymax
;
88 unsigned int w
, h
, bits_per_pixel
, bytes_per_line
, nplanes
, stride
, y
, x
,
91 uint8_t const *bufstart
= buf
;
95 if (buf
[0] != 0x0a || buf
[1] > 5) {
96 av_log(avctx
, AV_LOG_ERROR
, "this is not PCX encoded data\n");
97 return AVERROR_INVALIDDATA
;
101 xmin
= AV_RL16(buf
+ 4);
102 ymin
= AV_RL16(buf
+ 6);
103 xmax
= AV_RL16(buf
+ 8);
104 ymax
= AV_RL16(buf
+10);
106 if (xmax
< xmin
|| ymax
< ymin
) {
107 av_log(avctx
, AV_LOG_ERROR
, "invalid image dimensions\n");
108 return AVERROR_INVALIDDATA
;
114 bits_per_pixel
= buf
[3];
115 bytes_per_line
= AV_RL16(buf
+66);
117 bytes_per_scanline
= nplanes
* bytes_per_line
;
119 if (bytes_per_scanline
< w
* bits_per_pixel
* nplanes
/ 8) {
120 av_log(avctx
, AV_LOG_ERROR
, "PCX data is corrupted\n");
121 return AVERROR_INVALIDDATA
;
124 switch ((nplanes
<<8) + bits_per_pixel
) {
126 avctx
->pix_fmt
= AV_PIX_FMT_RGB24
;
135 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
138 av_log(avctx
, AV_LOG_ERROR
, "invalid PCX file\n");
139 return AVERROR_INVALIDDATA
;
145 avctx
->release_buffer(avctx
, p
);
147 if ((ret
= av_image_check_size(w
, h
, 0, avctx
)) < 0)
149 if (w
!= avctx
->width
|| h
!= avctx
->height
)
150 avcodec_set_dimensions(avctx
, w
, h
);
151 if ((ret
= ff_get_buffer(avctx
, p
)) < 0) {
152 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
156 p
->pict_type
= AV_PICTURE_TYPE_I
;
159 stride
= p
->linesize
[0];
161 scanline
= av_malloc(bytes_per_scanline
);
163 return AVERROR(ENOMEM
);
165 if (nplanes
== 3 && bits_per_pixel
== 8) {
166 for (y
=0; y
<h
; y
++) {
167 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
169 for (x
=0; x
<w
; x
++) {
170 ptr
[3*x
] = scanline
[x
];
171 ptr
[3*x
+1] = scanline
[x
+ bytes_per_line
];
172 ptr
[3*x
+2] = scanline
[x
+(bytes_per_line
<<1)];
178 } else if (nplanes
== 1 && bits_per_pixel
== 8) {
179 const uint8_t *palstart
= bufstart
+ buf_size
- 769;
181 for (y
=0; y
<h
; y
++, ptr
+=stride
) {
182 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
183 memcpy(ptr
, scanline
, w
);
186 if (buf
!= palstart
) {
187 av_log(avctx
, AV_LOG_WARNING
, "image data possibly corrupted\n");
191 av_log(avctx
, AV_LOG_ERROR
, "expected palette after image data\n");
195 } else if (nplanes
== 1) { /* all packed formats, max. 16 colors */
198 for (y
=0; y
<h
; y
++) {
199 init_get_bits(&s
, scanline
, bytes_per_scanline
<<3);
201 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
204 ptr
[x
] = get_bits(&s
, bits_per_pixel
);
208 } else { /* planar, 4, 8 or 16 colors */
211 for (y
=0; y
<h
; y
++) {
212 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
214 for (x
=0; x
<w
; x
++) {
215 int m
= 0x80 >> (x
&7), v
= 0;
216 for (i
=nplanes
- 1; i
>=0; i
--) {
218 v
+= !!(scanline
[i
*bytes_per_line
+ (x
>>3)] & m
);
226 if (nplanes
== 1 && bits_per_pixel
== 8) {
227 pcx_palette(&buf
, (uint32_t *) p
->data
[1], 256);
228 } else if (bits_per_pixel
< 8) {
229 const uint8_t *palette
= bufstart
+16;
230 pcx_palette(&palette
, (uint32_t *) p
->data
[1], 16);
233 *picture
= s
->picture
;
236 ret
= buf
- bufstart
;
242 static av_cold
int pcx_end(AVCodecContext
*avctx
) {
243 PCXContext
*s
= avctx
->priv_data
;
245 if(s
->picture
.data
[0])
246 avctx
->release_buffer(avctx
, &s
->picture
);
251 AVCodec ff_pcx_decoder
= {
253 .type
= AVMEDIA_TYPE_VIDEO
,
254 .id
= AV_CODEC_ID_PCX
,
255 .priv_data_size
= sizeof(PCXContext
),
258 .decode
= pcx_decode_frame
,
259 .capabilities
= CODEC_CAP_DR1
,
260 .long_name
= NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),