Statistics
| Branch: | Revision:

ffmpeg / libavcodec / pnm.c @ c53d2d90

History | View | Annotate | Download (17.3 KB)

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 "avcodec.h"
22
#include "parser.h" //for ParseContext
23

    
24
typedef struct PNMContext {
25
    uint8_t *bytestream;
26
    uint8_t *bytestream_start;
27
    uint8_t *bytestream_end;
28
    AVFrame picture;
29
    int maxval;                 ///< maximum value of a pixel
30
} PNMContext;
31

    
32
static inline int pnm_space(int c)
33
{
34
    return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
35
}
36

    
37
static void pnm_get(PNMContext *sc, char *str, int buf_size)
38
{
39
    char *s;
40
    int c;
41

    
42
    /* skip spaces and comments */
43
    for(;;) {
44
        c = *sc->bytestream++;
45
        if (c == '#')  {
46
            do  {
47
                c = *sc->bytestream++;
48
            } while (c != '\n' && sc->bytestream < sc->bytestream_end);
49
        } else if (!pnm_space(c)) {
50
            break;
51
        }
52
    }
53

    
54
    s = str;
55
    while (sc->bytestream < sc->bytestream_end && !pnm_space(c)) {
56
        if ((s - str)  < buf_size - 1)
57
            *s++ = c;
58
        c = *sc->bytestream++;
59
    }
60
    *s = '\0';
61
}
62

    
63
static int common_init(AVCodecContext *avctx){
64
    PNMContext *s = avctx->priv_data;
65

    
66
    avcodec_get_frame_defaults((AVFrame*)&s->picture);
67
    avctx->coded_frame= (AVFrame*)&s->picture;
68

    
69
    return 0;
70
}
71

    
72
static int pnm_decode_header(AVCodecContext *avctx, PNMContext * const s){
73
    char buf1[32], tuple_type[32];
74
    int h, w, depth, maxval;
75

    
76
    pnm_get(s, buf1, sizeof(buf1));
77
    if (!strcmp(buf1, "P4")) {
78
        avctx->pix_fmt = PIX_FMT_MONOWHITE;
79
    } else if (!strcmp(buf1, "P5")) {
80
        if (avctx->codec_id == CODEC_ID_PGMYUV)
81
            avctx->pix_fmt = PIX_FMT_YUV420P;
82
        else
83
            avctx->pix_fmt = PIX_FMT_GRAY8;
84
    } else if (!strcmp(buf1, "P6")) {
85
        avctx->pix_fmt = PIX_FMT_RGB24;
86
    } else if (!strcmp(buf1, "P7")) {
87
        w = -1;
88
        h = -1;
89
        maxval = -1;
90
        depth = -1;
91
        tuple_type[0] = '\0';
92
        for(;;) {
93
            pnm_get(s, buf1, sizeof(buf1));
94
            if (!strcmp(buf1, "WIDTH")) {
95
                pnm_get(s, buf1, sizeof(buf1));
96
                w = strtol(buf1, NULL, 10);
97
            } else if (!strcmp(buf1, "HEIGHT")) {
98
                pnm_get(s, buf1, sizeof(buf1));
99
                h = strtol(buf1, NULL, 10);
100
            } else if (!strcmp(buf1, "DEPTH")) {
101
                pnm_get(s, buf1, sizeof(buf1));
102
                depth = strtol(buf1, NULL, 10);
103
            } else if (!strcmp(buf1, "MAXVAL")) {
104
                pnm_get(s, buf1, sizeof(buf1));
105
                maxval = strtol(buf1, NULL, 10);
106
            } else if (!strcmp(buf1, "TUPLETYPE")) {
107
                pnm_get(s, tuple_type, sizeof(tuple_type));
108
            } else if (!strcmp(buf1, "ENDHDR")) {
109
                break;
110
            } else {
111
                return -1;
112
            }
113
        }
114
        /* check that all tags are present */
115
        if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0' || avcodec_check_dimensions(avctx, w, h))
116
            return -1;
117

    
118
        avctx->width = w;
119
        avctx->height = h;
120
        if (depth == 1) {
121
            if (maxval == 1)
122
                avctx->pix_fmt = PIX_FMT_MONOWHITE;
123
            else
124
                avctx->pix_fmt = PIX_FMT_GRAY8;
125
        } else if (depth == 3) {
126
            avctx->pix_fmt = PIX_FMT_RGB24;
127
        } else if (depth == 4) {
128
            avctx->pix_fmt = PIX_FMT_RGB32;
129
        } else {
130
            return -1;
131
        }
132
        return 0;
133
    } else {
134
        return -1;
135
    }
136
    pnm_get(s, buf1, sizeof(buf1));
137
    avctx->width = atoi(buf1);
138
    if (avctx->width <= 0)
139
        return -1;
140
    pnm_get(s, buf1, sizeof(buf1));
141
    avctx->height = atoi(buf1);
142
    if(avcodec_check_dimensions(avctx, avctx->width, avctx->height))
143
        return -1;
144
    if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
145
        pnm_get(s, buf1, sizeof(buf1));
146
        s->maxval = atoi(buf1);
147
        if(s->maxval >= 256 && avctx->pix_fmt == PIX_FMT_GRAY8) {
148
            avctx->pix_fmt = PIX_FMT_GRAY16BE;
149
            if (s->maxval != 65535)
150
                avctx->pix_fmt = PIX_FMT_GRAY16;
151
        }
152
    }
