2 JPC-RR: A x86 PC Hardware Emulator
5 Copyright (C) 2009 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 return compute_coefficients_average(coeffs
, num
, denum
, width
, count
, base
);
211 return compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 1);
213 return compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 2);
215 return compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 3);
217 return compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 4);
219 return compute_coefficients_lanczos(coeffs
, num
, denum
, width
, count
, base
, 5);
221 fprintf(stderr
, "Error: Unknown algorithm #%i.", algo
);
225 /* Normalize the coefficients. */
226 for(int i
= 0; i
< *count
; i
++)
228 for(int i
= 0; i
< *count
; i
++)
233 //Read the frame data in src (swidth x sheight) and resize it to dest (dwidth x dheight).
234 void resize_frame(unsigned char* dest
, unsigned dwidth
, unsigned dheight
, uint32_t* src
, unsigned swidth
,
235 unsigned sheight
, enum algorithm algo
)
237 float coeffs
[MAXCOEFFICIENTS
];
238 unsigned trap
= 0xCAFEFACE;
243 interm
= calloc(3 * sizeof(float), dwidth
* sheight
);
245 fprintf(stderr
, "Out of memory!\n");
249 for(unsigned x
= 0; x
< dwidth
; x
++) {
252 compute_coefficients(coeffs
, (position_t
)x
* swidth
, dwidth
, swidth
, &count
, &base
, algo
);
253 assert(trap
== 0xCAFEFACE);
254 for(unsigned y
= 0; y
< sheight
; y
++) {
255 float vr
= 0, vg
= 0, vb
= 0;
256 for(unsigned k
= 0; k
< count
; k
++) {
257 uint32_t sample
= src
[y
* swidth
+ k
+ base
];
258 vr
+= coeffs
[k
] * ((sample
>> 16) & 0xFF);
259 vg
+= coeffs
[k
] * ((sample
>> 8) & 0xFF);
260 vb
+= coeffs
[k
] * (sample
& 0xFF);
262 interm
[y
* 3 * dwidth
+ 3 * x
+ 0] = vr
;
263 interm
[y
* 3 * dwidth
+ 3 * x
+ 1] = vg
;
264 interm
[y
* 3 * dwidth
+ 3 * x
+ 2] = vb
;
268 for(unsigned y
= 0; y
< dheight
; y
++) {
271 compute_coefficients(coeffs
, (position_t
)y
* sheight
, dheight
, sheight
, &count
, &base
, algo
);
272 assert(trap
== 0xCAFEFACE);
273 for(unsigned x
= 0; x
< dwidth
; x
++) {
274 float vr
= 0, vg
= 0, vb
= 0;
275 for(unsigned k
= 0; k
< count
; k
++) {
276 vr
+= coeffs
[k
] * interm
[(base
+ k
) * 3 * dwidth
+ x
* 3 + 0];
277 vg
+= coeffs
[k
] * interm
[(base
+ k
) * 3 * dwidth
+ x
* 3 + 1];
278 vb
+= coeffs
[k
] * interm
[(base
+ k
) * 3 * dwidth
+ x
* 3 + 2];
283 wr
= (wr
< 0) ? 0 : ((wr
> 255) ? 255 : wr
);
284 wg
= (wg
< 0) ? 0 : ((wg
> 255) ? 255 : wg
);
285 wb
= (wb
< 0) ? 0 : ((wb
> 255) ? 255 : wb
);
287 dest
[y
* 4 * dwidth
+ 4 * x
] = (unsigned char)wr
;
288 dest
[y
* 4 * dwidth
+ 4 * x
+ 1] = (unsigned char)wg
;
289 dest
[y
* 4 * dwidth
+ 4 * x
+ 2] = (unsigned char)wb
;
290 dest
[y
* 4 * dwidth
+ 4 * x
+ 3] = 0;
297 void dump_frame(FILE* out
, unsigned width
, unsigned height
, struct frame
* frame
, enum algorithm algo
)
300 unsigned char* buffer
= calloc(4 * width
, height
);
302 fprintf(stderr
, "Out of memory!\n");
307 resize_frame(buffer
, width
, height
, frame
->f_framedata
, frame
->f_width
, frame
->f_height
,
309 printf("Destination frame %i: Timeseq=%llu.\n", dnum
, frame
->f_timeseq
);
311 printf("Destination frame %i: Blank.\n", dnum
);
314 if(fwrite(buffer
, 4 * width
, height
, out
) < height
) {
315 fprintf(stderr
, "Can't write frame to output file!\n");
322 int main(int argc
, char** argv
)
324 struct framelist_entry frame_default_list
= {1, 0, NULL
};
325 struct framelist_entry
* current_block
= &frame_default_list
;
328 if(argc
< 7 || argc
> 8) {
329 fprintf(stderr
, "usage: %s <in> <out> <algo> <width> <height> <framegap> [<frames>]\n", argv
[0]);
330 fprintf(stderr
, "Read stream from <in> and dump the raw RGBx output to <out>. The\n");
331 fprintf(stderr
, "dumped frames are scaled to be <width>x<height> and frame is read\n");
332 fprintf(stderr
, "every <framegap> ns. If <frames> is given, it lists frames to\n");
333 fprintf(stderr
, "include, in form '1,6,62-122,244-'. If not specified, default is\n");
334 fprintf(stderr
, "'1-' (dump every frame). Frame numbers are 1-based.\n");
335 fprintf(stderr
, "<algo> gives the algorithm used. Following are supported:\n");
336 fprintf(stderr
, "average: Weighted average of covering pixels\n");
337 fprintf(stderr
, "lanczos1: Lanczos with alpha = 1\n");
338 fprintf(stderr
, "lanczos2: Lanczos with alpha = 2\n");
339 fprintf(stderr
, "lanczos3: Lanczos with alpha = 3\n");
340 fprintf(stderr
, "lanczos4: Lanczos with alpha = 4\n");
341 fprintf(stderr
, "lanczos5: Lanczos with alpha = 5\n");
344 struct frame_input_stream
* in
= fis_open(argv
[1]);
345 FILE* out
= fopen(argv
[2], "wb");
347 struct frame
* aframe
= NULL
;
351 fprintf(stderr
, "Can't open %s\n", argv
[2]);
355 unsigned long width
= read_number(argv
[4], "width", 0, 0);
356 unsigned long height
= read_number(argv
[5], "height", 0, 0);
357 unsigned long framegap
= read_number(argv
[6], "framegap", 0, 0);
358 uint64_t lastdumped
= 0;
360 if(!strcasecmp(argv
[3], "average"))
362 else if(!strcasecmp(argv
[3], "lanczos1"))
363 algo
= ALGO_LANCZOS1
;
364 else if(!strcasecmp(argv
[3], "lanczos2"))
365 algo
= ALGO_LANCZOS2
;
366 else if(!strcasecmp(argv
[3], "lanczos3"))
367 algo
= ALGO_LANCZOS3
;
368 else if(!strcasecmp(argv
[3], "lanczos4"))
369 algo
= ALGO_LANCZOS4
;
370 else if(!strcasecmp(argv
[3], "lanczos5"))
371 algo
= ALGO_LANCZOS5
;
373 fprintf(stderr
, "Error: Unknown resize algorithm '%s'\n", argv
[3]);
378 current_block
= parse_framelist(argv
[7]);
381 struct frame
* old_aframe
= aframe
;
382 frame
= fis_next_frame(in
);
386 if(!current_block
|| current_block
->fe_first
> num
)
388 else if(current_block
->fe_last
+ 1 == num
&& num
> 1) {
389 current_block
= current_block
->fe_next
;
392 dump_frame(out
, width
, height
, aframe
, algo
);
398 while(frame
->f_timeseq
> lastdumped
+ framegap
) {
399 //Check that frame is in list of frames to include.
401 if(!current_block
|| current_block
->fe_first
> num
)
403 else if(current_block
->fe_last
+ 1 == num
&& num
> 1) {
404 current_block
= current_block
->fe_next
;
407 dump_frame(out
, width
, height
, old_aframe
, algo
);
409 lastdumped
+= framegap
;
413 frame_release(old_aframe
);
418 frame_release(aframe
);
421 fprintf(stderr
, "Can't close output file!\n");