]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavcodec/pnm.c
Add support for grayscale images with arbitrary maxvals.
[frescor/ffmpeg.git] / libavcodec / pnm.c
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                            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, (uint8_t **)&buf, &buf_size)<0){
542         *poutbuf = NULL;
543         *poutbuf_size = 0;
544         return buf_size;
545     }
546     *poutbuf = (uint8_t *)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