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); \
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  header->bscale = d;
191  } else if (!strcmp(keyword, "BZERO") && sscanf(value, "%lf", &d) == 1) {
192  header->bzero = d;
193  } else if (!strcmp(keyword, "CTYPE3") && !strncmp(value, "'RGB", 4)) {
194  header->rgb = 1;
195  } else if (!strcmp(keyword, "DATAMAX") && sscanf(value, "%lf", &d) == 1) {
196  header->data_max_found = 1;
197  header->data_max = d;
198  } else if (!strcmp(keyword, "DATAMIN") && sscanf(value, "%lf", &d) == 1) {
199  header->data_min_found = 1;
200  header->data_min = d;
201  } else if (!strcmp(keyword, "END")) {
202  return 1;
203  } else if (!strcmp(keyword, "GROUPS") && sscanf(value, "%c", &c) == 1) {
204  header->groups = (c == 'T');
205  } else if (!strcmp(keyword, "GCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) {
206  header->gcount = t;
207  } else if (!strcmp(keyword, "PCOUNT") && sscanf(value, "%"SCNd64"", &t) == 1) {
208  header->pcount = t;
209  }
210  dict_set_if_not_null(metadata, keyword, value);
211  break;
212  }
213  return 0;
214 }
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int rgb
1 if file contains RGB image, 0 otherwise
Definition: fits.h:54
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
double data_max
Definition: fits.h:61
int image_extension
Definition: fits.h:55
FITSHeaderState
Definition: fits.h:29
double bscale
Definition: fits.h:56
Public dictionary API.
static int dict_set_if_not_null(AVDictionary ***metadata, char *keyword, char *value)
Definition: fits.c:43
FITSHeaderState state
Definition: fits.h:44
uint8_t
int naxis
Definition: fits.h:49
double bzero
Definition: fits.h:57
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
GLsizei GLboolean const GLfloat * value
Definition: opengl_enc.c:108
#define CHECK_KEYWORD(key)
Definition: fits.c:96
static const uint8_t header[24]
Definition: sdr2.c:67
#define av_log(a,...)
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
Structure to store the header keywords in FITS file.
Definition: fits.h:43
Definition: graph2dot.c:48
int data_min_found
Definition: fits.h:58
double data_min
Definition: fits.h:59
int avpriv_fits_header_init(FITSHeader *header, FITSHeaderState state)
Initialize a single header line.
Definition: fits.c:26
int bitpix
Definition: fits.h:46
Libavcodec external API header.
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
int naxisn[999]
Definition: fits.h:50
unsigned naxis_index
Definition: fits.h:45
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
int pcount
Definition: fits.h:51
int64_t blank
Definition: fits.h:47
#define CHECK_VALUE(key, val)
Definition: fits.c:102
int data_max_found
Definition: fits.h:60
static struct @316 state
int groups
Definition: fits.h:53
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a it should return
int gcount
Definition: fits.h:52
int blank_found
Definition: fits.h:48
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