LCOV - code coverage report
Current view: top level - libavcodec - eacmv.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 106 119 89.1 %
Date: 2017-12-11 04:34:20 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Electronic Arts CMV Video Decoder
       3             :  * Copyright (c) 2007-2008 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 St, Fifth Floor, Boston, MA  02110-1301  USA
      20             :  */
      21             : 
      22             : /**
      23             :  * @file
      24             :  * Electronic Arts CMV Video Decoder
      25             :  * by Peter Ross (pross@xvid.org)
      26             :  *
      27             :  * Technical details here:
      28             :  * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_CMV
      29             :  */
      30             : 
      31             : #include "libavutil/common.h"
      32             : #include "libavutil/intreadwrite.h"
      33             : #include "libavutil/imgutils.h"
      34             : #include "avcodec.h"
      35             : #include "internal.h"
      36             : 
      37             : typedef struct CmvContext {
      38             :     AVCodecContext *avctx;
      39             :     AVFrame *last_frame;   ///< last
      40             :     AVFrame *last2_frame;  ///< second-last
      41             :     int width, height;
      42             :     unsigned int palette[AVPALETTE_COUNT];
      43             : } CmvContext;
      44             : 
      45           2 : static av_cold int cmv_decode_init(AVCodecContext *avctx){
      46           2 :     CmvContext *s = avctx->priv_data;
      47             : 
      48           2 :     s->avctx = avctx;
      49           2 :     avctx->pix_fmt = AV_PIX_FMT_PAL8;
      50             : 
      51           2 :     s->last_frame  = av_frame_alloc();
      52           2 :     s->last2_frame = av_frame_alloc();
      53           2 :     if (!s->last_frame || !s->last2_frame) {
      54           0 :         av_frame_free(&s->last_frame);
      55           0 :         av_frame_free(&s->last2_frame);
      56           0 :         return AVERROR(ENOMEM);
      57             :     }
      58             : 
      59           2 :     return 0;
      60             : }
      61             : 
      62           3 : static void cmv_decode_intra(CmvContext * s, AVFrame *frame,
      63             :                              const uint8_t *buf, const uint8_t *buf_end)
      64             : {
      65           3 :     unsigned char *dst = frame->data[0];
      66             :     int i;
      67             : 
      68         603 :     for (i=0; i < s->avctx->height && buf_end - buf >= s->avctx->width; i++) {
      69         600 :         memcpy(dst, buf, s->avctx->width);
      70         600 :         dst += frame->linesize[0];
      71         600 :         buf += s->avctx->width;
      72             :     }
      73           3 : }
      74             : 
      75      401014 : static void cmv_motcomp(unsigned char *dst, ptrdiff_t dst_stride,
      76             :                         const unsigned char *src, ptrdiff_t src_stride,
      77             :                         int x, int y,
      78             :                         int xoffset, int yoffset,
      79             :                         int width, int height){
      80             :     int i,j;
      81             : 
      82     2005070 :     for(j=y;j<y+4;j++)
      83     8020280 :     for(i=x;i<x+4;i++)
      84             :     {
      85    12832448 :         if (i+xoffset>=0 && i+xoffset<width &&
      86    12832448 :             j+yoffset>=0 && j+yoffset<height) {
      87     6416224 :             dst[j*dst_stride + i] = src[(j+yoffset)*src_stride + i+xoffset];
      88             :         }else{
      89           0 :             dst[j*dst_stride + i] = 0;
      90             :         }
      91             :     }
      92      401014 : }
      93             : 
      94         192 : static void cmv_decode_inter(CmvContext *s, AVFrame *frame, const uint8_t *buf,
      95             :                              const uint8_t *buf_end)
      96             : {
      97         192 :     const uint8_t *raw = buf + (s->avctx->width*s->avctx->height/16);
      98             :     int x,y,i;
      99             : 
     100         192 :     i = 0;
     101        9792 :     for(y=0; y<s->avctx->height/4; y++)
     102      489600 :     for(x=0; x<s->avctx->width/4 && buf_end - buf > i; x++) {
     103      480000 :         if (buf[i]==0xFF) {
     104      140687 :             unsigned char *dst = frame->data[0] + (y*4)*frame->linesize[0] + x*4;
     105      140687 :             if (raw+16<buf_end && *raw==0xFF) { /* intra */
     106       78986 :                 raw++;
     107       78986 :                 memcpy(dst, raw, 4);
     108       78986 :                 memcpy(dst +     frame->linesize[0], raw+4, 4);
     109       78986 :                 memcpy(dst + 2 * frame->linesize[0], raw+8, 4);
     110       78986 :                 memcpy(dst + 3 * frame->linesize[0], raw+12, 4);
     111       78986 :                 raw+=16;
     112       61701 :             }else if(raw<buf_end) {  /* inter using second-last frame as reference */
     113       61701 :                 int xoffset = (*raw & 0xF) - 7;
     114       61701 :                 int yoffset = ((*raw >> 4)) - 7;
     115       61701 :                 if (s->last2_frame->data[0])
     116      246804 :                     cmv_motcomp(frame->data[0], frame->linesize[0],
     117      123402 :                                 s->last2_frame->data[0], s->last2_frame->linesize[0],
     118      123402 :                                 x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height);
     119       61701 :                 raw++;
     120             :             }
     121             :         }else{  /* inter using last frame as reference */
     122      339313 :             int xoffset = (buf[i] & 0xF) - 7;
     123      339313 :             int yoffset = ((buf[i] >> 4)) - 7;
     124      339313 :             if (s->last_frame->data[0])
     125     1357252 :                 cmv_motcomp(frame->data[0], frame->linesize[0],
     126      678626 :                             s->last_frame->data[0], s->last_frame->linesize[0],
     127      678626 :                             x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height);
     128             :         }
     129      480000 :         i++;
     130             :     }
     131         192 : }
     132             : 
     133           3 : static int cmv_process_header(CmvContext *s, const uint8_t *buf, const uint8_t *buf_end)
     134             : {
     135             :     int pal_start, pal_count, i, ret, fps;
     136             : 
     137           3 :     if(buf_end - buf < 16) {
     138           0 :         av_log(s->avctx, AV_LOG_WARNING, "truncated header\n");
     139           0 :         return AVERROR_INVALIDDATA;
     140             :     }
     141             : 
     142           3 :     s->width  = AV_RL16(&buf[4]);
     143           3 :     s->height = AV_RL16(&buf[6]);
     144             : 
     145           5 :     if (s->width  != s->avctx->width ||
     146           2 :         s->height != s->avctx->height) {
     147           1 :         av_frame_unref(s->last_frame);
     148           1 :         av_frame_unref(s->last2_frame);
     149             :     }
     150             : 
     151           3 :     ret = ff_set_dimensions(s->avctx, s->width, s->height);
     152           3 :     if (ret < 0)
     153           0 :         return ret;
     154             : 
     155           3 :     fps = AV_RL16(&buf[10]);
     156           3 :     if (fps > 0)
     157           3 :         s->avctx->framerate = (AVRational){ fps, 1 };
     158             : 
     159           3 :     pal_start = AV_RL16(&buf[12]);
     160           3 :     pal_count = AV_RL16(&buf[14]);
     161             : 
     162           3 :     buf += 16;
     163         576 :     for (i=pal_start; i<pal_start+pal_count && i<AVPALETTE_COUNT && buf_end - buf >= 3; i++) {
     164         573 :         s->palette[i] = 0xFFU << 24 | AV_RB24(buf);
     165         573 :         buf += 3;
     166             :     }
     167             : 
     168           3 :     return 0;
     169             : }
     170             : 
     171             : #define EA_PREAMBLE_SIZE 8
     172             : #define MVIh_TAG MKTAG('M', 'V', 'I', 'h')
     173             : 
     174         195 : static int cmv_decode_frame(AVCodecContext *avctx,
     175             :                             void *data, int *got_frame,
     176             :                             AVPacket *avpkt)
     177             : {
     178         195 :     const uint8_t *buf = avpkt->data;
     179         195 :     int buf_size = avpkt->size;
     180         195 :     CmvContext *s = avctx->priv_data;
     181         195 :     const uint8_t *buf_end = buf + buf_size;
     182         195 :     AVFrame *frame = data;
     183             :     int ret;
     184             : 
     185         195 :     if (buf_end - buf < EA_PREAMBLE_SIZE)
     186           0 :         return AVERROR_INVALIDDATA;
     187             : 
     188         195 :     if (AV_RL32(buf)==MVIh_TAG||AV_RB32(buf)==MVIh_TAG) {
     189           3 :         unsigned size = AV_RL32(buf + 4);
     190           3 :         ret = cmv_process_header(s, buf+EA_PREAMBLE_SIZE, buf_end);
     191           3 :         if (ret < 0)
     192           0 :             return ret;
     193           3 :         if (size > buf_end - buf - EA_PREAMBLE_SIZE)
     194           0 :             return -1;
     195           3 :         buf += size;
     196             :     }
     197             : 
     198         195 :     if (av_image_check_size(s->width, s->height, 0, s->avctx))
     199           0 :         return -1;
     200             : 
     201         195 :     if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
     202           0 :         return ret;
     203             : 
     204         195 :     memcpy(frame->data[1], s->palette, AVPALETTE_SIZE);
     205             : 
     206         195 :     buf += EA_PREAMBLE_SIZE;
     207         195 :     if ((buf[0]&1)) {  // subtype
     208         192 :         cmv_decode_inter(s, frame, buf+2, buf_end);
     209         192 :         frame->key_frame = 0;
     210         192 :         frame->pict_type = AV_PICTURE_TYPE_P;
     211             :     }else{
     212           3 :         frame->key_frame = 1;
     213           3 :         frame->pict_type = AV_PICTURE_TYPE_I;
     214           3 :         cmv_decode_intra(s, frame, buf+2, buf_end);
     215             :     }
     216             : 
     217         195 :     av_frame_unref(s->last2_frame);
     218         195 :     av_frame_move_ref(s->last2_frame, s->last_frame);
     219         195 :     if ((ret = av_frame_ref(s->last_frame, frame)) < 0)
     220           0 :         return ret;
     221             : 
     222         195 :     *got_frame = 1;
     223             : 
     224         195 :     return buf_size;
     225             : }
     226             : 
     227           2 : static av_cold int cmv_decode_end(AVCodecContext *avctx){
     228           2 :     CmvContext *s = avctx->priv_data;
     229             : 
     230           2 :     av_frame_free(&s->last_frame);
     231           2 :     av_frame_free(&s->last2_frame);
     232             : 
     233           2 :     return 0;
     234             : }
     235             : 
     236             : AVCodec ff_eacmv_decoder = {
     237             :     .name           = "eacmv",
     238             :     .long_name      = NULL_IF_CONFIG_SMALL("Electronic Arts CMV video"),
     239             :     .type           = AVMEDIA_TYPE_VIDEO,
     240             :     .id             = AV_CODEC_ID_CMV,
     241             :     .priv_data_size = sizeof(CmvContext),
     242             :     .init           = cmv_decode_init,
     243             :     .close          = cmv_decode_end,
     244             :     .decode         = cmv_decode_frame,
     245             :     .capabilities   = AV_CODEC_CAP_DR1,
     246             : };

Generated by: LCOV version 1.13