Coverage Report

Created: 2026-02-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/flashsv2enc.c
Line
Count
Source
1
/*
2
 * Flash Screen Video Version 2 encoder
3
 * Copyright (C) 2009 Joshua Warner
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
 * Flash Screen Video Version 2 encoder
25
 * @author Joshua Warner
26
 */
27
28
/* Differences from version 1 stream:
29
 * NOTE: Currently, the only player that supports version 2 streams is Adobe Flash Player itself.
30
 * * Supports sending only a range of scanlines in a block,
31
 *   indicating a difference from the corresponding block in the last keyframe.
32
 * * Supports initializing the zlib dictionary with data from the corresponding
33
 *   block in the last keyframe, to improve compression.
34
 * * Supports a hybrid 15-bit rgb / 7-bit palette color space.
35
 */
36
37
/* TODO:
38
 * Don't keep Block structures for both current frame and keyframe.
39
 * Make better heuristics for deciding stream parameters (optimum_* functions).  Currently these return constants.
40
 * Figure out how to encode palette information in the stream, choose an optimum palette at each keyframe.
41
 * Figure out how the zlibPrimeCompressCurrent flag works, implement support.
42
 * Find other sample files (that weren't generated here), develop a decoder.
43
 */
44
45
#include <stdio.h>
46
#include <stdlib.h>
47
#include <zlib.h>
48
49
#include "libavutil/imgutils.h"
50
#include "libavutil/mem.h"
51
#include "avcodec.h"
52
#include "codec_internal.h"
53
#include "encode.h"
54
#include "put_bits.h"
55
#include "zlib_wrapper.h"
56
57
#define HAS_IFRAME_IMAGE 0x02
58
13.1k
#define HAS_PALLET_INFO 0x01
59
60
#define COLORSPACE_BGR 0x00
61
68.0k
#define COLORSPACE_15_7 0x10
62
69.6k
#define HAS_DIFF_BLOCKS 0x04
63
66.7k
#define ZLIB_PRIME_COMPRESS_CURRENT 0x02
64
11.1k
#define ZLIB_PRIME_COMPRESS_PREVIOUS 0x01
65
66
// Disables experimental "smart" parameter-choosing code, as well as the statistics that it depends on.
67
// At the moment, the "smart" code is a great example of how the parameters *shouldn't* be chosen.
68
#define FLASHSV2_DUMB
69
70
typedef struct Block {
71
    uint8_t *enc;
72
    uint8_t *sl_begin, *sl_end;
73
    int enc_size;
74
    uint8_t *data;
75
    unsigned long data_size;
76
77
    uint8_t start, len;
78
    uint8_t dirty;
79
    uint8_t col, row, width, height;
80
    uint8_t flags;
81
} Block;
82
83
typedef struct Palette {
84
    unsigned colors[128];
85
    uint8_t index[1 << 15];
86
} Palette;
87
88
typedef struct FlashSV2Context {
89
    AVCodecContext *avctx;
90
    uint8_t *current_frame;
91
    uint8_t *key_frame;
92
    uint8_t *encbuffer;
93
    uint8_t *keybuffer;
94
    uint8_t *databuffer;
95
96
    uint8_t *blockbuffer;
97
    int blockbuffer_size;
98
99
    Block *frame_blocks;
100
    Block *key_blocks;
101
    int frame_size;
102
    int blocks_size;
103
104
    int use15_7, dist, comp;
105
106
    int rows, cols;
107
108
    int64_t last_key_frame;
109
110
    int image_width, image_height;
111
    int block_width, block_height;
112
    uint8_t flags;
113
    uint8_t use_custom_palette;
114
    uint8_t palette_type;       ///< 0=>default, 1=>custom - changed when palette regenerated.
115
    Palette palette;
116
    FFZStream zstream;
117
#ifndef FLASHSV2_DUMB
118
    double tot_blocks;          ///< blocks encoded since last keyframe
119
    double diff_blocks;         ///< blocks that were different since last keyframe
120
    double tot_lines;           ///< total scanlines in image since last keyframe
121
    double diff_lines;          ///< scanlines that were different since last keyframe
122
    double raw_size;            ///< size of raw frames since last keyframe
123
    double comp_size;           ///< size of compressed data since last keyframe
124
    double uncomp_size;         ///< size of uncompressed data since last keyframe
125
126
    double total_bits;          ///< total bits written to stream so far
127
#endif
128
} FlashSV2Context;
129
130
static av_cold void cleanup(FlashSV2Context * s)
131
1.08k
{
132
1.08k
    av_freep(&s->encbuffer);
133
1.08k
    av_freep(&s->keybuffer);
134
1.08k
    av_freep(&s->databuffer);
135
1.08k
    av_freep(&s->blockbuffer);
136
1.08k
    av_freep(&s->current_frame);
137
1.08k
    av_freep(&s->key_frame);
138
139
1.08k
    av_freep(&s->frame_blocks);
140
1.08k
    av_freep(&s->key_blocks);
141
1.08k
    ff_deflate_end(&s->zstream);
142
1.08k
}
143
144
static void init_blocks(FlashSV2Context * s, Block * blocks,
145
                        uint8_t * encbuf, uint8_t * databuf)
