pcx.c
Go to the documentation of this file.
1 /*
2  * PC Paintbrush PCX (.pcx) image decoder
3  * Copyright (c) 2007, 2008 Ivo van Poorten
4  *
5  * This decoder does not support CGA palettes. I am unable to find samples
6  * and Netpbm cannot generate them.
7  *
8  * This file is part of FFmpeg.
9  *
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.
14  *
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.
19  *
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
23  */
24 
25 #include "libavutil/imgutils.h"
26 #include "avcodec.h"
27 #include "bytestream.h"
28 #include "get_bits.h"
29 #include "internal.h"
30 
32  unsigned int bytes_per_scanline, int compressed)
33 {
34  unsigned int i = 0;
35  unsigned char run, value;
36 
37  if (compressed) {
38  while (i<bytes_per_scanline) {
39  run = 1;
40  value = bytestream2_get_byte(gb);
41  if (value >= 0xc0) {
42  run = value & 0x3f;
43  value = bytestream2_get_byte(gb);
44  }
45  while (i<bytes_per_scanline && run--)
46  dst[i++] = value;
47  }
48  } else {
49  bytestream2_get_buffer(gb, dst, bytes_per_scanline);
50  }
51 }
52 
53 static void pcx_palette(GetByteContext *gb, uint32_t *dst, int pallen)
54 {
55  int i;
56 
57  pallen = FFMIN(pallen, bytestream2_get_bytes_left(gb) / 3);
58  for (i=0; i<pallen; i++)
59  *dst++ = 0xFF000000 | bytestream2_get_be24u(gb);
60  if (pallen < 256)
61  memset(dst, 0, (256 - pallen) * sizeof(*dst));
62 }
63 
64 static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
65  AVPacket *avpkt) {
66  GetByteContext gb;
67  AVFrame * const p = data;
68  int compressed, xmin, ymin, xmax, ymax, ret;
69  unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x,
70  bytes_per_scanline;
71  uint8_t *ptr, *scanline;
72 
73  if (avpkt->size < 128)
74  return AVERROR_INVALIDDATA;
75 
76  bytestream2_init(&gb, avpkt->data, avpkt->size);
77 
78  if (bytestream2_get_byteu(&gb) != 0x0a || bytestream2_get_byteu(&gb) > 5) {
79  av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n");
80  return AVERROR_INVALIDDATA;
81  }
82 
83  compressed = bytestream2_get_byteu(&gb);
84  bits_per_pixel = bytestream2_get_byteu(&gb);
85  xmin = bytestream2_get_le16u(&gb);
86  ymin = bytestream2_get_le16u(&gb);
87  xmax = bytestream2_get_le16u(&gb);
88  ymax = bytestream2_get_le16u(&gb);
89  avctx->sample_aspect_ratio.num = bytestream2_get_le16u(&gb);
90  avctx->sample_aspect_ratio.den = bytestream2_get_le16u(&gb);
91 
92  if (xmax < xmin || ymax < ymin) {
93  av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n");
94  return AVERROR_INVALIDDATA;
95  }
96 
97  w = xmax - xmin + 1;
98  h = ymax - ymin + 1;
99 
100  bytestream2_skipu(&gb, 49);
101  nplanes = bytestream2_get_byteu(&gb);
102  bytes_per_line = bytestream2_get_le16u(&gb);
103  bytes_per_scanline = nplanes * bytes_per_line;
104 
105  if (bytes_per_scanline < (w * bits_per_pixel * nplanes + 7) / 8) {
106  av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n");
107  return AVERROR_INVALIDDATA;
108  }
109 
110  switch ((nplanes<<8) + bits_per_pixel) {
111  case 0x0308:
112  avctx->pix_fmt = AV_PIX_FMT_RGB24;
113  break;
114  case 0x0108:
115  case 0x0104:
116  case 0x0102:
117  case 0x0101:
118  case 0x0401:
119  case 0x0301:
120  case 0x0201:
121  avctx->pix_fmt = AV_PIX_FMT_PAL8;
122  break;
123  default:
124  av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n");
125  return AVERROR_INVALIDDATA;
126  }
127 
128  bytestream2_skipu(&gb, 60);
129 
130  if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
131  return ret;
132  if (w != avctx->width || h != avctx->height)
133  avcodec_set_dimensions(avctx, w, h);
134  if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
135  return ret;
136 
138 
139  ptr = p->data[0];
140  stride = p->linesize[0];
141 
142  scanline = av_malloc(bytes_per_scanline + FF_INPUT_BUFFER_PADDING_SIZE);
143  if (!scanline)
144  return AVERROR(ENOMEM);
145 
146  if (nplanes == 3 && bits_per_pixel == 8) {
147  for (y=0; y<h; y++) {
148  pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
149 
150  for (x=0; x<w; x++) {
151  ptr[3*x ] = scanline[x ];
152  ptr[3*x+1] = scanline[x+ bytes_per_line ];
153  ptr[3*x+2] = scanline[x+(bytes_per_line<<1)];
154  }
155 
156  ptr += stride;
157  }
158 
159  } else if (nplanes == 1 && bits_per_pixel == 8) {
160  int palstart = avpkt->size - 769;
161 
162  for (y=0; y<h; y++, ptr+=stride) {
163  pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
164  memcpy(ptr, scanline, w);
165  }
166 
167  if (bytestream2_tell(&gb) != palstart) {
168  av_log(avctx, AV_LOG_WARNING, "image data possibly corrupted\n");
169  bytestream2_seek(&gb, palstart, SEEK_SET);
170  }
171  if (bytestream2_get_byte(&gb) != 12) {
172  av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n");
173  ret = AVERROR_INVALIDDATA;
174  goto end;
175  }
176 
177  } else if (nplanes == 1) { /* all packed formats, max. 16 colors */
179 
180  for (y=0; y<h; y++) {
181  init_get_bits8(&s, scanline, bytes_per_scanline);
182 
183  pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
184 
185  for (x=0; x<w; x++)
186  ptr[x] = get_bits(&s, bits_per_pixel);
187  ptr += stride;
188  }
189 
190  } else { /* planar, 4, 8 or 16 colors */
191  int i;
192 
193  for (y=0; y<h; y++) {
194  pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
195 
196  for (x=0; x<w; x++) {
197  int m = 0x80 >> (x&7), v = 0;
198  for (i=nplanes - 1; i>=0; i--) {
199  v <<= 1;
200  v += !!(scanline[i*bytes_per_line + (x>>3)] & m);
201  }
202  ptr[x] = v;
203  }
204  ptr += stride;
205  }
206  }
207 
208  ret = bytestream2_tell(&gb);
209  if (nplanes == 1 && bits_per_pixel == 8) {
210  pcx_palette(&gb, (uint32_t *) p->data[1], 256);
211  ret += 256 * 3;
212  } else if (bits_per_pixel * nplanes == 1) {
213  AV_WN32A(p->data[1] , 0xFF000000);
214  AV_WN32A(p->data[1]+4, 0xFFFFFFFF);
215  } else if (bits_per_pixel < 8) {
216  bytestream2_seek(&gb, 16, SEEK_SET);
217  pcx_palette(&gb, (uint32_t *) p->data[1], 16);
218  }
219 
220  *got_frame = 1;
221 
222 end:
223  av_free(scanline);
224  return ret;
225 }
226 
228  .name = "pcx",
229  .type = AVMEDIA_TYPE_VIDEO,
230  .id = AV_CODEC_ID_PCX,
231  .decode = pcx_decode_frame,
232  .capabilities = CODEC_CAP_DR1,
233  .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),
234 };
float v
const char * s
Definition: avisynth_c.h:668
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
misc image utilities
static unsigned int get_bits(GetBitContext *s, int n)
Read 1-25 bits.
Definition: get_bits.h:240
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:70
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
int num
numerator
Definition: rational.h:44
void avcodec_set_dimensions(AVCodecContext *s, int width, int height)
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown) That is the width of a pixel divided by the height of the pixel...
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:130
AVCodec ff_pcx_decoder
Definition: pcx.c:227
uint8_t run
Definition: svq3.c:136
int stride
Definition: mace.c:144
#define AV_WN32A(p, v)
Definition: intreadwrite.h:530
output residual component w
uint8_t
8 bit with PIX_FMT_RGB32 palette
Definition: pixfmt.h:79
window constants for m
end end
#define CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
uint8_t * data
static av_always_inline void bytestream2_skipu(GetByteContext *g, unsigned int size)
Definition: bytestream.h:165
bitstream reader API header.
static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: pcx.c:64
Discrete Time axis x
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Spectrum Plot time data
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:258
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:149
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
const char * name
Name of the codec implementation.
external API header
#define FF_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
Definition: imgutils.c:231
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:144
#define FFMIN(a, b)
Definition: common.h:58
ret
Definition: avfilter.c:821
int width
picture width / height.
static void pcx_palette(GetByteContext *gb, uint32_t *dst, int pallen)
Definition: pcx.c:53
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:183
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
static int init_get_bits8(GetBitContext *s, const uint8_t *buffer, int byte_size)
Initialize GetBitContext.
Definition: get_bits.h:410
main external API structure.
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
double value
Definition: eval.c:82
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
synthesis window for stochastic i
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
static void pcx_rle_decode(GetByteContext *gb, uint8_t *dst, unsigned int bytes_per_scanline, int compressed)
Definition: pcx.c:31
common internal api header.
int den
denominator
Definition: rational.h:45
function y
Definition: D.m:1
else dst[i][x+y *dst_stride[i]]
Definition: vf_mcdeint.c:160
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:203
This structure stores compressed data.