1 | /****************************************************************************** |
---|
2 | * SAGE - Scalable Adaptive Graphics Environment |
---|
3 | * |
---|
4 | * Copyright (C) 2004 Electronic Visualization Laboratory, |
---|
5 | * University of Illinois at Chicago |
---|
6 | * |
---|
7 | * All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions are met: |
---|
11 | * |
---|
12 | * * Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * * Redistributions in binary form must reproduce the above |
---|
15 | * copyright notice, this list of conditions and the following disclaimer |
---|
16 | * in the documentation and/or other materials provided with the distribution. |
---|
17 | * * Neither the name of the University of Illinois at Chicago nor |
---|
18 | * the names of its contributors may be used to endorse or promote |
---|
19 | * products derived from this software without specific prior written permission. |
---|
20 | * |
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
---|
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
---|
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
---|
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
---|
25 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
---|
26 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
---|
27 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
---|
28 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
---|
29 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
---|
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
32 | * |
---|
33 | * Direct questions, comments etc about SAGE to http://www.evl.uic.edu/cavern/forum/ |
---|
34 | * |
---|
35 | *****************************************************************************/ |
---|
36 | |
---|
37 | /* |
---|
38 | * Bulk movieplayer. Plays uncompressed movies as encoded by "img2bmv", |
---|
39 | * using bpio threaded I/O library and OpenGL texturing. |
---|
40 | * |
---|
41 | * Stuart Levy, NCSA, University of Illinois Urbana-Champaign, June, 2004. |
---|
42 | */ |
---|
43 | |
---|
44 | #include "bpio.h" /* Need this first since it #defines some large-file options */ |
---|
45 | |
---|
46 | #include <stdlib.h> |
---|
47 | #include <stdio.h> |
---|
48 | #include <string.h> |
---|
49 | #include <math.h> |
---|
50 | #include <time.h> |
---|
51 | #include <signal.h> |
---|
52 | #include <errno.h> |
---|
53 | #include <sys/time.h> |
---|
54 | #include <getopt.h> |
---|
55 | |
---|
56 | #include "bpmovie.h" |
---|
57 | |
---|
58 | // headers for SAGE |
---|
59 | #include "sail.h" |
---|
60 | #include "misc.h" |
---|
61 | sail sageInf; // sail object |
---|
62 | unsigned char *rgbBuffer = 0; |
---|
63 | float pixelSize = 3.0; |
---|
64 | |
---|
65 | |
---|
66 | /* |
---|
67 | struct txcodes { |
---|
68 | int internalfmt; |
---|
69 | int format; |
---|
70 | int type; |
---|
71 | } txcode[] = { |
---|
72 | { 0,0,0 }, |
---|
73 | { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE }, |
---|
74 | { GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, |
---|
75 | { GL_RGB, GL_RGB, GL_UNSIGNED_BYTE }, |
---|
76 | { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE } |
---|
77 | }; |
---|
78 | */ |
---|
79 | |
---|
80 | int nfillers = 4; |
---|
81 | int nbufseach = 5; |
---|
82 | int readsize = 8388608; // 8MB |
---|
83 | int port = 0; |
---|
84 | |
---|
85 | char *prog; |
---|
86 | |
---|
87 | char *controlfname; |
---|
88 | |
---|
89 | enum stereomode { MONO, CROSSEYED, QUADBUFFERED }; |
---|
90 | |
---|
91 | enum stereomode stereo = CROSSEYED; |
---|
92 | |
---|
93 | |
---|
94 | /* State variables */ |
---|
95 | int winx, winy; /* current window size */ |
---|
96 | int newtex = 1; /* newly minted textures? (need full init rather than subload) */ |
---|
97 | |
---|
98 | int paused = 1; /* Movie paused? */ |
---|
99 | int doloop = 0; |
---|
100 | int majorloop = 1; |
---|
101 | int playfwd = 1; |
---|
102 | int quitnow = 0; |
---|
103 | int rateoverride = 0; /* Should defaultrate override preferred-rate setting in movie? */ |
---|
104 | int defaultrate = 10; /* default target frames/sec */ |
---|
105 | int framems = 100; /* target milliseconds per frame */ |
---|
106 | int msfudge = 35; /* framems = 1000/rate - msfudge */ |
---|
107 | int verbose = 0; |
---|
108 | int skipby = 1; /* skip -- show every Nth frame */ |
---|
109 | int preloadms = 0; /* After switching movies, wait this long for startup */ |
---|
110 | int shiftoverride = 0; |
---|
111 | int defaultshift = 0; |
---|
112 | int relshift = 0; |
---|
113 | int nwID = 1; |
---|
114 | |
---|
115 | static int swapinterval = -1; |
---|
116 | |
---|
117 | bpio_t *playlist; |
---|
118 | bpmvhead_t *mvlist; |
---|
119 | int nplay; |
---|
120 | int curplay; |
---|
121 | |
---|
122 | float accumdt = 0, accumweight = 0; |
---|
123 | |
---|
124 | void resumemovie( int loop ); |
---|
125 | void pausemovie(); |
---|
126 | int openmovie( bpio_t *bpio, char *fname, bpmvhead_t *bpmv ); |
---|
127 | |
---|
128 | off_t bpstartpos( bpio_t *bpio ) |
---|
129 | { |
---|
130 | return bpio==NULL ? 0 : bpio->bpb[0].wrappos; |
---|
131 | } |
---|
132 | |
---|
133 | off_t bpendpos( bpio_t *bpio ) |
---|
134 | { |
---|
135 | return bpio==NULL ? 0 : bpio->bpb[0].eofpos; |
---|
136 | } |
---|
137 | |
---|
138 | off_t bpincrpos( bpio_t *bpio ) |
---|
139 | { |
---|
140 | return bpio==NULL ? 0 : bpio->bufsize; |
---|
141 | } |
---|
142 | |
---|
143 | |
---|
144 | int bpawaitone( bpio_t *bpio ) |
---|
145 | { |
---|
146 | bpbuf_t *bpb = &playlist[curplay].bpb[ bpio->drain ]; |
---|
147 | |
---|
148 | pthread_mutex_lock( &bpb->bmut ); |
---|
149 | while(bpbempty( bpb ) && bpb->filling) { |
---|
150 | bpb->drainwaiting = 1; |
---|
151 | pthread_cond_wait( &bpb->bdrainwait, &bpb->bmut ); |
---|
152 | bpb->drainwaiting = 0; |
---|
153 | } |
---|
154 | pthread_mutex_unlock( &bpb->bmut ); |
---|
155 | |
---|
156 | return !bpbempty(bpb); |
---|
157 | } |
---|
158 | |
---|
159 | int bpconsume1( bpio_t *bpio ) |
---|
160 | { |
---|
161 | bpbuf_t *bpb = &bpio->bpb[ bpio->drain ]; |
---|
162 | |
---|
163 | if(!bpb->filling) /* if EOF or bpstop() or etc. */ |
---|
164 | return 0; |
---|
165 | |
---|
166 | pthread_mutex_lock( &bpb->bmut ); |
---|
167 | bpb->wp = (bpb->wp + 1) % bpb->nbufs; |
---|
168 | |
---|
169 | if(bpb->fillwaiting) |
---|
170 | pthread_cond_signal( &bpb->bfillwait ); |
---|
171 | pthread_mutex_unlock( &bpb->bmut ); |
---|
172 | |
---|
173 | bpio->drain = (bpio->drain+1) % bpio->nfillers; |
---|
174 | |
---|
175 | return bpawaitone( bpio ); |
---|
176 | } |
---|
177 | |
---|
178 | int bpframeof( bpio_t *bpio, off_t pos ) |
---|
179 | { |
---|
180 | off_t incr = bpio->bpb[0].incrpos; |
---|
181 | return incr > 0 ? (pos - bpstartpos(bpio)) / incr : |
---|
182 | incr < 0 ? (pos - bpstartpos(bpio)) / (-incr) : |
---|
183 | -1; |
---|
184 | } |
---|
185 | |
---|
186 | int defaultratefor( int curplay ) |
---|
187 | { |
---|
188 | return rateoverride |
---|
189 | || !(mvlist[curplay].flags & BPF_PREFRATE) |
---|
190 | || mvlist[curplay].prefrate == -1 /* bug in some versions of img2bmv */ |
---|
191 | ? defaultrate : mvlist[curplay].prefrate; |
---|
192 | } |
---|
193 | |
---|
194 | int defaultshiftfor( int curplay ) |
---|
195 | { |
---|
196 | return shiftoverride || !(mvlist[curplay].flags & BPF_PREFSHIFT) |
---|
197 | ? defaultshift : mvlist[curplay].prefshift; |
---|
198 | } |
---|
199 | |
---|
200 | int lasttimems; |
---|
201 | |
---|
202 | int timems() |
---|
203 | { |
---|
204 | static struct timeval then; |
---|
205 | struct timeval now; |
---|
206 | |
---|
207 | gettimeofday( &now, NULL ); |
---|
208 | if(then.tv_sec == 0) |
---|
209 | then = now; |
---|
210 | return (now.tv_sec - then.tv_sec) * 1000 + (now.tv_usec - then.tv_usec) / 1000; |
---|
211 | } |
---|
212 | |
---|
213 | int playlistadvance( int sign ) |
---|
214 | { |
---|
215 | bpio_t *bpio; |
---|
216 | int waspaused = paused; |
---|
217 | int oldplay = curplay; |
---|
218 | |
---|
219 | if(curplay >= 0) |
---|
220 | pausemovie(); |
---|
221 | |
---|
222 | curplay += sign; |
---|
223 | |
---|
224 | if(majorloop) |
---|
225 | curplay = (curplay + nplay) % nplay; |
---|
226 | |
---|
227 | if(curplay < 0 || curplay >= nplay) { |
---|
228 | pausemovie(); |
---|
229 | return 0; |
---|
230 | } |
---|
231 | |
---|
232 | if(oldplay != curplay) { |
---|
233 | int rate = defaultratefor( curplay ); |
---|
234 | |
---|
235 | framems = (rate > 0) ? 1000 / rate - msfudge: -rate; |
---|
236 | |
---|
237 | relshift = defaultshiftfor( curplay ); |
---|
238 | } |
---|
239 | |
---|
240 | bpio = &playlist[curplay]; |
---|
241 | |
---|
242 | bpforward( bpio, playfwd * skipby ); |
---|
243 | bpsync( bpio ); |
---|
244 | bpseek( bpio, playfwd>0 ? bpstartpos( bpio ) |
---|
245 | : bpendpos( bpio ) - bpio->bufsize * skipby ); |
---|
246 | |
---|
247 | if(verbose >= 2) |
---|
248 | fprintf(stderr, "advance %d framems %d\n", sign, framems); |
---|
249 | |
---|
250 | if(!waspaused) |
---|
251 | resumemovie( doloop ); |
---|
252 | |
---|
253 | if(preloadms) |
---|
254 | usleep( preloadms * 1000 ); |
---|
255 | |
---|
256 | return 1; |
---|
257 | } |
---|
258 | |
---|
259 | void idler(void); |
---|
260 | |
---|
261 | void showlater( int junk ) |
---|
262 | { |
---|
263 | //glutPostRedisplay(); |
---|
264 | //glutIdleFunc( paused ? NULL : idler ); |
---|
265 | } |
---|
266 | |
---|
267 | |
---|
268 | void idler() |
---|
269 | { |
---|
270 | if(quitnow) { |
---|
271 | exit(1); |
---|
272 | } |
---|
273 | if(verbose>=3) { printf("I"); fflush(stdout); } |
---|
274 | |
---|
275 | if(bpconsume1( &playlist[curplay] )) { |
---|
276 | /* Got a buffer ready. Should we show it now? */ |
---|
277 | if(swapinterval >= 0) { |
---|
278 | /* Rather than timing here, we'll depend on glXSwapIntervalSGI() */ |
---|
279 | //glutPostRedisplay(); |
---|
280 | } else { |
---|
281 | /* Nope, we do our own timing */ |
---|
282 | int now = timems(); |
---|
283 | if(now >= lasttimems + framems) { |
---|
284 | //glutPostRedisplay(); |
---|
285 | } else { |
---|
286 | // glutTimerFunc( (lasttimems + framems) - now, showlater, |
---|
287 | // (lasttimems+framems) - now ); |
---|
288 | // glutIdleFunc( NULL ); |
---|
289 | } |
---|
290 | } |
---|
291 | } else { |
---|
292 | if( ! playlistadvance( playfwd ) ) |
---|
293 | { |
---|
294 | // glutIdleFunc( NULL ); |
---|
295 | } |
---|
296 | } |
---|
297 | } |
---|
298 | |
---|
299 | void catch_quit(int sig) { |
---|
300 | quitnow = 1; |
---|
301 | } |
---|
302 | |
---|
303 | int ntimes = 50; |
---|
304 | |
---|
305 | void resumemovie( int loop ) |
---|
306 | { |
---|
307 | if(verbose>=3) printf("resume %d p%d\n", loop, paused); |
---|
308 | bpstart( &playlist[curplay], loop ); |
---|
309 | if(bpawaitone( &playlist[curplay] )) { |
---|
310 | // glutPostRedisplay(); |
---|
311 | if(paused) |
---|
312 | { |
---|
313 | // glutIdleFunc( idler ); |
---|
314 | } |
---|
315 | } else { |
---|
316 | printf("resume: bpawaitone -> 0?\n"); |
---|
317 | } |
---|
318 | paused = 0; |
---|
319 | } |
---|
320 | |
---|
321 | void startmovie( int loop ) |
---|
322 | { |
---|
323 | if(verbose>=2) printf("start %d\n", loop); |
---|
324 | bpseek( &playlist[curplay], bpstartpos( &playlist[curplay] ) ); |
---|
325 | bpsync( &playlist[curplay] ); |
---|
326 | resumemovie( loop ); |
---|
327 | } |
---|
328 | |
---|
329 | void pausemovie() |
---|
330 | { |
---|
331 | //glutIdleFunc( NULL ); |
---|
332 | paused = 1; |
---|
333 | } |
---|
334 | |
---|
335 | static int val, hasnum; |
---|
336 | |
---|
337 | int getval( int def ) { |
---|
338 | return hasnum < 0 ? -val : hasnum > 0 ? val : def; |
---|
339 | } |
---|
340 | |
---|
341 | void kb( unsigned char key, int x, int y ); |
---|
342 | |
---|
343 | void specialkb( int skey, int x, int y ) |
---|
344 | { |
---|
345 | bpio_t *bpio = &playlist[curplay]; |
---|
346 | |
---|
347 | /* |
---|
348 | switch(skey) { |
---|
349 | case GLUT_KEY_PAGE_UP: |
---|
350 | playlistadvance( -1 ); |
---|
351 | break; |
---|
352 | |
---|
353 | case GLUT_KEY_PAGE_DOWN: |
---|
354 | playlistadvance( 1 ); |
---|
355 | break; |
---|
356 | |
---|
357 | case GLUT_KEY_UP: |
---|
358 | skipby++; |
---|
359 | bpforward( bpio, skipby * playfwd ); |
---|
360 | break; |
---|
361 | |
---|
362 | case GLUT_KEY_DOWN: |
---|
363 | if(skipby>1) |
---|
364 | skipby--; |
---|
365 | bpforward( bpio, skipby * playfwd ); |
---|
366 | break; |
---|
367 | |
---|
368 | case GLUT_KEY_LEFT: |
---|
369 | if(glutGetModifiers() & GLUT_ACTIVE_CTRL) |
---|
370 | kb( 'L', x, y ); |
---|
371 | else |
---|
372 | kb( '<', x, y ); |
---|
373 | break; |
---|
374 | |
---|
375 | case GLUT_KEY_RIGHT: |
---|
376 | if(glutGetModifiers() & GLUT_ACTIVE_CTRL) |
---|
377 | kb( 'R', x, y ); |
---|
378 | else |
---|
379 | kb( '>', x, y ); |
---|
380 | break; |
---|
381 | |
---|
382 | case GLUT_KEY_HOME: |
---|
383 | startmovie( doloop ); |
---|
384 | break; |
---|
385 | } |
---|
386 | */ |
---|
387 | hasnum = val = 0; |
---|
388 | } |
---|
389 | |
---|
390 | void kb( unsigned char key, int x, int y ) |
---|
391 | { |
---|
392 | int isdigit = 0; |
---|
393 | bpio_t *bpio = &playlist[curplay]; |
---|
394 | |
---|
395 | switch(key) { |
---|
396 | case '\033': |
---|
397 | exit(0); |
---|
398 | |
---|
399 | case ' ': |
---|
400 | paused = !paused; |
---|
401 | if(paused) |
---|
402 | pausemovie(); |
---|
403 | else |
---|
404 | resumemovie( doloop ); |
---|
405 | break; |
---|
406 | |
---|
407 | case 'p': |
---|
408 | pausemovie(); |
---|
409 | break; |
---|
410 | |
---|
411 | case '.': case '<': |
---|
412 | bpstop( bpio ); |
---|
413 | bpsync( bpio ); |
---|
414 | bpforward( bpio, skipby ); |
---|
415 | resumemovie( doloop ); |
---|
416 | bpconsume1( bpio ); |
---|
417 | pausemovie(); |
---|
418 | break; |
---|
419 | |
---|
420 | case ',': case '>': |
---|
421 | bpstop( bpio ); |
---|
422 | bpsync( bpio ); |
---|
423 | bpforward( bpio, -skipby ); |
---|
424 | resumemovie( doloop ); |
---|
425 | bpconsume1( bpio ); |
---|
426 | pausemovie(); |
---|
427 | break; |
---|
428 | |
---|
429 | case '-': |
---|
430 | hasnum = -1; |
---|
431 | isdigit = 1; |
---|
432 | break; |
---|
433 | |
---|
434 | case 'n': |
---|
435 | if(hasnum) |
---|
436 | curplay = getval(0) - 1; |
---|
437 | playlistadvance( 1 ); |
---|
438 | break; |
---|
439 | |
---|
440 | case 'N': |
---|
441 | playlistadvance( -1 ); |
---|
442 | break; |
---|
443 | |
---|
444 | case 'P': |
---|
445 | preloadms = getval( 500 ); |
---|
446 | break; |
---|
447 | |
---|
448 | case 'f': |
---|
449 | playfwd = 1; |
---|
450 | bpforward( bpio, playfwd * skipby ); |
---|
451 | bpsync( bpio ); |
---|
452 | resumemovie( doloop ); |
---|
453 | break; |
---|
454 | |
---|
455 | case 'b': |
---|
456 | playfwd = -1; |
---|
457 | bpforward( bpio, playfwd * skipby ); |
---|
458 | bpsync( bpio ); |
---|
459 | resumemovie( doloop ); |
---|
460 | break; |
---|
461 | |
---|
462 | case 'l': |
---|
463 | doloop = hasnum ? val : !doloop; |
---|
464 | if(doloop != 0) |
---|
465 | playfwd = doloop; |
---|
466 | pausemovie(); |
---|
467 | resumemovie( doloop ); |
---|
468 | break; |
---|
469 | |
---|
470 | case 'R': |
---|
471 | relshift = getval( relshift+1 ); |
---|
472 | // glutPostRedisplay(); |
---|
473 | if(verbose>=2) printf("relshift %d\n", relshift); |
---|
474 | break; |
---|
475 | |
---|
476 | case 'L': |
---|
477 | relshift = -getval( -(relshift-1) ); |
---|
478 | // glutPostRedisplay(); |
---|
479 | if(verbose>=2) printf("relshift %d\n", relshift); |
---|
480 | break; |
---|
481 | |
---|
482 | |
---|
483 | case 'z': |
---|
484 | playfwd = 1; |
---|
485 | skipby = 1; |
---|
486 | bpforward( bpio, playfwd * skipby ); |
---|
487 | bpsync( bpio ); |
---|
488 | startmovie( doloop ); /* schedule first frame */ |
---|
489 | pausemovie(); |
---|
490 | break; |
---|
491 | |
---|
492 | case 'v': |
---|
493 | verbose = getval( !verbose ); |
---|
494 | break; |
---|
495 | |
---|
496 | case 'g': { |
---|
497 | int frameno = getval(0); |
---|
498 | int nframes = mvlist[curplay].nframes; |
---|
499 | if(frameno >= nframes-1) |
---|
500 | frameno = nframes-1; |
---|
501 | else if(frameno < 0) |
---|
502 | frameno = 0; |
---|
503 | |
---|
504 | bpseek( bpio, bpstartpos( bpio ) + frameno * (off_t) bpio->bufsize ); |
---|
505 | bpsync( bpio ); |
---|
506 | resumemovie( doloop ); |
---|
507 | bpawaitone( bpio ); |
---|
508 | pausemovie(); |
---|
509 | } |
---|
510 | break; |
---|
511 | |
---|
512 | case '0': case '1': case '2': case '3': case '4': |
---|
513 | case '5': case '6': case '7': case '8': case '9': |
---|
514 | val = val*10 + key - '0'; |
---|
515 | hasnum = 1; |
---|
516 | isdigit = 1; |
---|
517 | break; |
---|
518 | |
---|
519 | |
---|
520 | case 's': { |
---|
521 | int rate = getval( defaultratefor(curplay) ); |
---|
522 | framems = (int) ( rate>0 ? 1000.0/rate - msfudge : -rate ); |
---|
523 | } |
---|
524 | if(verbose>=2) |
---|
525 | fprintf(stderr, "%d fps -> allot %d ms/frame with 10ms fudge\n", val, framems); |
---|
526 | break; |
---|
527 | |
---|
528 | case 't': |
---|
529 | framems = getval( framems ); |
---|
530 | break; |
---|
531 | |
---|
532 | case 'S': |
---|
533 | skipby = getval( 1 ); |
---|
534 | bpforward( bpio, playfwd * skipby ); |
---|
535 | break; |
---|
536 | |
---|
537 | case '=': { |
---|
538 | int frameno = ( bptell( bpio ) - bpstartpos( bpio ) ) / bpincrpos( bpio ); |
---|
539 | float fps = accumdt==0 ? 0 : 1000 * accumweight / accumdt; |
---|
540 | fprintf(stderr, "frame %04d %5.1f fps\n", frameno, fps); |
---|
541 | } |
---|
542 | break; |
---|
543 | |
---|
544 | case 'h': |
---|
545 | fprintf(stderr, "bplay keyboard commands:\n\ |
---|
546 | <NNN>s aim for NNN frames/sec\n\ |
---|
547 | <NNN>S skip -- show every NNN'th frame\n\ |
---|
548 | <NNN>g go to NNN'th frame and pause (first = 0)\n\ |
---|
549 | . one frame forward\n\ |
---|
550 | , one frame backward\n\ |
---|
551 | f run forward\n\ |
---|
552 | b run backward\n\ |
---|
553 | v toggle verbose (on-screen framenumber & fps counter)\n\ |
---|
554 | p pause\n\ |
---|
555 | l toggle loop/stop-at-end\n\ |
---|
556 | SPACE toggle run/pause\n\ |
---|
557 | HOME go to beginning of movie and play (like \"0gf\")\n"); |
---|
558 | break; |
---|
559 | |
---|
560 | |
---|
561 | } |
---|
562 | if(!isdigit) { |
---|
563 | if(verbose>=2) { |
---|
564 | if(hasnum) printf("\"%d%c\"\n", getval(0), key); |
---|
565 | else printf("\"%c\"", key); |
---|
566 | } |
---|
567 | val = hasnum = 0; |
---|
568 | } |
---|
569 | } |
---|
570 | |
---|
571 | void swab32( void *ap, int nbytes ) |
---|
572 | { |
---|
573 | unsigned int *p = (unsigned int *)ap; |
---|
574 | while((nbytes -= 4) >= 0) { |
---|
575 | unsigned int v = *p; |
---|
576 | *p++ = ((v>>24)&0xFF) | ((v>>8)&0xFF00) | ((v&0xFF00)<<8) | ((v&0xFF)<<24); |
---|
577 | } |
---|
578 | } |
---|
579 | |
---|
580 | void swabbpmv( bpmvhead_t *bpmv ) |
---|
581 | { |
---|
582 | swab32( bpmv, (char *)&bpmv->extfname - (char *)bpmv ); |
---|
583 | |
---|
584 | /* bpmv->start is a 64-bit quantity and needs its words swapped */ |
---|
585 | bpmv->start = ((bpmv->start & 0xFFFFFFFFLL) << 32) |
---|
586 | | ((bpmv->start >> 32) & 0xFFFFFFFFLL); |
---|
587 | } |
---|
588 | |
---|
589 | |
---|
590 | int openmovie( bpio_t *bpio, char *fname, bpmvhead_t *bpmv ) |
---|
591 | { |
---|
592 | int fd; |
---|
593 | int n; |
---|
594 | bpmvhead_t head; |
---|
595 | |
---|
596 | if(fname == NULL) |
---|
597 | return -1; |
---|
598 | |
---|
599 | fd = open(fname, O_RDONLY); |
---|
600 | |
---|
601 | if(fd < 0) { |
---|
602 | fprintf(stderr, "%s: %s: can't open: %s\n", |
---|
603 | prog, fname, strerror(errno)); |
---|
604 | return -1; |
---|
605 | } |
---|
606 | |
---|
607 | n = read( fd, &head, sizeof(head) ); |
---|
608 | if(n <= &head.extfname[0] - (char *)&head) { |
---|
609 | fprintf(stderr, "%s: %s: can't read header: %s\n", |
---|
610 | prog, fname, strerror(errno)); |
---|
611 | return -1; |
---|
612 | } |
---|
613 | |
---|
614 | if(head.magic != BPMV3_MAGIC) |
---|
615 | swabbpmv( &head ); |
---|
616 | if(head.magic != BPMV3_MAGIC) { |
---|
617 | fprintf(stderr, "%s: %s doesn't look like a bpmovie file (as made by img2bpmv).\n", |
---|
618 | prog, fname); |
---|
619 | return -2; |
---|
620 | } |
---|
621 | |
---|
622 | close(fd); |
---|
623 | |
---|
624 | /* OK then. */ |
---|
625 | |
---|
626 | newtex = 1; |
---|
627 | |
---|
628 | if(bpio->nfillers == 0) |
---|
629 | bpinit( bpio, nfillers, head.imagestride, readsize, nbufseach ); |
---|
630 | |
---|
631 | if(head.flags & BPF_EXTDATA) { |
---|
632 | if(bpopen( bpio, head.extfname ) < 0) { |
---|
633 | fprintf(stderr, "%s: %s refers to movie data in \"%s\": %s\n", |
---|
634 | prog, fname, head.extfname, strerror(errno)); |
---|
635 | return -1; |
---|
636 | } |
---|
637 | } else { |
---|
638 | if(bpopen( bpio, fname ) < 0) |
---|
639 | return -1; |
---|
640 | } |
---|
641 | |
---|
642 | if(bpmv) |
---|
643 | *bpmv = head; |
---|
644 | |
---|
645 | if(head.flags & BPF_EXTDATA) { |
---|
646 | off_t end = head.start + (long long)head.imagestride * (long long)head.nframes; |
---|
647 | bprange( bpio, head.start, end ); |
---|
648 | } else { |
---|
649 | bprange( bpio, head.start, -1LL ); |
---|
650 | } |
---|
651 | bpseek( bpio, head.start ); |
---|
652 | bpsync( bpio ); |
---|
653 | |
---|
654 | return head.nframes; |
---|
655 | } |
---|
656 | |
---|
657 | void draweye( bpmvhead_t *bpmv, unsigned int *txs, unsigned char *tilebuf, |
---|
658 | float scl, float imxsz, float xoff, float yoff, int x0, int x1, float *xagain ) |
---|
659 | { |
---|
660 | //struct txcodes *txc = &txcode[ bpmv->format ]; |
---|
661 | int i,j,k, ii; |
---|
662 | |
---|
663 | for(i = k = 0; i < bpmv->nytile; i++) { |
---|
664 | for(j = x0; j < x1; j++, k++) { |
---|
665 | |
---|
666 | float xx0 = xoff + scl * j * bpmv->xtile; |
---|
667 | float xx1 = xoff + scl * (j+1) * bpmv->xtile; |
---|
668 | float yy0 = yoff + scl * i * bpmv->ytile; |
---|
669 | float yy1 = yoff + scl * (i+1) * bpmv->ytile; |
---|
670 | |
---|
671 | /* |
---|
672 | fprintf(stderr, "%d %d %d %d - stride %d %d %d\n", |
---|
673 | j * bpmv->xtile, |
---|
674 | (j+1) * bpmv->xtile, |
---|
675 | i * bpmv->ytile, |
---|
676 | (i+1) * bpmv->ytile, |
---|
677 | bpmv->xtilestride, |
---|
678 | bpmv->ytilestride, bpmv->tilerowstride); |
---|
679 | */ |
---|
680 | |
---|
681 | unsigned char *ptr = tilebuf + j*bpmv->xtilestride + i*bpmv->ytilestride; |
---|
682 | unsigned char *dst = rgbBuffer + int(i*bpmv->xtile*x1*bpmv->ytile*pixelSize) + int(j*bpmv->xtile*pixelSize); |
---|
683 | for (ii=0;ii<bpmv->ytile;ii++) |
---|
684 | { |
---|
685 | memcpy(dst, ptr, int(bpmv->xtile * pixelSize)); |
---|
686 | dst += int(bpmv->xtile * x1 * pixelSize); |
---|
687 | ptr += int(bpmv->xtile * pixelSize); |
---|
688 | } |
---|
689 | |
---|
690 | |
---|
691 | //glBindTexture( GL_TEXTURE_2D, txs[k] ); |
---|
692 | |
---|
693 | if (newtex) { |
---|
694 | |
---|
695 | /* glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); */ |
---|
696 | /* glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); */ |
---|
697 | /* glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); */ |
---|
698 | |
---|
699 | /* glTexImage2D( GL_TEXTURE_2D, 0, */ |
---|
700 | /* txc->internalfmt, bpmv->xtile, bpmv->ytile, 0, */ |
---|
701 | /* txc->format, txc->type, */ |
---|
702 | /* tilebuf + j*bpmv->xtilestride + i*bpmv->ytilestride ); */ |
---|
703 | } else { |
---|
704 | /* glTexSubImage2D( GL_TEXTURE_2D, 0, 0,0, */ |
---|
705 | /* bpmv->xtile, bpmv->ytile, txc->format, txc->type, */ |
---|
706 | /* tilebuf + j*bpmv->xtilestride + i*bpmv->ytilestride ); */ |
---|
707 | |
---|
708 | } |
---|
709 | |
---|
710 | /* glBegin( GL_QUADS ); */ |
---|
711 | |
---|
712 | /* glTexCoord2f( 0, 0 ); */ |
---|
713 | /* glVertex3f( xx0, yy0, 0 ); */ |
---|
714 | |
---|
715 | /* glTexCoord2f( 0, 1 ); */ |
---|
716 | /* glVertex3f( xx0, yy1, 0 ); */ |
---|
717 | |
---|
718 | /* glTexCoord2f( 1, 1 ); */ |
---|
719 | /* glVertex3f( xx1, yy1, 0 ); */ |
---|
720 | |
---|
721 | /* glTexCoord2f( 1, 0 ); */ |
---|
722 | /* glVertex3f( xx1, yy0, 0 ); */ |
---|
723 | |
---|
724 | /* If it's a mono movie and we're in stereo, |
---|
725 | * we need to draw this tile twice. |
---|
726 | */ |
---|
727 | if(xagain != NULL) { |
---|
728 | /* glTexCoord2f( 0, 0 ); */ |
---|
729 | /* glVertex3f( xx0 + *xagain, yy0, 0 ); */ |
---|
730 | |
---|
731 | /* glTexCoord2f( 0, 1 ); */ |
---|
732 | /* glVertex3f( xx0 + *xagain, yy1, 0 ); */ |
---|
733 | |
---|
734 | /* glTexCoord2f( 1, 1 ); */ |
---|
735 | /* glVertex3f( xx1 + *xagain, yy1, 0 ); */ |
---|
736 | |
---|
737 | /* glTexCoord2f( 1, 0 ); */ |
---|
738 | /* glVertex3f( xx1 + *xagain, yy0, 0 ); */ |
---|
739 | } |
---|
740 | |
---|
741 | /* glEnd(); */ |
---|
742 | |
---|
743 | { |
---|
744 | /* GLuint e = glGetError(); */ |
---|
745 | /* if(e != 0) fprintf(stderr, "E%d ", e); */ |
---|
746 | } |
---|
747 | } |
---|
748 | } |
---|
749 | |
---|
750 | #if 0 |
---|
751 | static int count = 1; |
---|
752 | char fn[256]; |
---|
753 | sprintf(fn, "out%d.raw", count++); |
---|
754 | FILE *ff = fopen(fn, "w+"); |
---|
755 | fwrite(rgbBuffer, 1, x1*bpmv->xtile*bpmv->nytile*bpmv->ytile*3, ff); |
---|
756 | fclose(ff); |
---|
757 | #else |
---|
758 | |
---|
759 | sageInf.swapBuffer(); |
---|
760 | rgbBuffer = (unsigned char *)sageInf.getBuffer(); |
---|
761 | |
---|
762 | #endif |
---|
763 | } |
---|
764 | |
---|
765 | void redraw() |
---|
766 | { |
---|
767 | static unsigned int *txs; |
---|
768 | static int ntxs = 0; |
---|
769 | |
---|
770 | bpmvhead_t *bpmv = &mvlist[curplay]; |
---|
771 | float xscl, yscl, scl, eyex, imxsz, xoff, yoff; |
---|
772 | float xright; |
---|
773 | |
---|
774 | unsigned char *tilebuf; |
---|
775 | int now; |
---|
776 | |
---|
777 | float dt, decay; |
---|
778 | |
---|
779 | tilebuf = bpcurbuf( &playlist[curplay] ); |
---|
780 | |
---|
781 | if(tilebuf == NULL) { |
---|
782 | /* glClearColor( 0, 0, 0.3, 1 ); */ |
---|
783 | /* glClear( GL_COLOR_BUFFER_BIT ); */ |
---|
784 | /* glutSwapBuffers(); */ |
---|
785 | return; |
---|
786 | } |
---|
787 | |
---|
788 | /* fprintf(stderr, "<%d:%d> ", playlist[curplay].drain, *(int *)tilebuf); */ |
---|
789 | |
---|
790 | if(playlist[curplay].bufsize != bpmv->imagestride) { |
---|
791 | /* I/O mismatch */ |
---|
792 | /* glClearColor( 0.5, 0, 0, 1 ); */ |
---|
793 | /* glClear( GL_COLOR_BUFFER_BIT ); */ |
---|
794 | /* glutSwapBuffers(); */ |
---|
795 | return; |
---|
796 | } |
---|
797 | |
---|
798 | if(verbose < 4) { |
---|
799 | /* glClearColor( 0, 0, 0, 1 ); */ |
---|
800 | /* if(stereo != QUADBUFFERED) */ |
---|
801 | /* glClear( GL_COLOR_BUFFER_BIT ); */ |
---|
802 | } |
---|
803 | |
---|
804 | /* glMatrixMode( GL_MODELVIEW ); */ |
---|
805 | /* glLoadIdentity(); */ |
---|
806 | |
---|
807 | /* OK, use textures from current bpio buffer */ |
---|
808 | |
---|
809 | if(bpmv->nxtile * bpmv->nytile != ntxs) { |
---|
810 | if(ntxs > 0) { |
---|
811 | //glDeleteTextures( ntxs, txs ); |
---|
812 | free( txs ); |
---|
813 | } |
---|
814 | |
---|
815 | ntxs = bpmv->nxtile * bpmv->nytile; |
---|
816 | txs = (unsigned int *) malloc( ntxs * sizeof(unsigned int) ); |
---|
817 | //glGenTextures( ntxs, txs ); |
---|
818 | newtex = 1; |
---|
819 | } |
---|
820 | |
---|
821 | // glEnable( GL_TEXTURE_2D ); |
---|
822 | |
---|
823 | /* |
---|
824 | * How big should this image be drawn? |
---|
825 | * Scale to fit the available area, centered. |
---|
826 | * If image is stereo and we're in crosseyed-stereo mode, |
---|
827 | * translate to keep center of image on center of display. |
---|
828 | */ |
---|
829 | |
---|
830 | eyex = (stereo==CROSSEYED) ? winx/2 : winx; |
---|
831 | imxsz = (bpmv->flags&BPF_STEREO) ? bpmv->xsize/2 : bpmv->xsize; |
---|
832 | xscl = eyex / (float)imxsz; |
---|
833 | yscl = winy / (float)bpmv->ysize; |
---|
834 | scl = (xscl < yscl) ? xscl : yscl; |
---|
835 | xoff = 0.5f * (eyex - scl * imxsz); |
---|
836 | yoff = 0.5f * (winy - scl * bpmv->ysize); |
---|
837 | xright = winx / 2; |
---|
838 | if(verbose >= 5) |
---|
839 | fprintf(stderr, "s%.3g xo%g yo%g\n", scl, xoff, yoff); |
---|
840 | |
---|
841 | if(verbose<4) { |
---|
842 | int stereomovie = bpmv->flags & BPF_STEREO; |
---|
843 | float xoff = 0.5f * (eyex - scl * imxsz); |
---|
844 | float yoff = 0.5f * (winy - scl * bpmv->ysize); |
---|
845 | int nxtile = bpmv->nxtile; |
---|
846 | |
---|
847 | switch(stereo) { |
---|
848 | case MONO: |
---|
849 | /* |
---|
850 | * If it's a stereo movie and we're in mono mode, |
---|
851 | * just display the left half. |
---|
852 | */ |
---|
853 | draweye( bpmv, txs, tilebuf, scl, imxsz, xoff, yoff, |
---|
854 | 0, stereomovie ? nxtile/2 : nxtile, NULL ); |
---|
855 | break; |
---|
856 | |
---|
857 | case CROSSEYED: |
---|
858 | if(stereomovie) { |
---|
859 | if(relshift == 0) { |
---|
860 | draweye( bpmv, txs, tilebuf, scl, imxsz, xoff, yoff, 0, nxtile, NULL ); |
---|
861 | } else { |
---|
862 | draweye( bpmv, txs, tilebuf, scl, imxsz, xoff+relshift, yoff, 0, nxtile/2, NULL ); |
---|
863 | draweye( bpmv, txs, tilebuf, scl, imxsz, xoff-relshift, yoff, nxtile/2, nxtile, NULL ); |
---|
864 | } |
---|
865 | } else { |
---|
866 | /* mono movie in stereo mode -- draw twice */ |
---|
867 | draweye( bpmv, txs, tilebuf, scl, imxsz, xoff, yoff, 0, nxtile, &xright ); |
---|
868 | } |
---|
869 | break; |
---|
870 | |
---|
871 | case QUADBUFFERED: |
---|
872 | /* if(stereomovie) { */ |
---|
873 | /* glDrawBuffer( GL_BACK_RIGHT ); */ |
---|
874 | /* glClear( GL_COLOR_BUFFER_BIT ); */ |
---|
875 | /* draweye( bpmv, txs, tilebuf, scl, imxsz, xoff-relshift, yoff, nxtile/2, nxtile, NULL ); */ |
---|
876 | /* glDrawBuffer( GL_BACK_LEFT ); */ |
---|
877 | /* glClear( GL_COLOR_BUFFER_BIT ); */ |
---|
878 | /* draweye( bpmv, txs, tilebuf, scl, imxsz, xoff+relshift, yoff, 0, nxtile/2, NULL ); */ |
---|
879 | /* } else { */ |
---|
880 | /* glDrawBuffer( GL_BACK ); */ |
---|
881 | /* glClear( GL_COLOR_BUFFER_BIT ); */ |
---|
882 | /* draweye( bpmv, txs, tilebuf, scl, imxsz, xoff+relshift, yoff, 0, nxtile, NULL ); */ |
---|
883 | /* } */ |
---|
884 | break; |
---|
885 | } |
---|
886 | } |
---|
887 | |
---|
888 | if(verbose) { |
---|
889 | char leg[80]; |
---|
890 | int frameno = *(int *)( tilebuf + bpmv->imagestride - 4); /* img2bmv easter egg */ |
---|
891 | float fps = accumdt==0 ? 0 : 1000 * accumweight / accumdt; |
---|
892 | bpio_t *bpio = &playlist[curplay]; |
---|
893 | int slotno = (int) ( ( bptell(bpio) - bpstartpos(bpio) ) / bpincrpos(bpio) ); |
---|
894 | int howmany = (int) ( ( bpendpos(bpio) - bpstartpos(bpio) ) / bpincrpos(bpio) ); |
---|
895 | int i; |
---|
896 | |
---|
897 | if(frameno > 0 && frameno < 20000) |
---|
898 | sprintf(leg, "%5d of 0..%-5d %4.1f fps frame %04d", slotno, howmany-1, fps, frameno); |
---|
899 | else |
---|
900 | sprintf(leg, "%5d of 0..%-5d %4.1f fps", slotno, howmany-1, fps); |
---|
901 | |
---|
902 | /* glMatrixMode( GL_MODELVIEW ); */ |
---|
903 | /* glPushMatrix(); */ |
---|
904 | |
---|
905 | /* glTranslatef( 18, winy-20, 0 ); */ |
---|
906 | /* glScalef( 0.1, 0.1, 0.1 ); */ |
---|
907 | |
---|
908 | /* glDisable( GL_TEXTURE_2D ); */ |
---|
909 | /* glColor3f( 1, 1, 0.5 ); */ |
---|
910 | |
---|
911 | /* for(i = 0; leg[i] != '\0'; i++) */ |
---|
912 | /* glutStrokeCharacter( GLUT_STROKE_ROMAN, leg[i] ); */ |
---|
913 | |
---|
914 | /* glPopMatrix(); */ |
---|
915 | } |
---|
916 | |
---|
917 | if(swapinterval < 0) { |
---|
918 | /* if we can't depend on glXSwapIntervalSGI() for timing */ |
---|
919 | now = timems(); |
---|
920 | } |
---|
921 | |
---|
922 | // glutSwapBuffers(); |
---|
923 | |
---|
924 | |
---|
925 | now = timems(); |
---|
926 | dt = (now - lasttimems); |
---|
927 | decay = exp( - dt / 100 ); |
---|
928 | accumdt = (accumdt * decay) + dt; |
---|
929 | accumweight = (accumweight * decay) + 1; |
---|
930 | |
---|
931 | lasttimems = now; |
---|
932 | |
---|
933 | if(verbose >= 2) { |
---|
934 | bpio_t *bpio = &playlist[curplay]; |
---|
935 | bpbuf_t *bpb = &bpio->bpb[ bpio->drain ]; |
---|
936 | int frameno = tilebuf ? *(int *)( tilebuf + bpmv->imagestride - 4) : -9999; /* img2bmv easter egg */ |
---|
937 | printf("<%02d:%02d~%02d> f%d fw%d r%d dw%d w%d %d..%d %.0fms\n", |
---|
938 | bpio->drain, |
---|
939 | bpb->curpos[bpb->wp] < 0 ? -1 : (int) (bpb->curpos[bpb->wp] / bpio->bufsize), |
---|
940 | frameno, |
---|
941 | bpb->filling, |
---|
942 | bpb->fillwaiting, bpb->rp, bpb->drainwaiting, bpb->wp, |
---|
943 | (int) (bpb->wrappos / bpio->bufsize), |
---|
944 | (int) (bpb->eofpos / bpio->bufsize), |
---|
945 | dt); |
---|
946 | } |
---|
947 | |
---|
948 | newtex = 0; |
---|
949 | |
---|
950 | } |
---|
951 | |
---|
952 | void visible( int yes ) |
---|
953 | { |
---|
954 | static int first = 1; |
---|
955 | if(yes && first) |
---|
956 | startmovie( doloop ); |
---|
957 | else |
---|
958 | pausemovie(); |
---|
959 | first = 0; |
---|
960 | } |
---|
961 | |
---|
962 | |
---|
963 | int main(int argc, char *argv[]) |
---|
964 | { |
---|
965 | int c, i; |
---|
966 | char *hostIP; |
---|
967 | |
---|
968 | static char Usage[] = "Usage: %s [options] file.bmv ...\n\ |
---|
969 | Plays uncompressed bulk movies in the format created by img2bmv.\n\ |
---|
970 | Options:\n\ |
---|
971 | -f NNN target NNN frames/sec or -f NNNm milliseconds/frame\n\ |
---|
972 | -t NTHREADS number of reader threads\n\ |
---|
973 | -r READSIZE size of each read() in bytes (default = image size)\n\ |
---|
974 | -M msfudge fudge factor for ms/frame timing estimates (default %d)\n\ |
---|
975 | -v verbose\n\ |
---|
976 | -n nwID network ID for SAGE\n"; |
---|
977 | |
---|
978 | prog = argv[0]; |
---|
979 | |
---|
980 | signal(SIGINT, catch_quit); |
---|
981 | |
---|
982 | hostIP = NULL; |
---|
983 | |
---|
984 | while((c = getopt(argc, argv, "t:b:r:p:S:F:f:P:L:R:vsmqM:c:n:")) != EOF) { |
---|
985 | switch(c) { |
---|
986 | case 'c': |
---|
987 | hostIP = strdup(optarg); |
---|
988 | break; |
---|
989 | |
---|
990 | case 't': |
---|
991 | nfillers = atoi(optarg); |
---|
992 | if(nfillers < 1) { |
---|
993 | fprintf(stderr, "%s: Need at least 1 reader thread\n", |
---|
994 | prog); |
---|
995 | exit(1); |
---|
996 | } |
---|
997 | break; |
---|
998 | |
---|
999 | case 'b': |
---|
1000 | nbufseach = atoi(optarg); |
---|
1001 | if(nbufseach < 2) { |
---|
1002 | fprintf(stderr, "%s: Need at least 2 buffers per reader thread\n", |
---|
1003 | prog); |
---|
1004 | exit(1); |
---|
1005 | } |
---|
1006 | break; |
---|
1007 | |
---|
1008 | case 'r': |
---|
1009 | readsize = atoi(optarg); |
---|
1010 | if(readsize <= 0 || readsize % getpagesize() != 0) { |
---|
1011 | fprintf(stderr, "%s: readsize must be a multiple of pagesize (%d)\n", |
---|
1012 | prog, getpagesize()); |
---|
1013 | exit(1); |
---|
1014 | } |
---|
1015 | break; |
---|
1016 | |
---|
1017 | case 'p': |
---|
1018 | port = atoi(optarg); /* Not implemented yet */ |
---|
1019 | break; |
---|
1020 | |
---|
1021 | case 'P': |
---|
1022 | preloadms = atoi(optarg); |
---|
1023 | break; |
---|
1024 | |
---|
1025 | case 'M': |
---|
1026 | msfudge = atoi(optarg); |
---|
1027 | break; |
---|
1028 | |
---|
1029 | case 'S': |
---|
1030 | skipby = atoi(optarg); |
---|
1031 | if(skipby <= 0) skipby = 1; |
---|
1032 | break; |
---|
1033 | |
---|
1034 | case 'F': |
---|
1035 | rateoverride = 1; /* and fall into ... */ |
---|
1036 | case 'f': |
---|
1037 | { |
---|
1038 | double v = atof(optarg); |
---|
1039 | if(strchr(optarg, '!')) |
---|
1040 | rateoverride = 1; |
---|
1041 | if(strchr(optarg, 'm')) |
---|
1042 | defaultrate = (int) -v; |
---|
1043 | else if(v>0) |
---|
1044 | defaultrate = (int) v; |
---|
1045 | else { |
---|
1046 | fprintf(stderr, "%s: -f %s: expected frame rate (frames/sec) or frame time in milliseconds (with \"m\" suffix).\n", |
---|
1047 | prog, optarg); |
---|
1048 | exit(1); |
---|
1049 | } |
---|
1050 | } |
---|
1051 | break; |
---|
1052 | |
---|
1053 | case 's': |
---|
1054 | stereo = CROSSEYED; |
---|
1055 | break; |
---|
1056 | |
---|
1057 | case 'm': |
---|
1058 | stereo = MONO; |
---|
1059 | break; |
---|
1060 | |
---|
1061 | case 'q': |
---|
1062 | stereo = QUADBUFFERED; /* Not implemented yet! */ |
---|
1063 | break; |
---|
1064 | |
---|
1065 | case 'R': |
---|
1066 | defaultshift = atoi(optarg); |
---|
1067 | shiftoverride = (strchr(optarg, '!') != NULL); |
---|
1068 | break; |
---|
1069 | |
---|
1070 | case 'L': |
---|
1071 | defaultshift = -atoi(optarg); |
---|
1072 | shiftoverride = (strchr(optarg, '!') != NULL); |
---|
1073 | break; |
---|
1074 | |
---|
1075 | case 'v': |
---|
1076 | verbose++; |
---|
1077 | break; |
---|
1078 | |
---|
1079 | case 'n': |
---|
1080 | nwID = atoi(optarg); |
---|
1081 | break; |
---|
1082 | |
---|
1083 | default: |
---|
1084 | fprintf(stderr, "%s: unknown option -%c\n", prog, c); |
---|
1085 | argc=1; |
---|
1086 | break; |
---|
1087 | } |
---|
1088 | } |
---|
1089 | |
---|
1090 | |
---|
1091 | nplay = argc - optind; |
---|
1092 | playlist = (bpio_t *) calloc( nplay, sizeof(bpio_t) ); |
---|
1093 | mvlist = (bpmvhead_t *) calloc( nplay, sizeof(bpmvhead_t) ); |
---|
1094 | |
---|
1095 | int totalframes=0, frames; |
---|
1096 | for(i = 0; i < nplay; i++) { |
---|
1097 | |
---|
1098 | frames = openmovie( &playlist[i], argv[i+optind], &mvlist[i] ); |
---|
1099 | if( frames < 0 ) { |
---|
1100 | fprintf(stderr, "%s: %s: cannot open: %s\n", |
---|
1101 | prog, argv[i+optind], strerror(errno)); |
---|
1102 | exit(1); |
---|
1103 | } |
---|
1104 | totalframes += frames; |
---|
1105 | } |
---|
1106 | |
---|
1107 | if(nplay <= 0 && port == 0) { |
---|
1108 | fprintf(stderr, Usage, prog, msfudge); |
---|
1109 | exit(1); |
---|
1110 | } |
---|
1111 | |
---|
1112 | // ---------------------------- |
---|
1113 | |
---|
1114 | sageRect hdmovieImageMap; |
---|
1115 | hdmovieImageMap.left = 0.0; |
---|
1116 | hdmovieImageMap.right = 1.0; |
---|
1117 | hdmovieImageMap.bottom = 0.0; |
---|
1118 | hdmovieImageMap.top = 1.0; |
---|
1119 | |
---|
1120 | sailConfig scfg; |
---|
1121 | scfg.init("bitplayer.conf"); |
---|
1122 | scfg.setAppName("bitplayer"); |
---|
1123 | scfg.rank = 0; |
---|
1124 | scfg.totalFrames = totalframes; |
---|
1125 | scfg.asyncUpdate = true; |
---|
1126 | |
---|
1127 | int stereomovie = mvlist[0].flags & BPF_STEREO; |
---|
1128 | if (stereomovie) |
---|
1129 | fprintf(stderr, "It's a Stereo Movie !!!\n"); |
---|
1130 | |
---|
1131 | if (stereomovie && (stereo == MONO)) |
---|
1132 | scfg.resX = mvlist[0].nxtile*mvlist[0].xtile/2; // always in mono |
---|
1133 | else |
---|
1134 | scfg.resX = mvlist[0].nxtile*mvlist[0].xtile; |
---|
1135 | |
---|
1136 | scfg.resY = mvlist[0].nytile*mvlist[0].ytile; |
---|
1137 | scfg.imageMap = hdmovieImageMap; |
---|
1138 | scfg.rowOrd = BOTTOM_TO_TOP; |
---|
1139 | scfg.nwID = nwID; |
---|
1140 | |
---|
1141 | if (stereomovie && (stereo == CROSSEYED)) { |
---|
1142 | scfg.winWidth *= 2; // display it twice as wide as a mono movie |
---|
1143 | } |
---|
1144 | |
---|
1145 | if (mvlist[0].format == RGB565) |
---|
1146 | { |
---|
1147 | scfg.pixFmt = PIXFMT_565; |
---|
1148 | pixelSize = 2; |
---|
1149 | } |
---|
1150 | else |
---|
1151 | if (mvlist[0].format == RGB888) |
---|
1152 | { |
---|
1153 | scfg.pixFmt = PIXFMT_888; |
---|
1154 | pixelSize = 3; |
---|
1155 | } |
---|
1156 | else |
---|
1157 | if (mvlist[0].format == ABGR8888) |
---|
1158 | { |
---|
1159 | scfg.pixFmt = PIXFMT_8888; |
---|
1160 | pixelSize = 4; |
---|
1161 | } |
---|
1162 | else |
---|
1163 | if (mvlist[0].format == COMPRESSDXT1) |
---|
1164 | { |
---|
1165 | scfg.pixFmt = PIXFMT_DXT; |
---|
1166 | pixelSize = 0.5; |
---|
1167 | } |
---|
1168 | else { |
---|
1169 | fprintf(stderr, "format not supported\n"); |
---|
1170 | exit(1); |
---|
1171 | } |
---|
1172 | |
---|
1173 | |
---|
1174 | sageInf.init(scfg); |
---|
1175 | |
---|
1176 | rgbBuffer = (unsigned char *)sageInf.getBuffer(); |
---|
1177 | memset(rgbBuffer, 0, int(scfg.resX*scfg.resY*pixelSize)); |
---|
1178 | |
---|
1179 | std::cout << "sail initialized :" << scfg.resX << "x" << scfg.resY << std::endl; |
---|
1180 | // ---------------------------- |
---|
1181 | |
---|
1182 | curplay = -1; |
---|
1183 | playlistadvance(1); |
---|
1184 | |
---|
1185 | startmovie( doloop ); |
---|
1186 | sageMessage msg; |
---|
1187 | int firstClickTime = 0, dir=0; |
---|
1188 | double fps, t1, t2; |
---|
1189 | |
---|
1190 | while (1) |
---|
1191 | { |
---|
1192 | t1 = sage::getTime(); |
---|
1193 | |
---|
1194 | if(!paused) |
---|
1195 | { |
---|
1196 | redraw(); |
---|
1197 | idler(); |
---|
1198 | } |
---|
1199 | |
---|
1200 | if (sageInf.checkMsg(msg, false) > 0) { |
---|
1201 | char* data = (char*) msg.getData(); |
---|
1202 | |
---|
1203 | switch (msg.getCode()) { |
---|
1204 | case APP_QUIT : { |
---|
1205 | std::cout << "Quit by SAGE" << std::endl; |
---|
1206 | exit(1); |
---|
1207 | break; |
---|
1208 | } |
---|
1209 | case SAGE_EVT_CLICK: { |
---|
1210 | float clickX, clickY; |
---|
1211 | int clickDeviceId, clickButtonId, clickIsDown, clickEvent; |
---|
1212 | |
---|
1213 | // Parse message |
---|
1214 | sscanf(data, "%d %f %f %d %d %d", |
---|
1215 | &clickDeviceId, &clickX, &clickY, |
---|
1216 | &clickButtonId, &clickIsDown, &clickEvent); |
---|
1217 | |
---|
1218 | if(clickIsDown && clickButtonId==1) |
---|
1219 | { |
---|
1220 | if(!paused) |
---|
1221 | pausemovie(); |
---|
1222 | else |
---|
1223 | resumemovie(doloop); |
---|
1224 | } |
---|
1225 | |
---|
1226 | // stop the ff or rewind |
---|
1227 | /*else if(!clickIsDown && clickButtonId==1 && dir!=0) |
---|
1228 | { |
---|
1229 | dir = 0; |
---|
1230 | bpio_t *bpio = &playlist[curplay]; |
---|
1231 | bpforward( bpio, playfwd * skipby ); |
---|
1232 | bpsync( bpio ); |
---|
1233 | resumemovie( doloop ); |
---|
1234 | }*/ |
---|
1235 | |
---|
1236 | break; |
---|
1237 | } |
---|
1238 | /*case SAGE_EVT_PAN: { |
---|
1239 | int panDeviceId; |
---|
1240 | float panX, panY, panDX, panDY, panDZ; |
---|
1241 | sscanf(data, "%d %f %f %f %f %f", |
---|
1242 | &panDeviceId, &panX, &panY, &panDX, &panDY, &panDZ); |
---|
1243 | |
---|
1244 | bpio_t *bpio = &playlist[curplay]; |
---|
1245 | |
---|
1246 | // if we weren't ff or rewinding OR the direction changed... |
---|
1247 | if (dir == 0 || (panDX < 0 && dir > 0) || (panDX > 0 && dir < 0)) |
---|
1248 | { |
---|
1249 | if(panDX < 0) |
---|
1250 | dir = -1; |
---|
1251 | else |
---|
1252 | dir = 1; |
---|
1253 | |
---|
1254 | bpforward( bpio, dir * 15 ); |
---|
1255 | bpsync( bpio ); |
---|
1256 | resumemovie( doloop ); |
---|
1257 | } |
---|
1258 | |
---|
1259 | break; |
---|
1260 | }*/ |
---|
1261 | } |
---|
1262 | } |
---|
1263 | |
---|
1264 | //sage::usleep( (1000/defaultrate)*1000 ); |
---|
1265 | t2 = sage::getTime(); |
---|
1266 | fps = (1000000.0/(t2-t1)); |
---|
1267 | if (fps > defaultrate) { |
---|
1268 | sage::usleep( (1000000.0/defaultrate) - (t2-t1) ); |
---|
1269 | } |
---|
1270 | |
---|
1271 | } |
---|
1272 | |
---|
1273 | |
---|
1274 | return 0; |
---|
1275 | } |
---|