146
2.11k
{
147
2.11k
    int row, col;
148
2.11k
    Block *b;
149
2.11k
    memset(blocks, 0, s->cols * s->rows * sizeof(*blocks));
150
21.0k
    for (col = 0; col < s->cols; col++) {
151
60.2k
        for (row = 0; row < s->rows; row++) {
152
41.2k
            b = blocks + (col + row * s->cols);
153
41.2k
            b->width = (col < s->cols - 1) ?
154
33.9k
                s->block_width :
155
41.2k
                s->image_width - col * s->block_width;
156
157
41.2k
            b->height = (row < s->rows - 1) ?
158
22.2k
                s->block_height :
159
41.2k
                s->image_height - row * s->block_height;
160
161
41.2k
            b->row   = row;
162
41.2k
            b->col   = col;
163
41.2k
            b->enc   = encbuf;
164
41.2k
            b->data  = databuf;
165
41.2k
            encbuf  += b->width * b->height * 3;
166
41.2k
            databuf  = databuf ? databuf + b->width * b->height * 6 : NULL;
167
41.2k
        }
168
18.9k
    }
169
2.11k
}
170
171
static void reset_stats(FlashSV2Context * s)
172
3.02k
{
173
#ifndef FLASHSV2_DUMB
174
    s->diff_blocks = 0.1;
175
    s->tot_blocks = 1;
176
    s->diff_lines = 0.1;
177
    s->tot_lines = 1;
178
    s->raw_size = s->comp_size = s->uncomp_size = 10;
179
#endif
180
3.02k
}
181
182
static int update_block_dimensions(FlashSV2Context *s, int block_width, int block_height)
183
1.05k
{
184
1.05k
    s->block_width  = block_width;
185
1.05k
    s->block_height = block_height;
186
1.05k
    s->rows = (s->image_height + s->block_height - 1) / s->block_height;
187
1.05k
    s->cols = (s->image_width  + s->block_width  - 1) / s->block_width;
188
1.05k
    if (s->rows * s->cols > s->blocks_size / sizeof(Block)) {
189
1.05k
        s->frame_blocks = av_realloc_array(s->frame_blocks, s->rows, s->cols * sizeof(Block));
190
1.05k
        s->key_blocks = av_realloc_array(s->key_blocks, s->cols, s->rows * sizeof(Block));
191
1.05k
        if (!s->frame_blocks || !s->key_blocks) {
192
0
            av_log(s->avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
193
0
            return AVERROR(ENOMEM);
194
0
        }
195
1.05k
        s->blocks_size = s->rows * s->cols * sizeof(Block);
196
1.05k
    }
197
1.05k
    init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
198
1.05k
    init_blocks(s, s->key_blocks, s->keybuffer, 0);
199
200
1.05k
    av_fast_malloc(&s->blockbuffer, &s->blockbuffer_size, block_width * block_height * 6);
201
1.05k
    if (!s->blockbuffer) {
202
0
        av_log(s->avctx, AV_LOG_ERROR, "Could not allocate block buffer.\n");
203
0
        return AVERROR(ENOMEM);
204
0
    }
205
1.05k
    return 0;
206
1.05k
}
207
208
209
static av_cold int flashsv2_encode_init(AVCodecContext * avctx)
210
1.08k
{
211
1.08k
    FlashSV2Context *s = avctx->priv_data;
212
1.08k
    int ret;
213
214
1.08k
    s->avctx = avctx;
215
216
1.08k
    s->comp = avctx->compression_level;
217
1.08k
    if (s->comp == -1)
218
1.08k
        s->comp = 9;
219
1.08k
    if (s->comp < 0 || s->comp > 9) {
220
0
        av_log(avctx, AV_LOG_ERROR,
221
0
               "Compression level should be 0-9, not %d\n", s->comp);
222
0
        return AVERROR(EINVAL);
223
0
    }
224
225
226
1.08k
    if ((avctx->width > 4095) || (avctx->height > 4095)) {
227
19
        av_log(avctx, AV_LOG_ERROR,
228
19
               "Input dimensions too large, input must be max 4095x4095 !\n");
229
19
        return AVERROR(EINVAL);
230
19
    }
231
1.06k
    if ((avctx->width < 16) || (avctx->height < 16)) {
232
9
        av_log(avctx, AV_LOG_ERROR,
233
9
               "Input dimensions too small, input must be at least 16x16 !\n");
234
9
        return AVERROR(EINVAL);
235
9
    }
236
237
1.05k
    if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
238
0
        return ret;
239
240
1.05k
    ret = ff_deflate_init(&s->zstream, s->comp, avctx);
241
1.05k
    if (ret < 0)
242
0
        return ret;
243
1.05k
    s->last_key_frame = 0;
244
245
1.05k
    s->image_width  = avctx->width;
246
1.05k
    s->image_height = avctx->height;
247
248
1.05k
    s->frame_size  = s->image_width * s->image_height * 3;
249
250
1.05k
    s->encbuffer     = av_mallocz(s->frame_size);
251
1.05k
    s->keybuffer     = av_mallocz(s->frame_size);
252
1.05k
    s->databuffer    = av_mallocz(s->frame_size * 6);
253
1.05k
    s->current_frame = av_mallocz(s->frame_size);
254
1.05k
    s->key_frame     = av_mallocz(s->frame_size);
255
1.05k
    if (!s->encbuffer || !s->keybuffer || !s->databuffer
256
1.05k
        || !s->current_frame || !s->key_frame) {
257
0
        av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
258
0
        return AVERROR(ENOMEM);
259
0
    }
260
261
1.05k
    reset_stats(s);
262
#ifndef FLASHSV2_DUMB
263
    s->total_bits = 1;
264
#endif
265
266
1.05k
    s->use_custom_palette =  0;
267
1.05k
    s->palette_type       = -1;        // so that the palette will be generated in reconfigure_at_keyframe
268
269
1.05k
    return update_block_dimensions(s, 64, 64);
270
1.05k
}
271
272
static int new_key_frame(FlashSV2Context * s)
273
1.96k
{
274
1.96k
    int i;
275
1.96k
    memcpy(s->key_blocks, s->frame_blocks, s->blocks_size);
276
1.96k
    memcpy(s->key_frame, s->current_frame, s->frame_size);
277
278
23.6k
    for (i = 0; i < s->rows * s->cols; i++) {
279
21.6k
        s->key_blocks[i].enc += (s->keybuffer - s->encbuffer);
280
21.6k
        s->key_blocks[i].sl_begin = 0;
281
21.6k
        s->key_blocks[i].sl_end   = 0;
282
21.6k
        s->key_blocks[i].data     = 0;
283
21.6k
    }
284
1.96k
    memcpy(s->keybuffer, s->encbuffer, s->frame_size);
285
286
1.96k
    return 0;
287
1.96k
}
288
289
static int write_palette(FlashSV2Context * s, uint8_t * buf, int buf_size)
290
0
{
291
    //this isn't implemented yet!  Default palette only!
292
0
    return -1;
293
0
}
294
295
static int write_header(FlashSV2Context * s, uint8_t * buf, int buf_size)
296
13.1k
{
297
13.1k
    PutBitContext pb;
298
13.1k
    int buf_pos, len;
299
300
13.1k
    if (buf_size < 5)
301
0
        return -1;
302
303
13.1k
    init_put_bits(&pb, buf, buf_size);
304
305
13.1k
    put_bits(&pb, 4, (s->block_width  >> 4) - 1);
306
13.1k
    put_bits(&pb, 12, s->image_width);
307
13.1k
    put_bits(&pb, 4, (s->block_height >> 4) - 1);
308
13.1k
    put_bits(&pb, 12, s->image_height);
309
310
13.1k
    flush_put_bits(&pb);
311
13.1k
    buf_pos = 4;
312
313
13.1k
    buf[buf_pos++] = s->flags;
314
315
13.1k
    if (s->flags & HAS_PALLET_INFO) {
316
0
        len = write_palette(s, buf + buf_pos, buf_size - buf_pos);
317
0
        if (len < 0)
318
0
            return -1;
319
0
        buf_pos += len;
320
0
    }
321
322
13.1k
    return buf_pos;
323
13.1k
}
324
325
static int write_block(Block * b, uint8_t * buf, int buf_size)
326
33.7k
{
327
33.7k
    int buf_pos = 0;
328
33.7k
    unsigned block_size = b->data_size;
329
330
33.7k
    if (b->flags & HAS_DIFF_BLOCKS)
331
2.90k
        block_size += 2;
332
33.7k
    if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT)
333
0
        block_size += 2;
334
33.7k
    if (block_size > 0)
335
32.9k
        block_size += 1;
336
33.7k
    if (buf_size < block_size + 2)
337
0
        return -1;
338
339
33.7k
    buf[buf_pos++] = block_size >> 8;
340
33.7k
    buf[buf_pos++] = block_size;
341
342
33.7k
    if (block_size == 0)
343
875
        return buf_pos;
344
345
32.9k
    buf[buf_pos++] = b->flags;
346
347
32.9k
    if (b->flags & HAS_DIFF_BLOCKS) {
348
2.90k
        buf[buf_pos++] = (b->start);
349
2.90k
        buf[buf_pos++] = (b->len);
350
2.90k
    }
351
352
32.9k
    if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT) {
353
        //This feature of the format is poorly understood, and as of now, unused.
354
0
        buf[buf_pos++] = (b->col);
355
0
        buf[buf_pos++] = (b->row);
356
0
    }
