• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * FITS muxer
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 /**
23  * @file
24  * FITS muxer.
25  */
26 
27 #include "avio_internal.h"
28 #include "internal.h"
29 
30 typedef struct FITSContext {
31     int first_image;
32 } FITSContext;
33 
fits_write_header(AVFormatContext * s)34 static int fits_write_header(AVFormatContext *s)
35 {
36     FITSContext *fitsctx = s->priv_data;
37     fitsctx->first_image = 1;
38     return 0;
39 }
40 
41 /**
42  * Write one header line comprising of keyword and value(int)
43  * @param s AVFormat Context
44  * @param keyword pointer to the char array in which keyword is stored
45  * @param value the value corresponding to the keyword
46  * @param lines_written to keep track of lines written so far
47  * @return 0
48  */
write_keyword_value(AVFormatContext * s,const char * fmt,const char * keyword,void * value,int * lines_written)49 static int write_keyword_value(AVFormatContext *s, const char *fmt,
50                                const char *keyword, void *value, int *lines_written)
51 {
52     int len, ret;
53     uint8_t header[80];
54 
55     len = strlen(keyword);
56     memset(header, ' ', sizeof(header));
57     memcpy(header, keyword, len);
58 
59     header[8] = '=';
60     header[9] = ' ';
61 
62     if (!strcmp(fmt, "%d")) {
63         ret = snprintf(header + 10, 70, fmt, *(int *)value);
64     } else {
65         ret = snprintf(header + 10, 70, fmt, *(float *)value);
66     }
67 
68     memset(&header[ret + 10], ' ', sizeof(header) - (ret + 10));
69 
70     avio_write(s->pb, header, sizeof(header));
71     *lines_written += 1;
72     return 0;
73 }
74 
write_image_header(AVFormatContext * s)75 static int write_image_header(AVFormatContext *s)
76 {
77     AVStream *st = s->streams[0];
78     AVCodecParameters *encctx = st->codecpar;
79     FITSContext *fitsctx = s->priv_data;
80     uint8_t buffer[80];
81     int bitpix, naxis, naxis3 = 1, bzero = 0, rgb = 0, lines_written = 0, lines_left;
82     int pcount = 0, gcount = 1;
83     float datamax, datamin;
84 
85     switch (encctx->format) {
86         case AV_PIX_FMT_GRAY8:
87             bitpix = 8;
88             naxis = 2;
89             datamin = 0;
90             datamax = 255;
91             break;
92         case AV_PIX_FMT_GRAY16BE:
93             bitpix = 16;
94             naxis = 2;
95             bzero = 32768;
96             datamin = 0;
97             datamax = 65535;
98             break;
99         case AV_PIX_FMT_GBRP:
100         case AV_PIX_FMT_GBRAP:
101             bitpix = 8;
102             naxis = 3;
103             rgb = 1;
104             if (encctx->format == AV_PIX_FMT_GBRP) {
105                 naxis3 = 3;
106             } else {
107                 naxis3 = 4;
108             }
109             datamin = 0;
110             datamax = 255;
111             break;
112         case AV_PIX_FMT_GBRP16BE:
113         case AV_PIX_FMT_GBRAP16BE:
114             bitpix = 16;
115             naxis = 3;
116             rgb = 1;
117             if (encctx->format == AV_PIX_FMT_GBRP16BE) {
118                 naxis3 = 3;
119             } else {
120                 naxis3 = 4;
121             }
122             bzero = 32768;
123             datamin = 0;
124             datamax = 65535;
125             break;
126         default:
127             return AVERROR(EINVAL);
128     }
129 
130     if (fitsctx->first_image) {
131         memcpy(buffer, "SIMPLE  = ", 10);
132         memset(buffer + 10, ' ', 70);
133         buffer[29] = 'T';
134         avio_write(s->pb, buffer, sizeof(buffer));
135     } else {
136         memcpy(buffer, "XTENSION= 'IMAGE   '", 20);
137         memset(buffer + 20, ' ', 60);
138         avio_write(s->pb, buffer, sizeof(buffer));
139     }
140     lines_written++;
141 
142     write_keyword_value(s, "%d", "BITPIX", &bitpix, &lines_written);         // no of bits per pixel
143     write_keyword_value(s, "%d", "NAXIS", &naxis, &lines_written);           // no of dimensions of image
144     write_keyword_value(s, "%d", "NAXIS1", &encctx->width, &lines_written);   // first dimension i.e. width
145     write_keyword_value(s, "%d", "NAXIS2", &encctx->height, &lines_written);  // second dimension i.e. height
146 
147     if (rgb)
148         write_keyword_value(s, "%d", "NAXIS3", &naxis3, &lines_written);     // third dimension to store RGBA planes
149 
150     if (!fitsctx->first_image) {
151         write_keyword_value(s, "%d", "PCOUNT", &pcount, &lines_written);
152         write_keyword_value(s, "%d", "GCOUNT", &gcount, &lines_written);
153     } else {
154         fitsctx->first_image = 0;
155     }
156 
157     write_keyword_value(s, "%g", "DATAMIN", &datamin, &lines_written);
158     write_keyword_value(s, "%g", "DATAMAX", &datamax, &lines_written);
159 
160     /*
161      * Since FITS does not support unsigned 16 bit integers,
162      * BZERO = 32768 is used to store unsigned 16 bit integers as
163      * signed integers so that it can be read properly.
164      */
165     if (bitpix == 16)
166         write_keyword_value(s, "%d", "BZERO", &bzero, &lines_written);
167 
168     if (rgb) {
169         memcpy(buffer, "CTYPE3  = 'RGB     '", 20);
170         memset(buffer + 20, ' ', 60);
171         avio_write(s->pb, buffer, sizeof(buffer));
172         lines_written++;
173     }
174 
175     memcpy(buffer, "END", 3);
176     memset(buffer + 3, ' ', 77);
177     avio_write(s->pb, buffer, sizeof(buffer));
178     lines_written++;
179 
180     lines_left = ((lines_written + 35) / 36) * 36 - lines_written;
181     ffio_fill(s->pb, ' ', sizeof(buffer) * lines_left);
182     return 0;
183 }
184 
fits_write_packet(AVFormatContext * s,AVPacket * pkt)185 static int fits_write_packet(AVFormatContext *s, AVPacket *pkt)
186 {
187     int ret = write_image_header(s);
188     if (ret < 0)
189         return ret;
190     avio_write(s->pb, pkt->data, pkt->size);
191     return 0;
192 }
193 
194 const AVOutputFormat ff_fits_muxer = {
195     .name         = "fits",
196     .long_name    = NULL_IF_CONFIG_SMALL("Flexible Image Transport System"),
197     .extensions   = "fits",
198     .priv_data_size = sizeof(FITSContext),
199     .audio_codec  = AV_CODEC_ID_NONE,
200     .video_codec  = AV_CODEC_ID_FITS,
201     .write_header = fits_write_header,
202     .write_packet = fits_write_packet,
203 };
204