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