FFmpeg
Loading...
Searching...
No Matches
pnm.c
Go to the documentation of this file.
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
22#include <stdlib.h>
23#include <string.h>
24
25#include "libavutil/avassert.h"
26#include "libavutil/imgutils.h"
27#include "libavutil/avstring.h"
28#include "avcodec.h"
29#include "decode.h"
30#include "pnm.h"
31
32static inline int pnm_space(int c)
33{
34 return c == ' ' || c == '\n' || c == '\r' || c == '\t';
35}
36
37static void pnm_get(PNMContext *sc, char *str, int buf_size)
38{
39 char *s;
40 int c;
41 const uint8_t *bs = sc->bytestream;
42 const uint8_t *end = sc->bytestream_end;
43
44 /* skip spaces and comments */
45 while (bs < end) {
46 c = *bs++;
47 if (c == '#') {
48 while (c != '\n' && bs < end) {
49 c = *bs++;
50 }
51 } else if (!pnm_space(c)) {
52 break;
53 }
54 }
55
56 s = str;
57 while (bs < end && !pnm_space(c) && (s - str) < buf_size - 1) {
58 *s++ = c;
59 c = *bs++;
60 }
61 *s = '\0';
62 sc->bytestream = bs;
63}
64
66{
67 char buf1[32], tuple_type[32];
68 int h, w, depth, maxval;
69 int ret;
70
71 if (s->bytestream_end - s->bytestream < 3 ||
72 s->bytestream[0] != 'P' ||
73 (s->bytestream[1] < '1' ||
74 s->bytestream[1] > '7' &&
75 s->bytestream[1] != 'f' &&
76 s->bytestream[1] != 'F' &&
77 s->bytestream[1] != 'H' &&
78 s->bytestream[1] != 'h')) {
79 s->bytestream += s->bytestream_end > s->bytestream;
80 s->bytestream += s->bytestream_end > s->bytestream;
82 }
83 pnm_get(s, buf1, sizeof(buf1));
84 s->type= buf1[1]-'0';
85 s->half = 0;
86
87 if (buf1[1] == 'F') {
89 } else if (buf1[1] == 'f') {
91 } else if (buf1[1] == 'H') {
93 s->half = 1;
94 } else if (buf1[1] == 'h') {
96 s->half = 1;
97 } else if (s->type==1 || s->type==4) {
99 } else if (s->type==2 || s->type==5) {
100 if (avctx->codec_id == AV_CODEC_ID_PGMYUV) {
103 } else {
104 avctx->pix_fmt = AV_PIX_FMT_GRAY8;
105 }
106 } else if (s->type==3 || s->type==6) {
107 avctx->pix_fmt = AV_PIX_FMT_RGB24;
108 } else if (s->type==7) {
109 w = -1;
110 h = -1;
111 maxval = -1;
112 depth = -1;
113 tuple_type[0] = '\0';
114 for (;;) {
115 pnm_get(s, buf1, sizeof(buf1));
116 if (!strcmp(buf1, "WIDTH")) {
117 pnm_get(s, buf1, sizeof(buf1));
118 w = strtol(buf1, NULL, 10);
119 } else if (!strcmp(buf1, "HEIGHT")) {
120 pnm_get(s, buf1, sizeof(buf1));
121 h = strtol(buf1, NULL, 10);
122 } else if (!strcmp(buf1, "DEPTH")) {
123 pnm_get(s, buf1, sizeof(buf1));
124 depth = strtol(buf1, NULL, 10);
125 } else if (!strcmp(buf1, "MAXVAL")) {
126 pnm_get(s, buf1, sizeof(buf1));
127 maxval = strtol(buf1, NULL, 10);
128 } else if (!strcmp(buf1, "TUPLTYPE") ||
129 /* libavcodec used to write invalid files */
130 !strcmp(buf1, "TUPLETYPE")) {
131 pnm_get(s, tuple_type, sizeof(tuple_type));
132 } else if (!strcmp(buf1, "ENDHDR")) {
133 break;
134 } else {
135 return AVERROR_INVALIDDATA;
136 }
137 }
138 if (!pnm_space(s->bytestream[-1]))
139 return AVERROR_INVALIDDATA;
140
141 /* check that all tags are present */
142 if (w <= 0 || h <= 0 || maxval <= 0 || maxval > UINT16_MAX || depth <= 0 || tuple_type[0] == '\0' ||
143 av_image_check_size(w, h, 0, avctx) || s->bytestream >= s->bytestream_end)
144 return AVERROR_INVALIDDATA;
145
146 ret = ff_set_dimensions(avctx, w, h);
147 if (ret < 0)
148 return ret;
149 s->maxval = maxval;
150 if (depth == 1) {
151 if (maxval == 1) {
153 } else if (maxval < 256) {
154 avctx->pix_fmt = AV_PIX_FMT_GRAY8;
155 } else {
156 avctx->pix_fmt = AV_PIX_FMT_GRAY16;
157 }
158 } else if (depth == 2) {
159 if (maxval < 256) {
160 avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
161 } else {
162 avctx->pix_fmt = AV_PIX_FMT_YA16;
163 }
164 } else if (depth == 3) {
165 if (maxval < 256) {
166 avctx->pix_fmt = AV_PIX_FMT_RGB24;
167 } else {
168 avctx->pix_fmt = AV_PIX_FMT_RGB48;
169 }
170 } else if (depth == 4) {
171 if (maxval < 256) {
172 avctx->pix_fmt = AV_PIX_FMT_RGBA;
173 } else {
174 avctx->pix_fmt = AV_PIX_FMT_RGBA64;
175 }
176 } else {
177 return AVERROR_INVALIDDATA;
178 }
179 return 0;
180 } else {
181 av_assert0(0);
182 }
183 pnm_get(s, buf1, sizeof(buf1));
184 w = atoi(buf1);
185 pnm_get(s, buf1, sizeof(buf1));
186 h = atoi(buf1);
187 if(w <= 0 || h <= 0 || av_image_check_size(w, h, 0, avctx) || s->bytestream >= s->bytestream_end)
188 return AVERROR_INVALIDDATA;
189
190 ret = ff_set_dimensions(avctx, w, h);
191 if (ret < 0)
192 return ret;
193
194 if (avctx->pix_fmt == AV_PIX_FMT_GBRPF32 || avctx->pix_fmt == AV_PIX_FMT_GRAYF32) {
195 pnm_get(s, buf1, sizeof(buf1));
196 if (av_sscanf(buf1, "%f", &s->scale) != 1 || s->scale == 0.0 || !isfinite(s->scale)) {
197 av_log(avctx, AV_LOG_ERROR, "Invalid scale.\n");
198 return AVERROR_INVALIDDATA;
199 }
200 s->endian = s->scale < 0.f;
201 s->scale = fabsf(s->scale);
202 s->maxval = (1ULL << 32) - 1;
203 } else if (avctx->pix_fmt != AV_PIX_FMT_MONOWHITE && avctx->pix_fmt != AV_PIX_FMT_MONOBLACK) {
204 pnm_get(s, buf1, sizeof(buf1));
205 s->maxval = atoi(buf1);
206 if (s->maxval <= 0 || s->maxval > UINT16_MAX) {
207 av_log(avctx, AV_LOG_ERROR, "Invalid maxval: %d\n", s->maxval);
208 s->maxval = 255;
209 }
210 if (s->maxval >= 256) {
211 if (avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
212 avctx->pix_fmt = AV_PIX_FMT_GRAY16;
213 } else if (avctx->pix_fmt == AV_PIX_FMT_RGB24) {
214 avctx->pix_fmt = AV_PIX_FMT_RGB48;
215 } else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P && s->maxval < 65536) {
216 if (s->maxval < 512)
218 else if (s->maxval < 1024)
220 else
222 } else {
223 av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format\n");
224 avctx->pix_fmt = AV_PIX_FMT_NONE;
225 return AVERROR_INVALIDDATA;
226 }
227 }
228 }else
229 s->maxval=1;
230
231 if (!pnm_space(s->bytestream[-1]))
232 return AVERROR_INVALIDDATA;
233
234 /* more check if YUV420 */
236 avctx->pix_fmt != AV_PIX_FMT_GBRPF32) {
237 if ((avctx->width & 1) != 0)
238 return AVERROR_INVALIDDATA;
239 h = (avctx->height * 2);
240 if ((h % 3) != 0)
241 return AVERROR_INVALIDDATA;
242 h /= 3;
243 avctx->height = h;
244 }
245 return 0;
246}
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
Libavcodec external API header.
int av_sscanf(const char *string, const char *format,...)
Definition avsscanf.c:962
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
static __device__ float fabsf(float a)
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Definition utils.c:91
@ AV_CODEC_ID_PGMYUV
Definition codec_id.h:115
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
Definition imgutils.c:318
misc image utilities
#define isfinite(x)
Definition libm.h:361
uint8_t w
Definition llvidencdsp.c:39
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition pixdesc.h:132
#define AV_PIX_FMT_YUV420P16
Definition pixfmt.h:556
#define AV_PIX_FMT_GBRPF32
Definition pixfmt.h:584
#define AV_PIX_FMT_YUV420P10
Definition pixfmt.h:545
@ AVCOL_RANGE_MPEG
Narrow or limited range content.
Definition pixfmt.h:766
#define AV_PIX_FMT_YA16
Definition pixfmt.h:530
#define AV_PIX_FMT_RGBA64
Definition pixfmt.h:535
#define AV_PIX_FMT_YUV420P9
Definition pixfmt.h:542
#define AV_PIX_FMT_RGB48
Definition pixfmt.h:531
#define AV_PIX_FMT_GRAYF32
Definition pixfmt.h:588
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition pixfmt.h:75
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_MONOBLACK
Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb.
Definition pixfmt.h:83
@ AV_PIX_FMT_GRAY8A
alias for AV_PIX_FMT_YA8
Definition pixfmt.h:143
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition pixfmt.h:100
@ AV_PIX_FMT_MONOWHITE
Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb.
Definition pixfmt.h:82
#define AV_PIX_FMT_GRAY16
Definition pixfmt.h:528
static int pnm_space(int c)
Definition pnm.c:32
static void pnm_get(PNMContext *sc, char *str, int buf_size)
Definition pnm.c:37
int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext *const s)
Definition pnm.c:65
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition avcodec.h:681
enum AVCodecID codec_id
Definition avcodec.h:453
uint64_t flags
Combination of AV_PIX_FMT_FLAG_... flags.
Definition pixdesc.h:94
const uint8_t * bytestream
Definition pnm.h:29
const uint8_t * bytestream_end
Definition pnm.h:31
#define av_log(a,...)
static double c[64]