153
    /* more check if YUV420 */
154
    if (avctx->pix_fmt == PIX_FMT_YUV420P) {
155
        if ((avctx->width & 1) != 0)
156
            return -1;
157
        h = (avctx->height * 2);
158
        if ((h % 3) != 0)
159
            return -1;
160
        h /= 3;
161
        avctx->height = h;
162
    }
163
    return 0;
164
}
165

    
166
static int pnm_decode_frame(AVCodecContext *avctx,
167
                        void *data, int *data_size,
168
                        uint8_t *buf, int buf_size)
169
{
170
    PNMContext * const s = avctx->priv_data;
171
    AVFrame *picture = data;
172
    AVFrame * const p= (AVFrame*)&s->picture;
173
    int i, n, linesize, h, upgrade = 0;
174
    unsigned char *ptr;
175

    
176
    s->bytestream_start=
177
    s->bytestream= buf;
178
    s->bytestream_end= buf + buf_size;
179

    
180
    if(pnm_decode_header(avctx, s) < 0)
181
        return -1;
182

    
183
    if(p->data[0])
184
        avctx->release_buffer(avctx, p);
185

    
186
    p->reference= 0;
187
    if(avctx->get_buffer(avctx, p) < 0){
188
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
189
        return -1;
190
    }
191
    p->pict_type= FF_I_TYPE;
192
    p->key_frame= 1;
193

    
194
    switch(avctx->pix_fmt) {
195
    default:
196
        return -1;
197
    case PIX_FMT_RGB24:
198
        n = avctx->width * 3;
199
        goto do_read;
200
    case PIX_FMT_GRAY8:
201
        n = avctx->width;
202
        if (s->maxval < 255)
203
            upgrade = 1;
204
        goto do_read;
205
    case PIX_FMT_GRAY16BE:
206
    case PIX_FMT_GRAY16LE:
207
        n = avctx->width * 2;
208
        if (s->maxval < 65535)
209
            upgrade = 2;
210
        goto do_read;
211
    case PIX_FMT_MONOWHITE:
212
    case PIX_FMT_MONOBLACK:
213
        n = (avctx->width + 7) >> 3;
214
    do_read:
215
        ptr = p->data[0];
216
        linesize = p->linesize[0];
217
        if(s->bytestream + n*avctx->height > s->bytestream_end)
218
            return -1;
219
        for(i = 0; i < avctx->height; i++) {
220
            if (!upgrade)
221
                memcpy(ptr, s->bytestream, n);
222
            else if (upgrade == 1) {
223
                unsigned int j, f = (255*128 + s->maxval/2) / s->maxval;
224
                for (j=0; j<n; j++)
225
                    ptr[j] = (s->bytestream[j] * f + 64) >> 7;
226
            } else if (upgrade == 2) {
227
                unsigned int j, v, f = (65535*32768 + s->maxval/2) / s->maxval;
228
                for (j=0; j<n/2; j++) {
229
                    v = be2me_16(((uint16_t *)s->bytestream)[j]);
230
                    ((uint16_t *)ptr)[j] = (v * f + 16384) >> 15;
231
                }
232
            }
233
            s->bytestream += n;
234
            ptr += linesize;
235
        }
236
        break;
237
    case PIX_FMT_YUV420P:
238
        {
239
            unsigned char *ptr1, *ptr2;
240

    
241
            n = avctx->width;
242
            ptr = p->data[0];
243
            linesize = p->linesize[0];
244
            if(s->bytestream + n*avctx->height*3/2 > s->bytestream_end)
245
                return -1;
246
            for(i = 0; i < avctx->height; i++) {
247
                memcpy(ptr, s->bytestream, n);
248
                s->bytestream += n;
249
                ptr += linesize;
250
            }
251
            ptr1 = p->data[1];
252
            ptr2 = p->data[2];
253
            n >>= 1;
254
            h = avctx->height >> 1;
255
            for(i = 0; i < h; i++) {
256
                memcpy(ptr1, s->bytestream, n);
257
                s->bytestream += n;
258
                memcpy(ptr2, s->bytestream, n);
259
                s->bytestream += n;
260
                ptr1 += p->linesize[1];
261
                ptr2 += p->linesize[2];
262
            }
263
        }
264
        break;
265
    case PIX_FMT_RGB32:
266
        ptr = p->data[0];
267
        linesize = p->linesize[0];
268
        if(s->bytestream + avctx->width*avctx->height*4 > s->bytestream_end)
269
            return -1;
270
        for(i = 0; i < avctx->height; i++) {
271
            int j, r, g, b, a;
272

    
273
            for(j = 0;j < avctx->width; j++) {
274
                r = *s->bytestream++;
275
                g = *s->bytestream++;
276
                b = *s->bytestream++;
277
                a = *s->bytestream++;
278
                ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
279
            }
280
            ptr += linesize;
281
        }
282
        break;
283
    }
284
    *picture= *(AVFrame*)&s->picture;
285
    *data_size = sizeof(AVPicture);
286

    
287
    return s->bytestream - s->bytestream_start;
288
}
289

    
290
static int pnm_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
291
    PNMContext *s = avctx->priv_data;
