• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Flash Screen Video decoder
3  * Copyright (C) 2004 Alex Beregszaszi
4  * Copyright (C) 2006 Benjamin Larsson
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 /**
24  * @file
25  * Flash Screen Video decoder
26  * @author Alex Beregszaszi
27  * @author Benjamin Larsson
28  * @author Daniel Verkamp
29  * @author Konstantin Shishkov
30  *
31  * A description of the bitstream format for Flash Screen Video version 1/2
32  * is part of the SWF File Format Specification (version 10), which can be
33  * downloaded from http://www.adobe.com/devnet/swf.html.
34  */
35 
36 #include "config_components.h"
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <zlib.h>
41 
42 #include "libavutil/intreadwrite.h"
43 #include "avcodec.h"
44 #include "bytestream.h"
45 #include "codec_internal.h"
46 #include "get_bits.h"
47 #include "internal.h"
48 #include "zlib_wrapper.h"
49 
50 typedef struct BlockInfo {
51     const uint8_t *pos;
52     int      size;
53 } BlockInfo;
54 
55 typedef struct FlashSVContext {
56     AVCodecContext *avctx;
57     AVFrame        *frame;
58     int             image_width, image_height;
59     int             block_width, block_height;
60     uint8_t        *tmpblock;
61     int             block_size;
62     int             ver;
63     const uint32_t *pal;
64     int             is_keyframe;
65     const uint8_t  *keyframedata;
66     AVBufferRef    *keyframedata_buf;
67     uint8_t        *keyframe;
68     BlockInfo      *blocks;
69     int             color_depth;
70     int             zlibprime_curr, zlibprime_prev;
71     int             diff_start, diff_height;
72     FFZStream       zstream;
73     uint8_t         tmp[UINT16_MAX];
74 } FlashSVContext;
75 
decode_hybrid(const uint8_t * sptr,const uint8_t * sptr_end,uint8_t * dptr,int dx,int dy,int h,int w,int stride,const uint32_t * pal)76 static int decode_hybrid(const uint8_t *sptr, const uint8_t *sptr_end, uint8_t *dptr, int dx, int dy,
77                          int h, int w, int stride, const uint32_t *pal)
78 {
79     int x, y;
80     const uint8_t *orig_src = sptr;
81 
82     for (y = dx + h; y > dx; y--) {
83         uint8_t *dst = dptr + (y * stride) + dy * 3;
84         for (x = 0; x < w; x++) {
85             if (sptr >= sptr_end)
86                 return AVERROR_INVALIDDATA;
87             if (*sptr & 0x80) {
88                 /* 15-bit color */
89                 unsigned c = AV_RB16(sptr) & ~0x8000;
90                 unsigned b =  c        & 0x1F;
91                 unsigned g = (c >>  5) & 0x1F;
92                 unsigned r =  c >> 10;
93                 /* 000aaabb -> aaabbaaa  */
94                 *dst++ = (b << 3) | (b >> 2);
95                 *dst++ = (g << 3) | (g >> 2);
96                 *dst++ = (r << 3) | (r >> 2);
97                 sptr += 2;
98             } else {
99                 /* palette index */
100                 uint32_t c = pal[*sptr++];
101                 bytestream_put_le24(&dst, c);
102             }
103         }
104     }
105     return sptr - orig_src;
106 }
107 
flashsv_decode_end(AVCodecContext * avctx)108 static av_cold int flashsv_decode_end(AVCodecContext *avctx)
109 {
110     FlashSVContext *s = avctx->priv_data;
111 
112     ff_inflate_end(&s->zstream);
113     /* release the frame if needed */
114     av_frame_free(&s->frame);
115 
116     /* free the tmpblock */
117     av_freep(&s->tmpblock);
118 
119     return 0;
120 }
121 
flashsv_decode_init(AVCodecContext * avctx)122 static av_cold int flashsv_decode_init(AVCodecContext *avctx)
123 {
124     FlashSVContext *s = avctx->priv_data;
125 
126     s->avctx          = avctx;
127     avctx->pix_fmt = AV_PIX_FMT_BGR24;
128 
129     s->frame = av_frame_alloc();
130     if (!s->frame) {
131         return AVERROR(ENOMEM);
132     }
133 
134     return ff_inflate_init(&s->zstream, avctx);
135 }
136 
flashsv2_prime(FlashSVContext * s,const uint8_t * src,int size)137 static int flashsv2_prime(FlashSVContext *s, const uint8_t *src, int size)
138 {
139     int zret; // Zlib return code
140     static const uint8_t zlib_header[] = { 0x78, 0x01 };
141     z_stream *const zstream = &s->zstream.zstream;
142     uint8_t *data = s->tmpblock;
143     unsigned remaining;
144 
145     if (!src)
146         return AVERROR_INVALIDDATA;
147 
148     zstream->next_in   = src;
149     zstream->avail_in  = size;
150     zstream->next_out  = data;
151     zstream->avail_out = s->block_size * 3;
152     zret = inflate(zstream, Z_SYNC_FLUSH);
153     if (zret != Z_OK && zret != Z_STREAM_END)
154         return AVERROR_UNKNOWN;
155     remaining = s->block_size * 3 - zstream->avail_out;
156 
157     if ((zret = inflateReset(zstream)) != Z_OK) {
158         av_log(s->avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret);
159         return AVERROR_UNKNOWN;
160     }
161 
162     /* Create input for zlib that is equivalent to encoding the output
163      * from above and decoding it again (the net result of this is that
164      * the dictionary of past decoded data is correctly primed and
165      * the adler32 checksum is correctly initialized).
166      * This is accomplished by synthetizing blocks of uncompressed data
167      * out of the output from above. See section 3.2.4 of RFC 1951. */
168     zstream->next_in  = zlib_header;
169     zstream->avail_in = sizeof(zlib_header);
170     zret = inflate(zstream, Z_SYNC_FLUSH);
171     if (zret != Z_OK)
172         return AVERROR_UNKNOWN;
173     while (remaining > 0) {
174         unsigned block_size = FFMIN(UINT16_MAX, remaining);
175         uint8_t header[5];
176         /* Bit 0: Non-last-block, bits 1-2: BTYPE for uncompressed block */
177         header[0] = 0;
178         /* Block size */
179         AV_WL16(header + 1, block_size);
180         /* Block size (one's complement) */
181         AV_WL16(header + 3, block_size ^ 0xFFFF);
182         zstream->next_in   = header;
183         zstream->avail_in  = sizeof(header);
184         zstream->next_out  = s->tmp;
185         zstream->avail_out = sizeof(s->tmp);
186         zret = inflate(zstream, Z_SYNC_FLUSH);
187         if (zret != Z_OK)
188             return AVERROR_UNKNOWN;
189         zstream->next_in   = data;
190         zstream->avail_in  = block_size;
191         zret = inflate(zstream, Z_SYNC_FLUSH);
192         if (zret != Z_OK)
193             return AVERROR_UNKNOWN;
194         data      += block_size;
195         remaining -= block_size;
196     }
197 
198     return 0;
199 }
200 
flashsv_decode_block(AVCodecContext * avctx,const AVPacket * avpkt,GetBitContext * gb,int block_size,int width,int height,int x_pos,int y_pos,int blk_idx)201 static int flashsv_decode_block(AVCodecContext *avctx, const AVPacket *avpkt,
202                                 GetBitContext *gb, int block_size,
203                                 int width, int height, int x_pos, int y_pos,
204                                 int blk_idx)
205 {
206     struct FlashSVContext *s = avctx->priv_data;
207     z_stream *const zstream = &s->zstream.zstream;
208     uint8_t *line = s->tmpblock;
209     int k;
210     int ret = inflateReset(zstream);
211     if (ret != Z_OK) {
212         av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
213         return AVERROR_UNKNOWN;
214     }
215     if (s->zlibprime_curr || s->zlibprime_prev) {
216         ret = flashsv2_prime(s,
217                              s->blocks[blk_idx].pos,
218                              s->blocks[blk_idx].size);
219         if (ret < 0)
220             return ret;
221     }
222     zstream->next_in   = avpkt->data + get_bits_count(gb) / 8;
223     zstream->avail_in  = block_size;
224     zstream->next_out  = s->tmpblock;
225     zstream->avail_out = s->block_size * 3;
226     ret = inflate(zstream, Z_FINISH);
227     if (ret == Z_DATA_ERROR) {
228         av_log(avctx, AV_LOG_ERROR, "Zlib resync occurred\n");
229         inflateSync(zstream);
230         ret = inflate(zstream, Z_FINISH);
231     }
232 
233     if (ret != Z_OK && ret != Z_STREAM_END) {
234         //return -1;
235     }
236 
237     if (s->is_keyframe) {
238         s->blocks[blk_idx].pos  = s->keyframedata + (get_bits_count(gb) / 8);
239         s->blocks[blk_idx].size = block_size;
240     }
241 
242     y_pos += s->diff_start;
243 
244     if (!s->color_depth) {
245         /* Flash Screen Video stores the image upside down, so copy
246          * lines to destination in reverse order. */
247         for (k = 1; k <= s->diff_height; k++) {
248             memcpy(s->frame->data[0] + x_pos * 3 +
249                    (s->image_height - y_pos - k) * s->frame->linesize[0],
250                    line, width * 3);
251             /* advance source pointer to next line */
252             line += width * 3;
253         }
254     } else {
255         /* hybrid 15-bit/palette mode */
256         ret = decode_hybrid(s->tmpblock, zstream->next_out,
257                       s->frame->data[0],
258                       s->image_height - (y_pos + 1 + s->diff_height),
259                       x_pos, s->diff_height, width,
260                       s->frame->linesize[0], s->pal);
261         if (ret < 0) {
262             av_log(avctx, AV_LOG_ERROR, "decode_hybrid failed\n");
263             return ret;
264         }
265     }
266     skip_bits_long(gb, 8 * block_size); /* skip the consumed bits */
267     return 0;
268 }
269 
flashsv_decode_frame(AVCodecContext * avctx,AVFrame * rframe,int * got_frame,AVPacket * avpkt)270 static int flashsv_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
271                                 int *got_frame, AVPacket *avpkt)
272 {
273     int buf_size = avpkt->size;
274     FlashSVContext *s = avctx->priv_data;
275     int h_blocks, v_blocks, h_part, v_part, i, j, ret;
276     GetBitContext gb;
277     int last_blockwidth = s->block_width;
278     int last_blockheight= s->block_height;
279 
280     /* no supplementary picture */
281     if (buf_size == 0)
282         return 0;
283     if (buf_size < 4)
284         return -1;
285 
286     if ((ret = init_get_bits8(&gb, avpkt->data, buf_size)) < 0)
287         return ret;
288 
289     /* start to parse the bitstream */
290     s->block_width  = 16 * (get_bits(&gb, 4) + 1);
291     s->image_width  = get_bits(&gb, 12);
292     s->block_height = 16 * (get_bits(&gb, 4) + 1);
293     s->image_height = get_bits(&gb, 12);
294 
295     if (   last_blockwidth != s->block_width
296         || last_blockheight!= s->block_height)
297         av_freep(&s->blocks);
298 
299     if (s->ver == 2) {
300         skip_bits(&gb, 6);
301         if (get_bits1(&gb)) {
302             avpriv_request_sample(avctx, "iframe");
303             return AVERROR_PATCHWELCOME;
304         }
305         if (get_bits1(&gb)) {
306             avpriv_request_sample(avctx, "Custom palette");
307             return AVERROR_PATCHWELCOME;
308         }
309     }
310 
311     /* calculate number of blocks and size of border (partial) blocks */
312     h_blocks = s->image_width  / s->block_width;
313     h_part   = s->image_width  % s->block_width;
314     v_blocks = s->image_height / s->block_height;
315     v_part   = s->image_height % s->block_height;
316 
317     /* the block size could change between frames, make sure the buffer
318      * is large enough, if not, get a larger one */
319     if (s->block_size < s->block_width * s->block_height) {
320         int tmpblock_size = 3 * s->block_width * s->block_height, err;
321 
322         if ((err = av_reallocp(&s->tmpblock, tmpblock_size)) < 0) {
323             s->block_size = 0;
324             av_log(avctx, AV_LOG_ERROR,
325                    "Cannot allocate decompression buffer.\n");
326             return err;
327         }
328     }
329     s->block_size = s->block_width * s->block_height;
330 
331     /* initialize the image size once */
332     if (avctx->width == 0 && avctx->height == 0) {
333         if ((ret = ff_set_dimensions(avctx, s->image_width, s->image_height)) < 0)
334             return ret;
335     }
336 
337     /* check for changes of image width and image height */
338     if (avctx->width != s->image_width || avctx->height != s->image_height) {
339         av_log(avctx, AV_LOG_ERROR,
340                "Frame width or height differs from first frame!\n");
341         av_log(avctx, AV_LOG_ERROR, "fh = %d, fv %d  vs  ch = %d, cv = %d\n",
342                avctx->height, avctx->width, s->image_height, s->image_width);
343         return AVERROR_INVALIDDATA;
344     }
345 
346     /* we care for keyframes only in Screen Video v2 */
347     s->is_keyframe = (avpkt->flags & AV_PKT_FLAG_KEY) && (s->ver == 2);
348     if (s->is_keyframe) {
349         int err = av_buffer_replace(&s->keyframedata_buf, avpkt->buf);
350         if (err < 0)
351             return err;
352         s->keyframedata = avpkt->data;
353         if (s->blocks)
354             memset(s->blocks, 0, (v_blocks + !!v_part) * (h_blocks + !!h_part) *
355                                  sizeof(s->blocks[0]));
356     }
357     if(s->ver == 2 && !s->blocks)
358         s->blocks = av_mallocz((v_blocks + !!v_part) * (h_blocks + !!h_part) *
359                                sizeof(s->blocks[0]));
360 
361     ff_dlog(avctx, "image: %dx%d block: %dx%d num: %dx%d part: %dx%d\n",
362             s->image_width, s->image_height, s->block_width, s->block_height,
363             h_blocks, v_blocks, h_part, v_part);
364 
365     if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
366         return ret;
367 
368     /* loop over all block columns */
369     for (j = 0; j < v_blocks + (v_part ? 1 : 0); j++) {
370 
371         int y_pos  = j * s->block_height; // vertical position in frame
372         int cur_blk_height = (j < v_blocks) ? s->block_height : v_part;
373 
374         /* loop over all block rows */
375         for (i = 0; i < h_blocks + (h_part ? 1 : 0); i++) {
376             int x_pos = i * s->block_width; // horizontal position in frame
377             int cur_blk_width = (i < h_blocks) ? s->block_width : h_part;
378             int has_diff = 0;
379 
380             /* get the size of the compressed zlib chunk */
381             int size = get_bits(&gb, 16);
382 
383             s->color_depth    = 0;
384             s->zlibprime_curr = 0;
385             s->zlibprime_prev = 0;
386             s->diff_start     = 0;
387             s->diff_height    = cur_blk_height;
388 
389             if (8 * size > get_bits_left(&gb)) {
390                 av_frame_unref(s->frame);
391                 return AVERROR_INVALIDDATA;
392             }
393 
394             if (s->ver == 2 && size) {
395                 skip_bits(&gb, 3);
396                 s->color_depth    = get_bits(&gb, 2);
397                 has_diff          = get_bits1(&gb);
398                 s->zlibprime_curr = get_bits1(&gb);
399                 s->zlibprime_prev = get_bits1(&gb);
400 
401                 if (s->color_depth != 0 && s->color_depth != 2) {
402                     av_log(avctx, AV_LOG_ERROR,
403                            "%dx%d invalid color depth %d\n",
404                            i, j, s->color_depth);
405                     return AVERROR_INVALIDDATA;
406                 }
407 
408                 if (has_diff) {
409                     if (size < 3) {
410                         av_log(avctx, AV_LOG_ERROR, "size too small for diff\n");
411                         return AVERROR_INVALIDDATA;
412                     }
413                     if (!s->keyframe) {
414                         av_log(avctx, AV_LOG_ERROR,
415                                "Inter frame without keyframe\n");
416                         return AVERROR_INVALIDDATA;
417                     }
418                     s->diff_start  = get_bits(&gb, 8);
419                     s->diff_height = get_bits(&gb, 8);
420                     if (s->diff_start + s->diff_height > cur_blk_height) {
421                         av_log(avctx, AV_LOG_ERROR,
422                                "Block parameters invalid: %d + %d > %d\n",
423                                s->diff_start, s->diff_height, cur_blk_height);
424                         return AVERROR_INVALIDDATA;
425                     }
426                     av_log(avctx, AV_LOG_DEBUG,
427                            "%dx%d diff start %d height %d\n",
428                            i, j, s->diff_start, s->diff_height);
429                     size -= 2;
430                 }
431 
432                 if (s->zlibprime_prev)
433                     av_log(avctx, AV_LOG_DEBUG, "%dx%d zlibprime_prev\n", i, j);
434 
435                 if (s->zlibprime_curr) {
436                     int col = get_bits(&gb, 8);
437                     int row = get_bits(&gb, 8);
438                     av_log(avctx, AV_LOG_DEBUG, "%dx%d zlibprime_curr %dx%d\n",
439                            i, j, col, row);
440                     if (size < 3) {
441                         av_log(avctx, AV_LOG_ERROR, "size too small for zlibprime_curr\n");
442                         return AVERROR_INVALIDDATA;
443                     }
444                     size -= 2;
445                     avpriv_request_sample(avctx, "zlibprime_curr");
446                     return AVERROR_PATCHWELCOME;
447                 }
448                 if (!s->blocks && (s->zlibprime_curr || s->zlibprime_prev)) {
449                     av_log(avctx, AV_LOG_ERROR,
450                            "no data available for zlib priming\n");
451                     return AVERROR_INVALIDDATA;
452                 }
453                 size--; // account for flags byte
454             }
455 
456             if (has_diff) {
457                 int k;
458                 int off = (s->image_height - y_pos - 1) * s->frame->linesize[0];
459 
460                 for (k = 0; k < cur_blk_height; k++) {
461                     int x = off - k * s->frame->linesize[0] + x_pos * 3;
462                     memcpy(s->frame->data[0] + x, s->keyframe + x,
463                            cur_blk_width * 3);
464                 }
465             }
466 
467             /* skip unchanged blocks, which have size 0 */
468             if (size) {
469                 if (flashsv_decode_block(avctx, avpkt, &gb, size,
470                                          cur_blk_width, cur_blk_height,
471                                          x_pos, y_pos,
472                                          i + j * (h_blocks + !!h_part)))
473                     av_log(avctx, AV_LOG_ERROR,
474                            "error in decompression of block %dx%d\n", i, j);
475             }
476         }
477     }
478     if (s->is_keyframe && s->ver == 2) {
479         if (!s->keyframe) {
480             s->keyframe = av_malloc(s->frame->linesize[0] * avctx->height);
481             if (!s->keyframe) {
482                 av_log(avctx, AV_LOG_ERROR, "Cannot allocate image data\n");
483                 return AVERROR(ENOMEM);
484             }
485         }
486         memcpy(s->keyframe, s->frame->data[0],
487                s->frame->linesize[0] * avctx->height);
488     }
489 
490     if ((ret = av_frame_ref(rframe, s->frame)) < 0)
491         return ret;
492 
493     *got_frame = 1;
494 
495     if ((get_bits_count(&gb) / 8) != buf_size)
496         av_log(avctx, AV_LOG_ERROR, "buffer not fully consumed (%d != %d)\n",
497                buf_size, (get_bits_count(&gb) / 8));
498 
499     /* report that the buffer was completely consumed */
500     return buf_size;
501 }
502 
503 #if CONFIG_FLASHSV_DECODER
504 const FFCodec ff_flashsv_decoder = {
505     .p.name         = "flashsv",
506     .p.long_name    = NULL_IF_CONFIG_SMALL("Flash Screen Video v1"),
507     .p.type         = AVMEDIA_TYPE_VIDEO,
508     .p.id           = AV_CODEC_ID_FLASHSV,
509     .priv_data_size = sizeof(FlashSVContext),
510     .init           = flashsv_decode_init,
511     .close          = flashsv_decode_end,
512     FF_CODEC_DECODE_CB(flashsv_decode_frame),
513     .p.capabilities = AV_CODEC_CAP_DR1,
514     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
515     .p.pix_fmts     = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
516 };
517 #endif /* CONFIG_FLASHSV_DECODER */
518 
519 #if CONFIG_FLASHSV2_DECODER
520 static const uint32_t ff_flashsv2_default_palette[128] = {
521     0x000000, 0x333333, 0x666666, 0x999999, 0xCCCCCC, 0xFFFFFF,
522     0x330000, 0x660000, 0x990000, 0xCC0000, 0xFF0000, 0x003300,
523     0x006600, 0x009900, 0x00CC00, 0x00FF00, 0x000033, 0x000066,
524     0x000099, 0x0000CC, 0x0000FF, 0x333300, 0x666600, 0x999900,
525     0xCCCC00, 0xFFFF00, 0x003333, 0x006666, 0x009999, 0x00CCCC,
526     0x00FFFF, 0x330033, 0x660066, 0x990099, 0xCC00CC, 0xFF00FF,
527     0xFFFF33, 0xFFFF66, 0xFFFF99, 0xFFFFCC, 0xFF33FF, 0xFF66FF,
528     0xFF99FF, 0xFFCCFF, 0x33FFFF, 0x66FFFF, 0x99FFFF, 0xCCFFFF,
529     0xCCCC33, 0xCCCC66, 0xCCCC99, 0xCCCCFF, 0xCC33CC, 0xCC66CC,
530     0xCC99CC, 0xCCFFCC, 0x33CCCC, 0x66CCCC, 0x99CCCC, 0xFFCCCC,
531     0x999933, 0x999966, 0x9999CC, 0x9999FF, 0x993399, 0x996699,
532     0x99CC99, 0x99FF99, 0x339999, 0x669999, 0xCC9999, 0xFF9999,
533     0x666633, 0x666699, 0x6666CC, 0x6666FF, 0x663366, 0x669966,
534     0x66CC66, 0x66FF66, 0x336666, 0x996666, 0xCC6666, 0xFF6666,
535     0x333366, 0x333399, 0x3333CC, 0x3333FF, 0x336633, 0x339933,
536     0x33CC33, 0x33FF33, 0x663333, 0x993333, 0xCC3333, 0xFF3333,
537     0x003366, 0x336600, 0x660033, 0x006633, 0x330066, 0x663300,
538     0x336699, 0x669933, 0x993366, 0x339966, 0x663399, 0x996633,
539     0x6699CC, 0x99CC66, 0xCC6699, 0x66CC99, 0x9966CC, 0xCC9966,
540     0x99CCFF, 0xCCFF99, 0xFF99CC, 0x99FFCC, 0xCC99FF, 0xFFCC99,
541     0x111111, 0x222222, 0x444444, 0x555555, 0xAAAAAA, 0xBBBBBB,
542     0xDDDDDD, 0xEEEEEE
543 };
544 
flashsv2_decode_init(AVCodecContext * avctx)545 static av_cold int flashsv2_decode_init(AVCodecContext *avctx)
546 {
547     FlashSVContext *s = avctx->priv_data;
548     int ret;
549 
550     ret = flashsv_decode_init(avctx);
551     if (ret < 0)
552         return ret;
553     s->pal = ff_flashsv2_default_palette;
554     s->ver = 2;
555 
556     return 0;
557 }
558 
flashsv2_decode_end(AVCodecContext * avctx)559 static av_cold int flashsv2_decode_end(AVCodecContext *avctx)
560 {
561     FlashSVContext *s = avctx->priv_data;
562 
563     av_buffer_unref(&s->keyframedata_buf);
564     s->keyframedata = NULL;
565     av_freep(&s->blocks);
566     av_freep(&s->keyframe);
567     flashsv_decode_end(avctx);
568 
569     return 0;
570 }
571 
572 const FFCodec ff_flashsv2_decoder = {
573     .p.name         = "flashsv2",
574     .p.long_name    = NULL_IF_CONFIG_SMALL("Flash Screen Video v2"),
575     .p.type         = AVMEDIA_TYPE_VIDEO,
576     .p.id           = AV_CODEC_ID_FLASHSV2,
577     .priv_data_size = sizeof(FlashSVContext),
578     .init           = flashsv2_decode_init,
579     .close          = flashsv2_decode_end,
580     FF_CODEC_DECODE_CB(flashsv_decode_frame),
581     .p.capabilities = AV_CODEC_CAP_DR1,
582     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
583     .p.pix_fmts     = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
584 };
585 #endif /* CONFIG_FLASHSV2_DECODER */
586