LCOV - code coverage report
Current view: top level - libavcodec - cdxl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 153 184 83.2 %
Date: 2017-12-14 19:11:59 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /*
       2             :  * CDXL video decoder
       3             :  * Copyright (c) 2011-2012 Paul B Mahol
       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             :  * Commodore CDXL video decoder
      25             :  * @author Paul B Mahol
      26             :  */
      27             : 
      28             : #define UNCHECKED_BITSTREAM_READER 1
      29             : 
      30             : #include "libavutil/intreadwrite.h"
      31             : #include "libavutil/imgutils.h"
      32             : #include "avcodec.h"
      33             : #include "bytestream.h"
      34             : #include "get_bits.h"
      35             : #include "internal.h"
      36             : 
      37             : #define BIT_PLANAR   0x00
      38             : #define CHUNKY       0x20
      39             : #define BYTE_PLANAR  0x40
      40             : #define BIT_LINE     0x80
      41             : #define BYTE_LINE    0xC0
      42             : 
      43             : typedef struct CDXLVideoContext {
      44             :     AVCodecContext *avctx;
      45             :     int            bpp;
      46             :     int            format;
      47             :     int            padded_bits;
      48             :     const uint8_t  *palette;
      49             :     int            palette_size;
      50             :     const uint8_t  *video;
      51             :     int            video_size;
      52             :     uint8_t        *new_video;
      53             :     int            new_video_size;
      54             : } CDXLVideoContext;
      55             : 
      56          11 : static av_cold int cdxl_decode_init(AVCodecContext *avctx)
      57             : {
      58          11 :     CDXLVideoContext *c = avctx->priv_data;
      59             : 
      60          11 :     c->new_video_size = 0;
      61          11 :     c->avctx          = avctx;
      62             : 
      63          11 :     return 0;
      64             : }
      65             : 
      66          90 : static void import_palette(CDXLVideoContext *c, uint32_t *new_palette)
      67             : {
      68             :     int i;
      69             : 
      70        4554 :     for (i = 0; i < c->palette_size / 2; i++) {
      71        4464 :         unsigned rgb = AV_RB16(&c->palette[i * 2]);
      72        4464 :         unsigned r   = ((rgb >> 8) & 0xF) * 0x11;
      73        4464 :         unsigned g   = ((rgb >> 4) & 0xF) * 0x11;
      74        4464 :         unsigned b   =  (rgb       & 0xF) * 0x11;
      75        4464 :         AV_WN32(&new_palette[i], (0xFFU << 24) | (r << 16) | (g << 8) | b);
      76             :     }
      77          90 : }
      78             : 
      79          79 : static void bitplanar2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
      80             : {
      81             :     GetBitContext gb;
      82             :     int x, y, plane;
      83             : 
      84          79 :     if (init_get_bits8(&gb, c->video, c->video_size) < 0)
      85           0 :         return;
      86         489 :     for (plane = 0; plane < c->bpp; plane++) {
      87       43050 :         for (y = 0; y < c->avctx->height; y++) {
      88     6629520 :             for (x = 0; x < c->avctx->width; x++)
      89     6586880 :                 out[linesize * y + x] |= get_bits1(&gb) << plane;
      90       42640 :             skip_bits(&gb, c->padded_bits);
      91             :         }
      92             :     }
      93             : }
      94             : 
      95          11 : static void bitline2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
      96             : {
      97             :     GetBitContext  gb;
      98             :     int x, y, plane;
      99             : 
     100          11 :     if (init_get_bits8(&gb, c->video, c->video_size) < 0)
     101           0 :         return;
     102        1441 :     for (y = 0; y < c->avctx->height; y++) {
     103       10010 :         for (plane = 0; plane < c->bpp; plane++) {
     104     1398540 :             for (x = 0; x < c->avctx->width; x++)
     105     1389960 :                 out[linesize * y + x] |= get_bits1(&gb) << plane;
     106        8580 :             skip_bits(&gb, c->padded_bits);
     107             :         }
     108             :     }
     109             : }
     110             : 
     111           0 : static void chunky2chunky(CDXLVideoContext *c, int linesize, uint8_t *out)
     112             : {
     113             :     GetByteContext gb;
     114             :     int y;
     115             : 
     116           0 :     bytestream2_init(&gb, c->video, c->video_size);
     117           0 :     for (y = 0; y < c->avctx->height; y++) {
     118           0 :         bytestream2_get_buffer(&gb, out + linesize * y, c->avctx->width * 3);
     119             :     }
     120           0 : }
     121             : 
     122          90 : static void import_format(CDXLVideoContext *c, int linesize, uint8_t *out)
     123             : {
     124          90 :     memset(out, 0, linesize * c->avctx->height);
     125             : 
     126          90 :     switch (c->format) {
     127          79 :     case BIT_PLANAR:
     128          79 :         bitplanar2chunky(c, linesize, out);
     129          79 :         break;
     130          11 :     case BIT_LINE:
     131          11 :         bitline2chunky(c, linesize, out);
     132          11 :         break;
     133           0 :     case CHUNKY:
     134           0 :         chunky2chunky(c, linesize, out);
     135           0 :         break;
     136             :     }
     137          90 : }
     138             : 
     139          59 : static void cdxl_decode_rgb(CDXLVideoContext *c, AVFrame *frame)
     140             : {
     141          59 :     uint32_t *new_palette = (uint32_t *)frame->data[1];
     142             : 
     143          59 :     memset(frame->data[1], 0, AVPALETTE_SIZE);
     144          59 :     import_palette(c, new_palette);
     145          59 :     import_format(c, frame->linesize[0], frame->data[0]);
     146          59 : }
     147             : 
     148           0 : static void cdxl_decode_raw(CDXLVideoContext *c, AVFrame *frame)
     149             : {
     150           0 :     import_format(c, frame->linesize[0], frame->data[0]);
     151           0 : }
     152             : 
     153          28 : static void cdxl_decode_ham6(CDXLVideoContext *c, AVFrame *frame)
     154             : {
     155          28 :     AVCodecContext *avctx = c->avctx;
     156             :     uint32_t new_palette[16], r, g, b;
     157             :     uint8_t *ptr, *out, index, op;
     158             :     int x, y;
     159             : 
     160          28 :     ptr = c->new_video;
     161          28 :     out = frame->data[0];
     162             : 
     163          28 :     import_palette(c, new_palette);
     164          28 :     import_format(c, avctx->width, c->new_video);
     165             : 
     166        3498 :     for (y = 0; y < avctx->height; y++) {
     167        3470 :         r = new_palette[0] & 0xFF0000;
     168        3470 :         g = new_palette[0] & 0xFF00;
     169        3470 :         b = new_palette[0] & 0xFF;
     170      561530 :         for (x = 0; x < avctx->width; x++) {
     171      558060 :             index  = *ptr++;
     172      558060 :             op     = index >> 4;
     173      558060 :             index &= 15;
     174      558060 :             switch (op) {
     175      131279 :             case 0:
     176      131279 :                 r = new_palette[index] & 0xFF0000;
     177      131279 :                 g = new_palette[index] & 0xFF00;
     178      131279 :                 b = new_palette[index] & 0xFF;
     179      131279 :                 break;
     180      108493 :             case 1:
     181      108493 :                 b = index * 0x11;
     182      108493 :                 break;
     183      212370 :             case 2:
     184      212370 :                 r = index * 0x11 << 16;
     185      212370 :                 break;
     186      105918 :             case 3:
     187      105918 :                 g = index * 0x11 << 8;
     188      105918 :                 break;
     189             :             }
     190      558060 :             AV_WL24(out + x * 3, r | g | b);
     191             :         }
     192        3470 :         out += frame->linesize[0];
     193             :     }
     194          28 : }
     195             : 
     196           3 : static void cdxl_decode_ham8(CDXLVideoContext *c, AVFrame *frame)
     197             : {
     198           3 :     AVCodecContext *avctx = c->avctx;
     199             :     uint32_t new_palette[64], r, g, b;
     200             :     uint8_t *ptr, *out, index, op;
     201             :     int x, y;
     202             : 
     203           3 :     ptr = c->new_video;
     204           3 :     out = frame->data[0];
     205             : 
     206           3 :     import_palette(c, new_palette);
     207           3 :     import_format(c, avctx->width, c->new_video);
     208             : 
     209         387 :     for (y = 0; y < avctx->height; y++) {
     210         384 :         r = new_palette[0] & 0xFF0000;
     211         384 :         g = new_palette[0] & 0xFF00;
     212         384 :         b = new_palette[0] & 0xFF;
     213       67968 :         for (x = 0; x < avctx->width; x++) {
     214       67584 :             index  = *ptr++;
     215       67584 :             op     = index >> 6;
     216       67584 :             index &= 63;
     217       67584 :             switch (op) {
     218        3417 :             case 0:
     219        3417 :                 r = new_palette[index] & 0xFF0000;
     220        3417 :                 g = new_palette[index] & 0xFF00;
     221        3417 :                 b = new_palette[index] & 0xFF;
     222        3417 :                 break;
     223         627 :             case 1:
     224         627 :                 b = (index <<  2) | (b & 3);
     225         627 :                 break;
     226        1122 :             case 2:
     227        1122 :                 r = (index << 18) | (r & (3 << 16));
     228        1122 :                 break;
     229       62418 :             case 3:
     230       62418 :                 g = (index << 10) | (g & (3 << 8));
     231       62418 :                 break;
     232             :             }
     233       67584 :             AV_WL24(out + x * 3, r | g | b);
     234             :         }
     235         384 :         out += frame->linesize[0];
     236             :     }
     237           3 : }
     238             : 
     239          90 : static int cdxl_decode_frame(AVCodecContext *avctx, void *data,
     240             :                              int *got_frame, AVPacket *pkt)
     241             : {
     242          90 :     CDXLVideoContext *c = avctx->priv_data;
     243          90 :     AVFrame * const p = data;
     244          90 :     int ret, w, h, encoding, aligned_width, buf_size = pkt->size;
     245          90 :     const uint8_t *buf = pkt->data;
     246             : 
     247          90 :     if (buf_size < 32)
     248           0 :         return AVERROR_INVALIDDATA;
     249          90 :     encoding        = buf[1] & 7;
     250          90 :     c->format       = buf[1] & 0xE0;
     251          90 :     w               = AV_RB16(&buf[14]);
     252          90 :     h               = AV_RB16(&buf[16]);
     253          90 :     c->bpp          = buf[19];
     254          90 :     c->palette_size = AV_RB16(&buf[20]);
     255          90 :     c->palette      = buf + 32;
     256          90 :     c->video        = c->palette + c->palette_size;
     257          90 :     c->video_size   = buf_size - c->palette_size - 32;
     258             : 
     259          90 :     if (c->palette_size > 512)
     260           0 :         return AVERROR_INVALIDDATA;
     261          90 :     if (buf_size < c->palette_size + 32)
     262           0 :         return AVERROR_INVALIDDATA;
     263          90 :     if (c->bpp < 1)
     264           0 :         return AVERROR_INVALIDDATA;
     265          90 :     if (c->format != BIT_PLANAR && c->format != BIT_LINE && c->format != CHUNKY) {
     266           0 :         avpriv_request_sample(avctx, "Pixel format 0x%0x", c->format);
     267           0 :         return AVERROR_PATCHWELCOME;
     268             :     }
     269             : 
     270          90 :     if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
     271           0 :         return ret;
     272             : 
     273          90 :     if (c->format == CHUNKY)
     274           0 :         aligned_width = avctx->width;
     275             :     else
     276          90 :         aligned_width = FFALIGN(c->avctx->width, 16);
     277          90 :     c->padded_bits  = aligned_width - c->avctx->width;
     278          90 :     if (c->video_size < aligned_width * avctx->height * (int64_t)c->bpp / 8)
     279           0 :         return AVERROR_INVALIDDATA;
     280          90 :     if (!encoding && c->palette_size && c->bpp <= 8 && c->format != CHUNKY) {
     281          59 :         avctx->pix_fmt = AV_PIX_FMT_PAL8;
     282          31 :     } else if (encoding == 1 && (c->bpp == 6 || c->bpp == 8) && c->format != CHUNKY) {
     283          31 :         if (c->palette_size != (1 << (c->bpp - 1)))
     284           0 :             return AVERROR_INVALIDDATA;
     285          31 :         avctx->pix_fmt = AV_PIX_FMT_BGR24;
     286           0 :     } else if (!encoding && c->bpp == 24 && c->format == CHUNKY &&
     287           0 :                !c->palette_size) {
     288           0 :         avctx->pix_fmt = AV_PIX_FMT_RGB24;
     289             :     } else {
     290           0 :         avpriv_request_sample(avctx, "Encoding %d, bpp %d and format 0x%x",
     291             :                               encoding, c->bpp, c->format);
     292           0 :         return AVERROR_PATCHWELCOME;
     293             :     }
     294             : 
     295          90 :     if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
     296           0 :         return ret;
     297          90 :     p->pict_type = AV_PICTURE_TYPE_I;
     298             : 
     299          90 :     if (encoding) {
     300          31 :         av_fast_padded_malloc(&c->new_video, &c->new_video_size,
     301          31 :                               h * w + AV_INPUT_BUFFER_PADDING_SIZE);
     302          31 :         if (!c->new_video)
     303           0 :             return AVERROR(ENOMEM);
     304          31 :         if (c->bpp == 8)
     305           3 :             cdxl_decode_ham8(c, p);
     306             :         else
     307          28 :             cdxl_decode_ham6(c, p);
     308          59 :     } else if (avctx->pix_fmt == AV_PIX_FMT_PAL8) {
     309          59 :         cdxl_decode_rgb(c, p);
     310             :     } else {
     311           0 :         cdxl_decode_raw(c, p);
     312             :     }
     313          90 :     *got_frame = 1;
     314             : 
     315          90 :     return buf_size;
     316             : }
     317             : 
     318          11 : static av_cold int cdxl_decode_end(AVCodecContext *avctx)
     319             : {
     320          11 :     CDXLVideoContext *c = avctx->priv_data;
     321             : 
     322          11 :     av_freep(&c->new_video);
     323             : 
     324          11 :     return 0;
     325             : }
     326             : 
     327             : AVCodec ff_cdxl_decoder = {
     328             :     .name           = "cdxl",
     329             :     .long_name      = NULL_IF_CONFIG_SMALL("Commodore CDXL video"),
     330             :     .type           = AVMEDIA_TYPE_VIDEO,
     331             :     .id             = AV_CODEC_ID_CDXL,
     332             :     .priv_data_size = sizeof(CDXLVideoContext),
     333             :     .init           = cdxl_decode_init,
     334             :     .close          = cdxl_decode_end,
     335             :     .decode         = cdxl_decode_frame,
     336             :     .capabilities   = AV_CODEC_CAP_DR1,
     337             : };

Generated by: LCOV version 1.13