]> git.sesse.net Git - ffmpeg/blob - libavformat/pnm.c
* Fixing a bug with incorrect bits set in AAUX source pack
[ffmpeg] / 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 };