Mercurial > libavcodec.hg
comparison a64multienc.c @ 12409:91db982aaaad libavcodec
fixed some return values and deprecated CODEC_TYPE_VIDEO.
dithering (faster) along a linear gradient now.
author | bindhammer |
---|---|
date | Tue, 24 Aug 2010 14:02:31 +0000 |
parents | f25a00f68cfa |
children | 7cf900245fce |
comparison
equal
deleted
inserted
replaced
12408:ae72506d4c2a | 12409:91db982aaaad |
---|---|
23 * @file | 23 * @file |
24 * a64 video encoder - multicolor modes | 24 * a64 video encoder - multicolor modes |
25 */ | 25 */ |
26 | 26 |
27 #include "a64enc.h" | 27 #include "a64enc.h" |
28 #include "a64colors.h" | |
28 #include "a64tables.h" | 29 #include "a64tables.h" |
29 #include "elbg.h" | 30 #include "elbg.h" |
30 #include "libavutil/intreadwrite.h" | 31 #include "libavutil/intreadwrite.h" |
31 | 32 |
32 #define DITHERSTEPS 8 | 33 #define DITHERSTEPS 8 |
34 #define CHARSET_CHARS 256 | |
35 | |
36 /* gray gradient */ | |
37 static const int mc_colors[5]={0x0,0xb,0xc,0xf,0x1}; | |
33 | 38 |
34 static void to_meta_with_crop(AVCodecContext *avctx, AVFrame *p, int *dest) | 39 static void to_meta_with_crop(AVCodecContext *avctx, AVFrame *p, int *dest) |
35 { | 40 { |
36 int blockx, blocky, x, y; | 41 int blockx, blocky, x, y; |
37 int luma = 0; | 42 int luma = 0; |
61 uint8_t *colrammap) | 66 uint8_t *colrammap) |
62 { | 67 { |
63 A64Context *c = avctx->priv_data; | 68 A64Context *c = avctx->priv_data; |
64 uint8_t row1; | 69 uint8_t row1; |
65 int charpos, x, y; | 70 int charpos, x, y; |
66 int pix; | 71 int a, b; |
67 int dither; | 72 uint8_t pix; |
68 int index1, index2; | |
69 int lowdiff, highdiff; | 73 int lowdiff, highdiff; |
70 int maxindex = c->mc_use_5col + 3; | |
71 int maxsteps = DITHERSTEPS * maxindex + 1; | |
72 int *best_cb = c->mc_best_cb; | 74 int *best_cb = c->mc_best_cb; |
73 | 75 static uint8_t index1[256]; |
74 /* now reduce colors first */ | 76 static uint8_t index2[256]; |
75 for (x = 0; x < 256 * 32; x++) best_cb[x] = best_cb[x] * maxsteps / 255; | 77 static uint8_t dither[256]; |
76 | 78 int i; |
79 int distance; | |
80 | |
81 /* generate lookup-tables for dither and index before looping */ | |
82 i = 0; | |
83 for (a=0; a < 256; a++) { | |
84 if(i < 4 && a == c->mc_luma_vals[i+1]) { | |
85 distance = c->mc_luma_vals[i+1] - c->mc_luma_vals[i]; | |
86 for(b = 0; b <= distance; b++) { | |
87 dither[c->mc_luma_vals[i]+b] = b * (DITHERSTEPS - 1) / distance; | |
88 } | |
89 i++; | |
90 } | |
91 if(i >=4 ) dither[a] = 0; | |
92 index1[a] = i; | |
93 index2[a] = FFMIN(i+1, 4); | |
94 } | |
77 /* and render charset */ | 95 /* and render charset */ |
78 for (charpos = 0; charpos < 256; charpos++) { | 96 for (charpos = 0; charpos < CHARSET_CHARS; charpos++) { |
79 lowdiff = 0; | 97 lowdiff = 0; |
80 highdiff = 0; | 98 highdiff = 0; |
81 for (y = 0; y < 8; y++) { | 99 for (y = 0; y < 8; y++) { |
82 row1 = 0; | 100 row1 = 0; |
83 for (x = 0; x < 4; x++) { | 101 for (x = 0; x < 4; x++) { |
84 pix = best_cb[y * 4 + x]; | 102 pix = best_cb[y * 4 + x]; |
85 dither = pix % DITHERSTEPS; | 103 |
86 index1 = pix / DITHERSTEPS; | 104 /* accumulate error for brightest/darkest color */ |
87 index2 = FFMIN(index1 + 1, maxindex); | 105 if (index1[pix] >= 3) |
88 | 106 highdiff += pix - c->mc_luma_vals[3]; |
89 if (pix > 3 * DITHERSTEPS) | 107 if (index1[pix] < 1) |
90 highdiff += pix - 3 * DITHERSTEPS; | 108 lowdiff += c->mc_luma_vals[1] - pix; |
91 if (pix < DITHERSTEPS) | |
92 lowdiff += DITHERSTEPS - pix; | |
93 | 109 |
94 row1 <<= 2; | 110 row1 <<= 2; |
95 if (prep_dither_patterns[dither][y & 3][x & 3]) { | 111 |
96 row1 |= 3-(index2 & 3); | 112 if (multi_dither_patterns[dither[pix]][(y & 3)][x & 3]) |
97 } else { | 113 row1 |= 3-(index2[pix] & 3); |
98 row1 |= 3-(index1 & 3); | 114 else |
99 } | 115 row1 |= 3-(index1[pix] & 3); |
100 } | 116 } |
101 charset[y] = row1; | 117 charset[y+0x000] = row1; |
102 } | 118 } |
103 | 119 /* do we need to adjust pixels? */ |
104 /* are we in 5col mode and need to adjust pixels? */ | 120 if (highdiff > 0 && lowdiff > 0) { |
105 if (c->mc_use_5col && highdiff > 0 && lowdiff > 0) { | |
106 if (lowdiff > highdiff) { | 121 if (lowdiff > highdiff) { |
107 for (x = 0; x < 32; x++) | 122 for (x = 0; x < 32; x++) |
108 best_cb[x] = FFMIN(3 * DITHERSTEPS, best_cb[x]); | 123 best_cb[x] = FFMIN(c->mc_luma_vals[3], best_cb[x]); |
109 } else { | 124 } else { |
110 for (x = 0; x < 32; x++) | 125 for (x = 0; x < 32; x++) |
111 best_cb[x] = FFMAX(DITHERSTEPS, best_cb[x]); | 126 best_cb[x] = FFMAX(c->mc_luma_vals[1], best_cb[x]); |
112 } | 127 } |
113 charpos--; /* redo char */ | 128 charpos--; /* redo now adjusted char */ |
129 /* no adjustment needed, all fine */ | |
114 } else { | 130 } else { |
115 /* advance pointers */ | 131 /* advance pointers */ |
116 best_cb += 32; | 132 best_cb += 32; |
117 charset += 8; | 133 charset += 8; |
118 | 134 |
119 if (highdiff > 0) { | 135 /* remember colorram value */ |
120 colrammap[charpos] = 0x9; | 136 colrammap[charpos] = (highdiff > 0) + 8; |
121 } else { | |
122 colrammap[charpos] = 0x8; | |
123 } | |
124 } | 137 } |
125 } | 138 } |
126 } | 139 } |
127 | 140 |
128 static av_cold int a64multi_close_encoder(AVCodecContext *avctx) | 141 static av_cold int a64multi_close_encoder(AVCodecContext *avctx) |
129 { | 142 { |
130 A64Context *c = avctx->priv_data; | 143 A64Context *c = avctx->priv_data; |
131 av_free(c->mc_meta_charset); | 144 av_free(c->mc_meta_charset); |
132 av_free(c->mc_best_cb); | 145 av_free(c->mc_best_cb); |
133 av_free(c->mc_charmap); | 146 av_free(c->mc_charmap); |
147 av_free(c->mc_charset); | |
134 return 0; | 148 return 0; |
135 } | 149 } |
136 | 150 |
137 static av_cold int a64multi_init_encoder(AVCodecContext *avctx) | 151 static av_cold int a64multi_init_encoder(AVCodecContext *avctx) |
138 { | 152 { |
139 A64Context *c = avctx->priv_data; | 153 A64Context *c = avctx->priv_data; |
154 int a; | |
140 av_lfg_init(&c->randctx, 1); | 155 av_lfg_init(&c->randctx, 1); |
141 | 156 |
142 if (avctx->global_quality < 1) { | 157 if (avctx->global_quality < 1) { |
143 c->mc_lifetime = 4; | 158 c->mc_lifetime = 4; |
144 } else { | 159 } else { |
145 c->mc_lifetime = avctx->global_quality /= FF_QP2LAMBDA; | 160 c->mc_lifetime = avctx->global_quality /= FF_QP2LAMBDA; |
146 } | 161 } |
147 | 162 |
148 av_log(avctx, AV_LOG_INFO, "charset lifetime set to %d frame(s)\n", c->mc_lifetime); | 163 av_log(avctx, AV_LOG_INFO, "charset lifetime set to %d frame(s)\n", c->mc_lifetime); |
149 | 164 |
165 /* precalc luma values for later use */ | |
166 for (a = 0; a < 5; a++) { | |
167 c->mc_luma_vals[a]=a64_palette[mc_colors[a]][0] * 0.30 + | |
168 a64_palette[mc_colors[a]][1] * 0.59 + | |
169 a64_palette[mc_colors[a]][2] * 0.11; | |
170 } | |
171 | |
150 c->mc_frame_counter = 0; | 172 c->mc_frame_counter = 0; |
151 c->mc_use_5col = avctx->codec->id == CODEC_ID_A64_MULTI5; | 173 c->mc_use_5col = avctx->codec->id == CODEC_ID_A64_MULTI5; |
152 c->mc_meta_charset = av_malloc(32000 * c->mc_lifetime * sizeof(int)); | 174 c->mc_meta_charset = av_malloc(32000 * c->mc_lifetime * sizeof(int)); |
153 c->mc_best_cb = av_malloc(256 * 32 * sizeof(int)); | 175 c->mc_best_cb = av_malloc(CHARSET_CHARS * 32 * sizeof(int)); |
154 c->mc_charmap = av_malloc(1000 * c->mc_lifetime * sizeof(int)); | 176 c->mc_charmap = av_malloc(1000 * c->mc_lifetime * sizeof(int)); |
177 c->mc_charset = av_malloc(0x800 * sizeof(uint8_t)); | |
155 | 178 |
156 avcodec_get_frame_defaults(&c->picture); | 179 avcodec_get_frame_defaults(&c->picture); |
157 avctx->coded_frame = &c->picture; | 180 avctx->coded_frame = &c->picture; |
158 avctx->coded_frame->pict_type = FF_I_TYPE; | 181 avctx->coded_frame->pict_type = FF_I_TYPE; |
159 avctx->coded_frame->key_frame = 1; | 182 avctx->coded_frame->key_frame = 1; |
186 | 209 |
187 req_size = 0x800 + frm_size * c->mc_lifetime; | 210 req_size = 0x800 + frm_size * c->mc_lifetime; |
188 | 211 |
189 if (req_size > buf_size) { | 212 if (req_size > buf_size) { |
190 av_log(avctx, AV_LOG_ERROR, "buf size too small (need %d, got %d)\n", req_size, buf_size); | 213 av_log(avctx, AV_LOG_ERROR, "buf size too small (need %d, got %d)\n", req_size, buf_size); |
191 return -1; | 214 return AVERROR(EINVAL); |
192 } | 215 } |
193 /* fill up mc_meta_charset with framedata until lifetime exceeds */ | 216 /* fill up mc_meta_charset with framedata until lifetime exceeds */ |
194 if (c->mc_frame_counter < c->mc_lifetime) { | 217 if (c->mc_frame_counter < c->mc_lifetime) { |
195 *p = *pict; | 218 *p = *pict; |
196 p->pict_type = FF_I_TYPE; | 219 p->pict_type = FF_I_TYPE; |
201 return 0; | 224 return 0; |
202 } | 225 } |
203 /* lifetime exceeded so now convert X frames at once */ | 226 /* lifetime exceeded so now convert X frames at once */ |
204 if (c->mc_frame_counter == c->mc_lifetime && c->mc_lifetime > 0) { | 227 if (c->mc_frame_counter == c->mc_lifetime && c->mc_lifetime > 0) { |
205 c->mc_frame_counter = 0; | 228 c->mc_frame_counter = 0; |
206 ff_init_elbg(meta, 32, 1000 * c-> mc_lifetime, best_cb, 256, 5, charmap, &c->randctx); | 229 ff_init_elbg(meta, 32, 1000 * c-> mc_lifetime, best_cb, CHARSET_CHARS, 5, charmap, &c->randctx); |
207 ff_do_elbg (meta, 32, 1000 * c-> mc_lifetime, best_cb, 256, 5, charmap, &c->randctx); | 230 ff_do_elbg (meta, 32, 1000 * c-> mc_lifetime, best_cb, CHARSET_CHARS, 5, charmap, &c->randctx); |
208 | 231 |
209 render_charset(avctx, buf, colrammap); | 232 render_charset(avctx, buf, colrammap); |
210 | 233 |
211 for (frame = 0; frame < c->mc_lifetime; frame++) { | 234 for (frame = 0; frame < c->mc_lifetime; frame++) { |
212 for (a = 0; a < 1000; a++) { | 235 for (a = 0; a < 1000; a++) { |
221 return 0; | 244 return 0; |
222 } | 245 } |
223 | 246 |
224 AVCodec a64multi_encoder = { | 247 AVCodec a64multi_encoder = { |
225 .name = "a64multi", | 248 .name = "a64multi", |
226 .type = CODEC_TYPE_VIDEO, | 249 .type = AVMEDIA_TYPE_VIDEO, |
227 .id = CODEC_ID_A64_MULTI, | 250 .id = CODEC_ID_A64_MULTI, |
228 .priv_data_size = sizeof(A64Context), | 251 .priv_data_size = sizeof(A64Context), |
229 .init = a64multi_init_encoder, | 252 .init = a64multi_init_encoder, |
230 .encode = a64multi_encode_frame, | 253 .encode = a64multi_encode_frame, |
231 .close = a64multi_close_encoder, | 254 .close = a64multi_close_encoder, |
234 .capabilities = CODEC_CAP_DELAY, | 257 .capabilities = CODEC_CAP_DELAY, |
235 }; | 258 }; |
236 | 259 |
237 AVCodec a64multi5_encoder = { | 260 AVCodec a64multi5_encoder = { |
238 .name = "a64multi5", | 261 .name = "a64multi5", |
239 .type = CODEC_TYPE_VIDEO, | 262 .type = AVMEDIA_TYPE_VIDEO, |
240 .id = CODEC_ID_A64_MULTI5, | 263 .id = CODEC_ID_A64_MULTI5, |
241 .priv_data_size = sizeof(A64Context), | 264 .priv_data_size = sizeof(A64Context), |
242 .init = a64multi_init_encoder, | 265 .init = a64multi_init_encoder, |
243 .encode = a64multi_encode_frame, | 266 .encode = a64multi_encode_frame, |
244 .close = a64multi_close_encoder, | 267 .close = a64multi_close_encoder, |