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 
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 };
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:60
AVCodec
AVCodec.
Definition: avcodec.h:3481
cga_mode45_index
static const uint8_t cga_mode45_index[6][4]
Definition: pictordec.c:99
ff_cga_palette
const uint32_t ff_cga_palette[16]
Definition: cga_data.c:30
GetByteContext
Definition: bytestream.h:33
n
int n
Definition: avisynth_c.h:760
decode_frame
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: pictordec.c:108
end
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
bytestream2_seek
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:208
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:26
internal.h
AVPacket::data
uint8_t * data
Definition: avcodec.h:1477
data
const char data[16]
Definition: mxf.c:91
t1
#define t1
Definition: regdef.h:29
bytestream2_get_bytes_left
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
finish
static void finish(void)
Definition: movenc.c:345
PicContext::height
int height
Definition: pictordec.c:34
U
#define U(x)
Definition: vp56_arith.h:37
ff_pictor_decoder
AVCodec ff_pictor_decoder
Definition: pictordec.c:270
plane
int plane
Definition: avisynth_c.h:384
PicContext
Definition: pictordec.c:33
PicContext::width
int width
Definition: pictordec.c:34
mask
static const uint16_t mask[17]
Definition: lzw.c:38
decode
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:42
width
#define width
s
#define s(width, name)
Definition: cbs_vp9.c:257
if
if(ret)
Definition: filter_design.txt:179
PicContext::nb_planes
int nb_planes
Definition: pictordec.c:35
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
run
uint8_t run
Definition: svq3.c:206
ff_ega_palette
const uint32_t ff_ega_palette[64]
Definition: cga_data.c:35
AV_CODEC_ID_PICTOR
@ AV_CODEC_ID_PICTOR
Definition: avcodec.h:359
AVPALETTE_SIZE
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:274
picmemset_8bpp
static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run, int *x, int *y)
Definition: pictordec.c:39
bytestream2_tell
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:188
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1965
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:981
AVPacket::size
int size
Definition: avcodec.h:1478
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
val
const char const char void * val
Definition: avisynth_c.h:863
cga_data.h
FFMIN
#define FFMIN(a, b)
Definition: common.h:96
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
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
uint8_t
uint8_t
Definition: audio_convert.c:194
AVCodec::name
const char * name
Name of the codec implementation.
Definition: avcodec.h:3488
AVCodecContext::height
int height
Definition: avcodec.h:1738
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1775
avcodec.h
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
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
AVCodecContext
main external API structure.
Definition: avcodec.h:1565
t2
#define t2
Definition: regdef.h:30
PicContext::g
GetByteContext g
Definition: pictordec.c:36
shift
static int shift(int a, int b)
Definition: sonic.c:82
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
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:104
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:39
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:1592
AVPacket
This structure stores compressed data.
Definition: avcodec.h:1454
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:1738
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:133
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
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:282