1/* 2 * Electronic Arts CMV Video Decoder 3 * Copyright (c) 2007-2008 Peter Ross 4 * 5 * This file is part of Libav. 6 * 7 * Libav 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 * Libav 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 Libav; 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/intreadwrite.h" 32#include "libavutil/imgutils.h" 33#include "avcodec.h" 34 35typedef struct CmvContext { 36 AVCodecContext *avctx; 37 AVFrame frame; ///< current 38 AVFrame last_frame; ///< last 39 AVFrame last2_frame; ///< second-last 40 int width, height; 41 unsigned int palette[AVPALETTE_COUNT]; 42} CmvContext; 43 44static av_cold int cmv_decode_init(AVCodecContext *avctx){ 45 CmvContext *s = avctx->priv_data; 46 s->avctx = avctx; 47 avctx->pix_fmt = PIX_FMT_PAL8; 48 return 0; 49} 50 51static void cmv_decode_intra(CmvContext * s, const uint8_t *buf, const uint8_t *buf_end){ 52 unsigned char *dst = s->frame.data[0]; 53 int i; 54 55 for (i=0; i < s->avctx->height && buf_end - buf >= s->avctx->width; i++) { 56 memcpy(dst, buf, s->avctx->width); 57 dst += s->frame.linesize[0]; 58 buf += s->avctx->width; 59 } 60} 61 62static void cmv_motcomp(unsigned char *dst, int dst_stride, 63 const unsigned char *src, int src_stride, 64 int x, int y, 65 int xoffset, int yoffset, 66 int width, int height){ 67 int i,j; 68 69 for(j=y;j<y+4;j++) 70 for(i=x;i<x+4;i++) 71 { 72 if (i+xoffset>=0 && i+xoffset<width && 73 j+yoffset>=0 && j+yoffset<height) { 74 dst[j*dst_stride + i] = src[(j+yoffset)*src_stride + i+xoffset]; 75 }else{ 76 dst[j*dst_stride + i] = 0; 77 } 78 } 79} 80 81static void cmv_decode_inter(CmvContext * s, const uint8_t *buf, const uint8_t *buf_end){ 82 const uint8_t *raw = buf + (s->avctx->width*s->avctx->height/16); 83 int x,y,i; 84 85 i = 0; 86 for(y=0; y<s->avctx->height/4; y++) 87 for(x=0; x<s->avctx->width/4 && buf_end - buf > i; x++) { 88 if (buf[i]==0xFF) { 89 unsigned char *dst = s->frame.data[0] + (y*4)*s->frame.linesize[0] + x*4; 90 if (raw+16<buf_end && *raw==0xFF) { /* intra */ 91 raw++; 92 memcpy(dst, raw, 4); 93 memcpy(dst+s->frame.linesize[0], raw+4, 4); 94 memcpy(dst+2*s->frame.linesize[0], raw+8, 4); 95 memcpy(dst+3*s->frame.linesize[0], raw+12, 4); 96 raw+=16; 97 }else if(raw<buf_end) { /* inter using second-last frame as reference */ 98 int xoffset = (*raw & 0xF) - 7; 99 int yoffset = ((*raw >> 4)) - 7; 100 if (s->last2_frame.data[0]) 101 cmv_motcomp(s->frame.data[0], s->frame.linesize[0], 102 s->last2_frame.data[0], s->last2_frame.linesize[0], 103 x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height); 104 raw++; 105 } 106 }else{ /* inter using last frame as reference */ 107 int xoffset = (buf[i] & 0xF) - 7; 108 int yoffset = ((buf[i] >> 4)) - 7; 109 cmv_motcomp(s->frame.data[0], s->frame.linesize[0], 110 s->last_frame.data[0], s->last_frame.linesize[0], 111 x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height); 112 } 113 i++; 114 } 115} 116 117static void cmv_process_header(CmvContext *s, const uint8_t *buf, const uint8_t *buf_end) 118{ 119 int pal_start, pal_count, i; 120 121 if(buf_end - buf < 16) { 122 av_log(s->avctx, AV_LOG_WARNING, "truncated header\n"); 123 return; 124 } 125 126 s->width = AV_RL16(&buf[4]); 127 s->height = AV_RL16(&buf[6]); 128 if (s->avctx->width!=s->width || s->avctx->height!=s->height) 129 avcodec_set_dimensions(s->avctx, s->width, s->height); 130 131 s->avctx->time_base.num = 1; 132 s->avctx->time_base.den = AV_RL16(&buf[10]); 133 134 pal_start = AV_RL16(&buf[12]); 135 pal_count = AV_RL16(&buf[14]); 136 137 buf += 16; 138 for (i=pal_start; i<pal_start+pal_count && i<AVPALETTE_COUNT && buf_end - buf >= 3; i++) { 139 s->palette[i] = AV_RB24(buf); 140 buf += 3; 141 } 142} 143 144#define EA_PREAMBLE_SIZE 8 145#define MVIh_TAG MKTAG('M', 'V', 'I', 'h') 146 147static int cmv_decode_frame(AVCodecContext *avctx, 148 void *data, int *data_size, 149 AVPacket *avpkt) 150{ 151 const uint8_t *buf = avpkt->data; 152 int buf_size = avpkt->size; 153 CmvContext *s = avctx->priv_data; 154 const uint8_t *buf_end = buf + buf_size; 155 156 if (buf_end - buf < EA_PREAMBLE_SIZE) 157 return AVERROR_INVALIDDATA; 158 159 if (AV_RL32(buf)==MVIh_TAG||AV_RB32(buf)==MVIh_TAG) { 160 cmv_process_header(s, buf+EA_PREAMBLE_SIZE, buf_end); 161 return buf_size; 162 } 163 164 if (av_image_check_size(s->width, s->height, 0, s->avctx)) 165 return -1; 166 167 /* shuffle */ 168 if (s->last2_frame.data[0]) 169 avctx->release_buffer(avctx, &s->last2_frame); 170 FFSWAP(AVFrame, s->last_frame, s->last2_frame); 171 FFSWAP(AVFrame, s->frame, s->last_frame); 172 173 s->frame.reference = 1; 174 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; 175 if (avctx->get_buffer(avctx, &s->frame)<0) { 176 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 177 return -1; 178 } 179 180 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); 181 182 buf += EA_PREAMBLE_SIZE; 183 if ((buf[0]&1)) { // subtype 184 cmv_decode_inter(s, buf+2, buf_end); 185 s->frame.key_frame = 0; 186 s->frame.pict_type = AV_PICTURE_TYPE_P; 187 }else{ 188 s->frame.key_frame = 1; 189 s->frame.pict_type = AV_PICTURE_TYPE_I; 190 cmv_decode_intra(s, buf+2, buf_end); 191 } 192 193 *data_size = sizeof(AVFrame); 194 *(AVFrame*)data = s->frame; 195 196 return buf_size; 197} 198 199static av_cold int cmv_decode_end(AVCodecContext *avctx){ 200 CmvContext *s = avctx->priv_data; 201 if (s->frame.data[0]) 202 s->avctx->release_buffer(avctx, &s->frame); 203 if (s->last_frame.data[0]) 204 s->avctx->release_buffer(avctx, &s->last_frame); 205 if (s->last2_frame.data[0]) 206 s->avctx->release_buffer(avctx, &s->last2_frame); 207 208 return 0; 209} 210 211AVCodec ff_eacmv_decoder = { 212 .name = "eacmv", 213 .type = AVMEDIA_TYPE_VIDEO, 214 .id = CODEC_ID_CMV, 215 .priv_data_size = sizeof(CmvContext), 216 .init = cmv_decode_init, 217 .close = cmv_decode_end, 218 .decode = cmv_decode_frame, 219 .capabilities = CODEC_CAP_DR1, 220 .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts CMV video"), 221}; 222