Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Zip Motion Blocks Video (ZMBV) decoder | |
3 | * Copyright (c) 2006 Konstantin Shishkov | |
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 | /** | |
23 | * @file | |
24 | * Zip Motion Blocks Video decoder | |
25 | */ | |
26 | ||
27 | #include <stdio.h> | |
28 | #include <stdlib.h> | |
29 | ||
30 | #include "libavutil/common.h" | |
31 | #include "libavutil/imgutils.h" | |
32 | #include "libavutil/intreadwrite.h" | |
33 | #include "avcodec.h" | |
34 | #include "internal.h" | |
35 | ||
36 | #include <zlib.h> | |
37 | ||
38 | #define ZMBV_KEYFRAME 1 | |
39 | #define ZMBV_DELTAPAL 2 | |
40 | ||
41 | enum ZmbvFormat { | |
42 | ZMBV_FMT_NONE = 0, | |
43 | ZMBV_FMT_1BPP = 1, | |
44 | ZMBV_FMT_2BPP = 2, | |
45 | ZMBV_FMT_4BPP = 3, | |
46 | ZMBV_FMT_8BPP = 4, | |
47 | ZMBV_FMT_15BPP = 5, | |
48 | ZMBV_FMT_16BPP = 6, | |
49 | ZMBV_FMT_24BPP = 7, | |
50 | ZMBV_FMT_32BPP = 8 | |
51 | }; | |
52 | ||
53 | /* | |
54 | * Decoder context | |
55 | */ | |
56 | typedef struct ZmbvContext { | |
57 | AVCodecContext *avctx; | |
58 | ||
59 | int bpp; | |
60 | unsigned int decomp_size; | |
61 | uint8_t* decomp_buf; | |
62 | uint8_t pal[768]; | |
63 | uint8_t *prev, *cur; | |
64 | int width, height; | |
65 | int fmt; | |
66 | int comp; | |
67 | int flags; | |
68 | int stride; | |
69 | int bw, bh, bx, by; | |
70 | int decomp_len; | |
71 | z_stream zstream; | |
72 | int (*decode_intra)(struct ZmbvContext *c); | |
73 | int (*decode_xor)(struct ZmbvContext *c); | |
74 | } ZmbvContext; | |
75 | ||
76 | /** | |
77 | * Decode XOR'ed frame - 8bpp version | |
78 | */ | |
79 | ||
80 | static int zmbv_decode_xor_8(ZmbvContext *c) | |
81 | { | |
82 | uint8_t *src = c->decomp_buf; | |
83 | uint8_t *output, *prev; | |
84 | int8_t *mvec; | |
85 | int x, y; | |
86 | int d, dx, dy, bw2, bh2; | |
87 | int block; | |
88 | int i, j; | |
89 | int mx, my; | |
90 | ||
91 | output = c->cur; | |
92 | prev = c->prev; | |
93 | ||
94 | if (c->flags & ZMBV_DELTAPAL) { | |
95 | for (i = 0; i < 768; i++) | |
96 | c->pal[i] ^= *src++; | |
97 | } | |
98 | ||
99 | mvec = (int8_t*)src; | |
100 | src += ((c->bx * c->by * 2 + 3) & ~3); | |
101 | ||
102 | block = 0; | |
103 | for (y = 0; y < c->height; y += c->bh) { | |
104 | bh2 = ((c->height - y) > c->bh) ? c->bh : (c->height - y); | |
105 | for (x = 0; x < c->width; x += c->bw) { | |
106 | uint8_t *out, *tprev; | |
107 | ||
108 | d = mvec[block] & 1; | |
109 | dx = mvec[block] >> 1; | |
110 | dy = mvec[block + 1] >> 1; | |
111 | block += 2; | |
112 | ||
113 | bw2 = ((c->width - x) > c->bw) ? c->bw : (c->width - x); | |
114 | ||
115 | /* copy block - motion vectors out of bounds are used to zero blocks */ | |
116 | out = output + x; | |
117 | tprev = prev + x + dx + dy * c->width; | |
118 | mx = x + dx; | |
119 | my = y + dy; | |
120 | for (j = 0; j < bh2; j++) { | |
121 | if (my + j < 0 || my + j >= c->height) { | |
122 | memset(out, 0, bw2); | |
123 | } else { | |
124 | for (i = 0; i < bw2; i++) { | |
125 | if (mx + i < 0 || mx + i >= c->width) | |
126 | out[i] = 0; | |
127 | else | |
128 | out[i] = tprev[i]; | |
129 | } | |
130 | } | |
131 | out += c->width; | |
132 | tprev += c->width; | |
133 | } | |
134 | ||
135 | if (d) { /* apply XOR'ed difference */ | |
136 | out = output + x; | |
137 | for (j = 0; j < bh2; j++) { | |
138 | for (i = 0; i < bw2; i++) | |
139 | out[i] ^= *src++; | |
140 | out += c->width; | |
141 | } | |
142 | } | |
143 | } | |
144 | output += c->width * c->bh; | |
145 | prev += c->width * c->bh; | |
146 | } | |
147 | if (src - c->decomp_buf != c->decomp_len) | |
148 | av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", | |
149 | src-c->decomp_buf, c->decomp_len); | |
150 | return 0; | |
151 | } | |
152 | ||
153 | /** | |
154 | * Decode XOR'ed frame - 15bpp and 16bpp version | |
155 | */ | |
156 | ||
157 | static int zmbv_decode_xor_16(ZmbvContext *c) | |
158 | { | |
159 | uint8_t *src = c->decomp_buf; | |
160 | uint16_t *output, *prev; | |
161 | int8_t *mvec; | |
162 | int x, y; | |
163 | int d, dx, dy, bw2, bh2; | |
164 | int block; | |
165 | int i, j; | |
166 | int mx, my; | |
167 | ||
168 | output = (uint16_t*)c->cur; | |
169 | prev = (uint16_t*)c->prev; | |
170 | ||
171 | mvec = (int8_t*)src; | |
172 | src += ((c->bx * c->by * 2 + 3) & ~3); | |
173 | ||
174 | block = 0; | |
175 | for (y = 0; y < c->height; y += c->bh) { | |
176 | bh2 = ((c->height - y) > c->bh) ? c->bh : (c->height - y); | |
177 | for (x = 0; x < c->width; x += c->bw) { | |
178 | uint16_t *out, *tprev; | |
179 | ||
180 | d = mvec[block] & 1; | |
181 | dx = mvec[block] >> 1; | |
182 | dy = mvec[block + 1] >> 1; | |
183 | block += 2; | |
184 | ||
185 | bw2 = ((c->width - x) > c->bw) ? c->bw : (c->width - x); | |
186 | ||
187 | /* copy block - motion vectors out of bounds are used to zero blocks */ | |
188 | out = output + x; | |
189 | tprev = prev + x + dx + dy * c->width; | |
190 | mx = x + dx; | |
191 | my = y + dy; | |
192 | for (j = 0; j < bh2; j++) { | |
193 | if (my + j < 0 || my + j >= c->height) { | |
194 | memset(out, 0, bw2 * 2); | |
195 | } else { | |
196 | for (i = 0; i < bw2; i++) { | |
197 | if (mx + i < 0 || mx + i >= c->width) | |
198 | out[i] = 0; | |
199 | else | |
200 | out[i] = tprev[i]; | |
201 | } | |
202 | } | |
203 | out += c->width; | |
204 | tprev += c->width; | |
205 | } | |
206 | ||
207 | if (d) { /* apply XOR'ed difference */ | |
208 | out = output + x; | |
209 | for (j = 0; j < bh2; j++){ | |
210 | for (i = 0; i < bw2; i++) { | |
211 | out[i] ^= *((uint16_t*)src); | |
212 | src += 2; | |
213 | } | |
214 | out += c->width; | |
215 | } | |
216 | } | |
217 | } | |
218 | output += c->width * c->bh; | |
219 | prev += c->width * c->bh; | |
220 | } | |
221 | if (src - c->decomp_buf != c->decomp_len) | |
222 | av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", | |
223 | src-c->decomp_buf, c->decomp_len); | |
224 | return 0; | |
225 | } | |
226 | ||
227 | #ifdef ZMBV_ENABLE_24BPP | |
228 | /** | |
229 | * Decode XOR'ed frame - 24bpp version | |
230 | */ | |
231 | ||
232 | static int zmbv_decode_xor_24(ZmbvContext *c) | |
233 | { | |
234 | uint8_t *src = c->decomp_buf; | |
235 | uint8_t *output, *prev; | |
236 | int8_t *mvec; | |
237 | int x, y; | |
238 | int d, dx, dy, bw2, bh2; | |
239 | int block; | |
240 | int i, j; | |
241 | int mx, my; | |
242 | int stride; | |
243 | ||
244 | output = c->cur; | |
245 | prev = c->prev; | |
246 | ||
247 | stride = c->width * 3; | |
248 | mvec = (int8_t*)src; | |
249 | src += ((c->bx * c->by * 2 + 3) & ~3); | |
250 | ||
251 | block = 0; | |
252 | for (y = 0; y < c->height; y += c->bh) { | |
253 | bh2 = ((c->height - y) > c->bh) ? c->bh : (c->height - y); | |
254 | for (x = 0; x < c->width; x += c->bw) { | |
255 | uint8_t *out, *tprev; | |
256 | ||
257 | d = mvec[block] & 1; | |
258 | dx = mvec[block] >> 1; | |
259 | dy = mvec[block + 1] >> 1; | |
260 | block += 2; | |
261 | ||
262 | bw2 = ((c->width - x) > c->bw) ? c->bw : (c->width - x); | |
263 | ||
264 | /* copy block - motion vectors out of bounds are used to zero blocks */ | |
265 | out = output + x * 3; | |
266 | tprev = prev + (x + dx) * 3 + dy * stride; | |
267 | mx = x + dx; | |
268 | my = y + dy; | |
269 | for (j = 0; j < bh2; j++) { | |
270 | if (my + j < 0 || my + j >= c->height) { | |
271 | memset(out, 0, bw2 * 3); | |
272 | } else { | |
273 | for (i = 0; i < bw2; i++){ | |
274 | if (mx + i < 0 || mx + i >= c->width) { | |
275 | out[i * 3 + 0] = 0; | |
276 | out[i * 3 + 1] = 0; | |
277 | out[i * 3 + 2] = 0; | |
278 | } else { | |
279 | out[i * 3 + 0] = tprev[i * 3 + 0]; | |
280 | out[i * 3 + 1] = tprev[i * 3 + 1]; | |
281 | out[i * 3 + 2] = tprev[i * 3 + 2]; | |
282 | } | |
283 | } | |
284 | } | |
285 | out += stride; | |
286 | tprev += stride; | |
287 | } | |
288 | ||
289 | if (d) { /* apply XOR'ed difference */ | |
290 | out = output + x * 3; | |
291 | for (j = 0; j < bh2; j++) { | |
292 | for (i = 0; i < bw2; i++) { | |
293 | out[i * 3 + 0] ^= *src++; | |
294 | out[i * 3 + 1] ^= *src++; | |
295 | out[i * 3 + 2] ^= *src++; | |
296 | } | |
297 | out += stride; | |
298 | } | |
299 | } | |
300 | } | |
301 | output += stride * c->bh; | |
302 | prev += stride * c->bh; | |
303 | } | |
304 | if (src - c->decomp_buf != c->decomp_len) | |
305 | av_log(c->avctx, AV_LOG_ERROR, "Used %i of %i bytes\n", | |
306 | src-c->decomp_buf, c->decomp_len); | |
307 | return 0; | |
308 | } | |
309 | #endif //ZMBV_ENABLE_24BPP | |
310 | ||
311 | /** | |
312 | * Decode XOR'ed frame - 32bpp version | |
313 | */ | |
314 | ||
315 | static int zmbv_decode_xor_32(ZmbvContext *c) | |
316 | { | |
317 | uint8_t *src = c->decomp_buf; | |
318 | uint32_t *output, *prev; | |
319 | int8_t *mvec; | |
320 | int x, y; | |
321 | int d, dx, dy, bw2, bh2; | |
322 | int block; | |
323 | int i, j; | |
324 | int mx, my; | |
325 | ||
326 | output = (uint32_t*)c->cur; | |
327 | prev = (uint32_t*)c->prev; | |
328 | ||
329 | mvec = (int8_t*)src; | |
330 | src += ((c->bx * c->by * 2 + 3) & ~3); | |
331 | ||
332 | block = 0; | |
333 | for (y = 0; y < c->height; y += c->bh) { | |
334 | bh2 = ((c->height - y) > c->bh) ? c->bh : (c->height - y); | |
335 | for (x = 0; x < c->width; x += c->bw) { | |
336 | uint32_t *out, *tprev; | |
337 | ||
338 | d = mvec[block] & 1; | |
339 | dx = mvec[block] >> 1; | |
340 | dy = mvec[block + 1] >> 1; | |
341 | block += 2; | |
342 | ||
343 | bw2 = ((c->width - x) > c->bw) ? c->bw : (c->width - x); | |
344 | ||
345 | /* copy block - motion vectors out of bounds are used to zero blocks */ | |
346 | out = output + x; | |
347 | tprev = prev + x + dx + dy * c->width; | |
348 | mx = x + dx; | |
349 | my = y + dy; | |
350 | for (j = 0; j < bh2; j++) { | |
351 | if (my + j < 0 || my + j >= c->height) { | |
352 | memset(out, 0, bw2 * 4); | |
353 | } else { | |
354 | for (i = 0; i < bw2; i++){ | |
355 | if (mx + i < 0 || mx + i >= c->width) | |
356 | out[i] = 0; | |
357 | else | |
358 | out[i] = tprev[i]; | |
359 | } | |
360 | } | |
361 | out += c->width; | |
362 | tprev += c->width; | |
363 | } | |
364 | ||
365 | if (d) { /* apply XOR'ed difference */ | |
366 | out = output + x; | |
367 | for (j = 0; j < bh2; j++){ | |
368 | for (i = 0; i < bw2; i++) { | |
369 | out[i] ^= *((uint32_t *) src); | |
370 | src += 4; | |
371 | } | |
372 | out += c->width; | |
373 | } | |
374 | } | |
375 | } | |
376 | output += c->width * c->bh; | |
377 | prev += c->width * c->bh; | |
378 | } | |
379 | if (src - c->decomp_buf != c->decomp_len) | |
380 | av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", | |
381 | src-c->decomp_buf, c->decomp_len); | |
382 | return 0; | |
383 | } | |
384 | ||
385 | /** | |
386 | * Decode intraframe | |
387 | */ | |
388 | static int zmbv_decode_intra(ZmbvContext *c) | |
389 | { | |
390 | uint8_t *src = c->decomp_buf; | |
391 | ||
392 | /* make the palette available on the way out */ | |
393 | if (c->fmt == ZMBV_FMT_8BPP) { | |
394 | memcpy(c->pal, src, 768); | |
395 | src += 768; | |
396 | } | |
397 | ||
398 | memcpy(c->cur, src, c->width * c->height * (c->bpp / 8)); | |
399 | return 0; | |
400 | } | |
401 | ||
402 | static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) | |
403 | { | |
404 | AVFrame *frame = data; | |
405 | const uint8_t *buf = avpkt->data; | |
406 | int buf_size = avpkt->size; | |
407 | ZmbvContext * const c = avctx->priv_data; | |
408 | int zret = Z_OK; // Zlib return code | |
409 | int len = buf_size; | |
410 | int hi_ver, lo_ver, ret; | |
411 | ||
412 | /* parse header */ | |
413 | c->flags = buf[0]; | |
414 | buf++; len--; | |
415 | if (c->flags & ZMBV_KEYFRAME) { | |
416 | void *decode_intra = NULL; | |
417 | c->decode_intra= NULL; | |
418 | hi_ver = buf[0]; | |
419 | lo_ver = buf[1]; | |
420 | c->comp = buf[2]; | |
421 | c->fmt = buf[3]; | |
422 | c->bw = buf[4]; | |
423 | c->bh = buf[5]; | |
424 | c->decode_intra = NULL; | |
425 | c->decode_xor = NULL; | |
426 | ||
427 | buf += 6; | |
428 | len -= 6; | |
429 | av_log(avctx, AV_LOG_DEBUG, | |
430 | "Flags=%X ver=%i.%i comp=%i fmt=%i blk=%ix%i\n", | |
431 | c->flags,hi_ver,lo_ver,c->comp,c->fmt,c->bw,c->bh); | |
432 | if (hi_ver != 0 || lo_ver != 1) { | |
433 | avpriv_request_sample(avctx, "Version %i.%i", hi_ver, lo_ver); | |
434 | return AVERROR_PATCHWELCOME; | |
435 | } | |
436 | if (c->bw == 0 || c->bh == 0) { | |
437 | avpriv_request_sample(avctx, "Block size %ix%i", c->bw, c->bh); | |
438 | return AVERROR_PATCHWELCOME; | |
439 | } | |
440 | if (c->comp != 0 && c->comp != 1) { | |
441 | avpriv_request_sample(avctx, "Compression type %i", c->comp); | |
442 | return AVERROR_PATCHWELCOME; | |
443 | } | |
444 | ||
445 | switch (c->fmt) { | |
446 | case ZMBV_FMT_8BPP: | |
447 | c->bpp = 8; | |
448 | decode_intra = zmbv_decode_intra; | |
449 | c->decode_xor = zmbv_decode_xor_8; | |
450 | avctx->pix_fmt = AV_PIX_FMT_PAL8; | |
451 | c->stride = c->width; | |
452 | break; | |
453 | case ZMBV_FMT_15BPP: | |
454 | case ZMBV_FMT_16BPP: | |
455 | c->bpp = 16; | |
456 | decode_intra = zmbv_decode_intra; | |
457 | c->decode_xor = zmbv_decode_xor_16; | |
458 | if (c->fmt == ZMBV_FMT_15BPP) | |
459 | avctx->pix_fmt = AV_PIX_FMT_RGB555LE; | |
460 | else | |
461 | avctx->pix_fmt = AV_PIX_FMT_RGB565LE; | |
462 | c->stride = c->width * 2; | |
463 | break; | |
464 | #ifdef ZMBV_ENABLE_24BPP | |
465 | case ZMBV_FMT_24BPP: | |
466 | c->bpp = 24; | |
467 | decode_intra = zmbv_decode_intra; | |
468 | c->decode_xor = zmbv_decode_xor_24; | |
469 | avctx->pix_fmt = AV_PIX_FMT_RGB24; | |
470 | c->stride = c->width * 3; | |
471 | break; | |
472 | #endif //ZMBV_ENABLE_24BPP | |
473 | case ZMBV_FMT_32BPP: | |
474 | c->bpp = 32; | |
475 | decode_intra = zmbv_decode_intra; | |
476 | c->decode_xor = zmbv_decode_xor_32; | |
477 | avctx->pix_fmt = AV_PIX_FMT_BGR0; | |
478 | c->stride = c->width * 4; | |
479 | break; | |
480 | default: | |
481 | c->decode_xor = NULL; | |
482 | avpriv_request_sample(avctx, "Format %i", c->fmt); | |
483 | return AVERROR_PATCHWELCOME; | |
484 | } | |
485 | ||
486 | zret = inflateReset(&c->zstream); | |
487 | if (zret != Z_OK) { | |
488 | av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret); | |
489 | return AVERROR_UNKNOWN; | |
490 | } | |
491 | ||
492 | c->cur = av_realloc_f(c->cur, avctx->width * avctx->height, (c->bpp / 8)); | |
493 | c->prev = av_realloc_f(c->prev, avctx->width * avctx->height, (c->bpp / 8)); | |
494 | c->bx = (c->width + c->bw - 1) / c->bw; | |
495 | c->by = (c->height+ c->bh - 1) / c->bh; | |
496 | if (!c->cur || !c->prev) | |
497 | return AVERROR(ENOMEM); | |
498 | memset(c->cur, 0, avctx->width * avctx->height * (c->bpp / 8)); | |
499 | memset(c->prev, 0, avctx->width * avctx->height * (c->bpp / 8)); | |
500 | c->decode_intra= decode_intra; | |
501 | } | |
502 | ||
503 | if (!c->decode_intra) { | |
504 | av_log(avctx, AV_LOG_ERROR, "Error! Got no format or no keyframe!\n"); | |
505 | return AVERROR_INVALIDDATA; | |
506 | } | |
507 | ||
508 | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) | |
509 | return ret; | |
510 | ||
511 | if (c->comp == 0) { //Uncompressed data | |
512 | if (c->decomp_size < len) { | |
513 | av_log(avctx, AV_LOG_ERROR, "Buffer too small\n"); | |
514 | return AVERROR_INVALIDDATA; | |
515 | } | |
516 | memcpy(c->decomp_buf, buf, len); | |
517 | } else { // ZLIB-compressed data | |
518 | c->zstream.total_in = c->zstream.total_out = 0; | |
519 | c->zstream.next_in = (uint8_t*)buf; | |
520 | c->zstream.avail_in = len; | |
521 | c->zstream.next_out = c->decomp_buf; | |
522 | c->zstream.avail_out = c->decomp_size; | |
523 | zret = inflate(&c->zstream, Z_SYNC_FLUSH); | |
524 | if (zret != Z_OK && zret != Z_STREAM_END) { | |
525 | av_log(avctx, AV_LOG_ERROR, "inflate error %d\n", zret); | |
526 | return AVERROR_INVALIDDATA; | |
527 | } | |
528 | c->decomp_len = c->zstream.total_out; | |
529 | } | |
530 | if (c->flags & ZMBV_KEYFRAME) { | |
531 | frame->key_frame = 1; | |
532 | frame->pict_type = AV_PICTURE_TYPE_I; | |
533 | c->decode_intra(c); | |
534 | } else { | |
535 | frame->key_frame = 0; | |
536 | frame->pict_type = AV_PICTURE_TYPE_P; | |
537 | if (c->decomp_len) | |
538 | c->decode_xor(c); | |
539 | } | |
540 | ||
541 | /* update frames */ | |
542 | { | |
543 | uint8_t *out, *src; | |
544 | int j; | |
545 | ||
546 | out = frame->data[0]; | |
547 | src = c->cur; | |
548 | switch (c->fmt) { | |
549 | case ZMBV_FMT_8BPP: | |
550 | for (j = 0; j < 256; j++) | |
551 | AV_WN32(&frame->data[1][j * 4], 0xFFU << 24 | AV_RB24(&c->pal[j * 3])); | |
552 | case ZMBV_FMT_15BPP: | |
553 | case ZMBV_FMT_16BPP: | |
554 | #ifdef ZMBV_ENABLE_24BPP | |
555 | case ZMBV_FMT_24BPP: | |
556 | #endif | |
557 | case ZMBV_FMT_32BPP: | |
558 | av_image_copy_plane(out, frame->linesize[0], src, c->stride, | |
559 | c->stride, c->height); | |
560 | break; | |
561 | default: | |
562 | av_log(avctx, AV_LOG_ERROR, "Cannot handle format %i\n", c->fmt); | |
563 | } | |
564 | FFSWAP(uint8_t *, c->cur, c->prev); | |
565 | } | |
566 | *got_frame = 1; | |
567 | ||
568 | /* always report that the buffer was completely consumed */ | |
569 | return buf_size; | |
570 | } | |
571 | ||
572 | static av_cold int decode_init(AVCodecContext *avctx) | |
573 | { | |
574 | ZmbvContext * const c = avctx->priv_data; | |
575 | int zret; // Zlib return code | |
576 | ||
577 | c->avctx = avctx; | |
578 | ||
579 | c->width = avctx->width; | |
580 | c->height = avctx->height; | |
581 | ||
582 | c->bpp = avctx->bits_per_coded_sample; | |
583 | ||
584 | // Needed if zlib unused or init aborted before inflateInit | |
585 | memset(&c->zstream, 0, sizeof(z_stream)); | |
586 | ||
587 | c->decomp_size = (avctx->width + 255) * 4 * (avctx->height + 64); | |
588 | ||
589 | /* Allocate decompression buffer */ | |
590 | if (c->decomp_size) { | |
591 | if (!(c->decomp_buf = av_mallocz(c->decomp_size))) { | |
592 | av_log(avctx, AV_LOG_ERROR, | |
593 | "Can't allocate decompression buffer.\n"); | |
594 | return AVERROR(ENOMEM); | |
595 | } | |
596 | } | |
597 | ||
598 | c->zstream.zalloc = Z_NULL; | |
599 | c->zstream.zfree = Z_NULL; | |
600 | c->zstream.opaque = Z_NULL; | |
601 | zret = inflateInit(&c->zstream); | |
602 | if (zret != Z_OK) { | |
603 | av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); | |
604 | return AVERROR_UNKNOWN; | |
605 | } | |
606 | ||
607 | return 0; | |
608 | } | |
609 | ||
610 | static av_cold int decode_end(AVCodecContext *avctx) | |
611 | { | |
612 | ZmbvContext * const c = avctx->priv_data; | |
613 | ||
614 | av_freep(&c->decomp_buf); | |
615 | ||
616 | inflateEnd(&c->zstream); | |
617 | av_freep(&c->cur); | |
618 | av_freep(&c->prev); | |
619 | ||
620 | return 0; | |
621 | } | |
622 | ||
623 | AVCodec ff_zmbv_decoder = { | |
624 | .name = "zmbv", | |
625 | .long_name = NULL_IF_CONFIG_SMALL("Zip Motion Blocks Video"), | |
626 | .type = AVMEDIA_TYPE_VIDEO, | |
627 | .id = AV_CODEC_ID_ZMBV, | |
628 | .priv_data_size = sizeof(ZmbvContext), | |
629 | .init = decode_init, | |
630 | .close = decode_end, | |
631 | .decode = decode_frame, | |
632 | .capabilities = CODEC_CAP_DR1, | |
633 | }; |