From bb07ab7cf22e7bf0717264f9e7b15dfb6d67e391 Mon Sep 17 00:00:00 2001 From: Tobias Bindhammer Date: Tue, 24 Aug 2010 14:02:31 +0000 Subject: [PATCH] fixed some return values and deprecated CODEC_TYPE_VIDEO. dithering (faster) along a linear gradient now. Originally committed as revision 24898 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/a64colors.h | 50 +++++++++++++++++++ libavcodec/a64enc.h | 2 + libavcodec/a64multienc.c | 105 ++++++++++++++++++++++++--------------- libavcodec/a64tables.h | 3 +- libavformat/a64.c | 2 +- 5 files changed, 119 insertions(+), 43 deletions(-) create mode 100644 libavcodec/a64colors.h diff --git a/libavcodec/a64colors.h b/libavcodec/a64colors.h new file mode 100644 index 0000000000..5928c8d453 --- /dev/null +++ b/libavcodec/a64colors.h @@ -0,0 +1,50 @@ +/* + * a64 video encoder - tables used by 64enc + * Copyright (c) 2009 Tobias Bindhammer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * a64 video encoder - c64 colors in rgb + */ + +#ifndef AVCODEC_A64COLORS_H +#define AVCODEC_A64COLORS_H + +/* c64 palette in RGB */ +static const uint8_t a64_palette[16][3] = { + {0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff}, + {0x68, 0x37, 0x2b}, + {0x70, 0xa4, 0xb2}, + {0x6f, 0x3d, 0x86}, + {0x58, 0x8d, 0x43}, + {0x35, 0x28, 0x79}, + {0xb8, 0xc7, 0x6f}, + {0x6f, 0x4f, 0x25}, + {0x43, 0x39, 0x00}, + {0x9a, 0x67, 0x59}, + {0x44, 0x44, 0x44}, + {0x6c, 0x6c, 0x6c}, + {0x9a, 0xd2, 0x84}, + {0x6c, 0x5e, 0xb5}, + {0x95, 0x95, 0x95}, +}; + +#endif /* AVCODEC_A64COLORS_H */ diff --git a/libavcodec/a64enc.h b/libavcodec/a64enc.h index 3002f5001d..a04a819616 100644 --- a/libavcodec/a64enc.h +++ b/libavcodec/a64enc.h @@ -45,6 +45,8 @@ typedef struct A64Context { int *mc_meta_charset; int *mc_charmap; int *mc_best_cb; + int *mc_charset; + int mc_luma_vals[5]; } A64Context; #endif /* AVCODEC_A64ENC_H */ 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); - } - } - charset[y] = row1; - } - /* are we in 5col mode and need to adjust pixels? */ - if (c->mc_use_5col && highdiff > 0 && lowdiff > 0) { + if (multi_dither_patterns[dither[pix]][(y & 3)][x & 3]) + row1 |= 3-(index2[pix] & 3); + else + row1 |= 3-(index1[pix] & 3); + } + charset[y+0x000] = row1; + } + /* 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, diff --git a/libavcodec/a64tables.h b/libavcodec/a64tables.h index 31d8c2e2a0..7ce60b0e5d 100644 --- a/libavcodec/a64tables.h +++ b/libavcodec/a64tables.h @@ -32,7 +32,8 @@ /** * dither patterns used vor rendering the multicolor charset */ -static const uint8_t prep_dither_patterns[9][4][4] = { + +static const uint8_t multi_dither_patterns[9][4][4] = { { {0, 0, 0, 0}, {0, 0, 0, 0}, diff --git a/libavformat/a64.c b/libavformat/a64.c index 5cf9dbc377..32ed00b063 100644 --- a/libavformat/a64.c +++ b/libavformat/a64.c @@ -46,7 +46,7 @@ static int a64_write_header(struct AVFormatContext *s) header[4] = 3; break; default: - return -1; + return AVERROR(EINVAL); break; } put_buffer(s->pb, header, 2);