292
    AVFrame *pict = data;
293
    AVFrame * const p= (AVFrame*)&s->picture;
294
    int i, h, h1, c, n, linesize;
295
    uint8_t *ptr, *ptr1, *ptr2;
296

    
297
    if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
298
        av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
299
        return -1;
300
    }
301

    
302
    *p = *pict;
303
    p->pict_type= FF_I_TYPE;
304
    p->key_frame= 1;
305

    
306
    s->bytestream_start=
307
    s->bytestream= outbuf;
308
    s->bytestream_end= outbuf+buf_size;
309

    
310
    h = avctx->height;
311
    h1 = h;
312
    switch(avctx->pix_fmt) {
313
    case PIX_FMT_MONOWHITE:
314
        c = '4';
315
        n = (avctx->width + 7) >> 3;
316
        break;
317
    case PIX_FMT_GRAY8:
318
        c = '5';
319
        n = avctx->width;
320
        break;
321
    case PIX_FMT_GRAY16BE:
322
        c = '5';
323
        n = avctx->width * 2;
324
        break;
325
    case PIX_FMT_RGB24:
326
        c = '6';
327
        n = avctx->width * 3;
328
        break;
329
    case PIX_FMT_YUV420P:
330
        c = '5';
331
        n = avctx->width;
332
        h1 = (h * 3) / 2;
333
        break;
334
    default:
335
        return -1;
336
    }
337
    snprintf(s->bytestream, s->bytestream_end - s->bytestream,
338
             "P%c\n%d %d\n",
339
             c, avctx->width, h1);
340
    s->bytestream += strlen(s->bytestream);
341
    if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
342
        snprintf(s->bytestream, s->bytestream_end - s->bytestream,
343
                 "%d\n", (avctx->pix_fmt != PIX_FMT_GRAY16BE) ? 255 : 65535);
344
        s->bytestream += strlen(s->bytestream);
345
    }
346

    
347
    ptr = p->data[0];
348
    linesize = p->linesize[0];
349
    for(i=0;i<h;i++) {
350
        memcpy(s->bytestream, ptr, n);
351
        s->bytestream += n;
352
        ptr += linesize;
353
    }
354

    
355
    if (avctx->pix_fmt == PIX_FMT_YUV420P) {
356
        h >>= 1;
357
        n >>= 1;
358
        ptr1 = p->data[1];
359
        ptr2 = p->data[2];
360
        for(i=0;i<h;i++) {
361
            memcpy(s->bytestream, ptr1, n);
362
            s->bytestream += n;
363
            memcpy(s->bytestream, ptr2, n);
364
            s->bytestream += n;
365
                ptr1 += p->linesize[1];
366
                ptr2 += p->linesize[2];
367
        }
368
    }
369
    return s->bytestream - s->bytestream_start;
