45e751b389d9422d61020f2a2367ad6789f0274c
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"
30 typedef struct PCXContext
{
34 static av_cold
int pcx_init(AVCodecContext
*avctx
) {
35 PCXContext
*s
= avctx
->priv_data
;
37 avcodec_get_frame_defaults(&s
->picture
);
38 avctx
->coded_frame
= &s
->picture
;
44 * @return advanced src pointer
46 static const uint8_t *pcx_rle_decode(const uint8_t *src
, uint8_t *dst
,
47 unsigned int bytes_per_scanline
, int compressed
) {
49 unsigned char run
, value
;
52 while (i
<bytes_per_scanline
) {
59 while (i
<bytes_per_scanline
&& run
--)
63 memcpy(dst
, src
, bytes_per_scanline
);
64 src
+= bytes_per_scanline
;
70 static void pcx_palette(const uint8_t **src
, uint32_t *dst
, unsigned int pallen
) {
73 for (i
=0; i
<pallen
; i
++)
74 *dst
++ = bytestream_get_be24(src
);
76 memset(dst
, 0, (256 - pallen
) * sizeof(*dst
));
79 static int pcx_decode_frame(AVCodecContext
*avctx
, void *data
, int *data_size
,
81 const uint8_t *buf
= avpkt
->data
;
82 int buf_size
= avpkt
->size
;
83 PCXContext
* const s
= avctx
->priv_data
;
84 AVFrame
*picture
= data
;
85 AVFrame
* const p
= &s
->picture
;
86 int compressed
, xmin
, ymin
, xmax
, ymax
;
87 unsigned int w
, h
, bits_per_pixel
, bytes_per_line
, nplanes
, stride
, y
, x
,
90 uint8_t const *bufstart
= buf
;
94 if (buf
[0] != 0x0a || buf
[1] > 5) {
95 av_log(avctx
, AV_LOG_ERROR
, "this is not PCX encoded data\n");
100 xmin
= AV_RL16(buf
+ 4);
101 ymin
= AV_RL16(buf
+ 6);
102 xmax
= AV_RL16(buf
+ 8);
103 ymax
= AV_RL16(buf
+10);
105 if (xmax
< xmin
|| ymax
< ymin
) {
106 av_log(avctx
, AV_LOG_ERROR
, "invalid image dimensions\n");
113 bits_per_pixel
= buf
[3];
114 bytes_per_line
= AV_RL16(buf
+66);
116 bytes_per_scanline
= nplanes
* bytes_per_line
;
118 if (bytes_per_scanline
< w
* bits_per_pixel
* nplanes
/ 8) {
119 av_log(avctx
, AV_LOG_ERROR
, "PCX data is corrupted\n");
123 switch ((nplanes
<<8) + bits_per_pixel
) {
125 avctx
->pix_fmt
= AV_PIX_FMT_RGB24
;
134 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
137 av_log(avctx
, AV_LOG_ERROR
, "invalid PCX file\n");
144 avctx
->release_buffer(avctx
, p
);
146 if (av_image_check_size(w
, h
, 0, avctx
))
148 if (w
!= avctx
->width
|| h
!= avctx
->height
)
149 avcodec_set_dimensions(avctx
, w
, h
);
150 if (avctx
->get_buffer(avctx
, p
) < 0) {
151 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
155 p
->pict_type
= AV_PICTURE_TYPE_I
;
158 stride
= p
->linesize
[0];
160 scanline
= av_malloc(bytes_per_scanline
);
162 return AVERROR(ENOMEM
);
164 if (nplanes
== 3 && bits_per_pixel
== 8) {
165 for (y
=0; y
<h
; y
++) {
166 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
168 for (x
=0; x
<w
; x
++) {
169 ptr
[3*x
] = scanline
[x
];
170 ptr
[3*x
+1] = scanline
[x
+ bytes_per_line
];
171 ptr
[3*x
+2] = scanline
[x
+(bytes_per_line
<<1)];
177 } else if (nplanes
== 1 && bits_per_pixel
== 8) {
178 const uint8_t *palstart
= bufstart
+ buf_size
- 769;
180 for (y
=0; y
<h
; y
++, ptr
+=stride
) {
181 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
182 memcpy(ptr
, scanline
, w
);
185 if (buf
!= palstart
) {
186 av_log(avctx
, AV_LOG_WARNING
, "image data possibly corrupted\n");
190 av_log(avctx
, AV_LOG_ERROR
, "expected palette after image data\n");
194 } else if (nplanes
== 1) { /* all packed formats, max. 16 colors */
197 for (y
=0; y
<h
; y
++) {
198 init_get_bits(&s
, scanline
, bytes_per_scanline
<<3);
200 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
203 ptr
[x
] = get_bits(&s
, bits_per_pixel
);
207 } else { /* planar, 4, 8 or 16 colors */
210 for (y
=0; y
<h
; y
++) {
211 buf
= pcx_rle_decode(buf
, scanline
, bytes_per_scanline
, compressed
);
213 for (x
=0; x
<w
; x
++) {
214 int m
= 0x80 >> (x
&7), v
= 0;
215 for (i
=nplanes
- 1; i
>=0; i
--) {
217 v
+= !!(scanline
[i
*bytes_per_line
+ (x
>>3)] & m
);
225 if (nplanes
== 1 && bits_per_pixel
== 8) {
226 pcx_palette(&buf
, (uint32_t *) p
->data
[1], 256);
227 } else if (bits_per_pixel
< 8) {
228 const uint8_t *palette
= bufstart
+16;
229 pcx_palette(&palette
, (uint32_t *) p
->data
[1], 16);
232 *picture
= s
->picture
;
233 *data_size
= sizeof(AVFrame
);
235 ret
= buf
- bufstart
;
241 static av_cold
int pcx_end(AVCodecContext
*avctx
) {
242 PCXContext
*s
= avctx
->priv_data
;
244 if(s
->picture
.data
[0])
245 avctx
->release_buffer(avctx
, &s
->picture
);
250 AVCodec ff_pcx_decoder
= {
252 .type
= AVMEDIA_TYPE_VIDEO
,
253 .id
= AV_CODEC_ID_PCX
,
254 .priv_data_size
= sizeof(PCXContext
),
257 .decode
= pcx_decode_frame
,
258 .capabilities
= CODEC_CAP_DR1
,
259 .long_name
= NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),