]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavcodec/pnm.c
move p*m from image/lavf -> image2/lavc
[frescor/ffmpeg.git] / libavcodec / pnm.c
1 /*
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 "avcodec.h"
20
21 typedef struct PNMContext {
22     uint8_t *bytestream;
23     uint8_t *bytestream_start;
24     uint8_t *bytestream_end;
25     AVFrame picture;
26 } PNMContext;
27
28 static inline int pnm_space(int c)  
29 {
30     return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
31 }
32
33 static void pnm_get(PNMContext *sc, char *str, int buf_size) 
34 {
35     char *s;
36     int c;
37     
38     /* skip spaces and comments */
39     for(;;) {
40         c = *sc->bytestream++;
41         if (c == '#')  {
42             do  {
43                 c = *sc->bytestream++;
44             } while (c != '\n' && sc->bytestream < sc->bytestream_end);
45         } else if (!pnm_space(c)) {
46             break;
47         }
48     }
49     
50     s = str;
51     while (sc->bytestream < sc->bytestream_end && !pnm_space(c)) {
52         if ((s - str)  < buf_size - 1)
53             *s++ = c;
54         c = *sc->bytestream++;
55     }
56     *s = '\0';
57 }
58
59 static int common_init(AVCodecContext *avctx){
60     PNMContext *s = avctx->priv_data;
61
62     avcodec_get_frame_defaults((AVFrame*)&s->picture);
63     avctx->coded_frame= (AVFrame*)&s->picture;
64
65     return 0;
66 }
67
68 static int pnm_decode_frame(AVCodecContext *avctx, 
69                         void *data, int *data_size,
70                         uint8_t *buf, int buf_size)
71 {
72     PNMContext * const s = avctx->priv_data;
73     AVFrame *picture = data;
74     AVFrame * const p= (AVFrame*)&s->picture;
75     int i, n, linesize, h;
76     char buf1[32];
77     unsigned char *ptr;
78
79     /* special case for last picture */
80     if (buf_size == 0) {
81         return 0;
82     }
83     
84     s->bytestream_start=
85     s->bytestream= buf;
86     s->bytestream_end= buf + buf_size;
87
88     pnm_get(s, buf1, sizeof(buf1));
89     if (!strcmp(buf1, "P4")) {
90         avctx->pix_fmt = PIX_FMT_MONOWHITE;
91     } else if (!strcmp(buf1, "P5")) {
92         if (avctx->codec_id == CODEC_ID_PGMYUV) 
93             avctx->pix_fmt = PIX_FMT_YUV420P;
94         else
95             avctx->pix_fmt = PIX_FMT_GRAY8;
96     } else if (!strcmp(buf1, "P6")) {
97         avctx->pix_fmt = PIX_FMT_RGB24;
98     } else {
99         return -1;
100     }
101     pnm_get(s, buf1, sizeof(buf1));
102     avctx->width = atoi(buf1);
103     if (avctx->width <= 0)
104         return -1;
105     pnm_get(s, buf1, sizeof(buf1));
106     avctx->height = atoi(buf1);
107     if (avctx->height <= 0)
108         return -1;
109     if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
110         pnm_get(s, buf1, sizeof(buf1));
111     }
112
113     /* more check if YUV420 */
114     if (avctx->pix_fmt == PIX_FMT_YUV420P) {
115         if ((avctx->width & 1) != 0)
116             return -1;
117         h = (avctx->height * 2);
118         if ((h % 3) != 0)
119             return -1;
120         h /= 3;
121         avctx->height = h;
122     }
123     
124     if(p->data[0])
125         avctx->release_buffer(avctx, p);
126
127     p->reference= 0;
128     if(avctx->get_buffer(avctx, p) < 0){
129         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
130         return -1;
131     }
132     p->pict_type= FF_I_TYPE;
133     p->key_frame= 1;
134     
135     switch(avctx->pix_fmt) {
136     default:
137         return -1;
138     case PIX_FMT_RGB24:
139         n = avctx->width * 3;
140         goto do_read;
141     case PIX_FMT_GRAY8:
142         n = avctx->width;
143         goto do_read;
144     case PIX_FMT_MONOWHITE:
145         n = (avctx->width + 7) >> 3;
146     do_read:
147         ptr = p->data[0];
148         linesize = p->linesize[0];
149         for(i = 0; i < avctx->height; i++) {
150             memcpy(ptr, s->bytestream, n);
151             s->bytestream += n;
152             ptr += linesize;
153         }
154         break;
155     case PIX_FMT_YUV420P:
156         {
157             unsigned char *ptr1, *ptr2;
158
159             n = avctx->width;
160             ptr = p->data[0];
161             linesize = p->linesize[0];
162             for(i = 0; i < avctx->height; i++) {
163                 memcpy(ptr, s->bytestream, n);
164                 s->bytestream += n;
165                 ptr += linesize;
166             }
167             ptr1 = p->data[1];
168             ptr2 = p->data[2];
169             n >>= 1;
170             h = avctx->height >> 1;
171             for(i = 0; i < h; i++) {
172                 memcpy(ptr1, s->bytestream, n);
173                 s->bytestream += n;
174                 memcpy(ptr2, s->bytestream, n);
175                 s->bytestream += n;
176                 ptr1 += p->linesize[1];
177                 ptr2 += p->linesize[2];
178             }
179         }
180         break;
181     }
182     *picture= *(AVFrame*)&s->picture;
183     *data_size = sizeof(AVPicture);
184
185     return s->bytestream - s->bytestream_start;
186 }
187
188 static int pnm_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
189     PNMContext *s = avctx->priv_data;
190     AVFrame *pict = data;
191     AVFrame * const p= (AVFrame*)&s->picture;
192     int i, h, h1, c, n, linesize;
193     uint8_t *ptr, *ptr1, *ptr2;
194
195     *p = *pict;
196     p->pict_type= FF_I_TYPE;
197     p->key_frame= 1;
198     
199     s->bytestream_start=
200     s->bytestream= outbuf;
201     s->bytestream_end= outbuf+buf_size;
202
203     h = avctx->height;
204     h1 = h;
205     switch(avctx->pix_fmt) {
206     case PIX_FMT_MONOWHITE:
207         c = '4';
208         n = (avctx->width + 7) >> 3;
209         break;
210     case PIX_FMT_GRAY8:
211         c = '5';
212         n = avctx->width;
213         break;
214     case PIX_FMT_RGB24:
215         c = '6';
216         n = avctx->width * 3;
217         break;
218     case PIX_FMT_YUV420P:
219         c = '5';
220         n = avctx->width;
221         h1 = (h * 3) / 2;
222         break;
223     default:
224         return -1;
225     }
226     snprintf(s->bytestream, s->bytestream_end - s->bytestream, 
227              "P%c\n%d %d\n",
228              c, avctx->width, h1);
229     s->bytestream += strlen(s->bytestream);
230     if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
231         snprintf(s->bytestream, s->bytestream_end - s->bytestream, 
232                  "%d\n", 255);
233         s->bytestream += strlen(s->bytestream);
234     }
235
236     ptr = p->data[0];
237     linesize = p->linesize[0];
238     for(i=0;i<h;i++) {
239         memcpy(s->bytestream, ptr, n);
240         s->bytestream += n;
241         ptr += linesize;
242     }
243     
244     if (avctx->pix_fmt == PIX_FMT_YUV420P) {
245         h >>= 1;
246         n >>= 1;
247         ptr1 = p->data[1];
248         ptr2 = p->data[2];
249         for(i=0;i<h;i++) {
250             memcpy(s->bytestream, ptr1, n);
251             s->bytestream += n;
252             memcpy(s->bytestream, ptr2, n);
253             s->bytestream += n;
254                 ptr1 += p->linesize[1];
255                 ptr2 += p->linesize[2];
256         }
257     }
258     return s->bytestream - s->bytestream_start;
259 }
260
261 static int pam_decode_frame(AVCodecContext *avctx, 
262                         void *data, int *data_size,
263                         uint8_t *buf, int buf_size)
264 {
265     PNMContext * const s = avctx->priv_data;
266     AVFrame *picture = data;
267     AVFrame * const p= (AVFrame*)&s->picture;
268     int i, n, linesize, h, w, depth, maxval;
269     char buf1[32], tuple_type[32];
270     unsigned char *ptr;
271
272     /* special case for last picture */
273     if (buf_size == 0) {
274         return 0;
275     }
276     
277     s->bytestream_start=
278     s->bytestream= buf;
279     s->bytestream_end= buf + buf_size;
280
281     pnm_get(s, buf1, sizeof(buf1));
282     if (strcmp(buf1, "P7") != 0)
283         return -1;
284     w = -1;
285     h = -1;
286     maxval = -1;
287     depth = -1;
288     tuple_type[0] = '\0';
289     for(;;) {
290         pnm_get(s, buf1, sizeof(buf1));
291         if (!strcmp(buf1, "WIDTH")) {
292             pnm_get(s, buf1, sizeof(buf1));
293             w = strtol(buf1, NULL, 10);
294         } else if (!strcmp(buf1, "HEIGHT")) {
295             pnm_get(s, buf1, sizeof(buf1));
296             h = strtol(buf1, NULL, 10);
297         } else if (!strcmp(buf1, "DEPTH")) {
298             pnm_get(s, buf1, sizeof(buf1));
299             depth = strtol(buf1, NULL, 10);
300         } else if (!strcmp(buf1, "MAXVAL")) {
301             pnm_get(s, buf1, sizeof(buf1));
302             maxval = strtol(buf1, NULL, 10);
303         } else if (!strcmp(buf1, "TUPLETYPE")) {
304             pnm_get(s, tuple_type, sizeof(tuple_type));
305         } else if (!strcmp(buf1, "ENDHDR")) {
306             break;
307         } else {
308             return -1;
309         }
310     }
311     /* check that all tags are present */
312     if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0')
313         return -1;
314     avctx->width = w;
315     avctx->height = h;
316     if (depth == 1) {
317         if (maxval == 1)
318             avctx->pix_fmt = PIX_FMT_MONOWHITE;
319         else 
320             avctx->pix_fmt = PIX_FMT_GRAY8;
321     } else if (depth == 3) {
322         avctx->pix_fmt = PIX_FMT_RGB24;
323     } else if (depth == 4) {
324         avctx->pix_fmt = PIX_FMT_RGBA32;
325     } else {
326         return -1;
327     }
328     
329     if(p->data[0])
330         avctx->release_buffer(avctx, p);
331
332     p->reference= 0;
333     if(avctx->get_buffer(avctx, p) < 0){
334         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
335         return -1;
336     }
337     p->pict_type= FF_I_TYPE;
338     p->key_frame= 1;
339     
340     switch(avctx->pix_fmt) {
341     default:
342         return -1;
343     case PIX_FMT_RGB24:
344         n = avctx->width * 3;
345         goto do_read;
346     case PIX_FMT_GRAY8:
347         n = avctx->width;
348         goto do_read;
349     case PIX_FMT_MONOWHITE:
350         n = (avctx->width + 7) >> 3;
351     do_read:
352         ptr = p->data[0];
353         linesize = p->linesize[0];
354         for(i = 0; i < avctx->height; i++) {
355             memcpy(ptr, s->bytestream, n);
356             s->bytestream += n;
357             ptr += linesize;
358         }
359         break;
360     case PIX_FMT_RGBA32:
361         ptr = p->data[0];
362         linesize = p->linesize[0];
363         for(i = 0; i < avctx->height; i++) {
364             int j, r, g, b, a;
365
366             for(j = 0;j < w; j++) {
367                 r = *s->bytestream++;
368                 g = *s->bytestream++;
369                 b = *s->bytestream++;
370                 a = *s->bytestream++;
371                 ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
372             }
373             ptr += linesize;
374         }
375         break;
376     }   
377     *picture= *(AVFrame*)&s->picture;
378     *data_size = sizeof(AVPicture);
379
380     return s->bytestream - s->bytestream_start;
381 }
382
383 static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
384     PNMContext *s = avctx->priv_data;
385     AVFrame *pict = data;
386     AVFrame * const p= (AVFrame*)&s->picture;
387     int i, h, w, n, linesize, depth, maxval;
388     const char *tuple_type;
389     uint8_t *ptr;
390
391     *p = *pict;
392     p->pict_type= FF_I_TYPE;
393     p->key_frame= 1;
394     
395     s->bytestream_start=
396     s->bytestream= outbuf;
397     s->bytestream_end= outbuf+buf_size;
398
399     h = avctx->height;
400     w = avctx->width;
401     switch(avctx->pix_fmt) {
402     case PIX_FMT_MONOWHITE:
403         n = (w + 7) >> 3;
404         depth = 1;
405         maxval = 1;
406         tuple_type = "BLACKANDWHITE";
407         break;
408     case PIX_FMT_GRAY8:
409         n = w;
410         depth = 1;
411         maxval = 255;
412         tuple_type = "GRAYSCALE";
413         break;
414     case PIX_FMT_RGB24:
415         n = w * 3;
416         depth = 3;
417         maxval = 255;
418         tuple_type = "RGB";
419         break;
420     case PIX_FMT_RGBA32:
421         n = w * 4;
422         depth = 4;
423         maxval = 255;
424         tuple_type = "RGB_ALPHA";
425         break;
426     default:
427         return -1;
428     }
429     snprintf(s->bytestream, s->bytestream_end - s->bytestream, 
430              "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
431              w, h, depth, maxval, tuple_type);
432     s->bytestream += strlen(s->bytestream);
433     
434     ptr = p->data[0];
435     linesize = p->linesize[0];
436     
437     if (avctx->pix_fmt == PIX_FMT_RGBA32) {
438         int j;
439         unsigned int v;
440
441         for(i=0;i<h;i++) {
442             for(j=0;j<w;j++) {
443                 v = ((uint32_t *)ptr)[j];
444                 *s->bytestream++ = v >> 16;
445                 *s->bytestream++ = v >> 8;
446                 *s->bytestream++ = v;
447                 *s->bytestream++ = v >> 24;
448             }
449             ptr += linesize;
450         }
451     } else {
452         for(i=0;i<h;i++) {
453             memcpy(s->bytestream, ptr, n);
454             s->bytestream += n;
455             ptr += linesize;
456         }
457     }
458     return s->bytestream - s->bytestream_start;
459 }
460
461 #if 0
462 static int pnm_probe(AVProbeData *pd)
463 {
464     const char *p = pd->buf;
465     if (pd->buf_size >= 8 &&
466         p[0] == 'P' &&
467         p[1] >= '4' && p[1] <= '6' &&
468         pnm_space(p[2]) )
469         return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */
470     else
471         return 0;
472 }
473
474 static int pgmyuv_probe(AVProbeData *pd)
475 {
476     if (match_ext(pd->filename, "pgmyuv"))
477         return AVPROBE_SCORE_MAX;
478     else
479         return 0;
480 }
481
482 static int pam_probe(AVProbeData *pd)
483 {
484     const char *p = pd->buf;
485     if (pd->buf_size >= 8 &&
486         p[0] == 'P' &&
487         p[1] == '7' &&
488         p[2] == '\n')
489         return AVPROBE_SCORE_MAX;
490     else
491         return 0;
492 }
493 #endif
494
495 AVCodec pgm_encoder = {
496     "pgm",
497     CODEC_TYPE_VIDEO,
498     CODEC_ID_PGM,
499     sizeof(PNMContext),
500     common_init,
501     pnm_encode_frame,
502     NULL, //encode_end,
503     pnm_decode_frame,
504     .pix_fmts= (enum PixelFormat[]){PIX_FMT_GRAY8, -1}, 
505 };
506
507 AVCodec pgmyuv_encoder = {
508     "pgmyuv",
509     CODEC_TYPE_VIDEO,
510     CODEC_ID_PGMYUV,
511     sizeof(PNMContext),
512     common_init,
513     pnm_encode_frame,
514     NULL, //encode_end,
515     pnm_decode_frame,
516     .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1}, 
517 };
518
519 AVCodec ppm_encoder = {
520     "ppm",
521     CODEC_TYPE_VIDEO,
522     CODEC_ID_PPM,
523     sizeof(PNMContext),
524     common_init,
525     pnm_encode_frame,
526     NULL, //encode_end,
527     pnm_decode_frame,
528     .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, -1}, 
529 };
530
531 AVCodec pbm_encoder = {
532     "pbm",
533     CODEC_TYPE_VIDEO,
534     CODEC_ID_PBM,
535     sizeof(PNMContext),
536     common_init,
537     pnm_encode_frame,
538     NULL, //encode_end,
539     pnm_decode_frame,
540     .pix_fmts= (enum PixelFormat[]){PIX_FMT_MONOWHITE, -1}, 
541 };
542
543 AVCodec pam_encoder = {
544     "pam",
545     CODEC_TYPE_VIDEO,
546     CODEC_ID_PAM,
547     sizeof(PNMContext),
548     common_init,
549     pam_encode_frame,
550     NULL, //encode_end,
551     pam_decode_frame,
552     .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGBA32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, -1}, 
553 };