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 "pnm.h" 23 24static inline int pnm_space(int c) 25{ 26 return c == ' ' || c == '\n' || c == '\r' || c == '\t'; 27} 28 29static void pnm_get(PNMContext *sc, char *str, int buf_size) 30{ 31 char *s; 32 int c; 33 34 /* skip spaces and comments */ 35 for(;;) { 36 c = *sc->bytestream++; 37 if (c == '#') { 38 do { 39 c = *sc->bytestream++; 40 } while (c != '\n' && sc->bytestream < sc->bytestream_end); 41 } else if (!pnm_space(c)) { 42 break; 43 } 44 } 45 46 s = str; 47 while (sc->bytestream < sc->bytestream_end && !pnm_space(c)) { 48 if ((s - str) < buf_size - 1) 49 *s++ = c; 50 c = *sc->bytestream++; 51 } 52 *s = '\0'; 53} 54 55int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s){ 56 char buf1[32], tuple_type[32]; 57 int h, w, depth, maxval; 58 59 pnm_get(s, buf1, sizeof(buf1)); 60 if (!strcmp(buf1, "P4")) { 61 avctx->pix_fmt = PIX_FMT_MONOWHITE; 62 } else if (!strcmp(buf1, "P5")) { 63 if (avctx->codec_id == CODEC_ID_PGMYUV) 64 avctx->pix_fmt = PIX_FMT_YUV420P; 65 else 66 avctx->pix_fmt = PIX_FMT_GRAY8; 67 } else if (!strcmp(buf1, "P6")) { 68 avctx->pix_fmt = PIX_FMT_RGB24; 69 } else if (!strcmp(buf1, "P7")) { 70 w = -1; 71 h = -1; 72 maxval = -1; 73 depth = -1; 74 tuple_type[0] = '\0'; 75 for(;;) { 76 pnm_get(s, buf1, sizeof(buf1)); 77 if (!strcmp(buf1, "WIDTH")) { 78 pnm_get(s, buf1, sizeof(buf1)); 79 w = strtol(buf1, NULL, 10); 80 } else if (!strcmp(buf1, "HEIGHT")) { 81 pnm_get(s, buf1, sizeof(buf1)); 82 h = strtol(buf1, NULL, 10); 83 } else if (!strcmp(buf1, "DEPTH")) { 84 pnm_get(s, buf1, sizeof(buf1)); 85 depth = strtol(buf1, NULL, 10); 86 } else if (!strcmp(buf1, "MAXVAL")) { 87 pnm_get(s, buf1, sizeof(buf1)); 88 maxval = strtol(buf1, NULL, 10); 89 } else if (!strcmp(buf1, "TUPLETYPE")) { 90 pnm_get(s, tuple_type, sizeof(tuple_type)); 91 } else if (!strcmp(buf1, "ENDHDR")) { 92 break; 93 } else { 94 return -1; 95 } 96 } 97 /* check that all tags are present */ 98 if (w <= 0 || h <= 0 || maxval <= 0 || depth <= 0 || tuple_type[0] == '\0' || avcodec_check_dimensions(avctx, w, h)) 99 return -1; 100 101 avctx->width = w; 102 avctx->height = h; 103 if (depth == 1) { 104 if (maxval == 1) 105 avctx->pix_fmt = PIX_FMT_MONOWHITE; 106 else 107 avctx->pix_fmt = PIX_FMT_GRAY8; 108 } else if (depth == 3) { 109 if (maxval < 256) { 110 avctx->pix_fmt = PIX_FMT_RGB24; 111 } else { 112 av_log(avctx, AV_LOG_ERROR, "16-bit components are only supported for grayscale\n"); 113 avctx->pix_fmt = PIX_FMT_NONE; 114 return -1; 115 } 116 } else if (depth == 4) { 117 avctx->pix_fmt = PIX_FMT_RGB32; 118 } else { 119 return -1; 120 } 121 return 0; 122 } else { 123 return -1; 124 } 125 pnm_get(s, buf1, sizeof(buf1)); 126 avctx->width = atoi(buf1); 127 if (avctx->width <= 0) 128 return -1; 129 pnm_get(s, buf1, sizeof(buf1)); 130 avctx->height = atoi(buf1); 131 if(avcodec_check_dimensions(avctx, avctx->width, avctx->height)) 132 return -1; 133 if (avctx->pix_fmt != PIX_FMT_MONOWHITE) { 134 pnm_get(s, buf1, sizeof(buf1)); 135 s->maxval = atoi(buf1); 136 if (s->maxval >= 256) { 137 if (avctx->pix_fmt == PIX_FMT_GRAY8) { 138 avctx->pix_fmt = PIX_FMT_GRAY16BE; 139 if (s->maxval != 65535) 140 avctx->pix_fmt = PIX_FMT_GRAY16; 141 } if (avctx->pix_fmt == PIX_FMT_RGB24) { 142 if (s->maxval > 255) 143 avctx->pix_fmt = PIX_FMT_RGB48BE; 144 } else { 145 av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format\n"); 146 avctx->pix_fmt = PIX_FMT_NONE; 147 return -1; 148 } 149 } 150 } 151 /* more check if YUV420 */ 152 if (avctx->pix_fmt == PIX_FMT_YUV420P) { 153 if ((avctx->width & 1) != 0) 154 return -1; 155 h = (avctx->height * 2); 156 if ((h % 3) != 0) 157 return -1; 158 h /= 3; 159 avctx->height = h; 160 } 161 return 0; 162} 163