370
}
371

    
372
static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
373
    PNMContext *s = avctx->priv_data;
374
    AVFrame *pict = data;
375
    AVFrame * const p= (AVFrame*)&s->picture;
376
    int i, h, w, n, linesize, depth, maxval;
377
    const char *tuple_type;
378
    uint8_t *ptr;
379

    
380
    if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
381
        av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
382
        return -1;
383
    }
384

    
385
    *p = *pict;
386
    p->pict_type= FF_I_TYPE;
387
    p->key_frame= 1;
388

    
389
    s->bytestream_start=
390
    s->bytestream= outbuf;
391
    s->bytestream_end= outbuf+buf_size;
392

    
393
    h = avctx->height;
394
    w = avctx->width;
395
    switch(avctx->pix_fmt) {
396
    case PIX_FMT_MONOWHITE:
397
        n = (w + 7) >> 3;
398
        depth = 1;
399
        maxval = 1;
400
        tuple_type = "BLACKANDWHITE";
401
        break;
402
    case PIX_FMT_GRAY8:
403
        n = w;
404
        depth = 1;
405
        maxval = 255;
406
        tuple_type = "GRAYSCALE";
407
        break;
408
    case PIX_FMT_RGB24:
409
        n = w * 3;
410
        depth = 3;
411
        maxval = 255;
412
        tuple_type = "RGB";
413
        break;
414
    case PIX_FMT_RGB32:
415
        n = w * 4;
416
        depth = 4;
417
        maxval = 255;
418
        tuple_type = "RGB_ALPHA";
419
        break;
420
    default:
421
        return -1;
422
    }
423
    snprintf(s->bytestream, s->bytestream_end - s->bytestream,
424
             "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
425
             w, h, depth, maxval, tuple_type);
426
    s->bytestream += strlen(s->bytestream);
427

    
428
    ptr = p->data[0];
429
    linesize = p->linesize[0];
430

    
431
    if (avctx->pix_fmt == PIX_FMT_RGB32) {
432
        int j;
433
        unsigned int v;
434

    
435
        for(i=0;i<h;i++) {
436
            for(j=0;j<w;j++) {
437
                v = ((uint32_t *)ptr)[j];
438
                *s->bytestream++ = v >> 16;
439
                *s->bytestream++ = v >> 8;
440
                *s->bytestream++ = v;
441
                *s->bytestream++ = v >> 24;
442
            }
443
            ptr += linesize;
444
        }
445
    } else {
446
        for(i=0;i<h;i++) {
447
            memcpy(s->bytestream, ptr, n);
448
            s->bytestream += n;
449
            ptr += linesize;
450
        }
451
    }
452
    return s->bytestream - s->bytestream_start;
453
}
454

    
455
#if 0
456
static int pnm_probe(AVProbeData *pd)
457
{
458
    const char *p = pd->buf;
459
    if (pd->buf_size >= 8 &&
460
        p[0] == 'P' &&
461
        p[1] >= '4' && p[1] <= '6' &&
462
        pnm_space(p[2]) )
463
        return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */
464
    else
465
        return 0;
466
}
467

468
static int pgmyuv_probe(AVProbeData *pd)
469
{
470
    if (match_ext(pd->filename, "pgmyuv"))
471
        return AVPROBE_SCORE_MAX;
472
    else
473
        return 0;
474
}
475

476
static int pam_probe(AVProbeData *pd)
477
{
478
    const char *p = pd->buf;
479
    if (pd->buf_size >= 8 &&
480
        p[0] == 'P' &&
481
        p[1] == '7' &&
482
        p[2] == '\n')
483
        return AVPROBE_SCORE_MAX;
484
    else
485
        return 0;
486
}
487
#endif
488

    
489
#ifdef CONFIG_PNM_PARSER
490
static int pnm_parse(AVCodecParserContext *s,
491
                           AVCodecContext *avctx,
492
                           const uint8_t **poutbuf, int *poutbuf_size,
493
                           const uint8_t *buf, int buf_size)
