2 * Electronic Arts CMV Video Decoder
3 * Copyright (c) 2007-2008 Peter Ross
5 * This file is part of FFmpeg.
7 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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 (suxen_drol at hotmail dot com)
27 * Technical details here:
28 * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_CMV
33 typedef struct CmvContext
{
34 AVCodecContext
*avctx
;
35 AVFrame frame
; ///< current
36 AVFrame last_frame
; ///< last
37 AVFrame last2_frame
; ///< second-last
39 unsigned int palette
[AVPALETTE_COUNT
];
42 static av_cold
int cmv_decode_init(AVCodecContext
*avctx
){
43 CmvContext
*s
= avctx
->priv_data
;
45 avctx
->pix_fmt
= PIX_FMT_PAL8
;
49 static void cmv_decode_intra(CmvContext
* s
, const uint8_t *buf
, const uint8_t *buf_end
){
50 unsigned char *dst
= s
->frame
.data
[0];
53 for (i
=0; i
< s
->avctx
->height
&& buf
+s
->avctx
->width
<=buf_end
; i
++) {
54 memcpy(dst
, buf
, s
->avctx
->width
);
55 dst
+= s
->frame
.linesize
[0];
56 buf
+= s
->avctx
->width
;
60 static void cmv_motcomp(unsigned char *dst
, int dst_stride
,
61 const unsigned char *src
, int src_stride
,
63 int xoffset
, int yoffset
,
64 int width
, int height
){
70 if (i
+xoffset
>=0 && i
+xoffset
<width
&&
71 j
+yoffset
>=0 && j
+yoffset
<height
) {
72 dst
[j
*dst_stride
+ i
] = src
[(j
+yoffset
)*src_stride
+ i
+xoffset
];
74 dst
[j
*dst_stride
+ i
] = 0;
79 static void cmv_decode_inter(CmvContext
* s
, const uint8_t *buf
, const uint8_t *buf_end
){
80 const uint8_t *raw
= buf
+ (s
->avctx
->width
*s
->avctx
->height
/16);
84 for(y
=0; y
<s
->avctx
->height
/4; y
++)
85 for(x
=0; x
<s
->avctx
->width
/4 && buf
+i
<buf_end
; x
++) {
87 unsigned char *dst
= s
->frame
.data
[0] + (y
*4)*s
->frame
.linesize
[0] + x
*4;
88 if (raw
+16<buf_end
&& *raw
==0xFF) { /* intra */
91 memcpy(dst
+s
->frame
.linesize
[0], raw
+4, 4);
92 memcpy(dst
+2*s
->frame
.linesize
[0], raw
+8, 4);
93 memcpy(dst
+3*s
->frame
.linesize
[0], raw
+12, 4);
95 }else if(raw
<buf_end
) { /* inter using second-last frame as reference */
96 int xoffset
= (*raw
& 0xF) - 7;
97 int yoffset
= ((*raw
>> 4)) - 7;
98 cmv_motcomp(s
->frame
.data
[0], s
->frame
.linesize
[0],
99 s
->last2_frame
.data
[0], s
->last2_frame
.linesize
[0],
100 x
*4, y
*4, xoffset
, yoffset
, s
->avctx
->width
, s
->avctx
->height
);
103 }else{ /* inter using last frame as reference */
104 int xoffset
= (buf
[i
] & 0xF) - 7;
105 int yoffset
= ((buf
[i
] >> 4)) - 7;
106 cmv_motcomp(s
->frame
.data
[0], s
->frame
.linesize
[0],
107 s
->last_frame
.data
[0], s
->last_frame
.linesize
[0],
108 x
*4, y
*4, xoffset
, yoffset
, s
->avctx
->width
, s
->avctx
->height
);
114 static void cmv_process_header(CmvContext
*s
, const uint8_t *buf
, const uint8_t *buf_end
)
116 int pal_start
, pal_count
, i
;
118 if(buf
+16>=buf_end
) {
119 av_log(s
->avctx
, AV_LOG_WARNING
, "truncated header\n");
123 s
->width
= AV_RL16(&buf
[4]);
124 s
->height
= AV_RL16(&buf
[6]);
125 if (s
->avctx
->width
!=s
->width
|| s
->avctx
->height
!=s
->height
)
126 avcodec_set_dimensions(s
->avctx
, s
->width
, s
->height
);
128 s
->avctx
->time_base
.num
= 1;
129 s
->avctx
->time_base
.den
= AV_RL16(&buf
[10]);
131 pal_start
= AV_RL16(&buf
[12]);
132 pal_count
= AV_RL16(&buf
[14]);
135 for (i
=pal_start
; i
<pal_start
+pal_count
&& i
<AVPALETTE_COUNT
&& buf
+2<buf_end
; i
++) {
136 s
->palette
[i
] = AV_RB24(buf
);
141 #define EA_PREAMBLE_SIZE 8
142 #define MVIh_TAG MKTAG('M', 'V', 'I', 'h')
144 static int cmv_decode_frame(AVCodecContext
*avctx
,
145 void *data
, int *data_size
,
146 const uint8_t *buf
, int buf_size
)
148 CmvContext
*s
= avctx
->priv_data
;
149 const uint8_t *buf_end
= buf
+ buf_size
;
151 if (AV_RL32(buf
)==MVIh_TAG
||AV_RB32(buf
)==MVIh_TAG
) {
152 cmv_process_header(s
, buf
+EA_PREAMBLE_SIZE
, buf_end
);
156 if (avcodec_check_dimensions(s
->avctx
, s
->width
, s
->height
))
160 if (s
->last2_frame
.data
[0])
161 avctx
->release_buffer(avctx
, &s
->last2_frame
);
162 FFSWAP(AVFrame
, s
->last_frame
, s
->last2_frame
);
163 FFSWAP(AVFrame
, s
->frame
, s
->last_frame
);
165 s
->frame
.reference
= 1;
166 s
->frame
.buffer_hints
= FF_BUFFER_HINTS_VALID
;
167 if (avctx
->get_buffer(avctx
, &s
->frame
)<0) {
168 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
172 memcpy(s
->frame
.data
[1], s
->palette
, AVPALETTE_SIZE
);
174 buf
+= EA_PREAMBLE_SIZE
;
175 if ((buf
[0]&1)) { // subtype
176 cmv_decode_inter(s
, buf
+2, buf_end
);
177 s
->frame
.key_frame
= 0;
178 s
->frame
.pict_type
= FF_P_TYPE
;
180 s
->frame
.key_frame
= 1;
181 s
->frame
.pict_type
= FF_I_TYPE
;
182 cmv_decode_intra(s
, buf
+2, buf_end
);
185 *data_size
= sizeof(AVFrame
);
186 *(AVFrame
*)data
= s
->frame
;
191 static av_cold
int cmv_decode_end(AVCodecContext
*avctx
){
192 CmvContext
*s
= avctx
->priv_data
;
193 if (s
->frame
.data
[0])
194 s
->avctx
->release_buffer(avctx
, &s
->frame
);
195 if (s
->last_frame
.data
[0])
196 s
->avctx
->release_buffer(avctx
, &s
->last_frame
);
197 if (s
->last2_frame
.data
[0])
198 s
->avctx
->release_buffer(avctx
, &s
->last2_frame
);
203 AVCodec eacmv_decoder
= {
213 .long_name
= NULL_IF_CONFIG_SMALL("Electronic Arts CMV Video"),