Mercurial > libavcodec.hg
annotate eacmv.c @ 9077:ad7fd7a40717 libavcodec
Do not read uninitialized buffer, no matter if it will be multiplied by
zero later. This should fix some valgrind warnings and hopefully FATE
ra144 test on ARM.
author | vitor |
---|---|
date | Sun, 01 Mar 2009 11:14:21 +0000 |
parents | e9d9d946f213 |
children | bf274494b66e |
rev | line source |
---|---|
7222 | 1 /* |
2 * Electronic Arts CMV Video Decoder | |
3 * Copyright (c) 2007-2008 Peter Ross | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
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. | |
11 * | |
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. | |
16 * | |
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 | |
20 */ | |
21 | |
22 /** | |
8718
e9d9d946f213
Use full internal pathname in doxygen @file directives.
diego
parents:
8573
diff
changeset
|
23 * @file libavcodec/eacmv.c |
7222 | 24 * Electronic Arts CMV Video Decoder |
25 * by Peter Ross (suxen_drol at hotmail dot com) | |
26 * | |
27 * Technical details here: | |
28 * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_CMV | |
29 */ | |
30 | |
8573
2acf0ae7b041
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
7222
diff
changeset
|
31 #include "libavutil/intreadwrite.h" |
7222 | 32 #include "avcodec.h" |
33 | |
34 typedef struct CmvContext { | |
35 AVCodecContext *avctx; | |
36 AVFrame frame; ///< current | |
37 AVFrame last_frame; ///< last | |
38 AVFrame last2_frame; ///< second-last | |
39 int width, height; | |
40 unsigned int palette[AVPALETTE_COUNT]; | |
41 } CmvContext; | |
42 | |
43 static av_cold int cmv_decode_init(AVCodecContext *avctx){ | |
44 CmvContext *s = avctx->priv_data; | |
45 s->avctx = avctx; | |
46 avctx->pix_fmt = PIX_FMT_PAL8; | |
47 return 0; | |
48 } | |
49 | |
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]; | |
52 int i; | |
53 | |
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; | |
58 } | |
59 } | |
60 | |
61 static void cmv_motcomp(unsigned char *dst, int dst_stride, | |
62 const unsigned char *src, int src_stride, | |
63 int x, int y, | |
64 int xoffset, int yoffset, | |
65 int width, int height){ | |
66 int i,j; | |
67 | |
68 for(j=y;j<y+4;j++) | |
69 for(i=x;i<x+4;i++) | |
70 { | |
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]; | |
74 }else{ | |
75 dst[j*dst_stride + i] = 0; | |
76 } | |
77 } | |
78 } | |
79 | |
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); | |
82 int x,y,i; | |
83 | |
84 i = 0; | |
85 for(y=0; y<s->avctx->height/4; y++) | |
86 for(x=0; x<s->avctx->width/4 && buf+i<buf_end; x++) { | |
87 if (buf[i]==0xFF) { | |
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 */ | |
90 raw++; | |
91 memcpy(dst, raw, 4); | |
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); | |
95 raw+=16; | |
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); | |
102 raw++; | |
103 } | |
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); | |
110 } | |
111 i++; | |
112 } | |
113 } | |
114 | |
115 static void cmv_process_header(CmvContext *s, const uint8_t *buf, const uint8_t *buf_end) | |
116 { | |
117 int pal_start, pal_count, i; | |
118 | |
119 if(buf+16>=buf_end) { | |
120 av_log(s->avctx, AV_LOG_WARNING, "truncated header\n"); | |
121 return; | |
122 } | |
123 | |
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); | |
128 | |
129 s->avctx->time_base.num = 1; | |
130 s->avctx->time_base.den = AV_RL16(&buf[10]); | |
131 | |
132 pal_start = AV_RL16(&buf[12]); | |
133 pal_count = AV_RL16(&buf[14]); | |
134 | |
135 buf += 16; | |
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); | |
138 buf += 3; | |
139 } | |
140 } | |
141 | |
142 #define EA_PREAMBLE_SIZE 8 | |
143 #define MVIh_TAG MKTAG('M', 'V', 'I', 'h') | |
144 | |
145 static int cmv_decode_frame(AVCodecContext *avctx, | |
146 void *data, int *data_size, | |
147 const uint8_t *buf, int buf_size) | |
148 { | |
149 CmvContext *s = avctx->priv_data; | |
150 const uint8_t *buf_end = buf + buf_size; | |
151 | |
152 if (AV_RL32(buf)==MVIh_TAG||AV_RB32(buf)==MVIh_TAG) { | |
153 cmv_process_header(s, buf+EA_PREAMBLE_SIZE, buf_end); | |
154 return buf_size; | |
155 } | |
156 | |
157 if (avcodec_check_dimensions(s->avctx, s->width, s->height)) | |
158 return -1; | |
159 | |
160 /* shuffle */ | |
161 if (s->last2_frame.data[0]) | |
162 avctx->release_buffer(avctx, &s->last2_frame); | |
163 FFSWAP(AVFrame, s->last_frame, s->last2_frame); | |
164 FFSWAP(AVFrame, s->frame, s->last_frame); | |
165 | |
166 s->frame.reference = 1; | |
167 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; | |
168 if (avctx->get_buffer(avctx, &s->frame)<0) { | |
169 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
170 return -1; | |
171 } | |
172 | |
173 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); | |
174 | |
175 buf += EA_PREAMBLE_SIZE; | |
176 if ((buf[0]&1)) { // subtype | |
177 cmv_decode_inter(s, buf+2, buf_end); | |
178 s->frame.key_frame = 0; | |
179 s->frame.pict_type = FF_P_TYPE; | |
180 }else{ | |
181 s->frame.key_frame = 1; | |
182 s->frame.pict_type = FF_I_TYPE; | |
183 cmv_decode_intra(s, buf+2, buf_end); | |
184 } | |
185 | |
186 *data_size = sizeof(AVFrame); | |
187 *(AVFrame*)data = s->frame; | |
188 | |
189 return buf_size; | |
190 } | |
191 | |
192 static av_cold int cmv_decode_end(AVCodecContext *avctx){ | |
193 CmvContext *s = avctx->priv_data; | |
194 if (s->frame.data[0]) | |
195 s->avctx->release_buffer(avctx, &s->frame); | |
196 if (s->last_frame.data[0]) | |
197 s->avctx->release_buffer(avctx, &s->last_frame); | |
198 if (s->last2_frame.data[0]) | |
199 s->avctx->release_buffer(avctx, &s->last2_frame); | |
200 | |
201 return 0; | |
202 } | |
203 | |
204 AVCodec eacmv_decoder = { | |
205 "eacmv", | |
206 CODEC_TYPE_VIDEO, | |
207 CODEC_ID_CMV, | |
208 sizeof(CmvContext), | |
209 cmv_decode_init, | |
210 NULL, | |
211 cmv_decode_end, | |
212 cmv_decode_frame, | |
213 CODEC_CAP_DR1, | |
214 .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts CMV Video"), | |
215 }; |