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