357
358
32.9k
    memcpy(buf + buf_pos, b->data, b->data_size);
359
360
32.9k
    buf_pos += b->data_size;
361
362
32.9k
    return buf_pos;
363
33.7k
}
364
365
static int encode_zlib(Block *b, uint8_t *buf, unsigned long *buf_size,
366
                       z_stream *zstream)
367
33.4k
{
368
33.4k
    int res;
369
370
33.4k
    if (deflateReset(zstream) != Z_OK)
371
0
        return AVERROR_EXTERNAL;
372
33.4k
    zstream->next_out  = buf;
373
33.4k
    zstream->avail_out = *buf_size;
374
33.4k
    zstream->next_in   = b->sl_begin;
375
33.4k
    zstream->avail_in  = b->sl_end - b->sl_begin;
376
33.4k
    res = deflate(zstream, Z_FINISH);
377
33.4k
    if (res != Z_STREAM_END)
378
22
        return AVERROR_EXTERNAL;
379
33.4k
    *buf_size -= zstream->avail_out;
380
33.4k
    return 0;
381
33.4k
}
382
383
static int encode_zlibprime(Block * b, Block * prime, uint8_t * buf,
384
                            int *buf_size, z_stream *zstream)
385
11.7k
{
386
11.7k
    int res;
387
388
11.7k
    if (deflateReset(zstream) != Z_OK)
389
0
        return AVERROR_EXTERNAL;
390
11.7k
    zstream->next_in  = prime->enc;
391
11.7k
    zstream->avail_in = prime->enc_size;
392
23.5k
    while (zstream->avail_in > 0) {
393
11.7k
        zstream->next_out  = buf;
394
11.7k
        zstream->avail_out = *buf_size;
395
11.7k
        res = deflate(zstream, Z_SYNC_FLUSH);
396
11.7k
        if (res < 0)
397
0
            return -1;
398
11.7k
    }
399
400
11.7k
    zstream->next_in   = b->sl_begin;
401
11.7k
    zstream->avail_in  = b->sl_end - b->sl_begin;
402
11.7k
    zstream->next_out  = buf;
403
11.7k
    zstream->avail_out = *buf_size;
404
11.7k
    res = deflate(zstream, Z_FINISH);
405
11.7k
    *buf_size -= zstream->avail_out;
406
11.7k
    if (res != Z_STREAM_END)
407
0
        return -1;
408
11.7k
    return 0;
409
11.7k
}
410
411
static int encode_bgr(Block * b, const uint8_t * src, int stride)
412
0
{
413
0
    int i;
414
0
    uint8_t *ptr = b->enc;
415
0
    for (i = 0; i < b->start; i++)
416
0
        memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
417
0
    b->sl_begin = ptr + i * b->width * 3;
418
0
    for (; i < b->start + b->len; i++)
419
0
        memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
420
0
    b->sl_end = ptr + i * b->width * 3;
421
0
    for (; i < b->height; i++)
422
0
        memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
423
0
    b->enc_size = ptr + i * b->width * 3 - b->enc;
424
0
    return b->enc_size;
425
0
}
426
427
static inline unsigned pixel_color15(const uint8_t * src)
428
66.1M
{
429
66.1M
    return (src[0] >> 3) | ((src[1] & 0xf8) << 2) | ((src[2] & 0xf8) << 7);
430
66.1M
}
431
432
static inline unsigned int chroma_diff(unsigned int c1, unsigned int c2)
433
4.57G
{
434
18.2G
#define ABSDIFF(a,b) (abs((int)(a)-(int)(b)))
435
436
4.57G
    unsigned int t1 = (c1 & 0x000000ff) + ((c1 & 0x0000ff00) >> 8) + ((c1 & 0x00ff0000) >> 16);
437
4.57G
    unsigned int t2 = (c2 & 0x000000ff) + ((c2 & 0x0000ff00) >> 8) + ((c2 & 0x00ff0000) >> 16);
438
439
4.57G
    return ABSDIFF(t1, t2) + ABSDIFF(c1 & 0x000000ff, c2 & 0x000000ff) +
440
4.57G
        ABSDIFF((c1 & 0x0000ff00) >> 8 , (c2 & 0x0000ff00) >> 8) +
441
4.57G
        ABSDIFF((c1 & 0x00ff0000) >> 16, (c2 & 0x00ff0000) >> 16);
442
4.57G
}
443
444
static inline int pixel_color7_fast(Palette * palette, unsigned c15)
445
66.1M
{
446
66.1M
    return palette->index[c15];
447
66.1M
}
448
449
static int pixel_color7_slow(Palette * palette, unsigned color)
450
34.7M
{
451
34.7M
    int i, min = 0x7fffffff;
452
34.7M
    int minc = -1;
453
4.47G
    for (i = 0; i < 128; i++) {
454
4.44G
        int c1 = palette->colors[i];
455
4.44G
        int diff = chroma_diff(c1, color);
456
4.44G
        if (diff < min) {
457
215M
            min = diff;
458
215M
            minc = i;
459
215M
        }
460
4.44G
    }
461
34.7M
    return minc;
462
34.7M
}
463
464
static inline unsigned pixel_bgr(const uint8_t * src)
465
66.1M
{
466
66.1M
    return (src[0]) | (src[1] << 8) | (src[2] << 16);
467
66.1M
}
468
469
static int write_pixel_15_7(Palette * palette, uint8_t * dest, const uint8_t * src,
470
                            int dist)
