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