Mercurial > libavcodec.hg
annotate yop.c @ 12494:94eaea836bf4 libavcodec
Check avctx width/height more thoroughly (e.g. all values 0 except width would
have been accepted before).
Also do not fail if they are invalid but instead override them to 0.
This allows decoding e.g. MPEG video when only the container values are corrupted.
For encoding a value of 0,0 of course makes no sense, but was allowed
through before and will be caught by an extra check in the encode function.
author | reimar |
---|---|
date | Wed, 15 Sep 2010 04:46:55 +0000 |
parents | ffb3668ff7af |
children |
rev | line source |
---|---|
11553 | 1 /** |
11644
7dd2a45249a9
Remove explicit filename from Doxygen @file commands.
diego
parents:
11560
diff
changeset
|
2 * @file |
11553 | 3 * Psygnosis YOP decoder |
4 * | |
5 * Copyright (C) 2010 Mohamed Naufal Basheer <naufal11@gmail.com> | |
6 * derived from the code by | |
7 * Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com> | |
8 * | |
9 * This file is part of FFmpeg. | |
10 * | |
11 * FFmpeg is free software; you can redistribute it and/or | |
12 * modify it under the terms of the GNU Lesser General Public | |
13 * License as published by the Free Software Foundation; either | |
14 * version 2.1 of the License, or (at your option) any later version. | |
15 * | |
16 * FFmpeg is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 * Lesser General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU Lesser General Public | |
22 * License along with FFmpeg; if not, write to the Free Software | |
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 */ | |
25 | |
26 #include "libavutil/intreadwrite.h" | |
12372
914f484bb476
Remove use of the deprecated function avcodec_check_dimensions(), use
stefano
parents:
12024
diff
changeset
|
27 #include "libavcore/imgutils.h" |
11553 | 28 |
29 #include "avcodec.h" | |
30 #include "get_bits.h" | |
31 | |
32 typedef struct YopDecContext { | |
33 AVFrame frame; | |
34 AVCodecContext *avctx; | |
35 | |
36 int num_pal_colors; | |
37 int first_color[2]; | |
38 int frame_data_length; | |
39 int row_pos; | |
40 | |
41 uint8_t *low_nibble; | |
42 uint8_t *srcptr; | |
43 uint8_t *dstptr; | |
44 uint8_t *dstbuf; | |
45 } YopDecContext; | |
46 | |
47 // These tables are taken directly from: | |
48 // http://wiki.multimedia.cx/index.php?title=Psygnosis_YOP | |
49 | |
50 /** | |
51 * Lookup table for painting macroblocks. Bytes 0-2 of each entry contain | |
52 * the macroblock positions to be painted (taken as (0, B0, B1, B2)). | |
53 * Byte 3 contains the number of bytes consumed on the input, | |
54 * equal to max(bytes 0-2) + 1. | |
55 */ | |
56 static const uint8_t paint_lut[15][4] = | |
57 {{1, 2, 3, 4}, {1, 2, 0, 3}, | |
58 {1, 2, 1, 3}, {1, 2, 2, 3}, | |
59 {1, 0, 2, 3}, {1, 0, 0, 2}, | |
60 {1, 0, 1, 2}, {1, 1, 2, 3}, | |
61 {0, 1, 2, 3}, {0, 1, 0, 2}, | |
62 {1, 1, 0, 2}, {0, 1, 1, 2}, | |
63 {0, 0, 1, 2}, {0, 0, 0, 1}, | |
64 {1, 1, 1, 2}, | |
65 }; | |
66 | |
67 /** | |
68 * Lookup table for copying macroblocks. Each entry contains the respective | |
69 * x and y pixel offset for the copy source. | |
70 */ | |
71 static const int8_t motion_vector[16][2] = | |
72 {{-4, -4}, {-2, -4}, | |
73 { 0, -4}, { 2, -4}, | |
74 {-4, -2}, {-4, 0}, | |
75 {-3, -3}, {-1, -3}, | |
76 { 1, -3}, { 3, -3}, | |
77 {-3, -1}, {-2, -2}, | |
78 { 0, -2}, { 2, -2}, | |
79 { 4, -2}, {-2, 0}, | |
80 }; | |
81 | |
82 static av_cold int yop_decode_init(AVCodecContext *avctx) | |
83 { | |
84 YopDecContext *s = avctx->priv_data; | |
85 s->avctx = avctx; | |
86 | |
87 if (avctx->width & 1 || avctx->height & 1 || | |
12462
ffb3668ff7af
Use new imgutils.h API names, fix deprecation warnings.
stefano
parents:
12372
diff
changeset
|
88 av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) { |
11553 | 89 av_log(avctx, AV_LOG_ERROR, "YOP has invalid dimensions\n"); |
90 return -1; | |
91 } | |
92 | |
93 avctx->pix_fmt = PIX_FMT_PAL8; | |
94 | |
95 s->num_pal_colors = avctx->extradata[0]; | |
96 s->first_color[0] = avctx->extradata[1]; | |
97 s->first_color[1] = avctx->extradata[2]; | |
98 | |
99 if (s->num_pal_colors + s->first_color[0] > 256 || | |
100 s->num_pal_colors + s->first_color[1] > 256) { | |
101 av_log(avctx, AV_LOG_ERROR, | |
102 "YOP: palette parameters invalid, header probably corrupt\n"); | |
103 return AVERROR_INVALIDDATA; | |
104 } | |
105 | |
106 return 0; | |
107 } | |
108 | |
109 static av_cold int yop_decode_close(AVCodecContext *avctx) | |
110 { | |
111 YopDecContext *s = avctx->priv_data; | |
112 if (s->frame.data[0]) | |
113 avctx->release_buffer(avctx, &s->frame); | |
114 return 0; | |
115 } | |
116 | |
117 /** | |
12024 | 118 * Paint a macroblock using the pattern in paint_lut. |
11553 | 119 * @param s codec context |
120 * @param tag the tag that was in the nibble | |
121 */ | |
122 static void yop_paint_block(YopDecContext *s, int tag) | |
123 { | |
124 s->dstptr[0] = s->srcptr[0]; | |
125 s->dstptr[1] = s->srcptr[paint_lut[tag][0]]; | |
126 s->dstptr[s->frame.linesize[0]] = s->srcptr[paint_lut[tag][1]]; | |
127 s->dstptr[s->frame.linesize[0] + 1] = s->srcptr[paint_lut[tag][2]]; | |
128 | |
129 // The number of src bytes consumed is in the last part of the lut entry. | |
130 s->srcptr += paint_lut[tag][3]; | |
131 } | |
132 | |
133 /** | |
12024 | 134 * Copy a previously painted macroblock to the current_block. |
11553 | 135 * @param copy_tag the tag that was in the nibble |
136 */ | |
137 static int yop_copy_previous_block(YopDecContext *s, int copy_tag) | |
138 { | |
139 uint8_t *bufptr; | |
140 | |
141 // Calculate position for the copy source | |
142 bufptr = s->dstptr + motion_vector[copy_tag][0] + | |
143 s->frame.linesize[0] * motion_vector[copy_tag][1]; | |
144 if (bufptr < s->dstbuf) { | |
145 av_log(s->avctx, AV_LOG_ERROR, | |
146 "YOP: cannot decode, file probably corrupt\n"); | |
147 return AVERROR_INVALIDDATA; | |
148 } | |
149 | |
150 s->dstptr[0] = bufptr[0]; | |
151 s->dstptr[1] = bufptr[1]; | |
152 s->dstptr[s->frame.linesize[0]] = bufptr[s->frame.linesize[0]]; | |
153 s->dstptr[s->frame.linesize[0] + 1] = bufptr[s->frame.linesize[0] + 1]; | |
154 | |
155 return 0; | |
156 } | |
157 | |
158 /** | |
12024 | 159 * Return the next nibble in sequence, consuming a new byte on the input |
11553 | 160 * only if necessary. |
161 */ | |
162 static uint8_t yop_get_next_nibble(YopDecContext *s) | |
163 { | |
164 int ret; | |
165 | |
166 if (s->low_nibble) { | |
167 ret = *s->low_nibble & 0xf; | |
168 s->low_nibble = NULL; | |
169 }else { | |
170 s->low_nibble = s->srcptr++; | |
171 ret = *s->low_nibble >> 4; | |
172 } | |
173 return ret; | |
174 } | |
175 | |
176 /** | |
12024 | 177 * Take s->dstptr to the next macroblock in sequence. |
11553 | 178 */ |
179 static void yop_next_macroblock(YopDecContext *s) | |
180 { | |
181 // If we are advancing to the next row of macroblocks | |
182 if (s->row_pos == s->frame.linesize[0] - 2) { | |
183 s->dstptr += s->frame.linesize[0]; | |
184 s->row_pos = 0; | |
185 }else { | |
186 s->row_pos += 2; | |
187 } | |
188 s->dstptr += 2; | |
189 } | |
190 | |
191 static int yop_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |
192 AVPacket *avpkt) | |
193 { | |
194 YopDecContext *s = avctx->priv_data; | |
195 int tag, firstcolor, is_odd_frame; | |
196 int ret, i; | |
197 uint32_t *palette; | |
198 | |
199 if (s->frame.data[0]) | |
200 avctx->release_buffer(avctx, &s->frame); | |
201 | |
202 ret = avctx->get_buffer(avctx, &s->frame); | |
203 if (ret < 0) { | |
204 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
205 return ret; | |
206 } | |
207 | |
208 s->frame.linesize[0] = avctx->width; | |
209 | |
210 s->dstbuf = s->frame.data[0]; | |
211 s->dstptr = s->frame.data[0]; | |
212 s->srcptr = avpkt->data + 4; | |
213 s->row_pos = 0; | |
214 s->low_nibble = NULL; | |
215 | |
216 is_odd_frame = avpkt->data[0]; | |
217 firstcolor = s->first_color[is_odd_frame]; | |
218 palette = (uint32_t *)s->frame.data[1]; | |
219 | |
220 for (i = 0; i < s->num_pal_colors; i++, s->srcptr += 3) | |
221 palette[i + firstcolor] = (s->srcptr[0] << 18) | | |
222 (s->srcptr[1] << 10) | | |
223 (s->srcptr[2] << 2); | |
224 | |
225 s->frame.palette_has_changed = 1; | |
226 | |
227 while (s->dstptr - s->dstbuf < | |
228 avctx->width * avctx->height && | |
229 s->srcptr - avpkt->data < avpkt->size) { | |
230 | |
231 tag = yop_get_next_nibble(s); | |
232 | |
233 if (tag != 0xf) { | |
234 yop_paint_block(s, tag); | |
235 }else { | |
236 tag = yop_get_next_nibble(s); | |
237 ret = yop_copy_previous_block(s, tag); | |
238 if (ret < 0) { | |
239 avctx->release_buffer(avctx, &s->frame); | |
240 return ret; | |
241 } | |
242 } | |
243 yop_next_macroblock(s); | |
244 } | |
245 | |
246 *data_size = sizeof(AVFrame); | |
247 *(AVFrame *) data = s->frame; | |
248 return avpkt->size; | |
249 } | |
250 | |
251 AVCodec yop_decoder = { | |
252 "yop", | |
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
11553
diff
changeset
|
253 AVMEDIA_TYPE_VIDEO, |
11553 | 254 CODEC_ID_YOP, |
255 sizeof(YopDecContext), | |
256 yop_decode_init, | |
257 NULL, | |
258 yop_decode_close, | |
259 yop_decode_frame, | |
260 .long_name = NULL_IF_CONFIG_SMALL("Psygnosis YOP Video"), | |
261 }; |