471
66.1M
{
472
66.1M
    unsigned c15 = pixel_color15(src);
473
66.1M
    unsigned color = pixel_bgr(src);
474
66.1M
    int d15 = chroma_diff(color, color & 0x00f8f8f8);
475
66.1M
    int c7 = pixel_color7_fast(palette, c15);
476
66.1M
    int d7 = chroma_diff(color, palette->colors[c7]);
477
66.1M
    if (dist + d15 >= d7) {
478
58.3M
        dest[0] = c7;
479
58.3M
        return 1;
480
58.3M
    } else {
481
7.79M
        dest[0] = 0x80 | (c15 >> 8);
482
7.79M
        dest[1] = c15 & 0xff;
483
7.79M
        return 2;
484
7.79M
    }
485
66.1M
}
486
487
static int update_palette_index(Palette * palette)
488
1.05k
{
489
1.05k
    int r, g, b;
490
1.05k
    unsigned int bgr, c15, index;
491
34.9k
    for (r = 4; r < 256; r += 8) {
492
1.11M
        for (g = 4; g < 256; g += 8) {
493
35.7M
            for (b = 4; b < 256; b += 8) {
494
34.7M
                bgr = b | (g << 8) | (r << 16);
495
34.7M
                c15 = (b >> 3) | ((g & 0xf8) << 2) | ((r & 0xf8) << 7);
496
34.7M
                index = pixel_color7_slow(palette, bgr);
497
498
34.7M
                palette->index[c15] = index;
499
34.7M
            }
500
1.08M
        }
501
33.8k
    }
502
1.05k
    return 0;
503
1.05k
}
504
505
static const unsigned int default_screen_video_v2_palette[128] = {
506
    0x00000000, 0x00333333, 0x00666666, 0x00999999, 0x00CCCCCC, 0x00FFFFFF,
507
    0x00330000, 0x00660000, 0x00990000, 0x00CC0000, 0x00FF0000, 0x00003300,
508
    0x00006600, 0x00009900, 0x0000CC00, 0x0000FF00, 0x00000033, 0x00000066,
509
    0x00000099, 0x000000CC, 0x000000FF, 0x00333300, 0x00666600, 0x00999900,
510
    0x00CCCC00, 0x00FFFF00, 0x00003333, 0x00006666, 0x00009999, 0x0000CCCC,
511
    0x0000FFFF, 0x00330033, 0x00660066, 0x00990099, 0x00CC00CC, 0x00FF00FF,
512
    0x00FFFF33, 0x00FFFF66, 0x00FFFF99, 0x00FFFFCC, 0x00FF33FF, 0x00FF66FF,
513
    0x00FF99FF, 0x00FFCCFF, 0x0033FFFF, 0x0066FFFF, 0x0099FFFF, 0x00CCFFFF,
514
    0x00CCCC33, 0x00CCCC66, 0x00CCCC99, 0x00CCCCFF, 0x00CC33CC, 0x00CC66CC,
515
    0x00CC99CC, 0x00CCFFCC, 0x0033CCCC, 0x0066CCCC, 0x0099CCCC, 0x00FFCCCC,
516
    0x00999933, 0x00999966, 0x009999CC, 0x009999FF, 0x00993399, 0x00996699,
517
    0x0099CC99, 0x0099FF99, 0x00339999, 0x00669999, 0x00CC9999, 0x00FF9999,
518
    0x00666633, 0x00666699, 0x006666CC, 0x006666FF, 0x00663366, 0x00669966,
519
    0x0066CC66, 0x0066FF66, 0x00336666, 0x00996666, 0x00CC6666, 0x00FF6666,
520
    0x00333366, 0x00333399, 0x003333CC, 0x003333FF, 0x00336633, 0x00339933,
521
    0x0033CC33, 0x0033FF33, 0x00663333, 0x00993333, 0x00CC3333, 0x00FF3333,
522
    0x00003366, 0x00336600, 0x00660033, 0x00006633, 0x00330066, 0x00663300,
523
    0x00336699, 0x00669933, 0x00993366, 0x00339966, 0x00663399, 0x00996633,
524
    0x006699CC, 0x0099CC66, 0x00CC6699, 0x0066CC99, 0x009966CC, 0x00CC9966,
525
    0x0099CCFF, 0x00CCFF99, 0x00FF99CC, 0x0099FFCC, 0x00CC99FF, 0x00FFCC99,
526
    0x00111111, 0x00222222, 0x00444444, 0x00555555, 0x00AAAAAA, 0x00BBBBBB,
527
    0x00DDDDDD, 0x00EEEEEE
528
};
529
530
static int generate_default_palette(Palette * palette)
531
1.05k
{
532
1.05k
    memcpy(palette->colors, default_screen_video_v2_palette,
533
1.05k
           sizeof(default_screen_video_v2_palette));
534
535
1.05k
    return update_palette_index(palette);
536
1.05k
}
537
538
static int generate_optimum_palette(Palette * palette, const uint8_t * image,
539
                                   int width, int height, int stride)
