Revision 9ac2e797 libavcodec/pnm.c

View differences:

libavcodec/pnm.c
21 21
#include "avcodec.h"
22 22
#include "pnm.h"
23 23

  
24

  
25
static int common_init(AVCodecContext *avctx){
26
    PNMContext *s = avctx->priv_data;
27

  
28
    avcodec_get_frame_defaults((AVFrame*)&s->picture);
29
    avctx->coded_frame= (AVFrame*)&s->picture;
30

  
31
    return 0;
24
static inline int pnm_space(int c)
25
{
26
    return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
32 27
}
33 28

  
34
static int pnm_decode_frame(AVCodecContext *avctx,
35
                        void *data, int *data_size,
36
                        uint8_t *buf, int buf_size)
29
static void pnm_get(PNMContext *sc, char *str, int buf_size)
37 30
{
38
    PNMContext * const s = avctx->priv_data;
39
    AVFrame *picture = data;
40
    AVFrame * const p= (AVFrame*)&s->picture;
41
    int i, n, linesize, h, upgrade = 0;
42
    unsigned char *ptr;
43

  
44
    s->bytestream_start=
45
    s->bytestream= buf;
46
    s->bytestream_end= buf + buf_size;
47

  
48
    if(ff_pnm_decode_header(avctx, s) < 0)
49
        return -1;
50

  
51
    if(p->data[0])
52
        avctx->release_buffer(avctx, p);
53

  
54
    p->reference= 0;
55
    if(avctx->get_buffer(avctx, p) < 0){
56
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
57
        return -1;
31
    char *s;
32
    int c;
33

  
34
    /* skip spaces and comments */
35
    for(;;) {
36
        c = *sc->bytestream++;
37
        if (c == '#')  {
38
            do  {
39
                c = *sc->bytestream++;
40
            } while (c != '\n' && sc->bytestream < sc->bytestream_end);
41
        } else if (!pnm_space(c)) {
42
            break;
43
        }
58 44
    }
59
    p->pict_type= FF_I_TYPE;
60
    p->key_frame= 1;
61 45

  
62
    switch(avctx->pix_fmt) {
63
    default:
64
        return -1;
65
    case PIX_FMT_RGB24:
66
        n = avctx->width * 3;
67
        goto do_read;
68
    case PIX_FMT_GRAY8:
69
        n = avctx->width;
70
        if (s->maxval < 255)
71
            upgrade = 1;
72
        goto do_read;
73
    case PIX_FMT_GRAY16BE:
74
    case PIX_FMT_GRAY16LE:
75
        n = avctx->width * 2;
76
        if (s->maxval < 65535)
77
            upgrade = 2;
78
        goto do_read;
79
    case PIX_FMT_MONOWHITE:
80
    case PIX_FMT_MONOBLACK:
81
        n = (avctx->width + 7) >> 3;
82
    do_read:
83
        ptr = p->data[0];
84
        linesize = p->linesize[0];
85
        if(s->bytestream + n*avctx->height > s->bytestream_end)
86
            return -1;
87
        for(i = 0; i < avctx->height; i++) {
88
            if (!upgrade)
89
                memcpy(ptr, s->bytestream, n);
90
            else if (upgrade == 1) {
91
                unsigned int j, f = (255*128 + s->maxval/2) / s->maxval;
92
                for (j=0; j<n; j++)
93
                    ptr[j] = (s->bytestream[j] * f + 64) >> 7;
94
            } else if (upgrade == 2) {
95
                unsigned int j, v, f = (65535*32768 + s->maxval/2) / s->maxval;
96
                for (j=0; j<n/2; j++) {
97
                    v = be2me_16(((uint16_t *)s->bytestream)[j]);
98
                    ((uint16_t *)ptr)[j] = (v * f + 16384) >> 15;
99
                }
100
            }
101
            s->bytestream += n;
102
            ptr += linesize;
103
        }
104
        break;
105
    case PIX_FMT_YUV420P:
106
        {
107
            unsigned char *ptr1, *ptr2;
46
    s = str;
47
    while (sc->bytestream < sc->bytestream_end && !pnm_space(c)) {
48
        if ((s - str)  < buf_size - 1)
49
            *s++ = c;
50
        c = *sc->bytestream++;
51
    }
52
    *s = '\0';
53
}
108 54

  
109
            n = avctx->width;
110
            ptr = p->data[0];
111
            linesize = p->linesize[0];
112
            if(s->bytestream + n*avctx->height*3/2 > s->bytestream_end)
55
int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s){
56
    char buf1[32], tuple_type[32];
57
    int h, w, depth, maxval;
58

  
59
    pnm_get(s, buf1, sizeof(buf1));
60
    if (!strcmp(buf1, "P4")) {
61
        avctx->pix_fmt = PIX_FMT_MONOWHITE;
62
    } else if (!strcmp(buf1, "P5")) {
63
        if (avctx->codec_id == CODEC_ID_PGMYUV)
64
            avctx->pix_fmt = PIX_FMT_YUV420P;
65
        else
66
            avctx->pix_fmt = PIX_FMT_GRAY8;
67
    } else if (!strcmp(buf1, "P6")) {
68
        avctx->pix_fmt = PIX_FMT_RGB24;
69
    } else if (!strcmp(buf1, "P7")) {
70
        w = -1;
71
        h = -1;
72
        maxval = -1;
73
        depth = -1;
74
        tuple_type[0] = '\0';
75
        for(;;) {
76
            pnm_get(s, buf1, sizeof(buf1));
77
            if (!strcmp(buf1, "WIDTH")) {
78
                pnm_get(s, buf1, sizeof(buf1));
79
                w = strtol(buf1, NULL, 10);
80
            } else if (!strcmp(buf1, "HEIGHT")) {
81
                pnm_get(s, buf1, sizeof(buf1));
82
                h = strtol(buf1, NULL, 10);
83
            } else if (!strcmp(buf1, "DEPTH")) {
84
                pnm_get(s, buf1, sizeof(buf1));
85
                depth = strtol(buf1, NULL, 10);
86
            } else if (!strcmp(buf1, "MAXVAL")) {
87
                pnm_get(s, buf1, sizeof(buf1));
88
                maxval = strtol(buf1, NULL, 10);
89
            } else if (!strcmp(buf1, "TUPLETYPE")) {
90
                pnm_get(s, tuple_type, sizeof(tuple_type));
91
            } else if (!strcmp(buf1, "ENDHDR")) {
92
                break;
93
            } else {
113 94
                return -1;
114
            for(i = 0; i < avctx->height; i++) {
115
                memcpy(ptr, s->bytestream, n);
116
                s->bytestream += n;
117
                ptr += linesize;
118
            }
119
            ptr1 = p->data[1];
120
            ptr2 = p->data[2];
121
            n >>= 1;
122
            h = avctx->height >> 1;
123
            for(i = 0; i < h; i++) {
124
                memcpy(ptr1, s->bytestream, n);
125
                s->bytestream += n;
126
                memcpy(ptr2, s->bytestream, n);
127
                s->bytestream += n;
128
                ptr1 += p->linesize[1];
129
                ptr2 += p->linesize[2];
130 95
            }
131 96
        }
132
        break;
133
    case PIX_FMT_RGB32:
134
        ptr = p->data[0];
135
        linesize = p->linesize[0];
136
        if(s->bytestream + avctx->width*avctx->height*4 > s->bytestream_end)
97
        /* check that all tags are present */
98
        if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0' || avcodec_check_dimensions(avctx, w, h))
137 99
            return -1;
138
        for(i = 0; i < avctx->height; i++) {
139
            int j, r, g, b, a;
140 100

  
141
            for(j = 0;j < avctx->width; j++) {
142
                r = *s->bytestream++;
143
                g = *s->bytestream++;
144
                b = *s->bytestream++;
145
                a = *s->bytestream++;
146
                ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
147
            }
148
            ptr += linesize;
101
        avctx->width = w;
102
        avctx->height = h;
103
        if (depth == 1) {
104
            if (maxval == 1)
105
                avctx->pix_fmt = PIX_FMT_MONOWHITE;
106
            else
107
                avctx->pix_fmt = PIX_FMT_GRAY8;
108
        } else if (depth == 3) {
109
            avctx->pix_fmt = PIX_FMT_RGB24;
110
        } else if (depth == 4) {
111
            avctx->pix_fmt = PIX_FMT_RGB32;
112
        } else {
113
            return -1;
149 114
        }
150
        break;
151
    }
152
    *picture= *(AVFrame*)&s->picture;
153
    *data_size = sizeof(AVPicture);
154

  
155
    return s->bytestream - s->bytestream_start;
156
}
157

  
158
static int pnm_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
159
    PNMContext *s = avctx->priv_data;
160
    AVFrame *pict = data;
161
    AVFrame * const p= (AVFrame*)&s->picture;
162
    int i, h, h1, c, n, linesize;
163
    uint8_t *ptr, *ptr1, *ptr2;
164

  
165
    if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
166
        av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
115
        return 0;
116
    } else {
167 117
        return -1;
168 118
    }
169

  
170
    *p = *pict;
171
    p->pict_type= FF_I_TYPE;
172
    p->key_frame= 1;
173

  
174
    s->bytestream_start=
175
    s->bytestream= outbuf;
176
    s->bytestream_end= outbuf+buf_size;
177

  
178
    h = avctx->height;
179
    h1 = h;
180
    switch(avctx->pix_fmt) {
181
    case PIX_FMT_MONOWHITE:
182
        c = '4';
183
        n = (avctx->width + 7) >> 3;
184
        break;
185
    case PIX_FMT_GRAY8:
186
        c = '5';
187
        n = avctx->width;
188
        break;
189
    case PIX_FMT_GRAY16BE:
190
        c = '5';
191
        n = avctx->width * 2;
192
        break;
193
    case PIX_FMT_RGB24:
194
        c = '6';
195
        n = avctx->width * 3;
196
        break;
197
    case PIX_FMT_YUV420P:
198
        c = '5';
199
        n = avctx->width;
200
        h1 = (h * 3) / 2;
201
        break;
202
    default:
119
    pnm_get(s, buf1, sizeof(buf1));
120
    avctx->width = atoi(buf1);
121
    if (avctx->width <= 0)
122
        return -1;
123
    pnm_get(s, buf1, sizeof(buf1));
124
    avctx->height = atoi(buf1);
125
    if(avcodec_check_dimensions(avctx, avctx->width, avctx->height))
203 126
        return -1;
204
    }
205
    snprintf(s->bytestream, s->bytestream_end - s->bytestream,
206
             "P%c\n%d %d\n",
207
             c, avctx->width, h1);
208
    s->bytestream += strlen(s->bytestream);
209 127
    if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
210
        snprintf(s->bytestream, s->bytestream_end - s->bytestream,
211
                 "%d\n", (avctx->pix_fmt != PIX_FMT_GRAY16BE) ? 255 : 65535);
212
        s->bytestream += strlen(s->bytestream);
213
    }
214

  
215
    ptr = p->data[0];
216
    linesize = p->linesize[0];
217
    for(i=0;i<h;i++) {
218
        memcpy(s->bytestream, ptr, n);
219
        s->bytestream += n;
220
        ptr += linesize;
221
    }
222

  
223
    if (avctx->pix_fmt == PIX_FMT_YUV420P) {
224
        h >>= 1;
225
        n >>= 1;
226
        ptr1 = p->data[1];
227
        ptr2 = p->data[2];
228
        for(i=0;i<h;i++) {
229
            memcpy(s->bytestream, ptr1, n);
230
            s->bytestream += n;
231
            memcpy(s->bytestream, ptr2, n);
232
            s->bytestream += n;
233
                ptr1 += p->linesize[1];
234
                ptr2 += p->linesize[2];
128
        pnm_get(s, buf1, sizeof(buf1));
129
        s->maxval = atoi(buf1);
130
        if(s->maxval >= 256 && avctx->pix_fmt == PIX_FMT_GRAY8) {
131
            avctx->pix_fmt = PIX_FMT_GRAY16BE;
132
            if (s->maxval != 65535)
133
                avctx->pix_fmt = PIX_FMT_GRAY16;
235 134
        }
236 135
    }
237
    return s->bytestream - s->bytestream_start;
238
}
239

  
240
static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
241
    PNMContext *s = avctx->priv_data;
242
    AVFrame *pict = data;
243
    AVFrame * const p= (AVFrame*)&s->picture;
244
    int i, h, w, n, linesize, depth, maxval;
245
    const char *tuple_type;
246
    uint8_t *ptr;
247

  
248
    if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
249
        av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
250
        return -1;
251
    }
252

  
253
    *p = *pict;
254
    p->pict_type= FF_I_TYPE;
255
    p->key_frame= 1;
256

  
257
    s->bytestream_start=
258
    s->bytestream= outbuf;
259
    s->bytestream_end= outbuf+buf_size;
260

  
261
    h = avctx->height;
262
    w = avctx->width;
263
    switch(avctx->pix_fmt) {
264
    case PIX_FMT_MONOWHITE:
265
        n = (w + 7) >> 3;
266
        depth = 1;
267
        maxval = 1;
268
        tuple_type = "BLACKANDWHITE";
269
        break;
270
    case PIX_FMT_GRAY8:
271
        n = w;
272
        depth = 1;
273
        maxval = 255;
274
        tuple_type = "GRAYSCALE";
275
        break;
276
    case PIX_FMT_RGB24:
277
        n = w * 3;
278
        depth = 3;
279
        maxval = 255;
280
        tuple_type = "RGB";
281
        break;
282
    case PIX_FMT_RGB32:
283
        n = w * 4;
284
        depth = 4;
285
        maxval = 255;
286
        tuple_type = "RGB_ALPHA";
287
        break;
288
    default:
289
        return -1;
290
    }
291
    snprintf(s->bytestream, s->bytestream_end - s->bytestream,
292
             "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
293
             w, h, depth, maxval, tuple_type);
294
    s->bytestream += strlen(s->bytestream);
295

  
296
    ptr = p->data[0];
297
    linesize = p->linesize[0];
298

  
299
    if (avctx->pix_fmt == PIX_FMT_RGB32) {
300
        int j;
301
        unsigned int v;
302

  
303
        for(i=0;i<h;i++) {
304
            for(j=0;j<w;j++) {
305
                v = ((uint32_t *)ptr)[j];
306
                *s->bytestream++ = v >> 16;
307
                *s->bytestream++ = v >> 8;
308
                *s->bytestream++ = v;
309
                *s->bytestream++ = v >> 24;
310
            }
311
            ptr += linesize;
312
        }
313
    } else {
314
        for(i=0;i<h;i++) {
315
            memcpy(s->bytestream, ptr, n);
316
            s->bytestream += n;
317
            ptr += linesize;
318
        }
136
    /* more check if YUV420 */
137
    if (avctx->pix_fmt == PIX_FMT_YUV420P) {
138
        if ((avctx->width & 1) != 0)
139
            return -1;
140
        h = (avctx->height * 2);
141
        if ((h % 3) != 0)
142
            return -1;
143
        h /= 3;
144
        avctx->height = h;
319 145
    }
320
    return s->bytestream - s->bytestream_start;
321
}
322

  
323
#if 0
324
static int pnm_probe(AVProbeData *pd)
325
{
326
    const char *p = pd->buf;
327
    if (pd->buf_size >= 8 &&
328
        p[0] == 'P' &&
329
        p[1] >= '4' && p[1] <= '6' &&
330
        pnm_space(p[2]) )
331
        return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */
332
    else
333
        return 0;
334
}
335

  
336
static int pgmyuv_probe(AVProbeData *pd)
337
{
338
    if (match_ext(pd->filename, "pgmyuv"))
339
        return AVPROBE_SCORE_MAX;
340
    else
341
        return 0;
342
}
343

  
344
static int pam_probe(AVProbeData *pd)
345
{
346
    const char *p = pd->buf;
347
    if (pd->buf_size >= 8 &&
348
        p[0] == 'P' &&
349
        p[1] == '7' &&
350
        p[2] == '\n')
351
        return AVPROBE_SCORE_MAX;
352
    else
353
        return 0;
146
    return 0;
354 147
}
355
#endif
356

  
357

  
358
#ifdef CONFIG_PGM_ENCODER
359
AVCodec pgm_encoder = {
360
    "pgm",
361
    CODEC_TYPE_VIDEO,
362
    CODEC_ID_PGM,
363
    sizeof(PNMContext),
364
    common_init,
365
    pnm_encode_frame,
366
    NULL, //encode_end,
367
    pnm_decode_frame,
368
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, -1},
369
};
370
#endif // CONFIG_PGM_ENCODER
371

  
372
#ifdef CONFIG_PGMYUV_ENCODER
373
AVCodec pgmyuv_encoder = {
374
    "pgmyuv",
375
    CODEC_TYPE_VIDEO,
376
    CODEC_ID_PGMYUV,
377
    sizeof(PNMContext),
378
    common_init,
379
    pnm_encode_frame,
380
    NULL, //encode_end,
381
    pnm_decode_frame,
382
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1},
383
};
384
#endif // CONFIG_PGMYUV_ENCODER
385

  
386
#ifdef CONFIG_PPM_ENCODER
387
AVCodec ppm_encoder = {
388
    "ppm",
389
    CODEC_TYPE_VIDEO,
390
    CODEC_ID_PPM,
391
    sizeof(PNMContext),
392
    common_init,
393
    pnm_encode_frame,
394
    NULL, //encode_end,
395
    pnm_decode_frame,
396
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, -1},
397
};
398
#endif // CONFIG_PPM_ENCODER
399

  
400
#ifdef CONFIG_PBM_ENCODER
401
AVCodec pbm_encoder = {
402
    "pbm",
403
    CODEC_TYPE_VIDEO,
404
    CODEC_ID_PBM,
405
    sizeof(PNMContext),
406
    common_init,
407
    pnm_encode_frame,
408
    NULL, //encode_end,
409
    pnm_decode_frame,
410
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_MONOWHITE, -1},
411
};
412
#endif // CONFIG_PBM_ENCODER
413

  
414
#ifdef CONFIG_PAM_ENCODER
415
AVCodec pam_encoder = {
416
    "pam",
417
    CODEC_TYPE_VIDEO,
418
    CODEC_ID_PAM,
419
    sizeof(PNMContext),
420
    common_init,
421
    pam_encode_frame,
422
    NULL, //encode_end,
423
    pnm_decode_frame,
424
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, -1},
425
};
426
#endif // CONFIG_PAM_ENCODER

Also available in: Unified diff