FFmpeg
pictordec.c
Go to the documentation of this file.
1 /*
2  * Pictor/PC Paint decoder
3  * Copyright (c) 2010 Peter Ross <pross@xvid.org>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * Pictor/PC Paint decoder
25  */
26 
27 #include "libavutil/imgutils.h"
28 #include "avcodec.h"
29 #include "bytestream.h"
30 #include "cga_data.h"
31 #include "internal.h"
32 
33 typedef struct PicContext {
34  int width, height;
35  int nb_planes;
37 } PicContext;
38 
39 static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run,
40  int *x, int *y)
41 {
42  while (run > 0) {
43  uint8_t *d = frame->data[0] + *y * frame->linesize[0];
44  if (*x + run >= s->width) {
45  int n = s->width - *x;
46  memset(d + *x, value, n);
47  run -= n;
48  *x = 0;
49  *y -= 1;
50  if (*y < 0)
51  break;
52  } else {
53  memset(d + *x, value, run);
54  *x += run;
55  break;
56  }
57  }
58 }
59 
60 static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run,
61  int *x, int *y, int *plane, int bits_per_plane)
62 {
63  uint8_t *d;
64  int shift = *plane * bits_per_plane;
65  unsigned mask = ((1U << bits_per_plane) - 1) << shift;
66  int xl = *x;
67  int yl = *y;
68  int planel = *plane;
69  int pixels_per_value = 8/bits_per_plane;
70  value <<= shift;
71 
72  d = frame->data[0] + yl * frame->linesize[0];
73  while (run > 0) {
74  int j;
75  for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
76  d[xl] |= (value >> j) & mask;
77  xl += 1;
78  while (xl == s->width) {
79  yl -= 1;
80  xl = 0;
81  if (yl < 0) {
82  yl = s->height - 1;
83  planel += 1;
84  if (planel >= s->nb_planes)
85  goto end;
86  value <<= bits_per_plane;
87  mask <<= bits_per_plane;
88  }
89  d = frame->data[0] + yl * frame->linesize[0];
90  if (s->nb_planes == 1 &&
91  run*pixels_per_value >= s->width &&
92  pixels_per_value < s->width &&
93  s->width % pixels_per_value == 0
94  ) {
95  for (; xl < pixels_per_value; xl ++) {
96  j = (j < bits_per_plane ? 8 : j) - bits_per_plane;
97  d[xl] |= (value >> j) & mask;
98  }
99  av_memcpy_backptr(d+xl, pixels_per_value, s->width - xl);
100  run -= s->width / pixels_per_value;
101  xl = s->width;
102  }
103  }
104  }
105  run--;
106  }
107 end:
108  *x = xl;
109  *y = yl;
110  *plane = planel;
111 }
112 
113 static const uint8_t cga_mode45_index[6][4] = {
114  [0] = { 0, 3, 5, 7 }, // mode4, palette#1, low intensity
115  [1] = { 0, 2, 4, 6 }, // mode4, palette#2, low intensity
116  [2] = { 0, 3, 4, 7 }, // mode5, low intensity
117  [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
118  [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
119  [5] = { 0, 11, 12, 15 }, // mode5, high intensity
120 };
121 
122 static int decode_frame(AVCodecContext *avctx,
123  void *data, int *got_frame,
124  AVPacket *avpkt)
125 {
126  PicContext *s = avctx->priv_data;
127  AVFrame *frame = data;
128  uint32_t *palette;
129  int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
130  int i, x, y, plane, tmp, ret, val;
131 
132  bytestream2_init(&s->g, avpkt->data, avpkt->size);
133 
134  if (bytestream2_get_bytes_left(&s->g) < 11)
135  return AVERROR_INVALIDDATA;
136 
137  if (bytestream2_get_le16u(&s->g) != 0x1234)
138  return AVERROR_INVALIDDATA;
139 
140  s->width = bytestream2_get_le16u(&s->g);
141  s->height = bytestream2_get_le16u(&s->g);
142  bytestream2_skip(&s->g, 4);
143  tmp = bytestream2_get_byteu(&s->g);
144  bits_per_plane = tmp & 0xF;
145  s->nb_planes = (tmp >> 4) + 1;
146  bpp = bits_per_plane * s->nb_planes;
147  if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
148  avpriv_request_sample(avctx, "Unsupported bit depth");
149  return AVERROR_PATCHWELCOME;
150  }
151 
152  if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
153  bytestream2_skip(&s->g, 2);
154  etype = bytestream2_get_le16(&s->g);
155  esize = bytestream2_get_le16(&s->g);
156  if (bytestream2_get_bytes_left(&s->g) < esize)
157  return AVERROR_INVALIDDATA;
158  } else {
159  etype = -1;
160  esize = 0;
161  }
162 
163  avctx->pix_fmt = AV_PIX_FMT_PAL8;
164 
165  if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
166  return -1;
167  if (s->width != avctx->width || s->height != avctx->height) {
168  ret = ff_set_dimensions(avctx, s->width, s->height);
169  if (ret < 0)
170  return ret;
171  }
172 
173  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
174  return ret;
175  memset(frame->data[0], 0, s->height * frame->linesize[0]);
176  frame->pict_type = AV_PICTURE_TYPE_I;
177  frame->palette_has_changed = 1;
178 
179  pos_after_pal = bytestream2_tell(&s->g) + esize;
180  palette = (uint32_t*)frame->data[1];
181  if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
182  int idx = bytestream2_get_byte(&s->g);
183  npal = 4;
184  for (i = 0; i < npal; i++)
185  palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
186  } else if (etype == 2) {
187  npal = FFMIN(esize, 16);
188  for (i = 0; i < npal; i++) {
189  int pal_idx = bytestream2_get_byte(&s->g);
190  palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)];
191  }
192  } else if (etype == 3) {
193  npal = FFMIN(esize, 16);
194  for (i = 0; i < npal; i++) {
195  int pal_idx = bytestream2_get_byte(&s->g);
196  palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)];
197  }
198  } else if (etype == 4 || etype == 5) {
199  npal = FFMIN(esize / 3, 256);
200  for (i = 0; i < npal; i++) {
201  palette[i] = bytestream2_get_be24(&s->g) << 2;
202  palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
203  }
204  } else {
205  if (bpp == 1) {
206  npal = 2;
207  palette[0] = 0xFF000000;
208  palette[1] = 0xFFFFFFFF;
209  } else if (bpp == 2) {
210  npal = 4;
211  for (i = 0; i < npal; i++)
212  palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
213  } else {
214  npal = 16;
215  memcpy(palette, ff_cga_palette, npal * 4);
216  }
217  }
218  // fill remaining palette entries
219  memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
220  // skip remaining palette bytes
221  bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
222 
223  val = 0;
224  y = s->height - 1;
225  if (bytestream2_get_le16(&s->g)) {
226  x = 0;
227  plane = 0;
228  while (bytestream2_get_bytes_left(&s->g) >= 6) {
229  int stop_size, marker, t1, t2;
230 
231  t1 = bytestream2_get_bytes_left(&s->g);
232  t2 = bytestream2_get_le16(&s->g);
233  stop_size = t1 - FFMIN(t1, t2);
234  // ignore uncompressed block size
235  bytestream2_skip(&s->g, 2);
236  marker = bytestream2_get_byte(&s->g);
237 
238  while (plane < s->nb_planes &&
239  bytestream2_get_bytes_left(&s->g) > stop_size) {
240  int run = 1;
241  val = bytestream2_get_byte(&s->g);
242  if (val == marker) {
243  run = bytestream2_get_byte(&s->g);
244  if (run == 0)
245  run = bytestream2_get_le16(&s->g);
246  val = bytestream2_get_byte(&s->g);
247  }
248  if (!bytestream2_get_bytes_left(&s->g))
249  break;
250 
251  if (bits_per_plane == 8) {
252  picmemset_8bpp(s, frame, val, run, &x, &y);
253  if (y < 0)
254  goto finish;
255  } else {
256  picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
257  }
258  }
259  }
260 
261  if (s->nb_planes - plane > 1)
262  return AVERROR_INVALIDDATA;
263 
264  if (plane < s->nb_planes && x < avctx->width) {
265  int run = (y + 1) * avctx->width - x;
266  if (bits_per_plane == 8)
267  picmemset_8bpp(s, frame, val, run, &x, &y);
268  else
269  picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
270  }
271  } else {
272  while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
273  memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
274  bytestream2_skip(&s->g, avctx->width);
275  y--;
276  }
277  }
278 finish:
279 
280  *got_frame = 1;
281  return avpkt->size;
282 }
283 
285  .name = "pictor",
286  .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
287  .type = AVMEDIA_TYPE_VIDEO,
288  .id = AV_CODEC_ID_PICTOR,
289  .priv_data_size = sizeof(PicContext),
290  .decode = decode_frame,
291  .capabilities = AV_CODEC_CAP_DR1,
292 };
int plane
Definition: avisynth_c.h:384
const char const char void * val
Definition: avisynth_c.h:863
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
static int shift(int a, int b)
Definition: sonic.c:82
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run, int *x, int *y)
Definition: pictordec.c:39
misc image utilities
int width
Definition: pictordec.c:34
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:104
#define avpriv_request_sample(...)
int size
Definition: avcodec.h:1481
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1778
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
uint8_t run
Definition: svq3.c:206
AVCodec.
Definition: avcodec.h:3492
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:71
static const uint8_t cga_mode45_index[6][4]
Definition: pictordec.c:113
uint8_t
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
GLsizei GLboolean const GLfloat * value
Definition: opengl_enc.c:108
static void finish(void)
Definition: movenc.c:345
uint8_t * data
Definition: avcodec.h:1480
const uint8_t * buffer
Definition: bytestream.h:34
CGA/EGA/VGA ROM data.
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
Overlapping memcpy() implementation.
Definition: mem.c:426
GetByteContext g
Definition: pictordec.c:36
#define U(x)
Definition: vp56_arith.h:37
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
static const uint16_t mask[17]
Definition: lzw.c:38
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
#define t1
Definition: regdef.h:29
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
const char * name
Name of the codec implementation.
Definition: avcodec.h:3499
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:282
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:378
#define FFMIN(a, b)
Definition: common.h:96
int width
picture width / height.
Definition: avcodec.h:1741
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
#define s(width, name)
Definition: cbs_vp9.c:257
int n
Definition: avisynth_c.h:760
if(ret)
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:188
Libavcodec external API header.
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: pictordec.c:122
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
main external API structure.
Definition: avcodec.h:1568
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1968
AVCodec ff_pictor_decoder
Definition: pictordec.c:284
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:452
int height
Definition: pictordec.c:34
const uint32_t ff_cga_palette[16]
Definition: cga_data.c:30
const uint32_t ff_ega_palette[64]
Definition: cga_data.c:35
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
common internal api header.
void * priv_data
Definition: avcodec.h:1595
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:208
int nb_planes
Definition: pictordec.c:35
This structure stores compressed data.
Definition: avcodec.h:1457
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:984
#define t2
Definition: regdef.h:30
static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run, int *x, int *y, int *plane, int bits_per_plane)
Definition: pictordec.c:60
static uint8_t tmp[11]
Definition: aes_ctr.c:26