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,