Mercurial > libavcodec.hg
annotate zmbvenc.c @ 9830:bd0879f752e6 libavcodec
Express the H.264 parser dependency on the golomb code in configure instead of
in the Makefile as it is done for all other parts that depend on golomb.
author | diego |
---|---|
date | Tue, 09 Jun 2009 20:29:52 +0000 |
parents | bc32976d6d9d |
children | 38cfe222e1a4 |
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 */ | |
64 static inline int block_cmp(uint8_t *src, int stride, uint8_t *src2, int stride2, int bw, int bh) | |
65 { | |
66 int sum = 0; | |
67 int i, j; | |
6758 | 68 uint8_t histogram[256]={0}; |
4285 | 69 |
70 for(j = 0; j < bh; j++){ | |
71 for(i = 0; i < bw; i++) | |
6758 | 72 histogram[src[i] ^ src2[i]]++; |
4285 | 73 src += stride; |
74 src2 += stride2; | |
75 } | |
6758 | 76 |
77 for(i=1; i<256; i++) | |
78 sum+= score_tab[histogram[i]]; | |
79 | |
4285 | 80 return sum; |
81 } | |
82 | |
83 /** Motion estimation function | |
84 * TODO make better ME decisions | |
85 */ | |
86 static int zmbv_me(ZmbvEncContext *c, uint8_t *src, int sstride, uint8_t *prev, int pstride, | |
87 int x, int y, int *mx, int *my) | |
88 { | |
4647 | 89 int dx, dy, tx, ty, tv, bv, bw, bh; |
4285 | 90 |
91 *mx = *my = 0; | |
4647 | 92 bw = FFMIN(ZMBV_BLOCK, c->avctx->width - x); |
93 bh = FFMIN(ZMBV_BLOCK, c->avctx->height - y); | |
94 bv = block_cmp(src, sstride, prev, pstride, bw, bh); | |
4285 | 95 if(!bv) return 0; |
4647 | 96 for(ty = FFMAX(y - c->range, 0); ty < FFMIN(y + c->range, c->avctx->height - bh); ty++){ |
97 for(tx = FFMAX(x - c->range, 0); tx < FFMIN(x + c->range, c->avctx->width - bw); tx++){ | |
4285 | 98 if(tx == x && ty == y) continue; // we already tested this block |
99 dx = tx - x; | |
100 dy = ty - y; | |
4647 | 101 tv = block_cmp(src, sstride, prev + dx + dy*pstride, pstride, bw, bh); |
4285 | 102 if(tv < bv){ |
103 bv = tv; | |
104 *mx = dx; | |
105 *my = dy; | |
106 if(!bv) return 0; | |
107 } | |
108 } | |
109 } | |
110 return bv; | |
111 } | |
112 | |
113 static int encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data) | |
114 { | |
4827 | 115 ZmbvEncContext * const c = avctx->priv_data; |
4285 | 116 AVFrame *pict = data; |
117 AVFrame * const p = &c->pic; | |
118 uint8_t *src, *prev; | |
119 uint32_t *palptr; | |
120 int len = 0; | |
121 int keyframe, chpal; | |
122 int fl; | |
123 int work_size = 0; | |
124 int bw, bh; | |
125 int i, j; | |
126 | |
127 keyframe = !c->curfrm; | |
4287 | 128 c->curfrm++; |
4285 | 129 if(c->curfrm == c->keyint) |
130 c->curfrm = 0; | |
131 *p = *pict; | |
132 p->pict_type= keyframe ? FF_I_TYPE : FF_P_TYPE; | |
133 p->key_frame= keyframe; | |
134 chpal = !keyframe && memcmp(p->data[1], c->pal2, 1024); | |
135 | |
136 fl = (keyframe ? ZMBV_KEYFRAME : 0) | (chpal ? ZMBV_DELTAPAL : 0); | |
137 *buf++ = fl; len++; | |
138 if(keyframe){ | |
139 deflateReset(&c->zstream); | |
140 *buf++ = 0; len++; // hi ver | |
141 *buf++ = 1; len++; // lo ver | |
142 *buf++ = 1; len++; // comp | |
143 *buf++ = 4; len++; // format - 8bpp | |
144 *buf++ = ZMBV_BLOCK; len++; // block width | |
145 *buf++ = ZMBV_BLOCK; len++; // block height | |
146 } | |
147 palptr = (uint32_t*)p->data[1]; | |
148 src = p->data[0]; | |
149 prev = c->prev; | |
150 if(chpal){ | |
151 uint8_t tpal[3]; | |
152 for(i = 0; i < 256; i++){ | |
5089 | 153 AV_WB24(tpal, palptr[i]); |
4285 | 154 c->work_buf[work_size++] = tpal[0] ^ c->pal[i * 3 + 0]; |
155 c->work_buf[work_size++] = tpal[1] ^ c->pal[i * 3 + 1]; | |
156 c->work_buf[work_size++] = tpal[2] ^ c->pal[i * 3 + 2]; | |
157 c->pal[i * 3 + 0] = tpal[0]; | |
158 c->pal[i * 3 + 1] = tpal[1]; | |
159 c->pal[i * 3 + 2] = tpal[2]; | |
160 } | |
161 memcpy(c->pal2, p->data[1], 1024); | |
162 } | |
163 if(keyframe){ | |
164 for(i = 0; i < 256; i++){ | |
5089 | 165 AV_WB24(c->pal+(i*3), palptr[i]); |
4285 | 166 } |
167 memcpy(c->work_buf, c->pal, 768); | |
168 memcpy(c->pal2, p->data[1], 1024); | |
169 work_size = 768; | |
170 for(i = 0; i < avctx->height; i++){ | |
171 memcpy(c->work_buf + work_size, src, avctx->width); | |
172 src += p->linesize[0]; | |
173 work_size += avctx->width; | |
174 } | |
175 }else{ | |
176 int x, y, bh2, bw2; | |
177 uint8_t *tsrc, *tprev; | |
178 uint8_t *mv; | |
179 int mx, my, bv; | |
180 | |
181 bw = (avctx->width + ZMBV_BLOCK - 1) / ZMBV_BLOCK; | |
182 bh = (avctx->height + ZMBV_BLOCK - 1) / ZMBV_BLOCK; | |
183 mv = c->work_buf + work_size; | |
184 memset(c->work_buf + work_size, 0, (bw * bh * 2 + 3) & ~3); | |
185 work_size += (bw * bh * 2 + 3) & ~3; | |
186 /* for now just XOR'ing */ | |
187 for(y = 0; y < avctx->height; y += ZMBV_BLOCK) { | |
188 bh2 = FFMIN(avctx->height - y, ZMBV_BLOCK); | |
189 for(x = 0; x < avctx->width; x += ZMBV_BLOCK, mv += 2) { | |
190 bw2 = FFMIN(avctx->width - x, ZMBV_BLOCK); | |
191 | |
192 tsrc = src + x; | |
193 tprev = prev + x; | |
194 | |
195 bv = zmbv_me(c, tsrc, p->linesize[0], tprev, c->pstride, x, y, &mx, &my); | |
196 mv[0] = (mx << 1) | !!bv; | |
197 mv[1] = my << 1; | |
198 tprev += mx + my * c->pstride; | |
199 if(bv){ | |
200 for(j = 0; j < bh2; j++){ | |
201 for(i = 0; i < bw2; i++) | |
202 c->work_buf[work_size++] = tsrc[i] ^ tprev[i]; | |
203 tsrc += p->linesize[0]; | |
204 tprev += c->pstride; | |
205 } | |
206 } | |
207 } | |
208 src += p->linesize[0] * ZMBV_BLOCK; | |
209 prev += c->pstride * ZMBV_BLOCK; | |
210 } | |
211 } | |
212 /* save the previous frame */ | |
213 src = p->data[0]; | |
214 prev = c->prev; | |
215 for(i = 0; i < avctx->height; i++){ | |
216 memcpy(prev, src, avctx->width); | |
217 prev += c->pstride; | |
218 src += p->linesize[0]; | |
219 } | |
220 | |
221 c->zstream.next_in = c->work_buf; | |
222 c->zstream.avail_in = work_size; | |
223 c->zstream.total_in = 0; | |
224 | |
225 c->zstream.next_out = c->comp_buf; | |
226 c->zstream.avail_out = c->comp_size; | |
227 c->zstream.total_out = 0; | |
9621 | 228 if(deflate(&c->zstream, Z_SYNC_FLUSH) != Z_OK){ |
4285 | 229 av_log(avctx, AV_LOG_ERROR, "Error compressing data\n"); |
230 return -1; | |
231 } | |
232 | |
233 memcpy(buf, c->comp_buf, c->zstream.total_out); | |
234 return len + c->zstream.total_out; | |
235 } | |
236 | |
237 | |
238 /** | |
239 * Init zmbv encoder | |
240 */ | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
5215
diff
changeset
|
241 static av_cold int encode_init(AVCodecContext *avctx) |
4285 | 242 { |
4827 | 243 ZmbvEncContext * const c = avctx->priv_data; |
4285 | 244 int zret; // Zlib return code |
6758 | 245 int i; |
4285 | 246 int lvl = 9; |
247 | |
6758 | 248 for(i=1; i<256; i++) |
6818 | 249 score_tab[i]= -i * log(i/(double)(ZMBV_BLOCK*ZMBV_BLOCK)) * (256/M_LN2); |
6758 | 250 |
4285 | 251 c->avctx = avctx; |
252 | |
253 c->curfrm = 0; | |
254 c->keyint = avctx->keyint_min; | |
255 c->range = 8; | |
256 if(avctx->me_range > 0) | |
257 c->range = FFMIN(avctx->me_range, 127); | |
258 | |
259 if(avctx->compression_level >= 0) | |
260 lvl = avctx->compression_level; | |
261 if(lvl < 0 || lvl > 9){ | |
262 av_log(avctx, AV_LOG_ERROR, "Compression level should be 0-9, not %i\n", lvl); | |
263 return -1; | |
264 } | |
265 | |
266 if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) { | |
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, | |
6788 | 333 .pix_fmts = (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 }; |