2 JPC-RR: A x86 PC Hardware Emulator
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
38 #define MAXCOEFFICIENTS 256
40 typedef signed long long position_t
;
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
)
64 x
= strtoul(value
, &end
, 10);
65 if((*end
&& *end
!= sep
) || (x
== 0 && !zero_ok
)) {
66 fprintf(stderr
, "Invalid %s: '%s'\n", name
, value
);
72 struct framelist_entry
* parse_framelist(const char* list
)
76 struct framelist_entry
* entry
;
77 unsigned long first
, last
;
80 next
= strchr(list
, ',');
82 next
= list
+ strlen(list
);
86 entry
= malloc(sizeof(struct framelist_entry
));
88 fprintf(stderr
, "Out of memory!\n");
92 split
= strchr(list
, '-');
96 if(split
&& !*split
) {
97 first
= read_number(list
, "framelist start", 0, '-');
99 } else if(!split
|| split
> next
)
100 first
= last
= read_number(list
, "framelist entry", 0, ',');
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
);
111 entry
->fe_first
= first
;
112 entry
->fe_last
= last
;
113 entry
->fe_next
= parse_framelist(next
);
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) {
132 fprintf(stderr
, "Error: Parameter alpha must be positive in lanczos resizer.",
133 2 * a
+ 1, MAXCOEFFICIENTS
);
138 fprintf(stderr
, "Error: Parameter alpha way too large in lanczos resizer.",
139 2 * a
+ 1, MAXCOEFFICIENTS
);
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
);
149 lowbound
= num
- a
* denum
;
150 highbound
= num
+ a
* denum
;
153 if(highbound
> width
* denum
)
154 highbound
= width
* denum
- denum
;
156 scan
= lowbound
+ (denum
- lowbound
% denum
) % denum
;
157 *base
= scan
/ denum
;
159 while(scan
<= highbound
) {
160 float difference
= (float)(num
- scan
) / denum
;
162 coeffs
[(*count
)++] = 1;
164 coeffs
[(*count
)++] = a
* sin(M_PI
*difference
) * sin(M_PI
*difference
/2) /
165 (M_PI
* M_PI
* difference
* difference
);
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
;
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
);
186 *base
= scan
/ denum
;
187 *coeffs
= (scan
+ denum
) - lowbound
;
190 while(scan
< highbound
) {
191 if(scan
+ denum
> highbound
)
192 coeffs
[(*count
)++] = highbound
- scan
;
194 coeffs
[(*count
)++] = 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
203 void compute_coefficients(float* coeffs
, position_t num
, position_t denum
, position_t width
,
204 unsigned* count
, unsigned* base
, enum algorithm algo
)
209 compute_coefficients_average(coeffs
, num
, denum
, width
, count
, base
);
212 compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 1);
215 compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 2);
218 compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 3);
221 compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 4);
224 compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 5);
227 fprintf(stderr
, "Error: Unknown algorithm #%i.", algo
);
231 /* Normalize the coefficients. */
232 for(int i
= 0; i
< *count
; i
++)
234 for(int i
= 0; i
< *count
; i
++)
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;
249 interm
= calloc(3 * sizeof(float), dwidth
* sheight
);
251 fprintf(stderr
, "Out of memory!\n");
255 for(unsigned x
= 0; x
< dwidth
; x
++) {
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
++) {
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];
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;
303 void dump_frame(FILE* out
, unsigned width
, unsigned height
, struct frame
* frame
, enum algorithm algo
)
306 unsigned char* buffer
= calloc(4 * width
, height
);
308 fprintf(stderr
, "Out of memory!\n");
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
,
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
);
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");
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
;
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");
360 struct frame_input_stream
* in
= fis_open(argv
[1]);
361 FILE* out
= fopen(argv
[2], "wb");
363 struct frame
* aframe
= NULL
;
367 fprintf(stderr
, "Can't open %s\n", argv
[2]);
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"))
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
;
389 fprintf(stderr
, "Error: Unknown resize algorithm '%s'\n", argv
[3]);
394 current_block
= parse_framelist(argv
[7]);
397 struct frame
* old_aframe
= aframe
;
398 frame
= fis_next_frame(in
);
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
;
408 dump_frame(out
, width
, height
, aframe
, algo
);
414 while(frame
->f_timeseq
> lastdumped
+ framegap
) {
415 //Check that frame is in list of frames to include.
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
;
423 dump_frame(out
, width
, height
, old_aframe
, algo
);
425 lastdumped
+= framegap
;
429 frame_release(old_aframe
);
434 frame_release(aframe
);
437 fprintf(stderr
, "Can't close output file!\n");