540
0
{
541
    //this isn't implemented yet!  Default palette only!
542
0
    return -1;
543
0
}
544
545
static inline int encode_15_7_sl(Palette * palette, uint8_t * dest,
546
                                 const uint8_t * src, int width, int dist)
547
1.27M
{
548
1.27M
    int len = 0, x;
549
67.4M
    for (x = 0; x < width; x++) {
550
66.1M
        len += write_pixel_15_7(palette, dest + len, src + 3 * x, dist);
551
66.1M
    }
552
1.27M
    return len;
553
1.27M
}
554
555
static int encode_15_7(Palette * palette, Block * b, const uint8_t * src,
556
                       int stride, int dist)
557
33.5k
{
558
33.5k
    int i;
559
33.5k
    uint8_t *ptr = b->enc;
560
46.8k
    for (i = 0; i < b->start; i++)
561
13.3k
        ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
562
33.5k
    b->sl_begin = ptr;
563
1.28M
    for (; i < b->start + b->len; i++)
564
1.25M
        ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
565
33.5k
    b->sl_end = ptr;
566
46.4k
    for (; i < b->height; i++)
567
12.9k
        ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
568
33.5k
    b->enc_size = ptr - b->enc;
569
33.5k
    return b->enc_size;
570
33.5k
}
571
572
static int encode_block(FlashSV2Context *s, Palette * palette, Block * b,
573
                        Block *prev, const uint8_t *src, int stride,
574
                        int dist, int keyframe)
