Statistics
| Branch: | Revision:

ffmpeg / libavformat / pnm.c @ a7eb3c8d

History | View | Annotate | Download (11.9 KB)

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