1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * FITS demuxer 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 demuxer. 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 28cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 29cabdff1aSopenharmony_ci#include "internal.h" 30cabdff1aSopenharmony_ci#include "libavutil/opt.h" 31cabdff1aSopenharmony_ci#include "libavcodec/fits.h" 32cabdff1aSopenharmony_ci#include "libavutil/bprint.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_ci#define FITS_BLOCK_SIZE 2880 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_citypedef struct FITSContext { 37cabdff1aSopenharmony_ci const AVClass *class; 38cabdff1aSopenharmony_ci AVRational framerate; 39cabdff1aSopenharmony_ci int first_image; 40cabdff1aSopenharmony_ci int64_t pts; 41cabdff1aSopenharmony_ci} FITSContext; 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_cistatic int fits_probe(const AVProbeData *p) 44cabdff1aSopenharmony_ci{ 45cabdff1aSopenharmony_ci const uint8_t *b = p->buf; 46cabdff1aSopenharmony_ci if (!memcmp(b, "SIMPLE = T", 30)) 47cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX - 1; 48cabdff1aSopenharmony_ci return 0; 49cabdff1aSopenharmony_ci} 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_cistatic int fits_read_header(AVFormatContext *s) 52cabdff1aSopenharmony_ci{ 53cabdff1aSopenharmony_ci AVStream *st; 54cabdff1aSopenharmony_ci FITSContext * fits = s->priv_data; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 57cabdff1aSopenharmony_ci if (!st) 58cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 61cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_FITS; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, fits->framerate.den, fits->framerate.num); 64cabdff1aSopenharmony_ci fits->pts = 0; 65cabdff1aSopenharmony_ci fits->first_image = 1; 66cabdff1aSopenharmony_ci return 0; 67cabdff1aSopenharmony_ci} 68cabdff1aSopenharmony_ci 69cabdff1aSopenharmony_ci/** 70cabdff1aSopenharmony_ci * Parses header and checks that the current HDU contains image or not 71cabdff1aSopenharmony_ci * It also stores the header in the avbuf and stores the size of data part in data_size 72cabdff1aSopenharmony_ci * @param s pointer to AVFormat Context 73cabdff1aSopenharmony_ci * @param fits pointer to FITSContext 74cabdff1aSopenharmony_ci * @param header pointer to FITSHeader 75cabdff1aSopenharmony_ci * @param avbuf pointer to AVBPrint to store the header 76cabdff1aSopenharmony_ci * @param data_size to store the size of data part 77cabdff1aSopenharmony_ci * @return 1 if image found, 0 if any other extension and AVERROR_INVALIDDATA otherwise 78cabdff1aSopenharmony_ci */ 79cabdff1aSopenharmony_cistatic int64_t is_image(AVFormatContext *s, FITSContext *fits, FITSHeader *header, 80cabdff1aSopenharmony_ci AVBPrint *avbuf, uint64_t *data_size) 81cabdff1aSopenharmony_ci{ 82cabdff1aSopenharmony_ci int i, ret, image = 0; 83cabdff1aSopenharmony_ci char buf[FITS_BLOCK_SIZE] = { 0 }; 84cabdff1aSopenharmony_ci int64_t buf_size = 0, size = 0, t; 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_ci do { 87cabdff1aSopenharmony_ci ret = avio_read(s->pb, buf, FITS_BLOCK_SIZE); 88cabdff1aSopenharmony_ci if (ret < 0) { 89cabdff1aSopenharmony_ci return ret; 90cabdff1aSopenharmony_ci } else if (ret < FITS_BLOCK_SIZE) { 91cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 92cabdff1aSopenharmony_ci } 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_ci av_bprint_append_data(avbuf, buf, FITS_BLOCK_SIZE); 95cabdff1aSopenharmony_ci ret = 0; 96cabdff1aSopenharmony_ci buf_size = 0; 97cabdff1aSopenharmony_ci while(!ret && buf_size < FITS_BLOCK_SIZE) { 98cabdff1aSopenharmony_ci ret = avpriv_fits_header_parse_line(s, header, buf + buf_size, NULL); 99cabdff1aSopenharmony_ci buf_size += 80; 100cabdff1aSopenharmony_ci } 101cabdff1aSopenharmony_ci } while (!ret); 102cabdff1aSopenharmony_ci if (ret < 0) 103cabdff1aSopenharmony_ci return ret; 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci image = fits->first_image || header->image_extension; 106cabdff1aSopenharmony_ci fits->first_image = 0; 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci if (header->groups) { 109cabdff1aSopenharmony_ci image = 0; 110cabdff1aSopenharmony_ci if (header->naxis > 1) 111cabdff1aSopenharmony_ci size = 1; 112cabdff1aSopenharmony_ci } else if (header->naxis) { 113cabdff1aSopenharmony_ci size = header->naxisn[0]; 114cabdff1aSopenharmony_ci } else { 115cabdff1aSopenharmony_ci image = 0; 116cabdff1aSopenharmony_ci } 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci for (i = 1; i < header->naxis; i++) { 119cabdff1aSopenharmony_ci if(size && header->naxisn[i] > UINT64_MAX / size) 120cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 121cabdff1aSopenharmony_ci size *= header->naxisn[i]; 122cabdff1aSopenharmony_ci } 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci if(header->pcount > UINT64_MAX - size) 125cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 126cabdff1aSopenharmony_ci size += header->pcount; 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci t = (abs(header->bitpix) >> 3) * ((int64_t) header->gcount); 129cabdff1aSopenharmony_ci if(size && t > INT64_MAX / size) 130cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 131cabdff1aSopenharmony_ci size *= t; 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci if (!size) { 134cabdff1aSopenharmony_ci image = 0; 135cabdff1aSopenharmony_ci } else { 136cabdff1aSopenharmony_ci if(FITS_BLOCK_SIZE - 1 > INT64_MAX - size) 137cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 138cabdff1aSopenharmony_ci size = ((size + FITS_BLOCK_SIZE - 1) / FITS_BLOCK_SIZE) * FITS_BLOCK_SIZE; 139cabdff1aSopenharmony_ci } 140cabdff1aSopenharmony_ci *data_size = size; 141cabdff1aSopenharmony_ci return image; 142cabdff1aSopenharmony_ci} 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_cistatic int fits_read_packet(AVFormatContext *s, AVPacket *pkt) 145cabdff1aSopenharmony_ci{ 146cabdff1aSopenharmony_ci int64_t pos, ret; 147cabdff1aSopenharmony_ci uint64_t size; 148cabdff1aSopenharmony_ci FITSContext *fits = s->priv_data; 149cabdff1aSopenharmony_ci FITSHeader header; 150cabdff1aSopenharmony_ci AVBPrint avbuf; 151cabdff1aSopenharmony_ci char *buf; 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci if (fits->first_image) { 154cabdff1aSopenharmony_ci avpriv_fits_header_init(&header, STATE_SIMPLE); 155cabdff1aSopenharmony_ci } else { 156cabdff1aSopenharmony_ci avpriv_fits_header_init(&header, STATE_XTENSION); 157cabdff1aSopenharmony_ci } 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_ci av_bprint_init(&avbuf, FITS_BLOCK_SIZE, AV_BPRINT_SIZE_UNLIMITED); 160cabdff1aSopenharmony_ci while ((ret = is_image(s, fits, &header, &avbuf, &size)) == 0) { 161cabdff1aSopenharmony_ci av_bprint_finalize(&avbuf, NULL); 162cabdff1aSopenharmony_ci pos = avio_skip(s->pb, size); 163cabdff1aSopenharmony_ci if (pos < 0) 164cabdff1aSopenharmony_ci return pos; 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci av_bprint_init(&avbuf, FITS_BLOCK_SIZE, AV_BPRINT_SIZE_UNLIMITED); 167cabdff1aSopenharmony_ci avpriv_fits_header_init(&header, STATE_XTENSION); 168cabdff1aSopenharmony_ci } 169cabdff1aSopenharmony_ci if (ret < 0) 170cabdff1aSopenharmony_ci goto fail; 171cabdff1aSopenharmony_ci 172cabdff1aSopenharmony_ci if (!av_bprint_is_complete(&avbuf)) { 173cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 174cabdff1aSopenharmony_ci goto fail; 175cabdff1aSopenharmony_ci } 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci av_assert0(avbuf.len <= INT64_MAX && size <= INT64_MAX); 178cabdff1aSopenharmony_ci if (avbuf.len + size > INT_MAX - 80) { 179cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 180cabdff1aSopenharmony_ci goto fail; 181cabdff1aSopenharmony_ci } 182cabdff1aSopenharmony_ci // Header is sent with the first line removed... 183cabdff1aSopenharmony_ci ret = av_new_packet(pkt, avbuf.len - 80 + size); 184cabdff1aSopenharmony_ci if (ret < 0) 185cabdff1aSopenharmony_ci goto fail; 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci pkt->stream_index = 0; 188cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci ret = av_bprint_finalize(&avbuf, &buf); 191cabdff1aSopenharmony_ci if (ret < 0) { 192cabdff1aSopenharmony_ci return ret; 193cabdff1aSopenharmony_ci } 194cabdff1aSopenharmony_ci 195cabdff1aSopenharmony_ci memcpy(pkt->data, buf + 80, avbuf.len - 80); 196cabdff1aSopenharmony_ci pkt->size = avbuf.len - 80; 197cabdff1aSopenharmony_ci av_freep(&buf); 198cabdff1aSopenharmony_ci ret = avio_read(s->pb, pkt->data + pkt->size, size); 199cabdff1aSopenharmony_ci if (ret < 0) { 200cabdff1aSopenharmony_ci return ret; 201cabdff1aSopenharmony_ci } 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci pkt->size += ret; 204cabdff1aSopenharmony_ci pkt->pts = fits->pts; 205cabdff1aSopenharmony_ci fits->pts++; 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci return 0; 208cabdff1aSopenharmony_ci 209cabdff1aSopenharmony_cifail: 210cabdff1aSopenharmony_ci av_bprint_finalize(&avbuf, NULL); 211cabdff1aSopenharmony_ci return ret; 212cabdff1aSopenharmony_ci} 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_cistatic const AVOption fits_options[] = { 215cabdff1aSopenharmony_ci { "framerate", "set the framerate", offsetof(FITSContext, framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "1"}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM}, 216cabdff1aSopenharmony_ci { NULL }, 217cabdff1aSopenharmony_ci}; 218cabdff1aSopenharmony_ci 219cabdff1aSopenharmony_cistatic const AVClass fits_demuxer_class = { 220cabdff1aSopenharmony_ci .class_name = "FITS demuxer", 221cabdff1aSopenharmony_ci .item_name = av_default_item_name, 222cabdff1aSopenharmony_ci .option = fits_options, 223cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 224cabdff1aSopenharmony_ci}; 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ciconst AVInputFormat ff_fits_demuxer = { 227cabdff1aSopenharmony_ci .name = "fits", 228cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Flexible Image Transport System"), 229cabdff1aSopenharmony_ci .priv_data_size = sizeof(FITSContext), 230cabdff1aSopenharmony_ci .read_probe = fits_probe, 231cabdff1aSopenharmony_ci .read_header = fits_read_header, 232cabdff1aSopenharmony_ci .read_packet = fits_read_packet, 233cabdff1aSopenharmony_ci .priv_class = &fits_demuxer_class, 234cabdff1aSopenharmony_ci .raw_codec_id = AV_CODEC_ID_FITS, 235cabdff1aSopenharmony_ci}; 236