575
33.5k
{
576
33.5k
    unsigned buf_size = b->width * b->height * 6;
577
33.5k
    uint8_t *buf = s->blockbuffer;
578
33.5k
    int res;
579
580
33.5k
    if (b->flags & COLORSPACE_15_7) {
581
33.5k
        encode_15_7(palette, b, src, stride, dist);
582
33.5k
    } else {
583
0
        encode_bgr(b, src, stride);
584
0
    }
585
586
33.5k
    if (b->len > 0) {
587
33.4k
        b->data_size = buf_size;
588
33.4k
        res = encode_zlib(b, b->data, &b->data_size, &s->zstream.zstream);
589
33.4k
        if (res)
590
22
            return res;
591
592
33.4k
        if (!keyframe) {
593
11.7k
            res = encode_zlibprime(b, prev, buf, &buf_size, &s->zstream.zstream);
594
11.7k
            if (res)
595
0
                return res;
596
597
11.7k
            if (buf_size < b->data_size) {
598
11.1k
                b->data_size = buf_size;
599
11.1k
                memcpy(b->data, buf, buf_size);
600
11.1k
                b->flags |= ZLIB_PRIME_COMPRESS_PREVIOUS;
601
11.1k
            }
602
11.7k
        }
603
33.4k
    } else {
604
137
        b->data_size = 0;
605
137
    }
606
33.5k
    return 0;
607
33.5k
}
608
609
static int compare_sl(FlashSV2Context * s, Block * b, const uint8_t * src,
610
                      uint8_t * frame, uint8_t * key, int y, int keyframe)
611
1.29M
{
612
1.29M
    if (memcmp(src, frame, b->width * 3) != 0) {
613
282k
        b->dirty = 1;
614
282k
        memcpy(frame, src, b->width * 3);
615
#ifndef FLASHSV2_DUMB
616
        s->diff_lines++;
617
#endif
618
282k
    }
619
1.29M
    if (memcmp(src, key, b->width * 3) != 0) {
620
307k
        if (b->len == 0)
621
19.8k
            b->start = y;
622
307k
        b->len = y + 1 - b->start;
623
307k
    }
624
1.29M
    return 0;
625
1.29M
}
626
627
static int mark_all_blocks(FlashSV2Context * s, const uint8_t * src, int stride,
628
                           int keyframe)
629
13.1k
{
630
13.1k
    int sl, rsl, col, pos, possl;
631
13.1k
    Block *b;
632
502k
    for (sl = s->image_height - 1; sl >= 0; sl--) {
633
1.78M
        for (col = 0; col < s->cols; col++) {
634
1.29M
            rsl = s->image_height - sl - 1;
635
1.29M
            b = s->frame_blocks + col + rsl / s->block_height * s->cols;
636
1.29M
            possl = stride * sl + col * s->block_width * 3;
637
1.29M
            pos = s->image_width * rsl * 3 + col * s->block_width * 3;
638
1.29M
            compare_sl(s, b, src + possl, s->current_frame + pos,
639
1.29M
                       s->key_frame + pos, rsl % s->block_height, keyframe);
640
1.29M
        }
641
489k
    }
642
#ifndef FLASHSV2_DUMB
643
    s->tot_lines += s->image_height * s->cols;
644
#endif
645
13.1k
    return 0;
646
13.1k
}
647
648
static int encode_all_blocks(FlashSV2Context * s, int keyframe)
649
13.1k
{
650
13.1k
    int row, col, res;
651
13.1k
    uint8_t *data;
652
13.1k
    Block *b, *prev;
653
29.0k
    for (row = 0; row < s->rows; row++) {
654
50.3k
        for (col = 0; col < s->cols; col++) {
655
34.4k
            b = s->frame_blocks + (row * s->cols + col);
656
34.4k
            prev = s->key_blocks + (row * s->cols + col);
657
34.4k
            b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
658
34.4k
            if (keyframe) {
659
21.6k
                b->start = 0;
660
21.6k
                b->len = b->height;
661
21.6k
            } else if (!b->dirty) {
662
875
                b->start = 0;
663
875
                b->len = 0;
664
875
                b->data_size = 0;
665
875
                continue;
666
11.9k
            } else if (b->start != 0 || b->len != b->height) {
667
2.90k
                b->flags |= HAS_DIFF_BLOCKS;
668
2.90k
            }
669
33.5k
            data = s->current_frame + s->image_width * 3 * s->block_height * row + s->block_width * col * 3;
670
33.5k
            res = encode_block(s, &s->palette, b, prev, data,
671
33.5k
                               s->image_width * 3, s->dist, keyframe);
672
#ifndef FLASHSV2_DUMB
673
            if (b->dirty)
674
                s->diff_blocks++;
675
            s->comp_size += b->data_size;
676
            s->uncomp_size += b->enc_size;
677
#endif
678
33.5k
            if (res)
679
22
                return res;
680
33.5k
        }
681
15.9k
    }
682
#ifndef FLASHSV2_DUMB
683
    s->raw_size += s->image_width * s->image_height * 3;
684
    s->tot_blocks += s->rows * s->cols;
685
#endif
686
13.1k
    return 0;
687
13.1k
}
688
689
static int write_all_blocks(FlashSV2Context * s, uint8_t * buf,
690
                            int buf_size)
