LCOV - code coverage report
Current view: top level - libavformat - fitsdec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 82 102 80.4 %
Date: 2017-12-17 16:07:53 Functions: 4 4 100.0 %

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

Generated by: LCOV version 1.13