FFmpeg  4.3.7
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 
249  if (bits_per_plane == 8) {
250  picmemset_8bpp(s, frame, val, run, &x, &y);
251  if (y < 0)
252  goto finish;
253  } else {
254  picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
255  }
256  }
257  }
258 
259  if (s->nb_planes - plane > 1)
260  return AVERROR_INVALIDDATA;
261 
262  if (plane < s->nb_planes && x < avctx->width) {
263  int run = (y + 1) * avctx->width - x;
264  if (bits_per_plane == 8)
265  picmemset_8bpp(s, frame, val, run, &x, &y);
266  else
267  picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
268  }
269  } else {
270  while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
271  memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
272  bytestream2_skip(&s->g, avctx->width);
273  y--;
274  }
275  }
276 finish:
277 
278  *got_frame = 1;
279  return avpkt->size;
280 }
281 
283  .name = "pictor",
284  .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
285  .type = AVMEDIA_TYPE_VIDEO,
286  .id = AV_CODEC_ID_PICTOR,
287  .priv_data_size = sizeof(PicContext),
288  .decode = decode_frame,
289  .capabilities = AV_CODEC_CAP_DR1,
290 };
#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:300
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: packet.h:356
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:736
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:209
AVCodec.
Definition: codec.h:190
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:92
static AVFrame * frame
const char data[16]
Definition: mxf.c:91
static void finish(void)
Definition: movenc.c:345
uint8_t * data
Definition: packet.h:355
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:428
GetByteContext g
Definition: pictordec.c:36
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
#define U(x)
Definition: vp56_arith.h:37
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
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:188
#define t1
Definition: regdef.h:29
const char * name
Name of the codec implementation.
Definition: codec.h:197
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:383
#define FFMIN(a, b)
Definition: common.h:96
int width
picture width / height.
Definition: avcodec.h:699
#define s(width, name)
Definition: cbs_vp9.c:257
#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:331
main external API structure.
Definition: avcodec.h:526
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1854
AVCodec ff_pictor_decoder
Definition: pictordec.c:282
double value
Definition: eval.c:98
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:457
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:314
common internal api header.
if(ret< 0)
Definition: vf_mcdeint.c:279
void * priv_data
Definition: avcodec.h:553
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:208
int nb_planes
Definition: pictordec.c:35
static double val(void *priv, double ch)
Definition: aeval.c:76
This structure stores compressed data.
Definition: packet.h:332
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:50
#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