2 * Electronic Arts CMV Video Decoder
3 * Copyright (c) 2007-2008 Peter Ross
5 * This file is part of Libav.
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.
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.
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
24 * Electronic Arts CMV Video Decoder
25 * by Peter Ross (pross@xvid.org)
27 * Technical details here:
28 * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_CMV
31 #include "libavutil/common.h"
32 #include "libavutil/intreadwrite.h"
33 #include "libavutil/imgutils.h"
37 typedef struct CmvContext
{
38 AVCodecContext
*avctx
;
39 AVFrame
*last_frame
; ///< last
40 AVFrame
*last2_frame
; ///< second-last
42 unsigned int palette
[AVPALETTE_COUNT
];
45 static av_cold
int cmv_decode_init(AVCodecContext
*avctx
){
46 CmvContext
*s
= avctx
->priv_data
;
48 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
50 s
->last_frame
= av_frame_alloc();
51 s
->last2_frame
= av_frame_alloc();
52 if (!s
->last_frame
|| !s
->last2_frame
) {
53 av_frame_free(&s
->last_frame
);
54 av_frame_free(&s
->last2_frame
);
55 return AVERROR(ENOMEM
);
61 static void cmv_decode_intra(CmvContext
* s
, AVFrame
*frame
,
62 const uint8_t *buf
, const uint8_t *buf_end
)
64 unsigned char *dst
= frame
->data
[0];
67 for (i
=0; i
< s
->avctx
->height
&& buf_end
- buf
>= s
->avctx
->width
; i
++) {
68 memcpy(dst
, buf
, s
->avctx
->width
);
69 dst
+= frame
->linesize
[0];
70 buf
+= s
->avctx
->width
;
74 static void cmv_motcomp(unsigned char *dst
, ptrdiff_t dst_stride
,
75 const unsigned char *src
, ptrdiff_t src_stride
,
77 int xoffset
, int yoffset
,
78 int width
, int height
){
84 if (i
+xoffset
>=0 && i
+xoffset
<width
&&
85 j
+yoffset
>=0 && j
+yoffset
<height
) {
86 dst
[j
*dst_stride
+ i
] = src
[(j
+yoffset
)*src_stride
+ i
+xoffset
];
88 dst
[j
*dst_stride
+ i
] = 0;
93 static void cmv_decode_inter(CmvContext
*s
, AVFrame
*frame
, const uint8_t *buf
,
94 const uint8_t *buf_end
)
96 const uint8_t *raw
= buf
+ (s
->avctx
->width
*s
->avctx
->height
/16);
100 for(y
=0; y
<s
->avctx
->height
/4; y
++)
101 for(x
=0; x
<s
->avctx
->width
/4 && buf_end
- buf
> i
; x
++) {
103 unsigned char *dst
= frame
->data
[0] + (y
*4)*frame
->linesize
[0] + x
*4;
104 if (raw
+16<buf_end
&& *raw
==0xFF) { /* intra */
107 memcpy(dst
+ frame
->linesize
[0], raw
+4, 4);
108 memcpy(dst
+ 2 * frame
->linesize
[0], raw
+8, 4);
109 memcpy(dst
+ 3 * frame
->linesize
[0], raw
+12, 4);
111 }else if(raw
<buf_end
) { /* inter using second-last frame as reference */
112 int xoffset
= (*raw
& 0xF) - 7;
113 int yoffset
= ((*raw
>> 4)) - 7;
114 if (s
->last2_frame
->data
[0])
115 cmv_motcomp(frame
->data
[0], frame
->linesize
[0],
116 s
->last2_frame
->data
[0], s
->last2_frame
->linesize
[0],
117 x
*4, y
*4, xoffset
, yoffset
, s
->avctx
->width
, s
->avctx
->height
);
120 }else{ /* inter using last frame as reference */
121 int xoffset
= (buf
[i
] & 0xF) - 7;
122 int yoffset
= ((buf
[i
] >> 4)) - 7;
123 if (s
->last_frame
->data
[0])
124 cmv_motcomp(frame
->data
[0], frame
->linesize
[0],
125 s
->last_frame
->data
[0], s
->last_frame
->linesize
[0],
126 x
*4, y
*4, xoffset
, yoffset
, s
->avctx
->width
, s
->avctx
->height
);
132 static int cmv_process_header(CmvContext
*s
, const uint8_t *buf
, const uint8_t *buf_end
)
134 int pal_start
, pal_count
, i
, ret
, fps
;
136 if(buf_end
- buf
< 16) {
137 av_log(s
->avctx
, AV_LOG_WARNING
, "truncated header\n");
138 return AVERROR_INVALIDDATA
;
141 s
->width
= AV_RL16(&buf
[4]);
142 s
->height
= AV_RL16(&buf
[6]);
144 if (s
->width
!= s
->avctx
->width
||
145 s
->height
!= s
->avctx
->height
) {
146 av_frame_unref(s
->last_frame
);
147 av_frame_unref(s
->last2_frame
);
150 ret
= ff_set_dimensions(s
->avctx
, s
->width
, s
->height
);
154 fps
= AV_RL16(&buf
[10]);
156 s
->avctx
->framerate
= (AVRational
){ fps
, 1 };
158 pal_start
= AV_RL16(&buf
[12]);
159 pal_count
= AV_RL16(&buf
[14]);
162 for (i
=pal_start
; i
<pal_start
+pal_count
&& i
<AVPALETTE_COUNT
&& buf_end
- buf
>= 3; i
++) {
163 s
->palette
[i
] = AV_RB24(buf
);
170 #define EA_PREAMBLE_SIZE 8
171 #define MVIh_TAG MKTAG('M', 'V', 'I', 'h')
173 static int cmv_decode_frame(AVCodecContext
*avctx
,
174 void *data
, int *got_frame
,
177 const uint8_t *buf
= avpkt
->data
;
178 int buf_size
= avpkt
->size
;
179 CmvContext
*s
= avctx
->priv_data
;
180 const uint8_t *buf_end
= buf
+ buf_size
;
181 AVFrame
*frame
= data
;
184 if (buf_end
- buf
< EA_PREAMBLE_SIZE
)
185 return AVERROR_INVALIDDATA
;
187 if (AV_RL32(buf
)==MVIh_TAG
||AV_RB32(buf
)==MVIh_TAG
) {
188 ret
= cmv_process_header(s
, buf
+EA_PREAMBLE_SIZE
, buf_end
);
194 if (av_image_check_size(s
->width
, s
->height
, 0, s
->avctx
))
197 if ((ret
= ff_get_buffer(avctx
, frame
, AV_GET_BUFFER_FLAG_REF
)) < 0) {
198 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
202 memcpy(frame
->data
[1], s
->palette
, AVPALETTE_SIZE
);
204 buf
+= EA_PREAMBLE_SIZE
;
205 if ((buf
[0]&1)) { // subtype
206 cmv_decode_inter(s
, frame
, buf
+2, buf_end
);
207 frame
->key_frame
= 0;
208 frame
->pict_type
= AV_PICTURE_TYPE_P
;
210 frame
->key_frame
= 1;
211 frame
->pict_type
= AV_PICTURE_TYPE_I
;
212 cmv_decode_intra(s
, frame
, buf
+2, buf_end
);
215 av_frame_unref(s
->last2_frame
);
216 av_frame_move_ref(s
->last2_frame
, s
->last_frame
);
217 if ((ret
= av_frame_ref(s
->last_frame
, frame
)) < 0)
225 static av_cold
int cmv_decode_end(AVCodecContext
*avctx
){
226 CmvContext
*s
= avctx
->priv_data
;
228 av_frame_free(&s
->last_frame
);
229 av_frame_free(&s
->last2_frame
);
234 AVCodec ff_eacmv_decoder
= {
236 .long_name
= NULL_IF_CONFIG_SMALL("Electronic Arts CMV video"),
237 .type
= AVMEDIA_TYPE_VIDEO
,
238 .id
= AV_CODEC_ID_CMV
,
239 .priv_data_size
= sizeof(CmvContext
),
240 .init
= cmv_decode_init
,
241 .close
= cmv_decode_end
,
242 .decode
= cmv_decode_frame
,
243 .capabilities
= AV_CODEC_CAP_DR1
,