LCOV - code coverage report
Current view: top level - libavcodec - mvcdec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 104 122 85.2 %
Date: 2017-12-16 13:57:32 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Silicon Graphics Motion Video Compressor 1 & 2 decoder
       3             :  * Copyright (c) 2012 Peter Ross
       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             :  * Silicon Graphics Motion Video Compressor 1 & 2 decoder
      25             :  */
      26             : 
      27             : #include "libavutil/intreadwrite.h"
      28             : 
      29             : #include "avcodec.h"
      30             : #include "bytestream.h"
      31             : #include "internal.h"
      32             : 
      33             : typedef struct MvcContext {
      34             :     int vflip;
      35             : } MvcContext;
      36             : 
      37           4 : static av_cold int mvc_decode_init(AVCodecContext *avctx)
      38             : {
      39           4 :     MvcContext *s = avctx->priv_data;
      40           4 :     int width     = avctx->width;
      41           4 :     int height    = avctx->height;
      42             :     int ret;
      43             : 
      44           4 :     if (avctx->codec_id == AV_CODEC_ID_MVC1) {
      45           2 :         width  += 3;
      46           2 :         height += 3;
      47             :     }
      48           4 :     width  &= ~3;
      49           4 :     height &= ~3;
      50           4 :     if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
      51           0 :         return ret;
      52             : 
      53           8 :     avctx->pix_fmt = (avctx->codec_id == AV_CODEC_ID_MVC1) ? AV_PIX_FMT_RGB555
      54           4 :                                                            : AV_PIX_FMT_RGB32;
      55           8 :     s->vflip = avctx->extradata_size >= 9 &&
      56           4 :                !memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9);
      57           4 :     return 0;
      58             : }
      59             : 
      60          25 : static int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb,
      61             :                        uint8_t *dst_start, int width, int height, int linesize)
      62             : {
      63             :     uint8_t *dst;
      64             :     uint16_t v[8];
      65             :     int mask, x, y, i;
      66             : 
      67        1825 :     for (y = 0; y < height; y += 4) {
      68      174600 :         for (x = 0; x < width; x += 4) {
      69      172800 :             if (bytestream2_get_bytes_left(gb) < 6)
      70           0 :                 return 0;
      71             : 
      72      172800 :             mask = bytestream2_get_be16u(gb);
      73      172800 :             v[0] = bytestream2_get_be16u(gb);
      74      172800 :             v[1] = bytestream2_get_be16u(gb);
      75      172800 :             if ((v[0] & 0x8000)) {
      76       32072 :                 if (bytestream2_get_bytes_left(gb) < 12) {
      77           0 :                     av_log(avctx, AV_LOG_WARNING, "buffer overflow\n");
      78           0 :                     return AVERROR_INVALIDDATA;
      79             :                 }
      80      224504 :                 for (i = 2; i < 8; i++)
      81      192432 :                     v[i] = bytestream2_get_be16u(gb);
      82             :             } else {
      83      140728 :                 v[2] = v[4] = v[6] = v[0];
      84      140728 :                 v[3] = v[5] = v[7] = v[1];
      85             :             }
      86             : 
      87             : #define PIX16(target, true, false)                                            \
      88             :     i = (mask & target) ? true : false;                                       \
      89             :     AV_WN16A(dst, v[i] & 0x7FFF);                                             \
      90             :     dst += 2;
      91             : 
      92             : #define ROW16(row, a1, a0, b1, b0)                                            \
      93             :     dst = dst_start + (y + row) * linesize + x * 2;                           \
      94             :     PIX16(1 << (row * 4), a1, a0)                                             \
      95             :     PIX16(1 << (row * 4 + 1), a1, a0)                                         \
      96             :     PIX16(1 << (row * 4 + 2), b1, b0)                                         \
      97             :     PIX16(1 << (row * 4 + 3), b1, b0)
      98             : 
      99      172800 :             ROW16(0, 0, 1, 2, 3);
     100      172800 :             ROW16(1, 0, 1, 2, 3);
     101      172800 :             ROW16(2, 4, 5, 6, 7);
     102      172800 :             ROW16(3, 4, 5, 6, 7);
     103             :         }
     104             :     }
     105          25 :     return 0;
     106             : }
     107             : 
     108       42758 : static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
     109             : {
     110             :     int i, j;
     111      213790 :     for (j = 0; j < 4; j++)
     112      855160 :         for (i = 0; i < 4; i++)
     113      684128 :             AV_WN32A(dst + j * linesize + i * 4, pixel);
     114       42758 : }
     115             : 
     116             : #define PIX32(target, true, false)                                            \
     117             :     AV_WN32A(dst, (mask & target) ? v[true] : v[false]);                      \
     118             :     dst += 4;
     119             : 
     120             : #define ROW32(row, a1, a0, b1, b0)                                            \
     121             :     dst = dst_start + (y + row) * linesize + x * 4;                           \
     122             :     PIX32(1 << (row * 4), a1, a0)                                             \
     123             :     PIX32(1 << (row * 4 + 1), a1, a0)                                         \
     124             :     PIX32(1 << (row * 4 + 2), b1, b0)                                         \
     125             :     PIX32(1 << (row * 4 + 3), b1, b0)
     126             : 
     127             : #define MVC2_BLOCK                                                            \
     128             :     ROW32(0, 1, 0, 3, 2);                                                     \
     129             :     ROW32(1, 1, 0, 3, 2);                                                     \
     130             :     ROW32(2, 5, 4, 7, 6);                                                     \
     131             :     ROW32(3, 5, 4, 7, 6);
     132             : 
     133          30 : static int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb,
     134             :                        uint8_t *dst_start, int width, int height,
     135             :                        int linesize, int vflip)
     136             : {
     137             :     uint8_t *dst;
     138             :     uint32_t color[128], v[8];
     139             :     int w, h, nb_colors, i, x, y, p0, p1, mask;
     140             : 
     141          30 :     if (bytestream2_get_bytes_left(gb) < 6)
     142           0 :         return AVERROR_INVALIDDATA;
     143             : 
     144          30 :     w = bytestream2_get_be16u(gb);
     145          30 :     h = bytestream2_get_be16u(gb);
     146          30 :     if ((w & ~3) != width || (h & ~3) != height)
     147           0 :         av_log(avctx, AV_LOG_WARNING, "dimension mismatch\n");
     148             : 
     149          30 :     if (bytestream2_get_byteu(gb)) {
     150           0 :         avpriv_request_sample(avctx, "bitmap feature");
     151           0 :         return AVERROR_PATCHWELCOME;
     152             :     }
     153             : 
     154          30 :     nb_colors = bytestream2_get_byteu(gb);
     155          30 :     if (bytestream2_get_bytes_left(gb) < nb_colors * 3)
     156           0 :         return AVERROR_INVALIDDATA;
     157        3868 :     for (i = 0; i < FFMIN(nb_colors, 128); i++)
     158        3838 :         color[i] = 0xFF000000 | bytestream2_get_be24u(gb);
     159          30 :     if (nb_colors > 128)
     160           0 :         bytestream2_skip(gb, (nb_colors - 128) * 3);
     161             : 
     162          30 :     if (vflip) {
     163          30 :         dst_start += (height - 1) * linesize;
     164          30 :         linesize   = -linesize;
     165             :     }
     166          30 :     x = y = 0;
     167       59250 :     while (bytestream2_get_bytes_left(gb) >= 1) {
     168       59220 :         p0 = bytestream2_get_byteu(gb);
     169       59220 :         if ((p0 & 0x80)) {
     170       42758 :             if ((p0 & 0x40)) {
     171        1214 :                 p0 &= 0x3F;
     172        1214 :                 p0  = (p0 << 2) | (p0 >> 4);
     173        1214 :                 set_4x4_block(dst_start + y * linesize + x * 4, linesize,
     174        1214 :                               0xFF000000 | (p0 << 16) | (p0 << 8) | p0);
     175             :             } else {
     176             :                 int g, r;
     177       41544 :                 p0 &= 0x3F;
     178       41544 :                 p0  = (p0 << 2) | (p0 >> 4);
     179       41544 :                 if (bytestream2_get_bytes_left(gb) < 2)
     180           0 :                     return AVERROR_INVALIDDATA;
     181       41544 :                 g = bytestream2_get_byteu(gb);
     182       41544 :                 r = bytestream2_get_byteu(gb);
     183       41544 :                 set_4x4_block(dst_start + y * linesize + x * 4, linesize,
     184       41544 :                               0xFF000000 | (r << 16) | (g << 8) | p0);
     185             :             }
     186             :         } else {
     187       16462 :             if (bytestream2_get_bytes_left(gb) < 1)
     188           0 :                 return AVERROR_INVALIDDATA;
     189       16462 :             p1 = bytestream2_get_byteu(gb);
     190       16462 :             if ((p1 & 0x80)) {
     191        2894 :                 if ((p0 & 0x7F) == (p1 & 0x7F)) {
     192           0 :                     set_4x4_block(dst_start + y * linesize + x * 4, linesize,
     193           0 :                                   color[p0 & 0x7F]);
     194             :                 } else {
     195        2894 :                     if (bytestream2_get_bytes_left(gb) < 2)
     196           0 :                         return AVERROR_INVALIDDATA;
     197        2894 :                     v[0] = v[2] = v[4] = v[6] = color[p0 & 0x7F];
     198        2894 :                     v[1] = v[3] = v[5] = v[7] = color[p1 & 0x7F];
     199        2894 :                     mask = bytestream2_get_le16u(gb);
     200        2894 :                     MVC2_BLOCK
     201             :                 }
     202             :             } else {
     203       13568 :                 if (bytestream2_get_bytes_left(gb) < 8)
     204           0 :                     return AVERROR_INVALIDDATA;
     205       13568 :                 v[0] = color[p0 & 0x7F];
     206       13568 :                 v[1] = color[p1 & 0x7F];
     207       94976 :                 for (i = 2; i < 8; i++)
     208       81408 :                     v[i] = color[bytestream2_get_byteu(gb) & 0x7F];
     209       13568 :                 mask = bytestream2_get_le16u(gb);
     210       13568 :                 MVC2_BLOCK
     211             :             }
     212             :         }
     213             : 
     214       59220 :         x += 4;
     215       59220 :         if (x >= width) {
     216        1410 :             y += 4;
     217        1410 :             if (y >= height)
     218          30 :                 break;
     219        1380 :             x = 0;
     220             :         }
     221             :     }
     222          30 :     return 0;
     223             : }
     224             : 
     225          55 : static int mvc_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
     226             :                             AVPacket *avpkt)
     227             : {
     228          55 :     MvcContext *s = avctx->priv_data;
     229          55 :     AVFrame *frame = data;
     230             :     GetByteContext gb;
     231             :     int ret;
     232             : 
     233          55 :     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
     234           0 :         return ret;
     235             : 
     236          55 :     bytestream2_init(&gb, avpkt->data, avpkt->size);
     237          55 :     if (avctx->codec_id == AV_CODEC_ID_MVC1)
     238          25 :         ret = decode_mvc1(avctx, &gb, frame->data[0],
     239             :                           avctx->width, avctx->height, frame->linesize[0]);
     240             :     else
     241          30 :         ret = decode_mvc2(avctx, &gb, frame->data[0],
     242             :                           avctx->width, avctx->height, frame->linesize[0],
     243             :                           s->vflip);
     244          55 :     if (ret < 0)
     245           0 :         return ret;
     246             : 
     247          55 :     frame->pict_type = AV_PICTURE_TYPE_I;
     248          55 :     frame->key_frame = 1;
     249             : 
     250          55 :     *got_frame = 1;
     251             : 
     252          55 :     return avpkt->size;
     253             : }
     254             : 
     255             : #if CONFIG_MVC1_DECODER
     256             : AVCodec ff_mvc1_decoder = {
     257             :     .name           = "mvc1",
     258             :     .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
     259             :     .type           = AVMEDIA_TYPE_VIDEO,
     260             :     .id             = AV_CODEC_ID_MVC1,
     261             :     .priv_data_size = sizeof(MvcContext),
     262             :     .init           = mvc_decode_init,
     263             :     .decode         = mvc_decode_frame,
     264             :     .capabilities   = AV_CODEC_CAP_DR1,
     265             : };
     266             : #endif
     267             : 
     268             : #if CONFIG_MVC2_DECODER
     269             : AVCodec ff_mvc2_decoder = {
     270             :     .name           = "mvc2",
     271             :     .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
     272             :     .type           = AVMEDIA_TYPE_VIDEO,
     273             :     .id             = AV_CODEC_ID_MVC2,
     274             :     .priv_data_size = sizeof(MvcContext),
     275             :     .init           = mvc_decode_init,
     276             :     .decode         = mvc_decode_frame,
     277             :     .capabilities   = AV_CODEC_CAP_DR1,
     278             : };
     279             : #endif

Generated by: LCOV version 1.13