LCOV - code coverage report
Current view: top level - libavcodec - qpeg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 159 182 87.4 %
Date: 2017-12-14 01:15:32 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :  * QPEG codec
       3             :  * Copyright (c) 2004 Konstantin Shishkov
       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             :  * QPEG codec.
      25             :  */
      26             : 
      27             : #include "avcodec.h"
      28             : #include "bytestream.h"
      29             : #include "internal.h"
      30             : 
      31             : typedef struct QpegContext{
      32             :     AVCodecContext *avctx;
      33             :     AVFrame *pic, *ref;
      34             :     uint32_t pal[256];
      35             :     GetByteContext buffer;
      36             : } QpegContext;
      37             : 
      38           1 : static void qpeg_decode_intra(QpegContext *qctx, uint8_t *dst,
      39             :                               int stride, int width, int height)
      40             : {
      41             :     int i;
      42             :     int code;
      43             :     int c0, c1;
      44             :     int run, copy;
      45           1 :     int filled = 0;
      46             :     int rows_to_go;
      47             : 
      48           1 :     rows_to_go = height;
      49           1 :     height--;
      50           1 :     dst = dst + height * stride;
      51             : 
      52       10408 :     while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (rows_to_go > 0)) {
      53       10406 :         code = bytestream2_get_byte(&qctx->buffer);
      54       10406 :         run = copy = 0;
      55       10406 :         if(code == 0xFC) /* end-of-picture code */
      56           0 :             break;
      57       10406 :         if(code >= 0xF8) { /* very long run */
      58           0 :             c0 = bytestream2_get_byte(&qctx->buffer);
      59           0 :             c1 = bytestream2_get_byte(&qctx->buffer);
      60           0 :             run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
      61       10406 :         } else if (code >= 0xF0) { /* long run */
      62          21 :             c0 = bytestream2_get_byte(&qctx->buffer);
      63          21 :             run = ((code & 0xF) << 8) + c0 + 2;
      64       10385 :         } else if (code >= 0xE0) { /* short run */
      65        5687 :             run = (code & 0x1F) + 2;
      66        4698 :         } else if (code >= 0xC0) { /* very long copy */
      67           0 :             c0 = bytestream2_get_byte(&qctx->buffer);
      68           0 :             c1 = bytestream2_get_byte(&qctx->buffer);
      69           0 :             copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
      70        4698 :         } else if (code >= 0x80) { /* long copy */
      71           0 :             c0 = bytestream2_get_byte(&qctx->buffer);
      72           0 :             copy = ((code & 0x7F) << 8) + c0 + 1;
      73             :         } else { /* short copy */
      74        4698 :             copy = code + 1;
      75             :         }
      76             : 
      77             :         /* perform actual run or copy */
      78       10406 :         if(run) {
      79             :             int p;
      80             : 
      81        5708 :             p = bytestream2_get_byte(&qctx->buffer);
      82       31143 :             for(i = 0; i < run; i++) {
      83       25435 :                 dst[filled++] = p;
      84       25435 :                 if (filled >= width) {
      85          30 :                     filled = 0;
      86          30 :                     dst -= stride;
      87          30 :                     rows_to_go--;
      88          30 :                     if(rows_to_go <= 0)
      89           0 :                         break;
      90             :                 }
      91             :             }
      92             :         } else {
      93       56062 :             for(i = 0; i < copy; i++) {
      94       51365 :                 dst[filled++] = bytestream2_get_byte(&qctx->buffer);
      95       51365 :                 if (filled >= width) {
      96         210 :                     filled = 0;
      97         210 :                     dst -= stride;
      98         210 :                     rows_to_go--;
      99         210 :                     if(rows_to_go <= 0)
     100           1 :                         break;
     101             :                 }
     102             :             }
     103             :         }
     104             :     }
     105           1 : }
     106             : 
     107             : static const int qpeg_table_h[16] =
     108             :  { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
     109             : static const int qpeg_table_w[16] =
     110             :  { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
     111             : 
     112             : /* Decodes delta frames */
     113          99 : static void av_noinline qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
     114             :                               int stride, int width, int height,
     115             :                               int delta, const uint8_t *ctable,
     116             :                               uint8_t *refdata)
     117             : {
     118             :     int i, j;
     119             :     int code;
     120          99 :     int filled = 0;
     121             :     int orig_height;
     122             : 
     123          99 :     if (refdata) {
     124             :         /* copy prev frame */
     125       23859 :         for (i = 0; i < height; i++)
     126       23760 :             memcpy(dst + (i * stride), refdata + (i * stride), width);
     127             :     } else {
     128           0 :         refdata = dst;
     129             :     }
     130             : 
     131          99 :     orig_height = height;
     132          99 :     height--;
     133          99 :     dst = dst + height * stride;
     134             : 
     135      731885 :     while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (height >= 0)) {
     136      731779 :         code = bytestream2_get_byte(&qctx->buffer);
     137             : 
     138      731779 :         if(delta) {
     139             :             /* motion compensation */
     140     1482965 :             while(bytestream2_get_bytes_left(&qctx->buffer) > 0 && (code & 0xF0) == 0xF0) {
     141       19407 :                 if(delta == 1) {
     142             :                     int me_idx;
     143             :                     int me_w, me_h, me_x, me_y;
     144             :                     uint8_t *me_plane;
     145             :                     int corr, val;
     146             : 
     147             :                     /* get block size by index */
     148       19407 :                     me_idx = code & 0xF;
     149       19407 :                     me_w = qpeg_table_w[me_idx];
     150       19407 :                     me_h = qpeg_table_h[me_idx];
     151             : 
     152             :                     /* extract motion vector */
     153       19407 :                     corr = bytestream2_get_byte(&qctx->buffer);
     154             : 
     155       19407 :                     val = corr >> 4;
     156       19407 :                     if(val > 7)
     157        8637 :                         val -= 16;
     158       19407 :                     me_x = val;
     159             : 
     160       19407 :                     val = corr & 0xF;
     161       19407 :                     if(val > 7)
     162        9623 :                         val -= 16;
     163       19407 :                     me_y = val;
     164             : 
     165             :                     /* check motion vector */
     166       38814 :                     if ((me_x + filled < 0) || (me_x + me_w + filled > width) ||
     167       58221 :                        (height - me_y - me_h < 0) || (height - me_y >= orig_height) ||
     168       38814 :                        (filled + me_w > width) || (height - me_h < 0))
     169           0 :                         av_log(qctx->avctx, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
     170             :                                me_x, me_y, me_w, me_h, filled, height);
     171             :                     else {
     172             :                         /* do motion compensation */
     173       19407 :                         me_plane = refdata + (filled + me_x) + (height - me_y) * stride;
     174      177719 :                         for(j = 0; j < me_h; j++) {
     175     1454952 :                             for(i = 0; i < me_w; i++)
     176     1296640 :                                 dst[filled + i - (j * stride)] = me_plane[i - (j * stride)];
     177             :                         }
     178             :                     }
     179             :                 }
     180       19407 :                 code = bytestream2_get_byte(&qctx->buffer);
     181             :             }
     182             :         }
     183             : 
     184      731779 :         if(code == 0xE0) /* end-of-picture code */
     185          92 :             break;
     186      731687 :         if(code > 0xE0) { /* run code: 0xE1..0xFF */
     187             :             int p;
     188             : 
     189       96361 :             code &= 0x1F;
     190       96361 :             p = bytestream2_get_byte(&qctx->buffer);
     191      359528 :             for(i = 0; i <= code; i++) {
     192      263167 :                 dst[filled++] = p;
     193      263167 :                 if(filled >= width) {
     194          72 :                     filled = 0;
     195          72 :                     dst -= stride;
     196          72 :                     height--;
     197          72 :                     if (height < 0)
     198           0 :                         break;
     199             :                 }
     200             :             }
     201      635326 :         } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
     202      214471 :             code &= 0x1F;
     203             : 
     204      214471 :             if(code + 1 > bytestream2_get_bytes_left(&qctx->buffer))
     205           0 :                 break;
     206             : 
     207      957914 :             for(i = 0; i <= code; i++) {
     208      743443 :                 dst[filled++] = bytestream2_get_byte(&qctx->buffer);
     209      743443 :                 if(filled >= width) {
     210          16 :                     filled = 0;
     211          16 :                     dst -= stride;
     212          16 :                     height--;
     213          16 :                     if (height < 0)
     214           0 :                         break;
     215             :                 }
     216             :             }
     217      420855 :         } else if(code >= 0x80) { /* skip code: 0x80..0xBF */
     218             :             int skip;
     219             : 
     220      249130 :             code &= 0x3F;
     221             :             /* codes 0x80 and 0x81 are actually escape codes,
     222             :                skip value minus constant is in the next byte */
     223      249130 :             if(!code)
     224       29191 :                 skip = bytestream2_get_byte(&qctx->buffer) +  64;
     225      219939 :             else if(code == 1)
     226         273 :                 skip = bytestream2_get_byte(&qctx->buffer) + 320;
     227             :             else
     228      219666 :                 skip = code;
     229      249130 :             filled += skip;
     230      521658 :             while( filled >= width) {
     231       23398 :                 filled -= width;
     232       23398 :                 dst -= stride;
     233       23398 :                 height--;
     234       23398 :                 if(height < 0)
     235           0 :                     break;
     236             :             }
     237             :         } else {
     238             :             /* zero code treated as one-pixel skip */
     239      171725 :             if(code) {
     240      124870 :                 dst[filled++] = ctable[code & 0x7F];
     241             :             }
     242             :             else
     243       46855 :                 filled++;
     244      171725 :             if(filled >= width) {
     245         182 :                 filled = 0;
     246         182 :                 dst -= stride;
     247         182 :                 height--;
     248             :             }
     249             :         }
     250             :     }
     251          99 : }
     252             : 
     253         100 : static int decode_frame(AVCodecContext *avctx,
     254             :                         void *data, int *got_frame,
     255             :                         AVPacket *avpkt)
     256             : {
     257             :     uint8_t ctable[128];
     258         100 :     QpegContext * const a = avctx->priv_data;
     259         100 :     AVFrame * const p = a->pic;
     260         100 :     AVFrame * const ref = a->ref;
     261             :     uint8_t* outdata;
     262             :     int delta, ret;
     263             :     int pal_size;
     264         100 :     const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &pal_size);
     265             : 
     266         100 :     if (avpkt->size < 0x86) {
     267           0 :         av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
     268           0 :         return AVERROR_INVALIDDATA;
     269             :     }
     270             : 
     271         100 :     bytestream2_init(&a->buffer, avpkt->data, avpkt->size);
     272             : 
     273         100 :     av_frame_unref(ref);
     274         100 :     av_frame_move_ref(ref, p);
     275             : 
     276         100 :     if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0)
     277           0 :         return ret;
     278         100 :     outdata = p->data[0];
     279         100 :     bytestream2_skip(&a->buffer, 4);
     280         100 :     bytestream2_get_buffer(&a->buffer, ctable, 128);
     281         100 :     bytestream2_skip(&a->buffer, 1);
     282             : 
     283         100 :     delta = bytestream2_get_byte(&a->buffer);
     284         100 :     if(delta == 0x10) {
     285           1 :         qpeg_decode_intra(a, outdata, p->linesize[0], avctx->width, avctx->height);
     286             :     } else {
     287          99 :         qpeg_decode_inter(a, outdata, p->linesize[0], avctx->width, avctx->height, delta, ctable, ref->data[0]);
     288             :     }
     289             : 
     290             :     /* make the palette available on the way out */
     291         100 :     if (pal && pal_size == AVPALETTE_SIZE) {
     292           1 :         p->palette_has_changed = 1;
     293           1 :         memcpy(a->pal, pal, AVPALETTE_SIZE);
     294          99 :     } else if (pal) {
     295           0 :         av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", pal_size);
     296             :     }
     297         100 :     memcpy(p->data[1], a->pal, AVPALETTE_SIZE);
     298             : 
     299         100 :     if ((ret = av_frame_ref(data, p)) < 0)
     300           0 :         return ret;
     301             : 
     302         100 :     *got_frame      = 1;
     303             : 
     304         100 :     return avpkt->size;
     305             : }
     306             : 
     307           2 : static void decode_flush(AVCodecContext *avctx){
     308           2 :     QpegContext * const a = avctx->priv_data;
     309             :     int i, pal_size;
     310             :     const uint8_t *pal_src;
     311             : 
     312           2 :     pal_size = FFMIN(1024U, avctx->extradata_size);
     313           2 :     pal_src = avctx->extradata + avctx->extradata_size - pal_size;
     314             : 
     315         514 :     for (i=0; i<pal_size/4; i++)
     316         512 :         a->pal[i] = 0xFFU<<24 | AV_RL32(pal_src+4*i);
     317           2 : }
     318             : 
     319           2 : static av_cold int decode_end(AVCodecContext *avctx)
     320             : {
     321           2 :     QpegContext * const a = avctx->priv_data;
     322             : 
     323           2 :     av_frame_free(&a->pic);
     324           2 :     av_frame_free(&a->ref);
     325             : 
     326           2 :     return 0;
     327             : }
     328             : 
     329           2 : static av_cold int decode_init(AVCodecContext *avctx){
     330           2 :     QpegContext * const a = avctx->priv_data;
     331             : 
     332           2 :     a->avctx = avctx;
     333           2 :     avctx->pix_fmt= AV_PIX_FMT_PAL8;
     334             : 
     335           2 :     decode_flush(avctx);
     336             : 
     337           2 :     a->pic = av_frame_alloc();
     338           2 :     a->ref = av_frame_alloc();
     339           2 :     if (!a->pic || !a->ref) {
     340           0 :         decode_end(avctx);
     341           0 :         return AVERROR(ENOMEM);
     342             :     }
     343             : 
     344           2 :     return 0;
     345             : }
     346             : 
     347             : AVCodec ff_qpeg_decoder = {
     348             :     .name           = "qpeg",
     349             :     .long_name      = NULL_IF_CONFIG_SMALL("Q-team QPEG"),
     350             :     .type           = AVMEDIA_TYPE_VIDEO,
     351             :     .id             = AV_CODEC_ID_QPEG,
     352             :     .priv_data_size = sizeof(QpegContext),
     353             :     .init           = decode_init,
     354             :     .close          = decode_end,
     355             :     .decode         = decode_frame,
     356             :     .flush          = decode_flush,
     357             :     .capabilities   = AV_CODEC_CAP_DR1,
     358             : };

Generated by: LCOV version 1.13