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 "bytestream.h" 23#include "pnm.h" 24 25 26static av_cold int common_init(AVCodecContext *avctx){ 27 PNMContext *s = avctx->priv_data; 28 29 avcodec_get_frame_defaults((AVFrame*)&s->picture); 30 avctx->coded_frame= (AVFrame*)&s->picture; 31 32 return 0; 33} 34 35static int pnm_decode_frame(AVCodecContext *avctx, 36 void *data, int *data_size, 37 const uint8_t *buf, int buf_size) 38{ 39 PNMContext * const s = avctx->priv_data; 40 AVFrame *picture = data; 41 AVFrame * const p= (AVFrame*)&s->picture; 42 int i, n, linesize, h, upgrade = 0; 43 unsigned char *ptr; 44 45 s->bytestream_start= 46 s->bytestream= buf; 47 s->bytestream_end= buf + buf_size; 48 49 if(ff_pnm_decode_header(avctx, s) < 0) 50 return -1; 51 52 if(p->data[0]) 53 avctx->release_buffer(avctx, p); 54 55 p->reference= 0; 56 if(avctx->get_buffer(avctx, p) < 0){ 57 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 58 return -1; 59 } 60 p->pict_type= FF_I_TYPE; 61 p->key_frame= 1; 62 63 switch(avctx->pix_fmt) { 64 default: 65 return -1; 66 case PIX_FMT_RGB48BE: 67 n = avctx->width * 6; 68 goto do_read; 69 case PIX_FMT_RGB24: 70 n = avctx->width * 3; 71 goto do_read; 72 case PIX_FMT_GRAY8: 73 n = avctx->width; 74 if (s->maxval < 255) 75 upgrade = 1; 76 goto do_read; 77 case PIX_FMT_GRAY16BE: 78 case PIX_FMT_GRAY16LE: 79 n = avctx->width * 2; 80 if (s->maxval < 65535) 81 upgrade = 2; 82 goto do_read; 83 case PIX_FMT_MONOWHITE: 84 case PIX_FMT_MONOBLACK: 85 n = (avctx->width + 7) >> 3; 86 do_read: 87 ptr = p->data[0]; 88 linesize = p->linesize[0]; 89 if(s->bytestream + n*avctx->height > s->bytestream_end) 90 return -1; 91 for(i = 0; i < avctx->height; i++) { 92 if (!upgrade) 93 memcpy(ptr, s->bytestream, n); 94 else if (upgrade == 1) { 95 unsigned int j, f = (255*128 + s->maxval/2) / s->maxval; 96 for (j=0; j<n; j++) 97 ptr[j] = (s->bytestream[j] * f + 64) >> 7; 98 } else if (upgrade == 2) { 99 unsigned int j, v, f = (65535*32768 + s->maxval/2) / s->maxval; 100 for (j=0; j<n/2; j++) { 101 v = be2me_16(((uint16_t *)s->bytestream)[j]); 102 ((uint16_t *)ptr)[j] = (v * f + 16384) >> 15; 103 } 104 } 105 s->bytestream += n; 106 ptr += linesize; 107 } 108 break; 109 case PIX_FMT_YUV420P: 110 { 111 unsigned char *ptr1, *ptr2; 112 113 n = avctx->width; 114 ptr = p->data[0]; 115 linesize = p->linesize[0]; 116 if(s->bytestream + n*avctx->height*3/2 > s->bytestream_end) 117 return -1; 118 for(i = 0; i < avctx->height; i++) { 119 memcpy(ptr, s->bytestream, n); 120 s->bytestream += n; 121 ptr += linesize; 122 } 123 ptr1 = p->data[1]; 124 ptr2 = p->data[2]; 125 n >>= 1; 126 h = avctx->height >> 1; 127 for(i = 0; i < h; i++) { 128 memcpy(ptr1, s->bytestream, n); 129 s->bytestream += n; 130 memcpy(ptr2, s->bytestream, n); 131 s->bytestream += n; 132 ptr1 += p->linesize[1]; 133 ptr2 += p->linesize[2]; 134 } 135 } 136 break; 137 case PIX_FMT_RGB32: 138 ptr = p->data[0]; 139 linesize = p->linesize[0]; 140 if(s->bytestream + avctx->width*avctx->height*4 > s->bytestream_end) 141 return -1; 142 for(i = 0; i < avctx->height; i++) { 143 int j, r, g, b, a; 144 145 for(j = 0;j < avctx->width; j++) { 146 r = *s->bytestream++; 147 g = *s->bytestream++; 148 b = *s->bytestream++; 149 a = *s->bytestream++; 150 ((uint32_t *)ptr)[j] = (a << 24) | (r << 16) | (g << 8) | b; 151 } 152 ptr += linesize; 153 } 154 break; 155 } 156 *picture= *(AVFrame*)&s->picture; 157 *data_size = sizeof(AVPicture); 158 159 return s->bytestream - s->bytestream_start; 160} 161 162static int pnm_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){ 163 PNMContext *s = avctx->priv_data; 164 AVFrame *pict = data; 165 AVFrame * const p= (AVFrame*)&s->picture; 166 int i, h, h1, c, n, linesize; 167 uint8_t *ptr, *ptr1, *ptr2; 168 169 if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){ 170 av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n"); 171 return -1; 172 } 173 174 *p = *pict; 175 p->pict_type= FF_I_TYPE; 176 p->key_frame= 1; 177 178 s->bytestream_start= 179 s->bytestream= outbuf; 180 s->bytestream_end= outbuf+buf_size; 181 182 h = avctx->height; 183 h1 = h; 184 switch(avctx->pix_fmt) { 185 case PIX_FMT_MONOWHITE: 186 c = '4'; 187 n = (avctx->width + 7) >> 3; 188 break; 189 case PIX_FMT_GRAY8: 190 c = '5'; 191 n = avctx->width; 192 break; 193 case PIX_FMT_GRAY16BE: 194 c = '5'; 195 n = avctx->width * 2; 196 break; 197 case PIX_FMT_RGB24: 198 c = '6'; 199 n = avctx->width * 3; 200 break; 201 case PIX_FMT_RGB48BE: 202 c = '6'; 203 n = avctx->width * 6; 204 break; 205 case PIX_FMT_YUV420P: 206 c = '5'; 207 n = avctx->width; 208 h1 = (h * 3) / 2; 209 break; 210 default: 211 return -1; 212 } 213 snprintf(s->bytestream, s->bytestream_end - s->bytestream, 214 "P%c\n%d %d\n", 215 c, avctx->width, h1); 216 s->bytestream += strlen(s->bytestream); 217 if (avctx->pix_fmt != PIX_FMT_MONOWHITE) { 218 snprintf(s->bytestream, s->bytestream_end - s->bytestream, 219 "%d\n", (avctx->pix_fmt != PIX_FMT_GRAY16BE && avctx->pix_fmt != PIX_FMT_RGB48BE) ? 255 : 65535); 220 s->bytestream += strlen(s->bytestream); 221 } 222 223 ptr = p->data[0]; 224 linesize = p->linesize[0]; 225 for(i=0;i<h;i++) { 226 memcpy(s->bytestream, ptr, n); 227 s->bytestream += n; 228 ptr += linesize; 229 } 230 231 if (avctx->pix_fmt == PIX_FMT_YUV420P) { 232 h >>= 1; 233 n >>= 1; 234 ptr1 = p->data[1]; 235 ptr2 = p->data[2]; 236 for(i=0;i<h;i++) { 237 memcpy(s->bytestream, ptr1, n); 238 s->bytestream += n; 239 memcpy(s->bytestream, ptr2, n); 240 s->bytestream += n; 241 ptr1 += p->linesize[1]; 242 ptr2 += p->linesize[2]; 243 } 244 } 245 return s->bytestream - s->bytestream_start; 246} 247 248static int pam_encode_frame(AVCodecContext *avctx, unsigned char *outbuf, int buf_size, void *data){ 249 PNMContext *s = avctx->priv_data; 250 AVFrame *pict = data; 251 AVFrame * const p= (AVFrame*)&s->picture; 252 int i, h, w, n, linesize, depth, maxval; 253 const char *tuple_type; 254 uint8_t *ptr; 255 256 if(buf_size < avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height) + 200){ 257 av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n"); 258 return -1; 259 } 260 261 *p = *pict; 262 p->pict_type= FF_I_TYPE; 263 p->key_frame= 1; 264 265 s->bytestream_start= 266 s->bytestream= outbuf; 267 s->bytestream_end= outbuf+buf_size; 268 269 h = avctx->height; 270 w = avctx->width; 271 switch(avctx->pix_fmt) { 272 case PIX_FMT_MONOWHITE: 273 n = (w + 7) >> 3; 274 depth = 1; 275 maxval = 1; 276 tuple_type = "BLACKANDWHITE"; 277 break; 278 case PIX_FMT_GRAY8: 279 n = w; 280 depth = 1; 281 maxval = 255; 282 tuple_type = "GRAYSCALE"; 283 break; 284 case PIX_FMT_RGB24: 285 n = w * 3; 286 depth = 3; 287 maxval = 255; 288 tuple_type = "RGB"; 289 break; 290 case PIX_FMT_RGB32: 291 n = w * 4; 292 depth = 4; 293 maxval = 255; 294 tuple_type = "RGB_ALPHA"; 295 break; 296 default: 297 return -1; 298 } 299 snprintf(s->bytestream, s->bytestream_end - s->bytestream, 300 "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLETYPE %s\nENDHDR\n", 301 w, h, depth, maxval, tuple_type); 302 s->bytestream += strlen(s->bytestream); 303 304 ptr = p->data[0]; 305 linesize = p->linesize[0]; 306 307 if (avctx->pix_fmt == PIX_FMT_RGB32) { 308 int j; 309 unsigned int v; 310 311 for(i=0;i<h;i++) { 312 for(j=0;j<w;j++) { 313 v = ((uint32_t *)ptr)[j]; 314 bytestream_put_be24(&s->bytestream, v); 315 *s->bytestream++ = v >> 24; 316 } 317 ptr += linesize; 318 } 319 } else { 320 for(i=0;i<h;i++) { 321 memcpy(s->bytestream, ptr, n); 322 s->bytestream += n; 323 ptr += linesize; 324 } 325 } 326 return s->bytestream - s->bytestream_start; 327} 328 329#if 0 330static int pnm_probe(AVProbeData *pd) 331{ 332 const char *p = pd->buf; 333 if (pd->buf_size >= 8 && 334 p[0] == 'P' && 335 p[1] >= '4' && p[1] <= '6' && 336 pnm_space(p[2]) ) 337 return AVPROBE_SCORE_MAX - 1; /* to permit pgmyuv probe */ 338 else 339 return 0; 340} 341 342static int pgmyuv_probe(AVProbeData *pd) 343{ 344 if (match_ext(pd->filename, "pgmyuv")) 345 return AVPROBE_SCORE_MAX; 346 else 347 return 0; 348} 349 350static int pam_probe(AVProbeData *pd) 351{ 352 const char *p = pd->buf; 353 if (pd->buf_size >= 8 && 354 p[0] == 'P' && 355 p[1] == '7' && 356 p[2] == '\n') 357 return AVPROBE_SCORE_MAX; 358 else 359 return 0; 360} 361#endif 362 363 364#if CONFIG_PGM_ENCODER 365AVCodec pgm_encoder = { 366 "pgm", 367 CODEC_TYPE_VIDEO, 368 CODEC_ID_PGM, 369 sizeof(PNMContext), 370 common_init, 371 pnm_encode_frame, 372 NULL, //encode_end, 373 pnm_decode_frame, 374 .pix_fmts= (enum PixelFormat[]){PIX_FMT_GRAY8, PIX_FMT_GRAY16BE, PIX_FMT_NONE}, 375 .long_name= NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"), 376}; 377#endif // CONFIG_PGM_ENCODER 378 379#if CONFIG_PGMYUV_ENCODER 380AVCodec pgmyuv_encoder = { 381 "pgmyuv", 382 CODEC_TYPE_VIDEO, 383 CODEC_ID_PGMYUV, 384 sizeof(PNMContext), 385 common_init, 386 pnm_encode_frame, 387 NULL, //encode_end, 388 pnm_decode_frame, 389 .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, 390 .long_name= NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"), 391}; 392#endif // CONFIG_PGMYUV_ENCODER 393 394#if CONFIG_PPM_ENCODER 395AVCodec ppm_encoder = { 396 "ppm", 397 CODEC_TYPE_VIDEO, 398 CODEC_ID_PPM, 399 sizeof(PNMContext), 400 common_init, 401 pnm_encode_frame, 402 NULL, //encode_end, 403 pnm_decode_frame, 404 .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB48BE, PIX_FMT_NONE}, 405 .long_name= NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"), 406}; 407#endif // CONFIG_PPM_ENCODER 408 409#if CONFIG_PBM_ENCODER 410AVCodec pbm_encoder = { 411 "pbm", 412 CODEC_TYPE_VIDEO, 413 CODEC_ID_PBM, 414 sizeof(PNMContext), 415 common_init, 416 pnm_encode_frame, 417 NULL, //encode_end, 418 pnm_decode_frame, 419 .pix_fmts= (enum PixelFormat[]){PIX_FMT_MONOWHITE, PIX_FMT_NONE}, 420 .long_name= NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"), 421}; 422#endif // CONFIG_PBM_ENCODER 423 424#if CONFIG_PAM_ENCODER 425AVCodec pam_encoder = { 426 "pam", 427 CODEC_TYPE_VIDEO, 428 CODEC_ID_PAM, 429 sizeof(PNMContext), 430 common_init, 431 pam_encode_frame, 432 NULL, //encode_end, 433 pnm_decode_frame, 434 .pix_fmts= (enum PixelFormat[]){PIX_FMT_RGB24, PIX_FMT_RGB32, PIX_FMT_GRAY8, PIX_FMT_MONOWHITE, PIX_FMT_NONE}, 435 .long_name= NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"), 436}; 437#endif // CONFIG_PAM_ENCODER 438