1 /*******************************************************************************
2  lqtplay.c
3 
4  libquicktime - A library for reading and writing quicktime/avi/mp4 files.
5  http://libquicktime.sourceforge.net
6 
7  Copyright (C) 2002 Heroine Virtual Ltd.
8  Copyright (C) 2002-2011 Members of the libquicktime project.
9 
10  This library is free software; you can redistribute it and/or modify it under
11  the terms of the GNU Lesser General Public License as published by the Free
12  Software Foundation; either version 2.1 of the License, or (at your option)
13  any later version.
14 
15  This library is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18  details.
19 
20  You should have received a copy of the GNU Lesser General Public License along
21  with this library; if not, write to the Free Software Foundation, Inc., 51
22  Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *******************************************************************************/
24 
25 /*
26 
27  Simple quicktime movie player.
28 
29  - Gerd Knorr <kraxel@bytesex.org>
30 
31 */
32 
33 
34 #include <quicktime/lqt.h>
35 #include <quicktime/colormodels.h>
36 
37 #include <config.h> // ONLY for the PACKAGE macro. Usually, applications never need
38                     // to include config.h
39 
40 #define _(str) dgettext(PACKAGE, str)
41 
42 #include "common.h"
43 
44 #include <X11/Xlib.h>
45 #include <X11/Intrinsic.h>
46 #include <X11/StringDefs.h>
47 #include <X11/Shell.h>
48 #include <X11/Xaw/Simple.h>
49 #include <X11/extensions/XShm.h>
50 #include <X11/extensions/Xv.h>
51 #include <X11/extensions/Xvlib.h>
52 
53 #ifdef HAVE_GL
54 #include <GL/gl.h>
55 #include <GL/glx.h>
56 #endif
57 
58 #include <sys/types.h>
59 #include <sys/time.h>
60 #include <sys/ipc.h>
61 #include <sys/shm.h>
62 #include <sys/ioctl.h>
63 #ifdef	HAVE_SYS_SOUNDCARD_H
64 #include <sys/soundcard.h>
65 #else
66 #ifdef HAVE_SOUNDCARD_H
67 #include <soundcard.h>
68 #endif
69 #endif
70 #ifdef HAVE_ALSA
71 #include <alsa/asoundlib.h>
72 #endif
73 #ifdef HAVE_SNDIO
74 #include <poll.h>
75 #include <sndio.h>
76 #endif
77 
78 #include <unistd.h>
79 #include <stdlib.h>
80 #include <stdio.h>
81 #include <fcntl.h>
82 #include <time.h>
83 #include <math.h>
84 #include <errno.h>
85 #include <libintl.h>
86 #include <locale.h>
87 
88 /* File handle */
89 
90 static quicktime_t *qt = NULL;
91 
92 #define COUNT_SAMPLES
93 #define DUMP_TIMECODES
94 
95 #ifdef COUNT_SAMPLES
96 int64_t total_samples_decoded = 0;
97 #endif
98 
99 
100 /* ------------------------------------------------------------------------ */
101 /* X11 code                                                                 */
102 
103 static XtAppContext app_context;
104 static Widget       app_shell;
105 static Display      *dpy;
106 static Visual       *visual;
107 static XVisualInfo  vinfo,*vinfo_list;
108 static XPixmapFormatValues *pf;
109 
110 static Widget simple;
111 static Dimension swidth,sheight;
112 
113 static int xv_port      = 0;
114 static int xv_have_YUY2 = 0;
115 static int xv_have_I420 = 0;
116 static int xv_have_YV12 = 0;
117 
118 static int no_mitshm    = 0;
119 static int pixmap_bytes = 0;
120 static int x11_byteswap = 0;
121 
122 #ifdef HAVE_GL
123 static int use_gl       = 0;
124 #endif
125 
126 static int xpos = 0;
127 static int ypos = 0;
128 static int oh_width = 0;
129 
130 static unsigned long   lut_red[256];
131 static unsigned long   lut_green[256];
132 static unsigned long   lut_blue[256];
133 
134 #ifdef DUMP_TIMECODES
135 
136 int has_timecodes = 0;
137 uint32_t timecode_flags;
138 int timecode_rate;
139 
dump_timecode(quicktime_t * file,int track,uint32_t tc)140 static void dump_timecode(quicktime_t * file, int track, uint32_t tc)
141   {
142   int hours, minutes, seconds, frames;
143 
144   if(timecode_flags & LQT_TIMECODE_DROP)
145     {
146     int64_t D, M;
147 
148     D = tc / 17982;
149     M = tc % 17982;
150     tc +=  18*D + 2*((M - 2) / 1798);
151     }
152 
153   frames  = tc % timecode_rate;
154   tc /= timecode_rate;
155 
156  seconds = tc % 60;
157   tc /= 60;
158 
159   minutes = tc % 60;
160   tc /= 60;
161 
162   hours   = tc % 24;
163 
164   printf("Timecode: %02d:%02d:%02d.%02d (0x%08x)\n",
165          hours, minutes, seconds, frames, tc);
166   }
167 
168 #endif
169 
170 /* Video stuff */
171 
172 static int qt_cmodel = BC_RGB888;
173 
174 static int qt_cmodels[] =
175   {
176     BC_RGB888, /* Always supported */
177     /* Placeholders for various YUV formats, set by xv_init */
178     LQT_COLORMODEL_NONE,
179     LQT_COLORMODEL_NONE,
180     LQT_COLORMODEL_NONE,
181   };
182 
183 
184 #define SWAP2(x) (((x>>8) & 0x00ff) |\
185                   ((x<<8) & 0xff00))
186 
187 #define SWAP4(x) (((x>>24) & 0x000000ff) |\
188                   ((x>>8)  & 0x0000ff00) |\
189                   ((x<<8)  & 0x00ff0000) |\
190                   ((x<<24) & 0xff000000))
191 
192 static void
x11_lut(unsigned long red_mask,unsigned long green_mask,unsigned long blue_mask,int bytes,int swap)193 x11_lut(unsigned long red_mask, unsigned long green_mask,
194 	unsigned long blue_mask, int bytes, int swap)
195 {
196     int             rgb_red_bits = 0;
197     int             rgb_red_shift = 0;
198     int             rgb_green_bits = 0;
199     int             rgb_green_shift = 0;
200     int             rgb_blue_bits = 0;
201     int             rgb_blue_shift = 0;
202     unsigned int    i;
203     unsigned int    mask;
204 
205     for (i = 0; i < 32; i++) {
206         mask = (1 << i);
207         if (red_mask & mask)
208             rgb_red_bits++;
209         else if (!rgb_red_bits)
210             rgb_red_shift++;
211         if (green_mask & mask)
212             rgb_green_bits++;
213         else if (!rgb_green_bits)
214             rgb_green_shift++;
215         if (blue_mask & mask)
216             rgb_blue_bits++;
217         else if (!rgb_blue_bits)
218             rgb_blue_shift++;
219     }
220     if (rgb_red_bits > 8)
221 	for (i = 0; i < 256; i++)
222 	    lut_red[i] = (i << (rgb_red_bits + rgb_red_shift - 8));
223     else
224 	for (i = 0; i < 256; i++)
225 	    lut_red[i] = (i >> (8 - rgb_red_bits)) << rgb_red_shift;
226     if (rgb_green_bits > 8)
227 	for (i = 0; i < 256; i++)
228 	    lut_green[i] = (i << (rgb_green_bits + rgb_green_shift - 8));
229     else
230 	for (i = 0; i < 256; i++)
231 	    lut_green[i] = (i >> (8 - rgb_green_bits)) << rgb_green_shift;
232     if (rgb_blue_bits > 8)
233 	for (i = 0; i < 256; i++)
234 	    lut_blue[i] = (i << (rgb_blue_bits + rgb_blue_shift - 8));
235     else
236 	for (i = 0; i < 256; i++)
237 	    lut_blue[i] = (i >> (8 - rgb_blue_bits)) << rgb_blue_shift;
238 
239     if (2 == bytes && swap) {
240 	for (i = 0; i < 256; i++) {
241 	    lut_red[i] = SWAP2(lut_red[i]);
242 	    lut_green[i] = SWAP2(lut_green[i]);
243 	    lut_blue[i] = SWAP2(lut_blue[i]);
244 	}
245     }
246     if (4 == bytes && swap) {
247 	for (i = 0; i < 256; i++) {
248 	    lut_red[i] = SWAP4(lut_red[i]);
249 	    lut_green[i] = SWAP4(lut_green[i]);
250 	    lut_blue[i] = SWAP4(lut_blue[i]);
251 	}
252     }
253 }
254 
255 static void
rgb_to_lut2(unsigned char * dest,unsigned char * src,int p)256 rgb_to_lut2(unsigned char *dest, unsigned char *src, int p)
257 {
258     unsigned short *d = (unsigned short*)dest;
259 
260     while (p-- > 0) {
261 	*(d++) = lut_red[src[0]] | lut_green[src[1]] | lut_blue[src[2]];
262 	src += 3;
263     }
264 }
265 
266 static void
rgb_to_lut4(unsigned char * dest,unsigned char * src,int p)267 rgb_to_lut4(unsigned char *dest, unsigned char *src, int p)
268 {
269     unsigned int *d = (unsigned int*)dest;
270 
271     while (p-- > 0) {
272 	*(d++) = lut_red[src[0]] | lut_green[src[1]] | lut_blue[src[2]];
273 	src += 3;
274     }
275 }
276 
x11_init(void)277 static void x11_init(void)
278 {
279     int i,n;
280 
281     /* get visual info */
282     visual = DefaultVisualOfScreen(XtScreen(app_shell));
283     vinfo.visualid = XVisualIDFromVisual(visual);
284     vinfo_list = XGetVisualInfo(dpy, VisualIDMask, &vinfo, &n);
285     vinfo = vinfo_list[0];
286     if (vinfo.class != TrueColor || vinfo.depth < 15) {
287 	fprintf(stderr,_("can't handle visuals != TrueColor, sorry\n"));
288 	exit(1);
289     }
290 
291     /* look for default pixmap format */
292     pf = XListPixmapFormats(dpy,&n);
293     for (i = 0; i < n; i++)
294 	if (pf[i].depth == vinfo.depth)
295 	    pixmap_bytes = pf[i].bits_per_pixel/8;
296 
297     /* byteswapping needed ??? */
298 #ifdef WORDS_BIGENDIAN
299     if (ImageByteOrder(dpy)==LSBFirst)
300 	x11_byteswap=1;
301 #else
302     if (ImageByteOrder(dpy)==MSBFirst)
303 	x11_byteswap=1;
304 #endif
305 
306     /* init lookup tables */
307     x11_lut(vinfo.red_mask, vinfo.green_mask, vinfo.blue_mask,
308 	    pixmap_bytes,x11_byteswap);
309 }
310 
xv_init(void)311 static void xv_init(void)
312 {
313     int cmodel_index;
314     unsigned int ver, rel, req, ev, err;
315     int i;
316     unsigned int adaptors;
317     int formats;
318     XvAdaptorInfo        *ai;
319     XvImageFormatValues  *fo;
320 
321     if (Success != XvQueryExtension(dpy,&ver,&rel,&req,&ev,&err))
322 	return;
323 
324     /* find + lock port */
325     if (Success != XvQueryAdaptors(dpy,DefaultRootWindow(dpy),&adaptors,&ai))
326 	return;
327     for (i = 0; i < adaptors; i++) {
328 	if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask)) {
329 	    if (Success != XvGrabPort(dpy,ai[i].base_id,CurrentTime)) {
330 		fprintf(stderr,_("INFO: Xvideo port %ld: is busy, skipping\n"),
331 			ai[i].base_id);
332 		continue;
333 	    }
334 	    xv_port = ai[i].base_id;
335 	    break;
336 	}
337     }
338     if (0 == xv_port)
339 	return;
340 
341     /* check image formats */
342     fo = XvListImageFormats(dpy, xv_port, &formats);
343     for(i = 0; i < formats; i++) {
344 	fprintf(stderr, _("INFO: Xvideo port %d: 0x%x (%c%c%c%c) %s"),
345 		xv_port,
346 		fo[i].id,
347 		(fo[i].id)       & 0xff,
348 		(fo[i].id >>  8) & 0xff,
349 		(fo[i].id >> 16) & 0xff,
350 		(fo[i].id >> 24) & 0xff,
351 		(fo[i].format == XvPacked) ? "packed" : "planar");
352 	if (FOURCC_YUV2 == fo[i].id) {
353 	    fprintf(stderr," [BC_YUV422]");
354 	    xv_have_YUY2 = 1;
355 	}
356         if (FOURCC_YV12 == fo[i].id) {
357             fprintf(stderr," [BC_YUV420P]");
358             xv_have_YV12 = 1;
359         }
360 	if (FOURCC_I420 == fo[i].id) {
361 	    fprintf(stderr," [BC_YUV420P]");
362             xv_have_I420 = 1;
363 	}
364 	fprintf(stderr,"\n");
365     }
366 
367     /* Fill the cmodel array */
368     cmodel_index = 1;
369     if(xv_have_YUY2)
370       qt_cmodels[cmodel_index++] = BC_YUV422;
371     if(xv_have_YV12 || xv_have_I420)
372       qt_cmodels[cmodel_index++] = BC_YUV420P;
373 
374 }
375 
376 static int
catch_no_mitshm(Display * dpy,XErrorEvent * event)377 catch_no_mitshm(Display * dpy, XErrorEvent * event)
378 {
379     no_mitshm++;
380     return 0;
381 }
382 
383 static XImage*
x11_create_ximage(Display * dpy,int width,int height)384 x11_create_ximage(Display *dpy, int width, int height)
385 {
386     XImage          *ximage = NULL;
387     char   *ximage_data;
388     XShmSegmentInfo *shminfo = NULL;
389     void            *old_handler;
390 
391     if (no_mitshm)
392 	goto no_mitshm;
393 
394     old_handler = XSetErrorHandler(catch_no_mitshm);
395     shminfo = malloc(sizeof(XShmSegmentInfo));
396     memset(shminfo, 0, sizeof(XShmSegmentInfo));
397     ximage = XShmCreateImage(dpy,vinfo.visual,vinfo.depth,
398 			     ZPixmap, NULL,
399 			     shminfo, width, height);
400     if (NULL == ximage)
401 	goto shm_error;
402     shminfo->shmid = shmget(IPC_PRIVATE,
403 			    ximage->bytes_per_line * ximage->height,
404 			    IPC_CREAT | 0777);
405     if (-1 == shminfo->shmid) {
406 	perror("shmget");
407 	goto shm_error;
408     }
409     shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
410     if ((void *)-1 == shminfo->shmaddr) {
411 	perror("shmat");
412 	goto shm_error;
413     }
414     ximage->data = shminfo->shmaddr;
415     shminfo->readOnly = False;
416 
417     XShmAttach(dpy, shminfo);
418     XSync(dpy, False);
419     if (no_mitshm)
420 	goto shm_error;
421     shmctl(shminfo->shmid, IPC_RMID, 0);
422     XSetErrorHandler(old_handler);
423     return ximage;
424 
425 shm_error:
426     if (ximage) {
427 	XDestroyImage(ximage);
428 	ximage = NULL;
429     }
430     if ((void *)-1 != shminfo->shmaddr  &&  NULL != shminfo->shmaddr)
431 	shmdt(shminfo->shmaddr);
432     free(shminfo);
433     XSetErrorHandler(old_handler);
434     no_mitshm = 1;
435 
436  no_mitshm:
437     if (NULL == (ximage_data = malloc(width * height * pixmap_bytes))) {
438 	fprintf(stderr,_("out of memory\n"));
439 	exit(1);
440     }
441     ximage = XCreateImage(dpy, vinfo.visual, vinfo.depth,
442 			  ZPixmap, 0, ximage_data,
443 			  width, height,
444 			  8, 0);
445     memset(ximage->data, 0, ximage->bytes_per_line * ximage->height);
446     return ximage;
447 }
448 
449 static XvImage*
xv_create_ximage(Display * dpy,int width,int height,int port,int format)450 xv_create_ximage(Display *dpy, int width, int height, int port, int format)
451 {
452     XvImage         *xvimage = NULL;
453     char   *ximage_data;
454     XShmSegmentInfo *shminfo = NULL;
455     void            *old_handler;
456 
457     if (no_mitshm)
458 	goto no_mitshm;
459 
460     old_handler = XSetErrorHandler(catch_no_mitshm);
461     shminfo = malloc(sizeof(XShmSegmentInfo));
462     memset(shminfo, 0, sizeof(XShmSegmentInfo));
463     xvimage = XvShmCreateImage(dpy, port, format, 0,
464 			       width, height, shminfo);
465     if (NULL == xvimage)
466 	goto shm_error;
467     shminfo->shmid = shmget(IPC_PRIVATE, xvimage->data_size,
468 			    IPC_CREAT | 0777);
469     if (-1 == shminfo->shmid) {
470 	perror("shmget");
471 	goto shm_error;
472     }
473     shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
474     if ((void *)-1 == shminfo->shmaddr) {
475 	perror("shmat");
476 	goto shm_error;
477     }
478     xvimage->data = shminfo->shmaddr;
479     shminfo->readOnly = False;
480 
481     XShmAttach(dpy, shminfo);
482     XSync(dpy, False);
483     if (no_mitshm)
484 	goto shm_error;
485     shmctl(shminfo->shmid, IPC_RMID, 0);
486     XSetErrorHandler(old_handler);
487     return xvimage;
488 
489 shm_error:
490     if (xvimage) {
491 	XFree(xvimage);
492 	xvimage = NULL;
493     }
494     if ((void *)-1 != shminfo->shmaddr  &&  NULL != shminfo->shmaddr)
495 	shmdt(shminfo->shmaddr);
496     free(shminfo);
497     XSetErrorHandler(old_handler);
498     no_mitshm = 1;
499 
500  no_mitshm:
501     if (NULL == (ximage_data = malloc(width * height * 2))) {
502 	fprintf(stderr,_("out of memory\n"));
503 	exit(1);
504     }
505     xvimage = XvCreateImage(dpy, port, format, ximage_data,
506 			    width, height);
507     return xvimage;
508 }
509 
x11_blit(Window win,GC gc,XImage * xi,int width,int height)510 static void x11_blit(Window win, GC gc, XImage *xi, int width, int height)
511 {
512     if (no_mitshm)
513 	XPutImage(dpy,win,gc,xi, 0,0,0,0, width,height);
514     else
515 	XShmPutImage(dpy,win,gc,xi, 0,0,0,0, width,height, True);
516 }
517 
xv_blit(Window win,GC gc,XvImage * xi,int iw,int ih,int ww,int wh)518 static void xv_blit(Window win, GC gc, XvImage *xi,
519 		    int iw, int ih, int ww, int wh)
520 {
521     if (no_mitshm)
522 	XvPutImage(dpy,xv_port,win,gc,xi, 0,0,iw,ih, 0,0,ww,wh);
523     else
524 	XvShmPutImage(dpy,xv_port,win,gc,xi, 0,0,iw,ih, 0,0,ww,wh, True);
525 }
526 
527 /* ------------------------------------------------------------------------ */
528 /* OpenGL code                                                              */
529 #ifdef HAVE_GL
530 static int gl_texture_width,gl_texture_height;
531 static GLuint gl_texture;
532 static int gl_attrib[] = { GLX_RGBA,
533                            GLX_RED_SIZE, 8,
534                            GLX_GREEN_SIZE, 8,
535                            GLX_BLUE_SIZE, 8,
536                            GLX_DEPTH_SIZE, 8,
537 			   GLX_DOUBLEBUFFER,
538 			   None };
539 
gl_resize(Widget widget,int width,int height)540 static void gl_resize(Widget widget, int width, int height)
541 {
542     glViewport(0, 0, width, height);
543     glMatrixMode(GL_PROJECTION);
544     glLoadIdentity();
545     glOrtho(0.0, width, 0.0, height, -1.0, 1.0);
546     glMatrixMode(GL_MODELVIEW);
547     glLoadIdentity();
548 
549 }
550 
gl_blit(Widget widget,uint8_t * rgbbuf,int iw,int ih,int ww,int wh)551 static void gl_blit(Widget widget, uint8_t *rgbbuf,
552 		    int iw, int ih, int ww, int wh)
553 {
554     char *dummy;
555     float x,y;
556 
557     if (0 == gl_texture) {
558 	glGenTextures(1,&gl_texture);
559 	glBindTexture(GL_TEXTURE_2D,gl_texture);
560 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
561 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
562 	dummy = malloc(gl_texture_width*gl_texture_height*3);
563 	memset(dummy,128,gl_texture_width*gl_texture_height*3);
564 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,gl_texture_width,
565                      gl_texture_height,0,
566 		     GL_RGB,GL_UNSIGNED_BYTE,dummy);
567 	free(dummy);
568     }
569     glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0,iw,ih,
570 		    GL_RGB,GL_UNSIGNED_BYTE,rgbbuf);
571     x = (float)iw/gl_texture_width;
572     y = (float)ih/gl_texture_height;
573 
574     glEnable(GL_TEXTURE_2D);
575     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
576     glBegin(GL_QUADS);
577     glTexCoord2f(0,y);  glVertex3f(0,0,0);
578     glTexCoord2f(0,0);  glVertex3f(0,wh,0);
579     glTexCoord2f(x,0);  glVertex3f(ww,wh,0);
580     glTexCoord2f(x,y);  glVertex3f(ww,0,0);
581     glEnd();
582     glXSwapBuffers(XtDisplay(widget), XtWindow(widget));
583     glDisable(GL_TEXTURE_2D);
584 }
585 
gl_init(Widget widget,int iw,int ih)586 static void gl_init(Widget widget, int iw, int ih)
587 {
588     XVisualInfo *visinfo;
589     GLXContext ctx;
590     int i = 0;
591 
592     visinfo = glXChooseVisual(XtDisplay(widget),
593 			      DefaultScreen(XtDisplay(widget)),
594 			      gl_attrib);
595     if (!visinfo) {
596 	fprintf(stderr,_("WARNING: gl: can't get visual (rgb,db)\n"));
597 	return;
598     }
599     ctx = glXCreateContext(dpy, visinfo, NULL, True);
600     glXMakeCurrent(XtDisplay(widget),XtWindow(widget),ctx);
601     fprintf(stderr, _("INFO: gl: DRI=%s\n"),
602 	    glXIsDirect(dpy, ctx) ? _("Yes") : _("No"));
603     if (!glXIsDirect(dpy, ctx)) {
604         fprintf(stderr, _("WARNING: gl: Direct rendering missing\n"));
605         return;
606     }
607 #if 0
608     /* check against max size */
609     glGetIntegerv(GL_MAX_TEXTURE_SIZE,&i);
610     fprintf(stderr,_("INFO: gl: texture max size: %d\n"),i);
611     if ((iw > i) || (ih > i))
612         {
613         fprintf(stderr, _("WARNING: gl: Maximum texture size too small (got %dx%d, needed %dx%d)\n"),
614                 i, i, iw, ih);
615         return;
616         }
617 #endif
618     /* textures have power-of-two x,y dimensions */
619     for (i = 0; iw >= (1 << i); i++)
620 	;
621     gl_texture_width = (1 << i);
622     for (i = 0; ih >= (1 << i); i++)
623 	;
624     gl_texture_height = (1 << i);
625     fprintf(stderr,_("INFO: gl: frame=%dx%d, texture=%dx%d\n"),iw,ih,
626             gl_texture_width,gl_texture_height);
627 
628     glClearColor (0.0, 0.0, 0.0, 0.0);
629     glShadeModel(GL_FLAT);
630     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
631     use_gl = 1;
632 }
633 
634 #endif // HAVE_GL
635 
636 static int oss_sr,oss_hr;
637 
638 
639 
640 /* ------------------------------------------------------------------------ */
641 /* alsa code                                                                 */
642 
643 #ifdef HAVE_ALSA
644 
645 /* Enable alsa */
646 static int use_alsa = 1;
647 
648 #ifndef SND_PCM_FORMAT_S16_NE
649 # ifdef WORDS_BIGENDIAN
650 #  define SND_PCM_FORMAT_S16_NE SND_PCM_FORMAT_S16_BE
651 # else
652 #  define SND_PCM_FORMAT_S16_NE SND_PCM_FORMAT_S16_LE
653 # endif
654 #endif
655 
656 //static int periods = 32; /* number of periods == fragments */
657 static snd_pcm_uframes_t periodsize = 1024; /* Periodsize (bytes) */
658 static unsigned int buffer_time = 500000;
659 static unsigned int period_time = 125000;              /* period time in us */
660 
661 /* Handle for the PCM device */
662 static snd_pcm_t *pcm_handle;
663 
664 /* This structure contains information about    */
665 /* the hardware and can be used to specify the  */
666 /* configuration to be used for the PCM stream. */
667 static snd_pcm_hw_params_t *hwparams;
668 snd_pcm_uframes_t buffer_size;
669 
670 #else
671 
672 /* Disable Alsa */
673 static int use_alsa = 0;
674 
675 #endif /* HAVE_ALSA */
676 
alsa_init(char * dev,int channels,int rate)677 static int alsa_init(char *dev, int channels, int rate)
678 {
679 #ifdef HAVE_ALSA
680     int dir;
681     //    int exact_param;   /* parameter returned by          */
682                        /* snd_pcm_hw_params_set_*_near   */
683     unsigned int tmprate;
684     int err = 0;
685     tmprate = rate;
686     oss_hr = rate;
687     if (snd_pcm_open(&pcm_handle, dev, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) {
688 	fprintf(stderr, _("Error opening PCM device %s\n"), dev);
689 	return 1;
690     }
691 #if 1
692     /* Allocate the snd_pcm_hw_params_t structure on the stack. */
693     snd_pcm_hw_params_alloca(&hwparams);
694 
695     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
696 	fprintf(stderr, _("Can not configure this PCM device. (%s)\n"), snd_strerror(err));
697 	return 1;
698     }
699 
700     if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
701 	fprintf(stderr, _("Error setting access. (%s)\n"), snd_strerror(err));
702 	return 1;
703     }
704 
705     /* put checks here */
706     /* Only needed when sampling format not supported by hardware .. unlikely */
707 
708     /* Set sample format */
709     if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams,  SND_PCM_FORMAT_S16_NE)) < 0) {
710 	fprintf(stderr, _("Error setting format.(%s)\n"), snd_strerror(err));
711 	return 1;
712     }
713 
714     /* Set number of channels */ // weird 1 channel mode doesn't work
715     if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels)) < 0) {
716 	fprintf(stderr, _("Error setting channels. %i (%s)\n"), channels, snd_strerror(err));
717 	return 1;
718     }
719 
720     /* Let Alsa resample */
721     snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 1);
722 
723     /* Set sample rate. If the exact rate is not supported */
724     /* by the hardware, use nearest possible rate.         */
725 #if 1
726     if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &tmprate, NULL)) < 0 ) {
727 	fprintf(stderr, _("Error setting sample rate (%s)\n"), snd_strerror(err));
728 	return 1;
729     }
730 #else
731 
732     if ((err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, tmprate, 0)) < 0 ) {
733 	fprintf(stderr, _("Error setting sample rate (%s)\n"), snd_strerror(err));
734 	return 1;
735     }
736 #endif
737     if (tmprate != rate) fprintf(stderr,_("WARNING: Using %i Hz instead of requested rate %i Hz\n "), tmprate, rate);
738     oss_sr = tmprate;
739     dir = 0;
740     if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffer_time, &dir)) < 0) {
741 	printf("Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
742 	return 1;
743     }
744 
745     /* period time */
746     dir = 0;
747     if ((err = snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &period_time, &dir)) < 0) {
748 	fprintf(stderr, _("Error setting periods.(%s)\n"), snd_strerror(err));
749 	return 1;
750     }
751 
752 
753     if ((err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size))< 0) {
754                 fprintf(stderr, _("Unable to get buffer size for playback: %s\n"), snd_strerror(err));
755                 return 1;
756     }
757 
758     dir = 0;
759     err = snd_pcm_hw_params_get_period_size(hwparams, &periodsize, &dir);
760     if (err < 0) {
761                 fprintf(stderr, _("Unable to get period size for playback: %s\n"), snd_strerror(err));
762                 return 1;
763     }
764 
765     /* Apply HW parameter settings to */
766     /* PCM device and prepare device  */
767     if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
768 	fprintf(stderr, _("Error setting HW params.(%s)\n"), snd_strerror(err));
769 	return 1;
770     }
771 #else /* Simple pcm */
772     snd_spcm_init(pcm_handle,
773                   rate,
774                   channels,
775                   SND_PCM_FORMAT_S16_NE,
776                   SND_PCM_SUBFORMAT_STD,
777                   SND_SPCM_LATENCY_STANDARD,
778                   SND_PCM_ACCESS_RW_INTERLEAVED,
779                   SND_SPCM_XRUN_IGNORE);
780 
781 #endif
782 
783     if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
784 	fprintf(stderr, _("Error in pcm_prepare.(%s)\n"), snd_strerror(err));
785 	return 1;
786     }
787 
788 #endif
789 
790 return 0;
791 }
792 
793 
794 
795 /* ------------------------------------------------------------------------ */
796 /* sndio code                                                                 */
797 
798 #ifdef HAVE_SNDIO
799 
800 static struct sio_hdl *hdl;
801 static struct sio_par par;
802 
803 static int use_sndio = 1;
804 
805 static int oss_sr,oss_hr;
806 
807 #else
808 
809 /* Disable sndio */
810 static int use_sndio = 0;
811 
812 #endif /* HAVE_SNDIO */
813 
814 static int
sndio_setformat(int chan,int rate)815 sndio_setformat(int chan, int rate)
816 {
817 #ifdef HAVE_SNDIO
818     sio_initpar(&par);
819     par.bits = 16;
820     par.sig = 1;
821     par.rate = rate;
822     par.pchan = chan;
823     /* yes, lqtplay wants really small blocks */
824     par.round = rate / 100;
825     par.appbufsz = par.round * 25;
826 
827     if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) {
828 	fprintf(stderr,_("ERROR: can't set sound format\n"));
829 	exit(1);
830     }
831 
832     if (par.pchan != chan || par.bits != 16 || par.sig != 1 ||
833       par.le != SIO_LE_NATIVE) {
834 	fprintf(stderr,_("ERROR: can't set requested sound format\n"));
835 	exit(1);
836     }
837 
838     if (par.rate != rate) {
839         oss_sr = rate;
840 	oss_hr = par.rate;
841 	fprintf(stderr,_("WARNING: sample rate mismatch (need %d, got %d)\n"),
842 		rate, par.rate);
843     }
844 
845     return 0;
846 #else
847     return 1;
848 #endif
849 }
850 
sndio_init(char * dev,int channels,int rate)851 static int sndio_init(char *dev, int channels, int rate)
852 {
853 #ifdef HAVE_SNDIO
854     hdl = sio_open(NULL, SIO_PLAY, 1);
855     if (NULL == hdl) {
856 	fprintf(stderr,_("ERROR: can't open sndio\n"));
857 	return -1;
858     }
859     sndio_setformat(channels,rate);
860 
861     if (!sio_start(hdl)) {
862         fprintf(stderr,_("ERROR: can't start sndio\n"));
863         return -1;
864     }
865     return 0;
866 #else
867     return 1;
868 #endif
869 }
870 
871 
872 
873 /* ------------------------------------------------------------------------ */
874 /* oss code                                                                 */
875 
876 #ifndef AFMT_S16_NE
877 # ifdef WORDS_BIGENDIAN
878 #  define AFMT_S16_NE AFMT_S16_BE
879 # else
880 #  define AFMT_S16_NE AFMT_S16_LE
881 # endif
882 #endif
883 
884 static int oss_fd = -1;
885 static int oss_sr,oss_hr;
886 
887 static int
oss_setformat(int chan,int rate)888 oss_setformat(int chan, int rate)
889 {
890 #ifdef	SNDCTL_DSP_SETFMT
891     int hw_afmt = AFMT_S16_NE;
892     int hw_chan = chan;
893     int hw_rate = rate;
894 
895     ioctl(oss_fd, SNDCTL_DSP_SETFMT, &hw_afmt);
896     if (AFMT_S16_LE != hw_afmt) {
897 	fprintf(stderr,_("ERROR: can't set sound format\n"));
898 	exit(1);
899     }
900     ioctl(oss_fd, SNDCTL_DSP_CHANNELS, &hw_chan);
901     if (chan != hw_chan) {
902 	fprintf(stderr,_("ERROR: can't set sound channels\n"));
903 	exit(1);
904     }
905     ioctl(oss_fd, SNDCTL_DSP_SPEED, &hw_rate);
906     if (rate != hw_rate) {
907 	oss_sr = rate;
908 	oss_hr = hw_rate;
909 	fprintf(stderr,_("WARNING: sample rate mismatch (need %d, got %d)\n"),
910 		rate,hw_rate);
911     }
912     return 0;
913 #else
914     return 1;
915 #endif
916 }
917 
oss_init(char * dev,int channels,int rate)918 static int oss_init(char *dev, int channels, int rate)
919 {
920 #ifdef	SNDCTL_DSP_SETTRIGGER
921     int trigger;
922 #endif
923 
924     oss_fd = open(dev,O_WRONLY | O_NONBLOCK);
925     if (-1 == oss_fd) {
926 	fprintf(stderr,_("WARNING: open %s: %s\n"),dev,strerror(errno));
927 	return -1;
928     }
929     oss_setformat(channels,rate);
930 #ifdef	SNDCTL_DSP_SETTRIGGER
931     trigger = PCM_ENABLE_OUTPUT;
932     ioctl(oss_fd,SNDCTL_DSP_SETTRIGGER,&trigger);
933     return 0;
934 #else
935     return 1;
936 #endif
937 }
938 
939 /* ------------------------------------------------------------------------ */
940 /* quicktime code                                                           */
941 
942 /* Audio stuff */
943 
944 /* Interleaved audio buffer */
945 static int16_t *qt_audio = (int16_t*)0;    //,*qt1,*qt2;
946 static int16_t *qt_audio_ptr; /* Pointer to the sample buffer for the next write() call */
947 
948 static int qt_audio_samples_in_buffer;
949 
950 /* Non interleaved audio buffer */
951 static int16_t **qt_audion = (int16_t**)0;
952 
953 /* One decode call will decode this many samples */
954 
955 #define AUDIO_BLOCK_SIZE (10*1024)
956 
957 static int qt_channels,qt_sample_rate;
958 static int qt_audio_eof = 0; /* No more samples can be decoded */
959 
960 static int qt_hasvideo,qt_hasaudio,qt_isqtvr;
961 
962 static int qt_width = 320, qt_height = 32, qt_drop = 0, qt_droptotal = 0, qtvr_dwidth = 0, qtvr_dheight = 0;
963 static int64_t qt_frame_time; /* Timestamp of the decoded frame */
964 static int qt_timescale = 0;
965 
966 static unsigned char *qt_frame, *qt_frame_row, **qt_rows;
967 static unsigned char *qt_panorama_buffer;
968 static unsigned int *qt_frame_tmp[2];
969 static XImage *qt_ximage;
970 static XvImage *qt_xvimage;
971 static GC qt_gc;
972 
973 
qt_init(FILE * fp,char * filename)974 static void qt_init(FILE *fp, char *filename)
975 {
976     int ipos;
977     float minpan, maxpan;
978     /* audio device */
979     char *adev_name;
980 
981     /* default */
982     //    adev_name = strdup("plughw");
983     //adev_name = strdup("plughw:0,0");
984     adev_name = strdup("default");
985 
986     /* open file */
987     qt = quicktime_open(filename,1,0);
988     if (NULL == qt) {
989 	fprintf(fp,_("ERROR: can't open file: %s\n"),filename);
990 	exit(1);
991     }
992 
993     /* print misc info */
994     fprintf(fp,_("INFO: playing %s\n"),filename);
995 
996     quicktime_print_info(qt);
997 
998     qt_isqtvr = lqt_is_qtvr(qt);
999     if (qt_isqtvr) {
1000 	if (qt_isqtvr != QTVR_OBJ && qt_isqtvr != QTVR_PAN) {
1001 	    fprintf(stderr, _("'%s' is no QTVR file or an unsupported variant.\n"), filename);
1002 	    exit(1);
1003 	}
1004 
1005 	ipos = lqt_qtvr_get_initial_position(qt);
1006 	lqt_qtvr_get_pan(qt, &(minpan), &(maxpan), NULL);
1007 	qtvr_dwidth = lqt_qtvr_get_display_width(qt);
1008 	qtvr_dheight = lqt_qtvr_get_display_height(qt);
1009 	fprintf(stderr, _("startpos :%i\n"), ipos);
1010 	fprintf(stderr, _("movietype :%i\n"), lqt_qtvr_get_movietype(qt));
1011 	fprintf(stderr, _("panning :%f %f\n"), minpan, maxpan);
1012 	fprintf(stderr, _("rows :%i\n"), lqt_qtvr_get_rows(qt));
1013 	fprintf(stderr, _("colums :%i\n"), lqt_qtvr_get_columns(qt));
1014 	fprintf(stderr, _("disp width :%i\n"), qtvr_dwidth);
1015 	fprintf(stderr, _("disp height :%i\n"), qtvr_dheight);
1016 	fprintf(stderr, _("width :%i\n"), lqt_qtvr_get_width(qt));
1017 	fprintf(stderr, _("height :%i\n"), lqt_qtvr_get_height(qt));
1018 	fprintf(stderr, _("depth :%i\n"), lqt_qtvr_get_depth(qt));
1019 
1020 	if (qt_isqtvr == QTVR_PAN) {
1021 		oh_width = lqt_qtvr_get_height(qt) * qtvr_dwidth / (float)qtvr_dheight;
1022 		if (lqt_qtvr_get_panotype(qt) == QTVR_PANO_VERT) {
1023 			oh_width = floor(oh_width / (float)quicktime_video_height(qt, 0) + 1) *
1024 							  quicktime_video_height(qt, 0);
1025 		} else if (lqt_qtvr_get_panotype(qt) == QTVR_PANO_HORZ) {
1026 			oh_width = floor(oh_width / (float)quicktime_video_width(qt, 0) + 1) *
1027 							  quicktime_video_width(qt, 0);
1028 		}
1029 		fprintf(stderr, _("oh_width verz :%i\n"),oh_width);
1030 
1031 	}
1032     }
1033     /* sanity checks */
1034     if (!quicktime_has_video(qt)) {
1035 	fprintf(stderr,_("WARNING: no video stream\n"));
1036     } else if (!quicktime_supported_video(qt,0)) {
1037 	fprintf(stderr,_("WARNING: unsupported video codec\n"));
1038     } else {
1039 	qt_hasvideo = 1;
1040 	qt_width  = quicktime_video_width(qt,0);
1041 	qt_height = quicktime_video_height(qt,0);
1042         qt_timescale = lqt_video_time_scale(qt,0);
1043 #ifdef DUMP_TIMECODES
1044         has_timecodes = lqt_has_timecode_track(qt, 0, &timecode_flags, &timecode_rate);
1045 #endif
1046         fprintf(stderr, _("Timescale: %d\n"), qt_timescale);
1047     }
1048 
1049     if (!quicktime_has_audio(qt)) {
1050 	fprintf(stderr,_("WARNING: no audio stream\n"));
1051     } else if (!quicktime_supported_audio(qt,0)) {
1052 	fprintf(stderr,_("WARNING: unsupported audio codec\n"));
1053     } else {
1054 	qt_hasaudio = 1;
1055 	qt_channels = quicktime_track_channels(qt,0);
1056         qt_sample_rate = quicktime_sample_rate(qt,0);
1057   if (use_alsa == 1) {
1058     if (-1 == alsa_init(adev_name, qt_channels,
1059          qt_sample_rate)) {
1060            qt_hasaudio = 0;}
1061   } else if (use_sndio == 1) {
1062     if (-1 == sndio_init(adev_name, qt_channels,
1063          qt_sample_rate)) {
1064            qt_hasaudio = 0;}
1065   }
1066   else {
1067   	if (-1 == oss_init("/dev/dsp", qt_channels,
1068                            qt_sample_rate))
1069            qt_hasaudio = 0;
1070   }
1071   }
1072     if (0 == qt_hasvideo && 0 == qt_hasaudio) {
1073 	fprintf(stderr,_("ERROR: no playable stream found\n"));
1074 	exit(1);
1075     }
1076 }
1077 
qt_cleanup()1078 static void qt_cleanup()
1079   {
1080   if(qt)
1081     quicktime_close(qt);
1082   }
1083 
qt_init_video(void)1084 static int qt_init_video(void)
1085 {
1086         int i;
1087         /* init */
1088 
1089 	qt_rows = malloc(qt_height * sizeof(char*));
1090 	if (qt_isqtvr == QTVR_PAN) {
1091 	    qt_frame_row = malloc(qtvr_dwidth * 3);
1092 	    qt_frame = malloc(qtvr_dwidth * qtvr_dheight * 3);
1093         if (lqt_qtvr_get_panotype(qt) == QTVR_PANO_VERT) {
1094             qt_frame_tmp[0] = malloc(sizeof(int) * qtvr_dwidth * qt_width);
1095             qt_frame_tmp[1] = malloc(sizeof(int) * qtvr_dwidth * qt_width);
1096 
1097         } else {
1098             qt_frame_tmp[0] = malloc(sizeof(int) * qtvr_dwidth * qt_height);
1099             qt_frame_tmp[1] = malloc(sizeof(int) * qtvr_dwidth * qt_height);
1100         }
1101 		qt_panorama_buffer = malloc((lqt_qtvr_get_width(qt)+oh_width)*
1102 					 lqt_qtvr_get_height(qt)*
1103 					 3);
1104 	}
1105 	else
1106 	    qt_frame = malloc(qt_width * qt_height * 4);
1107 
1108 
1109 	qt_gc = XCreateGC(dpy,XtWindow(simple),0,NULL);
1110 	switch (qt_cmodel) {
1111 	case BC_RGB888:
1112 #ifdef HAVE_GL
1113           fprintf(stderr,_("INFO: using BC_RGB888 + %s\n"),
1114 		    use_gl ? _("OpenGL") : _("plain X11"));
1115 #else
1116           fprintf(stderr,_("INFO: using BC_RGB888 + %s\n"),
1117 		    _("plain X11"));
1118 #endif
1119 	    if (qt_isqtvr == QTVR_PAN) {
1120 		qt_ximage = x11_create_ximage(dpy,qtvr_dwidth,qtvr_dheight);
1121 	    }
1122 	    else
1123 		qt_ximage = x11_create_ximage(dpy,qt_width,qt_height);
1124 
1125 	    for (i = 0; i < qt_height; i++)
1126 		qt_rows[i] = qt_frame + qt_width * 3 * i;
1127 	    break;
1128 	case BC_YUV422:
1129 	    fprintf(stderr,_("INFO: using BC_YUV422 + Xvideo extension\n"));
1130 	    qt_xvimage = xv_create_ximage(dpy,qt_width,qt_height,
1131 					  xv_port,FOURCC_YUV2);
1132 	    for (i = 0; i < qt_height; i++)
1133               qt_rows[i] = (uint8_t*)(qt_xvimage->data + qt_width * 2 * i);
1134 
1135             lqt_set_row_span(qt,0,qt_xvimage->pitches[0]);
1136 
1137             break;
1138         case BC_YUV420P:
1139             if(xv_have_YV12)
1140               {
1141               fprintf(stderr,
1142                       _("INFO: using BC_YUV420P + Xvideo extension (YV12)\n"));
1143               qt_xvimage = xv_create_ximage(dpy,qt_width,qt_height,
1144               xv_port,FOURCC_YV12);
1145               qt_rows[0] = (uint8_t*)(qt_xvimage->data + qt_xvimage->offsets[0]);
1146               qt_rows[1] = (uint8_t*)(qt_xvimage->data + qt_xvimage->offsets[2]);
1147               qt_rows[2] = (uint8_t*)(qt_xvimage->data + qt_xvimage->offsets[1]);
1148               }
1149 	    else if(xv_have_I420)
1150               {
1151               fprintf(stderr,
1152                       _("INFO: using BC_YUV420P + Xvideo extension (I420)\n"));
1153               qt_xvimage = xv_create_ximage(dpy,qt_width,qt_height,
1154 	                                    xv_port,FOURCC_I420);
1155 	      qt_rows[0] = (uint8_t*)(qt_xvimage->data + qt_xvimage->offsets[0]);
1156 	      qt_rows[1] = (uint8_t*)(qt_xvimage->data + qt_xvimage->offsets[1]);
1157 	      qt_rows[2] = (uint8_t*)(qt_xvimage->data + qt_xvimage->offsets[2]);
1158 	      }
1159             lqt_set_row_span(qt,0,qt_xvimage->pitches[0]);
1160             lqt_set_row_span_uv(qt,0,qt_xvimage->pitches[1]);
1161             break;
1162 	default:
1163 	    fprintf(stderr,_("ERROR: internal error at %s:%d\n"),
1164 		    __FILE__,__LINE__);
1165 	    exit(1);
1166 	}
1167 	if (qt_isqtvr) {
1168 	    /* has to be done here to set initial pov */ // look into this
1169 		quicktime_set_video_position(qt, lqt_qtvr_get_initial_position(qt),0);
1170 	    /*XSetInputFocus(dpy, XtWindow(simple), RevertToPointerRoot, CurrentTime);
1171 	    */
1172 	    if (qt_isqtvr == QTVR_PAN) {
1173 			float dist;
1174 			int oh_frames;
1175 			int i, i2, l, j, j2, k;
1176 			float x, y;
1177 			int pano_width = lqt_qtvr_get_width(qt);
1178 			int pano_height = lqt_qtvr_get_height(qt);
1179 
1180 			oh_frames = oh_width/((lqt_qtvr_get_panotype(qt) == QTVR_PANO_HORZ)?qt_width:qt_height);
1181 
1182 			for (i = 0; i < lqt_qtvr_get_columns(qt) + oh_frames; i++) {
1183 				/* set position in video file */
1184 				/* if position larger than panorama, start from the beginning (overhead)*/
1185 				quicktime_set_video_position(qt,
1186 					 (i>=lqt_qtvr_get_columns(qt))?i-lqt_qtvr_get_columns(qt):i,
1187 					 0);
1188 				/* decode a frame */
1189 				lqt_decode_video(qt, qt_rows, 0);
1190 
1191 				if (lqt_qtvr_get_panotype(qt) == QTVR_PANO_VERT) {
1192 					long buffer_size;
1193 					buffer_size = (pano_width + oh_width) * qt_width * 3;
1194 
1195 					/* set position in the output buffer */
1196 					/* to the upper left corner of the desired frame */
1197 					j = i * qt_height * 3;
1198 
1199 					/* put frame, rotated into buffer */
1200 					/* TODO: do this slightly less ass backwards */
1201 					for (k = 0; k < qt_width; k++) {
1202 						for (l = qt_height - 1; l >= 0; l--) {
1203 							qt_panorama_buffer[buffer_size - j + 0] = qt_frame[((qt_height - l) * qt_width - k) * 3 + 0];
1204 							qt_panorama_buffer[buffer_size - j + 1] = qt_frame[((qt_height - l) * qt_width - k) * 3 + 1];
1205 							qt_panorama_buffer[buffer_size - j + 2] = qt_frame[((qt_height - l) * qt_width - k) * 3 + 2];
1206 							j+=3;
1207 						}
1208 					j += (pano_width + oh_width - qt_height) * 3;
1209 					}
1210 
1211 				} else if (lqt_qtvr_get_panotype(qt) == QTVR_PANO_HORZ) {
1212 					int row_offset;
1213 					/* put frame into buffer at offset j */
1214 					j = i * qt_width;
1215 
1216 					for (k = 0; k < qt_height; k++) {
1217 						row_offset = k * (pano_width + oh_width) + j;
1218 						for (l = 0; l < qt_width; l++) {
1219 							qt_panorama_buffer[(row_offset + l) * 3    ] = qt_frame[(k * qt_width + l) * 3    ];
1220 							qt_panorama_buffer[(row_offset + l) * 3 + 1] = qt_frame[(k * qt_width + l) * 3 + 1];
1221 							qt_panorama_buffer[(row_offset + l) * 3 + 2] = qt_frame[(k * qt_width + l) * 3 + 2];
1222 						}
1223 					}
1224 				}
1225 			}
1226 
1227 			// "precalc"
1228 
1229 			// default "zoom"
1230 			dist = lqt_qtvr_get_width(qt)/(2*M_PI);
1231 
1232 			for (j = 0; j < pano_height; j++) {
1233 				for (i=0; i < qtvr_dwidth; i++) {
1234 					x = i - (qtvr_dwidth/2);
1235 					y = j - (pano_height/2);
1236 
1237 
1238 					i2 = (qtvr_dwidth / 2) + dist * atan(x / dist);
1239 					j2 = (pano_height / 2) + (dist * y) / sqrt(dist * dist + x * x);
1240 
1241 					//j2 = j; i2 = i;
1242 					if (i2 < 0 || i2 > qtvr_dwidth || j2 < 0 || j2 > pano_height) {
1243 						continue;
1244 					}
1245 
1246 					k = (j * qtvr_dwidth + i);
1247 
1248 					qt_frame_tmp[0][k] = i2; //x
1249 					qt_frame_tmp[1][k] = j2; //y
1250 				}
1251 			}
1252 		}
1253 	}
1254 	return 0;
1255 }
1256 
qt_frame_decode(void)1257 static int qt_frame_decode(void)
1258   {
1259   int i, j, k1, k2, x2, x, y, i2;
1260   int pano_width = lqt_qtvr_get_width(qt);
1261   int pano_height = lqt_qtvr_get_height(qt);
1262 #ifdef DUMP_TIMECODES
1263   uint32_t timecode;
1264 #endif
1265   if (qt_isqtvr == QTVR_OBJ)
1266     {
1267     /* sanity check and decode  */
1268     if (quicktime_video_position(qt, 0) >= 0 &&
1269         quicktime_video_position(qt, 0) < quicktime_video_length(qt,0))
1270       lqt_decode_video(qt, qt_rows, 0);
1271     //    quicktime_decode_scaled(qt,0,0,qt_width,qt_height,qt_width,qt_height,
1272     //			    qt_cmodel,qt_rows,0);
1273     }
1274   else if (qt_isqtvr == QTVR_PAN)
1275     {
1276     float qdist = pow(pano_width / (2 * M_PI), 2);
1277     int tilt = ypos + qtvr_dheight / 2 - pano_height / 2;
1278     int tmp_row_offset;
1279     float hofac, hofac2;
1280 
1281     hofac = qtvr_dheight * (qtvr_dheight - pano_height) / (-12 * qdist);
1282 
1283     for (j = 0; j < qtvr_dheight; j++)
1284       {
1285       tmp_row_offset = (ypos + j) * qtvr_dwidth;
1286       for (i = 0; i < qtvr_dwidth; i++)
1287         {
1288         k2 = i * 3;
1289         k1 = (qt_frame_tmp[1][tmp_row_offset + i] * (pano_width + oh_width) +
1290               qt_frame_tmp[0][tmp_row_offset + i] + xpos) * 3;
1291 
1292         qt_frame_row[k2] = qt_panorama_buffer[k1];
1293         qt_frame_row[k2 + 1] = qt_panorama_buffer[k1 + 1];
1294         qt_frame_row[k2 + 2] = qt_panorama_buffer[k1 + 2];
1295         }
1296 
1297       // Perspective Correction
1298       // probably wrong
1299       y = j - (qtvr_dheight/2);
1300       hofac2 = (((y * tilt) / (qdist * 3)) + 1 - hofac);
1301       for (i=0; i < qtvr_dwidth; i++)
1302         {
1303         x = i - (qtvr_dwidth / 2);
1304 
1305         x2 = x * hofac2;
1306         i2 =  (qtvr_dwidth / 2) + x2;
1307 
1308         k2 = (j * qtvr_dwidth + i) * 3;
1309         k1 = i2 * 3;
1310 
1311         qt_frame[k2] = qt_frame_row[k1];
1312         qt_frame[k2 + 1] = qt_frame_row[k1 + 1];
1313         qt_frame[k2 + 2] = qt_frame_row[k1 + 2];
1314         }
1315       }
1316     }
1317   else
1318     {
1319     if (quicktime_video_position(qt,0) >= quicktime_video_length(qt,0))
1320       return -1;
1321 
1322     if (qt_drop)
1323       {
1324       qt_droptotal += qt_drop;
1325       fprintf(stderr,_("dropped %d frame(s)\r"),qt_droptotal);
1326       for (i = 0; i < qt_drop; i++)
1327         quicktime_read_frame(qt,qt_frame,0);
1328       qt_drop = 0;
1329       }
1330     qt_frame_time = lqt_frame_time(qt, 0);
1331 
1332 #ifdef DUMP_TIMECODES
1333     if(lqt_read_timecode(qt, 0, &timecode))
1334       dump_timecode(qt, 0, timecode);
1335 #endif
1336 
1337 
1338     lqt_decode_video(qt, qt_rows, 0);
1339 
1340     }
1341   return 0;
1342   }
1343 
qt_frame_blit(void)1344 static int qt_frame_blit(void)
1345 {
1346 
1347     switch (qt_cmodel) {
1348     case BC_RGB888:
1349 #ifdef HAVE_GL
1350       if (use_gl) {
1351 	  if (qt_isqtvr == QTVR_PAN) {
1352 	    gl_blit(simple,qt_frame,qtvr_dwidth,qtvr_dheight,swidth,sheight);
1353 	  } else gl_blit(simple,qt_frame,qt_width,qt_height,swidth,sheight);
1354 	} else
1355 #endif // HAVE_GL
1356 
1357         {
1358 	    switch (pixmap_bytes) {
1359 	    case 2:
1360                 if (qt_isqtvr == QTVR_PAN) {
1361 		    rgb_to_lut2((uint8_t*)(qt_ximage->data),qt_frame,qtvr_dwidth*qtvr_dheight);
1362 		} else rgb_to_lut2((uint8_t*)(qt_ximage->data),qt_frame,qt_width*qt_height);
1363 		break;
1364 	    case 4:
1365             if (qt_isqtvr == QTVR_PAN) {
1366 		rgb_to_lut4((uint8_t*)(qt_ximage->data),qt_frame,qtvr_dwidth*qtvr_dheight);
1367 	    } else  rgb_to_lut4((uint8_t*)(qt_ximage->data),qt_frame,qt_width*qt_height);
1368 		break;
1369 	    }
1370 	    if (qt_isqtvr == QTVR_PAN) {
1371 		x11_blit(XtWindow(simple),qt_gc,qt_ximage,qtvr_dwidth,qtvr_dheight);
1372 	    } else
1373 	    x11_blit(XtWindow(simple),qt_gc,qt_ximage,qt_width,qt_height);
1374 	}
1375 	break;
1376     case BC_YUV422:
1377     case BC_YUV420P:
1378 	xv_blit(XtWindow(simple),qt_gc,qt_xvimage,
1379 		qt_width,qt_height,swidth,sheight);
1380 	break;
1381     default:
1382 	fprintf(stderr,_("ERROR: internal error at %s:%d\n"),
1383 		__FILE__,__LINE__);
1384 	exit(1);
1385     }
1386 
1387     return 0;
1388 }
1389 
qt_frame_delay(struct timeval * start,struct timeval * wait)1390 static void qt_frame_delay(struct timeval *start, struct timeval *wait)
1391 {
1392     struct timeval now;
1393     long msec;
1394 
1395     gettimeofday(&now,NULL);
1396     /* Get the now - start (->negative value) */
1397     msec  = (start->tv_sec  - now.tv_sec)  * 1000;
1398     msec += (start->tv_usec - now.tv_usec) / 1000;
1399     if (qt_hasaudio && oss_sr && oss_hr) {
1400 	/* cheap trick to make a/v sync ... */
1401 	msec = (long long)msec * oss_hr / oss_sr;
1402     }
1403 
1404     msec += (qt_frame_time * 1000) / qt_timescale;
1405 
1406     if (msec < 0) {
1407 	qt_drop = -msec * quicktime_frame_rate(qt,0) / 1000;
1408 	wait->tv_sec  = 0;
1409 	wait->tv_usec = 0;
1410     } else {
1411 	wait->tv_sec  = msec / 1000;
1412 	wait->tv_usec = (msec % 1000) * 1000;
1413     }
1414 }
1415 
1416 
1417 /* Decode at most AUDIO_BLOCK_SIZE samples and interleave them into the
1418    qt_audio array. Return the real number of decoded samples */
1419 
decode_audio()1420 static int decode_audio()
1421   {
1422   int i, j;
1423   int samples_decoded;
1424   long last_pos = lqt_last_audio_position(qt, 0);
1425   if(!qt_audio)
1426     {
1427     /* Initialize */
1428 
1429     if(qt_channels > 1)
1430       {
1431       qt_audion  = malloc(qt_channels * sizeof(*qt_audion));
1432       for(i = 0; i < qt_channels; i++)
1433         {
1434         qt_audion[i] = calloc(AUDIO_BLOCK_SIZE, sizeof(*(qt_audion[i])));
1435         }
1436       }
1437     qt_audio  = calloc(AUDIO_BLOCK_SIZE*qt_channels, sizeof(*qt_audio));
1438     }
1439 
1440   if(qt_channels > 1)
1441     {
1442     lqt_decode_audio_track(qt, qt_audion, (float**)0, AUDIO_BLOCK_SIZE, 0);
1443     samples_decoded = lqt_last_audio_position(qt, 0) - last_pos;
1444 
1445     /* Interleave */
1446     for (i = 0; i < samples_decoded; i++)
1447       {
1448       for(j = 0; j < qt_channels; j++)
1449         {
1450         qt_audio[qt_channels*i+j] = qt_audion[j][i];
1451         }
1452       }
1453     }
1454   else
1455     {
1456     lqt_decode_audio_track(qt, &qt_audio, (float**)0, AUDIO_BLOCK_SIZE, 0);
1457     samples_decoded = lqt_last_audio_position(qt, 0) - last_pos;
1458     }
1459   total_samples_decoded += samples_decoded;
1460   qt_audio_samples_in_buffer = samples_decoded;
1461   qt_audio_ptr = qt_audio;
1462   if(samples_decoded < AUDIO_BLOCK_SIZE)
1463     {
1464     fprintf(stderr, _("Audio track finished (got %d samples, wanted %d)\n"),
1465             samples_decoded, AUDIO_BLOCK_SIZE);
1466     qt_audio_eof = 1;
1467     }
1468   return samples_decoded;
1469   }
1470 
1471 //static int runcount;
qt_alsa_audio_write()1472 static int qt_alsa_audio_write()
1473 {
1474 #ifdef HAVE_ALSA
1475     int done = 0;
1476     int ret = 0;
1477     while(!done) {
1478         /* Decode new audio samples */
1479         if(!qt_audio_samples_in_buffer)
1480           decode_audio(AUDIO_BLOCK_SIZE);
1481         ret = snd_pcm_writei(pcm_handle, (void *)(qt_audio_ptr), qt_audio_samples_in_buffer);
1482         if (ret == -EAGAIN) {
1483             ret = 0;
1484             done = 1;
1485     //           snd_pcm_wait(pcm_handle, 1000);
1486         }
1487         else if (ret == -EPIPE) {
1488             snd_pcm_prepare(pcm_handle);
1489             fprintf(stderr, _("Warning: buffer underrun\n"));
1490         }
1491         else if (ret < 0) {
1492             fprintf(stderr, _("Warning: %s\n"), snd_strerror(ret));
1493         }
1494         else if (ret >= 0)
1495           done = 1;
1496     }
1497     if (ret > 0 ) {
1498     qt_audio_samples_in_buffer -=ret;
1499     qt_audio_ptr += ret * qt_channels;
1500     }
1501 
1502     if (qt_audio_eof && 0 == qt_audio_samples_in_buffer) {
1503         snd_pcm_drain(pcm_handle);
1504         return -1;
1505     }
1506 #endif
1507 
1508   return 0;
1509 }
1510 
qt_sndio_audio_write(void)1511 static int qt_sndio_audio_write(void)
1512 {
1513 #ifdef HAVE_SNDIO
1514     struct pollfd pfd;
1515     int rc, n, revents;
1516 
1517     if(!qt_audio_samples_in_buffer)
1518       decode_audio(AUDIO_BLOCK_SIZE);
1519 
1520     /* this code is absolutely horrible.  do not follow this example. */
1521 
1522     n = sio_pollfd(hdl, &pfd, POLLOUT);
1523     rc = poll(&pfd, n, 10000);
1524     if (rc <= 0)
1525         goto fail;
1526     revents = sio_revents(hdl, &pfd);
1527     if (!(revents & POLLOUT))
1528         goto fail;
1529     rc = sio_write(hdl,qt_audio_ptr,qt_audio_samples_in_buffer * qt_channels * sizeof(*qt_audio));
1530     switch (rc) {
1531     case 0:
1532         goto fail;
1533 	break;
1534     default:
1535         qt_audio_samples_in_buffer -= rc / (qt_channels * sizeof(*qt_audio));
1536         qt_audio_ptr += rc / sizeof(*qt_audio);
1537         break;
1538     }
1539 
1540     if (qt_audio_eof && 0 == qt_audio_samples_in_buffer) {
1541        return -1;
1542     }
1543 
1544     return 0;
1545 
1546 fail:
1547     fprintf(stderr,_("write sndio: Huh? no data to write/no data written?\n"));
1548     sio_close(hdl);
1549     hdl = NULL;
1550     qt_hasaudio = 0;
1551 #endif
1552     return 0;
1553 }
1554 
qt_oss_audio_write(void)1555 static int qt_oss_audio_write(void)
1556 {
1557     int rc;
1558 
1559     if(!qt_audio_samples_in_buffer)
1560       decode_audio(AUDIO_BLOCK_SIZE);
1561 
1562     rc = write(oss_fd,qt_audio_ptr,qt_audio_samples_in_buffer * qt_channels * sizeof(*qt_audio));
1563     switch (rc) {
1564     case -1:
1565 	perror("write dsp");
1566 	close(oss_fd);
1567 	oss_fd = -1;
1568 	qt_hasaudio = 0;
1569 	break;
1570     case 0:
1571 	fprintf(stderr,_("write dsp: Huh? no data written?\n"));
1572 	close(oss_fd);
1573 	oss_fd = -1;
1574 	qt_hasaudio = 0;
1575 	break;
1576     default:
1577         qt_audio_samples_in_buffer -= rc / (qt_channels * sizeof(*qt_audio));
1578         qt_audio_ptr += rc / sizeof(*qt_audio);
1579         break;
1580     }
1581 
1582     if (qt_audio_eof && 0 == qt_audio_samples_in_buffer) {
1583        return -1;
1584     }
1585     return 0;
1586 }
1587 
1588 /* ------------------------------------------------------------------------ */
1589 /* main                                                                     */
1590 
1591 struct ARGS {
1592     int  xv;
1593     int  gl;
1594     int  alsa;
1595 } args;
1596 
1597 XtResource args_desc[] = {
1598     /* name, class, type, size, offset, default_type, default_addr */
1599     {
1600 	/* Integer */
1601 	"xv",
1602 	XtCValue, XtRInt, sizeof(int),
1603 	XtOffset(struct ARGS*,xv),
1604 	XtRString, "1"
1605     },{
1606 	"gl",
1607 	XtCValue, XtRInt, sizeof(int),
1608 	XtOffset(struct ARGS*,gl),
1609 	XtRString, "1"
1610     },{
1611 	"alsa",
1612 	XtCValue, XtRInt, sizeof(int),
1613 	XtOffset(struct ARGS*,alsa),
1614 	XtRString, "1"
1615     }
1616 };
1617 const int args_count = XtNumber(args_desc);
1618 
1619 XrmOptionDescRec opt_desc[] = {
1620     { "-noxv",  "xv", XrmoptionNoArg,  "0" },
1621     { "-nogl",  "gl", XrmoptionNoArg,  "0" },
1622     { "-noalsa",  "alsa", XrmoptionNoArg,  "0" },
1623 };
1624 const int opt_count = (sizeof(opt_desc)/sizeof(XrmOptionDescRec));
1625 
usage(FILE * fp,char * prog)1626 static void usage(FILE *fp, char *prog)
1627 {
1628     char *p;
1629 
1630     p = strrchr(prog,'/');
1631     if (p) prog = p+1;
1632     fprintf(fp,
1633 	    _("\n"
1634               "Very simple quicktime movie player for X11.  Just playes\n"
1635               "the movie and nothing else.  No fancy gui, no controls.\n"
1636               "\n"
1637               "You can quit with 'Q' and 'ESC' keys.\n"
1638               "\n"
1639               "usage: %s [ options ] <file>\n"
1640               "options:\n"
1641               "  -noxv   don't use the Xvideo extension\n"
1642               "  -nogl   don't use OpenGL\n"
1643               "  -noalsa don't use Alsa\n"
1644               "\n"),
1645 	    prog);
1646 }
1647 
decode_qtvr()1648 static void decode_qtvr()
1649 {
1650     XEvent event;
1651     int startpos;
1652 
1653     startpos = quicktime_video_position(qt, 0);
1654     XFlush(dpy);
1655     if (qt_hasvideo) {
1656 	  	if (qt_frame_decode() || qt_frame_blit()) exit(0);
1657     }
1658 
1659     for (;;) {
1660 		struct timespec time;
1661 
1662 		//      printf("loop pos :%ld\n",quicktime_video_position(qt,0));
1663 		if (quicktime_video_position(qt,0) >= startpos + lqt_qtvr_get_loop_frames(qt))
1664 			quicktime_set_video_position(qt, startpos, 0);
1665 
1666 		if (True == XCheckMaskEvent(dpy, ~0, &event)) {
1667 			XtDispatchEvent(&event);
1668 		} else {
1669 		//	printf("loop pos before decode :%ld\n",quicktime_video_position(qt,0));
1670 			XFlush(dpy);
1671 			XtAppProcessEvent(app_context, KeyPressMask||KeyReleaseMask);
1672 			time.tv_nsec = 10000000;
1673 			time.tv_sec = 0;
1674 			nanosleep(&time, NULL);
1675 		}
1676     }
1677 }
1678 
quit_ac(Widget widget,XEvent * event,String * params,Cardinal * num_params)1679 static void quit_ac(Widget widget, XEvent *event,
1680 		    String *params, Cardinal *num_params)
1681 {
1682     exit(0);
1683 }
1684 
resize_ev(Widget widget,XtPointer client_data,XEvent * event,Boolean * d)1685 static void resize_ev(Widget widget, XtPointer client_data,
1686 		      XEvent *event, Boolean *d)
1687 {
1688     switch(event->type) {
1689     case MapNotify:
1690     case ConfigureNotify:
1691         XtVaGetValues(widget,XtNheight,&sheight,XtNwidth,&swidth,NULL);
1692         fprintf(stderr,_("INFO: window size is %dx%d\n"),swidth,sheight);
1693 #ifdef HAVE_GL
1694 	      if (use_gl)
1695 	          gl_resize(widget,swidth,sheight);
1696 #endif
1697         if (qt_isqtvr != 0) decode_qtvr();
1698         break;
1699     case UnmapNotify:
1700     case DestroyNotify:
1701             exit(0);
1702         break;
1703     }
1704 }
1705 
1706 /* event handlers */
1707 
left_ac(Widget widget,XEvent * event,String * params,Cardinal * num_params)1708 static void left_ac(Widget widget, XEvent *event,
1709 		    String *params, Cardinal *num_params)
1710 {
1711     if (qt_isqtvr == QTVR_PAN) {
1712         if (xpos - 10 >= 0 ) xpos -= 10;
1713 
1714         if (xpos - 10 < 0) {
1715             xpos = xpos-10 + lqt_qtvr_get_width(qt);
1716         }
1717     }
1718     else if (qt_isqtvr == QTVR_OBJ) {
1719         int vpos = quicktime_video_position(qt, 0);
1720         int lfxcolumns = lqt_qtvr_get_loop_frames(qt) * lqt_qtvr_get_columns(qt);
1721 
1722         if (vpos % lfxcolumns == lfxcolumns - lqt_qtvr_get_loop_frames(qt) && vpos != 0) {
1723             quicktime_set_video_position(qt, vpos - (lqt_qtvr_get_columns(qt)-1), 0);
1724         }
1725         else {
1726             quicktime_set_video_position(qt, vpos + lqt_qtvr_get_loop_frames(qt), 0);
1727         }
1728     }
1729     else
1730         return;
1731 //    printf("pos %ld\n",quicktime_video_position(qt,0));
1732     decode_qtvr();
1733 }
1734 
right_ac(Widget widget,XEvent * event,String * params,Cardinal * num_params)1735 static void right_ac(Widget widget, XEvent *event,
1736 		    String *params, Cardinal *num_params)
1737 {
1738     if (qt_isqtvr == QTVR_PAN) {
1739 	  	if (xpos + 10 <= lqt_qtvr_get_width(qt)+oh_width - qtvr_dwidth) xpos += 10;
1740 		if (xpos + 10 > lqt_qtvr_get_width(qt)) {
1741 			xpos = xpos+10 - lqt_qtvr_get_width(qt);
1742 		}
1743     }
1744     else if (qt_isqtvr == QTVR_OBJ) {
1745 		int vpos = quicktime_video_position(qt, 0);
1746 		int lfxcolumns = lqt_qtvr_get_loop_frames(qt) * lqt_qtvr_get_columns(qt);
1747 
1748 		if (vpos % lfxcolumns == 0) {
1749 			quicktime_set_video_position(qt, vpos + (lqt_qtvr_get_loop_frames(qt) * lqt_qtvr_get_columns(qt)-1), 0);
1750 	}
1751 	else {
1752 			quicktime_set_video_position(qt, vpos - lqt_qtvr_get_loop_frames(qt), 0);
1753 		}
1754     }
1755     else
1756 	  	return;
1757 //    printf("pos %ld\n",quicktime_video_position(qt,0));
1758     decode_qtvr();
1759 }
1760 
up_ac(Widget widget,XEvent * event,String * params,Cardinal * num_params)1761 static void up_ac(Widget widget, XEvent *event,
1762 		    String *params, Cardinal *num_params)
1763 {
1764     if (qt_isqtvr == QTVR_PAN) {
1765 	  	if (ypos - 10 >= 0 ) ypos -= 10;
1766     }
1767     else if (qt_isqtvr == QTVR_OBJ) {
1768 		int vpos = quicktime_video_position(qt, 0);
1769 
1770 		if (vpos + lqt_qtvr_get_columns(qt) < lqt_qtvr_get_loop_frames(qt) * lqt_qtvr_get_rows(qt) * lqt_qtvr_get_columns(qt)) {
1771 			quicktime_set_video_position(qt ,vpos + lqt_qtvr_get_columns(qt), 0);
1772 		}
1773 //  printf("pos %ld\n",quicktime_video_position(qt,0));
1774     }
1775     else
1776 	  	return;
1777 
1778     decode_qtvr();
1779 }
1780 
down_ac(Widget widget,XEvent * event,String * params,Cardinal * num_params)1781 static void down_ac(Widget widget, XEvent *event,
1782 		    String *params, Cardinal *num_params)
1783 {
1784     if (qt_isqtvr == QTVR_PAN) {
1785 	  	if (ypos + 10 < lqt_qtvr_get_height(qt) - lqt_qtvr_get_display_height(qt)) ypos += 10;
1786     }
1787     else if (qt_isqtvr == QTVR_OBJ) {
1788 		if (quicktime_video_position(qt, 0) - lqt_qtvr_get_columns(qt) >= 0) {
1789 			quicktime_set_video_position(qt ,quicktime_video_position(qt, 0) - lqt_qtvr_get_columns(qt), 0);
1790 		}
1791     }
1792     else
1793 	  	return;
1794 //  printf("pos %ld\n",quicktime_video_position(qt,0));
1795 	decode_qtvr();
1796 }
1797 
expose_ev(Widget widget,XtPointer client_data,XEvent * event,Boolean * d)1798 static void expose_ev(Widget widget, XtPointer client_data,
1799 		      XEvent *event, Boolean *d)
1800 {
1801     if (event->type == Expose)
1802         decode_qtvr();
1803 }
1804 
1805 static XtActionsRec action_table[] = {
1806     { "Quit",  quit_ac },
1807     { "Right", right_ac },
1808     { "Left",  left_ac },
1809     { "Up",    up_ac },
1810     { "Down",  down_ac },
1811 };
1812 
1813 static String res[] = {
1814     "lqtplay.playback.translations:  #override \\n"
1815     "        <Key>Q:                 Quit()    \\n"
1816     "        <Key>Escape:            Quit()    \\n"
1817     "        <Key>Right:             Right()    \\n"
1818     "        <Key>Left:              Left()   \\n"
1819     "        <Key>Up:                Up() \\n"
1820     "        <Key>Down:              Down()",
1821     "lqtplay.playback.background:    black",
1822     NULL
1823 };
1824 
main(int argc,char * argv[])1825 int main(int argc, char *argv[])
1826 {
1827     int has_frame = 0, blit_frame = 0;
1828     struct timeval start,wait;
1829     //    int audio_frames;
1830 
1831     setlocale(LC_MESSAGES, "");
1832     setlocale(LC_CTYPE, "");
1833 
1834     bindtextdomain(PACKAGE, LOCALE_DIR);
1835 
1836     app_shell = XtVaAppInitialize(&app_context, "lqtplay",
1837 				  opt_desc, opt_count,
1838 				  &argc, argv,
1839 				  res, NULL);
1840     XtGetApplicationResources(app_shell,&args,
1841 			      args_desc,args_count,
1842 			      NULL,0);
1843 
1844     /* don't use alsa*/
1845     if (!args.alsa) use_alsa=0;
1846 
1847     /* open file */
1848     if (argc < 2) {
1849 	usage(stderr,argv[0]);
1850 	exit(1);
1851     }
1852     qt_init(stdout,argv[1]);
1853 
1854     /* init x11 stuff */
1855     dpy = XtDisplay(app_shell);
1856 
1857     XtAppAddActions(app_context,action_table,
1858 		    sizeof(action_table)/sizeof(XtActionsRec));
1859     XtVaSetValues(app_shell, XtNtitle,argv[1],NULL);
1860     if (qt_isqtvr) {
1861 	simple = XtVaCreateManagedWidget("playback",simpleWidgetClass,app_shell,
1862 			     		 XtNwidth,  qtvr_dwidth,
1863 					 XtNheight, qtvr_dheight,
1864 					 NULL);
1865 	XtAddEventHandler(simple,ExposureMask, True, expose_ev, NULL);
1866     }
1867     else
1868 	simple = XtVaCreateManagedWidget("playback",simpleWidgetClass,app_shell,
1869 			     		 XtNwidth,  qt_width,
1870 					 XtNheight, qt_height,
1871 					 NULL);
1872 
1873 
1874     XtAddEventHandler(simple,StructureNotifyMask, True, resize_ev, NULL);
1875 
1876     x11_init();
1877     if (args.xv && qt_hasvideo)
1878 	xv_init();
1879     if(qt_hasvideo) {
1880         if (qt_isqtvr == QTVR_PAN) {
1881 	    /* cmodel hardcoded for panos */
1882 	    lqt_set_cmodel(qt, 0, BC_RGB888);
1883 	}
1884 	else {
1885 	    /* Decide about the colormodel */
1886 	    fprintf(stderr, _("Stream colormodel %s, "),
1887                     lqt_colormodel_to_string(lqt_get_cmodel(qt, 0)));
1888 	    qt_cmodel = lqt_get_best_colormodel(qt, 0, qt_cmodels);
1889 	    fprintf(stderr, _("using %s\n"), lqt_colormodel_to_string(qt_cmodel));
1890 	    /* Set decoding colormodel */
1891 	    lqt_set_cmodel(qt, 0, qt_cmodel);
1892 	}
1893     }
1894     /* use OpenGL? */
1895     XtRealizeWidget(app_shell);
1896 #ifdef HAVE_GL
1897     if (BC_RGB888 == qt_cmodel && args.gl && qt_hasvideo) {
1898     	if (qt_isqtvr == QTVR_PAN) {
1899 	    gl_init(simple,qtvr_dwidth,qtvr_dheight);
1900 	} else
1901 	    gl_init(simple,qt_width,qt_height);
1902     }
1903 #endif
1904     /* frames per chunk for alsa */
1905 #if 0
1906     if(qt_hasvideo)
1907       audio_frames = ((oss_sr / quicktime_frame_rate(qt,0)) / 2 + 0.5);
1908     else
1909       audio_frames = oss_sr + 1024;
1910 #endif
1911     /* Initialize video */
1912     if(qt_hasvideo)
1913 	qt_init_video();
1914 
1915     if (qt_isqtvr) {
1916 	decode_qtvr();
1917     }
1918     else {
1919 	/* enter main loop */
1920 	gettimeofday(&start,NULL);
1921 	for (;;) {
1922 	    int rc,max;
1923 	    fd_set rd,wr;
1924 	    XEvent event;
1925 
1926 	    if (True == XCheckMaskEvent(dpy, ~0, &event)) {
1927 		XtDispatchEvent(&event);
1928 	    }
1929 	    else {
1930 		XFlush(dpy);
1931 		FD_ZERO(&rd);
1932 		FD_ZERO(&wr);
1933 		FD_SET(ConnectionNumber(dpy),&rd);
1934 		max = ConnectionNumber(dpy);
1935 		if (qt_hasaudio) {
1936 		    if (use_alsa == 0 && use_sndio == 0) {
1937 			FD_SET(oss_fd,&wr);
1938 			if (oss_fd > max)
1939 			    max = oss_fd;
1940 		    }
1941 		}
1942 
1943 		if (qt_hasvideo) {
1944 		    if(!has_frame) {
1945 			if(0 != qt_frame_decode()) {
1946 			    qt_hasvideo = 0;
1947 			    wait.tv_sec  = 0;
1948 			    wait.tv_usec = 1000;
1949 			} else {
1950 			has_frame = 1;
1951 			}
1952 		    }
1953 
1954 		qt_frame_delay(&start,&wait);
1955 
1956 
1957 		/* "wait" is the time, we would have to wait.
1958 		   If it's longer, than 2 ms, we'll continue feeding the
1959 		   soundcard. This prevents audio underruns for frames with a
1960 		   VERY long duration */
1961 		 if(wait.tv_sec || (wait.tv_usec > 2000)) {
1962 		     wait.tv_sec  = 0;
1963 		     wait.tv_usec = 2000;
1964 		     blit_frame = 0;
1965 		 } else
1966 		     blit_frame = 1;
1967 
1968 	     } else {
1969 		    wait.tv_sec  = 0;
1970 		    wait.tv_usec = 1000;
1971 		}
1972 		rc = select(max+1,&rd,&wr,NULL,&wait);
1973 		if (qt_hasaudio) {
1974 		    if (use_alsa == 1) {
1975 			if (0 != qt_alsa_audio_write()) qt_hasaudio = 0;
1976 		    }
1977 		    else if (use_sndio == 1) {
1978 			if (0 != qt_sndio_audio_write()) qt_hasaudio = 0;
1979 		    }
1980 		    else if (FD_ISSET(oss_fd,&wr)) {
1981 			if (0 != qt_oss_audio_write()) qt_hasaudio = 0;
1982 		    }
1983 		}
1984 		if (qt_hasvideo && 0 == rc && blit_frame) {
1985 		    qt_frame_blit();
1986 		    has_frame = 0;
1987 		}
1988 	    }
1989 	if(!qt_hasvideo && !qt_hasaudio)
1990 	  break;
1991 	}
1992     }
1993     qt_cleanup();
1994     fprintf(stderr, _("Decoded %lld samples\n"),
1995             (long long)total_samples_decoded);
1996     return 0;
1997 }
1998 
1999