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