00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00031 #include "libavutil/common.h"
00032 #include "libavutil/intreadwrite.h"
00033 #include "libavutil/imgutils.h"
00034 #include "avcodec.h"
00035
00036 typedef struct CmvContext {
00037 AVCodecContext *avctx;
00038 AVFrame frame;
00039 AVFrame last_frame;
00040 AVFrame last2_frame;
00041 int width, height;
00042 unsigned int palette[AVPALETTE_COUNT];
00043 } CmvContext;
00044
00045 static av_cold int cmv_decode_init(AVCodecContext *avctx){
00046 CmvContext *s = avctx->priv_data;
00047 avcodec_get_frame_defaults(&s->frame);
00048 avcodec_get_frame_defaults(&s->last_frame);
00049 avcodec_get_frame_defaults(&s->last2_frame);
00050
00051 s->avctx = avctx;
00052 avctx->pix_fmt = PIX_FMT_PAL8;
00053 return 0;
00054 }
00055
00056 static void cmv_decode_intra(CmvContext * s, const uint8_t *buf, const uint8_t *buf_end){
00057 unsigned char *dst = s->frame.data[0];
00058 int i;
00059
00060 for (i=0; i < s->avctx->height && buf_end - buf >= s->avctx->width; i++) {
00061 memcpy(dst, buf, s->avctx->width);
00062 dst += s->frame.linesize[0];
00063 buf += s->avctx->width;
00064 }
00065 }
00066
00067 static void cmv_motcomp(unsigned char *dst, int dst_stride,
00068 const unsigned char *src, int src_stride,
00069 int x, int y,
00070 int xoffset, int yoffset,
00071 int width, int height){
00072 int i,j;
00073
00074 for(j=y;j<y+4;j++)
00075 for(i=x;i<x+4;i++)
00076 {
00077 if (i+xoffset>=0 && i+xoffset<width &&
00078 j+yoffset>=0 && j+yoffset<height) {
00079 dst[j*dst_stride + i] = src[(j+yoffset)*src_stride + i+xoffset];
00080 }else{
00081 dst[j*dst_stride + i] = 0;
00082 }
00083 }
00084 }
00085
00086 static void cmv_decode_inter(CmvContext * s, const uint8_t *buf, const uint8_t *buf_end){
00087 const uint8_t *raw = buf + (s->avctx->width*s->avctx->height/16);
00088 int x,y,i;
00089
00090 i = 0;
00091 for(y=0; y<s->avctx->height/4; y++)
00092 for(x=0; x<s->avctx->width/4 && buf_end - buf > i; x++) {
00093 if (buf[i]==0xFF) {
00094 unsigned char *dst = s->frame.data[0] + (y*4)*s->frame.linesize[0] + x*4;
00095 if (raw+16<buf_end && *raw==0xFF) {
00096 raw++;
00097 memcpy(dst, raw, 4);
00098 memcpy(dst+s->frame.linesize[0], raw+4, 4);
00099 memcpy(dst+2*s->frame.linesize[0], raw+8, 4);
00100 memcpy(dst+3*s->frame.linesize[0], raw+12, 4);
00101 raw+=16;
00102 }else if(raw<buf_end) {
00103 int xoffset = (*raw & 0xF) - 7;
00104 int yoffset = ((*raw >> 4)) - 7;
00105 if (s->last2_frame.data[0])
00106 cmv_motcomp(s->frame.data[0], s->frame.linesize[0],
00107 s->last2_frame.data[0], s->last2_frame.linesize[0],
00108 x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height);
00109 raw++;
00110 }
00111 }else{
00112 int xoffset = (buf[i] & 0xF) - 7;
00113 int yoffset = ((buf[i] >> 4)) - 7;
00114 if (s->last_frame.data[0])
00115 cmv_motcomp(s->frame.data[0], s->frame.linesize[0],
00116 s->last_frame.data[0], s->last_frame.linesize[0],
00117 x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height);
00118 }
00119 i++;
00120 }
00121 }
00122
00123 static void cmv_process_header(CmvContext *s, const uint8_t *buf, const uint8_t *buf_end)
00124 {
00125 int pal_start, pal_count, i;
00126
00127 if(buf_end - buf < 16) {
00128 av_log(s->avctx, AV_LOG_WARNING, "truncated header\n");
00129 return;
00130 }
00131
00132 s->width = AV_RL16(&buf[4]);
00133 s->height = AV_RL16(&buf[6]);
00134 if (s->avctx->width!=s->width || s->avctx->height!=s->height)
00135 avcodec_set_dimensions(s->avctx, s->width, s->height);
00136
00137 s->avctx->time_base.num = 1;
00138 s->avctx->time_base.den = AV_RL16(&buf[10]);
00139
00140 pal_start = AV_RL16(&buf[12]);
00141 pal_count = AV_RL16(&buf[14]);
00142
00143 buf += 16;
00144 for (i=pal_start; i<pal_start+pal_count && i<AVPALETTE_COUNT && buf_end - buf >= 3; i++) {
00145 s->palette[i] = 0xFF << 24 | AV_RB24(buf);
00146 buf += 3;
00147 }
00148 }
00149
00150 #define EA_PREAMBLE_SIZE 8
00151 #define MVIh_TAG MKTAG('M', 'V', 'I', 'h')
00152
00153 static int cmv_decode_frame(AVCodecContext *avctx,
00154 void *data, int *data_size,
00155 AVPacket *avpkt)
00156 {
00157 const uint8_t *buf = avpkt->data;
00158 int buf_size = avpkt->size;
00159 CmvContext *s = avctx->priv_data;
00160 const uint8_t *buf_end = buf + buf_size;
00161
00162 if (buf_end - buf < EA_PREAMBLE_SIZE)
00163 return AVERROR_INVALIDDATA;
00164
00165 if (AV_RL32(buf)==MVIh_TAG||AV_RB32(buf)==MVIh_TAG) {
00166 unsigned size = AV_RL32(buf + 4);
00167 cmv_process_header(s, buf+EA_PREAMBLE_SIZE, buf_end);
00168 if (size > buf_end - buf - EA_PREAMBLE_SIZE)
00169 return -1;
00170 buf += size;
00171 }
00172
00173 if (av_image_check_size(s->width, s->height, 0, s->avctx))
00174 return -1;
00175
00176
00177 if (s->last2_frame.data[0])
00178 avctx->release_buffer(avctx, &s->last2_frame);
00179 FFSWAP(AVFrame, s->last_frame, s->last2_frame);
00180 FFSWAP(AVFrame, s->frame, s->last_frame);
00181
00182 s->frame.reference = 3;
00183 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID |
00184 FF_BUFFER_HINTS_READABLE |
00185 FF_BUFFER_HINTS_PRESERVE;
00186 if (avctx->get_buffer(avctx, &s->frame)<0) {
00187 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00188 return -1;
00189 }
00190
00191 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
00192
00193 buf += EA_PREAMBLE_SIZE;
00194 if ((buf[0]&1)) {
00195 cmv_decode_inter(s, buf+2, buf_end);
00196 s->frame.key_frame = 0;
00197 s->frame.pict_type = AV_PICTURE_TYPE_P;
00198 }else{
00199 s->frame.key_frame = 1;
00200 s->frame.pict_type = AV_PICTURE_TYPE_I;
00201 cmv_decode_intra(s, buf+2, buf_end);
00202 }
00203
00204 *data_size = sizeof(AVFrame);
00205 *(AVFrame*)data = s->frame;
00206
00207 return buf_size;
00208 }
00209
00210 static av_cold int cmv_decode_end(AVCodecContext *avctx){
00211 CmvContext *s = avctx->priv_data;
00212 if (s->frame.data[0])
00213 s->avctx->release_buffer(avctx, &s->frame);
00214 if (s->last_frame.data[0])
00215 s->avctx->release_buffer(avctx, &s->last_frame);
00216 if (s->last2_frame.data[0])
00217 s->avctx->release_buffer(avctx, &s->last2_frame);
00218
00219 return 0;
00220 }
00221
00222 AVCodec ff_eacmv_decoder = {
00223 .name = "eacmv",
00224 .type = AVMEDIA_TYPE_VIDEO,
00225 .id = AV_CODEC_ID_CMV,
00226 .priv_data_size = sizeof(CmvContext),
00227 .init = cmv_decode_init,
00228 .close = cmv_decode_end,
00229 .decode = cmv_decode_frame,
00230 .capabilities = CODEC_CAP_DR1,
00231 .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts CMV video"),
00232 };