Statistics
| Branch: | Revision:

ffmpeg / libavcodec / pnmenc.c @ 00182190

History | View | Annotate | Download (11.9 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 "bytestream.h"
23
#include "pnm.h"
24

    
25

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

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

    
32
    return 0;
33
}
34

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

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

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

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

    
55
    p->reference= 0;
56
    if(avctx->get_buffer(avctx, p) < 0){
57
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
58
        return -1;
59
    }
60
    p->pict_type= FF_I_TYPE;
61
    p->key_frame= 1;
62

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

    
113
            n = avctx->width;
114
            ptr = p->data[0];
115
            linesize = p->linesize[0];
116
            if(s->bytestream + n*avctx->height*3/2 > s->bytestream_end)
117
                return -1;
118
            for(i = 0; i < avctx->height; i++) {
119
                memcpy(ptr, s->bytestream, n);
120
                s->bytestream += n;
121
                ptr += linesize;
122
            }
123
            ptr1 = p->data[1];
124
            ptr2 = p->data[2];
125
            n >>= 1;
126
            h = avctx->height >> 1;
127
            for(i = 0; i < h; i++) {
128
                memcpy(ptr1, s->bytestream, n);
129
                s->bytestream += n;
130
                memcpy(ptr2, s->bytestream, n);
131
                s->bytestream += n;
132
                ptr1 += p->linesize[1];
133
                ptr2 += p->linesize[2];
134
            }
135
        }
136
        break;
137
    case PIX_FMT_RGB32:
138
        ptr = p->data[0];
139
        linesize = p->linesize[0];
140
        if(s->bytestream + avctx->width*avctx->height*4 > s->bytestream_end)
141
            return -1;
142
        for(i = 0; i < avctx->height; i++) {
143
            int j, r, g, b, a;
144

    
145
            for(j = 0;j < avctx->width; j++) {
146
                r = *s->bytestream++;
147
                g = *s->bytestream++;
148
                b = *s->bytestream++;
149
                a = *s->bytestream++;
150
                ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
151
            }
152
            ptr += linesize;
153
        }
154
        break;
155
    }
156
    *picture= *(AVFrame*)&s->picture;
157
    *data_size = sizeof(AVPicture);
158

    
159
    return s->bytestream - s->bytestream_start;
160
}
161

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

    
169
    if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
170
        av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
171
        return -1;
172
    }
173

    
174
    *p = *pict;
175
    p->pict_type= FF_I_TYPE;
176
    p->key_frame= 1;
177

    
178
    s->bytestream_start=
179
    s->bytestream= outbuf;
180
    s->bytestream_end= outbuf+buf_size;
181

    
182
    h = avctx->height;
183
    h1 = h;
184
    switch(avctx->pix_fmt) {
185
    case PIX_FMT_MONOWHITE:
186
        c = '4';
187
        n = (avctx->width + 7) >> 3;
188
        break;
189
    case PIX_FMT_GRAY8:
190
        c = '5';
191
        n = avctx->width;
192
        break;
193
    case PIX_FMT_GRAY16BE:
194
        c = '5';
195
        n = avctx->width * 2;
196
        break;
197
    case PIX_FMT_RGB24:
198
        c = '6';
199
        n = avctx->width * 3;
200
        break;
201
    case PIX_FMT_RGB48BE:
202
        c = '6';
203
        n = avctx->width * 6;
204
        break;
205
    case PIX_FMT_YUV420P:
206
        c = '5';
207
        n = avctx->width;
208
        h1 = (h * 3) / 2;
209
        break;
210
    default:
211
        return -1;
212
    }
213
    snprintf(s->bytestream, s->bytestream_end - s->bytestream,
214
             "P%c\n%d %d\n",
215
             c, avctx->width, h1);
216
    s->bytestream += strlen(s->bytestream);
217
    if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
218
        snprintf(s->bytestream, s->bytestream_end - s->bytestream,
219
                 "%d\n", (avctx->pix_fmt != PIX_FMT_GRAY16BE && avctx->pix_fmt != PIX_FMT_RGB48BE) ? 255 : 65535);
220
        s->bytestream += strlen(s->bytestream);
221
    }
222

    
223
    ptr = p->data[0];
224
    linesize = p->linesize[0];
225
    for(i=0;i<h;i++) {
226
        memcpy(s->bytestream, ptr, n);
227
        s->bytestream += n;
228
        ptr += linesize;
229
    }
230

    
231
    if (avctx->pix_fmt == PIX_FMT_YUV420P) {
232
        h >>= 1;
233
        n >>= 1;
234
        ptr1 = p->data[1];
235
        ptr2 = p->data[2];
236
        for(i=0;i<h;i++) {
237
            memcpy(s->bytestream, ptr1, n);
238
            s->bytestream += n;
239
            memcpy(s->bytestream, ptr2, n);
240
            s->bytestream += n;
241
                ptr1 += p->linesize[1];
242
                ptr2 += p->linesize[2];
243
        }
244
    }
