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