diff options
Diffstat (limited to 'libavcodec/a64multienc.c')
-rw-r--r-- | libavcodec/a64multienc.c | 103 |
1 files changed, 63 insertions, 40 deletions
diff --git a/libavcodec/a64multienc.c b/libavcodec/a64multienc.c index d2d0a1672a..ec2af9954b 100644 --- a/libavcodec/a64multienc.c +++ b/libavcodec/a64multienc.c @@ -25,11 +25,16 @@ */ #include "a64enc.h" +#include "a64colors.h" #include "a64tables.h" #include "elbg.h" #include "libavutil/intreadwrite.h" -#define DITHERSTEPS 8 +#define DITHERSTEPS 8 +#define CHARSET_CHARS 256 + +/* gray gradient */ +static const int mc_colors[5]={0x0,0xb,0xc,0xf,0x1}; static void to_meta_with_crop(AVCodecContext *avctx, AVFrame *p, int *dest) { @@ -63,64 +68,72 @@ static void render_charset(AVCodecContext *avctx, uint8_t *charset, A64Context *c = avctx->priv_data; uint8_t row1; int charpos, x, y; - int pix; - int dither; - int index1, index2; + int a, b; + uint8_t pix; int lowdiff, highdiff; - int maxindex = c->mc_use_5col + 3; - int maxsteps = DITHERSTEPS * maxindex + 1; int *best_cb = c->mc_best_cb; + static uint8_t index1[256]; + static uint8_t index2[256]; + static uint8_t dither[256]; + int i; + int distance; - /* now reduce colors first */ - for (x = 0; x < 256 * 32; x++) best_cb[x] = best_cb[x] * maxsteps / 255; - + /* generate lookup-tables for dither and index before looping */ + i = 0; + for (a=0; a < 256; a++) { + if(i < 4 && a == c->mc_luma_vals[i+1]) { + distance = c->mc_luma_vals[i+1] - c->mc_luma_vals[i]; + for(b = 0; b <= distance; b++) { + dither[c->mc_luma_vals[i]+b] = b * (DITHERSTEPS - 1) / distance; + } + i++; + } + if(i >=4 ) dither[a] = 0; + index1[a] = i; + index2[a] = FFMIN(i+1, 4); + } /* and render charset */ - for (charpos = 0; charpos < 256; charpos++) { + for (charpos = 0; charpos < CHARSET_CHARS; charpos++) { lowdiff = 0; highdiff = 0; for (y = 0; y < 8; y++) { row1 = 0; for (x = 0; x < 4; x++) { pix = best_cb[y * 4 + x]; - dither = pix % DITHERSTEPS; - index1 = pix / DITHERSTEPS; - index2 = FFMIN(index1 + 1, maxindex); - if (pix > 3 * DITHERSTEPS) - highdiff += pix - 3 * DITHERSTEPS; - if (pix < DITHERSTEPS) - lowdiff += DITHERSTEPS - pix; + /* accumulate error for brightest/darkest color */ + if (index1[pix] >= 3) + highdiff += pix - c->mc_luma_vals[3]; + if (index1[pix] < 1) + lowdiff += c->mc_luma_vals[1] - pix; row1 <<= 2; - if (prep_dither_patterns[dither][y & 3][x & 3]) { - row1 |= 3-(index2 & 3); - } else { - row1 |= 3-(index1 & 3); - } + + if (multi_dither_patterns[dither[pix]][(y & 3)][x & 3]) + row1 |= 3-(index2[pix] & 3); + else + row1 |= 3-(index1[pix] & 3); } - charset[y] = row1; + charset[y+0x000] = row1; } - - /* are we in 5col mode and need to adjust pixels? */ - if (c->mc_use_5col && highdiff > 0 && lowdiff > 0) { + /* do we need to adjust pixels? */ + if (highdiff > 0 && lowdiff > 0) { if (lowdiff > highdiff) { for (x = 0; x < 32; x++) - best_cb[x] = FFMIN(3 * DITHERSTEPS, best_cb[x]); + best_cb[x] = FFMIN(c->mc_luma_vals[3], best_cb[x]); } else { for (x = 0; x < 32; x++) - best_cb[x] = FFMAX(DITHERSTEPS, best_cb[x]); + best_cb[x] = FFMAX(c->mc_luma_vals[1], best_cb[x]); } - charpos--; /* redo char */ + charpos--; /* redo now adjusted char */ + /* no adjustment needed, all fine */ } else { /* advance pointers */ best_cb += 32; charset += 8; - if (highdiff > 0) { - colrammap[charpos] = 0x9; - } else { - colrammap[charpos] = 0x8; - } + /* remember colorram value */ + colrammap[charpos] = (highdiff > 0) + 8; } } } @@ -131,12 +144,14 @@ static av_cold int a64multi_close_encoder(AVCodecContext *avctx) av_free(c->mc_meta_charset); av_free(c->mc_best_cb); av_free(c->mc_charmap); + av_free(c->mc_charset); return 0; } static av_cold int a64multi_init_encoder(AVCodecContext *avctx) { A64Context *c = avctx->priv_data; + int a; av_lfg_init(&c->randctx, 1); if (avctx->global_quality < 1) { @@ -147,11 +162,19 @@ static av_cold int a64multi_init_encoder(AVCodecContext *avctx) av_log(avctx, AV_LOG_INFO, "charset lifetime set to %d frame(s)\n", c->mc_lifetime); + /* precalc luma values for later use */ + for (a = 0; a < 5; a++) { + c->mc_luma_vals[a]=a64_palette[mc_colors[a]][0] * 0.30 + + a64_palette[mc_colors[a]][1] * 0.59 + + a64_palette[mc_colors[a]][2] * 0.11; + } + c->mc_frame_counter = 0; c->mc_use_5col = avctx->codec->id == CODEC_ID_A64_MULTI5; c->mc_meta_charset = av_malloc(32000 * c->mc_lifetime * sizeof(int)); - c->mc_best_cb = av_malloc(256 * 32 * sizeof(int)); + c->mc_best_cb = av_malloc(CHARSET_CHARS * 32 * sizeof(int)); c->mc_charmap = av_malloc(1000 * c->mc_lifetime * sizeof(int)); + c->mc_charset = av_malloc(0x800 * sizeof(uint8_t)); avcodec_get_frame_defaults(&c->picture); avctx->coded_frame = &c->picture; @@ -188,7 +211,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, unsigned char *buf, if (req_size > buf_size) { av_log(avctx, AV_LOG_ERROR, "buf size too small (need %d, got %d)\n", req_size, buf_size); - return -1; + return AVERROR(EINVAL); } /* fill up mc_meta_charset with framedata until lifetime exceeds */ if (c->mc_frame_counter < c->mc_lifetime) { @@ -203,8 +226,8 @@ static int a64multi_encode_frame(AVCodecContext *avctx, unsigned char *buf, /* lifetime exceeded so now convert X frames at once */ if (c->mc_frame_counter == c->mc_lifetime && c->mc_lifetime > 0) { c->mc_frame_counter = 0; - ff_init_elbg(meta, 32, 1000 * c-> mc_lifetime, best_cb, 256, 5, charmap, &c->randctx); - ff_do_elbg (meta, 32, 1000 * c-> mc_lifetime, best_cb, 256, 5, charmap, &c->randctx); + ff_init_elbg(meta, 32, 1000 * c-> mc_lifetime, best_cb, CHARSET_CHARS, 5, charmap, &c->randctx); + ff_do_elbg (meta, 32, 1000 * c-> mc_lifetime, best_cb, CHARSET_CHARS, 5, charmap, &c->randctx); render_charset(avctx, buf, colrammap); @@ -223,7 +246,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, unsigned char *buf, AVCodec a64multi_encoder = { .name = "a64multi", - .type = CODEC_TYPE_VIDEO, + .type = AVMEDIA_TYPE_VIDEO, .id = CODEC_ID_A64_MULTI, .priv_data_size = sizeof(A64Context), .init = a64multi_init_encoder, @@ -236,7 +259,7 @@ AVCodec a64multi_encoder = { AVCodec a64multi5_encoder = { .name = "a64multi5", - .type = CODEC_TYPE_VIDEO, + .type = AVMEDIA_TYPE_VIDEO, .id = CODEC_ID_A64_MULTI5, .priv_data_size = sizeof(A64Context), .init = a64multi_init_encoder, |