Mercurial > libavcodec.hg
annotate yop.c @ 11816:7c2369ec6faa libavcodec
ARM: check struct offsets only when they are used
The offsets differ depending on configuration, so only check them when
they will actually be used. Presently, this is when NEON is enabled.
author | mru |
---|---|
date | Wed, 02 Jun 2010 22:05:25 +0000 |
parents | 7dd2a45249a9 |
children | fdafbcef52f5 |
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" | |
27 | |
28 #include "avcodec.h" | |
29 #include "get_bits.h" | |
30 | |
31 typedef struct YopDecContext { | |
32 AVFrame frame; | |
33 AVCodecContext *avctx; | |
34 | |
35 int num_pal_colors; | |
36 int first_color[2]; | |
37 int frame_data_length; | |
38 int row_pos; | |
39 | |
40 uint8_t *low_nibble; | |
41 uint8_t *srcptr; | |
42 uint8_t *dstptr; | |
43 uint8_t *dstbuf; | |
44 } YopDecContext; | |
45 | |
46 // These tables are taken directly from: | |
47 // http://wiki.multimedia.cx/index.php?title=Psygnosis_YOP | |
48 | |
49 /** | |
50 * Lookup table for painting macroblocks. Bytes 0-2 of each entry contain | |
51 * the macroblock positions to be painted (taken as (0, B0, B1, B2)). | |
52 * Byte 3 contains the number of bytes consumed on the input, | |
53 * equal to max(bytes 0-2) + 1. | |
54 */ | |
55 static const uint8_t paint_lut[15][4] = | |
56 {{1, 2, 3, 4}, {1, 2, 0, 3}, | |
57 {1, 2, 1, 3}, {1, 2, 2, 3}, | |
58 {1, 0, 2, 3}, {1, 0, 0, 2}, | |
59 {1, 0, 1, 2}, {1, 1, 2, 3}, | |
60 {0, 1, 2, 3}, {0, 1, 0, 2}, | |
61 {1, 1, 0, 2}, {0, 1, 1, 2}, | |
62 {0, 0, 1, 2}, {0, 0, 0, 1}, | |
63 {1, 1, 1, 2}, | |
64 }; | |
65 | |
66 /** | |
67 * Lookup table for copying macroblocks. Each entry contains the respective | |
68 * x and y pixel offset for the copy source. | |
69 */ | |
70 static const int8_t motion_vector[16][2] = | |
71 {{-4, -4}, {-2, -4}, | |
72 { 0, -4}, { 2, -4}, | |
73 {-4, -2}, {-4, 0}, | |
74 {-3, -3}, {-1, -3}, | |
75 { 1, -3}, { 3, -3}, | |
76 {-3, -1}, {-2, -2}, | |
77 { 0, -2}, { 2, -2}, | |
78 { 4, -2}, {-2, 0}, | |
79 }; | |
80 | |
81 static av_cold int yop_decode_init(AVCodecContext *avctx) | |
82 { | |
83 YopDecContext *s = avctx->priv_data; | |
84 s->avctx = avctx; | |
85 | |
86 if (avctx->width & 1 || avctx->height & 1 || | |
87 avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) { | |
88 av_log(avctx, AV_LOG_ERROR, "YOP has invalid dimensions\n"); | |
89 return -1; | |
90 } | |
91 | |
92 avctx->pix_fmt = PIX_FMT_PAL8; | |
93 | |
94 s->num_pal_colors = avctx->extradata[0]; | |
95 s->first_color[0] = avctx->extradata[1]; | |
96 s->first_color[1] = avctx->extradata[2]; | |
97 | |
98 if (s->num_pal_colors + s->first_color[0] > 256 || | |
99 s->num_pal_colors + s->first_color[1] > 256) { | |
100 av_log(avctx, AV_LOG_ERROR, | |
101 "YOP: palette parameters invalid, header probably corrupt\n"); | |
102 return AVERROR_INVALIDDATA; | |
103 } | |
104 | |
105 return 0; | |
106 } | |
107 | |
108 static av_cold int yop_decode_close(AVCodecContext *avctx) | |
109 { | |
110 YopDecContext *s = avctx->priv_data; | |
111 if (s->frame.data[0]) | |
112 avctx->release_buffer(avctx, &s->frame); | |
113 return 0; | |
114 } | |
115 | |
116 /** | |
117 * Paints a macroblock using the pattern in paint_lut. | |
118 * @param s codec context | |
119 * @param tag the tag that was in the nibble | |
120 */ | |
121 static void yop_paint_block(YopDecContext *s, int tag) | |
122 { | |
123 s->dstptr[0] = s->srcptr[0]; | |
124 s->dstptr[1] = s->srcptr[paint_lut[tag][0]]; | |
125 s->dstptr[s->frame.linesize[0]] = s->srcptr[paint_lut[tag][1]]; | |
126 s->dstptr[s->frame.linesize[0] + 1] = s->srcptr[paint_lut[tag][2]]; | |
127 | |
128 // The number of src bytes consumed is in the last part of the lut entry. | |
129 s->srcptr += paint_lut[tag][3]; | |
130 } | |
131 | |
132 /** | |
133 * Copies a previously painted macroblock to the current_block. | |
134 * @param copy_tag the tag that was in the nibble | |
135 */ | |
136 static int yop_copy_previous_block(YopDecContext *s, int copy_tag) | |
137 { | |
138 uint8_t *bufptr; | |
139 | |
140 // Calculate position for the copy source | |
141 bufptr = s->dstptr + motion_vector[copy_tag][0] + | |
142 s->frame.linesize[0] * motion_vector[copy_tag][1]; | |
143 if (bufptr < s->dstbuf) { | |
144 av_log(s->avctx, AV_LOG_ERROR, | |
145 "YOP: cannot decode, file probably corrupt\n"); | |
146 return AVERROR_INVALIDDATA; | |
147 } | |
148 | |
149 s->dstptr[0] = bufptr[0]; | |
150 s->dstptr[1] = bufptr[1]; | |
151 s->dstptr[s->frame.linesize[0]] = bufptr[s->frame.linesize[0]]; | |
152 s->dstptr[s->frame.linesize[0] + 1] = bufptr[s->frame.linesize[0] + 1]; | |
153 | |
154 return 0; | |
155 } | |
156 | |
157 /** | |
158 * Returns the next nibble in sequence, consuming a new byte on the input | |
159 * only if necessary. | |
160 */ | |
161 static uint8_t yop_get_next_nibble(YopDecContext *s) | |
162 { | |
163 int ret; | |
164 | |
165 if (s->low_nibble) { | |
166 ret = *s->low_nibble & 0xf; | |
167 s->low_nibble = NULL; | |
168 }else { | |
169 s->low_nibble = s->srcptr++; | |
170 ret = *s->low_nibble >> 4; | |
171 } | |
172 return ret; | |
173 } | |
174 | |
175 /** | |
176 * Takes s->dstptr to the next macroblock in sequence. | |
177 */ | |
178 static void yop_next_macroblock(YopDecContext *s) | |
179 { | |
180 // If we are advancing to the next row of macroblocks | |
181 if (s->row_pos == s->frame.linesize[0] - 2) { | |
182 s->dstptr += s->frame.linesize[0]; | |
183 s->row_pos = 0; | |
184 }else { | |
185 s->row_pos += 2; | |
186 } | |
187 s->dstptr += 2; | |
188 } | |
189 | |
190 static int yop_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |
191 AVPacket *avpkt) | |
192 { | |
193 YopDecContext *s = avctx->priv_data; | |
194 int tag, firstcolor, is_odd_frame; | |
195 int ret, i; | |
196 uint32_t *palette; | |
197 | |
198 if (s->frame.data[0]) | |
199 avctx->release_buffer(avctx, &s->frame); | |
200 | |
201 ret = avctx->get_buffer(avctx, &s->frame); | |
202 if (ret < 0) { | |
203 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
204 return ret; | |
205 } | |
206 | |
207 s->frame.linesize[0] = avctx->width; | |
208 | |
209 s->dstbuf = s->frame.data[0]; | |
210 s->dstptr = s->frame.data[0]; | |
211 s->srcptr = avpkt->data + 4; | |
212 s->row_pos = 0; | |
213 s->low_nibble = NULL; | |
214 | |
215 is_odd_frame = avpkt->data[0]; | |
216 firstcolor = s->first_color[is_odd_frame]; | |
217 palette = (uint32_t *)s->frame.data[1]; | |
218 | |
219 for (i = 0; i < s->num_pal_colors; i++, s->srcptr += 3) | |
220 palette[i + firstcolor] = (s->srcptr[0] << 18) | | |
221 (s->srcptr[1] << 10) | | |
222 (s->srcptr[2] << 2); | |
223 | |
224 s->frame.palette_has_changed = 1; | |
225 | |
226 while (s->dstptr - s->dstbuf < | |
227 avctx->width * avctx->height && | |
228 s->srcptr - avpkt->data < avpkt->size) { | |
229 | |
230 tag = yop_get_next_nibble(s); | |
231 | |
232 if (tag != 0xf) { | |
233 yop_paint_block(s, tag); | |
234 }else { | |
235 tag = yop_get_next_nibble(s); | |
236 ret = yop_copy_previous_block(s, tag); | |
237 if (ret < 0) { | |
238 avctx->release_buffer(avctx, &s->frame); | |
239 return ret; | |
240 } | |
241 } | |
242 yop_next_macroblock(s); | |
243 } | |
244 | |
245 *data_size = sizeof(AVFrame); | |
246 *(AVFrame *) data = s->frame; | |
247 return avpkt->size; | |
248 } | |
249 | |
250 AVCodec yop_decoder = { | |
251 "yop", | |
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
11553
diff
changeset
|
252 AVMEDIA_TYPE_VIDEO, |
11553 | 253 CODEC_ID_YOP, |
254 sizeof(YopDecContext), | |
255 yop_decode_init, | |
256 NULL, | |
257 yop_decode_close, | |
258 yop_decode_frame, | |
259 .long_name = NULL_IF_CONFIG_SMALL("Psygnosis YOP Video"), | |
260 }; |