245
    return s->bytestream - s->bytestream_start;
246
}
247

    
248
static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
249
    PNMContext *s = avctx->priv_data;
250
    AVFrame *pict = data;
251
    AVFrame * const p= (AVFrame*)&s->picture;
252
    int i, h, w, n, linesize, depth, maxval;
253
    const char *tuple_type;
254
    uint8_t *ptr;
255

    
256
    if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
257
        av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
258
        return -1;
259
    }
260

    
261
    *p = *pict;
262
    p->pict_type= FF_I_TYPE;
263
    p->key_frame= 1;
264

    
265
    s->bytestream_start=
266
    s->bytestream= outbuf;
267
    s->bytestream_end= outbuf+buf_size;
268

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

    
304
    ptr = p->data[0];
305
    linesize = p->linesize[0];
306

    
307
    if (avctx->pix_fmt == PIX_FMT_RGB32) {
308
        int j;
309
        unsigned int v;
310

    
311
        for(i=0;i<h;i++) {
312
            for(j=0;j<w;j++) {
313
                v = ((uint32_t *)ptr)[j];
314
                bytestream_put_be24(&s->bytestream, v);
315
                *s->bytestream++ = v >> 24;
316
            }
317
            ptr += linesize;
318
        }
319
    } else {
320
        for(i=0;i<h;i++) {
321
            memcpy(s->bytestream, ptr, n);
322
            s->bytestream += n;
323
            ptr += linesize;
324
        }
325
    }
326
    return s->bytestream - s->bytestream_start;
327
}
328

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

342
static int pgmyuv_probe(AVProbeData *pd)
343
{
344
    if (match_ext(pd->filename, "pgmyuv"))
345
        return AVPROBE_SCORE_MAX;
346
    else
347
        return 0;
348
}
349

350
static int pam_probe(AVProbeData *pd)
351
{
352
    const char *p = pd->buf;
353
    if (pd->buf_size >= 8 &&
354
        p[0] == 'P' &&
355
        p[1] == '7' &&
356
        p[2] == '\n')
357
        return AVPROBE_SCORE_MAX;
358
    else
359
        return 0;
360
}
361
#endif
362

    
363

    
364
#if CONFIG_PGM_ENCODER
365
AVCodec pgm_encoder = {
366
    "pgm",
367
    CODEC_TYPE_VIDEO,
368
    CODEC_ID_PGM,
369
    sizeof(PNMContext),
370
    common_init,
371
    pnm_encode_frame,
372
    NULL, //encode_end,
373
    pnm_decode_frame,
374
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, PIX_FMT_NONE},
375
    .long_name= NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"),
376
};
377
#endif // CONFIG_PGM_ENCODER
378

    
379
#if CONFIG_PGMYUV_ENCODER
380
AVCodec pgmyuv_encoder = {
381
    "pgmyuv",
382
    CODEC_TYPE_VIDEO,
383
    CODEC_ID_PGMYUV,
384
    sizeof(PNMContext),
385
    common_init,
386
    pnm_encode_frame,
387
    NULL, //encode_end,
388
    pnm_decode_frame,
389
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE},
390
    .long_name= NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"),
391
};
392
#endif // CONFIG_PGMYUV_ENCODER
393

    
394
#if CONFIG_PPM_ENCODER
395
AVCodec ppm_encoder = {
396
    "ppm",
397
    CODEC_TYPE_VIDEO,
398
    CODEC_ID_PPM,
399
    sizeof(PNMContext),
400
    common_init,
401
    pnm_encode_frame,
402
    NULL, //encode_end,
403
    pnm_decode_frame,
404
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB48BE, PIX_FMT_NONE},
405
    .long_name= NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"),
406
};
407
#endif // CONFIG_PPM_ENCODER
408

    
409
#if CONFIG_PBM_ENCODER
410
AVCodec pbm_encoder = {
411
    "pbm",
412
    CODEC_TYPE_VIDEO,
413
    CODEC_ID_PBM,
414
    sizeof(PNMContext),
415
    common_init,
416
    pnm_encode_frame,
417
    NULL, //encode_end,
418
    pnm_decode_frame,
419
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_MONOWHITE, PIX_FMT_NONE},
420
    .long_name= NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"),
421
};
422
#endif // CONFIG_PBM_ENCODER
423

    
424
#if CONFIG_PAM_ENCODER
425
AVCodec pam_encoder = {
426
    "pam",
427
    CODEC_TYPE_VIDEO,
428
    CODEC_ID_PAM,
429
    sizeof(PNMContext),
430
    common_init,
431
    pam_encode_frame,
432
    NULL, //encode_end,
433
    pnm_decode_frame,
434
    .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, PIX_FMT_NONE},
435
    .long_name= NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"),
436
};
437
#endif // CONFIG_PAM_ENCODER