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