/src/ffmpeg/libavcodec/motionpixels.c
Line | Count | Source |
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 "libavutil/mem.h" |
23 | | #include "libavutil/thread.h" |
24 | | |
25 | | #include "config.h" |
26 | | |
27 | | #include "avcodec.h" |
28 | | #include "get_bits.h" |
29 | | #include "bswapdsp.h" |
30 | | #include "codec_internal.h" |
31 | | #include "decode.h" |
32 | | |
33 | | #define MAX_HUFF_CODES 16 |
34 | | |
35 | | #include "motionpixels_tablegen.h" |
36 | | |
37 | | typedef struct HuffCode { |
38 | | uint8_t size; |
39 | | uint8_t delta; |
40 | | } HuffCode; |
41 | | |
42 | | typedef struct MotionPixelsContext { |
43 | | AVCodecContext *avctx; |
44 | | AVFrame *frame; |
45 | | BswapDSPContext bdsp; |
46 | | uint8_t *changes_map; |
47 | | int offset_bits_len; |
48 | | int codes_count, current_codes_count; |
49 | | int max_codes_bits; |
50 | | HuffCode codes[MAX_HUFF_CODES]; |
51 | | VLC vlc; |
52 | | YuvPixel *vpt, *hpt; |
53 | | uint8_t gradient_scale[3]; |
54 | | uint8_t *bswapbuf; |
55 | | int bswapbuf_size; |
56 | | } MotionPixelsContext; |
57 | | |
58 | | static av_cold int mp_decode_end(AVCodecContext *avctx) |
59 | 935 | { |
60 | 935 | MotionPixelsContext *mp = avctx->priv_data; |
61 | | |
62 | 935 | av_freep(&mp->changes_map); |
63 | 935 | av_freep(&mp->vpt); |
64 | 935 | av_freep(&mp->hpt); |
65 | 935 | av_freep(&mp->bswapbuf); |
66 | 935 | av_frame_free(&mp->frame); |
67 | | |
68 | 935 | return 0; |
69 | 935 | } |
70 | | |
71 | | static av_cold int mp_decode_init(AVCodecContext *avctx) |
72 | 935 | { |
73 | 935 | MotionPixelsContext *mp = avctx->priv_data; |
74 | 935 | int w4 = (avctx->width + 3) & ~3; |
75 | 935 | int h4 = (avctx->height + 3) & ~3; |
76 | | |
77 | 935 | if(avctx->extradata_size < 2){ |
78 | 179 | av_log(avctx, AV_LOG_ERROR, "extradata too small\n"); |
79 | 179 | return AVERROR_INVALIDDATA; |
80 | 179 | } |
81 | | |
82 | 756 | mp->avctx = avctx; |
83 | 756 | ff_bswapdsp_init(&mp->bdsp); |
84 | 756 | mp->changes_map = av_calloc(avctx->width, h4); |
85 | 756 | mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1; |
86 | 756 | mp->vpt = av_calloc(avctx->height, sizeof(*mp->vpt)); |
87 | 756 | mp->hpt = av_calloc(h4 / 4, w4 / 4 * sizeof(*mp->hpt)); |
88 | 756 | if (!mp->changes_map || !mp->vpt || !mp->hpt) |
89 | 0 | return AVERROR(ENOMEM); |
90 | 756 | avctx->pix_fmt = AV_PIX_FMT_RGB555; |
91 | | |
92 | 756 | mp->frame = av_frame_alloc(); |
93 | 756 | if (!mp->frame) |
94 | 0 | return AVERROR(ENOMEM); |
95 | | |
96 | 756 | #if !CONFIG_HARDCODED_TABLES |
97 | 756 | static AVOnce init_static_once = AV_ONCE_INIT; |
98 | 756 | ff_thread_once(&init_static_once, motionpixels_tableinit); |
99 | 756 | #endif |
100 | | |
101 | 756 | return 0; |
102 | 756 | } |
103 | | |
104 | | static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color) |
105 | 273k | { |
106 | 273k | uint16_t *pixels; |
107 | 273k | int offset, w, h, color = 0, x, y, i; |
108 | | |
109 | 73.0M | while (count--) { |
110 | 72.8M | offset = get_bits_long(gb, mp->offset_bits_len); |
111 | 72.8M | w = get_bits(gb, bits_len) + 1; |
112 | 72.8M | h = get_bits(gb, bits_len) + 1; |
113 | 72.8M | if (read_color) |
114 | 42.7M | color = get_bits(gb, 15); |
115 | 72.8M | x = offset % mp->avctx->width; |
116 | 72.8M | y = offset / mp->avctx->width; |
117 | 72.8M | if (y >= mp->avctx->height) |
118 | 129k | continue; |
119 | 72.6M | w = FFMIN(w, mp->avctx->width - x); |
120 | 72.6M | h = FFMIN(h, mp->avctx->height - y); |
121 | 72.6M | pixels = (uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2]; |
122 | 163M | while (h--) { |
123 | 91.2M | mp->changes_map[offset] = w; |
124 | 91.2M | if (read_color) |
125 | 814M | for (i = 0; i < w; ++i) |
126 | 761M | pixels[i] = color; |
127 | 91.2M | offset += mp->avctx->width; |
128 | 91.2M | pixels += mp->frame->linesize[0] / 2; |
129 | 91.2M | } |
130 | 72.6M | } |
131 | 273k | } |
132 | | |
133 | | static int mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size) |
134 | 11.8k | { |
135 | 16.8k | while (get_bits1(gb)) { |
136 | 9.05k | ++size; |
137 | 9.05k | if (size > mp->max_codes_bits) { |
138 | 361 | av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits); |
139 | 361 | return AVERROR_INVALIDDATA; |
140 | 361 | } |
141 | 8.69k | if (mp_get_code(mp, gb, size) < 0) |
142 | 3.68k | return AVERROR_INVALIDDATA; |
143 | 8.69k | } |
144 | 7.76k | if (mp->current_codes_count >= mp->codes_count) { |
145 | 354 | av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n"); |
146 | 354 | return AVERROR_INVALIDDATA; |
147 | 354 | } |
148 | | |
149 | 7.41k | mp->codes[mp->current_codes_count++].size = size; |
150 | 7.41k | return 0; |
151 | 7.76k | } |
152 | | |
153 | | static int mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb) |
154 | 5.31k | { |
155 | 5.31k | if (mp->codes_count == 1) { |
156 | 2.20k | mp->codes[0].delta = get_bits(gb, 4); |
157 | 3.10k | } else { |
158 | 3.10k | int i; |
159 | 3.10k | int ret; |
160 | | |
161 | 3.10k | mp->max_codes_bits = get_bits(gb, 4); |
162 | 20.7k | for (i = 0; i < mp->codes_count; ++i) |
163 | 17.6k | mp->codes[i].delta = get_bits(gb, 4); |
164 | 3.10k | mp->current_codes_count = 0; |
165 | 3.10k | if ((ret = mp_get_code(mp, gb, 0)) < 0) |
166 | 715 | return ret; |
167 | 2.39k | if (mp->current_codes_count < mp->codes_count) { |
168 | 1.30k | av_log(mp->avctx, AV_LOG_ERROR, "too few codes\n"); |
169 | 1.30k | return AVERROR_INVALIDDATA; |
170 | 1.30k | } |
171 | 2.39k | } |
172 | 3.29k | return 0; |
173 | 5.31k | } |
174 | | |
175 | | static av_always_inline int mp_gradient(MotionPixelsContext *mp, int component, int v) |
176 | 712M | { |
177 | 712M | int delta; |
178 | | |
179 | 712M | delta = (v - 7) * mp->gradient_scale[component]; |
180 | 712M | mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1; |
181 | 712M | return delta; |
182 | 712M | } |
183 | | |
184 | | static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y) |
185 | 1.01M | { |
186 | 1.01M | int color; |
187 | | |
188 | 1.01M | color = *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2]; |
189 | 1.01M | return mp_rgb_yuv_table[color & 0x7FFF]; |
190 | 1.01M | } |
191 | | |
192 | | static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p) |
193 | 625M | { |
194 | 625M | int color; |
195 | | |
196 | 625M | color = mp_yuv_to_rgb(p->y, p->v, p->u, 1); |
197 | 625M | *(uint16_t *)&mp->frame->data[0][y * mp->frame->linesize[0] + x * 2] = color; |
198 | 625M | } |
199 | | |
200 | | static av_always_inline int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb) |
201 | 712M | { |
202 | 712M | return mp->vlc.table ? get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1) |
203 | 712M | : mp->codes[0].delta; |
204 | 712M | } |
205 | | |
206 | | static void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y) |
207 | 10.2M | { |
208 | 10.2M | YuvPixel p; |
209 | 10.2M | const int y0 = y * mp->avctx->width; |
210 | 10.2M | int w, i, x = 0; |
211 | | |
212 | 10.2M | p = mp->vpt[y]; |
213 | 10.2M | if (mp->changes_map[y0 + x] == 0) { |
214 | 10.1M | memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); |
215 | 10.1M | ++x; |
216 | 10.1M | } |
217 | 626M | while (x < mp->avctx->width) { |
218 | 616M | w = mp->changes_map[y0 + x]; |
219 | 616M | if (w != 0) { |
220 | 811k | if ((y & 3) == 0) { |
221 | 205k | if (mp->changes_map[y0 + x + mp->avctx->width] < w || |
222 | 198k | mp->changes_map[y0 + x + mp->avctx->width * 2] < w || |
223 | 195k | mp->changes_map[y0 + x + mp->avctx->width * 3] < w) { |
224 | 106k | for (i = (x + 3) & ~3; i < x + w; i += 4) { |
225 | 93.5k | mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y); |
226 | 93.5k | } |
227 | 13.2k | } |
228 | 205k | } |
229 | 811k | x += w; |
230 | 811k | memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); |
231 | 811k | p = mp_get_yuv_from_rgb(mp, x - 1, y); |
232 | 615M | } else { |
233 | 615M | p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); |
234 | 615M | p.y = av_clip_uintp2(p.y, 5); |
235 | 615M | if ((x & 3) == 0) { |
236 | 151M | if ((y & 3) == 0) { |
237 | 40.8M | p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); |
238 | 40.8M | p.v = av_clip_intp2(p.v, 5); |
239 | 40.8M | p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); |
240 | 40.8M | p.u = av_clip_intp2(p.u, 5); |
241 | 40.8M | mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p; |
242 | 110M | } else { |
243 | 110M | p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v; |
244 | 110M | p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u; |
245 | 110M | } |
246 | 151M | } |
247 | 615M | mp_set_rgb_from_yuv(mp, x, y, &p); |
248 | 615M | ++x; |
249 | 615M | } |
250 | 616M | } |
251 | 10.2M | } |
252 | | |
253 | | static void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb) |
254 | 2.53k | { |
255 | 2.53k | YuvPixel p; |
256 | 2.53k | int y, y0; |
257 | | |
258 | 2.53k | av_assert1(mp->changes_map[0]); |
259 | | |
260 | 10.2M | for (y = 0; y < mp->avctx->height; ++y) { |
261 | 10.2M | if (mp->changes_map[y * mp->avctx->width] != 0) { |
262 | 109k | memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale)); |
263 | 109k | p = mp_get_yuv_from_rgb(mp, 0, y); |
264 | 10.1M | } else { |
265 | 10.1M | p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb)); |
266 | 10.1M | p.y = av_clip_uintp2(p.y, 5); |
267 | 10.1M | if ((y & 3) == 0) { |
268 | 2.53M | p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb)); |
269 | 2.53M | p.v = av_clip_intp2(p.v, 5); |
270 | 2.53M | p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb)); |
271 | 2.53M | p.u = av_clip_intp2(p.u, 5); |
272 | 2.53M | } |
273 | 10.1M | mp->vpt[y] = p; |
274 | 10.1M | mp_set_rgb_from_yuv(mp, 0, y, &p); |
275 | 10.1M | } |
276 | 10.2M | } |
277 | 7.59k | for (y0 = 0; y0 < 2; ++y0) |
278 | 10.2M | for (y = y0; y < mp->avctx->height; y += 2) |
279 | 10.2M | mp_decode_line(mp, gb, y); |
280 | 2.53k | } |
281 | | |
282 | | static int mp_decode_frame(AVCodecContext *avctx, AVFrame *rframe, |
283 | | int *got_frame, AVPacket *avpkt) |
284 | 364k | { |
285 | 364k | const uint8_t *buf = avpkt->data; |
286 | 364k | int buf_size = avpkt->size; |
287 | 364k | MotionPixelsContext *mp = avctx->priv_data; |
288 | 364k | GetBitContext gb; |
289 | 364k | int i, count1, count2, sz, ret; |
290 | | |
291 | 364k | if ((ret = ff_reget_buffer(avctx, mp->frame, 0)) < 0) |
292 | 266k | return ret; |
293 | | |
294 | | /* le32 bitstream msb first */ |
295 | 97.8k | av_fast_padded_malloc(&mp->bswapbuf, &mp->bswapbuf_size, buf_size); |
296 | 97.8k | if (!mp->bswapbuf) |
297 | 0 | return AVERROR(ENOMEM); |
298 | 97.8k | mp->bdsp.bswap_buf((uint32_t *) mp->bswapbuf, (const uint32_t *) buf, |
299 | 97.8k | buf_size / 4); |
300 | 97.8k | if (buf_size & 3) |
301 | 93.4k | memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3); |
302 | 97.8k | init_get_bits(&gb, mp->bswapbuf, buf_size * 8); |
303 | | |
304 | 97.8k | memset(mp->changes_map, 0, avctx->width * avctx->height); |
305 | 234k | for (i = !(avctx->extradata[1] & 2); i < 2; ++i) { |
306 | 136k | count1 = get_bits(&gb, 12); |
307 | 136k | count2 = get_bits(&gb, 12); |
308 | 136k | mp_read_changes_map(mp, &gb, count1, 8, i); |
309 | 136k | mp_read_changes_map(mp, &gb, count2, 4, i); |
310 | 136k | } |
311 | | |
312 | 97.8k | mp->codes_count = get_bits(&gb, 4); |
313 | 97.8k | if (mp->codes_count == 0) |
314 | 92.5k | goto end; |
315 | | |
316 | 5.31k | if (mp->changes_map[0] == 0) { |
317 | 4.96k | *(uint16_t *)mp->frame->data[0] = get_bits(&gb, 15); |
318 | 4.96k | mp->changes_map[0] = 1; |
319 | 4.96k | } |
320 | 5.31k | if (mp_read_codes_table(mp, &gb) < 0) |
321 | 2.02k | goto end; |
322 | | |
323 | 3.29k | sz = get_bits(&gb, 18); |
324 | 3.29k | if (avctx->extradata[0] != 5) |
325 | 2.82k | sz += get_bits(&gb, 18); |
326 | 3.29k | if (sz == 0) |
327 | 764 | goto end; |
328 | | |
329 | 2.53k | if (mp->codes_count > 1) { |
330 | | /* The entries of the mp->codes array are sorted from right to left |
331 | | * in the Huffman tree, hence -(int)sizeof(HuffCode). */ |
332 | 1.07k | ret = ff_vlc_init_from_lengths(&mp->vlc, mp->max_codes_bits, mp->codes_count, |
333 | 1.07k | &mp->codes[mp->codes_count - 1].size, -(int)sizeof(HuffCode), |
334 | 1.07k | &mp->codes[mp->codes_count - 1].delta, -(int)sizeof(HuffCode), 1, |
335 | 1.07k | 0, 0, avctx); |
336 | 1.07k | if (ret < 0) |
337 | 0 | goto end; |
338 | 1.07k | } |
339 | 2.53k | mp_decode_frame_helper(mp, &gb); |
340 | 2.53k | ff_vlc_free(&mp->vlc); |
341 | | |
342 | 97.8k | end: |
343 | 97.8k | if ((ret = av_frame_ref(rframe, mp->frame)) < 0) |
344 | 0 | return ret; |
345 | 97.8k | *got_frame = 1; |
346 | 97.8k | return buf_size; |
347 | 97.8k | } |
348 | | |
349 | | const FFCodec ff_motionpixels_decoder = { |
350 | | .p.name = "motionpixels", |
351 | | CODEC_LONG_NAME("Motion Pixels video"), |
352 | | .p.type = AVMEDIA_TYPE_VIDEO, |
353 | | .p.id = AV_CODEC_ID_MOTIONPIXELS, |
354 | | .priv_data_size = sizeof(MotionPixelsContext), |
355 | | .init = mp_decode_init, |
356 | | .close = mp_decode_end, |
357 | | FF_CODEC_DECODE_CB(mp_decode_frame), |
358 | | .p.capabilities = AV_CODEC_CAP_DR1, |
359 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
360 | | }; |