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, |
