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
23 * @file libavcodec/eacmv.c
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
31 #include "libavutil/intreadwrite.h"
34 typedef struct CmvContext
{
35 AVCodecContext
*avctx
;
36 AVFrame frame
; ///< current
37 AVFrame last_frame
; ///< last
38 AVFrame last2_frame
; ///< second-last
40 unsigned int palette
[AVPALETTE_COUNT
];
43 static av_cold
int cmv_decode_init(AVCodecContext
*avctx
){
44 CmvContext
*s
= avctx
->priv_data
;
46 avctx
->pix_fmt
= PIX_FMT_PAL8
;
50 static void cmv_decode_intra(CmvContext
* s
, const uint8_t *buf
, const uint8_t *buf_end
){
51 unsigned char *dst
= s
->frame
.data
[0];
54 for (i
=0; i
< s
->avctx
->height
&& buf
+s
->avctx
->width
<=buf_end
; i
++) {
55 memcpy(dst
, buf
, s
->avctx
->width
);
56 dst
+= s
->frame
.linesize
[0];
57 buf
+= s
->avctx
->width
;
61 static void cmv_motcomp(unsigned char *dst
, int dst_stride
,
62 const unsigned char *src
, int src_stride
,
64 int xoffset
, int yoffset
,
65 int width
, int height
){
71 if (i
+xoffset
>=0 && i
+xoffset
<width
&&
72 j
+yoffset
>=0 && j
+yoffset
<height
) {
73 dst
[j
*dst_stride
+ i
] = src
[(j
+yoffset
)*src_stride
+ i
+xoffset
];
75 dst
[j
*dst_stride
+ i
] = 0;
80 static void cmv_decode_inter(CmvContext
* s
, const uint8_t *buf
, const uint8_t *buf_end
){
81 const uint8_t *raw
= buf
+ (s
->avctx
->width
*s
->avctx
->height
/16);
85 for(y
=0; y
<s
->avctx
->height
/4; y
++)
86 for(x
=0; x
<s
->avctx
->width
/4 && buf
+i
<buf_end
; x
++) {
88 unsigned char *dst
= s
->frame
.data
[0] + (y
*4)*s
->frame
.linesize
[0] + x
*4;
89 if (raw
+16<buf_end
&& *raw
==0xFF) { /* intra */
92 memcpy(dst
+s
->frame
.linesize
[0], raw
+4, 4);
93 memcpy(dst
+2*s
->frame
.linesize
[0], raw
+8, 4);
94 memcpy(dst
+3*s
->frame
.linesize
[0], raw
+12, 4);
96 }else if(raw
<buf_end
) { /* inter using second-last frame as reference */
97 int xoffset
= (*raw
& 0xF) - 7;
98 int yoffset
= ((*raw
>> 4)) - 7;
99 cmv_motcomp(s
->frame
.data
[0], s
->frame
.linesize
[0],
100 s
->last2_frame
.data
[0], s
->last2_frame
.linesize
[0],
101 x
*4, y
*4, xoffset
, yoffset
, s
->avctx
->width
, s
->avctx
->height
);
104 }else{ /* inter using last frame as reference */
105 int xoffset
= (buf
[i
] & 0xF) - 7;
106 int yoffset
= ((buf
[i
] >> 4)) - 7;
107 cmv_motcomp(s
->frame
.data
[0], s
->frame
.linesize
[0],
108 s
->last_frame
.data
[0], s
->last_frame
.linesize
[0],
109 x
*4, y
*4, xoffset
, yoffset
, s
->avctx
->width
, s
->avctx
->height
);
115 static void cmv_process_header(CmvContext
*s
, const uint8_t *buf
, const uint8_t *buf_end
)
117 int pal_start
, pal_count
, i
;
119 if(buf
+16>=buf_end
) {
120 av_log(s
->avctx
, AV_LOG_WARNING
, "truncated header\n");
124 s
->width
= AV_RL16(&buf
[4]);
125 s
->height
= AV_RL16(&buf
[6]);
126 if (s
->avctx
->width
!=s
->width
|| s
->avctx
->height
!=s
->height
)
127 avcodec_set_dimensions(s
->avctx
, s
->width
, s
->height
);
129 s
->avctx
->time_base
.num
= 1;
130 s
->avctx
->time_base
.den
= AV_RL16(&buf
[10]);
132 pal_start
= AV_RL16(&buf
[12]);
133 pal_count
= AV_RL16(&buf
[14]);
136 for (i
=pal_start
; i
<pal_start
+pal_count
&& i
<AVPALETTE_COUNT
&& buf
+2<buf_end
; i
++) {
137 s
->palette
[i
] = AV_RB24(buf
);
142 #define EA_PREAMBLE_SIZE 8
143 #define MVIh_TAG MKTAG('M', 'V', 'I', 'h')
145 static int cmv_decode_frame(AVCodecContext
*avctx
,
146 void *data
, int *data_size
,
149 const uint8_t *buf
= avpkt
->data
;
150 int buf_size
= avpkt
->size
;
151 CmvContext
*s
= avctx
->priv_data
;
152 const uint8_t *buf_end
= buf
+ buf_size
;
154 if (AV_RL32(buf
)==MVIh_TAG
||AV_RB32(buf
)==MVIh_TAG
) {
155 cmv_process_header(s
, buf
+EA_PREAMBLE_SIZE
, buf_end
);
159 if (avcodec_check_dimensions(s
->avctx
, s
->width
, s
->height
))
163 if (s
->last2_frame
.data
[0])
164 avctx
->release_buffer(avctx
, &s
->last2_frame
);
165 FFSWAP(AVFrame
, s
->last_frame
, s
->last2_frame
);
166 FFSWAP(AVFrame
, s
->frame
, s
->last_frame
);
168 s
->frame
.reference
= 1;
169 s
->frame
.buffer_hints
= FF_BUFFER_HINTS_VALID
;
170 if (avctx
->get_buffer(avctx
, &s
->frame
)<0) {
171 av_log(avctx
, AV_LOG_ERROR
, "get_buffer() failed\n");
175 memcpy(s
->frame
.data
[1], s
->palette
, AVPALETTE_SIZE
);
177 buf
+= EA_PREAMBLE_SIZE
;
178 if ((buf
[0]&1)) { // subtype
179 cmv_decode_inter(s
, buf
+2, buf_end
);
180 s
->frame
.key_frame
= 0;
181 s
->frame
.pict_type
= FF_P_TYPE
;
183 s
->frame
.key_frame
= 1;
184 s
->frame
.pict_type
= FF_I_TYPE
;
185 cmv_decode_intra(s
, buf
+2, buf_end
);
188 *data_size
= sizeof(AVFrame
);
189 *(AVFrame
*)data
= s
->frame
;
194 static av_cold
int cmv_decode_end(AVCodecContext
*avctx
){
195 CmvContext
*s
= avctx
->priv_data
;
196 if (s
->frame
.data
[0])
197 s
->avctx
->release_buffer(avctx
, &s
->frame
);
198 if (s
->last_frame
.data
[0])
199 s
->avctx
->release_buffer(avctx
, &s
->last_frame
);
200 if (s
->last2_frame
.data
[0])
201 s
->avctx
->release_buffer(avctx
, &s
->last2_frame
);
206 AVCodec eacmv_decoder
= {
216 .long_name
= NULL_IF_CONFIG_SMALL("Electronic Arts CMV video"),