2 * Flash Screen Video Version 2 encoder
3 * Copyright (C) 2009 Joshua Warner
5 * This file is part of FFmpeg.
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.
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.
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
24 * Flash Screen Video Version 2 encoder
25 * @author Joshua Warner
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.
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.
49 #include "libavutil/imgutils.h"
52 #include "bytestream.h"
54 #define HAS_IFRAME_IMAGE 0x02
55 #define HAS_PALLET_INFO 0x01
57 #define COLORSPACE_BGR 0x00
58 #define COLORSPACE_15_7 0x10
59 #define HAS_DIFF_BLOCKS 0x04
60 #define ZLIB_PRIME_COMPRESS_CURRENT 0x02
61 #define ZLIB_PRIME_COMPRESS_PREVIOUS 0x01
63 // Disables experimental "smart" parameter-choosing code, as well as the statistics that it depends on.
64 // At the moment, the "smart" code is a great example of how the parameters *shouldn't* be chosen.
67 typedef struct Block {
69 uint8_t *sl_begin, *sl_end;
72 unsigned long data_size;
76 uint8_t col, row, width, height;
80 typedef struct Palette {
82 uint8_t index[1 << 15];
85 typedef struct FlashSV2Context {
86 AVCodecContext *avctx;
87 uint8_t *current_frame;
99 int use15_7, dist, comp;
105 int image_width, image_height;
106 int block_width, block_height;
108 uint8_t use_custom_palette;
109 uint8_t palette_type; ///< 0=>default, 1=>custom - changed when palette regenerated.
111 #ifndef FLASHSV2_DUMB
112 double tot_blocks; ///< blocks encoded since last keyframe
113 double diff_blocks; ///< blocks that were different since last keyframe
114 double tot_lines; ///< total scanlines in image since last keyframe
115 double diff_lines; ///< scanlines that were different since last keyframe
116 double raw_size; ///< size of raw frames since last keyframe
117 double comp_size; ///< size of compressed data since last keyframe
118 double uncomp_size; ///< size of uncompressed data since last keyframe
120 double total_bits; ///< total bits written to stream so far
124 static av_cold void cleanup(FlashSV2Context * s)
126 av_freep(&s->encbuffer);
127 av_freep(&s->keybuffer);
128 av_freep(&s->databuffer);
129 av_freep(&s->current_frame);
130 av_freep(&s->key_frame);
132 av_freep(&s->frame_blocks);
133 av_freep(&s->key_blocks);
136 static void init_blocks(FlashSV2Context * s, Block * blocks,
137 uint8_t * encbuf, uint8_t * databuf)
141 for (col = 0; col < s->cols; col++) {
142 for (row = 0; row < s->rows; row++) {
143 b = blocks + (col + row * s->cols);
144 b->width = (col < s->cols - 1) ?
146 s->image_width - col * s->block_width;
148 b->height = (row < s->rows - 1) ?
150 s->image_height - row * s->block_height;
156 encbuf += b->width * b->height * 3;
157 databuf += !databuf ? 0 : b->width * b->height * 6;
162 static void reset_stats(FlashSV2Context * s)
164 #ifndef FLASHSV2_DUMB
165 s->diff_blocks = 0.1;
169 s->raw_size = s->comp_size = s->uncomp_size = 10;
173 static av_cold int flashsv2_encode_init(AVCodecContext * avctx)
175 FlashSV2Context *s = avctx->priv_data;
179 s->comp = avctx->compression_level;
182 if (s->comp < 0 || s->comp > 9) {
183 av_log(avctx, AV_LOG_ERROR,
184 "Compression level should be 0-9, not %d\n", s->comp);
189 if ((avctx->width > 4095) || (avctx->height > 4095)) {
190 av_log(avctx, AV_LOG_ERROR,
191 "Input dimensions too large, input must be max 4096x4096 !\n");
195 if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0)
199 s->last_key_frame = 0;
201 s->image_width = avctx->width;
202 s->image_height = avctx->height;
204 s->block_width = (s->image_width / 12) & ~15;
205 s->block_height = (s->image_height / 12) & ~15;
207 s->rows = (s->image_height + s->block_height - 1) / s->block_height;
208 s->cols = (s->image_width + s->block_width - 1) / s->block_width;
210 s->frame_size = s->image_width * s->image_height * 3;
211 s->blocks_size = s->rows * s->cols * sizeof(Block);
213 s->encbuffer = av_mallocz(s->frame_size);
214 s->keybuffer = av_mallocz(s->frame_size);
215 s->databuffer = av_mallocz(s->frame_size * 6);
216 s->current_frame = av_mallocz(s->frame_size);
217 s->key_frame = av_mallocz(s->frame_size);
218 s->frame_blocks = av_mallocz(s->blocks_size);
219 s->key_blocks = av_mallocz(s->blocks_size);
221 init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
222 init_blocks(s, s->key_blocks, s->keybuffer, 0);
224 #ifndef FLASHSV2_DUMB
228 s->use_custom_palette = 0;
229 s->palette_type = -1; // so that the palette will be generated in reconfigure_at_keyframe
231 if (!s->encbuffer || !s->keybuffer || !s->databuffer
232 || !s->current_frame || !s->key_frame || !s->key_blocks
233 || !s->frame_blocks) {
234 av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
242 static int new_key_frame(FlashSV2Context * s)
245 memcpy(s->key_blocks, s->frame_blocks, s->blocks_size);
246 memcpy(s->key_frame, s->current_frame, s->frame_size);
248 for (i = 0; i < s->rows * s->cols; i++) {
249 s->key_blocks[i].enc += (s->keybuffer - s->encbuffer);
250 s->key_blocks[i].sl_begin = 0;
251 s->key_blocks[i].sl_end = 0;
252 s->key_blocks[i].data = 0;
254 FFSWAP(uint8_t * , s->keybuffer, s->encbuffer);
259 static int write_palette(FlashSV2Context * s, uint8_t * buf, int buf_size)
261 //this isn't implemented yet! Default palette only!
265 static int write_header(FlashSV2Context * s, uint8_t * buf, int buf_size)
273 init_put_bits(&pb, buf, buf_size * 8);
275 put_bits(&pb, 4, (s->block_width >> 4) - 1);
276 put_bits(&pb, 12, s->image_width);
277 put_bits(&pb, 4, (s->block_height >> 4) - 1);
278 put_bits(&pb, 12, s->image_height);
283 buf[buf_pos++] = s->flags;
285 if (s->flags & HAS_PALLET_INFO) {
286 len = write_palette(s, buf + buf_pos, buf_size - buf_pos);
295 static int write_block(Block * b, uint8_t * buf, int buf_size)
298 unsigned block_size = b->data_size;
300 if (b->flags & HAS_DIFF_BLOCKS)
302 if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT)
306 if (buf_size < block_size + 2)
309 buf[buf_pos++] = block_size >> 8;
310 buf[buf_pos++] = block_size;
315 buf[buf_pos++] = b->flags;
317 if (b->flags & HAS_DIFF_BLOCKS) {
318 buf[buf_pos++] = (b->start);
319 buf[buf_pos++] = (b->len);
322 if (b->flags & ZLIB_PRIME_COMPRESS_CURRENT) {
323 //This feature of the format is poorly understood, and as of now, unused.
324 buf[buf_pos++] = (b->col);
325 buf[buf_pos++] = (b->row);
328 memcpy(buf + buf_pos, b->data, b->data_size);
330 buf_pos += b->data_size;
335 static int encode_zlib(Block * b, uint8_t * buf, unsigned long *buf_size, int comp)
337 int res = compress2(buf, buf_size, b->sl_begin, b->sl_end - b->sl_begin, comp);
338 return res == Z_OK ? 0 : -1;
341 static int encode_zlibprime(Block * b, Block * prime, uint8_t * buf,
342 int *buf_size, int comp)
349 res = deflateInit(&s, comp);
353 s.next_in = prime->enc;
354 s.avail_in = prime->enc_size;
355 while (s.avail_in > 0) {
357 s.avail_out = *buf_size;
358 res = deflate(&s, Z_SYNC_FLUSH);
363 s.next_in = b->sl_begin;
364 s.avail_in = b->sl_end - b->sl_begin;
366 s.avail_out = *buf_size;
367 res = deflate(&s, Z_FINISH);
369 *buf_size -= s.avail_out;
370 if (res != Z_STREAM_END)
375 static int encode_bgr(Block * b, const uint8_t * src, int stride)
378 uint8_t *ptr = b->enc;
379 for (i = 0; i < b->start; i++)
380 memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
381 b->sl_begin = ptr + i * b->width * 3;
382 for (; i < b->start + b->len; i++)
383 memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
384 b->sl_end = ptr + i * b->width * 3;
385 for (; i < b->height; i++)
386 memcpy(ptr + i * b->width * 3, src + i * stride, b->width * 3);
387 b->enc_size = ptr + i * b->width * 3 - b->enc;
391 static inline unsigned pixel_color15(const uint8_t * src)
393 return (src[0] >> 3) | ((src[1] & 0xf8) << 2) | ((src[2] & 0xf8) << 7);
396 static inline unsigned int chroma_diff(unsigned int c1, unsigned int c2)
398 unsigned int t1 = (c1 & 0x000000ff) + ((c1 & 0x0000ff00) >> 8) + ((c1 & 0x00ff0000) >> 16);
399 unsigned int t2 = (c2 & 0x000000ff) + ((c2 & 0x0000ff00) >> 8) + ((c2 & 0x00ff0000) >> 16);
401 return abs(t1 - t2) + abs((c1 & 0x000000ff) - (c2 & 0x000000ff)) +
402 abs(((c1 & 0x0000ff00) >> 8) - ((c2 & 0x0000ff00) >> 8)) +
403 abs(((c1 & 0x00ff0000) >> 16) - ((c2 & 0x00ff0000) >> 16));
406 static inline int pixel_color7_fast(Palette * palette, unsigned c15)
408 return palette->index[c15];
411 static int pixel_color7_slow(Palette * palette, unsigned color)
413 int i, min = 0x7fffffff;
415 for (i = 0; i < 128; i++) {
416 int c1 = palette->colors[i];
417 int diff = chroma_diff(c1, color);
426 static inline unsigned pixel_bgr(const uint8_t * src)
428 return (src[0]) | (src[1] << 8) | (src[2] << 16);
431 static int write_pixel_15_7(Palette * palette, uint8_t * dest, const uint8_t * src,
434 unsigned c15 = pixel_color15(src);
435 unsigned color = pixel_bgr(src);
436 int d15 = chroma_diff(color, color & 0x00f8f8f8);
437 int c7 = pixel_color7_fast(palette, c15);
438 int d7 = chroma_diff(color, palette->colors[c7]);
439 if (dist + d15 >= d7) {
443 dest[0] = 0x80 | (c15 >> 8);
444 dest[1] = c15 & 0xff;
449 static int update_palette_index(Palette * palette)
452 unsigned int bgr, c15, index;
453 for (r = 4; r < 256; r += 8) {
454 for (g = 4; g < 256; g += 8) {
455 for (b = 4; b < 256; b += 8) {
456 bgr = b | (g << 8) | (r << 16);
457 c15 = (b >> 3) | ((g & 0xf8) << 2) | ((r & 0xf8) << 7);
458 index = pixel_color7_slow(palette, bgr);
460 palette->index[c15] = index;
467 static const unsigned int default_screen_video_v2_palette[128] = {
468 0x00000000, 0x00333333, 0x00666666, 0x00999999, 0x00CCCCCC, 0x00FFFFFF,
469 0x00330000, 0x00660000, 0x00990000, 0x00CC0000, 0x00FF0000, 0x00003300,
470 0x00006600, 0x00009900, 0x0000CC00, 0x0000FF00, 0x00000033, 0x00000066,
471 0x00000099, 0x000000CC, 0x000000FF, 0x00333300, 0x00666600, 0x00999900,
472 0x00CCCC00, 0x00FFFF00, 0x00003333, 0x00006666, 0x00009999, 0x0000CCCC,
473 0x0000FFFF, 0x00330033, 0x00660066, 0x00990099, 0x00CC00CC, 0x00FF00FF,
474 0x00FFFF33, 0x00FFFF66, 0x00FFFF99, 0x00FFFFCC, 0x00FF33FF, 0x00FF66FF,
475 0x00FF99FF, 0x00FFCCFF, 0x0033FFFF, 0x0066FFFF, 0x0099FFFF, 0x00CCFFFF,
476 0x00CCCC33, 0x00CCCC66, 0x00CCCC99, 0x00CCCCFF, 0x00CC33CC, 0x00CC66CC,
477 0x00CC99CC, 0x00CCFFCC, 0x0033CCCC, 0x0066CCCC, 0x0099CCCC, 0x00FFCCCC,
478 0x00999933, 0x00999966, 0x009999CC, 0x009999FF, 0x00993399, 0x00996699,
479 0x0099CC99, 0x0099FF99, 0x00339999, 0x00669999, 0x00CC9999, 0x00FF9999,
480 0x00666633, 0x00666699, 0x006666CC, 0x006666FF, 0x00663366, 0x00669966,
481 0x0066CC66, 0x0066FF66, 0x00336666, 0x00996666, 0x00CC6666, 0x00FF6666,
482 0x00333366, 0x00333399, 0x003333CC, 0x003333FF, 0x00336633, 0x00339933,
483 0x0033CC33, 0x0033FF33, 0x00663333, 0x00993333, 0x00CC3333, 0x00FF3333,
484 0x00003366, 0x00336600, 0x00660033, 0x00006633, 0x00330066, 0x00663300,
485 0x00336699, 0x00669933, 0x00993366, 0x00339966, 0x00663399, 0x00996633,
486 0x006699CC, 0x0099CC66, 0x00CC6699, 0x0066CC99, 0x009966CC, 0x00CC9966,
487 0x0099CCFF, 0x00CCFF99, 0x00FF99CC, 0x0099FFCC, 0x00CC99FF, 0x00FFCC99,
488 0x00111111, 0x00222222, 0x00444444, 0x00555555, 0x00AAAAAA, 0x00BBBBBB,
489 0x00DDDDDD, 0x00EEEEEE
492 static int generate_default_palette(Palette * palette)
494 memcpy(palette->colors, default_screen_video_v2_palette,
495 sizeof(default_screen_video_v2_palette));
497 return update_palette_index(palette);
500 static int generate_optimum_palette(Palette * palette, const uint8_t * image,
501 int width, int height, int stride)
503 //this isn't implemented yet! Default palette only!
507 static inline int encode_15_7_sl(Palette * palette, uint8_t * dest,
508 const uint8_t * src, int width, int dist)
511 for (x = 0; x < width; x++) {
512 len += write_pixel_15_7(palette, dest + len, src + 3 * x, dist);
517 static int encode_15_7(Palette * palette, Block * b, const uint8_t * src,
518 int stride, int dist)
521 uint8_t *ptr = b->enc;
522 for (i = 0; i < b->start; i++)
523 ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
525 for (; i < b->start + b->len; i++)
526 ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
528 for (; i < b->height; i++)
529 ptr += encode_15_7_sl(palette, ptr, src + i * stride, b->width, dist);
530 b->enc_size = ptr - b->enc;
534 static int encode_block(Palette * palette, Block * b, Block * prev,
535 const uint8_t * src, int stride, int comp, int dist,
538 unsigned buf_size = b->width * b->height * 6;
539 uint8_t buf[buf_size];
541 if (b->flags & COLORSPACE_15_7) {
542 encode_15_7(palette, b, src, stride, dist);
544 encode_bgr(b, src, stride);
548 b->data_size = buf_size;
549 res = encode_zlib(b, b->data, &b->data_size, comp);
554 res = encode_zlibprime(b, prev, buf, &buf_size, comp);
558 if (buf_size < b->data_size) {
559 b->data_size = buf_size;
560 memcpy(b->data, buf, buf_size);
561 b->flags |= ZLIB_PRIME_COMPRESS_PREVIOUS;
570 static int compare_sl(FlashSV2Context * s, Block * b, const uint8_t * src,
571 uint8_t * frame, uint8_t * key, int y, int keyframe)
573 if (memcmp(src, frame, b->width * 3) != 0) {
575 memcpy(frame, src, b->width * 3);
576 #ifndef FLASHSV2_DUMB
580 if (memcmp(src, key, b->width * 3) != 0) {
583 b->len = y + 1 - b->start;
588 static int mark_all_blocks(FlashSV2Context * s, const uint8_t * src, int stride,
591 int sl, rsl, col, pos, possl;
593 for (sl = s->image_height - 1; sl >= 0; sl--) {
594 for (col = 0; col < s->cols; col++) {
595 rsl = s->image_height - sl - 1;
596 b = s->frame_blocks + col + rsl / s->block_height * s->cols;
597 possl = stride * sl + col * s->block_width * 3;
598 pos = s->image_width * rsl * 3 + col * s->block_width * 3;
599 compare_sl(s, b, src + possl, s->current_frame + pos,
600 s->key_frame + pos, rsl % s->block_height, keyframe);
603 #ifndef FLASHSV2_DUMB
604 s->tot_lines += s->image_height * s->cols;
609 static int encode_all_blocks(FlashSV2Context * s, int keyframe)
614 for (row = 0; row < s->rows; row++) {
615 for (col = 0; col < s->cols; col++) {
616 b = s->frame_blocks + (row * s->cols + col);
617 prev = s->key_blocks + (row * s->cols + col);
621 b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
622 } else if (!b->dirty) {
626 b->flags = s->use15_7 ? COLORSPACE_15_7 : 0;
629 b->flags = s->use15_7 ? COLORSPACE_15_7 | HAS_DIFF_BLOCKS : HAS_DIFF_BLOCKS;
631 data = s->current_frame + s->image_width * 3 * s->block_height * row + s->block_width * col * 3;
632 res = encode_block(&s->palette, b, prev, data, s->image_width * 3, s->comp, s->dist, keyframe);
633 #ifndef FLASHSV2_DUMB
636 s->comp_size += b->data_size;
637 s->uncomp_size += b->enc_size;
643 #ifndef FLASHSV2_DUMB
644 s->raw_size += s->image_width * s->image_height * 3;
645 s->tot_blocks += s->rows * s->cols;
650 static int write_all_blocks(FlashSV2Context * s, uint8_t * buf,
653 int row, col, buf_pos = 0, len;
655 for (row = 0; row < s->rows; row++) {
656 for (col = 0; col < s->cols; col++) {
657 b = s->frame_blocks + row * s->cols + col;
658 len = write_block(b, buf + buf_pos, buf_size - buf_pos);
659 b->start = b->len = b->dirty = 0;
668 static int write_bitstream(FlashSV2Context * s, const uint8_t * src, int stride,
669 uint8_t * buf, int buf_size, int keyframe)
673 res = mark_all_blocks(s, src, stride, keyframe);
676 res = encode_all_blocks(s, keyframe);
680 res = write_header(s, buf, buf_size);
686 res = write_all_blocks(s, buf + buf_pos, buf_size - buf_pos);
690 #ifndef FLASHSV2_DUMB
691 s->total_bits += ((double) buf_pos) * 8.0;
697 static void recommend_keyframe(FlashSV2Context * s, int *keyframe)
699 #ifndef FLASHSV2_DUMB
700 double block_ratio, line_ratio, enc_ratio, comp_ratio, data_ratio;
701 if (s->avctx->gop_size > 0) {
702 block_ratio = s->diff_blocks / s->tot_blocks;
703 line_ratio = s->diff_lines / s->tot_lines;
704 enc_ratio = s->uncomp_size / s->raw_size;
705 comp_ratio = s->comp_size / s->uncomp_size;
706 data_ratio = s->comp_size / s->raw_size;
708 if ((block_ratio >= 0.5 && line_ratio / block_ratio <= 0.5) || line_ratio >= 0.95) {
718 static const double block_size_fraction = 1.0 / 300;
719 static int optimum_block_width(FlashSV2Context * s)
721 #ifndef FLASHSV2_DUMB
722 double save = (1-pow(s->diff_lines/s->diff_blocks/s->block_height, 0.5)) * s->comp_size/s->tot_blocks;
723 double width = block_size_fraction * sqrt(0.5 * save * s->rows * s->cols) * s->image_width;
724 int pwidth = ((int) width);
725 return FFCLIP(pwidth & ~15, 256, 16);
731 static int optimum_block_height(FlashSV2Context * s)
733 #ifndef FLASHSV2_DUMB
734 double save = (1-pow(s->diff_lines/s->diff_blocks/s->block_height, 0.5)) * s->comp_size/s->tot_blocks;
735 double height = block_size_fraction * sqrt(0.5 * save * s->rows * s->cols) * s->image_height;
736 int pheight = ((int) height);
737 return FFCLIP(pheight & ~15, 256, 16);
743 static const double use15_7_threshold = 8192;
745 static int optimum_use15_7(FlashSV2Context * s)
747 #ifndef FLASHSV2_DUMB
748 double ideal = ((double)(s->avctx->bit_rate * s->avctx->time_base.den * s->avctx->ticks_per_frame)) /
749 ((double) s->avctx->time_base.num) * s->avctx->frame_number;
750 if (ideal + use15_7_threshold < s->total_bits) {
756 return s->avctx->global_quality == 0;
760 static const double color15_7_factor = 100;
762 static int optimum_dist(FlashSV2Context * s)
764 #ifndef FLASHSV2_DUMB
766 s->avctx->bit_rate * s->avctx->time_base.den *
767 s->avctx->ticks_per_frame;
768 int dist = pow((s->total_bits / ideal) * color15_7_factor, 3);
769 av_log(s->avctx, AV_LOG_DEBUG, "dist: %d\n", dist);
777 static int reconfigure_at_keyframe(FlashSV2Context * s, const uint8_t * image,
780 int update_palette = 0;
782 s->block_width = optimum_block_width(s);
783 s->block_height = optimum_block_height(s);
785 s->rows = (s->image_height + s->block_height - 1) / s->block_height;
786 s->cols = (s->image_width + s->block_width - 1) / s->block_width;
788 if (s->rows * s->cols != s->blocks_size / sizeof(Block)) {
789 if (s->rows * s->cols > s->blocks_size / sizeof(Block)) {
790 s->frame_blocks = av_realloc(s->frame_blocks, s->rows * s->cols * sizeof(Block));
791 s->key_blocks = av_realloc(s->key_blocks, s->cols * s->rows * sizeof(Block));
792 if (!s->frame_blocks || !s->key_blocks) {
793 av_log(s->avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
796 s->blocks_size = s->rows * s->cols * sizeof(Block);
798 init_blocks(s, s->frame_blocks, s->encbuffer, s->databuffer);
799 init_blocks(s, s->key_blocks, s->keybuffer, 0);
803 s->use15_7 = optimum_use15_7(s);
805 if ((s->use_custom_palette && s->palette_type != 1) || update_palette) {
806 res = generate_optimum_palette(&s->palette, image, s->image_width, s->image_height, stride);
810 av_log(s->avctx, AV_LOG_DEBUG, "Generated optimum palette\n");
811 } else if (!s->use_custom_palette && s->palette_type != 0) {
812 res = generate_default_palette(&s->palette);
816 av_log(s->avctx, AV_LOG_DEBUG, "Generated default palette\n");
826 static int flashsv2_encode_frame(AVCodecContext * avctx, uint8_t * buf,
827 int buf_size, void *data)
829 FlashSV2Context *const s = avctx->priv_data;
830 AVFrame *pict = data;
831 AVFrame *const p = &s->frame;
837 /* First frame needs to be a keyframe */
838 if (avctx->frame_number == 0)
841 /* Check the placement of keyframes */
842 if (avctx->gop_size > 0) {
843 if (avctx->frame_number >= s->last_key_frame + avctx->gop_size)
847 if (buf_size < s->frame_size) {
848 //Conservative upper bound check for compressed data
849 av_log(avctx, AV_LOG_ERROR, "buf_size %d < %d\n", buf_size, s->frame_size);
854 && avctx->frame_number > s->last_key_frame + avctx->keyint_min) {
855 recommend_keyframe(s, &keyframe);
857 av_log(avctx, AV_LOG_DEBUG, "Recommending key frame at frame %d\n", avctx->frame_number);
861 res = reconfigure_at_keyframe(s, p->data[0], p->linesize[0]);
867 s->dist = optimum_dist(s);
869 res = write_bitstream(s, p->data[0], p->linesize[0], buf, buf_size, keyframe);
873 p->pict_type = FF_I_TYPE;
875 s->last_key_frame = avctx->frame_number;
876 av_log(avctx, AV_LOG_DEBUG, "Inserting key frame at frame %d\n", avctx->frame_number);
878 p->pict_type = FF_P_TYPE;
882 avctx->coded_frame = p;
887 static av_cold int flashsv2_encode_end(AVCodecContext * avctx)
889 FlashSV2Context *s = avctx->priv_data;
896 AVCodec ff_flashsv2_encoder = {
900 sizeof(FlashSV2Context),
901 flashsv2_encode_init,
902 flashsv2_encode_frame,
904 .pix_fmts = (enum PixelFormat[]) {PIX_FMT_BGR24, PIX_FMT_NONE},
905 .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video Version 2"),
906 .capabilities = CODEC_CAP_EXPERIMENTAL,