ade5d7c5dd35364131df0203c94d200949a8594d
[libav.git] / libavformat / pnm.c
1 /*
2 * PNM image format
3 * Copyright (c) 2002, 2003 Fabrice Bellard.
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 #include "avformat.h"
22
23 static inline int pnm_space(int c)
24 {
25 return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
26 }
27
28 static void pnm_get(ByteIOContext *f, char *str, int buf_size)
29 {
30 char *s;
31 int c;
32
33 /* skip spaces and comments */
34 for(;;) {
35 c = url_fgetc(f);
36 if (c == '#') {
37 do {
38 c = url_fgetc(f);
39 } while (c != '\n' && c != URL_EOF);
40 } else if (!pnm_space(c)) {
41 break;
42 }
43 }
44
45 s = str;
46 while (c != URL_EOF && !pnm_space(c)) {
47 if ((s - str) < buf_size - 1)
48 *s++ = c;
49 c = url_fgetc(f);
50 }
51 *s = '\0';
52 }
53
54 static int pnm_read1(ByteIOContext *f,
55 int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque,
56 int allow_yuv)
57 {
58 int i, n, linesize, h;
59 char buf1[32];
60 unsigned char *ptr;
61 AVImageInfo info1, *info = &info1;
62 int ret;
63
64 pnm_get(f, buf1, sizeof(buf1));
65 if (!strcmp(buf1, "P4")) {
66 info->pix_fmt = PIX_FMT_MONOWHITE;
67 } else if (!strcmp(buf1, "P5")) {
68 if (allow_yuv)
69 info->pix_fmt = PIX_FMT_YUV420P;
70 else
71 info->pix_fmt = PIX_FMT_GRAY8;
72 } else if (!strcmp(buf1, "P6")) {
73 info->pix_fmt = PIX_FMT_RGB24;
74 } else {
75 return AVERROR_INVALIDDATA;
76 }
77 pnm_get(f, buf1, sizeof(buf1));
78 info->width = atoi(buf1);
79 if (info->width <= 0)
80 return AVERROR_INVALIDDATA;
81 pnm_get(f, buf1, sizeof(buf1));
82 info->height = atoi(buf1);
83 if (info->height <= 0)
84 return AVERROR_INVALIDDATA;
85 if (info->pix_fmt != PIX_FMT_MONOWHITE) {
86 pnm_get(f, buf1, sizeof(buf1));
87 }
88
89 /* more check if YUV420 */
90 if (info->pix_fmt == PIX_FMT_YUV420P) {
91 if ((info->width & 1) != 0)
92 return AVERROR_INVALIDDATA;
93 h = (info->height * 2);
94 if ((h % 3) != 0)
95 return AVERROR_INVALIDDATA;
96 h /= 3;
97 info->height = h;
98 }
99
100 ret = alloc_cb(opaque, info);
101 if (ret)
102 return ret;
103
104 switch(info->pix_fmt) {
105 default:
106 return AVERROR_INVALIDDATA;
107 case PIX_FMT_RGB24:
108 n = info->width * 3;
109 goto do_read;
110 case PIX_FMT_GRAY8:
111 n = info->width;
112 goto do_read;
113 case PIX_FMT_MONOWHITE:
114 n = (info->width + 7) >> 3;
115 do_read:
116 ptr = info->pict.data[0];
117 linesize = info->pict.linesize[0];
118 for(i = 0; i < info->height; i++) {
119 get_buffer(f, ptr, n);
120 ptr += linesize;
121 }
122 break;
123 case PIX_FMT_YUV420P:
124 {
125 unsigned char *ptr1, *ptr2;
126
127 n = info->width;
128 ptr = info->pict.data[0];
129 linesize = info->pict.linesize[0];
130 for(i = 0; i < info->height; i++) {
131 get_buffer(f, ptr, n);
132 ptr += linesize;
133 }
134 ptr1 = info->pict.data[1];
135 ptr2 = info->pict.data[2];
136 n >>= 1;
137 h = info->height >> 1;
138 for(i = 0; i < h; i++) {
139 get_buffer(f, ptr1, n);
140 get_buffer(f, ptr2, n);
141 ptr1 += info->pict.linesize[1];
142 ptr2 += info->pict.linesize[2];
143 }
144 }
145 break;
146 }
147 return 0;
148 }
149
150 static int pnm_read(ByteIOContext *f,
151 int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
152 {
153 return pnm_read1(f, alloc_cb, opaque, 0);
154 }
155
156 static int pgmyuv_read(ByteIOContext *f,
157 int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
158 {
159 return pnm_read1(f, alloc_cb, opaque, 1);
160 }
161
162 static int pnm_write(ByteIOContext *pb, AVImageInfo *info)
163 {
164 int i, h, h1, c, n, linesize;
165 char buf[100];
166 uint8_t *ptr, *ptr1, *ptr2;
167
168 h = info->height;
169 h1 = h;
170 switch(info->pix_fmt) {
171 case PIX_FMT_MONOWHITE:
172 c = '4';
173 n = (info->width + 7) >> 3;
174 break;
175 case PIX_FMT_GRAY8:
176 c = '5';
177 n = info->width;
178 break;
179 case PIX_FMT_RGB24:
180 c = '6';
181 n = info->width * 3;
182 break;
183 case PIX_FMT_YUV420P:
184 c = '5';
185 n = info->width;
186 h1 = (h * 3) / 2;
187 break;
188 default:
189 return AVERROR_INVALIDDATA;
190 }
191 snprintf(buf, sizeof(buf),
192 "P%c\n%d %d\n",
193 c, info->width, h1);
194 put_buffer(pb, buf, strlen(buf));
195 if (info->pix_fmt != PIX_FMT_MONOWHITE) {
196 snprintf(buf, sizeof(buf),
197 "%d\n", 255);
198 put_buffer(pb, buf, strlen(buf));
199 }
200
201 ptr = info->pict.data[0];
202 linesize = info->pict.linesize[0];
203 for(i=0;i<h;i++) {
204 put_buffer(pb, ptr, n);
205 ptr += linesize;
206 }
207
208 if (info->pix_fmt == PIX_FMT_YUV420P) {
209 h >>= 1;
210 n >>= 1;
211 ptr1 = info->pict.data[1];
212 ptr2 = info->pict.data[2];
213 for(i=0;i<h;i++) {
214 put_buffer(pb, ptr1, n);
215 put_buffer(pb, ptr2, n);
216 ptr1 += info->pict.linesize[1];
217 ptr2 += info->pict.linesize[2];
218 }
219 }
220 put_flush_packet(pb);
221 return 0;
222 }
223
224 static int pam_read(ByteIOContext *f,
225 int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
226 {
227 int i, n, linesize, h, w, depth, maxval;
228 char buf1[32], tuple_type[32];
229 unsigned char *ptr;
230 AVImageInfo info1, *info = &info1;
231 int ret;
232
233 pnm_get(f, buf1, sizeof(buf1));
234 if (strcmp(buf1, "P7") != 0)
235 return AVERROR_INVALIDDATA;
236 w = -1;
237 h = -1;
238 maxval = -1;
239 depth = -1;
240 tuple_type[0] = '\0';
241 for(;;) {
242 pnm_get(f, buf1, sizeof(buf1));
243 if (!strcmp(buf1, "WIDTH")) {
244 pnm_get(f, buf1, sizeof(buf1));
245 w = strtol(buf1, NULL, 10);
246 } else if (!strcmp(buf1, "HEIGHT")) {
247 pnm_get(f, buf1, sizeof(buf1));
248 h = strtol(buf1, NULL, 10);
249 } else if (!strcmp(buf1, "DEPTH")) {
250 pnm_get(f, buf1, sizeof(buf1));
251 depth = strtol(buf1, NULL, 10);
252 } else if (!strcmp(buf1, "MAXVAL")) {
253 pnm_get(f, buf1, sizeof(buf1));
254 maxval = strtol(buf1, NULL, 10);
255 } else if (!strcmp(buf1, "TUPLETYPE")) {
256 pnm_get(f, buf1, sizeof(buf1));
257 pstrcpy(tuple_type, sizeof(tuple_type), buf1);
258 } else if (!strcmp(buf1, "ENDHDR")) {
259 break;
260 } else {
261 return AVERROR_INVALIDDATA;
262 }
263 }
264 /* check that all tags are present */
265 if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0')
266 return AVERROR_INVALIDDATA;
267 info->width = w;
268 info->height = h;
269 if (depth == 1) {
270 if (maxval == 1)
271 info->pix_fmt = PIX_FMT_MONOWHITE;
272 else
273 info->pix_fmt = PIX_FMT_GRAY8;
274 } else if (depth == 3) {
275 info->pix_fmt = PIX_FMT_RGB24;
276 } else if (depth == 4) {
277 info->pix_fmt = PIX_FMT_RGBA32;
278 } else {
279 return AVERROR_INVALIDDATA;
280 }
281 ret = alloc_cb(opaque, info);
282 if (ret)
283 return ret;
284
285 switch(info->pix_fmt) {
286 default:
287 return AVERROR_INVALIDDATA;
288 case PIX_FMT_RGB24:
289 n = info->width * 3;
290 goto do_read;
291 case PIX_FMT_GRAY8:
292 n = info->width;
293 goto do_read;
294 case PIX_FMT_MONOWHITE:
295 n = (info->width + 7) >> 3;
296 do_read:
297 ptr = info->pict.data[0];
298 linesize = info->pict.linesize[0];
299 for(i = 0; i < info->height; i++) {
300 get_buffer(f, ptr, n);
301 ptr += linesize;
302 }
303 break;
304 case PIX_FMT_RGBA32:
305 ptr = info->pict.data[0];
306 linesize = info->pict.linesize[0];
307 for(i = 0; i < info->height; i++) {
308 int j, r, g, b, a;
309
310 for(j = 0;j < w; j++) {
311 r = get_byte(f);
312 g = get_byte(f);
313 b = get_byte(f);
314 a = get_byte(f);
315 ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
316 }
317 ptr += linesize;
318 }
319 break;
320 }
321 return 0;
322 }
323
324 static int pam_write(ByteIOContext *pb, AVImageInfo *info)
325 {
326 int i, h, w, n, linesize, depth, maxval;
327 const char *tuple_type;
328 char buf[100];
329 uint8_t *ptr;
330
331 h = info->height;
332 w = info->width;
333 switch(info->pix_fmt) {
334 case PIX_FMT_MONOWHITE:
335 n = (info->width + 7) >> 3;
336 depth = 1;
337 maxval = 1;
338 tuple_type = "BLACKANDWHITE";
339 break;
340 case PIX_FMT_GRAY8:
341 n = info->width;
342 depth = 1;
343 maxval = 255;
344 tuple_type = "GRAYSCALE";
345 break;
346 case PIX_FMT_RGB24:
347 n = info->width * 3;
348 depth = 3;
349 maxval = 255;
350 tuple_type = "RGB";
351 break;
352 case PIX_FMT_RGBA32:
353 n = info->width * 4;
354 depth = 4;
355 maxval = 255;
356 tuple_type = "RGB_ALPHA";
357 break;
358 default:
359 return AVERROR_INVALIDDATA;
360 }
361 snprintf(buf, sizeof(buf),
362 "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
363 w, h, depth, maxval, tuple_type);
364 put_buffer(pb, buf, strlen(buf));
365
366 ptr = info->pict.data[0];
367 linesize = info->pict.linesize[0];
368
369 if (info->pix_fmt == PIX_FMT_RGBA32) {
370 int j;
371 unsigned int v;
372
373 for(i=0;i<h;i++) {
374 for(j=0;j<w;j++) {
375 v = ((uint32_t *)ptr)[j];
376 put_byte(pb, (v >> 16) & 0xff);
377 put_byte(pb, (v >> 8) & 0xff);
378 put_byte(pb, (v) & 0xff);
379 put_byte(pb, (v >> 24) & 0xff);
380 }
381 ptr += linesize;
382 }
383 } else {
384 for(i=0;i<h;i++) {
385 put_buffer(pb, ptr, n);
386 ptr += linesize;
387 }
388 }
389 put_flush_packet(pb);
390 return 0;
391 }
392
393 static int pnm_probe(AVProbeData *pd)
394 {
395 const char *p = pd->buf;
396 if (pd->buf_size >= 8 &&
397 p[0] == 'P' &&
398 p[1] >= '4' && p[1] <= '6' &&
399 pnm_space(p[2]) )
400 return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */
401 else
402 return 0;
403 }
404
405 static int pgmyuv_probe(AVProbeData *pd)
406 {
407 if (match_ext(pd->filename, "pgmyuv"))
408 return AVPROBE_SCORE_MAX;
409 else
410 return 0;
411 }
412
413 static int pam_probe(AVProbeData *pd)
414 {
415 const char *p = pd->buf;
416 if (pd->buf_size >= 8 &&
417 p[0] == 'P' &&
418 p[1] == '7' &&
419 p[2] == '\n')
420 return AVPROBE_SCORE_MAX;
421 else
422 return 0;
423 }
424
425 AVImageFormat pnm_image_format = {
426 "pnm",
427 NULL,
428 pnm_probe,
429 pnm_read,
430 0,
431 NULL,
432 };
433
434 AVImageFormat pbm_image_format = {
435 "pbm",
436 "pbm",
437 NULL,
438 NULL,
439 (1 << PIX_FMT_MONOWHITE),
440 pnm_write,
441 };
442
443 AVImageFormat pgm_image_format = {
444 "pgm",
445 "pgm",
446 NULL,
447 NULL,
448 (1 << PIX_FMT_GRAY8),
449 pnm_write,
450 };
451
452 AVImageFormat ppm_image_format = {
453 "ppm",
454 "ppm",
455 NULL,
456 NULL,
457 (1 << PIX_FMT_RGB24),
458 pnm_write,
459 };
460
461 AVImageFormat pam_image_format = {
462 "pam",
463 "pam",
464 pam_probe,
465 pam_read,
466 (1 << PIX_FMT_MONOWHITE) | (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_RGB24) |
467 (1 << PIX_FMT_RGBA32),
468 pam_write,
469 };
470
471 AVImageFormat pgmyuv_image_format = {
472 "pgmyuv",
473 "pgmyuv",
474 pgmyuv_probe,
475 pgmyuv_read,
476 (1 << PIX_FMT_YUV420P),
477 pnm_write,
478 };