1 /*
2 * a64 video encoder - multicolor modes
3 * Copyright (c) 2009 Tobias Bindhammer
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * a64 video encoder - multicolor modes
25 */
26
33
35 #define CHARSET_CHARS 256
37 #define CROP_SCREENS 1
38
41
43 /* general variables */
45
46 /* variables for multicolor modes */
59
60 /* pts of the next packet that will be output */
63
64 /* gray gradient */
65 static const int mc_colors[5]={0x0,0xb,0xc,0xf,0x1};
66
67 /* other possible gradients - to be tested */
68 //static const int mc_colors[5]={0x0,0x8,0xa,0xf,0x7};
69 //static const int mc_colors[5]={0x0,0x9,0x8,0xa,0x3};
70
72 {
73 int blockx, blocky, x,
y;
74 int luma = 0;
78
79 for (blocky = 0; blocky <
C64YRES; blocky += 8) {
80 for (blockx = 0; blockx <
C64XRES; blockx += 8) {
81 for (y = blocky; y < blocky + 8 && y <
C64YRES; y++) {
82 for (x = blockx; x < blockx + 8 && x <
C64XRES; x += 2) {
83 if(x < width && y < height) {
84 /* build average over 2 pixels */
85 luma = (src[(x + 0 + y * p->
linesize[0])] +
86 src[(x + 1 + y * p->
linesize[0])]) / 2;
87 /* write blocks as linear data now so they are suitable for elbg */
88 dest[0] = luma;
89 }
90 dest++;
91 }
92 }
93 }
94 }
95 }
96
99 {
105 int lowdiff, highdiff;
110 int i;
112
113 /* generate lookup-tables for dither and index before looping */
114 i = 0;
115 for (a=0; a < 256; a++) {
116 if(i < c->mc_pal_size -1 && a == c->
mc_luma_vals[i + 1]) {
120 }
121 i++;
122 }
126 }
127
128 /* and render charset */
130 lowdiff = 0;
131 highdiff = 0;
132 for (y = 0; y < 8; y++) {
133 row1 = 0; row2 = 0;
134 for (x = 0; x < 4; x++) {
135 pix = best_cb[y * 4 + x];
136
137 /* accumulate error for brightest/darkest color */
138 if (index1[pix] >= 3)
140 if (index1[pix] < 1)
142
143 row1 <<= 2;
144
146 row2 <<= 2;
148 row1 |= 3-(index2[pix] & 3);
149 else
150 row1 |= 3-(index1[pix] & 3);
151
153 row2 |= 3-(index2[pix] & 3);
154 else
155 row2 |= 3-(index1[pix] & 3);
156 }
157 else {
159 row1 |= 3-(index2[pix] & 3);
160 else
161 row1 |= 3-(index1[pix] & 3);
162 }
163 }
164 charset[y+0x000] = row1;
166 }
167 /* do we need to adjust pixels? */
168 if (highdiff > 0 && lowdiff > 0 && c->
mc_use_5col) {
169 if (lowdiff > highdiff) {
170 for (x = 0; x < 32; x++)
172 } else {
173 for (x = 0; x < 32; x++)
175 }
176 charpos--; /* redo now adjusted char */
177 /* no adjustment needed, all fine */
178 } else {
179 /* advance pointers */
180 best_cb += 32;
181 charset += 8;
182
183 /* remember colorram value */
184 colrammap[charpos] = (highdiff > 0);
185 }
186 }
187 }
188
190 {
197 return 0;
198 }
199
201 {
205
208 } else {
210 }
211
213
217
218 /* precalc luma values for later use */
223 }
224
232 }
233
234 /* set up extradata */
238 }
242
249
251
252 return 0;
253 }
254
256 {
259 /* only needs to be done in 5col mode */
260 /* XXX could be squeezed to 0x80 bytes */
261 for (a = 0; a < 256; a++) {
262 temp = colram[charmap[a + 0x000]] << 0;
263 temp |= colram[charmap[a + 0x100]] << 1;
264 temp |= colram[charmap[a + 0x200]] << 2;
265 if (a < 0xe8) temp |= colram[charmap[a + 0x300]] << 3;
267 }
268 }
269
271 const AVFrame *pict,
int *got_packet)
272 {
275
278 int b_height;
279 int b_width;
280
283
289
292 int screen_size;
293
297 screen_size = b_width * b_height;
298 } else {
301 screen_size = 0x400;
302 }
303
304 /* no data, means end encoding asap */
305 if (!pict) {
306 /* all done, end encoding */
308 /* no more frames in queue, prepare to flush remaining frames */
311 }
312 /* still frames in queue so limit lifetime to remaining frames */
314 /* still new data available */
315 } else {
316 /* fill up mc_meta_charset with data until lifetime exceeds */
318 *p = *pict;
325 /* lifetime is not reached so wait for next frame first */
326 return 0;
327 }
328 }
329
330 /* lifetime reached so now convert X frames at once */
332 req_size = 0;
333 /* any frames to encode? */
335 req_size = charset_size + c->
mc_lifetime*(screen_size + colram_size);
337 return ret;
339
340 /* calc optimal new charset + charmaps */
343
344 /* create colorram map and a c64 readable charset */
346
347 /* copy charset to buf */
348 memcpy(buf, charset, charset_size);
349
350 /* advance pointers */
351 buf += charset_size;
352 charset += charset_size;
353 }
354
355 /* write x frames to buf */
357 /* copy charmap to buf. buf is uchar*, charmap is int*, so no memcpy here, sorry */
358 for (y = 0; y < b_height; y++) {
359 for (x = 0; x < b_width; x++) {
360 buf[y * b_width + x] = charmap[y * b_width + x];
361 }
362 }
363 /* advance pointers */
364 buf += screen_size;
365 req_size += screen_size;
366
367 /* compress and copy colram to buf */
370 /* advance pointers */
371 buf += colram_size;
372 req_size += colram_size;
373 }
374
375 /* advance to next charmap */
376 charmap += 1000;
377 }
378
382
383 /* reset counter */
385
388
389 pkt->
size = req_size;
391 *got_packet = !!req_size;
392 }
393 return 0;
394 }
395
396 #if CONFIG_A64MULTI_ENCODER
397 AVCodec ff_a64multi_encoder = {
408 };
409 #endif
410 #if CONFIG_A64MULTI5_ENCODER
411 AVCodec ff_a64multi5_encoder = {
420 .long_name =
NULL_IF_CONFIG_SMALL(
"Multicolor charset for Commodore 64, extended with 5th color (colram)"),
422 };
423 #endif