1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Zip Motion Blocks Video (ZMBV) encoder 3cabdff1aSopenharmony_ci * Copyright (c) 2006 Konstantin Shishkov 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 * Zip Motion Blocks Video encoder 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include <stdio.h> 28cabdff1aSopenharmony_ci#include <stdlib.h> 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#include "libavutil/common.h" 31cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 32cabdff1aSopenharmony_ci#include "avcodec.h" 33cabdff1aSopenharmony_ci#include "codec_internal.h" 34cabdff1aSopenharmony_ci#include "encode.h" 35cabdff1aSopenharmony_ci#include "zlib_wrapper.h" 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci#include <zlib.h> 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci/* Frame header flags */ 40cabdff1aSopenharmony_ci#define ZMBV_KEYFRAME 1 41cabdff1aSopenharmony_ci#define ZMBV_DELTAPAL 2 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci/* Motion block width/height (maximum allowed value is 255) 44cabdff1aSopenharmony_ci * Note: histogram datatype in block_cmp() must be big enough to hold values 45cabdff1aSopenharmony_ci * up to (4 * ZMBV_BLOCK * ZMBV_BLOCK) 46cabdff1aSopenharmony_ci */ 47cabdff1aSopenharmony_ci#define ZMBV_BLOCK 16 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_ci/* Keyframe header format values */ 50cabdff1aSopenharmony_cienum ZmbvFormat { 51cabdff1aSopenharmony_ci ZMBV_FMT_NONE = 0, 52cabdff1aSopenharmony_ci ZMBV_FMT_1BPP = 1, 53cabdff1aSopenharmony_ci ZMBV_FMT_2BPP = 2, 54cabdff1aSopenharmony_ci ZMBV_FMT_4BPP = 3, 55cabdff1aSopenharmony_ci ZMBV_FMT_8BPP = 4, 56cabdff1aSopenharmony_ci ZMBV_FMT_15BPP = 5, 57cabdff1aSopenharmony_ci ZMBV_FMT_16BPP = 6, 58cabdff1aSopenharmony_ci ZMBV_FMT_24BPP = 7, 59cabdff1aSopenharmony_ci ZMBV_FMT_32BPP = 8 60cabdff1aSopenharmony_ci}; 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci/** 63cabdff1aSopenharmony_ci * Encoder context 64cabdff1aSopenharmony_ci */ 65cabdff1aSopenharmony_citypedef struct ZmbvEncContext { 66cabdff1aSopenharmony_ci AVCodecContext *avctx; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci int lrange, urange; 69cabdff1aSopenharmony_ci uint8_t *comp_buf, *work_buf; 70cabdff1aSopenharmony_ci uint8_t pal[768]; 71cabdff1aSopenharmony_ci uint32_t pal2[256]; //for quick comparisons 72cabdff1aSopenharmony_ci uint8_t *prev, *prev_buf; 73cabdff1aSopenharmony_ci int pstride; 74cabdff1aSopenharmony_ci int comp_size; 75cabdff1aSopenharmony_ci int keyint, curfrm; 76cabdff1aSopenharmony_ci int bypp; 77cabdff1aSopenharmony_ci enum ZmbvFormat fmt; 78cabdff1aSopenharmony_ci FFZStream zstream; 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_ci int score_tab[ZMBV_BLOCK * ZMBV_BLOCK * 4 + 1]; 81cabdff1aSopenharmony_ci} ZmbvEncContext; 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci/** Block comparing function 85cabdff1aSopenharmony_ci * XXX should be optimized and moved to DSPContext 86cabdff1aSopenharmony_ci */ 87cabdff1aSopenharmony_cistatic inline int block_cmp(ZmbvEncContext *c, uint8_t *src, int stride, 88cabdff1aSopenharmony_ci uint8_t *src2, int stride2, int bw, int bh, 89cabdff1aSopenharmony_ci int *xored) 90cabdff1aSopenharmony_ci{ 91cabdff1aSopenharmony_ci int sum = 0; 92cabdff1aSopenharmony_ci int i, j; 93cabdff1aSopenharmony_ci uint16_t histogram[256] = {0}; 94cabdff1aSopenharmony_ci int bw_bytes = bw * c->bypp; 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci /* Build frequency histogram of byte values for src[] ^ src2[] */ 97cabdff1aSopenharmony_ci for(j = 0; j < bh; j++){ 98cabdff1aSopenharmony_ci for(i = 0; i < bw_bytes; i++){ 99cabdff1aSopenharmony_ci int t = src[i] ^ src2[i]; 100cabdff1aSopenharmony_ci histogram[t]++; 101cabdff1aSopenharmony_ci } 102cabdff1aSopenharmony_ci src += stride; 103cabdff1aSopenharmony_ci src2 += stride2; 104cabdff1aSopenharmony_ci } 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci /* If not all the xored values were 0, then the blocks are different */ 107cabdff1aSopenharmony_ci *xored = (histogram[0] < bw_bytes * bh); 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci /* Exit early if blocks are equal */ 110cabdff1aSopenharmony_ci if (!*xored) return 0; 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci /* Sum the entropy of all values */ 113cabdff1aSopenharmony_ci for(i = 0; i < 256; i++) 114cabdff1aSopenharmony_ci sum += c->score_tab[histogram[i]]; 115cabdff1aSopenharmony_ci 116cabdff1aSopenharmony_ci return sum; 117cabdff1aSopenharmony_ci} 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_ci/** Motion estimation function 120cabdff1aSopenharmony_ci * TODO make better ME decisions 121cabdff1aSopenharmony_ci */ 122cabdff1aSopenharmony_cistatic int zmbv_me(ZmbvEncContext *c, uint8_t *src, int sstride, uint8_t *prev, 123cabdff1aSopenharmony_ci int pstride, int x, int y, int *mx, int *my, int *xored) 124cabdff1aSopenharmony_ci{ 125cabdff1aSopenharmony_ci int dx, dy, txored, tv, bv, bw, bh; 126cabdff1aSopenharmony_ci int mx0, my0; 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci mx0 = *mx; 129cabdff1aSopenharmony_ci my0 = *my; 130cabdff1aSopenharmony_ci bw = FFMIN(ZMBV_BLOCK, c->avctx->width - x); 131cabdff1aSopenharmony_ci bh = FFMIN(ZMBV_BLOCK, c->avctx->height - y); 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci /* Try (0,0) */ 134cabdff1aSopenharmony_ci bv = block_cmp(c, src, sstride, prev, pstride, bw, bh, xored); 135cabdff1aSopenharmony_ci *mx = *my = 0; 136cabdff1aSopenharmony_ci if(!bv) return 0; 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci /* Try previous block's MV (if not 0,0) */ 139cabdff1aSopenharmony_ci if (mx0 || my0){ 140cabdff1aSopenharmony_ci tv = block_cmp(c, src, sstride, prev + mx0 * c->bypp + my0 * pstride, pstride, bw, bh, &txored); 141cabdff1aSopenharmony_ci if(tv < bv){ 142cabdff1aSopenharmony_ci bv = tv; 143cabdff1aSopenharmony_ci *mx = mx0; 144cabdff1aSopenharmony_ci *my = my0; 145cabdff1aSopenharmony_ci *xored = txored; 146cabdff1aSopenharmony_ci if(!bv) return 0; 147cabdff1aSopenharmony_ci } 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci /* Try other MVs from top-to-bottom, left-to-right */ 151cabdff1aSopenharmony_ci for(dy = -c->lrange; dy <= c->urange; dy++){ 152cabdff1aSopenharmony_ci for(dx = -c->lrange; dx <= c->urange; dx++){ 153cabdff1aSopenharmony_ci if(!dx && !dy) continue; // we already tested this block 154cabdff1aSopenharmony_ci if(dx == mx0 && dy == my0) continue; // this one too 155cabdff1aSopenharmony_ci tv = block_cmp(c, src, sstride, prev + dx * c->bypp + dy * pstride, pstride, bw, bh, &txored); 156cabdff1aSopenharmony_ci if(tv < bv){ 157cabdff1aSopenharmony_ci bv = tv; 158cabdff1aSopenharmony_ci *mx = dx; 159cabdff1aSopenharmony_ci *my = dy; 160cabdff1aSopenharmony_ci *xored = txored; 161cabdff1aSopenharmony_ci if(!bv) return 0; 162cabdff1aSopenharmony_ci } 163cabdff1aSopenharmony_ci } 164cabdff1aSopenharmony_ci } 165cabdff1aSopenharmony_ci return bv; 166cabdff1aSopenharmony_ci} 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_cistatic int encode_frame(AVCodecContext *avctx, AVPacket *pkt, 169cabdff1aSopenharmony_ci const AVFrame *pict, int *got_packet) 170cabdff1aSopenharmony_ci{ 171cabdff1aSopenharmony_ci ZmbvEncContext * const c = avctx->priv_data; 172cabdff1aSopenharmony_ci z_stream *const zstream = &c->zstream.zstream; 173cabdff1aSopenharmony_ci const AVFrame * const p = pict; 174cabdff1aSopenharmony_ci uint8_t *src, *prev, *buf; 175cabdff1aSopenharmony_ci uint32_t *palptr; 176cabdff1aSopenharmony_ci int keyframe, chpal; 177cabdff1aSopenharmony_ci int fl; 178cabdff1aSopenharmony_ci int work_size = 0, pkt_size; 179cabdff1aSopenharmony_ci int bw, bh; 180cabdff1aSopenharmony_ci int i, j, ret; 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci keyframe = !c->curfrm; 183cabdff1aSopenharmony_ci c->curfrm++; 184cabdff1aSopenharmony_ci if(c->curfrm == c->keyint) 185cabdff1aSopenharmony_ci c->curfrm = 0; 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci palptr = (avctx->pix_fmt == AV_PIX_FMT_PAL8) ? (uint32_t *)p->data[1] : NULL; 188cabdff1aSopenharmony_ci chpal = !keyframe && palptr && memcmp(palptr, c->pal2, 1024); 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci src = p->data[0]; 191cabdff1aSopenharmony_ci prev = c->prev; 192cabdff1aSopenharmony_ci if(chpal){ 193cabdff1aSopenharmony_ci uint8_t tpal[3]; 194cabdff1aSopenharmony_ci for(i = 0; i < 256; i++){ 195cabdff1aSopenharmony_ci AV_WB24(tpal, palptr[i]); 196cabdff1aSopenharmony_ci c->work_buf[work_size++] = tpal[0] ^ c->pal[i * 3 + 0]; 197cabdff1aSopenharmony_ci c->work_buf[work_size++] = tpal[1] ^ c->pal[i * 3 + 1]; 198cabdff1aSopenharmony_ci c->work_buf[work_size++] = tpal[2] ^ c->pal[i * 3 + 2]; 199cabdff1aSopenharmony_ci c->pal[i * 3 + 0] = tpal[0]; 200cabdff1aSopenharmony_ci c->pal[i * 3 + 1] = tpal[1]; 201cabdff1aSopenharmony_ci c->pal[i * 3 + 2] = tpal[2]; 202cabdff1aSopenharmony_ci } 203cabdff1aSopenharmony_ci memcpy(c->pal2, palptr, 1024); 204cabdff1aSopenharmony_ci } 205cabdff1aSopenharmony_ci if(keyframe){ 206cabdff1aSopenharmony_ci if (palptr){ 207cabdff1aSopenharmony_ci for(i = 0; i < 256; i++){ 208cabdff1aSopenharmony_ci AV_WB24(c->pal+(i*3), palptr[i]); 209cabdff1aSopenharmony_ci } 210cabdff1aSopenharmony_ci memcpy(c->work_buf, c->pal, 768); 211cabdff1aSopenharmony_ci memcpy(c->pal2, palptr, 1024); 212cabdff1aSopenharmony_ci work_size = 768; 213cabdff1aSopenharmony_ci } 214cabdff1aSopenharmony_ci for(i = 0; i < avctx->height; i++){ 215cabdff1aSopenharmony_ci memcpy(c->work_buf + work_size, src, avctx->width * c->bypp); 216cabdff1aSopenharmony_ci src += p->linesize[0]; 217cabdff1aSopenharmony_ci work_size += avctx->width * c->bypp; 218cabdff1aSopenharmony_ci } 219cabdff1aSopenharmony_ci }else{ 220cabdff1aSopenharmony_ci int x, y, bh2, bw2, xored; 221cabdff1aSopenharmony_ci uint8_t *tsrc, *tprev; 222cabdff1aSopenharmony_ci uint8_t *mv; 223cabdff1aSopenharmony_ci int mx = 0, my = 0; 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci bw = (avctx->width + ZMBV_BLOCK - 1) / ZMBV_BLOCK; 226cabdff1aSopenharmony_ci bh = (avctx->height + ZMBV_BLOCK - 1) / ZMBV_BLOCK; 227cabdff1aSopenharmony_ci mv = c->work_buf + work_size; 228cabdff1aSopenharmony_ci memset(c->work_buf + work_size, 0, (bw * bh * 2 + 3) & ~3); 229cabdff1aSopenharmony_ci work_size += (bw * bh * 2 + 3) & ~3; 230cabdff1aSopenharmony_ci /* for now just XOR'ing */ 231cabdff1aSopenharmony_ci for(y = 0; y < avctx->height; y += ZMBV_BLOCK) { 232cabdff1aSopenharmony_ci bh2 = FFMIN(avctx->height - y, ZMBV_BLOCK); 233cabdff1aSopenharmony_ci for(x = 0; x < avctx->width; x += ZMBV_BLOCK, mv += 2) { 234cabdff1aSopenharmony_ci bw2 = FFMIN(avctx->width - x, ZMBV_BLOCK); 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ci tsrc = src + x * c->bypp; 237cabdff1aSopenharmony_ci tprev = prev + x * c->bypp; 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci zmbv_me(c, tsrc, p->linesize[0], tprev, c->pstride, x, y, &mx, &my, &xored); 240cabdff1aSopenharmony_ci mv[0] = (mx * 2) | !!xored; 241cabdff1aSopenharmony_ci mv[1] = my * 2; 242cabdff1aSopenharmony_ci tprev += mx * c->bypp + my * c->pstride; 243cabdff1aSopenharmony_ci if(xored){ 244cabdff1aSopenharmony_ci for(j = 0; j < bh2; j++){ 245cabdff1aSopenharmony_ci for(i = 0; i < bw2 * c->bypp; i++) 246cabdff1aSopenharmony_ci c->work_buf[work_size++] = tsrc[i] ^ tprev[i]; 247cabdff1aSopenharmony_ci tsrc += p->linesize[0]; 248cabdff1aSopenharmony_ci tprev += c->pstride; 249cabdff1aSopenharmony_ci } 250cabdff1aSopenharmony_ci } 251cabdff1aSopenharmony_ci } 252cabdff1aSopenharmony_ci src += p->linesize[0] * ZMBV_BLOCK; 253cabdff1aSopenharmony_ci prev += c->pstride * ZMBV_BLOCK; 254cabdff1aSopenharmony_ci } 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci /* save the previous frame */ 257cabdff1aSopenharmony_ci src = p->data[0]; 258cabdff1aSopenharmony_ci prev = c->prev; 259cabdff1aSopenharmony_ci for(i = 0; i < avctx->height; i++){ 260cabdff1aSopenharmony_ci memcpy(prev, src, avctx->width * c->bypp); 261cabdff1aSopenharmony_ci prev += c->pstride; 262cabdff1aSopenharmony_ci src += p->linesize[0]; 263cabdff1aSopenharmony_ci } 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci if (keyframe) 266cabdff1aSopenharmony_ci deflateReset(zstream); 267cabdff1aSopenharmony_ci 268cabdff1aSopenharmony_ci zstream->next_in = c->work_buf; 269cabdff1aSopenharmony_ci zstream->avail_in = work_size; 270cabdff1aSopenharmony_ci zstream->total_in = 0; 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci zstream->next_out = c->comp_buf; 273cabdff1aSopenharmony_ci zstream->avail_out = c->comp_size; 274cabdff1aSopenharmony_ci zstream->total_out = 0; 275cabdff1aSopenharmony_ci if (deflate(zstream, Z_SYNC_FLUSH) != Z_OK) { 276cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Error compressing data\n"); 277cabdff1aSopenharmony_ci return -1; 278cabdff1aSopenharmony_ci } 279cabdff1aSopenharmony_ci 280cabdff1aSopenharmony_ci pkt_size = zstream->total_out + 1 + 6 * keyframe; 281cabdff1aSopenharmony_ci if ((ret = ff_get_encode_buffer(avctx, pkt, pkt_size, 0)) < 0) 282cabdff1aSopenharmony_ci return ret; 283cabdff1aSopenharmony_ci buf = pkt->data; 284cabdff1aSopenharmony_ci 285cabdff1aSopenharmony_ci fl = (keyframe ? ZMBV_KEYFRAME : 0) | (chpal ? ZMBV_DELTAPAL : 0); 286cabdff1aSopenharmony_ci *buf++ = fl; 287cabdff1aSopenharmony_ci if (keyframe) { 288cabdff1aSopenharmony_ci *buf++ = 0; // hi ver 289cabdff1aSopenharmony_ci *buf++ = 1; // lo ver 290cabdff1aSopenharmony_ci *buf++ = 1; // comp 291cabdff1aSopenharmony_ci *buf++ = c->fmt; // format 292cabdff1aSopenharmony_ci *buf++ = ZMBV_BLOCK; // block width 293cabdff1aSopenharmony_ci *buf++ = ZMBV_BLOCK; // block height 294cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 295cabdff1aSopenharmony_ci } 296cabdff1aSopenharmony_ci memcpy(buf, c->comp_buf, zstream->total_out); 297cabdff1aSopenharmony_ci 298cabdff1aSopenharmony_ci *got_packet = 1; 299cabdff1aSopenharmony_ci 300cabdff1aSopenharmony_ci return 0; 301cabdff1aSopenharmony_ci} 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_cistatic av_cold int encode_end(AVCodecContext *avctx) 304cabdff1aSopenharmony_ci{ 305cabdff1aSopenharmony_ci ZmbvEncContext * const c = avctx->priv_data; 306cabdff1aSopenharmony_ci 307cabdff1aSopenharmony_ci av_freep(&c->comp_buf); 308cabdff1aSopenharmony_ci av_freep(&c->work_buf); 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci av_freep(&c->prev_buf); 311cabdff1aSopenharmony_ci ff_deflate_end(&c->zstream); 312cabdff1aSopenharmony_ci 313cabdff1aSopenharmony_ci return 0; 314cabdff1aSopenharmony_ci} 315cabdff1aSopenharmony_ci 316cabdff1aSopenharmony_ci/** 317cabdff1aSopenharmony_ci * Init zmbv encoder 318cabdff1aSopenharmony_ci */ 319cabdff1aSopenharmony_cistatic av_cold int encode_init(AVCodecContext *avctx) 320cabdff1aSopenharmony_ci{ 321cabdff1aSopenharmony_ci ZmbvEncContext * const c = avctx->priv_data; 322cabdff1aSopenharmony_ci int i; 323cabdff1aSopenharmony_ci int lvl = 9; 324cabdff1aSopenharmony_ci int prev_size, prev_offset; 325cabdff1aSopenharmony_ci 326cabdff1aSopenharmony_ci switch (avctx->pix_fmt) { 327cabdff1aSopenharmony_ci case AV_PIX_FMT_PAL8: 328cabdff1aSopenharmony_ci c->fmt = ZMBV_FMT_8BPP; 329cabdff1aSopenharmony_ci c->bypp = 1; 330cabdff1aSopenharmony_ci break; 331cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB555LE: 332cabdff1aSopenharmony_ci c->fmt = ZMBV_FMT_15BPP; 333cabdff1aSopenharmony_ci c->bypp = 2; 334cabdff1aSopenharmony_ci break; 335cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB565LE: 336cabdff1aSopenharmony_ci c->fmt = ZMBV_FMT_16BPP; 337cabdff1aSopenharmony_ci c->bypp = 2; 338cabdff1aSopenharmony_ci break; 339cabdff1aSopenharmony_ci#ifdef ZMBV_ENABLE_24BPP 340cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR24: 341cabdff1aSopenharmony_ci c->fmt = ZMBV_FMT_24BPP; 342cabdff1aSopenharmony_ci c->bypp = 3; 343cabdff1aSopenharmony_ci break; 344cabdff1aSopenharmony_ci#endif //ZMBV_ENABLE_24BPP 345cabdff1aSopenharmony_ci case AV_PIX_FMT_BGR0: 346cabdff1aSopenharmony_ci c->fmt = ZMBV_FMT_32BPP; 347cabdff1aSopenharmony_ci c->bypp = 4; 348cabdff1aSopenharmony_ci break; 349cabdff1aSopenharmony_ci } 350cabdff1aSopenharmony_ci 351cabdff1aSopenharmony_ci /* Entropy-based score tables for comparing blocks. 352cabdff1aSopenharmony_ci * Suitable for blocks up to (ZMBV_BLOCK * ZMBV_BLOCK) bytes. 353cabdff1aSopenharmony_ci * Scores are nonnegative, lower is better. 354cabdff1aSopenharmony_ci */ 355cabdff1aSopenharmony_ci for(i = 1; i <= ZMBV_BLOCK * ZMBV_BLOCK * c->bypp; i++) 356cabdff1aSopenharmony_ci c->score_tab[i] = -i * log2(i / (double)(ZMBV_BLOCK * ZMBV_BLOCK * c->bypp)) * 256; 357cabdff1aSopenharmony_ci 358cabdff1aSopenharmony_ci c->avctx = avctx; 359cabdff1aSopenharmony_ci 360cabdff1aSopenharmony_ci c->curfrm = 0; 361cabdff1aSopenharmony_ci c->keyint = avctx->keyint_min; 362cabdff1aSopenharmony_ci 363cabdff1aSopenharmony_ci /* Motion estimation range: maximum distance is -64..63 */ 364cabdff1aSopenharmony_ci c->lrange = c->urange = 8; 365cabdff1aSopenharmony_ci if(avctx->me_range > 0){ 366cabdff1aSopenharmony_ci c->lrange = FFMIN(avctx->me_range, 64); 367cabdff1aSopenharmony_ci c->urange = FFMIN(avctx->me_range, 63); 368cabdff1aSopenharmony_ci } 369cabdff1aSopenharmony_ci 370cabdff1aSopenharmony_ci if(avctx->compression_level >= 0) 371cabdff1aSopenharmony_ci lvl = avctx->compression_level; 372cabdff1aSopenharmony_ci if(lvl < 0 || lvl > 9){ 373cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Compression level should be 0-9, not %i\n", lvl); 374cabdff1aSopenharmony_ci return AVERROR(EINVAL); 375cabdff1aSopenharmony_ci } 376cabdff1aSopenharmony_ci 377cabdff1aSopenharmony_ci c->comp_size = avctx->width * c->bypp * avctx->height + 1024 + 378cabdff1aSopenharmony_ci ((avctx->width + ZMBV_BLOCK - 1) / ZMBV_BLOCK) * ((avctx->height + ZMBV_BLOCK - 1) / ZMBV_BLOCK) * 2 + 4; 379cabdff1aSopenharmony_ci if (!(c->work_buf = av_malloc(c->comp_size))) { 380cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Can't allocate work buffer.\n"); 381cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 382cabdff1aSopenharmony_ci } 383cabdff1aSopenharmony_ci /* Conservative upper bound taken from zlib v1.2.1 source via lcl.c */ 384cabdff1aSopenharmony_ci c->comp_size = c->comp_size + ((c->comp_size + 7) >> 3) + 385cabdff1aSopenharmony_ci ((c->comp_size + 63) >> 6) + 11; 386cabdff1aSopenharmony_ci 387cabdff1aSopenharmony_ci /* Allocate compression buffer */ 388cabdff1aSopenharmony_ci if (!(c->comp_buf = av_malloc(c->comp_size))) { 389cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Can't allocate compression buffer.\n"); 390cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 391cabdff1aSopenharmony_ci } 392cabdff1aSopenharmony_ci 393cabdff1aSopenharmony_ci /* Allocate prev buffer - pad around the image to allow out-of-edge ME: 394cabdff1aSopenharmony_ci * - The image should be padded with `lrange` rows before and `urange` rows 395cabdff1aSopenharmony_ci * after. 396cabdff1aSopenharmony_ci * - The stride should be padded with `lrange` pixels, then rounded up to a 397cabdff1aSopenharmony_ci * multiple of 16 bytes. 398cabdff1aSopenharmony_ci * - The first row should also be padded with `lrange` pixels before, then 399cabdff1aSopenharmony_ci * aligned up to a multiple of 16 bytes. 400cabdff1aSopenharmony_ci */ 401cabdff1aSopenharmony_ci c->pstride = FFALIGN((avctx->width + c->lrange) * c->bypp, 16); 402cabdff1aSopenharmony_ci prev_size = FFALIGN(c->lrange * c->bypp, 16) + c->pstride * (c->lrange + avctx->height + c->urange); 403cabdff1aSopenharmony_ci prev_offset = FFALIGN(c->lrange * c->bypp, 16) + c->pstride * c->lrange; 404cabdff1aSopenharmony_ci if (!(c->prev_buf = av_mallocz(prev_size))) { 405cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Can't allocate picture.\n"); 406cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 407cabdff1aSopenharmony_ci } 408cabdff1aSopenharmony_ci c->prev = c->prev_buf + prev_offset; 409cabdff1aSopenharmony_ci 410cabdff1aSopenharmony_ci return ff_deflate_init(&c->zstream, lvl, avctx); 411cabdff1aSopenharmony_ci} 412cabdff1aSopenharmony_ci 413cabdff1aSopenharmony_ciconst FFCodec ff_zmbv_encoder = { 414cabdff1aSopenharmony_ci .p.name = "zmbv", 415cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Zip Motion Blocks Video"), 416cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 417cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_ZMBV, 418cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 419cabdff1aSopenharmony_ci .priv_data_size = sizeof(ZmbvEncContext), 420cabdff1aSopenharmony_ci .init = encode_init, 421cabdff1aSopenharmony_ci FF_CODEC_ENCODE_CB(encode_frame), 422cabdff1aSopenharmony_ci .close = encode_end, 423cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_PAL8, 424cabdff1aSopenharmony_ci AV_PIX_FMT_RGB555LE, 425cabdff1aSopenharmony_ci AV_PIX_FMT_RGB565LE, 426cabdff1aSopenharmony_ci#ifdef ZMBV_ENABLE_24BPP 427cabdff1aSopenharmony_ci AV_PIX_FMT_BGR24, 428cabdff1aSopenharmony_ci#endif //ZMBV_ENABLE_24BPP 429cabdff1aSopenharmony_ci AV_PIX_FMT_BGR0, 430cabdff1aSopenharmony_ci AV_PIX_FMT_NONE }, 431cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 432cabdff1aSopenharmony_ci}; 433