494
{
495
    ParseContext *pc = s->priv_data;
496
    PNMContext pnmctx;
497
    int next;
498

    
499
    for(; pc->overread>0; pc->overread--){
500
        pc->buffer[pc->index++]= pc->buffer[pc->overread_index++];
501
    }
502
retry:
503
    if(pc->index){
504
        pnmctx.bytestream_start=
505
        pnmctx.bytestream= pc->buffer;
506
        pnmctx.bytestream_end= pc->buffer + pc->index;
507
    }else{
508
        pnmctx.bytestream_start=
509
        pnmctx.bytestream= (uint8_t *) buf; /* casts avoid warnings */
510
        pnmctx.bytestream_end= (uint8_t *) buf + buf_size;
511
    }
512
    if(pnm_decode_header(avctx, &pnmctx) < 0){
513
        if(pnmctx.bytestream < pnmctx.bytestream_end){
514
            if(pc->index){
515
                pc->index=0;
516
            }else{
517
                buf++;
518
                buf_size--;
519
            }
520
            goto retry;
521
        }
522
#if 0
523
        if(pc->index && pc->index*2 + FF_INPUT_BUFFER_PADDING_SIZE < pc->buffer_size && buf_size > pc->index){
524
            memcpy(pc->buffer + pc->index, buf, pc->index);
525
            pc->index += pc->index;
526
            buf += pc->index;
527
            buf_size -= pc->index;
528
            goto retry;
529
        }
530
#endif
531
        next= END_NOT_FOUND;
532
    }else{
533
        next= pnmctx.bytestream - pnmctx.bytestream_start
534
            + avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
535
        if(pnmctx.bytestream_start!=buf)
536
            next-= pc->index;
537
        if(next > buf_size)
538
            next= END_NOT_FOUND;
539
    }
540

    
541
    if(ff_combine_frame(pc, next, &buf, &buf_size)<0){
542
        *poutbuf = NULL;
543
        *poutbuf_size = 0;
544
        return buf_size;
545
    }
546
    *poutbuf = buf;
547
    *poutbuf_size = buf_size;
548
    return next;
549
}
550

    
551
AVCodecParser pnm_parser = {
552
    { CODEC_ID_PGM, CODEC_ID_PGMYUV, CODEC_ID_PPM, CODEC_ID_PBM, CODEC_ID_PAM},
553
    sizeof(ParseContext),
554
    NULL,
555
    pnm_parse,
556
    ff_parse_close,
557
};
558
#endif /* CONFIG_PNM_PARSER */
559

    
560
#ifdef CONFIG_PGM_ENCODER
561
AVCodec pgm_encoder = {
562
    "pgm",
563
    CODEC_TYPE_VIDEO,
564
    CODEC_ID_PGM,
565
    sizeof(PNMContext),
566
    common_init,
567
    pnm_encode_frame,
568
    NULL, //encode_end,
569
    pnm_decode_frame,
570
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, -1},
571
};
572
#endif // CONFIG_PGM_ENCODER
573

    
574
#ifdef CONFIG_PGMYUV_ENCODER
575
AVCodec pgmyuv_encoder = {
576
    "pgmyuv",
577
    CODEC_TYPE_VIDEO,
578
    CODEC_ID_PGMYUV,
579
    sizeof(PNMContext),
580
    common_init,
581
    pnm_encode_frame,
582
    NULL, //encode_end,
583
    pnm_decode_frame,
584
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1},
585
};
586
#endif // CONFIG_PGMYUV_ENCODER
587

    
588
#ifdef CONFIG_PPM_ENCODER
589
AVCodec ppm_encoder = {
590
    "ppm",
591
    CODEC_TYPE_VIDEO,
592
    CODEC_ID_PPM,
593
    sizeof(PNMContext),
594
    common_init,
595
    pnm_encode_frame,
596
    NULL, //encode_end,
597
    pnm_decode_frame,
598
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, -1},
599
};
600
#endif // CONFIG_PPM_ENCODER
601

    
602
#ifdef CONFIG_PBM_ENCODER
603
AVCodec pbm_encoder = {
604
    "pbm",
605
    CODEC_TYPE_VIDEO,
606
    CODEC_ID_PBM,
607
    sizeof(PNMContext),
608
    common_init,
609
    pnm_encode_frame,
610
    NULL, //encode_end,
611
    pnm_decode_frame,
612
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_MONOWHITE, -1},
613
};
614
#endif // CONFIG_PBM_ENCODER
615

    
616
#ifdef CONFIG_PAM_ENCODER
617
AVCodec pam_encoder = {
618
    "pam",
619
    CODEC_TYPE_VIDEO,
620
    CODEC_ID_PAM,
621
    sizeof(PNMContext),
622
    common_init,
623
    pam_encode_frame,
624
    NULL, //encode_end,
625
    pnm_decode_frame,
626
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, -1},
627
};
628
#endif // CONFIG_PAM_ENCODER