| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * PNM image format | 
					
						
							| 
									
										
										
										
											2009-01-19 15:46:40 +00:00
										 |  |  |  * Copyright (c) 2002, 2003 Fabrice Bellard | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * This file is part of FFmpeg. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * FFmpeg is free software; you can redistribute it and/or | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * FFmpeg is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General Public | 
					
						
							| 
									
										
										
										
											2006-10-07 15:30:46 +00:00
										 |  |  |  * License along with FFmpeg; if not, write to the Free Software | 
					
						
							| 
									
										
										
										
											2006-01-12 22:43:26 +00:00
										 |  |  |  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2009-10-27 16:57:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-07 14:37:08 +01:00
										 |  |  | #include "libavutil/imgutils.h"
 | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  | #include "avcodec.h"
 | 
					
						
							| 
									
										
										
										
											2007-05-10 23:03:14 +00:00
										 |  |  | #include "pnm.h"
 | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  | static inline int pnm_space(int c) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-05-06 09:16:36 +00:00
										 |  |  |     return c == ' ' || c == '\n' || c == '\r' || c == '\t'; | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  | static void pnm_get(PNMContext *sc, char *str, int buf_size) | 
					
						
							| 
									
										
										
										
											2004-11-12 22:55:29 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |     char *s; | 
					
						
							|  |  |  |     int c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* skip spaces and comments */ | 
					
						
							| 
									
										
										
										
											2009-10-27 16:57:35 +00:00
										 |  |  |     for (;;) { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         c = *sc->bytestream++; | 
					
						
							|  |  |  |         if (c == '#')  { | 
					
						
							| 
									
										
										
										
											2009-10-27 16:57:35 +00:00
										 |  |  |             do { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |                 c = *sc->bytestream++; | 
					
						
							|  |  |  |             } while (c != '\n' && sc->bytestream < sc->bytestream_end); | 
					
						
							|  |  |  |         } else if (!pnm_space(c)) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2005-12-17 18:14:38 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |     s = str; | 
					
						
							|  |  |  |     while (sc->bytestream < sc->bytestream_end && !pnm_space(c)) { | 
					
						
							|  |  |  |         if ((s - str)  < buf_size - 1) | 
					
						
							|  |  |  |             *s++ = c; | 
					
						
							|  |  |  |         c = *sc->bytestream++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     *s = '\0'; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-27 16:57:35 +00:00
										 |  |  | int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |     char buf1[32], tuple_type[32]; | 
					
						
							|  |  |  |     int h, w, depth, maxval; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							| 
									
										
										
										
											2009-12-01 16:56:13 +00:00
										 |  |  |     s->type= buf1[1]-'0'; | 
					
						
							|  |  |  |     if(buf1[0] != 'P') | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->type==1 || s->type==4) { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         avctx->pix_fmt = PIX_FMT_MONOWHITE; | 
					
						
							| 
									
										
										
										
											2009-12-01 16:56:13 +00:00
										 |  |  |     } else if (s->type==2 || s->type==5) { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         if (avctx->codec_id == CODEC_ID_PGMYUV) | 
					
						
							|  |  |  |             avctx->pix_fmt = PIX_FMT_YUV420P; | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             avctx->pix_fmt = PIX_FMT_GRAY8; | 
					
						
							| 
									
										
										
										
											2009-12-01 16:56:13 +00:00
										 |  |  |     } else if (s->type==3 || s->type==6) { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         avctx->pix_fmt = PIX_FMT_RGB24; | 
					
						
							| 
									
										
										
										
											2009-12-01 16:56:13 +00:00
										 |  |  |     } else if (s->type==7) { | 
					
						
							| 
									
										
										
										
											2009-10-27 16:57:35 +00:00
										 |  |  |         w      = -1; | 
					
						
							|  |  |  |         h      = -1; | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         maxval = -1; | 
					
						
							| 
									
										
										
										
											2009-10-27 16:57:35 +00:00
										 |  |  |         depth  = -1; | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         tuple_type[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2009-10-27 16:57:35 +00:00
										 |  |  |         for (;;) { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |             pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							|  |  |  |             if (!strcmp(buf1, "WIDTH")) { | 
					
						
							|  |  |  |                 pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							|  |  |  |                 w = strtol(buf1, NULL, 10); | 
					
						
							|  |  |  |             } else if (!strcmp(buf1, "HEIGHT")) { | 
					
						
							|  |  |  |                 pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							|  |  |  |                 h = strtol(buf1, NULL, 10); | 
					
						
							|  |  |  |             } else if (!strcmp(buf1, "DEPTH")) { | 
					
						
							|  |  |  |                 pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							|  |  |  |                 depth = strtol(buf1, NULL, 10); | 
					
						
							|  |  |  |             } else if (!strcmp(buf1, "MAXVAL")) { | 
					
						
							|  |  |  |                 pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							|  |  |  |                 maxval = strtol(buf1, NULL, 10); | 
					
						
							|  |  |  |             } else if (!strcmp(buf1, "TUPLETYPE")) { | 
					
						
							|  |  |  |                 pnm_get(s, tuple_type, sizeof(tuple_type)); | 
					
						
							|  |  |  |             } else if (!strcmp(buf1, "ENDHDR")) { | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2005-08-21 15:44:59 +00:00
										 |  |  |                 return -1; | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         /* check that all tags are present */ | 
					
						
							| 
									
										
										
										
											2010-09-07 19:15:29 +00:00
										 |  |  |         if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0' || av_image_check_size(w, h, 0, avctx)) | 
					
						
							| 
									
										
										
										
											2005-08-21 15:44:59 +00:00
										 |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2004-11-12 23:38:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-27 16:57:35 +00:00
										 |  |  |         avctx->width  = w; | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         avctx->height = h; | 
					
						
							|  |  |  |         if (depth == 1) { | 
					
						
							|  |  |  |             if (maxval == 1) | 
					
						
							|  |  |  |                 avctx->pix_fmt = PIX_FMT_MONOWHITE; | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 avctx->pix_fmt = PIX_FMT_GRAY8; | 
					
						
							|  |  |  |         } else if (depth == 3) { | 
					
						
							| 
									
										
										
										
											2008-09-14 15:50:59 +00:00
										 |  |  |             if (maxval < 256) { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |             avctx->pix_fmt = PIX_FMT_RGB24; | 
					
						
							| 
									
										
										
										
											2008-09-14 15:50:59 +00:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 av_log(avctx, AV_LOG_ERROR, "16-bit components are only supported for grayscale\n"); | 
					
						
							|  |  |  |                 avctx->pix_fmt = PIX_FMT_NONE; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         } else if (depth == 4) { | 
					
						
							|  |  |  |             avctx->pix_fmt = PIX_FMT_RGB32; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2004-11-12 23:38:43 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2005-01-12 00:16:25 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |     pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							|  |  |  |     avctx->width = atoi(buf1); | 
					
						
							|  |  |  |     if (avctx->width <= 0) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							|  |  |  |     avctx->height = atoi(buf1); | 
					
						
							| 
									
										
										
										
											2011-05-08 01:24:37 +02:00
										 |  |  |     if(avctx->height <= 0 || av_image_check_size(avctx->width, avctx->height, 0, avctx)) | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |         return -1; | 
					
						
							|  |  |  |     if (avctx->pix_fmt != PIX_FMT_MONOWHITE) { | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |         pnm_get(s, buf1, sizeof(buf1)); | 
					
						
							|  |  |  |         s->maxval = atoi(buf1); | 
					
						
							| 
									
										
										
										
											2011-01-10 00:42:57 +00:00
										 |  |  |         if (s->maxval <= 0) { | 
					
						
							|  |  |  |             av_log(avctx, AV_LOG_ERROR, "Invalid maxval: %d\n", s->maxval); | 
					
						
							| 
									
										
										
										
											2011-01-10 22:09:52 +00:00
										 |  |  |             s->maxval = 255; | 
					
						
							| 
									
										
										
										
											2011-01-10 00:42:57 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-09-14 15:50:59 +00:00
										 |  |  |         if (s->maxval >= 256) { | 
					
						
							|  |  |  |             if (avctx->pix_fmt == PIX_FMT_GRAY8) { | 
					
						
							| 
									
										
										
										
											2008-09-14 22:27:47 +00:00
										 |  |  |                 avctx->pix_fmt = PIX_FMT_GRAY16BE; | 
					
						
							|  |  |  |                 if (s->maxval != 65535) | 
					
						
							|  |  |  |                     avctx->pix_fmt = PIX_FMT_GRAY16; | 
					
						
							| 
									
										
										
										
											2009-03-06 00:54:49 +00:00
										 |  |  |             } else if (avctx->pix_fmt == PIX_FMT_RGB24) { | 
					
						
							| 
									
										
										
										
											2009-02-22 00:56:55 +00:00
										 |  |  |                 if (s->maxval > 255) | 
					
						
							|  |  |  |                     avctx->pix_fmt = PIX_FMT_RGB48BE; | 
					
						
							| 
									
										
										
										
											2008-09-14 15:50:59 +00:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2009-02-22 00:56:55 +00:00
										 |  |  |                 av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format\n"); | 
					
						
							| 
									
										
										
										
											2008-09-14 15:50:59 +00:00
										 |  |  |                 avctx->pix_fmt = PIX_FMT_NONE; | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-12-01 16:56:13 +00:00
										 |  |  |     }else | 
					
						
							|  |  |  |         s->maxval=1; | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |     /* more check if YUV420 */ | 
					
						
							|  |  |  |     if (avctx->pix_fmt == PIX_FMT_YUV420P) { | 
					
						
							|  |  |  |         if ((avctx->width & 1) != 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         h = (avctx->height * 2); | 
					
						
							|  |  |  |         if ((h % 3) != 0) | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         h /= 3; | 
					
						
							|  |  |  |         avctx->height = h; | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-05-11 09:28:07 +00:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2004-11-11 18:09:28 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-10-27 17:15:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | av_cold int ff_pnm_end(AVCodecContext *avctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PNMContext *s = avctx->priv_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (s->picture.data[0]) | 
					
						
							|  |  |  |         avctx->release_buffer(avctx, &s->picture); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | av_cold int ff_pnm_init(AVCodecContext *avctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PNMContext *s = avctx->priv_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     avcodec_get_frame_defaults((AVFrame*)&s->picture); | 
					
						
							|  |  |  |     avctx->coded_frame = (AVFrame*)&s->picture; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } |