Browse code

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

Tobias Bindhammer authored on 2010/08/24 23:02:31
Showing 5 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,50 @@
0
+/*
1
+ * a64 video encoder - tables used by 64enc
2
+ * Copyright (c) 2009 Tobias Bindhammer
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file
23
+ * a64 video encoder - c64 colors in rgb
24
+ */
25
+
26
+#ifndef AVCODEC_A64COLORS_H
27
+#define AVCODEC_A64COLORS_H
28
+
29
+/* c64 palette in RGB */
30
+static const uint8_t a64_palette[16][3] = {
31
+    {0x00, 0x00, 0x00},
32
+    {0xff, 0xff, 0xff},
33
+    {0x68, 0x37, 0x2b},
34
+    {0x70, 0xa4, 0xb2},
35
+    {0x6f, 0x3d, 0x86},
36
+    {0x58, 0x8d, 0x43},
37
+    {0x35, 0x28, 0x79},
38
+    {0xb8, 0xc7, 0x6f},
39
+    {0x6f, 0x4f, 0x25},
40
+    {0x43, 0x39, 0x00},
41
+    {0x9a, 0x67, 0x59},
42
+    {0x44, 0x44, 0x44},
43
+    {0x6c, 0x6c, 0x6c},
44
+    {0x9a, 0xd2, 0x84},
45
+    {0x6c, 0x5e, 0xb5},
46
+    {0x95, 0x95, 0x95},
47
+};
48
+
49
+#endif /* AVCODEC_A64COLORS_H */
... ...
@@ -45,6 +45,8 @@ typedef struct A64Context {
45 45
     int *mc_meta_charset;
46 46
     int *mc_charmap;
47 47
     int *mc_best_cb;
48
+    int *mc_charset;
49
+    int mc_luma_vals[5];
48 50
 } A64Context;
49 51
 
50 52
 #endif /* AVCODEC_A64ENC_H */
... ...
@@ -25,11 +25,16 @@
25 25
  */
26 26
 
27 27
 #include "a64enc.h"
28
+#include "a64colors.h"
28 29
 #include "a64tables.h"
29 30
 #include "elbg.h"
30 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 39
 static void to_meta_with_crop(AVCodecContext *avctx, AVFrame *p, int *dest)
35 40
 {
... ...
@@ -63,64 +68,72 @@ static void render_charset(AVCodecContext *avctx, uint8_t *charset,
63 63
     A64Context *c = avctx->priv_data;
64 64
     uint8_t row1;
65 65
     int charpos, x, y;
66
-    int pix;
67
-    int dither;
68
-    int index1, index2;
66
+    int a, b;
67
+    uint8_t pix;
69 68
     int lowdiff, highdiff;
70
-    int maxindex = c->mc_use_5col + 3;
71
-    int maxsteps = DITHERSTEPS * maxindex + 1;
72 69
     int *best_cb = c->mc_best_cb;
70
+    static uint8_t index1[256];
71
+    static uint8_t index2[256];
72
+    static uint8_t dither[256];
73
+    int i;
74
+    int distance;
73 75
 
74
-    /* now reduce colors first */
75
-    for (x = 0; x < 256 * 32; x++) best_cb[x] = best_cb[x] * maxsteps / 255;
76
-
76
+    /* generate lookup-tables for dither and index before looping */
77
+    i = 0;
78
+    for (a=0; a < 256; a++) {
79
+        if(i < 4 && a == c->mc_luma_vals[i+1]) {
80
+            distance = c->mc_luma_vals[i+1] - c->mc_luma_vals[i];
81
+            for(b = 0; b <= distance; b++) {
82
+                  dither[c->mc_luma_vals[i]+b] = b * (DITHERSTEPS - 1) / distance;
83
+            }
84
+            i++;
85
+        }
86
+        if(i >=4 ) dither[a] = 0;
87
+        index1[a] = i;
88
+        index2[a] = FFMIN(i+1, 4);
89
+    }
77 90
     /* and render charset */
78
-    for (charpos = 0; charpos < 256; charpos++) {
91
+    for (charpos = 0; charpos < CHARSET_CHARS; charpos++) {
79 92
         lowdiff  = 0;
80 93
         highdiff = 0;
81 94
         for (y = 0; y < 8; y++) {
82 95
             row1 = 0;
83 96
             for (x = 0; x < 4; x++) {
84 97
                 pix = best_cb[y * 4 + x];
85
-                dither = pix % DITHERSTEPS;
86
-                index1 = pix / DITHERSTEPS;
87
-                index2 = FFMIN(index1 + 1, maxindex);
88 98
 
89
-                if (pix > 3 * DITHERSTEPS)
90
-                    highdiff += pix - 3 * DITHERSTEPS;
91
-                if (pix < DITHERSTEPS)
92
-                    lowdiff += DITHERSTEPS - pix;
99
+                /* accumulate error for brightest/darkest color */
100
+                if (index1[pix] >= 3)
101
+                    highdiff += pix - c->mc_luma_vals[3];
102
+                if (index1[pix] < 1)
103
+                    lowdiff += c->mc_luma_vals[1] - pix;
93 104
 
94 105
                 row1 <<= 2;
95
-                if (prep_dither_patterns[dither][y & 3][x & 3]) {
96
-                    row1 |= 3-(index2 & 3);
97
-                } else {
98
-                    row1 |= 3-(index1 & 3);
99
-                }
106
+
107
+                if (multi_dither_patterns[dither[pix]][(y & 3)][x & 3])
108
+                    row1 |= 3-(index2[pix] & 3);
109
+                else
110
+                    row1 |= 3-(index1[pix] & 3);
100 111
             }
101
-            charset[y] = row1;
112
+            charset[y+0x000] = row1;
102 113
         }
103
-
104
-        /* are we in 5col mode and need to adjust pixels? */
105
-        if (c->mc_use_5col && highdiff > 0 && lowdiff > 0) {
114
+        /* do we need to adjust pixels? */
115
+        if (highdiff > 0 && lowdiff > 0) {
106 116
             if (lowdiff > highdiff) {
107 117
                 for (x = 0; x < 32; x++)
108
-                    best_cb[x] = FFMIN(3 * DITHERSTEPS, best_cb[x]);
118
+                    best_cb[x] = FFMIN(c->mc_luma_vals[3], best_cb[x]);
109 119
             } else {
110 120
                 for (x = 0; x < 32; x++)
111
-                    best_cb[x] = FFMAX(DITHERSTEPS, best_cb[x]);
121
+                    best_cb[x] = FFMAX(c->mc_luma_vals[1], best_cb[x]);
112 122
             }
113
-            charpos--;          /* redo char */
123
+            charpos--;          /* redo now adjusted char */
124
+        /* no adjustment needed, all fine */
114 125
         } else {
115 126
             /* advance pointers */
116 127
             best_cb += 32;
117 128
             charset += 8;
118 129
 
119
-            if (highdiff > 0) {
120
-                colrammap[charpos] = 0x9;
121
-            } else {
122
-                colrammap[charpos] = 0x8;
123
-            }
130
+            /* remember colorram value */
131
+            colrammap[charpos] = (highdiff > 0) + 8;
124 132
         }
125 133
     }
126 134
 }
... ...
@@ -131,12 +144,14 @@ static av_cold int a64multi_close_encoder(AVCodecContext *avctx)
131 131
     av_free(c->mc_meta_charset);
132 132
     av_free(c->mc_best_cb);
133 133
     av_free(c->mc_charmap);
134
+    av_free(c->mc_charset);
134 135
     return 0;
135 136
 }
136 137
 
137 138
 static av_cold int a64multi_init_encoder(AVCodecContext *avctx)
138 139
 {
139 140
     A64Context *c = avctx->priv_data;
141
+    int a;
140 142
     av_lfg_init(&c->randctx, 1);
141 143
 
142 144
     if (avctx->global_quality < 1) {
... ...
@@ -147,11 +162,19 @@ static av_cold int a64multi_init_encoder(AVCodecContext *avctx)
147 147
 
148 148
     av_log(avctx, AV_LOG_INFO, "charset lifetime set to %d frame(s)\n", c->mc_lifetime);
149 149
 
150
+    /* precalc luma values for later use */
151
+    for (a = 0; a < 5; a++) {
152
+        c->mc_luma_vals[a]=a64_palette[mc_colors[a]][0] * 0.30 +
153
+                           a64_palette[mc_colors[a]][1] * 0.59 +
154
+                           a64_palette[mc_colors[a]][2] * 0.11;
155
+    }
156
+
150 157
     c->mc_frame_counter = 0;
151 158
     c->mc_use_5col      = avctx->codec->id == CODEC_ID_A64_MULTI5;
152 159
     c->mc_meta_charset  = av_malloc(32000 * c->mc_lifetime * sizeof(int));
153
-    c->mc_best_cb       = av_malloc(256 * 32 * sizeof(int));
160
+    c->mc_best_cb       = av_malloc(CHARSET_CHARS * 32 * sizeof(int));
154 161
     c->mc_charmap       = av_malloc(1000 * c->mc_lifetime * sizeof(int));
162
+    c->mc_charset       = av_malloc(0x800 * sizeof(uint8_t));
155 163
 
156 164
     avcodec_get_frame_defaults(&c->picture);
157 165
     avctx->coded_frame            = &c->picture;
... ...
@@ -188,7 +211,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, unsigned char *buf,
188 188
 
189 189
     if (req_size > buf_size) {
190 190
         av_log(avctx, AV_LOG_ERROR, "buf size too small (need %d, got %d)\n", req_size, buf_size);
191
-        return -1;
191
+        return AVERROR(EINVAL);
192 192
     }
193 193
     /* fill up mc_meta_charset with framedata until lifetime exceeds */
194 194
     if (c->mc_frame_counter < c->mc_lifetime) {
... ...
@@ -203,8 +226,8 @@ static int a64multi_encode_frame(AVCodecContext *avctx, unsigned char *buf,
203 203
     /* lifetime exceeded so now convert X frames at once */
204 204
     if (c->mc_frame_counter == c->mc_lifetime && c->mc_lifetime > 0) {
205 205
         c->mc_frame_counter = 0;
206
-        ff_init_elbg(meta, 32, 1000 * c-> mc_lifetime, best_cb, 256, 5, charmap, &c->randctx);
207
-        ff_do_elbg  (meta, 32, 1000 * c-> mc_lifetime, best_cb, 256, 5, charmap, &c->randctx);
206
+        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, CHARSET_CHARS, 5, charmap, &c->randctx);
208 208
 
209 209
         render_charset(avctx, buf, colrammap);
210 210
 
... ...
@@ -223,7 +246,7 @@ static int a64multi_encode_frame(AVCodecContext *avctx, unsigned char *buf,
223 223
 
224 224
 AVCodec a64multi_encoder = {
225 225
     .name           = "a64multi",
226
-    .type           = CODEC_TYPE_VIDEO,
226
+    .type           = AVMEDIA_TYPE_VIDEO,
227 227
     .id             = CODEC_ID_A64_MULTI,
228 228
     .priv_data_size = sizeof(A64Context),
229 229
     .init           = a64multi_init_encoder,
... ...
@@ -236,7 +259,7 @@ AVCodec a64multi_encoder = {
236 236
 
237 237
 AVCodec a64multi5_encoder = {
238 238
     .name           = "a64multi5",
239
-    .type           = CODEC_TYPE_VIDEO,
239
+    .type           = AVMEDIA_TYPE_VIDEO,
240 240
     .id             = CODEC_ID_A64_MULTI5,
241 241
     .priv_data_size = sizeof(A64Context),
242 242
     .init           = a64multi_init_encoder,
... ...
@@ -32,7 +32,8 @@
32 32
 /**
33 33
  * dither patterns used vor rendering the multicolor charset
34 34
  */
35
-static const uint8_t prep_dither_patterns[9][4][4] = {
35
+
36
+static const uint8_t multi_dither_patterns[9][4][4] = {
36 37
     {
37 38
      {0, 0, 0, 0},
38 39
      {0, 0, 0, 0},
... ...
@@ -46,7 +46,7 @@ static int a64_write_header(struct AVFormatContext *s)
46 46
         header[4] = 3;
47 47
         break;
48 48
     default:
49
-        return -1;
49
+        return AVERROR(EINVAL);
50 50
         break;
51 51
     }
52 52
     put_buffer(s->pb, header, 2);