1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * FITS muxer 3cabdff1aSopenharmony_ci * Copyright (c) 2017 Paras Chadha 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * FITS muxer. 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "avio_internal.h" 28cabdff1aSopenharmony_ci#include "internal.h" 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_citypedef struct FITSContext { 31cabdff1aSopenharmony_ci int first_image; 32cabdff1aSopenharmony_ci} FITSContext; 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_cistatic int fits_write_header(AVFormatContext *s) 35cabdff1aSopenharmony_ci{ 36cabdff1aSopenharmony_ci FITSContext *fitsctx = s->priv_data; 37cabdff1aSopenharmony_ci fitsctx->first_image = 1; 38cabdff1aSopenharmony_ci return 0; 39cabdff1aSopenharmony_ci} 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci/** 42cabdff1aSopenharmony_ci * Write one header line comprising of keyword and value(int) 43cabdff1aSopenharmony_ci * @param s AVFormat Context 44cabdff1aSopenharmony_ci * @param keyword pointer to the char array in which keyword is stored 45cabdff1aSopenharmony_ci * @param value the value corresponding to the keyword 46cabdff1aSopenharmony_ci * @param lines_written to keep track of lines written so far 47cabdff1aSopenharmony_ci * @return 0 48cabdff1aSopenharmony_ci */ 49cabdff1aSopenharmony_cistatic int write_keyword_value(AVFormatContext *s, const char *fmt, 50cabdff1aSopenharmony_ci const char *keyword, void *value, int *lines_written) 51cabdff1aSopenharmony_ci{ 52cabdff1aSopenharmony_ci int len, ret; 53cabdff1aSopenharmony_ci uint8_t header[80]; 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_ci len = strlen(keyword); 56cabdff1aSopenharmony_ci memset(header, ' ', sizeof(header)); 57cabdff1aSopenharmony_ci memcpy(header, keyword, len); 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_ci header[8] = '='; 60cabdff1aSopenharmony_ci header[9] = ' '; 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci if (!strcmp(fmt, "%d")) { 63cabdff1aSopenharmony_ci ret = snprintf(header + 10, 70, fmt, *(int *)value); 64cabdff1aSopenharmony_ci } else { 65cabdff1aSopenharmony_ci ret = snprintf(header + 10, 70, fmt, *(float *)value); 66cabdff1aSopenharmony_ci } 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci memset(&header[ret + 10], ' ', sizeof(header) - (ret + 10)); 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci avio_write(s->pb, header, sizeof(header)); 71cabdff1aSopenharmony_ci *lines_written += 1; 72cabdff1aSopenharmony_ci return 0; 73cabdff1aSopenharmony_ci} 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_cistatic int write_image_header(AVFormatContext *s) 76cabdff1aSopenharmony_ci{ 77cabdff1aSopenharmony_ci AVStream *st = s->streams[0]; 78cabdff1aSopenharmony_ci AVCodecParameters *encctx = st->codecpar; 79cabdff1aSopenharmony_ci FITSContext *fitsctx = s->priv_data; 80cabdff1aSopenharmony_ci uint8_t buffer[80]; 81cabdff1aSopenharmony_ci int bitpix, naxis, naxis3 = 1, bzero = 0, rgb = 0, lines_written = 0, lines_left; 82cabdff1aSopenharmony_ci int pcount = 0, gcount = 1; 83cabdff1aSopenharmony_ci float datamax, datamin; 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_ci switch (encctx->format) { 86cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY8: 87cabdff1aSopenharmony_ci bitpix = 8; 88cabdff1aSopenharmony_ci naxis = 2; 89cabdff1aSopenharmony_ci datamin = 0; 90cabdff1aSopenharmony_ci datamax = 255; 91cabdff1aSopenharmony_ci break; 92cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY16BE: 93cabdff1aSopenharmony_ci bitpix = 16; 94cabdff1aSopenharmony_ci naxis = 2; 95cabdff1aSopenharmony_ci bzero = 32768; 96cabdff1aSopenharmony_ci datamin = 0; 97cabdff1aSopenharmony_ci datamax = 65535; 98cabdff1aSopenharmony_ci break; 99cabdff1aSopenharmony_ci case AV_PIX_FMT_GBRP: 100cabdff1aSopenharmony_ci case AV_PIX_FMT_GBRAP: 101cabdff1aSopenharmony_ci bitpix = 8; 102cabdff1aSopenharmony_ci naxis = 3; 103cabdff1aSopenharmony_ci rgb = 1; 104cabdff1aSopenharmony_ci if (encctx->format == AV_PIX_FMT_GBRP) { 105cabdff1aSopenharmony_ci naxis3 = 3; 106cabdff1aSopenharmony_ci } else { 107cabdff1aSopenharmony_ci naxis3 = 4; 108cabdff1aSopenharmony_ci } 109cabdff1aSopenharmony_ci datamin = 0; 110cabdff1aSopenharmony_ci datamax = 255; 111cabdff1aSopenharmony_ci break; 112cabdff1aSopenharmony_ci case AV_PIX_FMT_GBRP16BE: 113cabdff1aSopenharmony_ci case AV_PIX_FMT_GBRAP16BE: 114cabdff1aSopenharmony_ci bitpix = 16; 115cabdff1aSopenharmony_ci naxis = 3; 116cabdff1aSopenharmony_ci rgb = 1; 117cabdff1aSopenharmony_ci if (encctx->format == AV_PIX_FMT_GBRP16BE) { 118cabdff1aSopenharmony_ci naxis3 = 3; 119cabdff1aSopenharmony_ci } else { 120cabdff1aSopenharmony_ci naxis3 = 4; 121cabdff1aSopenharmony_ci } 122cabdff1aSopenharmony_ci bzero = 32768; 123cabdff1aSopenharmony_ci datamin = 0; 124cabdff1aSopenharmony_ci datamax = 65535; 125cabdff1aSopenharmony_ci break; 126cabdff1aSopenharmony_ci default: 127cabdff1aSopenharmony_ci return AVERROR(EINVAL); 128cabdff1aSopenharmony_ci } 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_ci if (fitsctx->first_image) { 131cabdff1aSopenharmony_ci memcpy(buffer, "SIMPLE = ", 10); 132cabdff1aSopenharmony_ci memset(buffer + 10, ' ', 70); 133cabdff1aSopenharmony_ci buffer[29] = 'T'; 134cabdff1aSopenharmony_ci avio_write(s->pb, buffer, sizeof(buffer)); 135cabdff1aSopenharmony_ci } else { 136cabdff1aSopenharmony_ci memcpy(buffer, "XTENSION= 'IMAGE '", 20); 137cabdff1aSopenharmony_ci memset(buffer + 20, ' ', 60); 138cabdff1aSopenharmony_ci avio_write(s->pb, buffer, sizeof(buffer)); 139cabdff1aSopenharmony_ci } 140cabdff1aSopenharmony_ci lines_written++; 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci write_keyword_value(s, "%d", "BITPIX", &bitpix, &lines_written); // no of bits per pixel 143cabdff1aSopenharmony_ci write_keyword_value(s, "%d", "NAXIS", &naxis, &lines_written); // no of dimensions of image 144cabdff1aSopenharmony_ci write_keyword_value(s, "%d", "NAXIS1", &encctx->width, &lines_written); // first dimension i.e. width 145cabdff1aSopenharmony_ci write_keyword_value(s, "%d", "NAXIS2", &encctx->height, &lines_written); // second dimension i.e. height 146cabdff1aSopenharmony_ci 147cabdff1aSopenharmony_ci if (rgb) 148cabdff1aSopenharmony_ci write_keyword_value(s, "%d", "NAXIS3", &naxis3, &lines_written); // third dimension to store RGBA planes 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci if (!fitsctx->first_image) { 151cabdff1aSopenharmony_ci write_keyword_value(s, "%d", "PCOUNT", &pcount, &lines_written); 152cabdff1aSopenharmony_ci write_keyword_value(s, "%d", "GCOUNT", &gcount, &lines_written); 153cabdff1aSopenharmony_ci } else { 154cabdff1aSopenharmony_ci fitsctx->first_image = 0; 155cabdff1aSopenharmony_ci } 156cabdff1aSopenharmony_ci 157cabdff1aSopenharmony_ci write_keyword_value(s, "%g", "DATAMIN", &datamin, &lines_written); 158cabdff1aSopenharmony_ci write_keyword_value(s, "%g", "DATAMAX", &datamax, &lines_written); 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci /* 161cabdff1aSopenharmony_ci * Since FITS does not support unsigned 16 bit integers, 162cabdff1aSopenharmony_ci * BZERO = 32768 is used to store unsigned 16 bit integers as 163cabdff1aSopenharmony_ci * signed integers so that it can be read properly. 164cabdff1aSopenharmony_ci */ 165cabdff1aSopenharmony_ci if (bitpix == 16) 166cabdff1aSopenharmony_ci write_keyword_value(s, "%d", "BZERO", &bzero, &lines_written); 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci if (rgb) { 169cabdff1aSopenharmony_ci memcpy(buffer, "CTYPE3 = 'RGB '", 20); 170cabdff1aSopenharmony_ci memset(buffer + 20, ' ', 60); 171cabdff1aSopenharmony_ci avio_write(s->pb, buffer, sizeof(buffer)); 172cabdff1aSopenharmony_ci lines_written++; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci memcpy(buffer, "END", 3); 176cabdff1aSopenharmony_ci memset(buffer + 3, ' ', 77); 177cabdff1aSopenharmony_ci avio_write(s->pb, buffer, sizeof(buffer)); 178cabdff1aSopenharmony_ci lines_written++; 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci lines_left = ((lines_written + 35) / 36) * 36 - lines_written; 181cabdff1aSopenharmony_ci ffio_fill(s->pb, ' ', sizeof(buffer) * lines_left); 182cabdff1aSopenharmony_ci return 0; 183cabdff1aSopenharmony_ci} 184cabdff1aSopenharmony_ci 185cabdff1aSopenharmony_cistatic int fits_write_packet(AVFormatContext *s, AVPacket *pkt) 186cabdff1aSopenharmony_ci{ 187cabdff1aSopenharmony_ci int ret = write_image_header(s); 188cabdff1aSopenharmony_ci if (ret < 0) 189cabdff1aSopenharmony_ci return ret; 190cabdff1aSopenharmony_ci avio_write(s->pb, pkt->data, pkt->size); 191cabdff1aSopenharmony_ci return 0; 192cabdff1aSopenharmony_ci} 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ciconst AVOutputFormat ff_fits_muxer = { 195cabdff1aSopenharmony_ci .name = "fits", 196cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Flexible Image Transport System"), 197cabdff1aSopenharmony_ci .extensions = "fits", 198cabdff1aSopenharmony_ci .priv_data_size = sizeof(FITSContext), 199cabdff1aSopenharmony_ci .audio_codec = AV_CODEC_ID_NONE, 200cabdff1aSopenharmony_ci .video_codec = AV_CODEC_ID_FITS, 201cabdff1aSopenharmony_ci .write_header = fits_write_header, 202cabdff1aSopenharmony_ci .write_packet = fits_write_packet, 203cabdff1aSopenharmony_ci}; 204