FFmpeg  4.2.2
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:295
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: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:3481
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:42
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
static AVFrame * frame
const char data[16]
Definition: mxf.c:91
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: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:3488
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:1738
#define s(width, name)
Definition: cbs_vp9.c:257
int n
Definition: avisynth_c.h:760
if(ret< 0)
Definition: vf_mcdeint.c:279
#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:326
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
double value
Definition: eval.c:98
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: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