1/* 2 * PNM image parser 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 22#include "libavutil/avassert.h" 23#include "libavutil/imgutils.h" 24 25#include "parser.h" //for ParseContext 26#include "pnm.h" 27 28typedef struct PNMParseContext { 29 ParseContext pc; 30 int remaining_bytes; 31 int ascii_scan; 32}PNMParseContext; 33 34static int pnm_parse(AVCodecParserContext *s, AVCodecContext *avctx, 35 const uint8_t **poutbuf, int *poutbuf_size, 36 const uint8_t *buf, int buf_size) 37{ 38 PNMParseContext *pnmpc = s->priv_data; 39 ParseContext *pc = &pnmpc->pc; 40 PNMContext pnmctx; 41 int next = END_NOT_FOUND; 42 int skip = 0; 43 44 if (pc->overread > 0) { 45 memmove(pc->buffer + pc->index, pc->buffer + pc->overread_index, pc->overread); 46 pc->index += pc->overread; 47 pc->overread_index += pc->overread; 48 pc->overread = 0; 49 } 50 51 if (pnmpc->remaining_bytes) { 52 int inc = FFMIN(pnmpc->remaining_bytes, buf_size); 53 skip += inc; 54 pnmpc->remaining_bytes -= inc; 55 56 if (!pnmpc->remaining_bytes) 57 next = skip; 58 goto end; 59 } 60 61retry: 62 if (pc->index) { 63 pnmctx.bytestream_start = 64 pnmctx.bytestream = pc->buffer; 65 pnmctx.bytestream_end = pc->buffer + pc->index; 66 } else { 67 pnmctx.bytestream_start = 68 pnmctx.bytestream = (uint8_t *) buf + skip; /* casts avoid warnings */ 69 pnmctx.bytestream_end = (uint8_t *) buf + buf_size - skip; 70 } 71 if (ff_pnm_decode_header(avctx, &pnmctx) < 0) { 72 if (pnmctx.bytestream < pnmctx.bytestream_end) { 73 if (pc->index) { 74 pc->index = 0; 75 pnmpc->ascii_scan = 0; 76 } else { 77 unsigned step = FFMAX(1, pnmctx.bytestream - pnmctx.bytestream_start); 78 79 skip += step; 80 } 81 goto retry; 82 } 83 } else if (pnmctx.type < 4) { 84 uint8_t *bs = pnmctx.bytestream; 85 const uint8_t *end = pnmctx.bytestream_end; 86 uint8_t *sync = bs; 87 88 if (pc->index) { 89 av_assert0(pnmpc->ascii_scan <= end - bs); 90 bs += pnmpc->ascii_scan; 91 } 92 93 while (bs < end) { 94 int c; 95 sync = bs; 96 c = *bs++; 97 if (c == '#') { 98 uint8_t *match = memchr(bs, '\n', end-bs); 99 if (match) 100 bs = match + 1; 101 else 102 break; 103 } else if (c == 'P') { 104 next = bs - pnmctx.bytestream_start + skip - 1; 105 pnmpc->ascii_scan = 0; 106 break; 107 } 108 } 109 if (next == END_NOT_FOUND) 110 pnmpc->ascii_scan = sync - pnmctx.bytestream + skip; 111 } else { 112 int ret = av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1); 113 next = pnmctx.bytestream - pnmctx.bytestream_start + skip; 114 if (ret > 0 && pnmctx.half) 115 ret >>= 1; 116 if (ret >= 0 && next + (uint64_t)ret <= INT_MAX) 117 next += ret; 118 } 119 if (next != END_NOT_FOUND && pnmctx.bytestream_start != buf + skip) 120 next -= pc->index; 121 if (next > buf_size) { 122 pnmpc->remaining_bytes = next - buf_size; 123 next = END_NOT_FOUND; 124 } 125end: 126 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { 127 *poutbuf = NULL; 128 *poutbuf_size = 0; 129 return buf_size; 130 } 131 *poutbuf = buf; 132 *poutbuf_size = buf_size; 133 return next; 134} 135 136const AVCodecParser ff_pnm_parser = { 137 .codec_ids = { AV_CODEC_ID_PGM, AV_CODEC_ID_PGMYUV, AV_CODEC_ID_PPM, 138 AV_CODEC_ID_PBM, AV_CODEC_ID_PAM, AV_CODEC_ID_PFM, 139 AV_CODEC_ID_PHM }, 140 .priv_data_size = sizeof(PNMParseContext), 141 .parser_parse = pnm_parse, 142 .parser_close = ff_parse_close, 143}; 144