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