Mercurial > libavcodec.hg
annotate motionpixels.c @ 12266:48d6738904a9 libavcodec
Fix SPLATB_REG mess. Used to be a if/elseif/elseif/elseif spaghetti, so this
splits it into small optimization-specific macros which are selected for each
DSP function. The advantage of this approach is that the sse4 functions now
use the ssse3 codepath also without needing an explicit sse4 codepath.
author | rbultje |
---|---|
date | Sat, 24 Jul 2010 19:33:05 +0000 |
parents | 8a4984c5cacc |
children |
rev | line source |
---|---|
7231 | 1 /* |
2 * Motion Pixels Video Decoder | |
3 * Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net) | |
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 Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 #include "avcodec.h" | |
9428 | 23 #include "get_bits.h" |
7231 | 24 #include "dsputil.h" |
25 | |
26 #define MAX_HUFF_CODES 16 | |
27 | |
10581
2980d9efc542
Add support for hardcoding the motionpixels rgb to yuv table.
reimar
parents:
10580
diff
changeset
|
28 #include "motionpixels_tablegen.h" |
7231 | 29 |
30 typedef struct HuffCode { | |
31 int code; | |
32 uint8_t size; | |
33 uint8_t delta; | |
34 } HuffCode; | |
35 | |
36 typedef struct MotionPixelsContext { | |
37 AVCodecContext *avctx; | |
38 AVFrame frame; | |
39 DSPContext dsp; | |
40 uint8_t *changes_map; | |
41 int offset_bits_len; | |
42 int codes_count, current_codes_count; | |
43 int max_codes_bits; | |
44 HuffCode codes[MAX_HUFF_CODES]; | |
45 VLC vlc; | |
46 YuvPixel *vpt, *hpt; | |
47 uint8_t gradient_scale[3]; | |
48 uint8_t *bswapbuf; | |
49 int bswapbuf_size; | |
50 } MotionPixelsContext; | |
51 | |
52 static av_cold int mp_decode_init(AVCodecContext *avctx) | |
53 { | |
54 MotionPixelsContext *mp = avctx->priv_data; | |
55 | |
10581
2980d9efc542
Add support for hardcoding the motionpixels rgb to yuv table.
reimar
parents:
10580
diff
changeset
|
56 motionpixels_tableinit(); |
7231 | 57 mp->avctx = avctx; |
58 dsputil_init(&mp->dsp, avctx); | |
59 mp->changes_map = av_mallocz(avctx->width * avctx->height); | |
60 mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1; | |
61 mp->vpt = av_mallocz(avctx->height * sizeof(YuvPixel)); | |
62 mp->hpt = av_mallocz(avctx->height * avctx->width / 16 * sizeof(YuvPixel)); | |
10580
2e01212efb32
10l, pix_fmt should be set by the motionpixels decoder, not by the demuxer.
reimar
parents:
9583
diff
changeset
|
63 avctx->pix_fmt = PIX_FMT_RGB555; |
7231 | 64 return 0; |
65 } | |
66 | |
67 static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color) | |
68 { | |
69 uint16_t *pixels; | |
70 int offset, w, h, color = 0, x, y, i; | |
71 | |
72 while (count--) { | |
73 offset = get_bits_long(gb, mp->offset_bits_len); | |
74 w = get_bits(gb, bits_len) + 1; | |
75 h = get_bits(gb, bits_len) + 1; | |
76 if (read_color) | |
77 color = get_bits(gb, 15); | |
78 x = offset % mp->avctx->width; | |
79 y = offset / mp->avctx->width; | |
80 if (y >= mp->avctx->height) | |
81 continue; | |
82 w = FFMIN(w, mp->avctx->width - x); | |
83 h = FFMIN(h, mp->avctx->height - y); | |
84 pixels = (uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2]; | |
85 while (h--) { | |
86 mp->changes_map[offset] = w; | |
87 if (read_color) | |
88 for (i = 0; i < w; ++i) | |
89 pixels[i] = color; | |
90 offset += mp->avctx->width; | |
91 pixels += mp->frame.linesize[0] / 2; | |
92 } | |
93 } | |
94 } | |
95 | |
96 static void mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size, int code) | |
97 { | |
98 while (get_bits1(gb)) { | |
99 ++size; | |
100 if (size > mp->max_codes_bits) { | |
101 av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits); | |
102 return; | |
103 } | |
104 code <<= 1; | |
105 mp_get_code(mp, gb, size, code + 1); | |
106 } | |
107 if (mp->current_codes_count >= MAX_HUFF_CODES) { | |
108 av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n"); | |
109 return; | |
110 } | |
111 mp->codes[mp->current_codes_count ].code = code; | |
112 mp->codes[mp->current_codes_count++].size = size; | |
113 } | |
114 | |
115 static void mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb) | |
116 { | |
117 if (mp->codes_count == 1) { | |
118 mp->codes[0].delta = get_bits(gb, 4); | |
119 } else { | |
120 int i; | |
121 | |
122 mp->max_codes_bits = get_bits(gb, 4); | |
123 for (i = 0; i < mp->codes_count; ++i) | |
124 mp->codes[i].delta = get_bits(gb, 4); | |
125 mp->current_codes_count = 0; | |
126 mp_get_code(mp, gb, 0, 0); | |
127 } | |
128 } | |
129 | |
130 static int mp_gradient(MotionPixelsContext *mp, int component, int v) | |
131 { | |
132 int delta; | |
133 | |
134 delta = (v - 7) * mp->gradient_scale[component]; | |
135 mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1; | |
136 return delta; | |
137 } | |
138 | |
139 static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y) | |
140 { | |
141 int color; | |
142 | |
143 color = *(uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2]; | |
144 return mp_rgb_yuv_table[color]; | |
145 } | |
146 | |
147 static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p) | |
148 { | |
149 int color; | |
150 | |
151 color = mp_yuv_to_rgb(p->y, p->v, p->u, 1); | |
152 *(uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2] = color; | |
153 } | |
154 | |
155 static int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb) | |
156 { | |
157 int i; | |
158 | |
159 i = (mp->codes_count == 1) ? 0 : get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1); | |
160 return mp->codes[i].delta; | |
161 } | |
162 | |
163 static void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y) | |
164 { | |
165 YuvPixel p; | |
166 const int y0 = y * mp->avctx->width; | |
167 int w, i, x = 0; | |
168 | |
169 p = mp->vpt[y]; | |
170 if (mp->changes_map[y0 + x] == 0) { | |
171 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); | |
172 ++x; | |
173 } | |
174 while (x < mp->avctx->width) { | |
175 w = mp->changes_map[y0 + x]; | |
176 if (w != 0) { | |
177 if ((y & 3) == 0) { | |
178 if (mp->changes_map[y0 + x + mp->avctx->width] < w || | |
179 mp->changes_map[y0 + x + mp->avctx->width * 2] < w || | |
180 mp->changes_map[y0 + x + mp->avctx->width * 3] < w) { | |
181 for (i = (x + 3) & ~3; i < x + w; i += 4) { | |
182 mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y); | |
183 } | |
184 } | |
185 } | |
186 x += w; | |
187 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); | |
188 p = mp_get_yuv_from_rgb(mp, x - 1, y); | |
189 } else { | |
190 p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); | |
191 if ((x & 3) == 0) { | |
192 if ((y & 3) == 0) { | |
193 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); | |
194 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); | |
195 mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p; | |
196 } else { | |
197 p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v; | |
198 p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u; | |
199 } | |
200 } | |
201 mp_set_rgb_from_yuv(mp, x, y, &p); | |
202 ++x; | |
203 } | |
204 } | |
205 } | |
206 | |
207 static void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb) | |
208 { | |
209 YuvPixel p; | |
210 int y, y0; | |
211 | |
212 for (y = 0; y < mp->avctx->height; ++y) { | |
213 if (mp->changes_map[y * mp->avctx->width] != 0) { | |
214 memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); | |
215 p = mp_get_yuv_from_rgb(mp, 0, y); | |
216 } else { | |
217 p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); | |
218 if ((y & 3) == 0) { | |
219 p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); | |
220 p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); | |
221 } | |
222 mp->vpt[y] = p; | |
223 mp_set_rgb_from_yuv(mp, 0, y, &p); | |
224 } | |
225 } | |
226 for (y0 = 0; y0 < 2; ++y0) | |
227 for (y = y0; y < mp->avctx->height; y += 2) | |
228 mp_decode_line(mp, gb, y); | |
229 } | |
230 | |
231 static int mp_decode_frame(AVCodecContext *avctx, | |
232 void *data, int *data_size, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
233 AVPacket *avpkt) |
7231 | 234 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
235 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
236 int buf_size = avpkt->size; |
7231 | 237 MotionPixelsContext *mp = avctx->priv_data; |
238 GetBitContext gb; | |
239 int i, count1, count2, sz; | |
240 | |
241 mp->frame.reference = 1; | |
242 mp->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; | |
243 if (avctx->reget_buffer(avctx, &mp->frame)) { | |
244 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); | |
245 return -1; | |
246 } | |
247 | |
248 /* le32 bitstream msb first */ | |
9415
141badec76fc
Add a av_fast_malloc function and replace several uses of av_fast_realloc,
reimar
parents:
9355
diff
changeset
|
249 av_fast_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size + FF_INPUT_BUFFER_PADDING_SIZE); |
141badec76fc
Add a av_fast_malloc function and replace several uses of av_fast_realloc,
reimar
parents:
9355
diff
changeset
|
250 if (!mp->bswapbuf) |
9583
26ccdc910898
Add missing return statement to out-of-memory condition. Fixes the warning:
diego
parents:
9428
diff
changeset
|
251 return AVERROR(ENOMEM); |
7231 | 252 mp->dsp.bswap_buf((uint32_t *)mp->bswapbuf, (const uint32_t *)buf, buf_size / 4); |
253 if (buf_size & 3) | |
254 memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3); | |
255 init_get_bits(&gb, mp->bswapbuf, buf_size * 8); | |
256 | |
257 memset(mp->changes_map, 0, avctx->width * avctx->height); | |
258 for (i = !(avctx->extradata[1] & 2); i < 2; ++i) { | |
259 count1 = get_bits(&gb, 12); | |
260 count2 = get_bits(&gb, 12); | |
261 mp_read_changes_map(mp, &gb, count1, 8, i); | |
262 mp_read_changes_map(mp, &gb, count2, 4, i); | |
263 } | |
264 | |
265 mp->codes_count = get_bits(&gb, 4); | |
266 if (mp->codes_count == 0) | |
267 goto end; | |
268 | |
269 if (mp->changes_map[0] == 0) { | |
270 *(uint16_t *)mp->frame.data[0] = get_bits(&gb, 15); | |
271 mp->changes_map[0] = 1; | |
272 } | |
273 mp_read_codes_table(mp, &gb); | |
274 | |
275 sz = get_bits(&gb, 18); | |
276 if (avctx->extradata[0] != 5) | |
277 sz += get_bits(&gb, 18); | |
278 if (sz == 0) | |
279 goto end; | |
280 | |
281 init_vlc(&mp->vlc, mp->max_codes_bits, mp->codes_count, &mp->codes[0].size, sizeof(HuffCode), 1, &mp->codes[0].code, sizeof(HuffCode), 4, 0); | |
282 mp_decode_frame_helper(mp, &gb); | |
283 free_vlc(&mp->vlc); | |
284 | |
285 end: | |
286 *data_size = sizeof(AVFrame); | |
287 *(AVFrame *)data = mp->frame; | |
288 return buf_size; | |
289 } | |
290 | |
291 static av_cold int mp_decode_end(AVCodecContext *avctx) | |
292 { | |
293 MotionPixelsContext *mp = avctx->priv_data; | |
294 | |
295 av_freep(&mp->changes_map); | |
296 av_freep(&mp->vpt); | |
297 av_freep(&mp->hpt); | |
298 av_freep(&mp->bswapbuf); | |
299 if (mp->frame.data[0]) | |
300 avctx->release_buffer(avctx, &mp->frame); | |
301 | |
302 return 0; | |
303 } | |
304 | |
305 AVCodec motionpixels_decoder = { | |
306 "motionpixels", | |
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
10581
diff
changeset
|
307 AVMEDIA_TYPE_VIDEO, |
7231 | 308 CODEC_ID_MOTIONPIXELS, |
309 sizeof(MotionPixelsContext), | |
310 mp_decode_init, | |
311 NULL, | |
312 mp_decode_end, | |
313 mp_decode_frame, | |
314 CODEC_CAP_DR1, | |
9083
bf274494b66e
Change a bunch of codec long_names to be more consistent and descriptive.
diego
parents:
7231
diff
changeset
|
315 .long_name = NULL_IF_CONFIG_SMALL("Motion Pixels video"), |
7231 | 316 }; |