FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/imm4.c
Date: 2026-09-25 23:13:28
Exec Total Coverage
Lines: 0 281 0.0%
Functions: 0 10 0.0%
Branches: 0 119 0.0%

Line Branch Exec Source
1 /*
2 * Infinity IMM4 decoder
3 *
4 * Copyright (c) 2018 Paul B Mahol
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <stddef.h>
24 #include <string.h>
25
26 #include "libavutil/attributes.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/mem_internal.h"
29 #include "libavutil/thread.h"
30
31 #include "avcodec.h"
32 #include "bswapdsp.h"
33 #include "codec_internal.h"
34 #include "decode.h"
35 #include "copy_block.h"
36 #include "get_bits.h"
37 #include "idctdsp.h"
38
39 #define CBPLO_VLC_BITS 6
40 #define CBPHI_VLC_BITS 6
41 #define BLKTYPE_VLC_BITS 9
42 #define BLOCK_VLC_BITS 12
43
44 typedef struct IMM4Context {
45 BswapDSPContext bdsp;
46 GetBitContext gb;
47
48 AVFrame *prev_frame;
49 uint8_t *bitstream;
50 int bitstream_size;
51
52 int factor;
53 unsigned lo;
54 unsigned hi;
55
56 IDCTDSPContext idsp;
57 DECLARE_ALIGNED(32, int16_t, block)[6][64];
58 } IMM4Context;
59
60 static const uint8_t intra_cb[] = {
61 24, 18, 12
62 };
63
64 static const uint8_t inter_cb[] = {
65 30, 20, 15
66 };
67
68 static const uint8_t cbplo[][2] = {
69 { 0,-6 }, { 0x01, 6 }, { 0x02, 6 }, { 0x03, 6 }, { 0x00, 4 },
70 { 0x01, 3 }, { 0x02, 3 }, { 0x03, 3 }, { 0x00, 1 },
71 };
72
73 static const uint8_t cbphi_bits[] = {
74 4, 5, 5, 4, 5, 4, 6, 4, 5, 6, 4, 4, 4, 4, 4, 2
75 };
76
77 static const uint8_t cbphi_codes[] = {
78 3, 5, 4, 9, 3, 7, 2, 11, 2, 3, 5, 10, 4, 8, 6, 3
79 };
80
81 static const uint8_t blktype[][2] = {
82 { 0,-8 }, { 0x34, 9 }, { 0,-9 }, { 0x14, 9 }, { 0,-9 },
83 { 0x23, 8 }, { 0x13, 8 }, { 0x32, 8 }, { 0x33, 7 }, { 0x22, 7 },
84 { 0x12, 7 }, { 0x21, 7 }, { 0x11, 7 }, { 0x04, 6 }, { 0x30, 6 },
85 { 0x03, 5 }, { 0x20, 4 }, { 0x10, 4 }, { 0x02, 3 }, { 0x01, 3 },
86 { 0x00, 1 },
87 };
88
89 static const uint16_t block_symbols[] = {
90 0, 0x4082, 0x4003, 0x000B, 0x000A, 0x4E01, 0x4D81, 0x4D01, 0x4C81,
91 0x0482, 0x0402, 0x0382, 0x0302, 0x0282, 0x0183, 0x0103, 0x0084, 0x000C,
92 0x0085, 0x0B81, 0x0C01, 0x4E81, 0x4F01, 0x4F81, 0x5001, 0x0086, 0x0104,
93 0x0203, 0x0283, 0x0303, 0x0502, 0x0C81, 0x0D01, 0x5081, 0x5101, 0x5181,
94 0x5201, 0x5281, 0x5301, 0x5381, 0x5401, 0x0000, 0x0009, 0x0008, 0x4C01,
95 0x4B81, 0x4B01, 0x4A81, 0x4A01, 0x4981, 0x4901, 0x4881, 0x4002, 0x0B01,
96 0x0A81, 0x0A01, 0x0981, 0x0901, 0x0881, 0x0801, 0x0781, 0x0202, 0x0182,
97 0x0007, 0x0006, 0x4801, 0x4781, 0x4701, 0x4681, 0x4601, 0x4581, 0x4501,
98 0x4481, 0x0701, 0x0681, 0x0102, 0x0083, 0x0005, 0x4401, 0x4381, 0x4301,
99 0x4281, 0x0601, 0x0581, 0x0501, 0x0004, 0x4201, 0x4181, 0x4101, 0x4081,
100 0x0481, 0x0401, 0x0381, 0x0301, 0x0082, 0x0003, 0x0281, 0x0201, 0x0181,
101 0x4001, 0x0001, 0x0081, 0x0101, 0x0002,
102 };
103
104 static const uint8_t block_bits[] = {
105 -9, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11,
106 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
107 12, 12, 12, 7, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
108 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
109 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6,
110 6, 5, 5, 5, 4, 2, 3, 4, 4,
111 };
112
113 static VLCElem cbplo_tab[1 << CBPLO_VLC_BITS];
114 static VLCElem cbphi_tab[1 << CBPHI_VLC_BITS];
115 static VLCElem blktype_tab[1 << BLKTYPE_VLC_BITS];
116 static VLCElem block_tab[1 << BLOCK_VLC_BITS];
117
118 ✗ static int get_cbphi(GetBitContext *gb, int x)
119 {
120 int value;
121
122 ✗ value = get_vlc2(gb, cbphi_tab, CBPHI_VLC_BITS, 1);
123 ✗ if (value < 0)
124 ✗ return AVERROR_INVALIDDATA;
125
126 ✗ return x ? value : 15 - value;
127 }
128
129 ✗ static int decode_block(AVCodecContext *avctx, GetBitContext *gb,
130 int block, int factor, int flag, int offset, int flag2)
131 {
132 ✗ IMM4Context *s = avctx->priv_data;
133 ✗ const uint8_t *idct_permutation = s->idsp.idct_permutation;
134 int i, last, len, factor2;
135
136 ✗ for (i = !flag; i < 64; i++) {
137 int value;
138
139 ✗ value = get_vlc2(gb, block_tab, BLOCK_VLC_BITS, 1);
140 ✗ if (value < 0)
141 ✗ return AVERROR_INVALIDDATA;
142 ✗ if (value == 0) {
143 ✗ last = get_bits1(gb);
144 ✗ len = get_bits(gb, 6);
145 ✗ factor2 = get_sbits(gb, 8);
146 } else {
147 ✗ factor2 = value & 0x7F;
148 ✗ last = (value >> 14) & 1;
149 ✗ len = (value >> 7) & 0x3F;
150 ✗ if (get_bits1(gb))
151 ✗ factor2 = -factor2;
152 }
153 ✗ i += len;
154 ✗ if (i >= 64)
155 ✗ break;
156 ✗ s->block[block][idct_permutation[i]] = offset * (factor2 < 0 ? -1 : 1) + factor * factor2;
157 ✗ if (last)
158 ✗ break;
159 }
160
161 ✗ if (s->hi == 2 && flag2 && block < 4) {
162 ✗ if (flag)
163 ✗ s->block[block][idct_permutation[0]] *= 2;
164 ✗ s->block[block][idct_permutation[1]] *= 2;
165 ✗ s->block[block][idct_permutation[8]] *= 2;
166 ✗ s->block[block][idct_permutation[16]] *= 2;
167 }
168
169 ✗ return 0;
170 }
171
172 ✗ static int decode_blocks(AVCodecContext *avctx, GetBitContext *gb,
173 unsigned cbp, int flag, int offset, unsigned flag2)
174 {
175 ✗ IMM4Context *s = avctx->priv_data;
176 ✗ const uint8_t *idct_permutation = s->idsp.idct_permutation;
177 int ret, i;
178
179 ✗ memset(s->block, 0, sizeof(s->block));
180
181 ✗ for (i = 0; i < 6; i++) {
182 ✗ if (!flag) {
183 ✗ int x = get_bits(gb, 8);
184
185 ✗ if (x == 255)
186 ✗ x = 128;
187 ✗ x *= 8;
188
189 ✗ s->block[i][idct_permutation[0]] = x;
190 }
191
192 ✗ if (cbp & (1 << (5 - i))) {
193 ✗ ret = decode_block(avctx, gb, i, s->factor, flag, offset, flag2);
194 ✗ if (ret < 0)
195 ✗ return ret;
196 }
197 }
198
199 ✗ return 0;
200 }
201
202 ✗ static int decode_intra(AVCodecContext *avctx, GetBitContext *gb, AVFrame *frame)
203 {
204 ✗ IMM4Context *s = avctx->priv_data;
205 ✗ int ret, x, y, offset = 0;
206
207 ✗ if (s->hi == 0) {
208 ✗ if (s->lo > 2)
209 ✗ return AVERROR_INVALIDDATA;
210 ✗ s->factor = intra_cb[s->lo];
211 } else {
212 ✗ s->factor = s->lo * 2;
213 }
214
215 ✗ if (s->hi) {
216 ✗ offset = s->factor;
217 ✗ offset >>= 1;
218 ✗ if (!(offset & 1))
219 ✗ offset--;
220 }
221
222 ✗ for (y = 0; y < avctx->height; y += 16) {
223 ✗ for (x = 0; x < avctx->width; x += 16) {
224 unsigned flag, cbplo;
225 int cbphi;
226
227 ✗ cbplo = get_vlc2(gb, cbplo_tab, CBPLO_VLC_BITS, 1);
228 ✗ flag = get_bits1(gb);
229
230 ✗ cbphi = get_cbphi(gb, 1);
231 ✗ if (cbphi < 0)
232 ✗ return cbphi;
233
234 ✗ ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 0, offset, flag);
235 ✗ if (ret < 0)
236 ✗ return ret;
237
238 ✗ s->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x,
239 ✗ frame->linesize[0], s->block[0]);
240 ✗ s->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x + 8,
241 ✗ frame->linesize[0], s->block[1]);
242 ✗ s->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x,
243 ✗ frame->linesize[0], s->block[2]);
244 ✗ s->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x + 8,
245 ✗ frame->linesize[0], s->block[3]);
246 ✗ s->idsp.idct_put(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1),
247 ✗ frame->linesize[1], s->block[4]);
248 ✗ s->idsp.idct_put(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1),
249 ✗ frame->linesize[2], s->block[5]);
250 }
251 }
252
253 ✗ return 0;
254 }
255
256 ✗ static int decode_inter(AVCodecContext *avctx, GetBitContext *gb,
257 AVFrame *frame, AVFrame *prev)
258 {
259 ✗ IMM4Context *s = avctx->priv_data;
260 ✗ int ret, x, y, offset = 0;
261
262 ✗ if (s->hi == 0) {
263 ✗ if (s->lo > 2)
264 ✗ return AVERROR_INVALIDDATA;
265 ✗ s->factor = inter_cb[s->lo];
266 } else {
267 ✗ s->factor = s->lo * 2;
268 }
269
270 ✗ if (s->hi) {
271 ✗ offset = s->factor;
272 ✗ offset >>= 1;
273 ✗ if (!(offset & 1))
274 ✗ offset--;
275 }
276
277 ✗ for (y = 0; y < avctx->height; y += 16) {
278 ✗ for (x = 0; x < avctx->width; x += 16) {
279 int reverse, intra_block, value;
280 ✗ unsigned cbplo, flag2 = 0;
281 int cbphi;
282
283 ✗ if (get_bits1(gb)) {
284 ✗ copy_block16(frame->data[0] + y * frame->linesize[0] + x,
285 ✗ prev->data[0] + y * prev->linesize[0] + x,
286 ✗ frame->linesize[0], prev->linesize[0], 16);
287 ✗ copy_block8(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1),
288 ✗ prev->data[1] + (y >> 1) * prev->linesize[1] + (x >> 1),
289 ✗ frame->linesize[1], prev->linesize[1], 8);
290 ✗ copy_block8(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1),
291 ✗ prev->data[2] + (y >> 1) * prev->linesize[2] + (x >> 1),
292 ✗ frame->linesize[2], prev->linesize[2], 8);
293 ✗ continue;
294 }
295
296 ✗ value = get_vlc2(gb, blktype_tab, BLKTYPE_VLC_BITS, 1);
297 ✗ if (value < 0)
298 ✗ return AVERROR_INVALIDDATA;
299
300 ✗ intra_block = value & 0x07;
301 ✗ reverse = intra_block == 3;
302 ✗ if (reverse)
303 ✗ flag2 = get_bits1(gb);
304
305 ✗ cbplo = value >> 4;
306 ✗ cbphi = get_cbphi(gb, reverse);
307 ✗ if (cbphi < 0)
308 ✗ return cbphi;
309
310 ✗ if (intra_block) {
311 ✗ ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 0, offset, flag2);
312 ✗ if (ret < 0)
313 ✗ return ret;
314
315 ✗ s->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x,
316 ✗ frame->linesize[0], s->block[0]);
317 ✗ s->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x + 8,
318 ✗ frame->linesize[0], s->block[1]);
319 ✗ s->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x,
320 ✗ frame->linesize[0], s->block[2]);
321 ✗ s->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x + 8,
322 ✗ frame->linesize[0], s->block[3]);
323 ✗ s->idsp.idct_put(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1),
324 ✗ frame->linesize[1], s->block[4]);
325 ✗ s->idsp.idct_put(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1),
326 ✗ frame->linesize[2], s->block[5]);
327 } else {
328 ✗ flag2 = get_bits1(gb);
329 ✗ skip_bits1(gb);
330 ✗ ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 1, offset, flag2);
331 ✗ if (ret < 0)
332 ✗ return ret;
333
334 ✗ copy_block16(frame->data[0] + y * frame->linesize[0] + x,
335 ✗ prev->data[0] + y * prev->linesize[0] + x,
336 ✗ frame->linesize[0], prev->linesize[0], 16);
337 ✗ copy_block8(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1),
338 ✗ prev->data[1] + (y >> 1) * prev->linesize[1] + (x >> 1),
339 ✗ frame->linesize[1], prev->linesize[1], 8);
340 ✗ copy_block8(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1),
341 ✗ prev->data[2] + (y >> 1) * prev->linesize[2] + (x >> 1),
342 ✗ frame->linesize[2], prev->linesize[2], 8);
343
344 ✗ s->idsp.idct_add(frame->data[0] + y * frame->linesize[0] + x,
345 ✗ frame->linesize[0], s->block[0]);
346 ✗ s->idsp.idct_add(frame->data[0] + y * frame->linesize[0] + x + 8,
347 ✗ frame->linesize[0], s->block[1]);
348 ✗ s->idsp.idct_add(frame->data[0] + (y + 8) * frame->linesize[0] + x,
349 ✗ frame->linesize[0], s->block[2]);
350 ✗ s->idsp.idct_add(frame->data[0] + (y + 8) * frame->linesize[0] + x + 8,
351 ✗ frame->linesize[0], s->block[3]);
352 ✗ s->idsp.idct_add(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1),
353 ✗ frame->linesize[1], s->block[4]);
354 ✗ s->idsp.idct_add(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1),
355 ✗ frame->linesize[2], s->block[5]);
356 }
357 }
358 }
359
360 ✗ return 0;
361 }
362
363 ✗ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
364 int *got_frame, AVPacket *avpkt)
365 {
366 ✗ IMM4Context *s = avctx->priv_data;
367 ✗ GetBitContext *gb = &s->gb;
368 int width, height;
369 unsigned type;
370 int ret, scaled;
371
372 ✗ if (avpkt->size <= 32)
373 ✗ return AVERROR_INVALIDDATA;
374
375 ✗ av_fast_padded_malloc(&s->bitstream, &s->bitstream_size,
376 ✗ FFALIGN(avpkt->size, 4));
377 ✗ if (!s->bitstream)
378 ✗ return AVERROR(ENOMEM);
379
380 ✗ s->bdsp.bswap_buf((uint32_t *)s->bitstream,
381 ✗ (uint32_t *)avpkt->data,
382 ✗ (avpkt->size + 3) >> 2);
383
384 ✗ if ((ret = init_get_bits8(gb, s->bitstream, FFALIGN(avpkt->size, 4))) < 0)
385 ✗ return ret;
386
387 ✗ avctx->pix_fmt = AV_PIX_FMT_YUV420P;
388 ✗ avctx->color_range = AVCOL_RANGE_JPEG;
389
390 ✗ width = avctx->width;
391 ✗ height = avctx->height;
392
393 ✗ scaled = avpkt->data[8];
394 ✗ if (scaled < 2) {
395 ✗ int mode = avpkt->data[10];
396
397 ✗ switch (mode) {
398 ✗ case 1:
399 ✗ width = 352;
400 ✗ height = 240;
401 ✗ break;
402 ✗ case 2:
403 ✗ width = 704;
404 ✗ height = 240;
405 ✗ break;
406 ✗ case 4:
407 ✗ width = 480;
408 ✗ height = 704;
409 ✗ break;
410 ✗ case 17:
411 ✗ width = 352;
412 ✗ height = 288;
413 ✗ break;
414 ✗ case 18:
415 ✗ width = 704;
416 ✗ height = 288;
417 ✗ break;
418 ✗ default:
419 ✗ width = 704;
420 ✗ height = 576;
421 ✗ break;
422 }
423 }
424
425 ✗ skip_bits_long(gb, 24 * 8);
426 ✗ type = get_bits_long(gb, 32);
427 ✗ s->hi = get_bits(gb, 16);
428 ✗ s->lo = get_bits(gb, 16);
429
430 ✗ switch (type) {
431 ✗ case 0x19781977:
432 ✗ frame->flags |= AV_FRAME_FLAG_KEY;
433 ✗ frame->pict_type = AV_PICTURE_TYPE_I;
434 ✗ break;
435 ✗ case 0x12250926:
436 ✗ frame->flags &= ~AV_FRAME_FLAG_KEY;
437 ✗ frame->pict_type = AV_PICTURE_TYPE_P;
438 ✗ break;
439 ✗ default:
440 ✗ avpriv_request_sample(avctx, "type %X", type);
441 ✗ return AVERROR_PATCHWELCOME;
442 }
443
444 ✗ if (avctx->width != width ||
445 ✗ avctx->height != height) {
446 ✗ if (!(frame->flags & AV_FRAME_FLAG_KEY)) {
447 ✗ av_log(avctx, AV_LOG_ERROR, "Frame size change is unsupported.\n");
448 ✗ return AVERROR_INVALIDDATA;
449 }
450 ✗ av_frame_unref(s->prev_frame);
451 }
452
453 ✗ ret = ff_set_dimensions(avctx, width, height);
454 ✗ if (ret < 0)
455 ✗ return ret;
456
457 ✗ if (((avctx->width + 15) / 16) * ((avctx->height + 15) / 16) > get_bits_left(gb))
458 ✗ return AVERROR_INVALIDDATA;
459
460
461 ✗ if ((ret = ff_get_buffer(avctx, frame, (frame->flags & AV_FRAME_FLAG_KEY) ? AV_GET_BUFFER_FLAG_REF : 0)) < 0)
462 ✗ return ret;
463
464 ✗ if (frame->flags & AV_FRAME_FLAG_KEY) {
465 ✗ ret = decode_intra(avctx, gb, frame);
466 ✗ if (ret < 0)
467 ✗ return ret;
468
469 ✗ if ((ret = av_frame_replace(s->prev_frame, frame)) < 0)
470 ✗ return ret;
471 } else {
472 ✗ if (!s->prev_frame->data[0]) {
473 ✗ av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
474 ✗ return AVERROR_INVALIDDATA;
475 }
476
477 ✗ ret = decode_inter(avctx, gb, frame, s->prev_frame);
478 ✗ if (ret < 0)
479 ✗ return ret;
480 }
481
482 ✗ *got_frame = 1;
483
484 ✗ return avpkt->size;
485 }
486
487 ✗ static av_cold void imm4_init_static_data(void)
488 {
489 ✗ VLC_INIT_STATIC_TABLE_FROM_LENGTHS(cbplo_tab, CBPLO_VLC_BITS, FF_ARRAY_ELEMS(cbplo),
490 &cbplo[0][1], 2, &cbplo[0][0], 2, 1,
491 0, 0);
492
493 ✗ VLC_INIT_STATIC_TABLE(cbphi_tab, CBPHI_VLC_BITS, FF_ARRAY_ELEMS(cbphi_bits),
494 cbphi_bits, 1, 1, cbphi_codes, 1, 1, 0);
495
496 ✗ VLC_INIT_STATIC_TABLE_FROM_LENGTHS(blktype_tab, BLKTYPE_VLC_BITS, FF_ARRAY_ELEMS(blktype),
497 &blktype[0][1], 2, &blktype[0][0], 2, 1,
498 0, 0);
499
500 ✗ VLC_INIT_STATIC_TABLE_FROM_LENGTHS(block_tab, BLOCK_VLC_BITS, FF_ARRAY_ELEMS(block_bits),
501 block_bits, 1, block_symbols, 2, 2,
502 0, 0);
503 ✗ }
504
505 ✗ static av_cold int decode_init(AVCodecContext *avctx)
506 {
507 static AVOnce init_static_once = AV_ONCE_INIT;
508 ✗ IMM4Context *s = avctx->priv_data;
509
510 ✗ ff_bswapdsp_init(&s->bdsp);
511 ✗ ff_idctdsp_init(&s->idsp, avctx);
512
513 ✗ s->prev_frame = av_frame_alloc();
514 ✗ if (!s->prev_frame)
515 ✗ return AVERROR(ENOMEM);
516
517 ✗ ff_thread_once(&init_static_once, imm4_init_static_data);
518
519 ✗ return 0;
520 }
521
522 ✗ static av_cold void decode_flush(AVCodecContext *avctx)
523 {
524 ✗ IMM4Context *s = avctx->priv_data;
525
526 ✗ av_frame_unref(s->prev_frame);
527 ✗ }
528
529 ✗ static av_cold int decode_close(AVCodecContext *avctx)
530 {
531 ✗ IMM4Context *s = avctx->priv_data;
532
533 ✗ av_frame_free(&s->prev_frame);
534 ✗ av_freep(&s->bitstream);
535 ✗ s->bitstream_size = 0;
536
537 ✗ return 0;
538 }
539
540 const FFCodec ff_imm4_decoder = {
541 .p.name = "imm4",
542 CODEC_LONG_NAME("Infinity IMM4"),
543 .p.type = AVMEDIA_TYPE_VIDEO,
544 .p.id = AV_CODEC_ID_IMM4,
545 .priv_data_size = sizeof(IMM4Context),
546 .init = decode_init,
547 .close = decode_close,
548 FF_CODEC_DECODE_CB(decode_frame),
549 .flush = decode_flush,
550 .p.capabilities = AV_CODEC_CAP_DR1,
551 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
552 };
553