LCOV - code coverage report
Current view: top level - libavcodec - pictordec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 89 146 61.0 %
Date: 2017-12-16 01:21:47 Functions: 2 3 66.7 %

          Line data    Source code
       1             : /*
       2             :  * Pictor/PC Paint decoder
       3             :  * Copyright (c) 2010 Peter Ross <pross@xvid.org>
       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             :  * Pictor/PC Paint decoder
      25             :  */
      26             : 
      27             : #include "libavutil/imgutils.h"
      28             : #include "avcodec.h"
      29             : #include "bytestream.h"
      30             : #include "cga_data.h"
      31             : #include "internal.h"
      32             : 
      33             : typedef struct PicContext {
      34             :     int width, height;
      35             :     int nb_planes;
      36             :     GetByteContext g;
      37             : } PicContext;
      38             : 
      39           0 : static void picmemset_8bpp(PicContext *s, AVFrame *frame, int value, int run,
      40             :                            int *x, int *y)
      41             : {
      42           0 :     while (run > 0) {
      43           0 :         uint8_t *d = frame->data[0] + *y * frame->linesize[0];
      44           0 :         if (*x + run >= s->width) {
      45           0 :             int n = s->width - *x;
      46           0 :             memset(d + *x, value, n);
      47           0 :             run -= n;
      48           0 :             *x = 0;
      49           0 :             *y -= 1;
      50           0 :             if (*y < 0)
      51           0 :                 break;
      52             :         } else {
      53           0 :             memset(d + *x, value, run);
      54           0 :             *x += run;
      55           0 :             break;
      56             :         }
      57             :     }
      58           0 : }
      59             : 
      60       46974 : static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run,
      61             :                       int *x, int *y, int *plane, int bits_per_plane)
      62             : {
      63             :     uint8_t *d;
      64       46974 :     int shift = *plane * bits_per_plane;
      65       46974 :     unsigned mask  = ((1U << bits_per_plane) - 1) << shift;
      66       46974 :     value   <<= shift;
      67             : 
      68      158218 :     while (run > 0) {
      69             :         int j;
      70      578446 :         for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
      71      514176 :             d = frame->data[0] + *y * frame->linesize[0];
      72      514176 :             d[*x] |= (value >> j) & mask;
      73      514176 :             *x += 1;
      74      514176 :             if (*x == s->width) {
      75        1648 :                 *y -= 1;
      76        1648 :                 *x = 0;
      77        1648 :                 if (*y < 0) {
      78           8 :                    *y = s->height - 1;
      79           8 :                    *plane += 1;
      80           8 :                    if (*plane >= s->nb_planes)
      81           2 :                        return;
      82           6 :                    value <<= bits_per_plane;
      83           6 :                    mask  <<= bits_per_plane;
      84             :                 }
      85             :             }
      86             :         }
      87       64270 :         run--;
      88             :     }
      89             : }
      90             : 
      91             : static const uint8_t cga_mode45_index[6][4] = {
      92             :     [0] = { 0, 3,  5,   7 }, // mode4, palette#1, low intensity
      93             :     [1] = { 0, 2,  4,   6 }, // mode4, palette#2, low intensity
      94             :     [2] = { 0, 3,  4,   7 }, // mode5, low intensity
      95             :     [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
      96             :     [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
      97             :     [5] = { 0, 11, 12, 15 }, // mode5, high intensity
      98             : };
      99             : 
     100           2 : static int decode_frame(AVCodecContext *avctx,
     101             :                         void *data, int *got_frame,
     102             :                         AVPacket *avpkt)
     103             : {
     104           2 :     PicContext *s = avctx->priv_data;
     105           2 :     AVFrame *frame = data;
     106             :     uint32_t *palette;
     107             :     int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
     108             :     int i, x, y, plane, tmp, ret, val;
     109             : 
     110           2 :     bytestream2_init(&s->g, avpkt->data, avpkt->size);
     111             : 
     112           2 :     if (bytestream2_get_bytes_left(&s->g) < 11)
     113           0 :         return AVERROR_INVALIDDATA;
     114             : 
     115           2 :     if (bytestream2_get_le16u(&s->g) != 0x1234)
     116           0 :         return AVERROR_INVALIDDATA;
     117             : 
     118           2 :     s->width       = bytestream2_get_le16u(&s->g);
     119           2 :     s->height      = bytestream2_get_le16u(&s->g);
     120           2 :     bytestream2_skip(&s->g, 4);
     121           2 :     tmp            = bytestream2_get_byteu(&s->g);
     122           2 :     bits_per_plane = tmp & 0xF;
     123           2 :     s->nb_planes   = (tmp >> 4) + 1;
     124           2 :     bpp            = bits_per_plane * s->nb_planes;
     125           2 :     if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
     126           0 :         avpriv_request_sample(avctx, "Unsupported bit depth");
     127           0 :         return AVERROR_PATCHWELCOME;
     128             :     }
     129             : 
     130           2 :     if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 1 || bpp == 4 || bpp == 8) {
     131           2 :         bytestream2_skip(&s->g, 2);
     132           2 :         etype = bytestream2_get_le16(&s->g);
     133           2 :         esize = bytestream2_get_le16(&s->g);
     134           4 :         if (bytestream2_get_bytes_left(&s->g) < esize)
     135           0 :             return AVERROR_INVALIDDATA;
     136             :     } else {
     137           0 :         etype = -1;
     138           0 :         esize = 0;
     139             :     }
     140             : 
     141           2 :     avctx->pix_fmt = AV_PIX_FMT_PAL8;
     142             : 
     143           2 :     if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
     144           0 :         return -1;
     145           2 :     if (s->width != avctx->width || s->height != avctx->height) {
     146           1 :         ret = ff_set_dimensions(avctx, s->width, s->height);
     147           1 :         if (ret < 0)
     148           0 :             return ret;
     149             :     }
     150             : 
     151           2 :     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
     152           0 :         return ret;
     153           2 :     memset(frame->data[0], 0, s->height * frame->linesize[0]);
     154           2 :     frame->pict_type           = AV_PICTURE_TYPE_I;
     155           2 :     frame->palette_has_changed = 1;
     156             : 
     157           2 :     pos_after_pal = bytestream2_tell(&s->g) + esize;
     158           2 :     palette = (uint32_t*)frame->data[1];
     159           2 :     if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
     160           0 :         int idx = bytestream2_get_byte(&s->g);
     161           0 :         npal = 4;
     162           0 :         for (i = 0; i < npal; i++)
     163           0 :             palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
     164           2 :     } else if (etype == 2) {
     165           0 :         npal = FFMIN(esize, 16);
     166           0 :         for (i = 0; i < npal; i++) {
     167           0 :             int pal_idx = bytestream2_get_byte(&s->g);
     168           0 :             palette[i]  = ff_cga_palette[FFMIN(pal_idx, 15)];
     169             :         }
     170           2 :     } else if (etype == 3) {
     171           0 :         npal = FFMIN(esize, 16);
     172           0 :         for (i = 0; i < npal; i++) {
     173           0 :             int pal_idx = bytestream2_get_byte(&s->g);
     174           0 :             palette[i]  = ff_ega_palette[FFMIN(pal_idx, 63)];
     175             :         }
     176           4 :     } else if (etype == 4 || etype == 5) {
     177           2 :         npal = FFMIN(esize / 3, 256);
     178          34 :         for (i = 0; i < npal; i++) {
     179          32 :             palette[i] = bytestream2_get_be24(&s->g) << 2;
     180          32 :             palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
     181             :         }
     182             :     } else {
     183           0 :         if (bpp == 1) {
     184           0 :             npal = 2;
     185           0 :             palette[0] = 0xFF000000;
     186           0 :             palette[1] = 0xFFFFFFFF;
     187           0 :         } else if (bpp == 2) {
     188           0 :             npal = 4;
     189           0 :             for (i = 0; i < npal; i++)
     190           0 :                 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
     191             :         } else {
     192           0 :             npal = 16;
     193           0 :             memcpy(palette, ff_cga_palette, npal * 4);
     194             :         }
     195             :     }
     196             :     // fill remaining palette entries
     197           2 :     memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
     198             :     // skip remaining palette bytes
     199           2 :     bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
     200             : 
     201           2 :     val = 0;
     202           2 :     y = s->height - 1;
     203           2 :     if (bytestream2_get_le16(&s->g)) {
     204           2 :         x = 0;
     205           2 :         plane = 0;
     206          12 :         while (bytestream2_get_bytes_left(&s->g) >= 6) {
     207             :             int stop_size, marker, t1, t2;
     208             : 
     209           8 :             t1        = bytestream2_get_bytes_left(&s->g);
     210           8 :             t2        = bytestream2_get_le16(&s->g);
     211           8 :             stop_size = t1 - FFMIN(t1, t2);
     212             :             // ignore uncompressed block size
     213           8 :             bytestream2_skip(&s->g, 2);
     214           8 :             marker    = bytestream2_get_byte(&s->g);
     215             : 
     216       93968 :             while (plane < s->nb_planes &&
     217       46980 :                    bytestream2_get_bytes_left(&s->g) > stop_size) {
     218       46974 :                 int run = 1;
     219       46974 :                 val = bytestream2_get_byte(&s->g);
     220       46974 :                 if (val == marker) {
     221        2136 :                     run = bytestream2_get_byte(&s->g);
     222        2136 :                     if (run == 0)
     223           0 :                         run = bytestream2_get_le16(&s->g);
     224        2136 :                     val = bytestream2_get_byte(&s->g);
     225             :                 }
     226       46974 :                 if (!bytestream2_get_bytes_left(&s->g))
     227           2 :                     break;
     228             : 
     229       46972 :                 if (bits_per_plane == 8) {
     230           0 :                     picmemset_8bpp(s, frame, val, run, &x, &y);
     231           0 :                     if (y < 0)
     232           0 :                         goto finish;
     233             :                 } else {
     234       46972 :                     picmemset(s, frame, val, run, &x, &y, &plane, bits_per_plane);
     235             :                 }
     236             :             }
     237             :         }
     238             : 
     239           2 :         if (plane < s->nb_planes && x < avctx->width) {
     240           2 :             int run = (y + 1) * avctx->width - x;
     241           2 :             if (bits_per_plane == 8)
     242           0 :                 picmemset_8bpp(s, frame, val, run, &x, &y);
     243             :             else
     244           2 :                 picmemset(s, frame, val, run / (8 / bits_per_plane), &x, &y, &plane, bits_per_plane);
     245             :         }
     246             :     } else {
     247           0 :         while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
     248           0 :             memcpy(frame->data[0] + y * frame->linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
     249           0 :             bytestream2_skip(&s->g, avctx->width);
     250           0 :             y--;
     251             :         }
     252             :     }
     253           0 : finish:
     254             : 
     255           2 :     *got_frame      = 1;
     256           2 :     return avpkt->size;
     257             : }
     258             : 
     259             : AVCodec ff_pictor_decoder = {
     260             :     .name           = "pictor",
     261             :     .long_name      = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
     262             :     .type           = AVMEDIA_TYPE_VIDEO,
     263             :     .id             = AV_CODEC_ID_PICTOR,
     264             :     .priv_data_size = sizeof(PicContext),
     265             :     .decode         = decode_frame,
     266             :     .capabilities   = AV_CODEC_CAP_DR1,
     267             : };

Generated by: LCOV version 1.13