]> rtime.felk.cvut.cz Git - frescor/ffmpeg.git/blob - libavcodec/pnm.c
PGM 16-bit gray support
[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 "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         if(atoi(buf1) == 65535 && avctx->pix_fmt == PIX_FMT_GRAY8)
146             avctx->pix_fmt = PIX_FMT_GRAY16BE;
147     }
148     /* more check if YUV420 */
149     if (avctx->pix_fmt == PIX_FMT_YUV420P) {
150         if ((avctx->width & 1) != 0)
151             return -1;
152         h = (avctx->height * 2);
153         if ((h % 3) != 0)
154             return -1;
155         h /= 3;
156         avctx->height = h;
157     }
158     return 0;
159 }
160
161 static int pnm_decode_frame(AVCodecContext *avctx,
162                         void *data, int *data_size,
163                         uint8_t *buf, int buf_size)
164 {
165     PNMContext * const s = avctx->priv_data;
166     AVFrame *picture = data;
167     AVFrame * const p= (AVFrame*)&s->picture;
168     int i, n, linesize, h;
169     unsigned char *ptr;
170
171     s->bytestream_start=
172     s->bytestream= buf;
173     s->bytestream_end= buf + buf_size;
174
175     if(pnm_decode_header(avctx, s) < 0)
176         return -1;
177
178     if(p->data[0])
179         avctx->release_buffer(avctx, p);
180
181     p->reference= 0;
182     if(avctx->get_buffer(avctx, p) < 0){
183         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
184         return -1;
185     }
186     p->pict_type= FF_I_TYPE;
187     p->key_frame= 1;
188
189     switch(avctx->pix_fmt) {
190     default:
191         return -1;
192     case PIX_FMT_RGB24:
193         n = avctx->width * 3;
194         goto do_read;
195     case PIX_FMT_GRAY8:
196         n = avctx->width;
197         goto do_read;
198     case PIX_FMT_GRAY16BE:
199         n = avctx->width * 2;
200         goto do_read;
201     case PIX_FMT_MONOWHITE:
202     case PIX_FMT_MONOBLACK:
203         n = (avctx->width + 7) >> 3;
204     do_read:
205         ptr = p->data[0];
206         linesize = p->linesize[0];
207         if(s->bytestream + n*avctx->height > s->bytestream_end)
208             return -1;
209         for(i = 0; i < avctx->height; i++) {
210             memcpy(ptr, s->bytestream, n);
211             s->bytestream += n;
212             ptr += linesize;
213         }
214         break;
215     case PIX_FMT_YUV420P:
216         {
217             unsigned char *ptr1, *ptr2;
218
219             n = avctx->width;
220             ptr = p->data[0];
221             linesize = p->linesize[0];
222             if(s->bytestream + n*avctx->height*3/2 > s->bytestream_end)
223                 return -1;
224             for(i = 0; i < avctx->height; i++) {
225                 memcpy(ptr, s->bytestream, n);
226                 s->bytestream += n;
227                 ptr += linesize;
228             }
229             ptr1 = p->data[1];
230             ptr2 = p->data[2];
231             n >>= 1;
232             h = avctx->height >> 1;
233             for(i = 0; i < h; i++) {
234                 memcpy(ptr1, s->bytestream, n);
235                 s->bytestream += n;
236                 memcpy(ptr2, s->bytestream, n);
237                 s->bytestream += n;
238                 ptr1 += p->linesize[1];
239                 ptr2 += p->linesize[2];
240             }
241         }
242         break;
243     case PIX_FMT_RGBA32:
244         ptr = p->data[0];
245         linesize = p->linesize[0];
246         if(s->bytestream + avctx->width*avctx->height*4 > s->bytestream_end)
247             return -1;
248         for(i = 0; i < avctx->height; i++) {
249             int j, r, g, b, a;
250
251             for(j = 0;j < avctx->width; j++) {
252                 r = *s->bytestream++;
253                 g = *s->bytestream++;
254                 b = *s->bytestream++;
255                 a = *s->bytestream++;
256                 ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b;
257             }
258             ptr += linesize;
259         }
260         break;
261     }
262     *picture= *(AVFrame*)&s->picture;
263     *data_size = sizeof(AVPicture);
264
265     return s->bytestream - s->bytestream_start;
266 }
267
268 static int pnm_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
269     PNMContext *s = avctx->priv_data;
270     AVFrame *pict = data;
271     AVFrame * const p= (AVFrame*)&s->picture;
272     int i, h, h1, c, n, linesize;
273     uint8_t *ptr, *ptr1, *ptr2;
274
275     if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
276         av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
277         return -1;
278     }
279
280     *p = *pict;
281     p->pict_type= FF_I_TYPE;
282     p->key_frame= 1;
283
284     s->bytestream_start=
285     s->bytestream= outbuf;
286     s->bytestream_end= outbuf+buf_size;
287
288     h = avctx->height;
289     h1 = h;
290     switch(avctx->pix_fmt) {
291     case PIX_FMT_MONOWHITE:
292         c = '4';
293         n = (avctx->width + 7) >> 3;
294         break;
295     case PIX_FMT_GRAY8:
296         c = '5';
297         n = avctx->width;
298         break;
299     case PIX_FMT_GRAY16BE:
300         c = '5';
301         n = avctx->width * 2;
302         break;
303     case PIX_FMT_RGB24:
304         c = '6';
305         n = avctx->width * 3;
306         break;
307     case PIX_FMT_YUV420P:
308         c = '5';
309         n = avctx->width;
310         h1 = (h * 3) / 2;
311         break;
312     default:
313         return -1;
314     }
315     snprintf(s->bytestream, s->bytestream_end - s->bytestream,
316              "P%c\n%d %d\n",
317              c, avctx->width, h1);
318     s->bytestream += strlen(s->bytestream);
319     if (avctx->pix_fmt != PIX_FMT_MONOWHITE) {
320         snprintf(s->bytestream, s->bytestream_end - s->bytestream,
321                  "%d\n", (avctx->pix_fmt != PIX_FMT_GRAY16BE) ? 255 : 65535);
322         s->bytestream += strlen(s->bytestream);
323     }
324
325     ptr = p->data[0];
326     linesize = p->linesize[0];
327     for(i=0;i<h;i++) {
328         memcpy(s->bytestream, ptr, n);
329         s->bytestream += n;
330         ptr += linesize;
331     }
332
333     if (avctx->pix_fmt == PIX_FMT_YUV420P) {
334         h >>= 1;
335         n >>= 1;
336         ptr1 = p->data[1];
337         ptr2 = p->data[2];
338         for(i=0;i<h;i++) {
339             memcpy(s->bytestream, ptr1, n);
340             s->bytestream += n;
341             memcpy(s->bytestream, ptr2, n);
342             s->bytestream += n;
343                 ptr1 += p->linesize[1];
344                 ptr2 += p->linesize[2];
345         }
346     }
347     return s->bytestream - s->bytestream_start;
348 }
349
350 static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){
351     PNMContext *s = avctx->priv_data;
352     AVFrame *pict = data;
353     AVFrame * const p= (AVFrame*)&s->picture;
354     int i, h, w, n, linesize, depth, maxval;
355     const char *tuple_type;
356     uint8_t *ptr;
357
358     if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){
359         av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
360         return -1;
361     }
362
363     *p = *pict;
364     p->pict_type= FF_I_TYPE;
365     p->key_frame= 1;
366
367     s->bytestream_start=
368     s->bytestream= outbuf;
369     s->bytestream_end= outbuf+buf_size;
370
371     h = avctx->height;
372     w = avctx->width;
373     switch(avctx->pix_fmt) {
374     case PIX_FMT_MONOWHITE:
375         n = (w + 7) >> 3;
376         depth = 1;
377         maxval = 1;
378         tuple_type = "BLACKANDWHITE";
379         break;
380     case PIX_FMT_GRAY8:
381         n = w;
382         depth = 1;
383         maxval = 255;
384         tuple_type = "GRAYSCALE";
385         break;
386     case PIX_FMT_RGB24:
387         n = w * 3;
388         depth = 3;
389         maxval = 255;
390         tuple_type = "RGB";
391         break;
392     case PIX_FMT_RGBA32:
393         n = w * 4;
394         depth = 4;
395         maxval = 255;
396         tuple_type = "RGB_ALPHA";
397         break;
398     default:
399         return -1;
400     }
401     snprintf(s->bytestream, s->bytestream_end - s->bytestream,
402              "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n",
403              w, h, depth, maxval, tuple_type);
404     s->bytestream += strlen(s->bytestream);
405
406     ptr = p->data[0];
407     linesize = p->linesize[0];
408
409     if (avctx->pix_fmt == PIX_FMT_RGBA32) {
410         int j;
411         unsigned int v;
412
413         for(i=0;i<h;i++) {
414             for(j=0;j<w;j++) {
415                 v = ((uint32_t *)ptr)[j];
416                 *s->bytestream++ = v >> 16;
417                 *s->bytestream++ = v >> 8;
418                 *s->bytestream++ = v;
419                 *s->bytestream++ = v >> 24;
420             }
421             ptr += linesize;
422         }
423     } else {
424         for(i=0;i<h;i++) {
425             memcpy(s->bytestream, ptr, n);
426             s->bytestream += n;
427             ptr += linesize;
428         }
429     }
430     return s->bytestream - s->bytestream_start;
431 }
432
433 #if 0
434 static int pnm_probe(AVProbeData *pd)
435 {
436     const char *p = pd->buf;
437     if (pd->buf_size >= 8 &&
438         p[0] == 'P' &&
439         p[1] >= '4' && p[1] <= '6' &&
440         pnm_space(p[2]) )
441         return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */
442     else
443         return 0;
444 }
445
446 static int pgmyuv_probe(AVProbeData *pd)
447 {
448     if (match_ext(pd->filename, "pgmyuv"))
449         return AVPROBE_SCORE_MAX;
450     else
451         return 0;
452 }
453
454 static int pam_probe(AVProbeData *pd)
455 {
456     const char *p = pd->buf;
457     if (pd->buf_size >= 8 &&
458         p[0] == 'P' &&
459         p[1] == '7' &&
460         p[2] == '\n')
461         return AVPROBE_SCORE_MAX;
462     else
463         return 0;
464 }
465 #endif
466
467 #ifdef CONFIG_PNM_PARSER
468 static int pnm_parse(AVCodecParserContext *s,
469                            AVCodecContext *avctx,
470                            uint8_t **poutbuf, int *poutbuf_size,
471                            const uint8_t *buf, int buf_size)
472 {
473     ParseContext *pc = s->priv_data;
474     PNMContext pnmctx;
475     int next;
476
477     for(; pc->overread>0; pc->overread--){
478         pc->buffer[pc->index++]= pc->buffer[pc->overread_index++];
479     }
480 retry:
481     if(pc->index){
482         pnmctx.bytestream_start=
483         pnmctx.bytestream= pc->buffer;
484         pnmctx.bytestream_end= pc->buffer + pc->index;
485     }else{
486         pnmctx.bytestream_start=
487         pnmctx.bytestream= (uint8_t *) buf; /* casts avoid warnings */
488         pnmctx.bytestream_end= (uint8_t *) buf + buf_size;
489     }
490     if(pnm_decode_header(avctx, &pnmctx) < 0){
491         if(pnmctx.bytestream < pnmctx.bytestream_end){
492             if(pc->index){
493                 pc->index=0;
494             }else{
495                 buf++;
496                 buf_size--;
497             }
498             goto retry;
499         }
500 #if 0
501         if(pc->index && pc->index*2 + FF_INPUT_BUFFER_PADDING_SIZE < pc->buffer_size && buf_size > pc->index){
502             memcpy(pc->buffer + pc->index, buf, pc->index);
503             pc->index += pc->index;
504             buf += pc->index;
505             buf_size -= pc->index;
506             goto retry;
507         }
508 #endif
509         next= END_NOT_FOUND;
510     }else{
511         next= pnmctx.bytestream - pnmctx.bytestream_start
512             + avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
513         if(pnmctx.bytestream_start!=buf)
514             next-= pc->index;
515         if(next > buf_size)
516             next= END_NOT_FOUND;
517     }
518
519     if(ff_combine_frame(pc, next, (uint8_t **)&buf, &buf_size)<0){
520         *poutbuf = NULL;
521         *poutbuf_size = 0;
522         return buf_size;
523     }
524     *poutbuf = (uint8_t *)buf;
525     *poutbuf_size = buf_size;
526     return next;
527 }
528
529 AVCodecParser pnm_parser = {
530     { CODEC_ID_PGM, CODEC_ID_PGMYUV, CODEC_ID_PPM, CODEC_ID_PBM, CODEC_ID_PAM},
531     sizeof(ParseContext),
532     NULL,
533     pnm_parse,
534     ff_parse_close,
535 };
536 #endif /* CONFIG_PNM_PARSER */
537
538 #ifdef CONFIG_PGM_ENCODER
539 AVCodec pgm_encoder = {
540     "pgm",
541     CODEC_TYPE_VIDEO,
542     CODEC_ID_PGM,
543     sizeof(PNMContext),
544     common_init,
545     pnm_encode_frame,
546     NULL, //encode_end,
547     pnm_decode_frame,
548     .pix_fmts= (enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, -1},
549 };
550 #endif // CONFIG_PGM_ENCODER
551
552 #ifdef CONFIG_PGMYUV_ENCODER
553 AVCodec pgmyuv_encoder = {
554     "pgmyuv",
555     CODEC_TYPE_VIDEO,
556     CODEC_ID_PGMYUV,
557     sizeof(PNMContext),
558     common_init,
559     pnm_encode_frame,
560     NULL, //encode_end,
561     pnm_decode_frame,
562     .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, -1},
563 };
564 #endif // CONFIG_PGMYUV_ENCODER
565
566 #ifdef CONFIG_PPM_ENCODER
567 AVCodec ppm_encoder = {
568     "ppm",
569     CODEC_TYPE_VIDEO,
570     CODEC_ID_PPM,
571     sizeof(PNMContext),
572     common_init,
573     pnm_encode_frame,
574     NULL, //encode_end,
575     pnm_decode_frame,
576     .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, -1},
577 };
578 #endif // CONFIG_PPM_ENCODER
579
580 #ifdef CONFIG_PBM_ENCODER
581 AVCodec pbm_encoder = {
582     "pbm",
583     CODEC_TYPE_VIDEO,
584     CODEC_ID_PBM,
585     sizeof(PNMContext),
586     common_init,
587     pnm_encode_frame,
588     NULL, //encode_end,
589     pnm_decode_frame,
590     .pix_fmts= (enum PixelFormat[]){PIX_FMT_MONOWHITE, -1},
591 };
592 #endif // CONFIG_PBM_ENCODER
593
594 #ifdef CONFIG_PAM_ENCODER
595 AVCodec pam_encoder = {
596     "pam",
597     CODEC_TYPE_VIDEO,
598     CODEC_ID_PAM,
599     sizeof(PNMContext),
600     common_init,
601     pam_encode_frame,
602     NULL, //encode_end,
603     pnm_decode_frame,
604     .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGBA32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, -1},
605 };
606 #endif // CONFIG_PAM_ENCODER