LCOV - code coverage report
Current view: top level - libavcodec - sgienc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 80 136 58.8 %
Date: 2017-12-11 04:34:20 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * SGI image encoder
       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/opt.h"
      23             : 
      24             : #include "avcodec.h"
      25             : #include "bytestream.h"
      26             : #include "internal.h"
      27             : #include "sgi.h"
      28             : #include "rle.h"
      29             : 
      30             : #define SGI_SINGLE_CHAN 2
      31             : #define SGI_MULTI_CHAN 3
      32             : 
      33             : typedef struct SgiContext {
      34             :     AVClass *class;
      35             : 
      36             :     int rle;
      37             : } SgiContext;
      38             : 
      39           1 : static av_cold int encode_init(AVCodecContext *avctx)
      40             : {
      41           1 :     if (avctx->width > 65535 || avctx->height > 65535) {
      42           0 :         av_log(avctx, AV_LOG_ERROR,
      43             :                "Unsupported resolution %dx%d.\n", avctx->width, avctx->height);
      44           0 :         av_log(avctx, AV_LOG_ERROR, "SGI does not support resolutions above 65535x65535\n");
      45           0 :         return AVERROR_INVALIDDATA;
      46             :     }
      47             : 
      48           1 :     return 0;
      49             : }
      50             : 
      51       11232 : static int sgi_rle_encode(PutByteContext *pbc, const uint8_t *src,
      52             :                           int w, int bpp)
      53             : {
      54       11232 :     int val, count, x, start = bytestream2_tell_p(pbc);
      55             :     void (*bytestream2_put)(PutByteContext *, unsigned int);
      56             : 
      57       11232 :     if (bpp == 1)
      58       11232 :         bytestream2_put = bytestream2_put_byte;
      59             :     else
      60           0 :         bytestream2_put = bytestream2_put_be16;
      61             : 
      62       97313 :     for (x = 0; x < w; x += count) {
      63             :         /* see if we can encode the next set of pixels with RLE */
      64       86081 :         count = ff_rle_count_pixels(src, w - x, bpp, 1);
      65       86081 :         if (count > 1) {
      66       34170 :             if (bytestream2_get_bytes_left_p(pbc) < bpp * 2)
      67           0 :                 return AVERROR_INVALIDDATA;
      68             : 
      69       34170 :             val = bpp == 1 ? *src : AV_RB16(src);
      70       34170 :             bytestream2_put(pbc, count);
      71       34170 :             bytestream2_put(pbc, val);
      72             :         } else {
      73             :             int i;
      74             :             /* fall back on uncompressed */
      75       51911 :             count = ff_rle_count_pixels(src, w - x, bpp, 0);
      76       51911 :             if (bytestream2_get_bytes_left_p(pbc) < bpp * (count + 1))
      77           0 :                 return AVERROR_INVALIDDATA;
      78             : 
      79       51911 :             bytestream2_put(pbc, count + 0x80);
      80     3834780 :             for (i = 0; i < count; i++) {
      81     3782869 :                 val = bpp == 1 ? src[i] : AV_RB16(src + i * bpp);
      82     3782869 :                 bytestream2_put(pbc, val);
      83             :             }
      84             :         }
      85             : 
      86       86081 :         src += count * bpp;
      87             :     }
      88             : 
      89       11232 :     return bytestream2_tell_p(pbc) - start;
      90             : }
      91             : 
      92          13 : static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
      93             :                         const AVFrame *frame, int *got_packet)
      94             : {
      95          13 :     SgiContext *s = avctx->priv_data;
      96          13 :     const AVFrame * const p = frame;
      97             :     PutByteContext pbc;
      98             :     uint8_t *in_buf, *encode_buf;
      99             :     int x, y, z, length, tablesize, ret, i;
     100             :     unsigned int width, height, depth, dimension;
     101             :     unsigned int bytes_per_channel, pixmax, put_be;
     102             : 
     103             : #if FF_API_CODED_FRAME
     104             : FF_DISABLE_DEPRECATION_WARNINGS
     105          13 :     avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
     106          13 :     avctx->coded_frame->key_frame = 1;
     107             : FF_ENABLE_DEPRECATION_WARNINGS
     108             : #endif
     109             : 
     110             : #if FF_API_CODER_TYPE
     111             : FF_DISABLE_DEPRECATION_WARNINGS
     112          13 :     if (avctx->coder_type == FF_CODER_TYPE_RAW)
     113           0 :         s->rle = 0;
     114             : FF_ENABLE_DEPRECATION_WARNINGS
     115             : #endif
     116             : 
     117          13 :     width  = avctx->width;
     118          13 :     height = avctx->height;
     119          13 :     bytes_per_channel = 1;
     120          13 :     pixmax = 0xFF;
     121          13 :     put_be = HAVE_BIGENDIAN;
     122             : 
     123          13 :     switch (avctx->pix_fmt) {
     124           0 :     case AV_PIX_FMT_GRAY8:
     125           0 :         dimension = SGI_SINGLE_CHAN;
     126           0 :         depth     = SGI_GRAYSCALE;
     127           0 :         break;
     128          13 :     case AV_PIX_FMT_RGB24:
     129          13 :         dimension = SGI_MULTI_CHAN;
     130          13 :         depth     = SGI_RGB;
     131          13 :         break;
     132           0 :     case AV_PIX_FMT_RGBA:
     133           0 :         dimension = SGI_MULTI_CHAN;
     134           0 :         depth     = SGI_RGBA;
     135           0 :         break;
     136           0 :     case AV_PIX_FMT_GRAY16LE:
     137           0 :         put_be = !HAVE_BIGENDIAN;
     138           0 :     case AV_PIX_FMT_GRAY16BE:
     139           0 :         bytes_per_channel = 2;
     140           0 :         pixmax = 0xFFFF;
     141           0 :         dimension = SGI_SINGLE_CHAN;
     142           0 :         depth     = SGI_GRAYSCALE;
     143           0 :         break;
     144           0 :     case AV_PIX_FMT_RGB48LE:
     145           0 :         put_be = !HAVE_BIGENDIAN;
     146           0 :     case AV_PIX_FMT_RGB48BE:
     147           0 :         bytes_per_channel = 2;
     148           0 :         pixmax = 0xFFFF;
     149           0 :         dimension = SGI_MULTI_CHAN;
     150           0 :         depth     = SGI_RGB;
     151           0 :         break;
     152           0 :     case AV_PIX_FMT_RGBA64LE:
     153           0 :         put_be = !HAVE_BIGENDIAN;
     154           0 :     case AV_PIX_FMT_RGBA64BE:
     155           0 :         bytes_per_channel = 2;
     156           0 :         pixmax = 0xFFFF;
     157           0 :         dimension = SGI_MULTI_CHAN;
     158           0 :         depth     = SGI_RGBA;
     159           0 :         break;
     160           0 :     default:
     161           0 :         return AVERROR_INVALIDDATA;
     162             :     }
     163             : 
     164          13 :     tablesize = depth * height * 4;
     165          13 :     length = SGI_HEADER_SIZE;
     166          13 :     if (!s->rle)
     167           0 :         length += depth * height * width;
     168             :     else // assume sgi_rle_encode() produces at most 2x size of input
     169          13 :         length += tablesize * 2 + depth * height * (2 * width + 1);
     170             : 
     171          13 :     if ((ret = ff_alloc_packet2(avctx, pkt, bytes_per_channel * length, 0)) < 0)
     172           0 :         return ret;
     173             : 
     174          13 :     bytestream2_init_writer(&pbc, pkt->data, pkt->size);
     175             : 
     176             :     /* Encode header. */
     177          13 :     bytestream2_put_be16(&pbc, SGI_MAGIC);
     178          13 :     bytestream2_put_byte(&pbc, s->rle); /* RLE 1 - VERBATIM 0 */
     179          13 :     bytestream2_put_byte(&pbc, bytes_per_channel);
     180          13 :     bytestream2_put_be16(&pbc, dimension);
     181          13 :     bytestream2_put_be16(&pbc, width);
     182          13 :     bytestream2_put_be16(&pbc, height);
     183          13 :     bytestream2_put_be16(&pbc, depth);
     184             : 
     185          13 :     bytestream2_put_be32(&pbc, 0L); /* pixmin */
     186          13 :     bytestream2_put_be32(&pbc, pixmax);
     187          13 :     bytestream2_put_be32(&pbc, 0L); /* dummy */
     188             : 
     189             :     /* name */
     190        1053 :     for (i = 0; i < 80; i++)
     191        1040 :         bytestream2_put_byte(&pbc, 0L);
     192             : 
     193             :     /* colormap */
     194          13 :     bytestream2_put_be32(&pbc, 0L);
     195             : 
     196             :     /* The rest of the 512 byte header is unused. */
     197        5265 :     for (i = 0; i < 404; i++)
     198        5252 :         bytestream2_put_byte(&pbc, 0L);
     199             : 
     200          13 :     if (s->rle) {
     201             :         PutByteContext taboff_pcb, tablen_pcb;
     202             : 
     203             :         /* Skip RLE offset table. */
     204          13 :         bytestream2_init_writer(&taboff_pcb, pbc.buffer, tablesize);
     205          13 :         bytestream2_skip_p(&pbc, tablesize);
     206             : 
     207             :         /* Skip RLE length table. */
     208          13 :         bytestream2_init_writer(&tablen_pcb, pbc.buffer, tablesize);
     209          13 :         bytestream2_skip_p(&pbc, tablesize);
     210             : 
     211             :         /* Make an intermediate consecutive buffer. */
     212          13 :         if (!(encode_buf = av_malloc(width * bytes_per_channel)))
     213           0 :             return AVERROR(ENOMEM);
     214             : 
     215          52 :         for (z = 0; z < depth; z++) {
     216          39 :             in_buf = p->data[0] + p->linesize[0] * (height - 1) + z * bytes_per_channel;
     217             : 
     218       11271 :             for (y = 0; y < height; y++) {
     219       11232 :                 bytestream2_put_be32(&taboff_pcb, bytestream2_tell_p(&pbc));
     220             : 
     221     3964896 :                 for (x = 0; x < width * bytes_per_channel; x += bytes_per_channel)
     222     3953664 :                     encode_buf[x] = in_buf[depth * x];
     223             : 
     224       11232 :                 length = sgi_rle_encode(&pbc, encode_buf, width,
     225             :                                         bytes_per_channel);
     226       11232 :                 if (length < 1) {
     227           0 :                     av_free(encode_buf);
     228           0 :                     return AVERROR_INVALIDDATA;
     229             :                 }
     230             : 
     231       11232 :                 bytestream2_put_be32(&tablen_pcb, length);
     232       11232 :                 in_buf -= p->linesize[0];
     233             :             }
     234             :         }
     235             : 
     236          13 :         av_free(encode_buf);
     237             :     } else {
     238           0 :         for (z = 0; z < depth; z++) {
     239           0 :             in_buf = p->data[0] + p->linesize[0] * (height - 1) + z * bytes_per_channel;
     240             : 
     241           0 :             for (y = 0; y < height; y++) {
     242           0 :                 for (x = 0; x < width * depth; x += depth)
     243           0 :                     if (bytes_per_channel == 1)
     244           0 :                         bytestream2_put_byte(&pbc, in_buf[x]);
     245             :                     else
     246           0 :                         if (put_be)
     247           0 :                             bytestream2_put_be16(&pbc, ((uint16_t *)in_buf)[x]);
     248             :                         else
     249           0 :                             bytestream2_put_le16(&pbc, ((uint16_t *)in_buf)[x]);
     250             : 
     251           0 :                 in_buf -= p->linesize[0];
     252             :             }
     253             :         }
     254             :     }
     255             : 
     256             :     /* total length */
     257          13 :     pkt->size   = bytestream2_tell_p(&pbc);
     258          13 :     pkt->flags |= AV_PKT_FLAG_KEY;
     259          13 :     *got_packet = 1;
     260             : 
     261          13 :     return 0;
     262             : }
     263             : 
     264             : #define OFFSET(x) offsetof(SgiContext, x)
     265             : #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
     266             : static const AVOption options[] = {
     267             :     { "rle", "Use run-length compression", OFFSET(rle), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
     268             : 
     269             :     { NULL },
     270             : };
     271             : 
     272             : static const AVClass sgi_class = {
     273             :     .class_name = "sgi",
     274             :     .item_name  = av_default_item_name,
     275             :     .option     = options,
     276             :     .version    = LIBAVUTIL_VERSION_INT,
     277             : };
     278             : 
     279             : AVCodec ff_sgi_encoder = {
     280             :     .name      = "sgi",
     281             :     .long_name = NULL_IF_CONFIG_SMALL("SGI image"),
     282             :     .type      = AVMEDIA_TYPE_VIDEO,
     283             :     .id        = AV_CODEC_ID_SGI,
     284             :     .priv_data_size = sizeof(SgiContext),
     285             :     .priv_class = &sgi_class,
     286             :     .init      = encode_init,
     287             :     .encode2   = encode_frame,
     288             :     .pix_fmts  = (const enum AVPixelFormat[]) {
     289             :         AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
     290             :         AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGB48BE,
     291             :         AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_RGBA64BE,
     292             :         AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_GRAY8,
     293             :         AV_PIX_FMT_NONE
     294             :     },
     295             : };

Generated by: LCOV version 1.13