691
13.1k
{
692
13.1k
    int row, col, buf_pos = 0, len;
693
13.1k
    Block *b;
694
28.9k
    for (row = 0; row < s->rows; row++) {
695
49.6k
        for (col = 0; col < s->cols; col++) {
696
33.7k
            b = s->frame_blocks + row * s->cols + col;
697
33.7k
            len = write_block(b, buf + buf_pos, buf_size - buf_pos);
698
33.7k
            b->start = b->len = b->dirty = 0;
699
33.7k
            if (len < 0)
700
0
                return len;
701
33.7k
            buf_pos += len;
702
33.7k
        }
703
15.8k
    }
704
13.1k
    return buf_pos;
705
13.1k
}
706
707
static int write_bitstream(FlashSV2Context * s, const uint8_t * src, int stride,
708
                           uint8_t * buf, int buf_size, int keyframe)
709
13.1k
{
710
13.1k
    int buf_pos, res;
711
712
13.1k
    res = mark_all_blocks(s, src, stride, keyframe);
713
13.1k
    if (res)
714
0
        return res;
715
13.1k
    res = encode_all_blocks(s, keyframe);
716
13.1k
    if (res)
717
22
        return res;
718
719
13.1k
    res = write_header(s, buf, buf_size);
720
13.1k
    if (res < 0) {
721
0
        return res;
722
13.1k
    } else {
723
13.1k
        buf_pos = res;
724
13.1k
    }
725
13.1k
    res = write_all_blocks(s, buf + buf_pos, buf_size - buf_pos);
726
13.1k
    if (res < 0)
727
0
        return res;
728
13.1k
    buf_pos += res;
729
#ifndef FLASHSV2_DUMB
730
    s->total_bits += ((double) buf_pos) * 8.0;
731
#endif
732
733
13.1k
    return buf_pos;
734
13.1k
}
735
736
static void recommend_keyframe(FlashSV2Context * s, int *keyframe)
737
6.62k
{
738
#ifndef FLASHSV2_DUMB
739
    double block_ratio, line_ratio, enc_ratio, comp_ratio, data_ratio;
740
    if (s->avctx->gop_size > 0) {
741
        block_ratio = s->diff_blocks / s->tot_blocks;
742
        line_ratio = s->diff_lines / s->tot_lines;
743
        enc_ratio = s->uncomp_size / s->raw_size;
744
        comp_ratio = s->comp_size / s->uncomp_size;
745
        data_ratio = s->comp_size / s->raw_size;
746
747
        if ((block_ratio >= 0.5 && line_ratio / block_ratio <= 0.5) || line_ratio >= 0.95) {
748
            *keyframe = 1;
749
            return;
750
        }
751
    }
752
#else
753
6.62k
    return;
754
6.62k
#endif
755
6.62k
}
756
757
#ifndef FLASHSV2_DUMB
758
static const double block_size_fraction = 1.0 / 300;
759
static const double use15_7_threshold = 8192;
760
static const double color15_7_factor = 100;
761
#endif
762
static int optimum_block_width(FlashSV2Context * s)
763
1.96k
{
764
#ifndef FLASHSV2_DUMB
765
    double save = (1-pow(s->diff_lines/s->diff_blocks/s->block_height, 0.5)) * s->comp_size/s->tot_blocks;
766
    double width = block_size_fraction * sqrt(0.5 * save * s->rows * s->cols) * s->image_width;
767
    int pwidth = ((int) width);
768
    return FFCLIP(pwidth & ~15, 256, 16);
769
#else
770
1.96k
    return 64;
771
1.96k
#endif
772
1.96k
}
773
774
static int optimum_block_height(FlashSV2Context * s)
775
1.96k
{
776
#ifndef FLASHSV2_DUMB
777
    double save = (1-pow(s->diff_lines/s->diff_blocks/s->block_height, 0.5)) * s->comp_size/s->tot_blocks;
778
    double height = block_size_fraction * sqrt(0.5 * save * s->rows * s->cols) * s->image_height;
779
    int pheight = ((int) height);
780
    return FFCLIP(pheight & ~15, 256, 16);
781
#else
782
1.96k
    return 64;
783
1.96k
#endif
784
1.96k
}
785
786
static int optimum_use15_7(FlashSV2Context * s)
787
1.96k
{
788
#ifndef FLASHSV2_DUMB
789
    double ideal = ((double)(s->avctx->bit_rate * s->avctx->time_base.den)) /
790
        ((double) s->avctx->time_base.num) * s->avctx->frame_num;
791
    if (ideal + use15_7_threshold < s->total_bits) {
792
        return 1;
793
    } else {
794
        return 0;
795
    }
796
#else
797
1.96k
    return s->avctx->global_quality == 0;
798
1.96k
#endif
799
1.96k
}
800
801
static int optimum_dist(FlashSV2Context * s)
802
13.1k
{
803
#ifndef FLASHSV2_DUMB
804
    double ideal =
805
        s->avctx->bit_rate * s->avctx->time_base.den;
806
    int dist = pow((s->total_bits / ideal) * color15_7_factor, 3);
807
    av_log(s->avctx, AV_LOG_DEBUG, "dist: %d\n", dist);
808
    return dist;
809
#else
810
13.1k
    return 15;
811
13.1k
#endif
812
13.1k
}
813
814
815
static int reconfigure_at_keyframe(FlashSV2Context * s, const uint8_t * image,
816
                                   int stride)
