xref: /third_party/ffmpeg/libavformat/fitsdec.c (revision cabdff1a)
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