cosmetics: reindent and break long lines after last commits
[ffmpeg.git] / libavcodec / interplayvideo.c
1 /*
2  * Interplay MVE Video Decoder
3  * Copyright (C) 2003 the ffmpeg project
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 libavcodec/interplayvideo.c
24  * Interplay MVE Video Decoder by Mike Melanson (melanson@pcisys.net)
25  * For more information about the Interplay MVE format, visit:
26  *   http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
27  * This code is written in such a way that the identifiers match up
28  * with the encoding descriptions in the document.
29  *
30  * This decoder presently only supports a PAL8 output colorspace.
31  *
32  * An Interplay video frame consists of 2 parts: The decoding map and
33  * the video data. A demuxer must load these 2 parts together in a single
34  * buffer before sending it through the stream to this decoder.
35  */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "avcodec.h"
42 #include "bytestream.h"
43 #include "dsputil.h"
44 #define ALT_BITSTREAM_READER_LE
45 #include "get_bits.h"
46
47 #define PALETTE_COUNT 256
48
49 /* debugging support */
50 #define DEBUG_INTERPLAY 0
51 #if DEBUG_INTERPLAY
52 #define debug_interplay(x,...) av_log(NULL, AV_LOG_DEBUG, x, __VA_ARGS__)
53 #else
54 static inline void debug_interplay(const char *format, ...) { }
55 #endif
56
57 typedef struct IpvideoContext {
58
59     AVCodecContext *avctx;
60     DSPContext dsp;
61     AVFrame second_last_frame;
62     AVFrame last_frame;
63     AVFrame current_frame;
64     const unsigned char *decoding_map;
65     int decoding_map_size;
66
67     const unsigned char *buf;
68     int size;
69
70     int is_16bpp;
71     const unsigned char *stream_ptr;
72     const unsigned char *stream_end;
73     unsigned char *pixel_ptr;
74     int line_inc;
75     int stride;
76     int upper_motion_limit_offset;
77
78 } IpvideoContext;
79
80 #define CHECK_STREAM_PTR(stream_ptr, stream_end, n) \
81     if (stream_end - stream_ptr < n) { \
82         av_log(s->avctx, AV_LOG_ERROR, "Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
83                stream_ptr + n, stream_end); \
84         return -1; \
85     }
86
87 static int copy_from(IpvideoContext *s, AVFrame *src, int delta_x, int delta_y)
88 {
89     int current_offset = s->pixel_ptr - s->current_frame.data[0];
90     int motion_offset = current_offset + delta_y * s->current_frame.linesize[0]
91                        + delta_x * (1 + s->is_16bpp);
92     if (motion_offset < 0) {
93         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset);
94         return -1;
95     } else if (motion_offset > s->upper_motion_limit_offset) {
96         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n",
97             motion_offset, s->upper_motion_limit_offset);
98         return -1;
99     }
100     s->dsp.put_pixels_tab[!s->is_16bpp][0](s->pixel_ptr, src->data[0] + motion_offset,
101                                            s->current_frame.linesize[0], 8);
102     return 0;
103 }
104
105 static int ipvideo_decode_block_opcode_0x0(IpvideoContext *s)
106 {
107     return copy_from(s, &s->last_frame, 0, 0);
108 }
109
110 static int ipvideo_decode_block_opcode_0x1(IpvideoContext *s)
111 {
112     return copy_from(s, &s->second_last_frame, 0, 0);
113 }
114
115 static int ipvideo_decode_block_opcode_0x2(IpvideoContext *s)
116 {
117     unsigned char B;
118     int x, y;
119
120     /* copy block from 2 frames ago using a motion vector; need 1 more byte */
121     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
122     B = *s->stream_ptr++;
123
124     if (B < 56) {
125         x = 8 + (B % 7);
126         y = B / 7;
127     } else {
128         x = -14 + ((B - 56) % 29);
129         y =   8 + ((B - 56) / 29);
130     }
131
132     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
133     return copy_from(s, &s->second_last_frame, x, y);
134 }
135
136 static int ipvideo_decode_block_opcode_0x3(IpvideoContext *s)
137 {
138     unsigned char B;
139     int x, y;
140
141     /* copy 8x8 block from current frame from an up/left block */
142
143     /* need 1 more byte for motion */
144     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
145     B = *s->stream_ptr++;
146
147     if (B < 56) {
148         x = -(8 + (B % 7));
149         y = -(B / 7);
150     } else {
151         x = -(-14 + ((B - 56) % 29));
152         y = -(  8 + ((B - 56) / 29));
153     }
154
155     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
156     return copy_from(s, &s->current_frame, x, y);
157 }
158
159 static int ipvideo_decode_block_opcode_0x4(IpvideoContext *s)
160 {
161     int x, y;
162     unsigned char B, BL, BH;
163
164     /* copy a block from the previous frame; need 1 more byte */
165     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
166
167     B = *s->stream_ptr++;
168     BL = B & 0x0F;
169     BH = (B >> 4) & 0x0F;
170     x = -8 + BL;
171     y = -8 + BH;
172
173     debug_interplay ("    motion byte = %d, (x, y) = (%d, %d)\n", B, x, y);
174     return copy_from(s, &s->last_frame, x, y);
175 }
176
177 static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s)
178 {
179     signed char x, y;
180
181     /* copy a block from the previous frame using an expanded range;
182      * need 2 more bytes */
183     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
184
185     x = *s->stream_ptr++;
186     y = *s->stream_ptr++;
187
188     debug_interplay ("    motion bytes = %d, %d\n", x, y);
189     return copy_from(s, &s->last_frame, x, y);
190 }
191
192 static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s)
193 {
194     /* mystery opcode? skip multiple blocks? */
195     av_log(s->avctx, AV_LOG_ERROR, "  Interplay video: Help! Mystery opcode 0x6 seen\n");
196
197     /* report success */
198     return 0;
199 }
200
201 static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s)
202 {
203     int x, y;
204     unsigned char P[2];
205     unsigned int flags;
206
207     /* 2-color encoding */
208     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
209
210     P[0] = *s->stream_ptr++;
211     P[1] = *s->stream_ptr++;
212
213     if (P[0] <= P[1]) {
214
215         /* need 8 more bytes from the stream */
216         CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
217
218         for (y = 0; y < 8; y++) {
219             flags = *s->stream_ptr++ | 0x100;
220             for (; flags != 1; flags >>= 1)
221                 *s->pixel_ptr++ = P[flags & 1];
222             s->pixel_ptr += s->line_inc;
223         }
224
225     } else {
226
227         /* need 2 more bytes from the stream */
228         CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
229
230         flags = bytestream_get_le16(&s->stream_ptr);
231         for (y = 0; y < 8; y += 2) {
232             for (x = 0; x < 8; x += 2, flags >>= 1) {
233                 s->pixel_ptr[x                ] =
234                 s->pixel_ptr[x + 1            ] =
235                 s->pixel_ptr[x +     s->stride] =
236                 s->pixel_ptr[x + 1 + s->stride] = P[flags & 1];
237             }
238             s->pixel_ptr += s->stride * 2;
239         }
240     }
241
242     /* report success */
243     return 0;
244 }
245
246 static int ipvideo_decode_block_opcode_0x8(IpvideoContext *s)
247 {
248     int x, y;
249     unsigned char P[2];
250     unsigned int flags = 0;
251
252     /* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
253      * either top and bottom or left and right halves */
254     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
255
256     P[0] = *s->stream_ptr++;
257     P[1] = *s->stream_ptr++;
258
259     if (P[0] <= P[1]) {
260
261         CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 14);
262         s->stream_ptr -= 2;
263
264         for (y = 0; y < 16; y++) {
265             // new values for each 4x4 block
266             if (!(y & 3)) {
267                 P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++;
268                 flags = bytestream_get_le16(&s->stream_ptr);
269             }
270
271             for (x = 0; x < 4; x++, flags >>= 1)
272                 *s->pixel_ptr++ = P[flags & 1];
273             s->pixel_ptr += s->stride - 4;
274             // switch to right half
275             if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
276         }
277
278     } else {
279
280         /* need 10 more bytes */
281         CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 10);
282
283         if (s->stream_ptr[4] <= s->stream_ptr[5]) {
284
285             flags = bytestream_get_le32(&s->stream_ptr);
286
287             /* vertical split; left & right halves are 2-color encoded */
288
289             for (y = 0; y < 16; y++) {
290                 for (x = 0; x < 4; x++, flags >>= 1)
291                     *s->pixel_ptr++ = P[flags & 1];
292                 s->pixel_ptr += s->stride - 4;
293                 // switch to right half
294                 if (y == 7) {
295                     s->pixel_ptr -= 8 * s->stride - 4;
296                     P[0] = *s->stream_ptr++; P[1] = *s->stream_ptr++;
297                     flags = bytestream_get_le32(&s->stream_ptr);
298                 }
299             }
300
301         } else {
302
303             /* horizontal split; top & bottom halves are 2-color encoded */
304
305             for (y = 0; y < 8; y++) {
306                 if (y == 4) {
307                     P[0] = *s->stream_ptr++;
308                     P[1] = *s->stream_ptr++;
309                 }
310                 flags = *s->stream_ptr++ | 0x100;
311
312                 for (; flags != 1; flags >>= 1)
313                     *s->pixel_ptr++ = P[flags & 1];
314                 s->pixel_ptr += s->line_inc;
315             }
316         }
317     }
318
319     /* report success */
320     return 0;
321 }
322
323 static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
324 {
325     int x, y;
326     unsigned char P[4];
327
328     /* 4-color encoding */
329     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
330
331     memcpy(P, s->stream_ptr, 4);
332     s->stream_ptr += 4;
333
334     if (P[0] <= P[1]) {
335         if (P[2] <= P[3]) {
336
337             /* 1 of 4 colors for each pixel, need 16 more bytes */
338             CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
339
340             for (y = 0; y < 8; y++) {
341                 /* get the next set of 8 2-bit flags */
342                 int flags = bytestream_get_le16(&s->stream_ptr);
343                 for (x = 0; x < 8; x++, flags >>= 2)
344                     *s->pixel_ptr++ = P[flags & 0x03];
345                 s->pixel_ptr += s->line_inc;
346             }
347
348         } else {
349             uint32_t flags;
350
351             /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
352             CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
353
354             flags = bytestream_get_le32(&s->stream_ptr);
355
356             for (y = 0; y < 8; y += 2) {
357                 for (x = 0; x < 8; x += 2, flags >>= 2) {
358                     s->pixel_ptr[x                ] =
359                     s->pixel_ptr[x + 1            ] =
360                     s->pixel_ptr[x +     s->stride] =
361                     s->pixel_ptr[x + 1 + s->stride] = P[flags & 0x03];
362                 }
363                 s->pixel_ptr += s->stride * 2;
364             }
365
366         }
367     } else {
368         uint64_t flags;
369
370         /* 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes */
371         CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 8);
372
373         flags = bytestream_get_le64(&s->stream_ptr);
374         if (P[2] <= P[3]) {
375             for (y = 0; y < 8; y++) {
376                 for (x = 0; x < 8; x += 2, flags >>= 2) {
377                     s->pixel_ptr[x    ] =
378                     s->pixel_ptr[x + 1] = P[flags & 0x03];
379                 }
380                 s->pixel_ptr += s->stride;
381             }
382         } else {
383             for (y = 0; y < 8; y += 2) {
384                 for (x = 0; x < 8; x++, flags >>= 2) {
385                     s->pixel_ptr[x            ] =
386                     s->pixel_ptr[x + s->stride] = P[flags & 0x03];
387                 }
388                 s->pixel_ptr += s->stride * 2;
389             }
390         }
391     }
392
393     /* report success */
394     return 0;
395 }
396
397 static int ipvideo_decode_block_opcode_0xA(IpvideoContext *s)
398 {
399     int x, y;
400     unsigned char P[4];
401     int flags = 0;
402
403     /* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
404      * either top and bottom or left and right halves */
405     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 24);
406
407     if (s->stream_ptr[0] <= s->stream_ptr[1]) {
408
409         /* 4-color encoding for each quadrant; need 32 bytes */
410         CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 32);
411
412         for (y = 0; y < 16; y++) {
413             // new values for each 4x4 block
414             if (!(y & 3)) {
415                 memcpy(P, s->stream_ptr, 4);
416                 s->stream_ptr += 4;
417                 flags = bytestream_get_le32(&s->stream_ptr);
418             }
419
420             for (x = 0; x < 4; x++, flags >>= 2)
421                 *s->pixel_ptr++ = P[flags & 0x03];
422
423             s->pixel_ptr += s->stride - 4;
424             // switch to right half
425             if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
426         }
427
428     } else {
429         // vertical split?
430         int vert = s->stream_ptr[12] <= s->stream_ptr[13];
431         uint64_t flags = 0;
432
433         /* 4-color encoding for either left and right or top and bottom
434          * halves */
435
436         for (y = 0; y < 16; y++) {
437             // load values for each half
438             if (!(y & 7)) {
439                 memcpy(P, s->stream_ptr, 4);
440                 s->stream_ptr += 4;
441                 flags = bytestream_get_le64(&s->stream_ptr);
442             }
443
444             for (x = 0; x < 4; x++, flags >>= 2)
445                 *s->pixel_ptr++ = P[flags & 0x03];
446
447             if (vert) {
448                 s->pixel_ptr += s->stride - 4;
449                 // switch to right half
450                 if (y == 7) s->pixel_ptr -= 8 * s->stride - 4;
451             } else if (y & 1) s->pixel_ptr += s->line_inc;
452         }
453     }
454
455     /* report success */
456     return 0;
457 }
458
459 static int ipvideo_decode_block_opcode_0xB(IpvideoContext *s)
460 {
461     int y;
462
463     /* 64-color encoding (each pixel in block is a different color) */
464     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 64);
465
466     for (y = 0; y < 8; y++) {
467         memcpy(s->pixel_ptr, s->stream_ptr, 8);
468         s->stream_ptr += 8;
469         s->pixel_ptr  += s->stride;
470     }
471
472     /* report success */
473     return 0;
474 }
475
476 static int ipvideo_decode_block_opcode_0xC(IpvideoContext *s)
477 {
478     int x, y;
479
480     /* 16-color block encoding: each 2x2 block is a different color */
481     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 16);
482
483     for (y = 0; y < 8; y += 2) {
484         for (x = 0; x < 8; x += 2) {
485             s->pixel_ptr[x                ] =
486             s->pixel_ptr[x + 1            ] =
487             s->pixel_ptr[x +     s->stride] =
488             s->pixel_ptr[x + 1 + s->stride] = *s->stream_ptr++;
489         }
490         s->pixel_ptr += s->stride * 2;
491     }
492
493     /* report success */
494     return 0;
495 }
496
497 static int ipvideo_decode_block_opcode_0xD(IpvideoContext *s)
498 {
499     int y;
500     unsigned char P[2];
501
502     /* 4-color block encoding: each 4x4 block is a different color */
503     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 4);
504
505     for (y = 0; y < 8; y++) {
506         if (!(y & 3)) {
507             P[0] = *s->stream_ptr++;
508             P[1] = *s->stream_ptr++;
509         }
510         memset(s->pixel_ptr,     P[0], 4);
511         memset(s->pixel_ptr + 4, P[1], 4);
512         s->pixel_ptr += s->stride;
513     }
514
515     /* report success */
516     return 0;
517 }
518
519 static int ipvideo_decode_block_opcode_0xE(IpvideoContext *s)
520 {
521     int y;
522     unsigned char pix;
523
524     /* 1-color encoding: the whole block is 1 solid color */
525     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 1);
526     pix = *s->stream_ptr++;
527
528     for (y = 0; y < 8; y++) {
529         memset(s->pixel_ptr, pix, 8);
530         s->pixel_ptr += s->stride;
531     }
532
533     /* report success */
534     return 0;
535 }
536
537 static int ipvideo_decode_block_opcode_0xF(IpvideoContext *s)
538 {
539     int x, y;
540     unsigned char sample[2];
541
542     /* dithered encoding */
543     CHECK_STREAM_PTR(s->stream_ptr, s->stream_end, 2);
544     sample[0] = *s->stream_ptr++;
545     sample[1] = *s->stream_ptr++;
546
547     for (y = 0; y < 8; y++) {
548         for (x = 0; x < 8; x += 2) {
549             *s->pixel_ptr++ = sample[  y & 1 ];
550             *s->pixel_ptr++ = sample[!(y & 1)];
551         }
552         s->pixel_ptr += s->line_inc;
553     }
554
555     /* report success */
556     return 0;
557 }
558
559 static int (* const ipvideo_decode_block[])(IpvideoContext *s) = {
560     ipvideo_decode_block_opcode_0x0, ipvideo_decode_block_opcode_0x1,
561     ipvideo_decode_block_opcode_0x2, ipvideo_decode_block_opcode_0x3,
562     ipvideo_decode_block_opcode_0x4, ipvideo_decode_block_opcode_0x5,
563     ipvideo_decode_block_opcode_0x6, ipvideo_decode_block_opcode_0x7,
564     ipvideo_decode_block_opcode_0x8, ipvideo_decode_block_opcode_0x9,
565     ipvideo_decode_block_opcode_0xA, ipvideo_decode_block_opcode_0xB,
566     ipvideo_decode_block_opcode_0xC, ipvideo_decode_block_opcode_0xD,
567     ipvideo_decode_block_opcode_0xE, ipvideo_decode_block_opcode_0xF,
568 };
569
570 static void ipvideo_decode_opcodes(IpvideoContext *s)
571 {
572     int x, y;
573     unsigned char opcode;
574     int ret;
575     static int frame = 0;
576     GetBitContext gb;
577
578     debug_interplay("------------------ frame %d\n", frame);
579     frame++;
580
581     if (!s->is_16bpp) {
582         /* this is PAL8, so make the palette available */
583         memcpy(s->current_frame.data[1], s->avctx->palctrl->palette, PALETTE_COUNT * 4);
584
585         s->stride = s->current_frame.linesize[0];
586         s->stream_ptr = s->buf + 14;  /* data starts 14 bytes in */
587         s->stream_end = s->buf + s->size;
588     } else {
589         s->stride = s->current_frame.linesize[0] >> 1;
590     }
591     s->line_inc = s->stride - 8;
592     s->upper_motion_limit_offset = (s->avctx->height - 8) * s->stride
593                                   + (s->avctx->width - 8) * (1 + s->is_16bpp);
594
595     init_get_bits(&gb, s->decoding_map, s->decoding_map_size * 8);
596     for (y = 0; y < s->avctx->height; y += 8) {
597         for (x = 0; x < s->avctx->width; x += 8) {
598             opcode = get_bits(&gb, 4);
599
600             debug_interplay("  block @ (%3d, %3d): encoding 0x%X, data ptr @ %p\n",
601                             x, y, opcode, s->stream_ptr);
602
603             if (!s->is_16bpp) {
604                 s->pixel_ptr = s->current_frame.data[0] + x
605                               + y*s->current_frame.linesize[0];
606                 ret = ipvideo_decode_block[opcode](s);
607             } else {
608                 s->pixel_ptr = s->current_frame.data[0] + x*2
609                               + y*s->current_frame.linesize[0];
610             }
611             if (ret != 0) {
612                 av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
613                        frame, x, y);
614                 return;
615             }
616         }
617     }
618     if (s->stream_end - s->stream_ptr > 1) {
619         av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n",
620                s->stream_end - s->stream_ptr);
621     }
622 }
623
624 static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
625 {
626     IpvideoContext *s = avctx->priv_data;
627
628     s->avctx = avctx;
629
630     if (s->avctx->palctrl == NULL) {
631         av_log(avctx, AV_LOG_ERROR, " Interplay video: palette expected.\n");
632         return -1;
633     }
634
635     s->is_16bpp = avctx->bits_per_coded_sample == 16;
636     avctx->pix_fmt = s->is_16bpp ? PIX_FMT_RGB555 : PIX_FMT_PAL8;
637     if (s->is_16bpp) {
638         av_log(avctx, AV_LOG_ERROR, "16-bit Interplay video is not supported yet.\n");
639         return -1;
640     }
641     dsputil_init(&s->dsp, avctx);
642
643     /* decoding map contains 4 bits of information per 8x8 block */
644     s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2);
645
646     s->current_frame.data[0] = s->last_frame.data[0] =
647     s->second_last_frame.data[0] = NULL;
648
649     return 0;
650 }
651
652 static int ipvideo_decode_frame(AVCodecContext *avctx,
653                                 void *data, int *data_size,
654                                 AVPacket *avpkt)
655 {
656     const uint8_t *buf = avpkt->data;
657     int buf_size = avpkt->size;
658     IpvideoContext *s = avctx->priv_data;
659     AVPaletteControl *palette_control = avctx->palctrl;
660
661     /* compressed buffer needs to be large enough to at least hold an entire
662      * decoding map */
663     if (buf_size < s->decoding_map_size)
664         return buf_size;
665
666     s->decoding_map = buf;
667     s->buf = buf + s->decoding_map_size;
668     s->size = buf_size - s->decoding_map_size;
669
670     s->current_frame.reference = 3;
671     if (avctx->get_buffer(avctx, &s->current_frame)) {
672         av_log(avctx, AV_LOG_ERROR, "  Interplay Video: get_buffer() failed\n");
673         return -1;
674     }
675
676     ipvideo_decode_opcodes(s);
677
678     if (!s->is_16bpp && palette_control->palette_changed) {
679         palette_control->palette_changed = 0;
680         s->current_frame.palette_has_changed = 1;
681     }
682
683     *data_size = sizeof(AVFrame);
684     *(AVFrame*)data = s->current_frame;
685
686     /* shuffle frames */
687     if (s->second_last_frame.data[0])
688         avctx->release_buffer(avctx, &s->second_last_frame);
689     s->second_last_frame = s->last_frame;
690     s->last_frame = s->current_frame;
691     s->current_frame.data[0] = NULL;  /* catch any access attempts */
692
693     /* report that the buffer was completely consumed */
694     return buf_size;
695 }
696
697 static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
698 {
699     IpvideoContext *s = avctx->priv_data;
700
701     /* release the last frame */
702     if (s->last_frame.data[0])
703         avctx->release_buffer(avctx, &s->last_frame);
704     if (s->second_last_frame.data[0])
705         avctx->release_buffer(avctx, &s->second_last_frame);
706
707     return 0;
708 }
709
710 AVCodec interplay_video_decoder = {
711     "interplayvideo",
712     CODEC_TYPE_VIDEO,
713     CODEC_ID_INTERPLAY_VIDEO,
714     sizeof(IpvideoContext),
715     ipvideo_decode_init,
716     NULL,
717     ipvideo_decode_end,
718     ipvideo_decode_frame,
719     CODEC_CAP_DR1,
720     .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"),
721 };