817
1.96k
{
818
1.96k
    int update_palette = 0;
819
1.96k
    int res;
820
1.96k
    int block_width  = optimum_block_width (s);
821
1.96k
    int block_height = optimum_block_height(s);
822
823
1.96k
    if (block_width != s->block_width || block_height != s->block_height) {
824
0
        res = update_block_dimensions(s, block_width, block_height);
825
0
        if (res < 0)
826
0
            return res;
827
0
    }
828
829
1.96k
    s->use15_7 = optimum_use15_7(s);
830
1.96k
    if (s->use15_7) {
831
1.96k
        if ((s->use_custom_palette && s->palette_type != 1) || update_palette) {
832
0
            res = generate_optimum_palette(&s->palette, image, s->image_width, s->image_height, stride);
833
0
            if (res)
834
0
                return res;
835
0
            s->palette_type = 1;
836
0
            av_log(s->avctx, AV_LOG_DEBUG, "Generated optimum palette\n");
837
1.96k
        } else if (!s->use_custom_palette && s->palette_type != 0) {
838
1.05k
            res = generate_default_palette(&s->palette);
839
1.05k
            if (res)
840
0
                return res;
841
1.05k
            s->palette_type = 0;
842
1.05k
            av_log(s->avctx, AV_LOG_DEBUG, "Generated default palette\n");
843
1.05k
        }
844
1.96k
    }
845
846
847
1.96k
    reset_stats(s);
848
849
1.96k
    return 0;
850
1.96k
}
851
852
static int flashsv2_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
853
                                 const AVFrame *p, int *got_packet)
854
13.1k
{
855
13.1k
    FlashSV2Context *const s = avctx->priv_data;
856
13.1k
    int res;
857
13.1k
    int keyframe = 0;
858
859
13.1k
    if ((res = ff_alloc_packet(avctx, pkt, s->frame_size + FF_INPUT_BUFFER_MIN_SIZE)) < 0)
860
0
        return res;
861
862
    /* First frame needs to be a keyframe */
863
13.1k
    if (avctx->frame_num == 0)
864
1.05k
        keyframe = 1;
865
866
    /* Check the placement of keyframes */
867
13.1k
    if (avctx->gop_size > 0) {
868
11.3k
        if (avctx->frame_num >= s->last_key_frame + avctx->gop_size)
869
906
            keyframe = 1;
870
11.3k
    }
871
872
13.1k
    if (!keyframe
873
11.1k
        && avctx->frame_num > s->last_key_frame + avctx->keyint_min) {
874
6.62k
        recommend_keyframe(s, &keyframe);
875
6.62k
        if (keyframe)
876
0
            av_log(avctx, AV_LOG_DEBUG, "Recommending key frame at frame %"PRId64"\n", avctx->frame_num);
877
6.62k
    }
878
879
13.1k
    if (keyframe) {
880
1.96k
        res = reconfigure_at_keyframe(s, p->data[0], p->linesize[0]);
881
1.96k
        if (res)
882
0
            return res;
883
1.96k
    }
884
885
13.1k
    if (s->use15_7)
886
13.1k
        s->dist = optimum_dist(s);
887
888
13.1k
    res = write_bitstream(s, p->data[0], p->linesize[0], pkt->data, pkt->size, keyframe);
889
890
13.1k
    if (keyframe) {
891
1.96k
        new_key_frame(s);
892
1.96k
        s->last_key_frame = avctx->frame_num;
893
1.96k
        pkt->flags |= AV_PKT_FLAG_KEY;
894
1.96k
        av_log(avctx, AV_LOG_DEBUG, "Inserting key frame at frame %"PRId64"\n", avctx->frame_num);
895
1.96k
    }
896
897
13.1k
    pkt->size = res;
898
13.1k
    *got_packet = 1;
899
900
13.1k
    return 0;
901
13.1k
}
902
903
static av_cold int flashsv2_encode_end(AVCodecContext * avctx)
904
1.08k
{
905
1.08k
    FlashSV2Context *s = avctx->priv_data;
906
907
1.08k
    cleanup(s);
908
909
1.08k
    return 0;
910
1.08k
}
911
912
const FFCodec ff_flashsv2_encoder = {
913
    .p.name         = "flashsv2",
914
    CODEC_LONG_NAME("Flash Screen Video Version 2"),
915
    .p.type         = AVMEDIA_TYPE_VIDEO,
916
    .p.id           = AV_CODEC_ID_FLASHSV2,
917
    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
918
    .priv_data_size = sizeof(FlashSV2Context),
919
    .init           = flashsv2_encode_init,
920
    FF_CODEC_ENCODE_CB(flashsv2_encode_frame),
921
    .close          = flashsv2_encode_end,
922
    CODEC_PIXFMTS(AV_PIX_FMT_BGR24),
923
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
924
};