FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/flashsv2enc.c
Date: 2021-09-23 20:34:37
Exec Total Coverage
Lines: 319 398 80.2%
Branches: 121 198 61.1%

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