Merge changes from JPC-RR release 10.7
[jpcrr.git] / streamtools / rawtorgb.c
bloba565e264414845c69124ed7ac25a952d66daf5af
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
5 Copyright (C) 2009-2010 H. Ilari Liusvaara
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as published by
9 the Free Software Foundation.
11 This program 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
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 Based on JPC x86 PC Hardware emulator,
21 A project from the Physics Dept, The University of Oxford
23 Details about original JPC can be found at:
25 www-jpc.physics.ox.ac.uk
30 #include "frame.h"
31 #include <stdio.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <assert.h>
38 #define MAXCOEFFICIENTS 256
40 typedef signed long long position_t;
42 enum algorithm
44 ALGO_AVERAGE,
45 ALGO_LANCZOS1,
46 ALGO_LANCZOS2,
47 ALGO_LANCZOS3,
48 ALGO_LANCZOS4,
49 ALGO_LANCZOS5
52 struct framelist_entry
54 unsigned long fe_first;
55 unsigned long fe_last; //0 is unbounded.
56 struct framelist_entry* fe_next;
59 unsigned long read_number(const char* value, const char* name, int zero_ok, char sep)
61 unsigned long x;
62 char* end;
64 x = strtoul(value, &end, 10);
65 if((*end && *end != sep) || (x == 0 && !zero_ok)) {
66 fprintf(stderr, "Invalid %s: '%s'\n", name, value);
67 exit(1);
69 return x;
72 struct framelist_entry* parse_framelist(const char* list)
74 const char* next;
75 const char* split;
76 struct framelist_entry* entry;
77 unsigned long first, last;
78 if(!list || !*list)
79 return NULL;
80 next = strchr(list, ',');
81 if(!next)
82 next = list + strlen(list);
83 else
84 next++;
86 entry = malloc(sizeof(struct framelist_entry));
87 if(!entry) {
88 fprintf(stderr, "Out of memory!\n");
89 exit(1);
92 split = strchr(list, '-');
93 if(split)
94 split++;
96 if(split && !*split) {
97 first = read_number(list, "framelist start", 0, '-');
98 last = 0;
99 } else if(!split || split > next)
100 first = last = read_number(list, "framelist entry", 0, ',');
101 else {
102 first = read_number(list, "framelist start", 0, '-');
103 last = read_number(split, "framelist end", 0, ',');
106 if(first > last && last != 0) {
107 fprintf(stderr, "Bad framelist range %lu-%lu!\n", first, last);
108 exit(1);
111 entry->fe_first = first;
112 entry->fe_last = last;
113 entry->fe_next = parse_framelist(next);
114 return entry;
117 #define LANZCOS_A 2
119 void compute_coefficients_lanczos(float* coeffs, position_t num, position_t denum, position_t width,
120 unsigned* count, unsigned* base, unsigned a)
122 signed lowbound, highbound, scan;
124 if(num % denum == 0) {
125 coeffs[0] = 1;
126 *count = 1;
127 *base = num / denum;
128 return;
131 if(a == 0) {
132 fprintf(stderr, "Error: Parameter alpha must be positive in lanczos resizer.",
133 2 * a + 1, MAXCOEFFICIENTS);
134 exit(1);
137 if(2 * a + 1 <= a) {
138 fprintf(stderr, "Error: Parameter alpha way too large in lanczos resizer.",
139 2 * a + 1, MAXCOEFFICIENTS);
140 exit(1);
143 if(2 * a + 1 > MAXCOEFFICIENTS) {
144 fprintf(stderr, "Error: Conversion would require %u coefficients, but only up to %u coefficients are supported.",
145 2 * a + 1, MAXCOEFFICIENTS);
146 exit(1);
149 lowbound = num - a * denum;
150 highbound = num + a * denum;
151 if(lowbound < 0)
152 lowbound = 0;
153 if(highbound > width * denum)
154 highbound = width * denum - denum;
156 scan = lowbound + (denum - lowbound % denum) % denum;
157 *base = scan / denum;
158 *count = 0;
159 while(scan <= highbound) {
160 float difference = (float)(num - scan) / denum;
161 if(num == scan)
162 coeffs[(*count)++] = 1;
163 else
164 coeffs[(*count)++] = a * sin(M_PI*difference) * sin(M_PI*difference/2) /
165 (M_PI * M_PI * difference * difference);
167 scan = scan + denum;
171 void compute_coefficients_average(float* coeffs, position_t num, position_t denum, position_t width,
172 unsigned* count, unsigned* base)
174 signed lowbound, highbound, scan;
176 lowbound = num;
177 highbound = num + width;
178 scan = lowbound - lowbound % denum;
180 if((width + denum - 1) / denum > MAXCOEFFICIENTS) {
181 fprintf(stderr, "Error: Conversion would require %lli coefficients, but only up to %u coefficients are supported.",
182 (width + denum - 1) / denum, MAXCOEFFICIENTS);
183 exit(1);
186 *base = scan / denum;
187 *coeffs = (scan + denum) - lowbound;
188 *count = 1;
189 scan = scan + denum;
190 while(scan < highbound) {
191 if(scan + denum > highbound)
192 coeffs[(*count)++] = highbound - scan;
193 else
194 coeffs[(*count)++] = denum;
196 scan = scan + denum;
200 // The coodinate space is such that range is [0, srclength] and is given as fraction
201 // num / denum, where denumerator is destination length. Thus source pixel spacing
202 // is unity.
203 void compute_coefficients(float* coeffs, position_t num, position_t denum, position_t width,
204 unsigned* count, unsigned* base, enum algorithm algo)
206 float sum = 0;
207 switch(algo) {
208 case ALGO_AVERAGE:
209 compute_coefficients_average(coeffs, num, denum, width, count, base);
210 break;
211 case ALGO_LANCZOS1:
212 compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 1);
213 break;
214 case ALGO_LANCZOS2:
215 compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 2);
216 break;
217 case ALGO_LANCZOS3:
218 compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 3);
219 break;
220 case ALGO_LANCZOS4:
221 compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 4);
222 break;
223 case ALGO_LANCZOS5:
224 compute_coefficients_lanczos(coeffs, num, denum, width, count, base, 5);
225 break;
226 default:
227 fprintf(stderr, "Error: Unknown algorithm #%i.", algo);
228 exit(1);
231 /* Normalize the coefficients. */
232 for(int i = 0; i < *count; i++)
233 sum += coeffs[i];
234 for(int i = 0; i < *count; i++)
235 coeffs[i] /= sum;
239 //Read the frame data in src (swidth x sheight) and resize it to dest (dwidth x dheight).
240 void resize_frame(unsigned char* dest, unsigned dwidth, unsigned dheight, uint32_t* src, unsigned swidth,
241 unsigned sheight, enum algorithm algo)
243 float coeffs[MAXCOEFFICIENTS];
244 unsigned trap = 0xCAFEFACE;
245 unsigned count;
246 unsigned base;
247 float* interm;
249 interm = calloc(3 * sizeof(float), dwidth * sheight);
250 if(!interm) {
251 fprintf(stderr, "Out of memory!\n");
252 exit(1);
255 for(unsigned x = 0; x < dwidth; x++) {
256 count = 0xDEADBEEF;
257 base = 0xDEADBEEF;
258 compute_coefficients(coeffs, (position_t)x * swidth, dwidth, swidth, &count, &base, algo);
259 assert(trap == 0xCAFEFACE);
260 for(unsigned y = 0; y < sheight; y++) {
261 float vr = 0, vg = 0, vb = 0;
262 for(unsigned k = 0; k < count; k++) {
263 uint32_t sample = src[y * swidth + k + base];
264 vr += coeffs[k] * ((sample >> 16) & 0xFF);
265 vg += coeffs[k] * ((sample >> 8) & 0xFF);
266 vb += coeffs[k] * (sample & 0xFF);
268 interm[y * 3 * dwidth + 3 * x + 0] = vr;
269 interm[y * 3 * dwidth + 3 * x + 1] = vg;
270 interm[y * 3 * dwidth + 3 * x + 2] = vb;
274 for(unsigned y = 0; y < dheight; y++) {
275 count = 0;
276 base = 0;
277 compute_coefficients(coeffs, (position_t)y * sheight, dheight, sheight, &count, &base, algo);
278 assert(trap == 0xCAFEFACE);
279 for(unsigned x = 0; x < dwidth; x++) {
280 float vr = 0, vg = 0, vb = 0;
281 for(unsigned k = 0; k < count; k++) {
282 vr += coeffs[k] * interm[(base + k) * 3 * dwidth + x * 3 + 0];
283 vg += coeffs[k] * interm[(base + k) * 3 * dwidth + x * 3 + 1];
284 vb += coeffs[k] * interm[(base + k) * 3 * dwidth + x * 3 + 2];
286 int wr = (int)vr;
287 int wg = (int)vg;
288 int wb = (int)vb;
289 wr = (wr < 0) ? 0 : ((wr > 255) ? 255 : wr);
290 wg = (wg < 0) ? 0 : ((wg > 255) ? 255 : wg);
291 wb = (wb < 0) ? 0 : ((wb > 255) ? 255 : wb);
293 dest[y * 4 * dwidth + 4 * x] = (unsigned char)wr;
294 dest[y * 4 * dwidth + 4 * x + 1] = (unsigned char)wg;
295 dest[y * 4 * dwidth + 4 * x + 2] = (unsigned char)wb;
296 dest[y * 4 * dwidth + 4 * x + 3] = 0;
300 free(interm);
303 void dump_frame(FILE* out, unsigned width, unsigned height, struct frame* frame, enum algorithm algo)
305 static int dnum = 1;
306 unsigned char* buffer = calloc(4 * width, height);
307 if(!buffer) {
308 fprintf(stderr, "Out of memory!\n");
309 exit(1);
312 if(frame) {
313 if(width != frame->f_width || height != frame->f_height)
314 resize_frame(buffer, width, height, frame->f_framedata, frame->f_width, frame->f_height,
315 algo);
316 else {
317 int k;
318 for(k = 0; k < width * height; k++) {
319 buffer[4 * k + 0] = (unsigned char)(frame->f_framedata[k] >> 16);
320 buffer[4 * k + 1] = (unsigned char)(frame->f_framedata[k] >> 8);
321 buffer[4 * k + 2] = (unsigned char)(frame->f_framedata[k]);
322 buffer[4 * k + 3] = (unsigned char)0;
325 printf("Destination frame %i: Timeseq=%llu.\n", dnum, frame->f_timeseq);
326 } else
327 printf("Destination frame %i: Blank.\n", dnum);
330 if(fwrite(buffer, 4 * width, height, out) < height) {
331 fprintf(stderr, "Can't write frame to output file!\n");
332 exit(1);
334 free(buffer);
335 dnum++;
338 int main(int argc, char** argv)
340 struct framelist_entry frame_default_list = {1, 0, NULL};
341 struct framelist_entry* current_block = &frame_default_list;
342 enum algorithm algo;
344 if(argc < 7 || argc > 8) {
345 fprintf(stderr, "usage: %s <in> <out> <algo> <width> <height> <framegap> [<frames>]\n", argv[0]);
346 fprintf(stderr, "Read stream from <in> and dump the raw RGBx output to <out>. The\n");
347 fprintf(stderr, "dumped frames are scaled to be <width>x<height> and frame is read\n");
348 fprintf(stderr, "every <framegap> ns. If <frames> is given, it lists frames to\n");
349 fprintf(stderr, "include, in form '1,6,62-122,244-'. If not specified, default is\n");
350 fprintf(stderr, "'1-' (dump every frame). Frame numbers are 1-based.\n");
351 fprintf(stderr, "<algo> gives the algorithm used. Following are supported:\n");
352 fprintf(stderr, "average: Weighted average of covering pixels\n");
353 fprintf(stderr, "lanczos1: Lanczos with alpha = 1\n");
354 fprintf(stderr, "lanczos2: Lanczos with alpha = 2\n");
355 fprintf(stderr, "lanczos3: Lanczos with alpha = 3\n");
356 fprintf(stderr, "lanczos4: Lanczos with alpha = 4\n");
357 fprintf(stderr, "lanczos5: Lanczos with alpha = 5\n");
358 return 1;
360 struct frame_input_stream* in = fis_open(argv[1]);
361 FILE* out = fopen(argv[2], "wb");
362 struct frame* frame;
363 struct frame* aframe = NULL;
364 int num = 1;
366 if(!out) {
367 fprintf(stderr, "Can't open %s\n", argv[2]);
368 exit(1);
371 unsigned long width = read_number(argv[4], "width", 0, 0);
372 unsigned long height = read_number(argv[5], "height", 0, 0);
373 unsigned long framegap = read_number(argv[6], "framegap", 0, 0);
374 uint64_t lastdumped = 0;
376 if(!strcasecmp(argv[3], "average"))
377 algo = ALGO_AVERAGE;
378 else if(!strcasecmp(argv[3], "lanczos1"))
379 algo = ALGO_LANCZOS1;
380 else if(!strcasecmp(argv[3], "lanczos2"))
381 algo = ALGO_LANCZOS2;
382 else if(!strcasecmp(argv[3], "lanczos3"))
383 algo = ALGO_LANCZOS3;
384 else if(!strcasecmp(argv[3], "lanczos4"))
385 algo = ALGO_LANCZOS4;
386 else if(!strcasecmp(argv[3], "lanczos5"))
387 algo = ALGO_LANCZOS5;
388 else {
389 fprintf(stderr, "Error: Unknown resize algorithm '%s'\n", argv[3]);
390 exit(1);
393 if(argc == 8)
394 current_block = parse_framelist(argv[7]);
396 while(1) {
397 struct frame* old_aframe = aframe;
398 frame = fis_next_frame(in);
399 if(!frame) {
400 if(aframe)
401 in_next_block2:
402 if(!current_block || current_block->fe_first > num)
404 else if(current_block->fe_last + 1 == num && num > 1) {
405 current_block = current_block->fe_next;
406 goto in_next_block2;
407 } else
408 dump_frame(out, width, height, aframe, algo);
409 break;
412 old_aframe = aframe;
413 aframe = frame;
414 while(frame->f_timeseq > lastdumped + framegap) {
415 //Check that frame is in list of frames to include.
416 in_next_block:
417 if(!current_block || current_block->fe_first > num)
419 else if(current_block->fe_last + 1 == num && num > 1) {
420 current_block = current_block->fe_next;
421 goto in_next_block;
422 } else {
423 dump_frame(out, width, height, old_aframe, algo);
425 lastdumped += framegap;
426 num++;
428 if(old_aframe)
429 frame_release(old_aframe);
433 if(aframe)
434 frame_release(aframe);
435 fis_close(in);
436 if(fclose(out)) {
437 fprintf(stderr, "Can't close output file!\n");
438 exit(1);