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