FFmpeg
Loading...
Searching...
No Matches
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
40
41static 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
62static 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 }
108end:
109 *x = xl;
110 *y = yl;
111 *plane = planel;
112}
113
114static 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");
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 that's 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
196 pos_after_pal = bytestream2_tell(&s->g) + esize;
197 palette = (uint32_t*)frame->data[1];
198 if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
199 int idx = bytestream2_get_byte(&s->g);
200 npal = 4;
201 for (i = 0; i < npal; i++)
202 palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
203 } else if (etype == 2) {
204 npal = FFMIN(esize, 16);
205 for (i = 0; i < npal; i++) {
206 int pal_idx = bytestream2_get_byte(&s->g);
207 palette[i] = ff_cga_palette[FFMIN(pal_idx, 15)];
208 }
209 } else if (etype == 3) {
210 npal = FFMIN(esize, 16);
211 for (i = 0; i < npal; i++) {
212 int pal_idx = bytestream2_get_byte(&s->g);
213 palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)];
214 }
215 } else if (etype == 4 || etype == 5) {
216 npal = FFMIN(esize / 3, 256);
217 for (i = 0; i < npal; i++) {
218 palette[i] = bytestream2_get_be24(&s->g) << 2;
219 palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
220 }
221 } else {
222 if (bpp == 1) {
223 npal = 2;
224 palette[0] = 0xFF000000;
225 palette[1] = 0xFFFFFFFF;
226 } else if (bpp == 2) {
227 npal = 4;
228 for (i = 0; i < npal; i++)
229 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
230 } else {
231 npal = 16;
232 memcpy(palette, ff_cga_palette, npal * 4);
233 }
234 }
235 // fill remaining palette entries
236 memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
237 // skip remaining palette bytes
238 bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
239
240 val = 0;
241 y = s->height - 1;
242 if (bytestream2_get_le16(&s->g)) {
243 x = 0;
244 plane = 0;
245 while (bytestream2_get_bytes_left(&s->g) >= 6) {
246 int stop_size, marker, t1, t2;
247
249 t2 = bytestream2_get_le16(&s->g);
250 stop_size = t1 - FFMIN(t1, t2);
251 // ignore uncompressed block size
252 bytestream2_skip(&s->g, 2);
253 marker = bytestream2_get_byte(&s->g);
254
255 while (plane < s->nb_planes &&
256 bytestream2_get_bytes_left(&s->g) > stop_size) {
257 int run = 1;
258 val = bytestream2_get_byte(&s->g);
259 if (val == marker) {
260 run = bytestream2_get_byte(&s->g);
261 if (run == 0)
262 run = bytestream2_get_le16(&s->g);
263 val = bytestream2_get_byte(&s->g);
264 }
265
266 if (bits_per_plane == 8) {
267 picmemset_8bpp(s, frame, val, run, &x, &y);
268 if (y < 0)
269 goto finish;
270 } else {
271 picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
272 }
273 }
274 }
275
276 if (s->nb_planes - plane > 1)
277 return AVERROR_INVALIDDATA;
278
279 if (plane < s->nb_planes && x < avctx->width) {
280 int run = (y + 1) * avctx->width - x;
281 if (bits_per_plane == 8)
282 picmemset_8bpp(s, frame, val, run, &x, &y);
283 else
284 picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
285 }
286 } else {
287 while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
288 memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
289 bytestream2_skip(&s->g, avctx->width);
290 y--;
291 }
292 }
293finish:
294
295 *got_frame = 1;
296 return avpkt->size;
297}
298
300 .p.name = "pictor",
301 CODEC_LONG_NAME("Pictor/PC Paint"),
302 .p.type = AVMEDIA_TYPE_VIDEO,
303 .p.id = AV_CODEC_ID_PICTOR,
304 .p.capabilities = AV_CODEC_CAP_DR1,
305 .priv_data_size = sizeof(PicContext),
307};
static double val(void *priv, double ch)
Definition aeval.c:77
const FFCodec ff_pictor_decoder
Definition pictordec.c:299
Libavcodec external API header.
static av_always_inline int bytestream2_get_bytes_left(const GetByteContext *g)
Definition bytestream.h:158
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition bytestream.h:137
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition bytestream.h:168
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition bytestream.h:212
static av_always_inline int bytestream2_tell(const GetByteContext *g)
Definition bytestream.h:192
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
const uint32_t ff_cga_palette[16]
Definition cga_data.c:30
const uint32_t ff_ega_palette[64]
Definition cga_data.c:35
CGA/EGA/VGA ROM data.
#define FF_CODEC_DECODE_CB(func)
#define CODEC_LONG_NAME(str)
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition decode.c:1777
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Definition utils.c:91
static AVFrame * frame
double value
Definition eval.c:102
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition codec.h:49
@ AV_CODEC_ID_PICTOR
Definition codec_id.h:191
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
void av_memcpy_backptr(uint8_t *dst, int back, int cnt)
Overlapping memcpy() implementation.
Definition mem.c:445
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
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
@ AV_PICTURE_TYPE_I
Intra.
Definition avutil.h:278
misc image utilities
static int decode_frame(AVCodecContext *avctx, AVFrame *picture, int *got_frame, AVPacket *avpkt)
Definition 4xm.c:837
static int shift(int a, int b)
Definition bonk.c:261
static const uint16_t mask[17]
Definition lzw.c:38
#define FFMIN(a, b)
Definition macros.h:49
Memory handling functions.
static int decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition pictordec.c:123
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
static const uint8_t cga_mode45_index[6][4]
Definition pictordec.c:114
static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run, int *x, int *y)
Definition pictordec.c:41
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition pixfmt.h:84
#define AVPALETTE_SIZE
Definition pixfmt.h:32
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
void * priv_data
Definition avcodec.h:470
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
This structure stores compressed data.
Definition packet.h:580
int size
Definition packet.h:604
uint8_t * data
Definition packet.h:603
int nb_planes
Definition pictordec.c:37
GetByteContext g
Definition pictordec.c:38
uint8_t run
Definition svq3.c:207
#define avpriv_request_sample(...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
static void finish(void)
Definition movenc.c:374
#define width
Definition dsp.h:89