LCOV - code coverage report
Current view: top level - libavcodec - cinepak.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 215 241 89.2 %
Date: 2017-12-12 11:08:38 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Cinepak Video Decoder
       3             :  * Copyright (C) 2003 The FFmpeg project
       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             :  * Cinepak video decoder
      25             :  * @author Ewald Snel <ewald@rambo.its.tudelft.nl>
      26             :  *
      27             :  * @see For more information on the Cinepak algorithm, visit:
      28             :  *   http://www.csse.monash.edu.au/~timf/
      29             :  * @see For more information on the quirky data inside Sega FILM/CPK files, visit:
      30             :  *   http://wiki.multimedia.cx/index.php?title=Sega_FILM
      31             :  *
      32             :  * Cinepak colorspace support (c) 2013 Rl, Aetey Global Technologies AB
      33             :  * @author Cinepak colorspace, Rl, Aetey Global Technologies AB
      34             :  */
      35             : 
      36             : #include <stdio.h>
      37             : #include <stdlib.h>
      38             : #include <string.h>
      39             : 
      40             : #include "libavutil/common.h"
      41             : #include "libavutil/intreadwrite.h"
      42             : #include "avcodec.h"
      43             : #include "internal.h"
      44             : 
      45             : 
      46             : typedef uint8_t cvid_codebook[12];
      47             : 
      48             : #define MAX_STRIPS      32
      49             : 
      50             : typedef struct cvid_strip {
      51             :     uint16_t          id;
      52             :     uint16_t          x1, y1;
      53             :     uint16_t          x2, y2;
      54             :     cvid_codebook     v4_codebook[256];
      55             :     cvid_codebook     v1_codebook[256];
      56             : } cvid_strip;
      57             : 
      58             : typedef struct CinepakContext {
      59             : 
      60             :     AVCodecContext *avctx;
      61             :     AVFrame *frame;
      62             : 
      63             :     const unsigned char *data;
      64             :     int size;
      65             : 
      66             :     int width, height;
      67             : 
      68             :     int palette_video;
      69             :     cvid_strip strips[MAX_STRIPS];
      70             : 
      71             :     int sega_film_skip_bytes;
      72             : 
      73             :     uint32_t pal[256];
      74             : } CinepakContext;
      75             : 
      76        2070 : static void cinepak_decode_codebook (cvid_codebook *codebook,
      77             :                                      int chunk_id, int size, const uint8_t *data)
      78             : {
      79        2070 :     const uint8_t *eod = (data + size);
      80             :     uint32_t flag, mask;
      81             :     int      i, n;
      82             :     uint8_t *p;
      83             : 
      84             :     /* check if this chunk contains 4- or 6-element vectors */
      85        2070 :     n    = (chunk_id & 0x04) ? 4 : 6;
      86        2070 :     flag = 0;
      87        2070 :     mask = 0;
      88             : 
      89        2070 :     p = codebook[0];
      90      376233 :     for (i=0; i < 256; i++) {
      91      374868 :         if ((chunk_id & 0x01) && !(mask >>= 1)) {
      92        6919 :             if ((data + 4) > eod)
      93         127 :                 break;
      94             : 
      95        6792 :             flag  = AV_RB32 (data);
      96        6792 :             data += 4;
      97        6792 :             mask  = 0x80000000;
      98             :         }
      99             : 
     100      608550 :         if (!(chunk_id & 0x01) || (flag & mask)) {
     101             :             int k, kk;
     102             : 
     103      234387 :             if ((data + n) > eod)
     104         578 :                 break;
     105             : 
     106     1169045 :             for (k = 0; k < 4; ++k) {
     107      935236 :                 int r = *data++;
     108     3740944 :                 for (kk = 0; kk < 3; ++kk)
     109     2805708 :                     *p++ = r;
     110             :             }
     111      233809 :             if (n == 6) {
     112             :                 int r, g, b, u, v;
     113      211154 :                 u = *(int8_t *)data++;
     114      211154 :                 v = *(int8_t *)data++;
     115      211154 :                 p -= 12;
     116     1055770 :                 for(k=0; k<4; ++k) {
     117      844616 :                     r = *p++ + v*2;
     118      844616 :                     g = *p++ - (u/2) - v;
     119      844616 :                     b = *p   + u*2;
     120      844616 :                     p -= 2;
     121      844616 :                     *p++ = av_clip_uint8(r);
     122      844616 :                     *p++ = av_clip_uint8(g);
     123      844616 :                     *p++ = av_clip_uint8(b);
     124             :                 }
     125             :             }
     126             :         } else {
     127      140354 :             p += 12;
     128             :         }
     129             :     }
     130        2070 : }
     131             : 
     132        1035 : static int cinepak_decode_vectors (CinepakContext *s, cvid_strip *strip,
     133             :                                    int chunk_id, int size, const uint8_t *data)
     134             : {
     135        1035 :     const uint8_t   *eod = (data + size);
     136             :     uint32_t         flag, mask;
     137             :     uint8_t         *cb0, *cb1, *cb2, *cb3;
     138             :     int             x, y;
     139             :     char            *ip0, *ip1, *ip2, *ip3;
     140             : 
     141        1035 :     flag = 0;
     142        1035 :     mask = 0;
     143             : 
     144       19017 :     for (y=strip->y1; y < strip->y2; y+=4) {
     145             : 
     146             : /* take care of y dimension not being multiple of 4, such streams exist */
     147       35968 :         ip0 = ip1 = ip2 = ip3 = s->frame->data[0] +
     148       17984 :           (s->palette_video?strip->x1:strip->x1*3) + (y * s->frame->linesize[0]);
     149       17984 :         if(s->avctx->height - y > 1) {
     150       17984 :             ip1 = ip0 + s->frame->linesize[0];
     151       17984 :             if(s->avctx->height - y > 2) {
     152       17984 :                 ip2 = ip1 + s->frame->linesize[0];
     153       17984 :                 if(s->avctx->height - y > 3) {
     154       17754 :                     ip3 = ip2 + s->frame->linesize[0];
     155             :                 }
     156             :             }
     157             :         }
     158             : /* to get the correct picture for not-multiple-of-4 cases let us fill each
     159             :  * block from the bottom up, thus possibly overwriting the bottommost line
     160             :  * more than once but ending with the correct data in place
     161             :  * (instead of in-loop checking) */
     162             : 
     163     1132191 :         for (x=strip->x1; x < strip->x2; x+=4) {
     164     1114209 :             if ((chunk_id & 0x01) && !(mask >>= 1)) {
     165       27974 :                 if ((data + 4) > eod)
     166           0 :                     return AVERROR_INVALIDDATA;
     167             : 
     168       27974 :                 flag  = AV_RB32 (data);
     169       27974 :                 data += 4;
     170       27974 :                 mask  = 0x80000000;
     171             :             }
     172             : 
     173     1114209 :             if (!(chunk_id & 0x01) || (flag & mask)) {
     174      785585 :                 if (!(chunk_id & 0x02) && !(mask >>= 1)) {
     175       23469 :                     if ((data + 4) > eod)
     176           0 :                         return AVERROR_INVALIDDATA;
     177             : 
     178       23469 :                     flag  = AV_RB32 (data);
     179       23469 :                     data += 4;
     180       23469 :                     mask  = 0x80000000;
     181             :                 }
     182             : 
     183     1041043 :                 if ((chunk_id & 0x02) || (~flag & mask)) {
     184             :                     uint8_t *p;
     185      255458 :                     if (data >= eod)
     186           0 :                         return AVERROR_INVALIDDATA;
     187             : 
     188      255458 :                     p = strip->v1_codebook[*data++];
     189      255458 :                     if (s->palette_video) {
     190           0 :                         ip3[0] = ip3[1] = ip2[0] = ip2[1] = p[6];
     191           0 :                         ip3[2] = ip3[3] = ip2[2] = ip2[3] = p[9];
     192           0 :                         ip1[0] = ip1[1] = ip0[0] = ip0[1] = p[0];
     193           0 :                         ip1[2] = ip1[3] = ip0[2] = ip0[3] = p[3];
     194             :                     } else {
     195      255458 :                         p += 6;
     196      255458 :                         memcpy(ip3 + 0, p, 3); memcpy(ip3 + 3, p, 3);
     197      255458 :                         memcpy(ip2 + 0, p, 3); memcpy(ip2 + 3, p, 3);
     198      255458 :                         p += 3; /* ... + 9 */
     199      255458 :                         memcpy(ip3 + 6, p, 3); memcpy(ip3 + 9, p, 3);
     200      255458 :                         memcpy(ip2 + 6, p, 3); memcpy(ip2 + 9, p, 3);
     201      255458 :                         p -= 9; /* ... + 0 */
     202      255458 :                         memcpy(ip1 + 0, p, 3); memcpy(ip1 + 3, p, 3);
     203      255458 :                         memcpy(ip0 + 0, p, 3); memcpy(ip0 + 3, p, 3);
     204      255458 :                         p += 3; /* ... + 3 */
     205      255458 :                         memcpy(ip1 + 6, p, 3); memcpy(ip1 + 9, p, 3);
     206      255458 :                         memcpy(ip0 + 6, p, 3); memcpy(ip0 + 9, p, 3);
     207             :                     }
     208             : 
     209      530127 :                 } else if (flag & mask) {
     210      530127 :                     if ((data + 4) > eod)
     211           2 :                         return AVERROR_INVALIDDATA;
     212             : 
     213      530125 :                     cb0 = strip->v4_codebook[*data++];
     214      530125 :                     cb1 = strip->v4_codebook[*data++];
     215      530125 :                     cb2 = strip->v4_codebook[*data++];
     216      530125 :                     cb3 = strip->v4_codebook[*data++];
     217      530125 :                     if (s->palette_video) {
     218             :                         uint8_t *p;
     219       66297 :                         p = ip3;
     220       66297 :                         *p++ = cb2[6];
     221       66297 :                         *p++ = cb2[9];
     222       66297 :                         *p++ = cb3[6];
     223       66297 :                         *p   = cb3[9];
     224       66297 :                         p = ip2;
     225       66297 :                         *p++ = cb2[0];
     226       66297 :                         *p++ = cb2[3];
     227       66297 :                         *p++ = cb3[0];
     228       66297 :                         *p   = cb3[3];
     229       66297 :                         p = ip1;
     230       66297 :                         *p++ = cb0[6];
     231       66297 :                         *p++ = cb0[9];
     232       66297 :                         *p++ = cb1[6];
     233       66297 :                         *p   = cb1[9];
     234       66297 :                         p = ip0;
     235       66297 :                         *p++ = cb0[0];
     236       66297 :                         *p++ = cb0[3];
     237       66297 :                         *p++ = cb1[0];
     238       66297 :                         *p   = cb1[3];
     239             :                     } else {
     240      463828 :                         memcpy(ip3 + 0, cb2 + 6, 6);
     241      463828 :                         memcpy(ip3 + 6, cb3 + 6, 6);
     242      463828 :                         memcpy(ip2 + 0, cb2 + 0, 6);
     243      463828 :                         memcpy(ip2 + 6, cb3 + 0, 6);
     244      463828 :                         memcpy(ip1 + 0, cb0 + 6, 6);
     245      463828 :                         memcpy(ip1 + 6, cb1 + 6, 6);
     246      463828 :                         memcpy(ip0 + 0, cb0 + 0, 6);
     247      463828 :                         memcpy(ip0 + 6, cb1 + 0, 6);
     248             :                     }
     249             : 
     250             :                 }
     251             :             }
     252             : 
     253     1114207 :             if (s->palette_video) {
     254       66297 :                 ip0 += 4;  ip1 += 4;
     255       66297 :                 ip2 += 4;  ip3 += 4;
     256             :             } else {
     257     1047910 :                 ip0 += 12;  ip1 += 12;
     258     1047910 :                 ip2 += 12;  ip3 += 12;
     259             :             }
     260             :         }
     261             :     }
     262             : 
     263        1033 :     return 0;
     264             : }
     265             : 
     266        1035 : static int cinepak_decode_strip (CinepakContext *s,
     267             :                                  cvid_strip *strip, const uint8_t *data, int size)
     268             : {
     269        1035 :     const uint8_t *eod = (data + size);
     270             :     int      chunk_id, chunk_size;
     271             : 
     272             :     /* coordinate sanity checks */
     273        2070 :     if (strip->x2 > s->width   ||
     274        2070 :         strip->y2 > s->height  ||
     275        2070 :         strip->x1 >= strip->x2 || strip->y1 >= strip->y2)
     276           0 :         return AVERROR_INVALIDDATA;
     277             : 
     278        4140 :     while ((data + 4) <= eod) {
     279        3105 :         chunk_id   = data[0];
     280        3105 :         chunk_size = AV_RB24 (&data[1]) - 4;
     281        3105 :         if(chunk_size < 0)
     282           0 :             return AVERROR_INVALIDDATA;
     283             : 
     284        3105 :         data      += 4;
     285        3105 :         chunk_size = ((data + chunk_size) > eod) ? (eod - data) : chunk_size;
     286             : 
     287        3105 :         switch (chunk_id) {
     288             : 
     289        1035 :         case 0x20:
     290             :         case 0x21:
     291             :         case 0x24:
     292             :         case 0x25:
     293        1035 :             cinepak_decode_codebook (strip->v4_codebook, chunk_id,
     294             :                 chunk_size, data);
     295        1035 :             break;
     296             : 
     297        1035 :         case 0x22:
     298             :         case 0x23:
     299             :         case 0x26:
     300             :         case 0x27:
     301        1035 :             cinepak_decode_codebook (strip->v1_codebook, chunk_id,
     302             :                 chunk_size, data);
     303        1035 :             break;
     304             : 
     305        1035 :         case 0x30:
     306             :         case 0x31:
     307             :         case 0x32:
     308        1035 :             return cinepak_decode_vectors (s, strip, chunk_id,
     309             :                 chunk_size, data);
     310             :         }
     311             : 
     312        2070 :         data += chunk_size;
     313             :     }
     314             : 
     315           0 :     return AVERROR_INVALIDDATA;
     316             : }
     317             : 
     318         547 : static int cinepak_decode (CinepakContext *s)
     319             : {
     320         547 :     const uint8_t  *eod = (s->data + s->size);
     321             :     int           i, result, strip_size, frame_flags, num_strips;
     322         547 :     int           y0 = 0;
     323             :     int           encoded_buf_size;
     324             : 
     325         547 :     frame_flags = s->data[0];
     326         547 :     num_strips  = AV_RB16 (&s->data[8]);
     327         547 :     encoded_buf_size = AV_RB24(&s->data[1]);
     328             : 
     329             :     /* if this is the first frame, check for deviant Sega FILM data */
     330         547 :     if (s->sega_film_skip_bytes == -1) {
     331           7 :         if (!encoded_buf_size) {
     332           0 :             avpriv_request_sample(s->avctx, "encoded_buf_size 0");
     333           0 :             return AVERROR_PATCHWELCOME;
     334             :         }
     335           7 :         if (encoded_buf_size != s->size && (s->size % encoded_buf_size) != 0) {
     336             :             /* If the encoded frame size differs from the frame size as indicated
     337             :              * by the container file, this data likely comes from a Sega FILM/CPK file.
     338             :              * If the frame header is followed by the bytes FE 00 00 06 00 00 then
     339             :              * this is probably one of the two known files that have 6 extra bytes
     340             :              * after the frame header. Else, assume 2 extra bytes. The container
     341             :              * size also cannot be a multiple of the encoded size. */
     342           3 :             if (s->size >= 16 &&
     343           1 :                 (s->data[10] == 0xFE) &&
     344           0 :                 (s->data[11] == 0x00) &&
     345           0 :                 (s->data[12] == 0x00) &&
     346           0 :                 (s->data[13] == 0x06) &&
     347           0 :                 (s->data[14] == 0x00) &&
     348           0 :                 (s->data[15] == 0x00))
     349           0 :                 s->sega_film_skip_bytes = 6;
     350             :             else
     351           1 :                 s->sega_film_skip_bytes = 2;
     352             :         } else
     353           6 :             s->sega_film_skip_bytes = 0;
     354             :     }
     355             : 
     356         547 :     s->data += 10 + s->sega_film_skip_bytes;
     357             : 
     358         547 :     num_strips = FFMIN(num_strips, MAX_STRIPS);
     359             : 
     360         547 :     s->frame->key_frame = 0;
     361             : 
     362        1580 :     for (i=0; i < num_strips; i++) {
     363        1035 :         if ((s->data + 12) > eod)
     364           0 :             return AVERROR_INVALIDDATA;
     365             : 
     366        1035 :         s->strips[i].id = s->data[0];
     367             : /* zero y1 means "relative to the previous stripe" */
     368        1035 :         if (!(s->strips[i].y1 = AV_RB16 (&s->data[4])))
     369        1035 :             s->strips[i].y2 = (s->strips[i].y1 = y0) + AV_RB16 (&s->data[8]);
     370             :         else
     371           0 :             s->strips[i].y2 = AV_RB16 (&s->data[8]);
     372        1035 :         s->strips[i].x1 = AV_RB16 (&s->data[6]);
     373        1035 :         s->strips[i].x2 = AV_RB16 (&s->data[10]);
     374             : 
     375        1035 :         if (s->strips[i].id == 0x10)
     376         115 :             s->frame->key_frame = 1;
     377             : 
     378        1035 :         strip_size = AV_RB24 (&s->data[1]) - 12;
     379        1035 :         if (strip_size < 0)
     380           0 :             return AVERROR_INVALIDDATA;
     381        1035 :         s->data   += 12;
     382        1035 :         strip_size = ((s->data + strip_size) > eod) ? (eod - s->data) : strip_size;
     383             : 
     384        1035 :         if ((i > 0) && !(frame_flags & 0x01)) {
     385          49 :             memcpy (s->strips[i].v4_codebook, s->strips[i-1].v4_codebook,
     386             :                 sizeof(s->strips[i].v4_codebook));
     387          49 :             memcpy (s->strips[i].v1_codebook, s->strips[i-1].v1_codebook,
     388             :                 sizeof(s->strips[i].v1_codebook));
     389             :         }
     390             : 
     391        1035 :         result = cinepak_decode_strip (s, &s->strips[i], s->data, strip_size);
     392             : 
     393        1035 :         if (result != 0)
     394           2 :             return result;
     395             : 
     396        1033 :         s->data += strip_size;
     397        1033 :         y0    = s->strips[i].y2;
     398             :     }
     399         545 :     return 0;
     400             : }
     401             : 
     402          14 : static av_cold int cinepak_decode_init(AVCodecContext *avctx)
     403             : {
     404          14 :     CinepakContext *s = avctx->priv_data;
     405             : 
     406          14 :     s->avctx = avctx;
     407          14 :     s->width = (avctx->width + 3) & ~3;
     408          14 :     s->height = (avctx->height + 3) & ~3;
     409             : 
     410          14 :     s->sega_film_skip_bytes = -1;  /* uninitialized state */
     411             : 
     412             :     // check for paletted data
     413          14 :     if (avctx->bits_per_coded_sample != 8) {
     414          12 :         s->palette_video = 0;
     415          12 :         avctx->pix_fmt = AV_PIX_FMT_RGB24;
     416             :     } else {
     417           2 :         s->palette_video = 1;
     418           2 :         avctx->pix_fmt = AV_PIX_FMT_PAL8;
     419             :     }
     420             : 
     421          14 :     s->frame = av_frame_alloc();
     422          14 :     if (!s->frame)
     423           0 :         return AVERROR(ENOMEM);
     424             : 
     425          14 :     return 0;
     426             : }
     427             : 
     428         547 : static int cinepak_decode_frame(AVCodecContext *avctx,
     429             :                                 void *data, int *got_frame,
     430             :                                 AVPacket *avpkt)
     431             : {
     432         547 :     const uint8_t *buf = avpkt->data;
     433         547 :     int ret = 0, buf_size = avpkt->size;
     434         547 :     CinepakContext *s = avctx->priv_data;
     435             : 
     436         547 :     s->data = buf;
     437         547 :     s->size = buf_size;
     438             : 
     439         547 :     if (s->size < 10)
     440           0 :         return AVERROR_INVALIDDATA;
     441             : 
     442         547 :     if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
     443           0 :         return ret;
     444             : 
     445         547 :     if (s->palette_video) {
     446             :         int size;
     447          56 :         const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size);
     448          56 :         if (pal && size == AVPALETTE_SIZE) {
     449           1 :             s->frame->palette_has_changed = 1;
     450           1 :             memcpy(s->pal, pal, AVPALETTE_SIZE);
     451          55 :         } else if (pal) {
     452           0 :             av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", size);
     453             :         }
     454             :     }
     455             : 
     456         547 :     if ((ret = cinepak_decode(s)) < 0) {
     457           2 :         av_log(avctx, AV_LOG_ERROR, "cinepak_decode failed\n");
     458             :     }
     459             : 
     460         547 :     if (s->palette_video)
     461          56 :         memcpy (s->frame->data[1], s->pal, AVPALETTE_SIZE);
     462             : 
     463         547 :     if ((ret = av_frame_ref(data, s->frame)) < 0)
     464           0 :         return ret;
     465             : 
     466         547 :     *got_frame = 1;
     467             : 
     468             :     /* report that the buffer was completely consumed */
     469         547 :     return buf_size;
     470             : }
     471             : 
     472          14 : static av_cold int cinepak_decode_end(AVCodecContext *avctx)
     473             : {
     474          14 :     CinepakContext *s = avctx->priv_data;
     475             : 
     476          14 :     av_frame_free(&s->frame);
     477             : 
     478          14 :     return 0;
     479             : }
     480             : 
     481             : AVCodec ff_cinepak_decoder = {
     482             :     .name           = "cinepak",
     483             :     .long_name      = NULL_IF_CONFIG_SMALL("Cinepak"),
     484             :     .type           = AVMEDIA_TYPE_VIDEO,
     485             :     .id             = AV_CODEC_ID_CINEPAK,
     486             :     .priv_data_size = sizeof(CinepakContext),
     487             :     .init           = cinepak_decode_init,
     488             :     .close          = cinepak_decode_end,
     489             :     .decode         = cinepak_decode_frame,
     490             :     .capabilities   = AV_CODEC_CAP_DR1,
     491             : };

Generated by: LCOV version 1.13