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 frame
; ///< current
40 AVFrame last_frame
; ///< last
41 AVFrame last2_frame
; ///< second-last
43 unsigned int palette
[AVPALETTE_COUNT
];
46 static av_cold
int cmv_decode_init(AVCodecContext
*avctx
){
47 CmvContext
*s
= avctx
->priv_data
;
49 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
53 static void cmv_decode_intra(CmvContext
* s
, const uint8_t *buf
, const uint8_t *buf_end
){
54 unsigned char *dst
= s
->frame
.data
[0];
57 for (i
=0; i
< s
->avctx
->height
&& buf_end
- buf
>= s
->avctx
->width
; i
++) {
58 memcpy(dst
, buf
, s
->avctx
->width
);
59 dst
+= s
->frame
.linesize
[0];
60 buf
+= s
->avctx
->width
;
64 static void cmv_motcomp(unsigned char *dst
, int dst_stride
,
65 const unsigned char *src
, int src_stride
,
67 int xoffset
, int yoffset
,
68 int width
, int height
){
74 if (i
+xoffset
>=0 && i
+xoffset
<width
&&
75 j
+yoffset
>=0 && j
+yoffset
<height
) {
76 dst
[j
*dst_stride
+ i
] = src
[(j
+yoffset
)*src_stride
+ i
+xoffset
];
78 dst
[j
*dst_stride
+ i
] = 0;
83 static void cmv_decode_inter(CmvContext
* s
, const uint8_t *buf
, const uint8_t *buf_end
){
84 const uint8_t *raw
= buf
+ (s
->avctx
->width
*s
->avctx
->height
/16);
88 for(y
=0; y
<s
->avctx
->height
/4; y
++)
89 for(x
=0; x
<s
->avctx
->width
/4 && buf_end
- buf
> i
; x
++) {
91 unsigned char *dst
= s
->frame
.data
[0] + (y
*4)*s
->frame
.linesize
[0] + x
*4;
92 if (raw
+16<buf_end
&& *raw
==0xFF) { /* intra */
95 memcpy(dst
+s
->frame
.linesize
[0], raw
+4, 4);
96 memcpy(dst
+2*s
->frame
.linesize
[0], raw
+8, 4);
97 memcpy(dst
+3*s
->frame
.linesize
[0], raw
+12, 4);
99 }else if(raw
<buf_end
) { /* inter using second-last frame as reference */
100 int xoffset
= (*raw
& 0xF) - 7;
101 int yoffset
= ((*raw
>> 4)) - 7;
102 if (s
->last2_frame
.data
[0])
103 cmv_motcomp(s
->frame
.data
[0], s
->frame
.linesize
[0],
104 s
->last2_frame
.data
[0], s
->last2_frame
.linesize
[0],
105 x
*4, y
*4, xoffset
, yoffset
, s
->avctx
->width
, s
->avctx
->height
);
108 }else{ /* inter using last frame as reference */
109 int xoffset
= (buf
[i
] & 0xF) - 7;
110 int yoffset
= ((buf
[i
] >> 4)) - 7;
111 cmv_motcomp(s
->frame
.data
[0], s
->frame
.linesize
[0],
112 s
->last_frame
.data
[0], s
->last_frame
.linesize
[0],
113 x
*4, y
*4, xoffset
, yoffset
, s
->avctx
->width
, s
->avctx
->height
);
119 static void cmv_process_header(CmvContext
*s
, const uint8_t *buf
, const uint8_t *buf_end
)
121 int pal_start
, pal_count
, i
;
123 if(buf_end
- buf
< 16) {
124 av_log(s
->avctx
, AV_LOG_WARNING
, "truncated header\n");
128 s
->width
= AV_RL16(&buf
[4]);
129 s
->height
= AV_RL16(&buf
[6]);
130 if (s
->avctx
->width
!=s
->width
|| s
->avctx
->height
!=s
->height
)
131 avcodec_set_dimensions(s
->avctx
, s
->width
, s
->height
);
133 s
->avctx
->time_base
.num
= 1;
134 s
->avctx
->time_base
.den
= AV_RL16(&buf
[10]);
136 pal_start
= AV_RL16(&buf
[12]);
137 pal_count
= AV_RL16(&buf
[14]);
140 for (i
=pal_start
; i
<pal_start
+pal_count
&& i
<AVPALETTE_COUNT
&& buf_end
- buf
>= 3; i
++) {
141 s
->palette
[i
] = AV_RB24(buf
);
146 #define EA_PREAMBLE_SIZE 8
147 #define MVIh_TAG MKTAG('M', 'V', 'I', 'h')
149 static int cmv_decode_frame(AVCodecContext
*avctx
,
150 void *data
, int *got_frame
,
153 const uint8_t *buf
= avpkt
->data
;
154 int buf_size
= avpkt
->size
;
155 CmvContext
*s
= avctx
->priv_data
;
156 const uint8_t *buf_end
= buf
+ buf_size
;
158 if (buf_end
- buf
< EA_PREAMBLE_SIZE
)
159 return AVERROR_INVALIDDATA
;
161 if (AV_RL32(buf
)==MVIh_TAG
||AV_RB32(buf
)==MVIh_TAG
) {
162 cmv_process_header(s
, buf
+EA_PREAMBLE_SIZE
, buf_end
);
166 if (av_image_check_size(s
->width
, s
->height
, 0, s
->avctx
))
170 if (s
->last2_frame
.data
[0])
171 avctx
->release_buffer(avctx
, &s
->last2_frame
);
172 FFSWAP(AVFrame
, s
->last_frame
, s
->last2_frame
);
173 FFSWAP(AVFrame
, s
->frame
, s
->last_frame
);
175 s
->frame
.reference
= 1;
176 s
->frame
.buffer_hints
= FF_BUFFER_HINTS_VALID
;
177 if (ff_get_buffer(avctx
, &s
->frame
)<0) {
178 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
182 memcpy(s
->frame
.data
[1], s
->palette
, AVPALETTE_SIZE
);
184 buf
+= EA_PREAMBLE_SIZE
;
185 if ((buf
[0]&1)) { // subtype
186 cmv_decode_inter(s
, buf
+2, buf_end
);
187 s
->frame
.key_frame
= 0;
188 s
->frame
.pict_type
= AV_PICTURE_TYPE_P
;
190 s
->frame
.key_frame
= 1;
191 s
->frame
.pict_type
= AV_PICTURE_TYPE_I
;
192 cmv_decode_intra(s
, buf
+2, buf_end
);
196 *(AVFrame
*)data
= s
->frame
;
201 static av_cold
int cmv_decode_end(AVCodecContext
*avctx
){
202 CmvContext
*s
= avctx
->priv_data
;
203 if (s
->frame
.data
[0])
204 s
->avctx
->release_buffer(avctx
, &s
->frame
);
205 if (s
->last_frame
.data
[0])
206 s
->avctx
->release_buffer(avctx
, &s
->last_frame
);
207 if (s
->last2_frame
.data
[0])
208 s
->avctx
->release_buffer(avctx
, &s
->last2_frame
);
213 AVCodec ff_eacmv_decoder
= {
215 .type
= AVMEDIA_TYPE_VIDEO
,
216 .id
= AV_CODEC_ID_CMV
,
217 .priv_data_size
= sizeof(CmvContext
),
218 .init
= cmv_decode_init
,
219 .close
= cmv_decode_end
,
220 .decode
= cmv_decode_frame
,
221 .capabilities
= CODEC_CAP_DR1
,
222 .long_name
= NULL_IF_CONFIG_SMALL("Electronic Arts CMV video"),