Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * simple movie player
  3  *
  4  *  (c) 2002 Gerd Knorr <kraxel@bytesex.org>
  5  *
  6  */
  7 
  8 #include "config.h"
  9 
 10 #include <stdio.h>
 11 #include <stdlib.h>
 12 #include <unistd.h>
 13 #include <strings.h>
 14 #include <errno.h>
 15 #include <fcntl.h>
 16 
 17 #include <sys/types.h>
 18 #include <sys/time.h>
 19 #include <sys/ipc.h>
 20 #include <sys/shm.h>
 21 #include <sys/ioctl.h>
 22 #include <sys/soundcard.h>
 23 
 24 #include <X11/Xlib.h>
 25 #include <X11/Intrinsic.h>
 26 #include <X11/StringDefs.h>
 27 #include <X11/Shell.h>
 28 #include <X11/Xaw/Simple.h>
 29 #include <X11/extensions/XShm.h>
 30 #ifdef HAVE_LIBXV
 31 # include <X11/extensions/Xv.h>
 32 # include <X11/extensions/Xvlib.h>
 33 #endif
 34 
 35 #include "grab-ng.h"
 36 #include "blit.h"
 37 
 38 /* ------------------------------------------------------------------------ */
 39 
 40 int debug = 0;
 41 
 42 /* X11 */
 43 static XtAppContext app_context;
 44 static Widget       app_shell;
 45 static Display      *dpy;
 46 static Colormap     colormap;
 47 static Visual       *visual;
 48 static XVisualInfo  vinfo,*vinfo_list;
 49 
 50 static Widget simple;
 51 static Dimension swidth,sheight;
 52 
 53 static struct blit_state *blit;
 54 
 55 /* libng */
 56 static const struct ng_reader      *reader;
 57 static void                        *rhandle;
 58 static const struct ng_dsp_driver  *snd;
 59 static void                        *shandle;
 60 static int                         snd_fd;
 61 
 62 static struct ng_video_fmt         cfmt;
 63 static struct ng_video_conv        *conv;
 64 static void                        *chandle;
 65 
 66 static struct ng_video_fmt         *vfmt;
 67 static struct ng_audio_fmt         *afmt;
 68 static struct ng_video_buf         *vbuf;
 69 static struct ng_audio_buf         *abuf;
 70 
 71 /* ------------------------------------------------------------------------ */
 72 
 73 struct ARGS {
 74     char  *dsp;
 75     int   slow;
 76     int   help;
 77     int   verbose;
 78     int   debug;
 79     int   xv;
 80     int   gl;
 81     int   max;
 82     int   audio;
 83     int   video;
 84 } args;
 85 
 86 XtResource args_desc[] = {
 87     /* name, class, type, size, offset, default_type, default_addr */
 88     {
 89         /* Strings */
 90         "dsp",
 91         XtCString, XtRString, sizeof(char*),
 92         XtOffset(struct ARGS*,dsp),
 93         XtRString, NULL,
 94     },{
 95         /* Integer */
 96         "verbose",
 97         XtCValue, XtRInt, sizeof(int),
 98         XtOffset(struct ARGS*,verbose),
 99         XtRString, ""
100     },{
101         "debug",
102         XtCValue, XtRInt, sizeof(int),
103         XtOffset(struct ARGS*,debug),
104         XtRString, ""
105     },{
106         "help",
107         XtCValue, XtRInt, sizeof(int),
108         XtOffset(struct ARGS*,help),
109         XtRString, ""
110     },{
111         "slow",
112         XtCValue, XtRInt, sizeof(int),
113         XtOffset(struct ARGS*,slow),
114         XtRString, "1"
115     },{
116         "xv",
117         XtCValue, XtRInt, sizeof(int),
118         XtOffset(struct ARGS*,xv),
119         XtRString, "1"
120     },{
121         "gl",
122         XtCValue, XtRInt, sizeof(int),
123         XtOffset(struct ARGS*,gl),
124         XtRString, "1"
125     },{
126         "max",
127         XtCValue, XtRInt, sizeof(int),
128         XtOffset(struct ARGS*,max),
129         XtRString, ""
130     },{
131         "audio",
132         XtCValue, XtRInt, sizeof(int),
133         XtOffset(struct ARGS*,audio),
134         XtRString, "1"
135     },{
136         "video",
137         XtCValue, XtRInt, sizeof(int),
138         XtOffset(struct ARGS*,video),
139         XtRString, "1"
140     }
141 };
142 const int args_count = XtNumber(args_desc);
143 
144 XrmOptionDescRec opt_desc[] = {
145     { "-dsp",        "dsp",         XrmoptionSepArg, NULL },
146     { "-slow",       "slow",        XrmoptionSepArg, NULL },
147 
148     { "-h",          "help",        XrmoptionNoArg,  "1" },
149     { "-help",       "help",        XrmoptionNoArg,  "1" },
150     { "--help",      "help",        XrmoptionNoArg,  "1" },
151 
152     { "-v",          "verbose",     XrmoptionNoArg,  "1" },
153     { "-verbose",    "verbose",     XrmoptionNoArg,  "1" },
154     { "-debug",      "debug",       XrmoptionNoArg,  "1" },
155     { "-max",        "max",         XrmoptionNoArg,  "1" },
156 
157     { "-xv",         "xv",          XrmoptionNoArg,  "1" },
158     { "-noxv",       "xv",          XrmoptionNoArg,  "" },
159     { "-gl",         "gl",          XrmoptionNoArg,  "1" },
160     { "-nogl",       "gl",          XrmoptionNoArg,  "" },
161     { "-audio",      "audio",       XrmoptionNoArg,  "1" },
162     { "-noaudio",    "audio",       XrmoptionNoArg,  "" },
163     { "-video",      "video",       XrmoptionNoArg,  "1" },
164     { "-novideo",    "video",       XrmoptionNoArg,  "" },
165 };
166 const int opt_count = (sizeof(opt_desc)/sizeof(XrmOptionDescRec));
167 
168 /* ------------------------------------------------------------------------ */
169 
170 static void quit_ac(Widget widget, XEvent *event,
171                     String *params, Cardinal *num_params)
172 {
173     exit(0);
174 }
175 
176 static void resize_ev(Widget widget, XtPointer client_data,
177                       XEvent *event, Boolean *d)
178 {
179     static int first = 1;
180     
181     switch(event->type) {
182     case MapNotify:
183     case ConfigureNotify:
184         if (first) {
185             blit = blit_init(simple,&vinfo,args.gl);
186             first = 0;
187         }
188         XtVaGetValues(widget,XtNheight,&sheight,XtNwidth,&swidth,NULL);
189         if (vfmt)
190             blit_resize(blit,swidth,sheight);
191         break;
192     }
193 }
194 
195 static XtActionsRec action_table[] = {
196     { "Quit",  quit_ac },
197 };
198 
199 static String res[] = {
200     "pia.winGravity:             Static",
201     "pia.playback.translations:  #override \\n"
202     "       <Key>Q:              Quit()    \\n"
203     "       <Key>Escape:         Quit()",
204     "pia.playback.background:    black",
205     NULL
206 };
207 
208 static void usage(FILE *out, char *prog)
209 {
210     char *h;
211 
212     if (NULL != (h = strrchr(prog,'/')))
213         prog = h+1;
214     fprintf(out,
215             "%s is simple movie player\n"
216             "\n"
217             "usage: %s [ options ] movie\n"
218             "options:\n"
219             "  -h, -help       this text\n"
220             "  -v, -verbose    be verbose\n"
221             "      -debug      enable debug messages\n"
222             "      -dsp <dev>  use sound device <dev>\n"
223 #ifdef HAVE_LIBXV
224             "      -noxv       disable Xvideo extention\n"
225 #endif
226 #ifdef HAVE_GL
227             "      -nogl       disable OpenGL\n"
228 #endif
229             "\n",
230             prog,prog);
231 }
232 
233 static void sync_info(long long drift, int drops, int frames)
234 {
235     int total = drops + frames;
236     
237     fprintf(stderr,"a/v sync: audio drift is %4d ms / "
238             "%d of %d frame(s) [%3.1f%%] dropped \r",
239             (int)((drift)/1000000),drops,total,
240             total ? (float)drops * 100 / total : 0);
241 }
242 
243 int main(int argc, char *argv[])
244 {
245     long long start, now, delay, latency = 0, drift = 0;
246     struct timeval wait;
247     int n, drop, droptotal, framecount, ww, wh;
248     unsigned int fmtids[2*VIDEO_FMT_COUNT], i;
249     XEvent event;
250     
251     app_shell = XtVaAppInitialize(&app_context, "pia",
252                                   opt_desc, opt_count,
253                                   &argc, argv,
254                                   res, NULL);
255     XtGetApplicationResources(app_shell,&args,
256                               args_desc,args_count,
257                               NULL,0);
258     if (args.help) {
259         usage(stdout,argv[0]);
260         exit(1);
261     }
262     if (args.debug) {
263         debug    = args.debug;
264         ng_debug = args.debug;
265     }
266 
267     if (argc < 2) {
268         usage(stderr,argv[0]);
269         exit(1);
270     }
271     ng_init();
272 
273     /* open file */
274     reader = ng_find_reader(argv[1]);
275     if (NULL == reader) {
276         fprintf(stderr,"can't handle %s\n",argv[1]);
277         exit(1);
278     }
279     rhandle = reader->rd_open(argv[1]);
280     if (NULL == rhandle) {
281         fprintf(stderr,"opening %s failed\n",argv[1]);
282         exit(1);
283     }
284     vfmt = reader->rd_vfmt(rhandle,NULL,0);
285     if (0 == vfmt->width || 0 == vfmt->height)
286         vfmt = NULL;
287     afmt = reader->rd_afmt(rhandle);
288 
289     if (0 == args.video)
290         vfmt = NULL;
291     if (0 == args.audio)
292         afmt = NULL;
293     if (1 != args.slow)
294         /* no audio for slow motion, will not sync anyway ... */
295         afmt = NULL;
296 
297     /* init x11 stuff */
298     dpy = XtDisplay(app_shell);
299     visual = x11_find_visual(XtDisplay(app_shell));
300     vinfo.visualid = XVisualIDFromVisual(visual);
301     vinfo_list = XGetVisualInfo(dpy, VisualIDMask, &vinfo, &n);
302     vinfo = vinfo_list[0];
303     XFree(vinfo_list);
304     if (visual != DefaultVisualOfScreen(XtScreen(app_shell))) {
305         fprintf(stderr,"switching visual (0x%lx)\n",vinfo.visualid);
306         colormap = XCreateColormap(dpy,RootWindowOfScreen(XtScreen(app_shell)),
307                                    vinfo.visual,AllocNone);
308         XtDestroyWidget(app_shell);
309         app_shell = XtVaAppCreateShell("pia","pia",
310                                        applicationShellWidgetClass, dpy,
311                                        XtNvisual,vinfo.visual,
312                                        XtNcolormap,colormap,
313                                        XtNdepth, vinfo.depth,
314                                        NULL);
315     } else {
316         colormap = DefaultColormapOfScreen(XtScreen(app_shell));
317     }
318     x11_init_visual(XtDisplay(app_shell),&vinfo);
319 #if HAVE_LIBXV
320     if (args.xv)
321         xv_image_init(dpy);
322 #endif
323     XtAppAddActions(app_context,action_table,
324                     sizeof(action_table)/sizeof(XtActionsRec));
325     XtVaSetValues(app_shell, XtNtitle,argv[1],NULL);
326 
327     /* show window */
328     ww = 320;
329     wh = 32;
330     if (vfmt) {
331         ww = vfmt->width;
332         wh = vfmt->height;
333         if (args.max) {
334             int sw = XtScreen(app_shell)->width;
335             int sh = XtScreen(app_shell)->height;
336             if (sw * wh > sh * ww) {
337                 ww = ww * sh / wh;
338                 wh = sh;
339             } else {
340                 wh = wh * sw / ww;
341                 ww =sw;
342             }
343         }
344     }
345     simple = XtVaCreateManagedWidget("playback",simpleWidgetClass,app_shell,
346                                      XtNwidth,ww, XtNheight,wh, NULL);
347     XtAddEventHandler(simple, StructureNotifyMask, True, resize_ev, NULL);
348     XtRealizeWidget(app_shell);
349     while (NULL == blit) {
350         XFlush(dpy);
351         while (True == XCheckMaskEvent(dpy, ~0, &event))
352             XtDispatchEvent(&event);
353     }
354 
355     /* video setup */
356     if (vfmt) {
357         blit_get_formats(blit,fmtids,sizeof(fmtids)/sizeof(int));
358         vfmt = reader->rd_vfmt(rhandle,fmtids,sizeof(fmtids)/sizeof(int));
359         if (0 == vfmt->width || 0 == vfmt->height || VIDEO_NONE == vfmt->fmtid)
360             vfmt = NULL;
361     }
362     if (vfmt) {
363         for (i = 0; i < sizeof(fmtids)/sizeof(int); i++)
364             if (fmtids[i] == vfmt->fmtid)
365                 break;
366         if (i == sizeof(fmtids)/sizeof(int)) {
367             /* blit can't display directly -- have to convert somehow */
368             for (i = 0; i < sizeof(fmtids)/sizeof(int); i++)
369                 if (NULL != (conv = ng_conv_find_match(vfmt->fmtid,fmtids[i])))
370                     break;
371             if (conv) {
372                 cfmt = *vfmt;
373                 cfmt.fmtid = conv->fmtid_out;
374                 cfmt.bytesperline = 0;
375                 chandle = ng_convert_alloc(conv,vfmt,&cfmt);
376                 ng_convert_init(chandle);
377                 if (debug)
378                     fprintf(stderr,"pia: conv [%s] => [%s]\n",
379                             ng_vfmt_to_desc[vfmt->fmtid],
380                             ng_vfmt_to_desc[cfmt.fmtid]);
381             }
382         }
383     }
384 
385     /* audio setup */
386     if (afmt) {
387         struct ng_audio_fmt f = *afmt;
388         snd = ng_dsp_open(args.dsp ? args.dsp : "/dev/dsp", &f,0,&shandle);
389         if (NULL == snd)
390             afmt = NULL;
391         else {
392             snd_fd  = snd->fd(shandle);
393             latency = snd->latency(shandle);
394             if (debug)
395                 fprintf(stderr,"a/v sync: audio latency is %lld ms\n",
396                         latency/1000000);
397         }
398     }
399 
400     /* enter main loop
401      * 
402      * can't use XtAppMainLoop + Input + Timeout handlers here because
403      * that doesn't give us usable event scheduling, thus we have our
404      * own main loop here ...
405      */
406     drop = 0;
407     droptotal = 0;
408     framecount = 0;
409     start = 0;
410     drift = 0;
411     if (afmt) {
412         /* fill sound buffer */
413         fd_set wr;
414         int rc;
415         
416         for (;;) {
417             FD_ZERO(&wr);
418             FD_SET(snd_fd,&wr);
419             wait.tv_sec = 0;
420             wait.tv_usec = 0;
421             rc = select(snd_fd+1,NULL,&wr,NULL,&wait);
422             if (1 != rc)
423                 break;
424             abuf = reader->rd_adata(rhandle);
425             if (NULL == abuf)
426                 break;
427             if (0 == start)
428                 start = ng_get_timestamp();
429             drift = abuf->info.ts - (ng_get_timestamp() - start);
430             abuf = snd->write(shandle,abuf);
431             if (NULL != abuf)
432                 break;
433         }
434     }
435     if (0 == start)
436         start = ng_get_timestamp();
437 
438     if (debug)
439         fprintf(stderr,"a/v sync: audio buffer filled\n");
440     for (; vfmt || afmt;) {
441         int rc,max;
442         fd_set rd,wr;
443 
444         /* handle X11 events */
445         if (True == XCheckMaskEvent(dpy, ~0, &event)) {
446             XtDispatchEvent(&event);
447             continue;
448         }
449 
450         /* read media data */
451         if (afmt && NULL == abuf) {
452             abuf = reader->rd_adata(rhandle);
453             if (NULL == abuf)
454                 afmt = NULL; /* EOF */
455             else
456                 drift = abuf->info.ts - (ng_get_timestamp() - start);
457         }
458         if (vfmt && NULL == vbuf) {
459             droptotal += drop;
460             vbuf = reader->rd_vdata(rhandle,drop);
461             if (conv)
462                 vbuf = ng_convert_frame(chandle,NULL,vbuf);
463             if (NULL != vbuf && 1 != args.slow)
464                 /* ts fixup for slow motion */
465                 vbuf->info.ts *= args.slow;
466             if (NULL == vbuf)
467                 vfmt = NULL; /* EOF */
468         }
469 
470         /* wait for events */
471         XFlush(dpy);
472         FD_ZERO(&rd);
473         FD_ZERO(&wr);
474         FD_SET(ConnectionNumber(dpy),&rd);
475         max = ConnectionNumber(dpy);
476         if (afmt) {
477             FD_SET(snd_fd,&wr);
478             if (snd_fd > max)
479                 max = snd_fd;
480         }
481         if (vfmt) {
482             /* check how long we have to wait until the next frame
483              * should be blitted to the screen */
484             now = ng_get_timestamp() - start;
485             if (afmt && latency) {
486                 /* sync video with audio track */
487                 now += drift;
488                 now -= latency;
489                 if (args.verbose)
490                     sync_info(drift-latency,droptotal,framecount);
491             }
492             delay = vbuf->info.ts - now;
493             if (delay < 0) {
494                 drop = -delay / reader->frame_time(rhandle);
495                 if (drop) {
496                     if (args.verbose)
497                         sync_info(drift-latency,droptotal,framecount);
498                 }
499                 wait.tv_sec  = 0;
500                 wait.tv_usec = 0;
501             } else {
502                 drop = 0;
503                 wait.tv_sec  = delay / 1000000000;
504                 wait.tv_usec = (delay / 1000) % 1000000;
505             }
506         } else {
507             wait.tv_sec  = 1;
508             wait.tv_usec = 0;
509         }
510         rc = select(max+1,&rd,&wr,NULL,&wait);
511         
512         if (afmt && FD_ISSET(snd_fd,&wr)) {
513             /* write audio data */
514             abuf = snd->write(shandle,abuf);
515         }
516         if (vfmt && 0 == rc) {
517             /* blit video frame */
518             blit_putframe(blit,vbuf);
519             framecount++;
520             vbuf = NULL;
521         }
522     }
523     return 0;
524 }
525 
  This page was automatically generated by the LXR engine.