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 "codec_internal.h"
32 #include "decode.h"
33 
34 typedef struct PicContext {
35  int width, height;
36  int nb_planes;
38 } PicContext;
39 
40 static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run,
41  int *x, int *y)
42 {
43  while (run > 0) {
44  uint8_t *d = frame->data[0] + *y * frame->linesize[0];
45  if (*x + run >= s->width) {
46  int n = s->width - *x;
47  memset(d + *x, value, n);
48  run -= n;
49  *x = 0;
50  *y -= 1;
51  if (*y < 0)
52  break;
53  } else {
54  memset(d + *x, value, run);
55  *x += run;
56  break;
57  }
58  }
59 }
60 
61 static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run,
62  int *x, int *y, int *plane, int bits_per_plane)
63 {
64  uint8_t *d;
65  int shift = *plane * bits_per_plane;
66  unsigned mask = ((1U << bits_per_plane) - 1) << shift;
67  int xl = *x;
68  int yl = *y;
69  int planel = *plane;
70  int pixels_per_value = 8/bits_per_plane;
71  value <<= shift;
72 
73  d = frame->data[0] + yl * frame->linesize[0];
74  while (run > 0) {
75  int j;
76  for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
77  d[xl] |= (value >> j) & mask;
78  xl += 1;
79  while (xl == s->width) {
80  yl -= 1;
81  xl = 0;
82  if (yl < 0) {
83  yl = s->height - 1;
84  planel += 1;
85  if (planel >= s->nb_planes)
86  goto end;
87  value <<= bits_per_plane;
88  mask <<= bits_per_plane;
89  }
90  d = frame->data[0] + yl * frame->linesize[0];
91  if (s->nb_planes == 1 &&
92  run*pixels_per_value >= s->width &&
93  pixels_per_value < (s->width / pixels_per_value * pixels_per_value)
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 / pixels_per_value * pixels_per_value;
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 
123  int *got_frame, AVPacket *avpkt)
124 {
125  PicContext *s = avctx->priv_data;
126  uint32_t *palette;
127  int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
128  int i, x, y, plane, tmp, ret, val;
129 
130  bytestream2_init(&s->g, avpkt->data, avpkt->size);
131 
132  if (bytestream2_get_bytes_left(&s->g) < 11)
133  return AVERROR_INVALIDDATA;
134 
135  if (bytestream2_get_le16u(&s->g) != 0x1234)
136  return AVERROR_INVALIDDATA;
137 
138  s->width = bytestream2_get_le16u(&s->g);
139  s->height = bytestream2_get_le16u(&s->g);
140  bytestream2_skip(&s->g, 4);
141  tmp = bytestream2_get_byteu(&s->g);
142  bits_per_plane = tmp & 0xF;
143  s->nb_planes = (tmp >> 4) + 1;
144  bpp = bits_per_plane * s->nb_planes;
145  if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
146  avpriv_request_sample(avctx, "Unsupported bit depth");
147  return AVERROR_PATCHWELCOME;
148  }
149 
150  if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
151  bytestream2_skip(&s->g, 2);
152  etype = bytestream2_get_le16(&s->g);
153  esize = bytestream2_get_le16(&s->g);
154  if (bytestream2_get_bytes_left(&s->g) < esize)
155  return AVERROR_INVALIDDATA;
156  } else {
157  etype = -1;
158  esize = 0;
159  }
160 
161  avctx->pix_fmt = AV_PIX_FMT_PAL8;
162 
163  if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
164  return -1;
165 
166  /*
167  There are 2 coding modes, RLE and RAW.
168  Undamaged RAW should be proportional to W*H and thus bigger than RLE
169  RLE codes the most compressed runs by
170  1 byte for val (=marker)
171  1 byte run (=0)
172  2 bytes run
173  1 byte val
174  thats 5 bytes and the maximum run we can code is 65535
175 
176  The RLE decoder can exit prematurly but it does not on any image available
177  Based on this the formula is assumed correct for undamaged images.
178  If an image is found which exploits the special end
179  handling and breaks this formula then this needs to be adapted.
180  */
181  if (bytestream2_get_bytes_left(&s->g) < s->width * s->height / 65535 * 5)
182  return AVERROR_INVALIDDATA;
183 
184  if (s->width != avctx->width || s->height != avctx->height) {
185  ret = ff_set_dimensions(avctx, s->width, s->height);
186  if (ret < 0)
187  return ret;
188  }
189 
190  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
191  return ret;
192  memset(frame->data[0], 0, s->height * frame->linesize[0]);
194 #if FF_API_PALETTE_HAS_CHANGED
198 #endif
199 
200  pos_after_pal = bytestream2_tell(&s->g) + esize;
201  palette = (uint32_t*)frame->data[1];
202  if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
203  int idx = bytestream2_get_byte(&s->g);
204  npal = 4;
205  for (i = 0; i < npal; i++)
206  palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
207  } else if (etype == 2) {
208  npal = FFMIN(esize, 16);
209  for (i = 0; i < npal; i++) {
210  int pal_idx = bytestream2_get_byte(&s->g);
211  palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)];
212  }
213  } else if (etype == 3) {
214  npal = FFMIN(esize, 16);
215  for (i = 0; i < npal; i++) {
216  int pal_idx = bytestream2_get_byte(&s->g);
217  palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)];
218  }
219  } else if (etype == 4 || etype == 5) {
220  npal = FFMIN(esize / 3, 256);
221  for (i = 0; i < npal; i++) {
222  palette[i] = bytestream2_get_be24(&s->g) << 2;
223  palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
224  }
225  } else {
226  if (bpp == 1) {
227  npal = 2;
228  palette[0] = 0xFF000000;
229  palette[1] = 0xFFFFFFFF;
230  } else if (bpp == 2) {
231  npal = 4;
232  for (i = 0; i < npal; i++)
233  palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
234  } else {
235  npal = 16;
236  memcpy(palette, ff_cga_palette, npal * 4);
237  }
238  }
239  // fill remaining palette entries
240  memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
241  // skip remaining palette bytes
242  bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
243 
244  val = 0;
245  y = s->height - 1;
246  if (bytestream2_get_le16(&s->g)) {
247  x = 0;
248  plane = 0;
249  while (bytestream2_get_bytes_left(&s->g) >= 6) {
250  int stop_size, marker, t1, t2;
251 
253  t2 = bytestream2_get_le16(&s->g);
254  stop_size = t1 - FFMIN(t1, t2);
255  // ignore uncompressed block size
256  bytestream2_skip(&s->g, 2);
257  marker = bytestream2_get_byte(&s->g);
258 
259  while (plane < s->nb_planes &&
260  bytestream2_get_bytes_left(&s->g) > stop_size) {
261  int run = 1;
262  val = bytestream2_get_byte(&s->g);
263  if (val == marker) {
264  run = bytestream2_get_byte(&s->g);
265  if (run == 0)
266  run = bytestream2_get_le16(&s->g);
267  val = bytestream2_get_byte(&s->g);
268  }
269 
270  if (bits_per_plane == 8) {
271  picmemset_8bpp(s, frame, val, run, &x, &y);
272  if (y < 0)
273  goto finish;
274  } else {
275  picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
276  }
277  }
278  }
279 
280  if (s->nb_planes - plane > 1)
281  return AVERROR_INVALIDDATA;
282 
283  if (plane < s->nb_planes && x < avctx->width) {
284  int run = (y + 1) * avctx->width - x;
285  if (bits_per_plane == 8)
286  picmemset_8bpp(s, frame, val, run, &x, &y);
287  else
288  picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
289  }
290  } else {
291  while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
292  memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
293  bytestream2_skip(&s->g, avctx->width);
294  y--;
295  }
296  }
297 finish:
298 
299  *got_frame = 1;
300  return avpkt->size;
301 }
302 
304  .p.name = "pictor",
305  CODEC_LONG_NAME("Pictor/PC Paint"),
306  .p.type = AVMEDIA_TYPE_VIDEO,
307  .p.id = AV_CODEC_ID_PICTOR,
308  .p.capabilities = AV_CODEC_CAP_DR1,
309  .priv_data_size = sizeof(PicContext),
311 };
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:61
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:113
AVFrame::palette_has_changed
attribute_deprecated int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:533
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:340
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
AVPacket::data
uint8_t * data
Definition: packet.h:522
FFCodec
Definition: codec_internal.h:127
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
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
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:131
finish
static void finish(void)
Definition: movenc.c:342
PicContext::height
int height
Definition: pictordec.c:35
PicContext
Definition: pictordec.c:34
val
static double val(void *priv, double ch)
Definition: aeval.c:78
PicContext::width
int width
Definition: pictordec.c:35
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:445
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:287
s
#define s(width, name)
Definition: cbs_vp9.c:198
decode.h
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
frame
static AVFrame * frame
Definition: demux_decode.c:54
if
if(ret)
Definition: filter_design.txt:179
PicContext::nb_planes
int nb_planes
Definition: pictordec.c:36
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
run
uint8_t run
Definition: svq3.c:203
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:40
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
AVFrame::pict_type
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:442
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1568
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:523
codec_internal.h
shift
static int shift(int a, int b)
Definition: bonk.c:262
cga_data.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
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
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:37
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
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:499
d
d
Definition: ffmpeg_filter.c:425
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
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:385
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:303
decode_frame
static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition: pictordec.c:122