History

Pictor/PC Paint decoder

Originally committed as revision 23532 to svn://svn.ffmpeg.org/ffmpeg/trunk

Peter Ross committed 16 years ago

Commit a526d611 parent f2b9b196 files · +257 −1Browse files

Unified · Split

6 files
  1. Changelog +1 −0
  2. doc/general.texi +2 −0
  3. libavcodec/Makefile +1 −0
  4. libavcodec/allcodecs.c +1 −0
  5. libavcodec/avcodec.h +2 −1
  6. libavcodec/pictordec.c +250 −0
Changelog+1−0
@@ -10,6 +10,7 @@ version <next>: · 9 unmodified lines
1010 - VP8 de/encoding via libvpx
1111 - CODEC_CAP_EXPERIMENTAL added
1212 - Demuxer for On2's IVF format
13+- Pictor/PC Paint decoder
1314
1415
1516
doc/general.texi+2−0
@@ -281,6 +281,8 @@ following image formats are supported: · 280 unmodified lines
281281 @tab Portable GrayMap image
282282 @item PGMYUV @tab X @tab X
283283 @tab PGM with U and V components in YUV 4:2:0
284+@item PIC @tab @tab X
285+ @tab Pictor/PC Paint
284286 @item PNG @tab X @tab X
285287 @tab 2/4 bpp not supported yet
286288 @item PPM @tab X @tab X
libavcodec/Makefile+1−0
@@ -264,6 +264,7 @@ OBJS-$(CONFIG_PGM_ENCODER) += pnmenc.o pnm.o · 263 unmodified lines
264264 OBJS-$(CONFIG_PGMYUV_DECODER) += pnmdec.o pnm.o
265265 OBJS-$(CONFIG_PGMYUV_ENCODER) += pnmenc.o pnm.o
266266 OBJS-$(CONFIG_PGSSUB_DECODER) += pgssubdec.o
267+OBJS-$(CONFIG_PICTOR_DECODER) += pictordec.o cga_data.o
267268 OBJS-$(CONFIG_PNG_DECODER) += png.o pngdec.o
268269 OBJS-$(CONFIG_PNG_ENCODER) += png.o pngenc.o
269270 OBJS-$(CONFIG_PPM_DECODER) += pnmdec.o pnm.o
libavcodec/allcodecs.c+1−0
@@ -152,6 +152,7 @@ void avcodec_register_all(void) · 151 unmodified lines
152152 REGISTER_ENCDEC (PCX, pcx);
153153 REGISTER_ENCDEC (PGM, pgm);
154154 REGISTER_ENCDEC (PGMYUV, pgmyuv);
155+ REGISTER_DECODER (PICTOR, pictor);
155156 REGISTER_ENCDEC (PNG, png);
156157 REGISTER_ENCDEC (PPM, ppm);
157158 REGISTER_DECODER (PTX, ptx);
libavcodec/avcodec.h+2−1
@@ -30,7 +30,7 @@ · 29 unmodified lines
3030 #include "libavutil/avutil.h"
3131
3232 #define LIBAVCODEC_VERSION_MAJOR 52
33−#define LIBAVCODEC_VERSION_MINOR 74
33+#define LIBAVCODEC_VERSION_MINOR 75
3434 #define LIBAVCODEC_VERSION_MICRO 1
3535
3636 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
@@ -211,6 +211,7 @@ enum CodecID { · 174 unmodified lines
211211 CODEC_ID_KGV1,
212212 CODEC_ID_YOP,
213213 CODEC_ID_VP8,
214+ CODEC_ID_PICTOR,
214215
215216 /* various PCM "codecs" */
216217 CODEC_ID_PCM_S16LE= 0x10000,
libavcodec/pictordec.c+250−0
@@ -0,0 +1,250 @@
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 libavcodec/picdec.c
24+ * Pictor/PC Paint decoder
25+ */
26+
27+#include "avcodec.h"
28+#include "bytestream.h"
29+#include "cga_data.h"
30+
31+typedef struct PicContext {
32+ AVFrame frame;
33+ int width, height;
34+ int nb_planes;
35+} PicContext;
36+
37+static void picmemset_8bpp(PicContext *s, int value, int run, int *x, int *y)
38+{
39+ while (run > 0) {
40+ uint8_t *d = s->frame.data[0] + *y * s->frame.linesize[0];
41+ if (*x + run >= s->width) {
42+ int n = s->width - *x;
43+ memset(d + *x, value, n);
44+ run -= n;
45+ *x = 0;
46+ *y -= 1;
47+ if (*y < 0)
48+ break;
49+ } else {
50+ memset(d + *x, value, run);
51+ *x += run;
52+ break;
53+ }
54+ }
55+}
56+
57+static void picmemset(PicContext *s, int value, int run, int *x, int *y, int *plane, int bits_per_plane)
58+{
59+ uint8_t *d;
60+ int shift = *plane * bits_per_plane;
61+ int mask = ((1 << bits_per_plane) - 1) << shift;
62+ value <<= shift;
63+
64+ while (run > 0) {
65+ int j;
66+ for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
67+ d = s->frame.data[0] + *y * s->frame.linesize[0];
68+ d[*x] |= (value >> j) & mask;
69+ *x += 1;
70+ if (*x == s->width) {
71+ *y -= 1;
72+ *x = 0;
73+ if (*y < 0) {
74+ *y = s->height - 1;
75+ *plane += 1;
76+ value <<= bits_per_plane;
77+ mask <<= bits_per_plane;
78+ if (*plane >= s->nb_planes)
79+ break;
80+ }
81+ }
82+ }
83+ run--;
84+ }
85+}
86+
87+static const uint8_t cga_mode45_index[6][4] = {
88+ [0] = { 0, 3, 5, 7 }, // mode4, palette#1, low intensity
89+ [1] = { 0, 2, 4, 6 }, // mode4, palette#2, low intensity
90+ [2] = { 0, 3, 4, 7 }, // mode5, low intensity
91+ [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
92+ [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
93+ [5] = { 0, 11, 12, 15 }, // mode5, high intensity
94+};
95+
96+static int decode_frame(AVCodecContext *avctx,
97+ void *data, int *data_size,
98+ AVPacket *avpkt)
99+{
100+ PicContext *s = avctx->priv_data;
101+ int buf_size = avpkt->size;
102+ const uint8_t *buf = avpkt->data;
103+ const uint8_t *buf_end = avpkt->data + buf_size;
104+ uint32_t *palette;
105+ int bits_per_plane, bpp, etype, esize, npal;
106+ int i, x, y, plane;
107+
108+ if (buf_size < 11)
109+ return AVERROR_INVALIDDATA;
110+
111+ if (bytestream_get_le16(&buf) != 0x1234)
112+ return AVERROR_INVALIDDATA;
113+ s->width = bytestream_get_le16(&buf);
114+ s->height = bytestream_get_le16(&buf);
115+ buf += 4;
116+ bits_per_plane = *buf & 0xF;
117+ s->nb_planes = (*buf++ >> 4) + 1;
118+ bpp = s->nb_planes ? bits_per_plane*s->nb_planes : bits_per_plane;
119+ if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
120+ av_log_ask_for_sample(s, "unsupported bit depth\n");
121+ return AVERROR_INVALIDDATA;
122+ }
123+
124+ if (*buf == 0xFF) {
125+ buf += 2;
126+ etype = bytestream_get_le16(&buf);
127+ esize = bytestream_get_le16(&buf);
128+ if (buf_end - buf < esize)
129+ return AVERROR_INVALIDDATA;
130+ } else {
131+ etype = -1;
132+ esize = 0;
133+ }
134+
135+ avctx->pix_fmt = PIX_FMT_PAL8;
136+
137+ if (s->width != avctx->width && s->height != avctx->height) {
138+ if (avcodec_check_dimensions(avctx, s->width, s->height) < 0)
139+ return -1;
140+ avcodec_set_dimensions(avctx, s->width, s->height);
141+ if (s->frame.data[0])
142+ avctx->release_buffer(avctx, &s->frame);
143+ }
144+
145+ if (avctx->get_buffer(avctx, &s->frame) < 0){
146+ av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
147+ return -1;
148+ }
149+ memset(s->frame.data[0], 0, s->height * s->frame.linesize[0]);
150+ s->frame.pict_type = FF_I_TYPE;
151+ s->frame.palette_has_changed = 1;
152+
153+ palette = (uint32_t*)s->frame.data[1];
154+ if (etype == 1 && esize > 1 && *buf < 6) {
155+ int idx = *buf;
156+ npal = 4;
157+ for (i = 0; i < npal; i++)
158+ palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
159+ } else if (etype == 2) {
160+ npal = FFMIN(esize, 16);
161+ for (i = 0; i < npal; i++)
162+ palette[i] = ff_cga_palette[ FFMIN(buf[i], 16)];
163+ } else if (etype == 3) {
164+ npal = FFMIN(esize, 16);
165+ for (i = 0; i < npal; i++)
166+ palette[i] = ff_ega_palette[ FFMIN(buf[i], 63)];
167+ } else if (etype == 4 || etype == 5) {
168+ npal = FFMIN(esize / 3, 256);
169+ for (i = 0; i < npal; i++)
170+ palette[i] = AV_RB24(buf + i*3) << 2;
171+ } else {
172+ if (bpp == 1) {
173+ npal = 2;
174+ palette[0] = 0x000000;
175+ palette[1] = 0xFFFFFF;
176+ } else if (bpp == 2) {
177+ npal = 4;
178+ for (i = 0; i < npal; i++)
179+ palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
180+ } else {
181+ npal = 16;
182+ memcpy(palette, ff_cga_palette, npal * 4);
183+ }
184+ }
185+ // fill remaining palette entries
186+ memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
187+ buf += esize;
188+
189+
190+ x = 0;
191+ y = s->height - 1;
192+ plane = 0;
193+ if (bytestream_get_le16(&buf)) {
194+ while (buf_end - buf >= 6) {
195+ const uint8_t *buf_pend = buf + FFMIN(AV_RL16(buf), buf_end - buf);
196+ //ignore uncompressed block size reported at buf[2]
197+ int marker = buf[4];
198+ buf += 5;
199+
200+ while (plane < s->nb_planes && buf_pend - buf >= 1) {
201+ int run = 1;
202+ int val = *buf++;
203+ if (val == marker) {
204+ run = *buf++;
205+ if (run == 0)
206+ run = bytestream_get_le16(&buf);
207+ val = *buf++;
208+ }
209+ if (buf > buf_end)
210+ break;
211+
212+ if (bits_per_plane == 8) {
213+ picmemset_8bpp(s, val, run, &x, &y);
214+ if (y < 0)
215+ break;
216+ } else {
217+ picmemset(s, val, run, &x, &y, &plane, bits_per_plane);
218+ }
219+ }
220+ }
221+ } else {
222+ av_log_ask_for_sample(s, "uncompressed image\n");
223+ return buf_size;
224+ }
225+
226+ *data_size = sizeof(AVFrame);
227+ *(AVFrame*)data = s->frame;
228+ return buf_size;
229+}
230+
231+static av_cold int decode_end(AVCodecContext *avctx)
232+{
233+ PicContext *s = avctx->priv_data;
234+ if (s->frame.data[0])
235+ avctx->release_buffer(avctx, &s->frame);
236+ return 0;
237+}
238+
239+AVCodec pictor_decoder = {
240+ "pictor",
241+ CODEC_TYPE_VIDEO,
242+ CODEC_ID_PICTOR,
243+ sizeof(PicContext),
244+ NULL,
245+ NULL,
246+ decode_end,
247+ decode_frame,
248+ CODEC_CAP_DR1,
249+ .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
250+};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t