comparison simpletv.c @ 1:769b155a34f9 SIMPETV_0_1

Initial revision
author darius
date Tue, 04 Jan 2005 05:17:43 +0000
parents
children 8d7d1680db7d
comparison
equal deleted inserted replaced
0:da66cf40a013 1:769b155a34f9
1 /* Capture and store a 24 bit RGB image as a PPM file */
2 /* Copyright (c) 2000 Randall Hopper
3 *
4 * Based on a grab.c from Roger Hardiman, which was
5 * based on an original program by Mark Tinguely and Jim Lowe .
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Mark Tinguely and Jim Lowe
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include <assert.h>
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <poll.h>
44 #include <sys/mman.h>
45 #include <sys/fcntl.h>
46 #include <sys/time.h>
47 #include <libgen.h>
48 #include <sys/soundcard.h>
49 #include <machine/ioctl_bt848.h>
50 #include <machine/ioctl_meteor.h>
51 #include <machine/param.h>
52 #include <sys/types.h>
53 #include <sys/ipc.h>
54 #include <sys/shm.h>
55 #include <X11/Xlib.h>
56 #include <X11/Xutil.h>
57 #include <X11/extensions/XShm.h>
58 #include <X11/extensions/Xvlib.h>
59 #ifndef USE_XVIMAGES
60 #include "Hermes/Hermes.h"
61 #endif
62
63 #include <lirc/lirc_client.h>
64
65 /* Some BT848/BT878 cards have gain control hardware which takes
66 1 or 2 seconds to settle. If you get a washed out / too bright
67 image, change the GRABBER_SETTLE_TIME from 0 to either 1 or 2
68 */
69 /*#define GRABBER_SETTLE_TIME 10*/
70 #define GRABBER_SETTLE_TIME 0
71
72
73 #define PAL 1
74 #define NTSC 2
75
76 /* PAL is 768 x 576. NTSC is 640 x 480 */
77 #define PAL_HEIGHT 576
78 #define NTSC_HEIGHT 480
79
80 int bktr_fd;
81 int tuner_fd;
82 unsigned char *bktr_buffer;
83 #if 1
84 int width = 320;
85 int height = 240;
86 #else
87 int width = 640;
88 int height = 480;
89 #endif
90
91 #ifndef USE_XVIMAGES
92 static XImage *rgb_image;
93 static Pixmap pmap;
94 #endif
95 static XShmSegmentInfo shminfo;
96 static Display *disp;
97 static Window win;
98 static Visual *vis;
99 static int scr;
100 static GC gc;
101 static int depth;
102 static Colormap cmap;
103 static XVisualInfo *vi;
104 static int bits_per_pixel;
105 static XvImage *yuv_image;
106 static XvAdaptorInfo *xv_adaptors;
107 static int xv_num_adaptors;
108 static int xv_adaptor;
109 static int xv_format_id;
110
111 static int channel;
112
113 #define DO_IOCTL_GERR(str) fprintf(stderr, "ioctl(%s) failed: %s\n", \
114 str, strerror(errno) )
115 #define DO_IOCTL_SERR(str,arg) fprintf(stderr, "ioctl(%s, %ld) failed: %s\n",\
116 str, (long)arg, strerror(errno) )
117 /*--------------------------------------------------------------------------*/
118
119 void Close()
120 {
121 close(tuner_fd);
122 close(bktr_fd);
123 }
124
125 void Open()
126 {
127 struct meteor_geomet geo;
128 int buffer_size, format, source, c;
129 char *device_name;
130
131 format = PAL; /* default value */
132 source = 1; /* default value */
133 device_name = "/dev/bktr0"; /* default value */
134
135 /* Open the Meteor or Bt848/Bt878 grabber */
136 if ((bktr_fd = open(device_name, O_RDONLY)) < 0) {
137 printf("open failed: %d\n", errno);
138 exit(1);
139 }
140
141 if ((tuner_fd = open("/dev/tuner0", O_RDONLY)) < 0) {
142 printf("open failed: %d\n", errno);
143 exit(1);
144 }
145
146 /* set up the capture type and size */
147 geo.rows = height;
148 geo.columns = width;
149 geo.frames = 1;
150 #ifdef USE_XVIMAGES
151 /* Should be YUV_12, but 422 actually gives a synced picture. Though */
152
153 /*geo.oformat = METEOR_GEO_YUV_12;*/
154 geo.oformat = METEOR_GEO_YUV_422 | METEOR_GEO_YUV_12;
155 /* geo.oformat = METEOR_GEO_YUV_12; */
156 #else
157 geo.oformat = METEOR_GEO_RGB24;
158 #endif
159
160 /* switch from interlaced capture to single field capture if */
161 /* the grab height is less than half the normal TV height */
162 /* this gives better quality captures when the object in the TV */
163 /* picture is moving */
164 if ((format == PAL) && (height <= (PAL_HEIGHT/2)))
165 geo.oformat |= METEOR_GEO_ODD_ONLY;
166 if ((format == NTSC) && (height <= (NTSC_HEIGHT/2)))
167 geo.oformat |= METEOR_GEO_ODD_ONLY;
168
169 if (ioctl(bktr_fd, METEORSETGEO, &geo) < 0) {
170 printf("METEORSETGEO ioctl failed: %d\n", errno);
171 exit(1);
172 }
173
174 /* Select PAL or NTSC */
175 switch (format) {
176 case PAL: c = METEOR_FMT_PAL; break;
177 case NTSC: c = METEOR_FMT_NTSC; break;
178 default: c = METEOR_FMT_NTSC; break;
179 }
180
181 c = BT848_IFORM_F_PALBDGHI;
182 if ( ioctl( bktr_fd, BT848SFMT, &c ) < 0 ) {
183 DO_IOCTL_SERR( "BT848SFMT", c );
184 return;
185 }
186 c = AUDIO_TUNER;
187 if ( ioctl( tuner_fd, BT848_SAUDIO, &c ) < 0 ) {
188 DO_IOCTL_SERR( "BT848SFMT", c );
189 return;
190 }
191 c = CHNLSET_AUSTRALIA;
192 if ( ioctl( tuner_fd, TVTUNER_SETTYPE, &c ) < 0 ) {
193 DO_IOCTL_SERR( "TVTUNER_SETTYPE", c );
194 return;
195 }
196
197 if ( ioctl( tuner_fd, TVTUNER_SETCHNL, &channel ) < 0 ) {
198 DO_IOCTL_SERR( "TVTUNER_SETCHNL", channel );
199 return;
200 }
201
202
203 /* Select the Video Source */
204 /* Video In, Tuner, S-Video */
205 switch (source) {
206 case 0: c = METEOR_INPUT_DEV0; break;
207 case 1: c = METEOR_INPUT_DEV1; break;
208 case 2: c = METEOR_INPUT_DEV2; break;
209 case 3: c = METEOR_INPUT_DEV3; break;
210 default: c = METEOR_INPUT_DEV0; break;
211 }
212
213 printf("Input - %x\n", c);
214 if (ioctl(bktr_fd, METEORSINPUT, &c) < 0) {
215 printf("ioctl failed: %d\n", errno);
216 exit(1);
217 }
218
219 /* Use mmap to Map the drivers grab buffer */
220 buffer_size = width*height*4; /* R,G,B,spare */
221 bktr_buffer = (unsigned char *)mmap((caddr_t)0,buffer_size,PROT_READ,
222 MAP_SHARED, bktr_fd, (off_t)0);
223
224 if (bktr_buffer == (unsigned char *) MAP_FAILED)
225 exit(1);
226
227
228 /* We may need to wait for a short time to allow the grabber */
229 /* brightness to settle down */
230 sleep(GRABBER_SETTLE_TIME);
231 }
232
233 /*--------------------------------------------------------------------------*/
234
235 void Capture()
236 {
237 int c;
238
239 /* Perform a single frame capture */
240 c = METEOR_CAP_SINGLE ;
241 ioctl(bktr_fd, METEORCAPTUR, &c);
242 }
243
244 /*--------------------------------------------------------------------------*/
245
246 void SaveImage()
247 {
248 unsigned char *line_buffer;
249 int o,w,h;
250 unsigned char *p;
251 unsigned char header[30];
252 char *filename = "t.ppm" /* argv[3] */;
253
254 /* Create the output file */
255 if ((o = open(filename, O_WRONLY | O_CREAT, 0644)) < 0) {
256 printf("ppm open failed: %d\n", errno);
257 exit(1);
258 }
259
260 /* make PPM header and save to file */
261 sprintf(header, "P6\n%d\n%d\n255\n",width,height);
262 write (o, header, strlen(header));
263
264 /* save the RGB data to PPM file */
265 /* save this one line at a time */
266 line_buffer =(unsigned char *)malloc( width *3 * sizeof(unsigned char));
267 p = bktr_buffer;
268 for (h = 0; h < height; h++) {
269 for (w = 0; w < width; w++) {
270 line_buffer[(w*3) + 2] = *p++; /* blue */
271 line_buffer[(w*3) + 1] = *p++; /* green */
272 line_buffer[(w*3) + 0] = *p++; /* red */
273 p++; /* NULL byte */
274 }
275 write(o,line_buffer, width*3);
276 }
277 close(o);
278 free(line_buffer);
279 }
280
281 void X_ShowCursor(void) {
282 XDefineCursor(disp, win, 0);
283 }
284
285 void X_HideCursor(void) {
286 Cursor no_ptr;
287 Pixmap bm_no;
288 XColor black,dummy;
289 Colormap colormap;
290 static unsigned char bm_no_data[] = {0,0,0,0, 0,0,0,0};
291
292 colormap = DefaultColormap(disp, DefaultScreen(disp));
293 XAllocNamedColor(disp, colormap, "black", &black, &dummy);
294 bm_no = XCreateBitmapFromData(disp, win, bm_no_data, 8, 8);
295 no_ptr = XCreatePixmapCursor(disp, bm_no, bm_no, &black, &black, 0, 0);
296
297 XDefineCursor(disp, win, no_ptr);
298 XFreeCursor(disp, no_ptr);
299 if (bm_no != None)
300 XFreePixmap(disp, bm_no);
301
302 }
303
304 /*
305 * Sends the EWMH fullscreen state event.
306 *
307 * action: could be on of _NET_WM_STATE_REMOVE -- remove state
308 * _NET_WM_STATE_ADD -- add state
309 * _NET_WM_STATE_TOGGLE -- toggle
310 */
311 #define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
312 #define _NET_WM_STATE_ADD 1 /* add/set property */
313 #define _NET_WM_STATE_TOGGLE 2 /* toggle property */
314 void
315 vo_x11_ewmh_fullscreen(int action) {
316 XEvent xev;
317
318 assert(action == _NET_WM_STATE_REMOVE ||
319 action == _NET_WM_STATE_ADD || action == _NET_WM_STATE_TOGGLE);
320
321
322 /* init X event structure for _NET_WM_FULLSCREEN client msg */
323 xev.xclient.type = ClientMessage;
324 xev.xclient.serial = 0;
325 xev.xclient.send_event = True;
326 xev.xclient.message_type = XInternAtom(disp, "_NET_WM_STATE", False);
327 xev.xclient.window = win;
328 xev.xclient.format = 32;
329 xev.xclient.data.l[0] = action;
330 xev.xclient.data.l[1] = XInternAtom(disp, "_NET_WM_STATE_FULLSCREEN", False);
331 xev.xclient.data.l[2] = 0;
332 xev.xclient.data.l[3] = 0;
333 xev.xclient.data.l[4] = 0;
334
335 /* finally send that damn thing */
336 if (!XSendEvent(disp, DefaultRootWindow(disp), False,
337 SubstructureRedirectMask | SubstructureNotifyMask,
338 &xev)) {
339 fprintf(stderr, "Failed to send fullscreen command\n");
340 }
341 }
342
343
344 void X_Setup(int w,int h)
345 {
346 XGCValues gcvals;
347 Window root;
348 XVisualInfo vinfo_pref;
349 int num_vis;
350 XPixmapFormatValues *pf;
351 int num_pf, pfi, i,j;
352
353 disp = XOpenDisplay(NULL);
354 if (!disp) {
355 fprintf(stderr,"X-Error: unable to connect to display\n");
356 exit(1);
357 }
358
359 XSynchronize( disp, True );
360
361 scr=DefaultScreen(disp);
362 vis=DefaultVisual(disp,scr);
363 root=DefaultRootWindow(disp);
364 depth=DefaultDepth(disp,scr);
365
366 vinfo_pref.screen = scr;
367 vinfo_pref.visualid = XVisualIDFromVisual( vis );
368 vi = XGetVisualInfo( disp, VisualScreenMask | VisualIDMask,
369 &vinfo_pref, &num_vis );
370 assert ( num_vis == 1 );
371
372 win = XCreateSimpleWindow(disp, root, 0, 0, w, h, 0, 0, 0);
373 gc = XCreateGC(disp, win, (unsigned long)0, &gcvals);
374 XSetForeground(disp, gc, 0);
375 XSetBackground(disp, gc, 1);
376
377 XMapWindow(disp,win);
378 cmap = DefaultColormap(disp, scr);
379 XSync(disp,False);
380
381 /* Setup with Xv extension */
382 xv_adaptor = -1;
383 xv_format_id = -1;
384 XvQueryAdaptors( disp, root, &xv_num_adaptors, &xv_adaptors );
385 for ( i = 0; i < xv_num_adaptors; i++ ) {
386 XvAdaptorInfo *adaptor = &xv_adaptors[i];
387 int takes_images;
388
389 takes_images = adaptor->type & ( XvInputMask | XvImageMask );
390 if ( takes_images ) {
391 XvImageFormatValues *formats;
392 int num_formats;
393
394 formats = XvListImageFormats( disp, adaptor->base_id, &num_formats );
395 for ( j = 0; j < num_formats; j++ )
396 if ( formats[j].type == XvYUV && formats[j].format == XvPlanar &&
397 strcmp( formats[j].guid, "YV12" ) == 0 )
398 break;
399 if ( j < num_formats ) {
400 xv_adaptor = i;
401 xv_format_id = formats[j].id;
402 break;
403 }
404 }
405 }
406 assert( xv_adaptor >= 0 );
407
408 /* Create an image to captured frames */
409 #ifdef USE_XVIMAGES
410 yuv_im age = XvShmCreateImage( disp, xv_adaptors[xv_adaptor].base_id,
411 xv_format_id, 0, w, h, &shminfo );
412 if (!yuv_image)
413 fprintf(stderr,"X-Error: unable to create XvShm XImage\n");
414
415 shminfo.shmid = shmget( IPC_PRIVATE, yuv_image->data_size, IPC_CREAT|0777);
416 if (shminfo.shmid == -1)
417 fprintf(stderr,"SharedMemory Error: unable to get identifier\n");
418
419 shminfo.shmaddr = yuv_image->data = shmat(shminfo.shmid, 0, 0);
420 #else
421 rgb_image = XShmCreateImage( disp, vis, depth, ZPixmap, NULL, &shminfo, w, h);
422 if (!rgb_image)
423 fprintf(stderr,"X-Error: unable to create XShm XImage\n");
424
425 shminfo.shmid = shmget( IPC_PRIVATE,
426 rgb_image->bytes_per_line * rgb_image->height,
427 IPC_CREAT|0777);
428 if (shminfo.shmid == -1)
429 fprintf(stderr, "SharedMemory Error: unable to get identifier\n");
430
431 shminfo.shmaddr = rgb_image->data = shmat(shminfo.shmid, 0, 0);
432 #endif
433
434 if(!XShmAttach( disp,&shminfo ))
435 fprintf(stderr,"X-Error: unable to attach XShm Shared Memory Segment\n");
436
437 /* Create a pixmap for the window background */
438 #ifdef OLD
439 pmap = XShmCreatePixmap(disp, win, shminfo.shmaddr, &shminfo, w, h, depth);
440 if (!pmap)
441 fprintf(stderr,"Unable to create pixmap\n");
442 #endif
443
444 /* Determine bits-per-pixel for pixmaps */
445 pf = XListPixmapFormats( disp, &num_pf);
446 assert(pf);
447 for (pfi = 0; pfi < num_pf; pfi++)
448 if (pf[pfi].depth == vi->depth)
449 break;
450 assert(pfi < num_pf);
451 bits_per_pixel = pf[pfi].bits_per_pixel;
452 XFree (pf);
453
454 #ifdef OLD
455 XSetWindowBackgroundPixmap(disp,win,pmap);
456 #endif
457 }
458
459 /*--------------------------------------------------------------------------*/
460
461 void X_Shutdown()
462 {
463 XShmDetach( disp, &shminfo );
464 #ifdef USE_XVIMAGES
465 # warning How do we destroy an XvImage?
466 #else
467 XDestroyImage( rgb_image );
468 #endif
469 shmdt( shminfo.shmaddr );
470 shmctl( shminfo.shmid, IPC_RMID, 0 );
471 }
472
473
474 /*--------------------------------------------------------------------------*/
475
476 void X_Display(void)
477 {
478 int _w,_h,_d;
479 Window _dw;
480
481 #ifdef USE_XVIMAGES
482 XGetGeometry( disp, win, &_dw, &_d, &_d, &_w, &_h, &_d, &_d);
483 XvShmPutImage( disp, xv_adaptors[ xv_adaptor ].base_id, win,
484 gc, yuv_image, 0, 0, yuv_image->width, yuv_image->height,
485 0, 0, _w, _h, True );
486 #else
487 XShmPutImage( disp, win, gc, rgb_image, 0,0,0,0,
488 rgb_image->width, rgb_image->height, False );
489 #endif
490 XSync(disp, False);
491 }
492
493 #define CMD_NONE 0
494 #define CMD_CHNUP 1
495 #define CMD_CHNDN 2
496 #define CMD_MUTE 3
497 #define CMD_QUIT 4
498 #define CMD_RELOAD 5
499 #define CMD_CURSOR 6
500 #define CMD_VOLDN 7
501 #define CMD_VOLUP 8
502 #define CMD_FSTOGGLE 9
503
504 /*--------------------------------------------------------------------------*/
505
506 int main(int argc, char *argv[]) {
507 #ifndef USE_XVIMAGES
508 HermesHandle conv;
509 HermesFormat fmt_source,fmt_dest;
510 #endif
511 XEvent e;
512 char *scratch_buf, *code, *c, *mixerdev;
513 int frames, channelidx, oldchan, mute, cursor, fd, ret, cmd;
514 int exitnow, mfd, uselirc, curvol;
515 struct timeval then, now, diff, lastmove;
516 float rate;
517 KeySym key;
518 char text[255];
519 int channellist[] = { 2, 7, 9, 10, 28 };
520 struct lirc_config *config;
521 struct pollfd fds[1];
522
523 #define NUMCHANS (sizeof(channellist) / sizeof(channellist[0]))
524
525 channelidx = mute = cursor = 0;
526
527 oldchan = channel = channellist[channelidx];
528
529 #ifndef USE_XVIMAGES
530 if (!Hermes_Init()) {
531 printf("Couldn't initialise Hermes!\n");
532 exit(1);
533 }
534
535 conv=Hermes_ConverterInstance(HERMES_CONVERT_NORMAL);
536 if (!conv) {
537 printf("Could not obtain converter instance from Hermes!\n");
538 exit(1);
539 }
540 #endif
541
542 X_Setup(width, height);
543 XSelectInput(disp, win, KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
544
545 X_HideCursor();
546
547 /* Open Capture device */
548 Open();
549
550 /* Open audio mixer */
551 mixerdev = "/dev/mixer";
552 if ((mfd = open(mixerdev, O_RDWR)) == -1)
553 fprintf(stderr, "Unable to open %s - %s\n", mixerdev, strerror(errno));
554
555 /* Talk to LIRC */
556 if ((fd = lirc_init(basename(argv[0]), 1)) == -1) {
557 fprintf(stderr, "Unable to init lirc client library\n");
558 uselirc = 0;
559 } else {
560 if (lirc_readconfig(NULL, &config, NULL) != 0) {
561 fprintf(stderr, "Unable to parse config file\n");
562 uselirc = 0;
563 } else
564 uselirc = 1;
565 fds[0].fd = fd;
566 fds[0].events = POLLRDNORM;
567 }
568
569 #ifndef USE_XVIMAGES
570 /* Conversion from and to formats */
571 fmt_source.indexed=0;
572 fmt_source.bits=32;
573 fmt_source.r=0xff0000;
574 fmt_source.g=0x00ff00;
575 fmt_source.b=0x0000ff;
576 fmt_source.a=0;
577
578 fmt_dest.indexed=0;
579 fmt_dest.bits=bits_per_pixel;
580 fmt_dest.r=vi->red_mask;
581 fmt_dest.g=vi->green_mask;
582 fmt_dest.b=vi->blue_mask;
583 fmt_dest.a=0;
584 #else
585 scratch_buf = malloc(width * height);
586 #endif
587
588 frames = 0;
589 gettimeofday(&then, NULL);
590 gettimeofday(&lastmove, NULL);
591
592 exitnow = 0;
593
594 /* Capture loop */
595 while (1) {
596 if (frames == 50) {
597 gettimeofday(&now, NULL);
598 timersub(&now, &then, &diff);
599
600 rate = (float)frames / (float)(diff.tv_usec / 1000000.0 + diff.tv_sec);
601
602 printf("%d frames in %.2f seconds, rate %.2f\n", frames, (float)(diff.tv_usec / 1000000.0) + diff.tv_sec, rate);
603 gettimeofday(&then, NULL);
604 frames = 0;
605 XResetScreenSaver(disp);
606 }
607 frames++;
608
609 timersub(&now, &lastmove, &diff);
610 if (((float)diff.tv_usec / 1000000.0 + (float)diff.tv_sec) > 2.0) {
611 if (cursor) {
612 X_HideCursor();
613 cursor = 0;
614 }
615 } else {
616 if (!cursor) {
617 X_ShowCursor();
618 cursor = 1;
619 }
620 }
621
622 if (XCheckMaskEvent(disp, PointerMotionMask, &e) && e.type == MotionNotify) {
623 gettimeofday(&lastmove, NULL);
624 }
625
626 cmd = CMD_NONE;
627
628 if (XCheckMaskEvent(disp, ButtonReleaseMask, &e)) {
629 printf("e.type = %d\n", e.type);
630 cmd = CMD_MUTE;
631 }
632
633 if (XCheckMaskEvent(disp, KeyReleaseMask, &e) && e.type == KeyRelease) {
634 gettimeofday(&lastmove, NULL);
635
636 XLookupString(&e.xkey, text, 255, &key, 0);
637 printf("Press - %c\n", text[0]);
638
639 switch (text[0]) {
640 case 'q':
641 cmd = CMD_QUIT;
642 break;
643
644 case '=':
645 case '+':
646 cmd = CMD_CHNUP;
647 break;
648
649 case '-':
650 cmd = CMD_CHNDN;
651 break;
652
653 case 'h':
654 cmd = CMD_CURSOR;
655 break;
656
657 case 'm':
658 cmd = CMD_MUTE;
659 break;
660
661 case 'r':
662 cmd = CMD_RELOAD;
663 break;
664
665 case ',':
666 cmd = CMD_VOLDN;
667 break;
668
669 case '.':
670 cmd = CMD_VOLUP;
671 break;
672
673 case 'f':
674 cmd = CMD_FSTOGGLE;
675 break;
676 }
677 }
678
679 /* Poll for IR events */
680 if (uselirc) {
681 fds[0].revents = 0;
682
683 while (1) {
684 if (poll(fds, 1, 0) == -1) {
685 fprintf(stderr, "Poll failed - %s\n", strerror(errno));
686 exit(EXIT_FAILURE);
687 }
688 if ((fds[0].revents & POLLRDNORM) != 0) {
689 fprintf(stderr, "Processing IR..\n");
690
691 if (lirc_nextcode(&code) == 0) {
692 if(code == NULL)
693 continue;
694
695 while ((ret = lirc_code2char(config, code, &c)) == 0 &&
696 c != NULL) {
697 fprintf(stderr, "Got command \"%s\"\n", c);
698
699 if (!strcmp(c, "Mute"))
700 cmd = CMD_MUTE;
701 else if (!strcmp(c, "CH_UP"))
702 cmd = CMD_CHNUP;
703 else if (!strcmp(c, "CH_DOWN"))
704 cmd = CMD_CHNDN;
705 else if (!strcmp(c, "Power"))
706 cmd = CMD_QUIT;
707 else if (!strcmp(c, "VOL_UP"))
708 cmd = CMD_VOLUP;
709 else if (!strcmp(c, "VOL_DOWN"))
710 cmd = CMD_VOLDN;
711 else if (!strcmp(c, "AV/TV"))
712 cmd = CMD_FSTOGGLE;
713
714 free(code);
715 }
716 }
717 } else
718 break;
719 }
720 }
721
722 switch (cmd) {
723 case CMD_QUIT:
724 exitnow = 1;
725 break;
726
727 case CMD_CHNUP:
728 case CMD_CHNDN:
729 if (cmd == CMD_CHNUP)
730 channelidx++;
731 else
732 channelidx--;
733
734 if (channelidx < 0)
735 channelidx = NUMCHANS - 1;
736 if (channelidx > NUMCHANS - 1)
737 channelidx = 0;
738
739 channel = channellist[channelidx];
740
741 printf("Channel - %d\n", channel);
742 if (oldchan != channel) {
743 oldchan = channel;
744
745 if ( ioctl( tuner_fd, TVTUNER_SETCHNL, &channel ) < 0 ) {
746 DO_IOCTL_SERR( "TVTUNER_SETCHNL", channel );
747 exit(1);
748 }
749 }
750 break;
751
752 case CMD_MUTE:
753 if (mute)
754 mute = 0;
755 else
756 mute = 1;
757
758 printf("Mute - %d\n", mute);
759 if (ioctl(tuner_fd, BT848_SAUDIO, &mute) < 0) {
760 DO_IOCTL_SERR("BT848_SAUDIO", mute);
761 exit(1);
762 }
763 break;
764
765 case CMD_CURSOR:
766 if (cursor) {
767 printf("Cursor hidden\n");
768 X_HideCursor();
769 cursor = 0;
770 } else {
771 printf("Cursor revealed\n");
772 X_ShowCursor();
773 cursor = 1;
774 }
775 break;
776
777 case CMD_RELOAD:
778 printf("Reloading\n");
779 Close();
780 Open();
781 break;
782
783 case CMD_VOLUP:
784 case CMD_VOLDN:
785 if (ioctl(mfd, MIXER_READ(SOUND_MIXER_VOLUME), &curvol) == -1) {
786 fprintf(stderr, "Unable to read current volume - %s\n", strerror(errno));
787 break;
788 }
789
790 curvol = curvol & 0x7f;
791
792 if (cmd == CMD_VOLUP)
793 curvol += 5;
794 else
795 curvol -= 5;
796
797 if (curvol < 0)
798 curvol = 0;
799 if (curvol > 100)
800 curvol = 100;
801
802 printf("Setting volume to %d\n", curvol);
803 curvol |= curvol << 8;
804
805 if (ioctl(mfd, MIXER_WRITE(SOUND_MIXER_VOLUME), &curvol) == -1) {
806 fprintf(stderr, "Unable to write volume - %s\n", strerror(errno));
807 break;
808 }
809 break;
810
811 case CMD_FSTOGGLE:
812 vo_x11_ewmh_fullscreen(_NET_WM_STATE_TOGGLE);
813 break;
814
815 }
816
817 Capture();
818
819 #ifdef USE_XVIMAGES
820 /* bktr's YUV_12 is planar W*H bytes Y, W/2*H/2 bytes U, */
821 /* W/2*H/2 bytes V. Xv's YV12 is the same with U and V */
822 /* planes reversed. */
823 {
824 int y_off, u_off, v_off;
825 y_off = 0;
826 u_off = width * height;
827 v_off = u_off + width*height/4;
828
829 assert(yuv_image->data_size == width * height * 3 / 2 );
830 memcpy(yuv_image->data , bktr_buffer , u_off-y_off );
831 memcpy(yuv_image->data + u_off, bktr_buffer + v_off, v_off-u_off );
832 memcpy(yuv_image->data + v_off, bktr_buffer + u_off, v_off-u_off );
833 }
834 #else
835 /*SaveImage();*/
836
837 Hermes_ConverterRequest(conv,&fmt_source,&fmt_dest);
838 Hermes_ConverterCopy(conv,bktr_buffer,0,0,width,height,width*4,
839 rgb_image->data,0,0,width,height,
840 rgb_image->bytes_per_line);
841 #endif
842
843 X_Display();
844 if (exitnow) {
845 printf("quitting\n");
846 break;
847 }
848 }
849
850 #ifndef USE_XVIMAGES
851 Hermes_ConverterReturn(conv);
852 Hermes_Done();
853 #endif
854
855 X_Shutdown();
856 lirc_freeconfig(config);
857 lirc_deinit();
858
859 return 0;
860 }