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  value <<= shift;
70 
71  d = frame->data[0] + yl * frame->linesize[0];
72  while (run > 0) {
73  int j;
74  for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
75  d[xl] |= (value >> j) & mask;
76  xl += 1;
77  if (xl == s->width) {
78  yl -= 1;
79  xl = 0;
80  if (yl < 0) {
81  yl = s->height - 1;
82  planel += 1;
83  if (planel >= s->nb_planes)
84  goto end;
85  value <<= bits_per_plane;
86  mask <<= bits_per_plane;
87  }
88  d = frame->data[0] + yl * frame->linesize[0];
89  }
90  }
91  run--;
92  }
93 end:
94  *x = xl;
95  *y = yl;
96  *plane = planel;
97 }
98 
99 static const uint8_t cga_mode45_index[6][4] = {
100  [0] = { 0, 3, 5, 7 }, // mode4, palette#1, low intensity
101  [1] = { 0, 2, 4, 6 }, // mode4, palette#2, low intensity
102  [2] = { 0, 3, 4, 7 }, // mode5, low intensity
103  [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
104  [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
105  [5] = { 0, 11, 12, 15 }, // mode5, high intensity
106 };
107 
108 static int decode_frame(AVCodecContext *avctx,
109  void *data, int *got_frame,
110  AVPacket *avpkt)
111 {
112  PicContext *s = avctx->priv_data;
113  AVFrame *frame = data;
114  uint32_t *palette;
115  int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
116  int i, x, y, plane, tmp, ret, val;
117 
118  bytestream2_init(&s->g, avpkt->data, avpkt->size);
119 
120  if (bytestream2_get_bytes_left(&s->g) < 11)
121  return AVERROR_INVALIDDATA;
122 
123  if (bytestream2_get_le16u(&s->g) != 0x1234)
124  return AVERROR_INVALIDDATA;
125 
126  s->width = bytestream2_get_le16u(&s->g);
127  s->height = bytestream2_get_le16u(&s->g);
128  bytestream2_skip(&s->g, 4);
129  tmp = bytestream2_get_byteu(&s->g);
130  bits_per_plane = tmp & 0xF;
131  s->nb_planes = (tmp >> 4) + 1;
132  bpp = bits_per_plane * s->nb_planes;
133  if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
134  avpriv_request_sample(avctx, "Unsupported bit depth");
135  return AVERROR_PATCHWELCOME;
136  }
137 
138  if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
139  bytestream2_skip(&s->g, 2);
140  etype = bytestream2_get_le16(&s->g);
141  esize = bytestream2_get_le16(&s->g);
142  if (bytestream2_get_bytes_left(&s->g) < esize)
143  return AVERROR_INVALIDDATA;
144  } else {
145  etype = -1;
146  esize = 0;
147  }
148 
149  avctx->pix_fmt = AV_PIX_FMT_PAL8;
150 
151  if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
152  return -1;
153  if (s->width != avctx->width || s->height != avctx->height) {
154  ret = ff_set_dimensions(avctx, s->width, s->height);
155  if (ret < 0)
156  return ret;
157  }
158 
159  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
160  return ret;
161  memset(frame->data[0], 0, s->height * frame->linesize[0]);
162  frame->pict_type = AV_PICTURE_TYPE_I;
163  frame->palette_has_changed = 1;
164 
165  pos_after_pal = bytestream2_tell(&s->g) + esize;
166  palette = (uint32_t*)frame->data[1];
167  if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
168  int idx = bytestream2_get_byte(&s->g);
169  npal = 4;
170  for (i = 0; i < npal; i++)
171  palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
172  } else if (etype == 2) {
173  npal = FFMIN(esize, 16);
174  for (i = 0; i < npal; i++) {
175  int pal_idx = bytestream2_get_byte(&s->g);
176  palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)];
177  }
178  } else if (etype == 3) {
179  npal = FFMIN(esize, 16);
180  for (i = 0; i < npal; i++) {
181  int pal_idx = bytestream2_get_byte(&s->g);
182  palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)];
183  }
184  } else if (etype == 4 || etype == 5) {
185  npal = FFMIN(esize / 3, 256);
186  for (i = 0; i < npal; i++) {
187  palette[i] = bytestream2_get_be24(&s->g) << 2;
188  palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
189  }
190  } else {
191  if (bpp == 1) {
192  npal = 2;
193  palette[0] = 0xFF000000;
194  palette[1] = 0xFFFFFFFF;
195  } else if (bpp == 2) {
196  npal = 4;
197  for (i = 0; i < npal; i++)
198  palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
199  } else {
200  npal = 16;
201  memcpy(palette, ff_cga_palette, npal * 4);
202  }
203  }
204  // fill remaining palette entries
205  memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
206  // skip remaining palette bytes
207  bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
208 
209  val = 0;
210  y = s->height - 1;
211  if (bytestream2_get_le16(&s->g)) {
212  x = 0;
213  plane = 0;
214  while (bytestream2_get_bytes_left(&s->g) >= 6) {
215  int stop_size, marker, t1, t2;
216 
217  t1 = bytestream2_get_bytes_left(&s->g);
218  t2 = bytestream2_get_le16(&s->g);
219  stop_size = t1 - FFMIN(t1, t2);
220  // ignore uncompressed block size
221  bytestream2_skip(&s->g, 2);
222  marker = bytestream2_get_byte(&s->g);
223 
224  while (plane < s->nb_planes &&
225  bytestream2_get_bytes_left(&s->g) > stop_size) {
226  int run = 1;
227  val = bytestream2_get_byte(&s->g);
228  if (val == marker) {
229  run = bytestream2_get_byte(&s->g);
230  if (run == 0)
231  run = bytestream2_get_le16(&s->g);
232  val = bytestream2_get_byte(&s->g);
233  }
234  if (!bytestream2_get_bytes_left(&s->g))
235  break;
236 
237  if (bits_per_plane == 8) {
238  picmemset_8bpp(s, frame, val, run, &x, &y);
239  if (y < 0)
240  goto finish;
241  } else {
242  picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
243  }
244  }
245  }
246 
247  if (s->nb_planes - plane > 1)
248  return AVERROR_INVALIDDATA;
249 
250  if (plane < s->nb_planes && x < avctx->width) {
251  int run = (y + 1) * avctx->width - x;
252  if (bits_per_plane == 8)
253  picmemset_8bpp(s, frame, val, run, &x, &y);
254  else
255  picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
256  }
257  } else {
258  while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
259  memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
260  bytestream2_skip(&s->g, avctx->width);
261  y--;
262  }
263  }
264 finish:
265 
266  *got_frame = 1;
267  return avpkt->size;
268 }
269 
271  .name = "pictor",
272  .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
273  .type = AVMEDIA_TYPE_VIDEO,
274  .id = AV_CODEC_ID_PICTOR,
275  .priv_data_size = sizeof(PicContext),
276  .decode = decode_frame,
277  .capabilities = AV_CODEC_CAP_DR1,
278 };
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:268
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
int size
Definition: avcodec.h:1478
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1775
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:3477
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:42
void void avpriv_request_sample(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
static const uint8_t cga_mode45_index[6][4]
Definition: pictordec.c:99
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:1477
const uint8_t * buffer
Definition: bytestream.h:34
CGA/EGA/VGA ROM data.
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:260
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:3484
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:351
#define FFMIN(a, b)
Definition: common.h:96
int width
picture width / height.
Definition: avcodec.h:1738
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:108
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:299
main external API structure.
Definition: avcodec.h:1565
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1964
AVCodec ff_pictor_decoder
Definition: pictordec.c:270
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:425
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:282
common internal api header.
void * priv_data
Definition: avcodec.h:1592
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:1454
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:981
#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