FFmpeg  4.3.6
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 "internal.h"
30 #include "pnm.h"
31 
32 static inline int pnm_space(int c)
33 {
34  return c == ' ' || c == '\n' || c == '\r' || c == '\t';
35 }
36 
37 static void pnm_get(PNMContext *sc, char *str, int buf_size)
38 {
39  char *s;
40  int c;
41  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 += s->bytestream_end > s->bytestream;
77  s->bytestream += s->bytestream_end > s->bytestream;
78  return AVERROR_INVALIDDATA;
79  }
80  pnm_get(s, buf1, sizeof(buf1));
81  s->type= buf1[1]-'0';
82 
83  if (buf1[1] == 'F') {
84  avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
85  } else if (s->type==1 || s->type==4) {
87  } else if (s->type==2 || s->type==5) {
88  if (avctx->codec_id == AV_CODEC_ID_PGMYUV)
89  avctx->pix_fmt = AV_PIX_FMT_YUV420P;
90  else
91  avctx->pix_fmt = AV_PIX_FMT_GRAY8;
92  } else if (s->type==3 || s->type==6) {
93  avctx->pix_fmt = AV_PIX_FMT_RGB24;
94  } else if (s->type==7) {
95  w = -1;
96  h = -1;
97  maxval = -1;
98  depth = -1;
99  tuple_type[0] = '\0';
100  for (;;) {
101  pnm_get(s, buf1, sizeof(buf1));
102  if (!strcmp(buf1, "WIDTH")) {
103  pnm_get(s, buf1, sizeof(buf1));
104  w = strtol(buf1, NULL, 10);
105  } else if (!strcmp(buf1, "HEIGHT")) {
106  pnm_get(s, buf1, sizeof(buf1));
107  h = strtol(buf1, NULL, 10);
108  } else if (!strcmp(buf1, "DEPTH")) {
109  pnm_get(s, buf1, sizeof(buf1));
110  depth = strtol(buf1, NULL, 10);
111  } else if (!strcmp(buf1, "MAXVAL")) {
112  pnm_get(s, buf1, sizeof(buf1));
113  maxval = strtol(buf1, NULL, 10);
114  } else if (!strcmp(buf1, "TUPLTYPE") ||
115  /* libavcodec used to write invalid files */
116  !strcmp(buf1, "TUPLETYPE")) {
117  pnm_get(s, tuple_type, sizeof(tuple_type));
118  } else if (!strcmp(buf1, "ENDHDR")) {
119  break;
120  } else {
121  return AVERROR_INVALIDDATA;
122  }
123  }
124  if (!pnm_space(s->bytestream[-1]))
125  return AVERROR_INVALIDDATA;
126 
127  /* check that all tags are present */
128  if (w <= 0 || h <= 0 || maxval <= 0 || maxval > UINT16_MAX || depth <= 0 || tuple_type[0] == '\0' ||
129  av_image_check_size(w, h, 0, avctx) || s->bytestream >= s->bytestream_end)
130  return AVERROR_INVALIDDATA;
131 
132  ret = ff_set_dimensions(avctx, w, h);
133  if (ret < 0)
134  return ret;
135  s->maxval = maxval;
136  if (depth == 1) {
137  if (maxval == 1) {
138  avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
139  } else if (maxval < 256) {
140  avctx->pix_fmt = AV_PIX_FMT_GRAY8;
141  } else {
142  avctx->pix_fmt = AV_PIX_FMT_GRAY16;
143  }
144  } else if (depth == 2) {
145  if (maxval < 256) {
146  avctx->pix_fmt = AV_PIX_FMT_GRAY8A;
147  } else {
148  avctx->pix_fmt = AV_PIX_FMT_YA16;
149  }
150  } else if (depth == 3) {
151  if (maxval < 256) {
152  avctx->pix_fmt = AV_PIX_FMT_RGB24;
153  } else {
154  avctx->pix_fmt = AV_PIX_FMT_RGB48;
155  }
156  } else if (depth == 4) {
157  if (maxval < 256) {
158  avctx->pix_fmt = AV_PIX_FMT_RGBA;
159  } else {
160  avctx->pix_fmt = AV_PIX_FMT_RGBA64;
161  }
162  } else {
163  return AVERROR_INVALIDDATA;
164  }
165  return 0;
166  } else {
167  av_assert0(0);
168  }
169  pnm_get(s, buf1, sizeof(buf1));
170  w = atoi(buf1);
171  pnm_get(s, buf1, sizeof(buf1));
172  h = atoi(buf1);
173  if(w <= 0 || h <= 0 || av_image_check_size(w, h, 0, avctx) || s->bytestream >= s->bytestream_end)
174  return AVERROR_INVALIDDATA;
175 
176  ret = ff_set_dimensions(avctx, w, h);
177  if (ret < 0)
178  return ret;
179 
180  if (avctx->pix_fmt == AV_PIX_FMT_GBRPF32) {
181  pnm_get(s, buf1, sizeof(buf1));
182  if (av_sscanf(buf1, "%f", &s->scale) != 1 || s->scale == 0.0 || !isfinite(s->scale)) {
183  av_log(avctx, AV_LOG_ERROR, "Invalid scale.\n");
184  return AVERROR_INVALIDDATA;
185  }
186  s->endian = s->scale < 0.f;
187  s->scale = fabsf(s->scale);
188  s->maxval = (1ULL << 32) - 1;
189  } else if (avctx->pix_fmt != AV_PIX_FMT_MONOWHITE && avctx->pix_fmt != AV_PIX_FMT_MONOBLACK) {
190  pnm_get(s, buf1, sizeof(buf1));
191  s->maxval = atoi(buf1);
192  if (s->maxval <= 0 || s->maxval > UINT16_MAX) {
193  av_log(avctx, AV_LOG_ERROR, "Invalid maxval: %d\n", s->maxval);
194  s->maxval = 255;
195  }
196  if (s->maxval >= 256) {
197  if (avctx->pix_fmt == AV_PIX_FMT_GRAY8) {
198  avctx->pix_fmt = AV_PIX_FMT_GRAY16;
199  } else if (avctx->pix_fmt == AV_PIX_FMT_RGB24) {
200  avctx->pix_fmt = AV_PIX_FMT_RGB48;
201  } else if (avctx->pix_fmt == AV_PIX_FMT_YUV420P && s->maxval < 65536) {
202  if (s->maxval < 512)
203  avctx->pix_fmt = AV_PIX_FMT_YUV420P9;
204  else if (s->maxval < 1024)
205  avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
206  else
207  avctx->pix_fmt = AV_PIX_FMT_YUV420P16;
208  } else {
209  av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format\n");
210  avctx->pix_fmt = AV_PIX_FMT_NONE;
211  return AVERROR_INVALIDDATA;
212  }
213  }
214  }else
215  s->maxval=1;
216 
217  if (!pnm_space(s->bytestream[-1]))
218  return AVERROR_INVALIDDATA;
219 
220  /* more check if YUV420 */
222  if ((avctx->width & 1) != 0)
223  return AVERROR_INVALIDDATA;
224  h = (avctx->height * 2);
225  if ((h % 3) != 0)
226  return AVERROR_INVALIDDATA;
227  h /= 3;
228  avctx->height = h;
229  }
230  return 0;
231 }
#define NULL
Definition: coverity.c:32
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2549
static int pnm_space(int c)
Definition: pnm.c:32
misc image utilities
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:104
#define AV_PIX_FMT_RGBA64
Definition: pixfmt.h:387
int maxval
maximum value of a pixel
Definition: pnm.h:31
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:736
uint8_t * bytestream
Definition: pnm.h:28
float scale
Definition: pnm.h:34
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
uint8_t
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:92
#define av_log(a,...)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define isfinite(x)
Definition: libm.h:359
#define AV_PIX_FMT_YA16
Definition: pixfmt.h:382
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:383
simple assert() macros that are a bit more flexible than ISO C assert().
static void pnm_get(PNMContext *sc, char *str, int buf_size)
Definition: pnm.c:37
uint8_t * bytestream_end
Definition: pnm.h:30
int av_sscanf(const char *string, const char *format,...)
See libc sscanf manual for more information.
Definition: avsscanf.c:962
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
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:282
alias for AV_PIX_FMT_YA8
Definition: pixfmt.h:146
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:381
int width
picture width / height.
Definition: avcodec.h:699
uint8_t w
Definition: llviddspenc.c:38
#define s(width, name)
Definition: cbs_vp9.c:257
#define AV_PIX_FMT_YUV420P16
Definition: pixfmt.h:408
Definition: pnm.h:27
Libavcodec external API header.
enum AVCodecID codec_id
Definition: avcodec.h:536
int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext *const s)
Definition: pnm.c:65
main external API structure.
Definition: avcodec.h:526
#define AV_PIX_FMT_YUV420P10
Definition: pixfmt.h:397
#define AV_PIX_FMT_YUV420P9
Definition: pixfmt.h:394
int endian
Definition: pnm.h:33
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:426
Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb...
Definition: pixfmt.h:76
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
Y , 8bpp.
Definition: pixfmt.h:74
common internal api header.
Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb...
Definition: pixfmt.h:75
static double c[64]
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition: pixdesc.h:144
int type
Definition: pnm.h:32