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 "libavutil/mem.h"
29 #include "avcodec.h"
30 #include "bytestream.h"
31 #include "cga_data.h"
32 #include "codec_internal.h"
33 #include "decode.h"
34 
35 typedef struct PicContext {
36  int width, height;
37  int nb_planes;
39 } PicContext;
40 
41 static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run,
42  int *x, int *y)
43 {
44  while (run > 0) {
45  uint8_t *d = frame->data[0] + *y * frame->linesize[0];
46  if (*x + run >= s->width) {
47  int n = s->width - *x;
48  memset(d + *x, value, n);
49  run -= n;
50  *x = 0;
51  *y -= 1;
52  if (*y < 0)
53  break;
54  } else {
55  memset(d + *x, value, run);
56  *x += run;
57  break;
58  }
59  }
60 }
61 
62 static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run,
63  int *x, int *y, int *plane, int bits_per_plane)
64 {
65  uint8_t *d;
66  int shift = *plane * bits_per_plane;
67  unsigned mask = ((1U << bits_per_plane) - 1) << shift;
68  int xl = *x;
69  int yl = *y;
70  int planel = *plane;
71  int pixels_per_value = 8/bits_per_plane;
72  value <<= shift;
73 
74  d = frame->data[0] + yl * frame->linesize[0];
75  while (run > 0) {
76  int j;
77  for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
78  d[xl] |= (value >> j) & mask;
79  xl += 1;
80  while (xl == s->width) {
81  yl -= 1;
82  xl = 0;
83  if (yl < 0) {
84  yl = s->height - 1;
85  planel += 1;
86  if (planel >= s->nb_planes)
87  goto end;
88  value <<= bits_per_plane;
89  mask <<= bits_per_plane;
90  }
91  d = frame->data[0] + yl * frame->linesize[0];
92  if (s->nb_planes == 1 &&
93  run*pixels_per_value >= s->width &&
94  pixels_per_value < (s->width / pixels_per_value * pixels_per_value)
95  ) {
96  for (; xl < pixels_per_value; xl ++) {
97  j = (j < bits_per_plane ? 8 : j) - bits_per_plane;
98  d[xl] |= (value >> j) & mask;
99  }
100  av_memcpy_backptr(d+xl, pixels_per_value, s->width - xl);
101  run -= s->width / pixels_per_value;
102  xl = s->width / pixels_per_value * pixels_per_value;
103  }
104  }
105  }
106  run--;
107  }
108 end:
109  *x = xl;
110  *y = yl;
111  *plane = planel;
112 }
113 
114 static const uint8_t cga_mode45_index[6][4] = {
115  [0] = { 0, 3, 5, 7 }, // mode4, palette#1, low intensity
116  [1] = { 0, 2, 4, 6 }, // mode4, palette#2, low intensity
117  [2] = { 0, 3, 4, 7 }, // mode5, low intensity
118  [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
119  [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
120  [5] = { 0, 11, 12, 15 }, // mode5, high intensity
121 };
122 
124  int *got_frame, AVPacket *avpkt)
125 {
126  PicContext *s = avctx->priv_data;
127  uint32_t *palette;
128  int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
129  int i, x, y, plane, tmp, ret, val;
130 
131  bytestream2_init(&s->g, avpkt->data, avpkt->size);
132 
133  if (bytestream2_get_bytes_left(&s->g) < 11)
134  return AVERROR_INVALIDDATA;
135 
136  if (bytestream2_get_le16u(&s->g) != 0x1234)
137  return AVERROR_INVALIDDATA;
138 
139  s->width = bytestream2_get_le16u(&s->g);
140  s->height = bytestream2_get_le16u(&s->g);
141  bytestream2_skip(&s->g, 4);
142  tmp = bytestream2_get_byteu(&s->g);
143  bits_per_plane = tmp & 0xF;
144  s->nb_planes = (tmp >> 4) + 1;
145  bpp = bits_per_plane * s->nb_planes;
146  if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
147  avpriv_request_sample(avctx, "Unsupported bit depth");
148  return AVERROR_PATCHWELCOME;
149  }
150 
151  if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
152  bytestream2_skip(&s->g, 2);
153  etype = bytestream2_get_le16(&s->g);
154  esize = bytestream2_get_le16(&s->g);
155  if (bytestream2_get_bytes_left(&s->g) < esize)
156  return AVERROR_INVALIDDATA;
157  } else {
158  etype = -1;
159  esize = 0;
160  }
161 
162  avctx->pix_fmt = AV_PIX_FMT_PAL8;
163 
164  if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
165  return -1;
166 
167  /*
168  There are 2 coding modes, RLE and RAW.
169  Undamaged RAW should be proportional to W*H and thus bigger than RLE
170  RLE codes the most compressed runs by
171  1 byte for val (=marker)
172  1 byte run (=0)
173  2 bytes run
174  1 byte val
175  thats 5 bytes and the maximum run we can code is 65535
176 
177  The RLE decoder can exit prematurly but it does not on any image available
178  Based on this the formula is assumed correct for undamaged images.
179  If an image is found which exploits the special end
180  handling and breaks this formula then this needs to be adapted.
181  */
182  if (bytestream2_get_bytes_left(&s->g) < s->width * s->height / 65535 * 5)
183  return AVERROR_INVALIDDATA;
184 
185  if (s->width != avctx->width || s->height != avctx->height) {
186  ret = ff_set_dimensions(avctx, s->width, s->height);
187  if (ret < 0)
188  return ret;
189  }
190 
191  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
192  return ret;
193  memset(frame->data[0], 0, s->height * frame->linesize[0]);
194  frame->pict_type = AV_PICTURE_TYPE_I;
195 #if FF_API_PALETTE_HAS_CHANGED
197  frame->palette_has_changed = 1;
199 #endif
200 
201  pos_after_pal = bytestream2_tell(&s->g) + esize;
202  palette = (uint32_t*)frame->data[1];
203  if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
204  int idx = bytestream2_get_byte(&s->g);
205  npal = 4;
206  for (i = 0; i < npal; i++)
207  palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
208  } else if (etype == 2) {
209  npal = FFMIN(esize, 16);
210  for (i = 0; i < npal; i++) {
211  int pal_idx = bytestream2_get_byte(&s->g);
212  palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)];
213  }
214  } else if (etype == 3) {
215  npal = FFMIN(esize, 16);
216  for (i = 0; i < npal; i++) {
217  int pal_idx = bytestream2_get_byte(&s->g);
218  palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)];
219  }
220  } else if (etype == 4 || etype == 5) {
221  npal = FFMIN(esize / 3, 256);
222  for (i = 0; i < npal; i++) {
223  palette[i] = bytestream2_get_be24(&s->g) << 2;
224  palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
225  }
226  } else {
227  if (bpp == 1) {
228  npal = 2;
229  palette[0] = 0xFF000000;
230  palette[1] = 0xFFFFFFFF;
231  } else if (bpp == 2) {
232  npal = 4;
233  for (i = 0; i < npal; i++)
234  palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
235  } else {
236  npal = 16;
237  memcpy(palette, ff_cga_palette, npal * 4);
238  }
239  }
240  // fill remaining palette entries
241  memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
242  // skip remaining palette bytes
243  bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
244 
245  val = 0;
246  y = s->height - 1;
247  if (bytestream2_get_le16(&s->g)) {
248  x = 0;
249  plane = 0;
250  while (bytestream2_get_bytes_left(&s->g) >= 6) {
251  int stop_size, marker, t1, t2;
252 
254  t2 = bytestream2_get_le16(&s->g);
255  stop_size = t1 - FFMIN(t1, t2);
256  // ignore uncompressed block size
257  bytestream2_skip(&s->g, 2);
258  marker = bytestream2_get_byte(&s->g);
259 
260  while (plane < s->nb_planes &&
261  bytestream2_get_bytes_left(&s->g) > stop_size) {
262  int run = 1;
263  val = bytestream2_get_byte(&s->g);
264  if (val == marker) {
265  run = bytestream2_get_byte(&s->g);
266  if (run == 0)
267  run = bytestream2_get_le16(&s->g);
268  val = bytestream2_get_byte(&s->g);
269  }
270 
271  if (bits_per_plane == 8) {
272  picmemset_8bpp(s, frame, val, run, &x, &y);
273  if (y < 0)
274  goto finish;
275  } else {
276  picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
277  }
278  }
279  }
280 
281  if (s->nb_planes - plane > 1)
282  return AVERROR_INVALIDDATA;
283 
284  if (plane < s->nb_planes && x < avctx->width) {
285  int run = (y + 1) * avctx->width - x;
286  if (bits_per_plane == 8)
287  picmemset_8bpp(s, frame, val, run, &x, &y);
288  else
289  picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
290  }
291  } else {
292  while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
293  memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
294  bytestream2_skip(&s->g, avctx->width);
295  y--;
296  }
297  }
298 finish:
299 
300  *got_frame = 1;
301  return avpkt->size;
302 }
303 
305  .p.name = "pictor",
306  CODEC_LONG_NAME("Pictor/PC Paint"),
307  .p.type = AVMEDIA_TYPE_VIDEO,
308  .p.id = AV_CODEC_ID_PICTOR,
309  .p.capabilities = AV_CODEC_CAP_DR1,
310  .priv_data_size = sizeof(PicContext),
312 };
picmemset
static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run, int *x, int *y, int *plane, int bits_per_plane)
Definition: pictordec.c:62
FF_ENABLE_DEPRECATION_WARNINGS
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition: internal.h:73
cga_mode45_index
static const uint8_t cga_mode45_index[6][4]
Definition: pictordec.c:114
ff_cga_palette
const uint32_t ff_cga_palette[16]
Definition: cga_data.c:30
GetByteContext
Definition: bytestream.h:33
bytestream2_seek
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:212
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:374
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
AVPacket::data
uint8_t * data
Definition: packet.h:524
FFCodec
Definition: codec_internal.h:126
t1
#define t1
Definition: regdef.h:29
ff_set_dimensions
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:94
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:130
finish
static void finish(void)
Definition: movenc.c:373
PicContext::height
int height
Definition: pictordec.c:36
PicContext
Definition: pictordec.c:35
val
static double val(void *priv, double ch)
Definition: aeval.c:78
PicContext::width
int width
Definition: pictordec.c:36
mask
static const uint16_t mask[17]
Definition: lzw.c:38
av_memcpy_backptr
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
Overlapping memcpy() implementation.
Definition: mem.c:447
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:286
s
#define s(width, name)
Definition: cbs_vp9.c:198
decode.h
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:271
if
if(ret)
Definition: filter_design.txt:179
PicContext::nb_planes
int nb_planes
Definition: pictordec.c:37
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
run
uint8_t run
Definition: svq3.c:204
ff_ega_palette
const uint32_t ff_ega_palette[64]
Definition: cga_data.c:35
AV_CODEC_ID_PICTOR
@ AV_CODEC_ID_PICTOR
Definition: codec_id.h:193
AVPALETTE_SIZE
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
picmemset_8bpp
static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run, int *x, int *y)
Definition: pictordec.c:41
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
bytestream2_tell
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:192
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1556
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:525
codec_internal.h
shift
static int shift(int a, int b)
Definition: bonk.c:261
cga_data.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AVCodecContext::height
int height
Definition: avcodec.h:618
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:657
avcodec.h
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:84
ret
ret
Definition: filter_design.txt:187
frame
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
Definition: filter_design.txt:264
U
#define U(x)
Definition: vpx_arith.h:37
AVCodecContext
main external API structure.
Definition: avcodec.h:445
t2
#define t2
Definition: regdef.h:30
PicContext::g
GetByteContext g
Definition: pictordec.c:38
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:36
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:472
AVPacket
This structure stores compressed data.
Definition: packet.h:501
d
d
Definition: ffmpeg_filter.c:424
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:618
bytestream.h
imgutils.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
av_image_check_size
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:318
ff_pictor_decoder
const FFCodec ff_pictor_decoder
Definition: pictordec.c:304
decode_frame
static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition: pictordec.c:123