LCOV - code coverage report
Current view: top level - libavcodec - sgidec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 105 132 79.5 %
Date: 2017-12-15 11:05:35 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SGI image decoder
       3             :  * Todd Kirby <doubleshot@pacbell.net>
       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             : #include "libavutil/imgutils.h"
      23             : #include "libavutil/avassert.h"
      24             : #include "avcodec.h"
      25             : #include "bytestream.h"
      26             : #include "internal.h"
      27             : #include "sgi.h"
      28             : 
      29             : typedef struct SgiState {
      30             :     AVCodecContext *avctx;
      31             :     unsigned int width;
      32             :     unsigned int height;
      33             :     unsigned int depth;
      34             :     unsigned int bytes_per_channel;
      35             :     int linesize;
      36             :     GetByteContext g;
      37             : } SgiState;
      38             : 
      39             : /**
      40             :  * Expand an RLE row into a channel.
      41             :  * @param s the current image state
      42             :  * @param out_buf Points to one line after the output buffer.
      43             :  * @param len length of out_buf in bytes
      44             :  * @param pixelstride pixel stride of input buffer
      45             :  * @return size of output in bytes, else return error code.
      46             :  */
      47       21152 : static int expand_rle_row8(SgiState *s, uint8_t *out_buf,
      48             :                            int len, int pixelstride)
      49             : {
      50             :     unsigned char pixel, count;
      51       21152 :     unsigned char *orig = out_buf;
      52       21152 :     uint8_t *out_end = out_buf + len;
      53             : 
      54      567573 :     while (out_buf < out_end) {
      55      525269 :         if (bytestream2_get_bytes_left(&s->g) < 1)
      56           0 :             return AVERROR_INVALIDDATA;
      57      525269 :         pixel = bytestream2_get_byteu(&s->g);
      58      525269 :         if (!(count = (pixel & 0x7f))) {
      59           0 :             break;
      60             :         }
      61             : 
      62             :         /* Check for buffer overflow. */
      63      525269 :         if (out_end - out_buf <= pixelstride * (count - 1)) {
      64           0 :             av_log(s->avctx, AV_LOG_ERROR, "Invalid pixel count.\n");
      65           0 :             return AVERROR_INVALIDDATA;
      66             :         }
      67             : 
      68      525269 :         if (pixel & 0x80) {
      69     5072935 :             while (count--) {
      70     4780725 :                 *out_buf = bytestream2_get_byte(&s->g);
      71     4780725 :                 out_buf += pixelstride;
      72             :             }
      73             :         } else {
      74      379164 :             pixel = bytestream2_get_byte(&s->g);
      75             : 
      76     4733827 :             while (count--) {
      77     3975499 :                 *out_buf = pixel;
      78     3975499 :                 out_buf += pixelstride;
      79             :             }
      80             :         }
      81             :     }
      82       21152 :     return (out_buf - orig) / pixelstride;
      83             : }
      84             : 
      85        4096 : static int expand_rle_row16(SgiState *s, uint16_t *out_buf,
      86             :                             int len, int pixelstride)
      87             : {
      88             :     unsigned short pixel;
      89             :     unsigned char count;
      90        4096 :     unsigned short *orig = out_buf;
      91        4096 :     uint16_t *out_end = out_buf + len;
      92             : 
      93      153072 :     while (out_buf < out_end) {
      94      144880 :         if (bytestream2_get_bytes_left(&s->g) < 2)
      95           0 :             return AVERROR_INVALIDDATA;
      96      144880 :         pixel = bytestream2_get_be16u(&s->g);
      97      144880 :         if (!(count = (pixel & 0x7f)))
      98           0 :             break;
      99             : 
     100             :         /* Check for buffer overflow. */
     101      144880 :         if (out_end - out_buf <= pixelstride * (count - 1)) {
     102           0 :             av_log(s->avctx, AV_LOG_ERROR, "Invalid pixel count.\n");
     103           0 :             return AVERROR_INVALIDDATA;
     104             :         }
     105             : 
     106      144880 :         if (pixel & 0x80) {
     107      327348 :             while (count--) {
     108      289372 :                 pixel = bytestream2_get_ne16(&s->g);
     109      289372 :                 AV_WN16A(out_buf, pixel);
     110      289372 :                 out_buf += pixelstride;
     111             :             }
     112             :         } else {
     113      125892 :             pixel = bytestream2_get_ne16(&s->g);
     114             : 
     115     2059564 :             while (count--) {
     116     1807780 :                 AV_WN16A(out_buf, pixel);
     117     1807780 :                 out_buf += pixelstride;
     118             :             }
     119             :         }
     120             :     }
     121        4096 :     return (out_buf - orig) / pixelstride;
     122             : }
     123             : 
     124             : 
     125             : /**
     126             :  * Read a run length encoded SGI image.
     127             :  * @param out_buf output buffer
     128             :  * @param s the current image state
     129             :  * @return 0 if no error, else return error code.
     130             :  */
     131          33 : static int read_rle_sgi(uint8_t *out_buf, SgiState *s)
     132             : {
     133             :     uint8_t *dest_row;
     134          33 :     unsigned int len = s->height * s->depth * 4;
     135          33 :     GetByteContext g_table = s->g;
     136             :     unsigned int y, z;
     137             :     unsigned int start_offset;
     138             :     int linesize, ret;
     139             : 
     140             :     /* size of  RLE offset and length tables */
     141          33 :     if (len * 2 > bytestream2_get_bytes_left(&s->g)) {
     142           0 :         return AVERROR_INVALIDDATA;
     143             :     }
     144             : 
     145         126 :     for (z = 0; z < s->depth; z++) {
     146          93 :         dest_row = out_buf;
     147       25341 :         for (y = 0; y < s->height; y++) {
     148       25248 :             linesize = s->width * s->depth;
     149       25248 :             dest_row -= s->linesize;
     150       25248 :             start_offset = bytestream2_get_be32(&g_table);
     151       25248 :             bytestream2_seek(&s->g, start_offset, SEEK_SET);
     152       25248 :             if (s->bytes_per_channel == 1)
     153       21152 :                 ret = expand_rle_row8(s, dest_row + z, linesize, s->depth);
     154             :             else
     155        4096 :                 ret = expand_rle_row16(s, (uint16_t *)dest_row + z, linesize, s->depth);
     156       25248 :             if (ret != s->width)
     157           0 :                 return AVERROR_INVALIDDATA;
     158             :         }
     159             :     }
     160          33 :     return 0;
     161             : }
     162             : 
     163             : /**
     164             :  * Read an uncompressed SGI image.
     165             :  * @param out_buf output buffer
     166             :  * @param s the current image state
     167             :  * @return 0 if read success, else return error code.
     168             :  */
     169           6 : static int read_uncompressed_sgi(unsigned char *out_buf, SgiState *s)
     170             : {
     171             :     int x, y, z;
     172           6 :     unsigned int offset = s->height * s->width * s->bytes_per_channel;
     173             :     GetByteContext gp[4];
     174             :     uint8_t *out_end;
     175             : 
     176             :     /* Test buffer size. */
     177           6 :     if (offset * s->depth > bytestream2_get_bytes_left(&s->g))
     178           0 :         return AVERROR_INVALIDDATA;
     179             : 
     180             :     /* Create a reader for each plane */
     181          22 :     for (z = 0; z < s->depth; z++) {
     182          16 :         gp[z] = s->g;
     183          16 :         bytestream2_skip(&gp[z], z * offset);
     184             :     }
     185             : 
     186        1542 :     for (y = s->height - 1; y >= 0; y--) {
     187        1536 :         out_end = out_buf + (y * s->linesize);
     188        1536 :         if (s->bytes_per_channel == 1) {
     189           0 :             for (x = s->width; x > 0; x--)
     190           0 :                 for (z = 0; z < s->depth; z++)
     191           0 :                     *out_end++ = bytestream2_get_byteu(&gp[z]);
     192             :         } else {
     193        1536 :             uint16_t *out16 = (uint16_t *)out_end;
     194      787968 :             for (x = s->width; x > 0; x--)
     195     2883584 :                 for (z = 0; z < s->depth; z++)
     196     2097152 :                     *out16++ = bytestream2_get_ne16u(&gp[z]);
     197             :         }
     198             :     }
     199           6 :     return 0;
     200             : }
     201             : 
     202          39 : static int decode_frame(AVCodecContext *avctx,
     203             :                         void *data, int *got_frame,
     204             :                         AVPacket *avpkt)
     205             : {
     206          39 :     SgiState *s = avctx->priv_data;
     207          39 :     AVFrame *p = data;
     208             :     unsigned int dimension, rle;
     209          39 :     int ret = 0;
     210             :     uint8_t *out_buf, *out_end;
     211             : 
     212          39 :     bytestream2_init(&s->g, avpkt->data, avpkt->size);
     213          39 :     if (bytestream2_get_bytes_left(&s->g) < SGI_HEADER_SIZE) {
     214           0 :         av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", avpkt->size);
     215           0 :         return AVERROR_INVALIDDATA;
     216             :     }
     217             : 
     218             :     /* Test for SGI magic. */
     219          39 :     if (bytestream2_get_be16u(&s->g) != SGI_MAGIC) {
     220           0 :         av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
     221           0 :         return AVERROR_INVALIDDATA;
     222             :     }
     223             : 
     224          39 :     rle                  = bytestream2_get_byteu(&s->g);
     225          39 :     s->bytes_per_channel = bytestream2_get_byteu(&s->g);
     226          39 :     dimension            = bytestream2_get_be16u(&s->g);
     227          39 :     s->width             = bytestream2_get_be16u(&s->g);
     228          39 :     s->height            = bytestream2_get_be16u(&s->g);
     229          39 :     s->depth             = bytestream2_get_be16u(&s->g);
     230             : 
     231          39 :     if (s->bytes_per_channel != 1 && s->bytes_per_channel != 2) {
     232           0 :         av_log(avctx, AV_LOG_ERROR, "wrong channel number\n");
     233           0 :         return AVERROR_INVALIDDATA;
     234             :     }
     235             : 
     236             :     /* Check for supported image dimensions. */
     237          39 :     if (dimension != 2 && dimension != 3) {
     238           0 :         av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n");
     239           0 :         return AVERROR_INVALIDDATA;
     240             :     }
     241             : 
     242          39 :     if (s->depth == SGI_GRAYSCALE) {
     243           8 :         avctx->pix_fmt = s->bytes_per_channel == 2 ? AV_PIX_FMT_GRAY16BE : AV_PIX_FMT_GRAY8;
     244          31 :     } else if (s->depth == SGI_RGB) {
     245          23 :         avctx->pix_fmt = s->bytes_per_channel == 2 ? AV_PIX_FMT_RGB48BE : AV_PIX_FMT_RGB24;
     246           8 :     } else if (s->depth == SGI_RGBA) {
     247           8 :         avctx->pix_fmt = s->bytes_per_channel == 2 ? AV_PIX_FMT_RGBA64BE : AV_PIX_FMT_RGBA;
     248             :     } else {
     249           0 :         av_log(avctx, AV_LOG_ERROR, "wrong picture format\n");
     250           0 :         return AVERROR_INVALIDDATA;
     251             :     }
     252             : 
     253          39 :     ret = ff_set_dimensions(avctx, s->width, s->height);
     254          39 :     if (ret < 0)
     255           0 :         return ret;
     256             : 
     257          39 :     if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
     258           0 :         return ret;
     259             : 
     260          39 :     p->pict_type = AV_PICTURE_TYPE_I;
     261          39 :     p->key_frame = 1;
     262          39 :     out_buf = p->data[0];
     263             : 
     264          39 :     out_end = out_buf + p->linesize[0] * s->height;
     265             : 
     266          39 :     s->linesize = p->linesize[0];
     267             : 
     268             :     /* Skip header. */
     269          39 :     bytestream2_seek(&s->g, SGI_HEADER_SIZE, SEEK_SET);
     270          39 :     if (rle) {
     271          33 :         ret = read_rle_sgi(out_end, s);
     272             :     } else {
     273           6 :         ret = read_uncompressed_sgi(out_buf, s);
     274             :     }
     275          39 :     if (ret)
     276           0 :         return ret;
     277             : 
     278          39 :     *got_frame = 1;
     279          39 :     return avpkt->size;
     280             : }
     281             : 
     282          27 : static av_cold int sgi_decode_init(AVCodecContext *avctx)
     283             : {
     284          27 :     SgiState *s = avctx->priv_data;
     285             : 
     286          27 :     s->avctx = avctx;
     287             : 
     288          27 :     return 0;
     289             : }
     290             : 
     291             : AVCodec ff_sgi_decoder = {
     292             :     .name           = "sgi",
     293             :     .long_name      = NULL_IF_CONFIG_SMALL("SGI image"),
     294             :     .type           = AVMEDIA_TYPE_VIDEO,
     295             :     .id             = AV_CODEC_ID_SGI,
     296             :     .priv_data_size = sizeof(SgiState),
     297             :     .decode         = decode_frame,
     298             :     .init           = sgi_decode_init,
     299             :     .capabilities   = AV_CODEC_CAP_DR1,
     300             : };

Generated by: LCOV version 1.13