LCOV - code coverage report
Current view: top level - libavcodec - c93.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 107 128 83.6 %
Date: 2017-12-14 01:15:32 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Interplay C93 video decoder
       3             :  * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
       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 "avcodec.h"
      23             : #include "bytestream.h"
      24             : #include "internal.h"
      25             : 
      26             : typedef struct C93DecoderContext {
      27             :     AVFrame *pictures[2];
      28             :     int currentpic;
      29             : } C93DecoderContext;
      30             : 
      31             : typedef enum {
      32             :     C93_8X8_FROM_PREV  = 0x02,
      33             :     C93_4X4_FROM_PREV  = 0x06,
      34             :     C93_4X4_FROM_CURR  = 0x07,
      35             :     C93_8X8_2COLOR     = 0x08,
      36             :     C93_4X4_2COLOR     = 0x0A,
      37             :     C93_4X4_4COLOR_GRP = 0x0B,
      38             :     C93_4X4_4COLOR     = 0x0D,
      39             :     C93_NOOP           = 0x0E,
      40             :     C93_8X8_INTRA      = 0x0F,
      41             : } C93BlockType;
      42             : 
      43             : #define WIDTH   320
      44             : #define HEIGHT  192
      45             : 
      46             : #define C93_HAS_PALETTE 0x01
      47             : #define C93_FIRST_FRAME 0x02
      48             : 
      49           2 : static av_cold int decode_end(AVCodecContext *avctx)
      50             : {
      51           2 :     C93DecoderContext * const c93 = avctx->priv_data;
      52             : 
      53           2 :     av_frame_free(&c93->pictures[0]);
      54           2 :     av_frame_free(&c93->pictures[1]);
      55             : 
      56           2 :     return 0;
      57             : }
      58             : 
      59           2 : static av_cold int decode_init(AVCodecContext *avctx)
      60             : {
      61           2 :     C93DecoderContext *s = avctx->priv_data;
      62           2 :     avctx->pix_fmt = AV_PIX_FMT_PAL8;
      63             : 
      64           2 :     s->pictures[0] = av_frame_alloc();
      65           2 :     s->pictures[1] = av_frame_alloc();
      66           2 :     if (!s->pictures[0] || !s->pictures[1]) {
      67           0 :         decode_end(avctx);
      68           0 :         return AVERROR(ENOMEM);
      69             :     }
      70             : 
      71           2 :     return 0;
      72             : }
      73             : 
      74       98205 : static inline int copy_block(AVCodecContext *avctx, uint8_t *to,
      75             :         uint8_t *from, int offset, int height, int stride)
      76             : {
      77             :     int i;
      78       98205 :     int width = height;
      79       98205 :     int from_x = offset % WIDTH;
      80       98205 :     int from_y = offset / WIDTH;
      81       98205 :     int overflow = from_x + width - WIDTH;
      82             : 
      83       98205 :     if (!from) {
      84             :         /* silently ignoring predictive blocks in first frame */
      85           0 :         return 0;
      86             :     }
      87             : 
      88       98205 :     if (from_y + height > HEIGHT) {
      89           0 :         av_log(avctx, AV_LOG_ERROR, "invalid offset %d during C93 decoding\n",
      90             :                offset);
      91           0 :         return AVERROR_INVALIDDATA;
      92             :     }
      93             : 
      94       98205 :     if (overflow > 0) {
      95           0 :         width -= overflow;
      96           0 :         for (i = 0; i < height; i++) {
      97           0 :             memcpy(&to[i*stride+width], &from[(from_y+i)*stride], overflow);
      98             :         }
      99             :     }
     100             : 
     101      573461 :     for (i = 0; i < height; i++) {
     102      475256 :         memcpy(&to[i*stride], &from[(from_y+i)*stride+from_x], width);
     103             :     }
     104             : 
     105       98205 :     return 0;
     106             : }
     107             : 
     108        2576 : static inline void draw_n_color(uint8_t *out, int stride, int width,
     109             :          int height, int bpp, uint8_t cols[4], uint8_t grps[4], uint32_t col)
     110             : {
     111             :     int x, y;
     112       11584 :     for (y = 0; y < height; y++) {
     113        9008 :         if (grps)
     114         480 :             cols[0] = grps[3 * (y >> 1)];
     115       46768 :         for (x = 0; x < width; x++) {
     116       37760 :             if (grps)
     117        1920 :                 cols[1]= grps[(x >> 1) + 1];
     118       37760 :             out[x + y*stride] = cols[col & ((1 << bpp) - 1)];
     119       37760 :             col >>= bpp;
     120             :         }
     121             :     }
     122        2576 : }
     123             : 
     124          45 : static int decode_frame(AVCodecContext *avctx, void *data,
     125             :                         int *got_frame, AVPacket *avpkt)
     126             : {
     127          45 :     const uint8_t *buf = avpkt->data;
     128          45 :     int buf_size = avpkt->size;
     129          45 :     C93DecoderContext * const c93 = avctx->priv_data;
     130          45 :     AVFrame * const newpic = c93->pictures[c93->currentpic];
     131          45 :     AVFrame * const oldpic = c93->pictures[c93->currentpic^1];
     132             :     GetByteContext gb;
     133             :     uint8_t *out;
     134          45 :     int stride, ret, i, x, y, b, bt = 0;
     135             : 
     136          45 :     if ((ret = ff_set_dimensions(avctx, WIDTH, HEIGHT)) < 0)
     137           0 :         return ret;
     138             : 
     139          45 :     c93->currentpic ^= 1;
     140             : 
     141          45 :     if ((ret = ff_reget_buffer(avctx, newpic)) < 0)
     142           0 :         return ret;
     143             : 
     144          45 :     stride = newpic->linesize[0];
     145             : 
     146          45 :     bytestream2_init(&gb, buf, buf_size);
     147          45 :     b = bytestream2_get_byte(&gb);
     148          45 :     if (b & C93_FIRST_FRAME) {
     149           1 :         newpic->pict_type = AV_PICTURE_TYPE_I;
     150           1 :         newpic->key_frame = 1;
     151             :     } else {
     152          44 :         newpic->pict_type = AV_PICTURE_TYPE_P;
     153          44 :         newpic->key_frame = 0;
     154             :     }
     155             : 
     156        1125 :     for (y = 0; y < HEIGHT; y += 8) {
     157        1080 :         out = newpic->data[0] + y * stride;
     158       88560 :         for (x = 0; x < WIDTH; x += 8) {
     159       43200 :             uint8_t *copy_from = oldpic->data[0];
     160             :             unsigned int offset, j;
     161             :             uint8_t cols[4], grps[4];
     162             :             C93BlockType block_type;
     163             : 
     164       43200 :             if (!bt)
     165       21600 :                 bt = bytestream2_get_byte(&gb);
     166             : 
     167       43200 :             block_type= bt & 0x0F;
     168       43200 :             switch (block_type) {
     169       20609 :             case C93_8X8_FROM_PREV:
     170       20609 :                 offset = bytestream2_get_le16(&gb);
     171       20609 :                 if ((ret = copy_block(avctx, out, copy_from, offset, 8, stride)) < 0)
     172           0 :                     return ret;
     173       20609 :                 break;
     174             : 
     175         621 :             case C93_4X4_FROM_CURR:
     176         621 :                 copy_from = newpic->data[0];
     177       19399 :             case C93_4X4_FROM_PREV:
     178       58197 :                 for (j = 0; j < 8; j += 4) {
     179      116394 :                     for (i = 0; i < 8; i += 4) {
     180       77596 :                         int offset = bytestream2_get_le16(&gb);
     181       77596 :                         int from_x = offset % WIDTH;
     182       77596 :                         int from_y = offset / WIDTH;
     183       77596 :                         if (block_type == C93_4X4_FROM_CURR && from_y == y+j &&
     184           0 :                             (FFABS(from_x - x-i) < 4 || FFABS(from_x - x-i) > WIDTH-4)) {
     185           0 :                             avpriv_request_sample(avctx, "block overlap %d %d %d %d", from_x, x+i, from_y, y+j);
     186           0 :                             return AVERROR_INVALIDDATA;
     187             :                         }
     188       77596 :                         if ((ret = copy_block(avctx, &out[j*stride+i],
     189             :                                               copy_from, offset, 4, stride)) < 0)
     190           0 :                             return ret;
     191             :                     }
     192             :                 }
     193       19399 :                 break;
     194             : 
     195          54 :             case C93_8X8_2COLOR:
     196          54 :                 bytestream2_get_buffer(&gb, cols, 2);
     197         486 :                 for (i = 0; i < 8; i++) {
     198         432 :                     draw_n_color(out + i*stride, stride, 8, 1, 1, cols,
     199             :                                      NULL, bytestream2_get_byte(&gb));
     200             :                 }
     201             : 
     202          54 :                 break;
     203             : 
     204         536 :             case C93_4X4_2COLOR:
     205             :             case C93_4X4_4COLOR:
     206             :             case C93_4X4_4COLOR_GRP:
     207        1608 :                 for (j = 0; j < 8; j += 4) {
     208        3216 :                     for (i = 0; i < 8; i += 4) {
     209        2144 :                         if (block_type == C93_4X4_2COLOR) {
     210         108 :                             bytestream2_get_buffer(&gb, cols, 2);
     211         108 :                             draw_n_color(out + i + j*stride, stride, 4, 4,
     212             :                                     1, cols, NULL, bytestream2_get_le16(&gb));
     213        2036 :                         } else if (block_type == C93_4X4_4COLOR) {
     214        1916 :                             bytestream2_get_buffer(&gb, cols, 4);
     215        1916 :                             draw_n_color(out + i + j*stride, stride, 4, 4,
     216             :                                     2, cols, NULL, bytestream2_get_le32(&gb));
     217             :                         } else {
     218         120 :                             bytestream2_get_buffer(&gb, grps, 4);
     219         120 :                             draw_n_color(out + i + j*stride, stride, 4, 4,
     220             :                                     1, cols, grps, bytestream2_get_le16(&gb));
     221             :                         }
     222             :                     }
     223             :                 }
     224         536 :                 break;
     225             : 
     226           0 :             case C93_NOOP:
     227           0 :                 break;
     228             : 
     229        2602 :             case C93_8X8_INTRA:
     230       23418 :                 for (j = 0; j < 8; j++)
     231       20816 :                     bytestream2_get_buffer(&gb, out + j*stride, 8);
     232        2602 :                 break;
     233             : 
     234           0 :             default:
     235           0 :                 av_log(avctx, AV_LOG_ERROR, "unexpected type %x at %dx%d\n",
     236             :                        block_type, x, y);
     237           0 :                 return AVERROR_INVALIDDATA;
     238             :             }
     239       43200 :             bt >>= 4;
     240       43200 :             out += 8;
     241             :         }
     242             :     }
     243             : 
     244          45 :     if (b & C93_HAS_PALETTE) {
     245           1 :         uint32_t *palette = (uint32_t *) newpic->data[1];
     246         257 :         for (i = 0; i < 256; i++) {
     247         256 :             palette[i] = 0xFFU << 24 | bytestream2_get_be24(&gb);
     248             :         }
     249           1 :         newpic->palette_has_changed = 1;
     250             :     } else {
     251          44 :         if (oldpic->data[1])
     252          44 :             memcpy(newpic->data[1], oldpic->data[1], 256 * 4);
     253             :     }
     254             : 
     255          45 :     if ((ret = av_frame_ref(data, newpic)) < 0)
     256           0 :         return ret;
     257          45 :     *got_frame = 1;
     258             : 
     259          45 :     return buf_size;
     260             : }
     261             : 
     262             : AVCodec ff_c93_decoder = {
     263             :     .name           = "c93",
     264             :     .long_name      = NULL_IF_CONFIG_SMALL("Interplay C93"),
     265             :     .type           = AVMEDIA_TYPE_VIDEO,
     266             :     .id             = AV_CODEC_ID_C93,
     267             :     .priv_data_size = sizeof(C93DecoderContext),
     268             :     .init           = decode_init,
     269             :     .close          = decode_end,
     270             :     .decode         = decode_frame,
     271             :     .capabilities   = AV_CODEC_CAP_DR1,
     272             :     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
     273             : };

Generated by: LCOV version 1.13