1/* 2 * Zip Motion Blocks Video (ZMBV) encoder 3 * Copyright (c) 2006 Konstantin Shishkov 4 * 5 * This file is part of Libav. 6 * 7 * Libav is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * Libav is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * Zip Motion Blocks Video encoder 25 */ 26 27#include <stdio.h> 28#include <stdlib.h> 29 30#include "libavutil/intreadwrite.h" 31#include "avcodec.h" 32 33#include <zlib.h> 34 35#define ZMBV_KEYFRAME 1 36#define ZMBV_DELTAPAL 2 37 38#define ZMBV_BLOCK 16 39 40/** 41 * Encoder context 42 */ 43typedef struct ZmbvEncContext { 44 AVCodecContext *avctx; 45 AVFrame pic; 46 47 int range; 48 uint8_t *comp_buf, *work_buf; 49 uint8_t pal[768]; 50 uint32_t pal2[256]; //for quick comparisons 51 uint8_t *prev; 52 int pstride; 53 int comp_size; 54 int keyint, curfrm; 55 z_stream zstream; 56} ZmbvEncContext; 57 58static int score_tab[256]; 59 60/** Block comparing function 61 * XXX should be optimized and moved to DSPContext 62 * TODO handle out of edge ME 63 */ 64static inline int block_cmp(uint8_t *src, int stride, uint8_t *src2, int stride2, 65 int bw, int bh, int *xored) 66{ 67 int sum = 0; 68 int i, j; 69 uint8_t histogram[256] = {0}; 70 71 *xored = 0; 72 for(j = 0; j < bh; j++){ 73 for(i = 0; i < bw; i++){ 74 int t = src[i] ^ src2[i]; 75 histogram[t]++; 76 *xored |= t; 77 } 78 src += stride; 79 src2 += stride2; 80 } 81 82 for(i = 1; i < 256; i++) 83 sum += score_tab[histogram[i]]; 84 85 return sum; 86} 87 88/** Motion estimation function 89 * TODO make better ME decisions 90 */ 91static int zmbv_me(ZmbvEncContext *c, uint8_t *src, int sstride, uint8_t *prev, 92 int pstride, int x, int y, int *mx, int *my, int *xored) 93{ 94 int dx, dy, tx, ty, tv, bv, bw, bh; 95 96 *mx = *my = 0; 97 bw = FFMIN(ZMBV_BLOCK, c->avctx->width - x); 98 bh = FFMIN(ZMBV_BLOCK, c->avctx->height - y); 99 bv = block_cmp(src, sstride, prev, pstride, bw, bh, xored); 100 if(!bv) return 0; 101 for(ty = FFMAX(y - c->range, 0); ty < FFMIN(y + c->range, c->avctx->height - bh); ty++){ 102 for(tx = FFMAX(x - c->range, 0); tx < FFMIN(x + c->range, c->avctx->width - bw); tx++){ 103 if(tx == x && ty == y) continue; // we already tested this block 104 dx = tx - x; 105 dy = ty - y; 106 tv = block_cmp(src, sstride, prev + dx + dy*pstride, pstride, bw, bh, xored); 107 if(tv < bv){ 108 bv = tv; 109 *mx = dx; 110 *my = dy; 111 if(!bv) return 0; 112 } 113 } 114 } 115 return bv; 116} 117 118static int encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data) 119{ 120 ZmbvEncContext * const c = avctx->priv_data; 121 AVFrame *pict = data; 122 AVFrame * const p = &c->pic; 123 uint8_t *src, *prev; 124 uint32_t *palptr; 125 int len = 0; 126 int keyframe, chpal; 127 int fl; 128 int work_size = 0; 129 int bw, bh; 130 int i, j; 131 132 keyframe = !c->curfrm; 133 c->curfrm++; 134 if(c->curfrm == c->keyint) 135 c->curfrm = 0; 136 *p = *pict; 137 p->pict_type= keyframe ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; 138 p->key_frame= keyframe; 139 chpal = !keyframe && memcmp(p->data[1], c->pal2, 1024); 140 141 fl = (keyframe ? ZMBV_KEYFRAME : 0) | (chpal ? ZMBV_DELTAPAL : 0); 142 *buf++ = fl; len++; 143 if(keyframe){ 144 deflateReset(&c->zstream); 145 *buf++ = 0; len++; // hi ver 146 *buf++ = 1; len++; // lo ver 147 *buf++ = 1; len++; // comp 148 *buf++ = 4; len++; // format - 8bpp 149 *buf++ = ZMBV_BLOCK; len++; // block width 150 *buf++ = ZMBV_BLOCK; len++; // block height 151 } 152 palptr = (uint32_t*)p->data[1]; 153 src = p->data[0]; 154 prev = c->prev; 155 if(chpal){ 156 uint8_t tpal[3]; 157 for(i = 0; i < 256; i++){ 158 AV_WB24(tpal, palptr[i]); 159 c->work_buf[work_size++] = tpal[0] ^ c->pal[i * 3 + 0]; 160 c->work_buf[work_size++] = tpal[1] ^ c->pal[i * 3 + 1]; 161 c->work_buf[work_size++] = tpal[2] ^ c->pal[i * 3 + 2]; 162 c->pal[i * 3 + 0] = tpal[0]; 163 c->pal[i * 3 + 1] = tpal[1]; 164 c->pal[i * 3 + 2] = tpal[2]; 165 } 166 memcpy(c->pal2, p->data[1], 1024); 167 } 168 if(keyframe){ 169 for(i = 0; i < 256; i++){ 170 AV_WB24(c->pal+(i*3), palptr[i]); 171 } 172 memcpy(c->work_buf, c->pal, 768); 173 memcpy(c->pal2, p->data[1], 1024); 174 work_size = 768; 175 for(i = 0; i < avctx->height; i++){ 176 memcpy(c->work_buf + work_size, src, avctx->width); 177 src += p->linesize[0]; 178 work_size += avctx->width; 179 } 180 }else{ 181 int x, y, bh2, bw2, xored; 182 uint8_t *tsrc, *tprev; 183 uint8_t *mv; 184 int mx, my; 185 186 bw = (avctx->width + ZMBV_BLOCK - 1) / ZMBV_BLOCK; 187 bh = (avctx->height + ZMBV_BLOCK - 1) / ZMBV_BLOCK; 188 mv = c->work_buf + work_size; 189 memset(c->work_buf + work_size, 0, (bw * bh * 2 + 3) & ~3); 190 work_size += (bw * bh * 2 + 3) & ~3; 191 /* for now just XOR'ing */ 192 for(y = 0; y < avctx->height; y += ZMBV_BLOCK) { 193 bh2 = FFMIN(avctx->height - y, ZMBV_BLOCK); 194 for(x = 0; x < avctx->width; x += ZMBV_BLOCK, mv += 2) { 195 bw2 = FFMIN(avctx->width - x, ZMBV_BLOCK); 196 197 tsrc = src + x; 198 tprev = prev + x; 199 200 zmbv_me(c, tsrc, p->linesize[0], tprev, c->pstride, x, y, &mx, &my, &xored); 201 mv[0] = (mx << 1) | !!xored; 202 mv[1] = my << 1; 203 tprev += mx + my * c->pstride; 204 if(xored){ 205 for(j = 0; j < bh2; j++){ 206 for(i = 0; i < bw2; i++) 207 c->work_buf[work_size++] = tsrc[i] ^ tprev[i]; 208 tsrc += p->linesize[0]; 209 tprev += c->pstride; 210 } 211 } 212 } 213 src += p->linesize[0] * ZMBV_BLOCK; 214 prev += c->pstride * ZMBV_BLOCK; 215 } 216 } 217 /* save the previous frame */ 218 src = p->data[0]; 219 prev = c->prev; 220 for(i = 0; i < avctx->height; i++){ 221 memcpy(prev, src, avctx->width); 222 prev += c->pstride; 223 src += p->linesize[0]; 224 } 225 226 c->zstream.next_in = c->work_buf; 227 c->zstream.avail_in = work_size; 228 c->zstream.total_in = 0; 229 230 c->zstream.next_out = c->comp_buf; 231 c->zstream.avail_out = c->comp_size; 232 c->zstream.total_out = 0; 233 if(deflate(&c->zstream, Z_SYNC_FLUSH) != Z_OK){ 234 av_log(avctx, AV_LOG_ERROR, "Error compressing data\n"); 235 return -1; 236 } 237 238 memcpy(buf, c->comp_buf, c->zstream.total_out); 239 return len + c->zstream.total_out; 240} 241 242 243/** 244 * Init zmbv encoder 245 */ 246static av_cold int encode_init(AVCodecContext *avctx) 247{ 248 ZmbvEncContext * const c = avctx->priv_data; 249 int zret; // Zlib return code 250 int i; 251 int lvl = 9; 252 253 for(i=1; i<256; i++) 254 score_tab[i]= -i * log(i/(double)(ZMBV_BLOCK*ZMBV_BLOCK)) * (256/M_LN2); 255 256 c->avctx = avctx; 257 258 c->curfrm = 0; 259 c->keyint = avctx->keyint_min; 260 c->range = 8; 261 if(avctx->me_range > 0) 262 c->range = FFMIN(avctx->me_range, 127); 263 264 if(avctx->compression_level >= 0) 265 lvl = avctx->compression_level; 266 if(lvl < 0 || lvl > 9){ 267 av_log(avctx, AV_LOG_ERROR, "Compression level should be 0-9, not %i\n", lvl); 268 return -1; 269 } 270 271 // Needed if zlib unused or init aborted before deflateInit 272 memset(&c->zstream, 0, sizeof(z_stream)); 273 c->comp_size = avctx->width * avctx->height + 1024 + 274 ((avctx->width + ZMBV_BLOCK - 1) / ZMBV_BLOCK) * ((avctx->height + ZMBV_BLOCK - 1) / ZMBV_BLOCK) * 2 + 4; 275 if ((c->work_buf = av_malloc(c->comp_size)) == NULL) { 276 av_log(avctx, AV_LOG_ERROR, "Can't allocate work buffer.\n"); 277 return -1; 278 } 279 /* Conservative upper bound taken from zlib v1.2.1 source via lcl.c */ 280 c->comp_size = c->comp_size + ((c->comp_size + 7) >> 3) + 281 ((c->comp_size + 63) >> 6) + 11; 282 283 /* Allocate compression buffer */ 284 if ((c->comp_buf = av_malloc(c->comp_size)) == NULL) { 285 av_log(avctx, AV_LOG_ERROR, "Can't allocate compression buffer.\n"); 286 return -1; 287 } 288 c->pstride = FFALIGN(avctx->width, 16); 289 if ((c->prev = av_malloc(c->pstride * avctx->height)) == NULL) { 290 av_log(avctx, AV_LOG_ERROR, "Can't allocate picture.\n"); 291 return -1; 292 } 293 294 c->zstream.zalloc = Z_NULL; 295 c->zstream.zfree = Z_NULL; 296 c->zstream.opaque = Z_NULL; 297 zret = deflateInit(&c->zstream, lvl); 298 if (zret != Z_OK) { 299 av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); 300 return -1; 301 } 302 303 avctx->coded_frame = (AVFrame*)&c->pic; 304 305 return 0; 306} 307 308 309 310/** 311 * Uninit zmbv encoder 312 */ 313static av_cold int encode_end(AVCodecContext *avctx) 314{ 315 ZmbvEncContext * const c = avctx->priv_data; 316 317 av_freep(&c->comp_buf); 318 av_freep(&c->work_buf); 319 320 deflateEnd(&c->zstream); 321 av_freep(&c->prev); 322 323 return 0; 324} 325 326AVCodec ff_zmbv_encoder = { 327 .name = "zmbv", 328 .type = AVMEDIA_TYPE_VIDEO, 329 .id = CODEC_ID_ZMBV, 330 .priv_data_size = sizeof(ZmbvEncContext), 331 .init = encode_init, 332 .encode = encode_frame, 333 .close = encode_end, 334 .pix_fmts = (const enum PixelFormat[]){PIX_FMT_PAL8, PIX_FMT_NONE}, 335 .long_name = NULL_IF_CONFIG_SMALL("Zip Motion Blocks Video"), 336}; 337