LCOV - code coverage report
Current view: top level - libavcodec - smc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 174 222 78.4 %
Date: 2017-12-10 21:22:29 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Quicktime Graphics (SMC) 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             :  * QT SMC Video Decoder by Mike Melanson (melanson@pcisys.net)
      25             :  * For more information about the SMC format, visit:
      26             :  *   http://www.pcisys.net/~melanson/codecs/
      27             :  *
      28             :  * The SMC decoder outputs PAL8 colorspace data.
      29             :  */
      30             : 
      31             : #include <stdio.h>
      32             : #include <stdlib.h>
      33             : #include <string.h>
      34             : 
      35             : #include "libavutil/intreadwrite.h"
      36             : #include "avcodec.h"
      37             : #include "bytestream.h"
      38             : #include "internal.h"
      39             : 
      40             : #define CPAIR 2
      41             : #define CQUAD 4
      42             : #define COCTET 8
      43             : 
      44             : #define COLORS_PER_TABLE 256
      45             : 
      46             : typedef struct SmcContext {
      47             : 
      48             :     AVCodecContext *avctx;
      49             :     AVFrame *frame;
      50             : 
      51             :     GetByteContext gb;
      52             : 
      53             :     /* SMC color tables */
      54             :     unsigned char color_pairs[COLORS_PER_TABLE * CPAIR];
      55             :     unsigned char color_quads[COLORS_PER_TABLE * CQUAD];
      56             :     unsigned char color_octets[COLORS_PER_TABLE * COCTET];
      57             : 
      58             :     uint32_t pal[256];
      59             : } SmcContext;
      60             : 
      61             : #define GET_BLOCK_COUNT() \
      62             :   (opcode & 0x10) ? (1 + bytestream2_get_byte(&s->gb)) : 1 + (opcode & 0x0F);
      63             : 
      64             : #define ADVANCE_BLOCK() \
      65             : { \
      66             :     pixel_ptr += 4; \
      67             :     if (pixel_ptr >= width) \
      68             :     { \
      69             :         pixel_ptr = 0; \
      70             :         row_ptr += stride * 4; \
      71             :     } \
      72             :     total_blocks--; \
      73             :     if (total_blocks < !!n_blocks) \
      74             :     { \
      75             :         av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \
      76             :         return; \
      77             :     } \
      78             : }
      79             : 
      80         120 : static void smc_decode_stream(SmcContext *s)
      81             : {
      82         120 :     int width = s->avctx->width;
      83         120 :     int height = s->avctx->height;
      84         120 :     int stride = s->frame->linesize[0];
      85             :     int i;
      86             :     int chunk_size;
      87         120 :     int buf_size = bytestream2_size(&s->gb);
      88             :     unsigned char opcode;
      89             :     int n_blocks;
      90             :     unsigned int color_flags;
      91             :     unsigned int color_flags_a;
      92             :     unsigned int color_flags_b;
      93             :     unsigned int flag_mask;
      94             : 
      95         120 :     unsigned char * const pixels = s->frame->data[0];
      96             : 
      97         120 :     int image_size = height * s->frame->linesize[0];
      98         120 :     int row_ptr = 0;
      99         120 :     int pixel_ptr = 0;
     100             :     int pixel_x, pixel_y;
     101         120 :     int row_inc = stride - 4;
     102             :     int block_ptr;
     103             :     int prev_block_ptr;
     104             :     int prev_block_ptr1, prev_block_ptr2;
     105             :     int prev_block_flag;
     106             :     int total_blocks;
     107             :     int color_table_index;  /* indexes to color pair, quad, or octet tables */
     108             :     int pixel;
     109             : 
     110         120 :     int color_pair_index = 0;
     111         120 :     int color_quad_index = 0;
     112         120 :     int color_octet_index = 0;
     113             : 
     114             :     /* make the palette available */
     115         120 :     memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
     116             : 
     117         120 :     bytestream2_skip(&s->gb, 1);
     118         120 :     chunk_size = bytestream2_get_be24(&s->gb);
     119         120 :     if (chunk_size != buf_size)
     120           0 :         av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
     121             :             chunk_size, buf_size);
     122             : 
     123         120 :     chunk_size = buf_size;
     124         120 :     total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
     125             : 
     126             :     /* traverse through the blocks */
     127      130937 :     while (total_blocks) {
     128             :         /* sanity checks */
     129             :         /* make sure the row pointer hasn't gone wild */
     130      130697 :         if (row_ptr >= image_size) {
     131           0 :             av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
     132             :                 row_ptr, image_size);
     133           0 :             return;
     134             :         }
     135      130697 :         if (bytestream2_get_bytes_left(&s->gb) < 1) {
     136           0 :             av_log(s->avctx, AV_LOG_ERROR, "input too small\n");
     137           0 :             return;
     138             :         }
     139             : 
     140      130697 :         opcode = bytestream2_get_byte(&s->gb);
     141      130697 :         switch (opcode & 0xF0) {
     142             :         /* skip n blocks */
     143       28630 :         case 0x00:
     144             :         case 0x10:
     145       28630 :             n_blocks = GET_BLOCK_COUNT();
     146      475645 :             while (n_blocks--) {
     147      418385 :                 ADVANCE_BLOCK();
     148             :             }
     149       28630 :             break;
     150             : 
     151             :         /* repeat last block n times */
     152        1068 :         case 0x20:
     153             :         case 0x30:
     154        1068 :             n_blocks = GET_BLOCK_COUNT();
     155             : 
     156             :             /* sanity check */
     157        1068 :             if ((row_ptr == 0) && (pixel_ptr == 0)) {
     158           0 :                 av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
     159             :                     opcode & 0xF0);
     160           0 :                 return;
     161             :             }
     162             : 
     163             :             /* figure out where the previous block started */
     164        1068 :             if (pixel_ptr == 0)
     165           0 :                 prev_block_ptr1 =
     166           0 :                     (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
     167             :             else
     168        1068 :                 prev_block_ptr1 = row_ptr + pixel_ptr - 4;
     169             : 
     170        4461 :             while (n_blocks--) {
     171        2325 :                 block_ptr = row_ptr + pixel_ptr;
     172        2325 :                 prev_block_ptr = prev_block_ptr1;
     173       11625 :                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
     174       46500 :                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
     175       37200 :                         pixels[block_ptr++] = pixels[prev_block_ptr++];
     176             :                     }
     177        9300 :                     block_ptr += row_inc;
     178        9300 :                     prev_block_ptr += row_inc;
     179             :                 }
     180        2325 :                 ADVANCE_BLOCK();
     181             :             }
     182        1068 :             break;
     183             : 
     184             :         /* repeat previous pair of blocks n times */
     185           0 :         case 0x40:
     186             :         case 0x50:
     187           0 :             n_blocks = GET_BLOCK_COUNT();
     188           0 :             n_blocks *= 2;
     189             : 
     190             :             /* sanity check */
     191           0 :             if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
     192           0 :                 av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
     193             :                     opcode & 0xF0);
     194           0 :                 return;
     195             :             }
     196             : 
     197             :             /* figure out where the previous 2 blocks started */
     198           0 :             if (pixel_ptr == 0)
     199           0 :                 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
     200           0 :                     s->avctx->width - 4 * 2;
     201           0 :             else if (pixel_ptr == 4)
     202           0 :                 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
     203             :             else
     204           0 :                 prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
     205             : 
     206           0 :             if (pixel_ptr == 0)
     207           0 :                 prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
     208             :             else
     209           0 :                 prev_block_ptr2 = row_ptr + pixel_ptr - 4;
     210             : 
     211           0 :             prev_block_flag = 0;
     212           0 :             while (n_blocks--) {
     213           0 :                 block_ptr = row_ptr + pixel_ptr;
     214           0 :                 if (prev_block_flag)
     215           0 :                     prev_block_ptr = prev_block_ptr2;
     216             :                 else
     217           0 :                     prev_block_ptr = prev_block_ptr1;
     218           0 :                 prev_block_flag = !prev_block_flag;
     219             : 
     220           0 :                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
     221           0 :                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
     222           0 :                         pixels[block_ptr++] = pixels[prev_block_ptr++];
     223             :                     }
     224           0 :                     block_ptr += row_inc;
     225           0 :                     prev_block_ptr += row_inc;
     226             :                 }
     227           0 :                 ADVANCE_BLOCK();
     228             :             }
     229           0 :             break;
     230             : 
     231             :         /* 1-color block encoding */
     232       11688 :         case 0x60:
     233             :         case 0x70:
     234       11688 :             n_blocks = GET_BLOCK_COUNT();
     235       11688 :             pixel = bytestream2_get_byte(&s->gb);
     236             : 
     237       73793 :             while (n_blocks--) {
     238       50417 :                 block_ptr = row_ptr + pixel_ptr;
     239      252085 :                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
     240     1008340 :                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
     241      806672 :                         pixels[block_ptr++] = pixel;
     242             :                     }
     243      201668 :                     block_ptr += row_inc;
     244             :                 }
     245       50417 :                 ADVANCE_BLOCK();
     246             :             }
     247       11688 :             break;
     248             : 
     249             :         /* 2-color block encoding */
     250       17912 :         case 0x80:
     251             :         case 0x90:
     252       17912 :             n_blocks = (opcode & 0x0F) + 1;
     253             : 
     254             :             /* figure out which color pair to use to paint the 2-color block */
     255       17912 :             if ((opcode & 0xF0) == 0x80) {
     256             :                 /* fetch the next 2 colors from bytestream and store in next
     257             :                  * available entry in the color pair table */
     258       15813 :                 for (i = 0; i < CPAIR; i++) {
     259       10542 :                     pixel = bytestream2_get_byte(&s->gb);
     260       10542 :                     color_table_index = CPAIR * color_pair_index + i;
     261       10542 :                     s->color_pairs[color_table_index] = pixel;
     262             :                 }
     263             :                 /* this is the base index to use for this block */
     264        5271 :                 color_table_index = CPAIR * color_pair_index;
     265        5271 :                 color_pair_index++;
     266             :                 /* wraparound */
     267        5271 :                 if (color_pair_index == COLORS_PER_TABLE)
     268           0 :                     color_pair_index = 0;
     269             :             } else
     270       12641 :                 color_table_index = CPAIR * bytestream2_get_byte(&s->gb);
     271             : 
     272       54768 :             while (n_blocks--) {
     273       18944 :                 color_flags = bytestream2_get_be16(&s->gb);
     274       18944 :                 flag_mask = 0x8000;
     275       18944 :                 block_ptr = row_ptr + pixel_ptr;
     276       94720 :                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
     277      378880 :                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
     278      303104 :                         if (color_flags & flag_mask)
     279      121822 :                             pixel = color_table_index + 1;
     280             :                         else
     281      181282 :                             pixel = color_table_index;
     282      303104 :                         flag_mask >>= 1;
     283      303104 :                         pixels[block_ptr++] = s->color_pairs[pixel];
     284             :                     }
     285       75776 :                     block_ptr += row_inc;
     286             :                 }
     287       18944 :                 ADVANCE_BLOCK();
     288             :             }
     289       17912 :             break;
     290             : 
     291             :         /* 4-color block encoding */
     292       35882 :         case 0xA0:
     293             :         case 0xB0:
     294       35882 :             n_blocks = (opcode & 0x0F) + 1;
     295             : 
     296             :             /* figure out which color quad to use to paint the 4-color block */
     297       35882 :             if ((opcode & 0xF0) == 0xA0) {
     298             :                 /* fetch the next 4 colors from bytestream and store in next
     299             :                  * available entry in the color quad table */
     300       72670 :                 for (i = 0; i < CQUAD; i++) {
     301       58136 :                     pixel = bytestream2_get_byte(&s->gb);
     302       58136 :                     color_table_index = CQUAD * color_quad_index + i;
     303       58136 :                     s->color_quads[color_table_index] = pixel;
     304             :                 }
     305             :                 /* this is the base index to use for this block */
     306       14534 :                 color_table_index = CQUAD * color_quad_index;
     307       14534 :                 color_quad_index++;
     308             :                 /* wraparound */
     309       14534 :                 if (color_quad_index == COLORS_PER_TABLE)
     310           0 :                     color_quad_index = 0;
     311             :             } else
     312       21348 :                 color_table_index = CQUAD * bytestream2_get_byte(&s->gb);
     313             : 
     314      112923 :             while (n_blocks--) {
     315       41159 :                 color_flags = bytestream2_get_be32(&s->gb);
     316             :                 /* flag mask actually acts as a bit shift count here */
     317       41159 :                 flag_mask = 30;
     318       41159 :                 block_ptr = row_ptr + pixel_ptr;
     319      205795 :                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
     320      823180 :                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
     321      658544 :                         pixel = color_table_index +
     322      658544 :                             ((color_flags >> flag_mask) & 0x03);
     323      658544 :                         flag_mask -= 2;
     324      658544 :                         pixels[block_ptr++] = s->color_quads[pixel];
     325             :                     }
     326      164636 :                     block_ptr += row_inc;
     327             :                 }
     328       41159 :                 ADVANCE_BLOCK();
     329             :             }
     330       35882 :             break;
     331             : 
     332             :         /* 8-color block encoding */
     333       33474 :         case 0xC0:
     334             :         case 0xD0:
     335       33474 :             n_blocks = (opcode & 0x0F) + 1;
     336             : 
     337             :             /* figure out which color octet to use to paint the 8-color block */
     338       33474 :             if ((opcode & 0xF0) == 0xC0) {
     339             :                 /* fetch the next 8 colors from bytestream and store in next
     340             :                  * available entry in the color octet table */
     341       98883 :                 for (i = 0; i < COCTET; i++) {
     342       87896 :                     pixel = bytestream2_get_byte(&s->gb);
     343       87896 :                     color_table_index = COCTET * color_octet_index + i;
     344       87896 :                     s->color_octets[color_table_index] = pixel;
     345             :                 }
     346             :                 /* this is the base index to use for this block */
     347       10987 :                 color_table_index = COCTET * color_octet_index;
     348       10987 :                 color_octet_index++;
     349             :                 /* wraparound */
     350       10987 :                 if (color_octet_index == COLORS_PER_TABLE)
     351           0 :                     color_octet_index = 0;
     352             :             } else
     353       22487 :                 color_table_index = COCTET * bytestream2_get_byte(&s->gb);
     354             : 
     355      109521 :             while (n_blocks--) {
     356             :                 /*
     357             :                   For this input of 6 hex bytes:
     358             :                     01 23 45 67 89 AB
     359             :                   Mangle it to this output:
     360             :                     flags_a = xx012456, flags_b = xx89A37B
     361             :                 */
     362             :                 /* build the color flags */
     363       42573 :                 int val1 = bytestream2_get_be16(&s->gb);
     364       42573 :                 int val2 = bytestream2_get_be16(&s->gb);
     365       42573 :                 int val3 = bytestream2_get_be16(&s->gb);
     366       42573 :                 color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4);
     367      127719 :                 color_flags_b = ((val3 & 0xFFF0) << 8) |
     368       85146 :                     ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F);
     369             : 
     370       42573 :                 color_flags = color_flags_a;
     371             :                 /* flag mask actually acts as a bit shift count here */
     372       42573 :                 flag_mask = 21;
     373       42573 :                 block_ptr = row_ptr + pixel_ptr;
     374      212865 :                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
     375             :                     /* reload flags at third row (iteration pixel_y == 2) */
     376      170292 :                     if (pixel_y == 2) {
     377       42573 :                         color_flags = color_flags_b;
     378       42573 :                         flag_mask = 21;
     379             :                     }
     380      851460 :                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
     381      681168 :                         pixel = color_table_index +
     382      681168 :                             ((color_flags >> flag_mask) & 0x07);
     383      681168 :                         flag_mask -= 3;
     384      681168 :                         pixels[block_ptr++] = s->color_octets[pixel];
     385             :                     }
     386      170292 :                     block_ptr += row_inc;
     387             :                 }
     388       42573 :                 ADVANCE_BLOCK();
     389             :             }
     390       33474 :             break;
     391             : 
     392             :         /* 16-color block encoding (every pixel is a different color) */
     393        2043 :         case 0xE0:
     394        2043 :             n_blocks = (opcode & 0x0F) + 1;
     395             : 
     396        6283 :             while (n_blocks--) {
     397        2197 :                 block_ptr = row_ptr + pixel_ptr;
     398       10985 :                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
     399       43940 :                     for (pixel_x = 0; pixel_x < 4; pixel_x++) {
     400       35152 :                         pixels[block_ptr++] = bytestream2_get_byte(&s->gb);
     401             :                     }
     402        8788 :                     block_ptr += row_inc;
     403             :                 }
     404        2197 :                 ADVANCE_BLOCK();
     405             :             }
     406        2043 :             break;
     407             : 
     408           0 :         case 0xF0:
     409           0 :             avpriv_request_sample(s->avctx, "0xF0 opcode");
     410           0 :             break;
     411             :         }
     412             :     }
     413             : 
     414         120 :     return;
     415             : }
     416             : 
     417           2 : static av_cold int smc_decode_init(AVCodecContext *avctx)
     418             : {
     419           2 :     SmcContext *s = avctx->priv_data;
     420             : 
     421           2 :     s->avctx = avctx;
     422           2 :     avctx->pix_fmt = AV_PIX_FMT_PAL8;
     423             : 
     424           2 :     s->frame = av_frame_alloc();
     425           2 :     if (!s->frame)
     426           0 :         return AVERROR(ENOMEM);
     427             : 
     428           2 :     return 0;
     429             : }
     430             : 
     431         120 : static int smc_decode_frame(AVCodecContext *avctx,
     432             :                              void *data, int *got_frame,
     433             :                              AVPacket *avpkt)
     434             : {
     435         120 :     const uint8_t *buf = avpkt->data;
     436         120 :     int buf_size = avpkt->size;
     437         120 :     SmcContext *s = avctx->priv_data;
     438             :     int pal_size;
     439         120 :     const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &pal_size);
     440             :     int ret;
     441             : 
     442         120 :     bytestream2_init(&s->gb, buf, buf_size);
     443             : 
     444         120 :     if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
     445           0 :         return ret;
     446             : 
     447         120 :     if (pal && pal_size == AVPALETTE_SIZE) {
     448           1 :         s->frame->palette_has_changed = 1;
     449           1 :         memcpy(s->pal, pal, AVPALETTE_SIZE);
     450         119 :     } else if (pal) {
     451           0 :         av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", pal_size);
     452             :     }
     453             : 
     454         120 :     smc_decode_stream(s);
     455             : 
     456         120 :     *got_frame      = 1;
     457         120 :     if ((ret = av_frame_ref(data, s->frame)) < 0)
     458           0 :         return ret;
     459             : 
     460             :     /* always report that the buffer was completely consumed */
     461         120 :     return buf_size;
     462             : }
     463             : 
     464           2 : static av_cold int smc_decode_end(AVCodecContext *avctx)
     465             : {
     466           2 :     SmcContext *s = avctx->priv_data;
     467             : 
     468           2 :     av_frame_free(&s->frame);
     469             : 
     470           2 :     return 0;
     471             : }
     472             : 
     473             : AVCodec ff_smc_decoder = {
     474             :     .name           = "smc",
     475             :     .long_name      = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
     476             :     .type           = AVMEDIA_TYPE_VIDEO,
     477             :     .id             = AV_CODEC_ID_SMC,
     478             :     .priv_data_size = sizeof(SmcContext),
     479             :     .init           = smc_decode_init,
     480             :     .close          = smc_decode_end,
     481             :     .decode         = smc_decode_frame,
     482             :     .capabilities   = AV_CODEC_CAP_DR1,
     483             : };

Generated by: LCOV version 1.13