FFmpeg
fits.c
Go to the documentation of this file.
1 /*
2  * FITS implementation of common functions
3  * Copyright (c) 2017 Paras Chadha
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 "avcodec.h"
23 #include "libavutil/dict.h"
24 #include "fits.h"
25 
27 {
28  header->state = state;
29  header->naxis_index = 0;
30  header->blank_found = 0;
31  header->pcount = 0;
32  header->gcount = 1;
33  header->groups = 0;
34  header->rgb = 0;
35  header->image_extension = 0;
36  header->bscale = 1.0;
37  header->bzero = 0;
38  header->data_min_found = 0;
39  header->data_max_found = 0;
40  return 0;
41 }
42 
43 static int dict_set_if_not_null(AVDictionary ***metadata, char *keyword, char *value)
44 {
45  if (metadata)
46  av_dict_set(*metadata, keyword, value, 0);
47  return 0;
48 }
49 
50 /**
51  * Extract keyword and value from a header line (80 bytes) and store them in keyword and value strings respectively
52  * @param ptr8 pointer to the data
53  * @param keyword pointer to the char array in which keyword is to be stored
54  * @param value pointer to the char array in which value is to be stored
55  * @return 0 if calculated successfully otherwise AVERROR_INVALIDDATA
56  */
57 static int read_keyword_value(const uint8_t *ptr8, char *keyword, char *value)
58 {
59  int i;
60 
61  for (i = 0; i < 8 && ptr8[i] != ' '; i++) {
62  keyword[i] = ptr8[i];
63  }
64  keyword[i] = '\0';
65 
66  if (ptr8[8] == '=') {
67  i = 10;
68  while (i < 80 && ptr8[i] == ' ') {
69  i++;
70  }
71 
72  if (i < 80) {
73  *value++ = ptr8[i];
74  i++;
75  if (ptr8[i-1] == '\'') {
76  for (; i < 80 && ptr8[i] != '\''; i++) {
77  *value++ = ptr8[i];
78  }
79  *value++ = '\'';
80  } else if (ptr8[i-1] == '(') {
81  for (; i < 80 && ptr8[i] != ')'; i++) {
82  *value++ = ptr8[i];
83  }
84  *value++ = ')';
85  } else {
86  for (; i < 80 && ptr8[i] != ' ' && ptr8[i] != '/'; i++) {
87  *value++ = ptr8[i];
88  }
89  }
90  }
91  }
92  *value = '\0';
93  return 0;
94 }
95 
96 #define CHECK_KEYWORD(key) \
97  if (strcmp(keyword, key)) { \
98  av_log(avcl, AV_LOG_ERROR, "expected %s keyword, found %s = %s\n", key, keyword, value); \
99  return AVERROR_INVALIDDATA; \
100  }
101 
102 #define CHECK_VALUE(key, val) \
103  if (sscanf(value, "%d", &header->val) != 1) { \
104  av_log(avcl, AV_LOG_ERROR, "invalid value of %s keyword, %s = %s\n", key, keyword, value); \
105  return AVERROR_INVALIDDATA; \
106  }
107 
108 int avpriv_fits_header_parse_line(void *avcl, FITSHeader *header, const uint8_t line[80], AVDictionary ***metadata)
109 {
110  int dim_no, ret;
111  int64_t t;
112  double d;
113  char keyword[10], value[72], c;
114 
115  read_keyword_value(line, keyword, value);
116  switch (header->state) {
117  case STATE_SIMPLE:
118  CHECK_KEYWORD("SIMPLE");
119 
120  if (value[0] == 'F') {
121  av_log(avcl, AV_LOG_WARNING, "not a standard FITS file\n");
122  } else if (value[0] != 'T') {
123  av_log(avcl, AV_LOG_ERROR, "invalid value of SIMPLE keyword, SIMPLE = %c\n", value[0]);
124  return AVERROR_INVALIDDATA;
125  }
126 
127  header->state = STATE_BITPIX;
128  break;
129  case STATE_XTENSION:
130  CHECK_KEYWORD("XTENSION");
131 
132  if (!strcmp(value, "'IMAGE '")) {
133  header->image_extension = 1;
134  }
135 
136  header->state = STATE_BITPIX;
137  break;
138  case STATE_BITPIX:
139  CHECK_KEYWORD("BITPIX");
140  CHECK_VALUE("BITPIX", bitpix);
141 
142  switch(header->bitpix) {
143  case 8:
144  case 16:
145  case 32: case -32:
146  case 64: case -64: break;
147  default:
148  av_log(avcl, AV_LOG_ERROR, "invalid value of BITPIX %d\n", header->bitpix); \
149  return AVERROR_INVALIDDATA;
150  }
151 
152  dict_set_if_not_null(metadata, keyword, value);
153 
154  header->state = STATE_NAXIS;
155  break;
156  case STATE_NAXIS:
157  CHECK_KEYWORD("NAXIS");
158  CHECK_VALUE("NAXIS", naxis);
159  dict_set_if_not_null(metadata, keyword, value);
160 
161  if (header->naxis) {
162  header->state = STATE_NAXIS_N;
163  } else {
164  header->state = STATE_REST;
165  }
166  break;
167  case STATE_NAXIS_N:
168  ret = sscanf(keyword, "NAXIS%d", &dim_no);
169  if (ret != 1 || dim_no != header->naxis_index + 1) {
170  av_log(avcl, AV_LOG_ERROR, "expected NAXIS%d keyword, found %s = %s\n", header->naxis_index + 1, keyword, value);
171  return AVERROR_INVALIDDATA;
172  }
173 
174  if (sscanf(value, "%d", &header->naxisn[header->naxis_index]) != 1) {
175  av_log(avcl, AV_LOG_ERROR, "invalid value of NAXIS%d keyword, %s = %s\n", header->naxis_index + 1, keyword, value);
176  return AVERROR_INVALIDDATA;
177  }
178 
179  dict_set_if_not_null(metadata, keyword, value);
180  header->naxis_index++;
181  if (header->naxis_index == header->naxis) {
182  header->state = STATE_REST;
183  }
184  break;
185  case STATE_REST:
186  if (!strcmp(keyword, "BLANK") && sscanf(value, "%"SCNd64"", &t) == 1) {
187  header->blank = t;
188  header->blank_found = 1;
189  } else if (!strcmp(keyword, "BSCALE") && sscanf(value, "%lf", &d) == 1) {
190  if (d <= 0)
191  return AVERROR_INVALIDDATA;
192  header->bscale = d;
193  } else if (!strcmp(keyword, "BZERO") && sscanf(value, "%lf", &d) == 1) {
194  header->bzero = d;
195  } else if (!strcmp(keyword, "CTYPE3") && !strncmp(value, "'RGB", 4)) {
196  header->rgb = 1;
197  } else if (!strcmp(keyword, "DATAMAX") && sscanf(value, "%lf", &d) == 1) {
198  header->data_max_found = 1;
199  header->data_max = d;
200  } else if (!strcmp(keyword, "DATAMIN") && sscanf(value, "%lf", &d) == 1) {
201  header->data_min_found = 1;
202  header->data_min = d;
203  } else if (!strcmp(keyword, "END")) {
204  return 1;
205  } else if (!strcmp(keyword, "GROUPS") && sscanf(value, "%c", &c) == 1) {
206  header->groups = (c == 'T');
207  } else if (!strcmp(keyword, "GCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) {
208  if (t < 0 || t > INT_MAX)
209  return AVERROR_INVALIDDATA;
210  header->gcount = t;
211  } else if (!strcmp(keyword, "PCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) {
212  if (t < 0 || t > INT_MAX)
213  return AVERROR_INVALIDDATA;
214  header->pcount = t;
215  }
216  dict_set_if_not_null(metadata, keyword, value);
217  break;
218  }
219  return 0;
220 }
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
AVDictionary
Definition: dict.c:30
CHECK_VALUE
#define CHECK_VALUE(key, val)
Definition: fits.c:102
STATE_XTENSION
@ STATE_XTENSION
Definition: fits.h:31
fits.h
read_keyword_value
static int read_keyword_value(const uint8_t *ptr8, char *keyword, char *value)
Extract keyword and value from a header line (80 bytes) and store them in keyword and value strings r...
Definition: fits.c:57
avpriv_fits_header_parse_line
int avpriv_fits_header_parse_line(void *avcl, FITSHeader *header, const uint8_t line[80], AVDictionary ***metadata)
Parse a single header line.
Definition: fits.c:108
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
STATE_REST
@ STATE_REST
Definition: fits.h:37
CHECK_KEYWORD
#define CHECK_KEYWORD(key)
Definition: fits.c:96
dict_set_if_not_null
static int dict_set_if_not_null(AVDictionary ***metadata, char *keyword, char *value)
Definition: fits.c:43
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
state
static struct @314 state
header
static const uint8_t header[24]
Definition: sdr2.c:67
line
Definition: graph2dot.c:48
avpriv_fits_header_init
int avpriv_fits_header_init(FITSHeader *header, FITSHeaderState state)
Initialize a single header line.
Definition: fits.c:26
STATE_BITPIX
@ STATE_BITPIX
Definition: fits.h:32
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
STATE_SIMPLE
@ STATE_SIMPLE
Definition: fits.h:30
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
uint8_t
uint8_t
Definition: audio_convert.c:194
avcodec.h
ret
ret
Definition: filter_design.txt:187
dict.h
FITSHeaderState
FITSHeaderState
Definition: fits.h:29
FITSHeader
Structure to store the header keywords in FITS file.
Definition: fits.h:43
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:70
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
STATE_NAXIS_N
@ STATE_NAXIS_N
Definition: fits.h:34
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
STATE_NAXIS
@ STATE_NAXIS
Definition: fits.h:33