/* Copyright (c) 1999 Wee Liang (wliang@tartarus.uwa.edu.au) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING); if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ /* Includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "wmgeneral/wmgeneral.h" #include "wmtv-master.xpm" #include "channels.h" /* Defines */ #define ON 1 #define OFF 0 #define NTFB 0 /* On/SetTune/Off Button */ #define SCANLB 1 /* Scan Left Button */ #define SCANRB 2 /* Scan Right Button */ #define FULLSB 3 /* Full Screen Toggle Button */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define SETON 0 #define SETOFF 1 #define SETUNE 2 #define SETSPD 3 #define MAXCHAN 99 #define OPTIONS "hvd:g:e:b:c:" #define TELEVISION 0 #define COMPOSITE 1 #define SVIDEO 2 #ifndef GLOBALCONFFILE #define GLOBALCONFFILE "/etc/wmtvrc" #endif /* Global Variables */ Display *display; int tfd; int card_present = FALSE; int ntfb_status = SETOFF; char *maxpreset = NULL; char **chan = NULL; int mode_present = FALSE; int chn = 0; int aud = 0; int tpst = 0; int cchannel = 0; int timebutton = 0; int tvsource = 0; int ccapt; int norcfile = 0; int ic = 0; int cnotune = 0; int vsource = 0; int isource = 0; int compchannel = 0; int vidmode = 0; int fmode = 0; int mute = 0; int dcret; int tml; int fswidth = 0; int fsheight = 0; pid_t child_pid = -1; int restart = FALSE; unsigned long ccrfreq; unsigned long rfreq; unsigned long st; char *norm = NULL; char *source; char *mode = NULL; char *fullscreen = NULL; int freqnorm = -1; char *cname[MAXCHAN]; char *comment[MAXCHAN]; long ftune[MAXCHAN]; char *progname; char *dev = "/dev/video"; char *sysConfFile = GLOBALCONFFILE; char *usrConfFile; int wmtv_mask_width = 64; int wmtv_mask_height = 64; char wmtv_mask_bits[64*64]; int btime = 0; int but_pressed = FALSE; int but_clicked = FALSE; int maxpst; int x_lc; int y_lc; Time t_lc; rckeys wmtv_keys[] = { { "freqnorm", &norm }, { "source", &source }, { "maxpreset", &maxpreset }, { "mode", &mode }, { "fullscreen", &fullscreen }, { NULL, NULL } }; XEvent Event; XWindowAttributes Winattr; Window fmwin; GC fmGC; XF86VidModeModeInfo **modelines, *fullscreenmode = NULL; XF86VidModeModeLine scmode; struct video_capability vcap; struct video_buffer vfb; struct video_window vwin; struct video_window vswin; struct video_channel vchn, vchns; struct video_picture vpic; struct video_tuner vtun; struct video_audio vaud; struct video_mbuf vmbuf; struct video_mmap vmmap; struct video_clip vclip[2]; struct video_clip vclip2[2]; /* Function prototypes */ void TVOn(void); void TVOff(void); void TuneTV(void); void ChanUp(void); void ChanDown(void); void FineTuneUp(void); void FineTuneDown(void); void ScanUp(void); void ScanDown(void); void ButtonUp(int); void ButtonDown(int); void Capture(void); void MuteAudio(void); void UnMuteAudio(void); void VolumeUp(void); void VolumeDown(void); void DrawPresetChan(int); void DoFullScreen(void); void GetFrameBuffer(void); void RetScreen(void); void GrabImage(void); void ParseRCFile(const char *, rckeys *); void ParseRCFile2(const char *); void WriteRCFile(const char *, rckeys *); void InitConfig(void); void InitPalette(void); void Usage(void); void Version(void); void sigchld_handler(int i) { pid_t pid; pid = waitpid((pid_t)-1, NULL, WNOHANG); while (pid>(pid_t)0) { if (pid == child_pid) { child_pid = -1; restart = TRUE; } pid = waitpid((pid_t)-1, NULL, WNOHANG); } } void init_signal() { struct sigaction sa; sa.sa_handler = &sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGCHLD, &sa, NULL); } char * expand_format(char *format, char *letters, char **expansions) { char *string; unsigned int string_pos = 0; unsigned int size; size = strlen(format)+1; string = (char *)malloc(size*sizeof(char)); for (; *format != '\0'; format++) { if (*format == '%') { format++; if (*format != '%') { unsigned int i; for (i = 0; letters[i] != '\0'; i++) { if (letters[i] == *format) break; } if (letters[i] != '\0') { unsigned int expansion_size; expansion_size = strlen(expansions[i]); while (string_pos+expansion_size+1 > size) { size *= 2; string = realloc(string, size*sizeof(char)); } memcpy(string+string_pos, expansions[i], expansion_size); string_pos += expansion_size; continue; } else { format--; } } } while (string_pos+1+1 > size) { size *= 2; string = realloc(string, size*sizeof(char)); } string[string_pos] = *format; string_pos++; } string[string_pos] = '\0'; return string; } /* main function */ int main(int argc, char *argv[]) { int c, opind; int pressed_button = -1; /* pid_t pid; */ static struct option long_options[] = { {"device", 1, 0, 'c'}, {"display", 1, 0, 'd'}, {"geometry", 1, 0, 'g'}, {"bpp", 1, 0, 'b'}, {"exe", 1, 0, 'e'}, {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {0, 0, 0, 0} }; progname = strdup(argv[0]); { char *home = getenv("HOME"); if (home == NULL) { fprintf(stderr, "wmtv: $HOME should be set.\n"); exit(1); } usrConfFile = (char *)malloc(sizeof(char)*(strlen(home)+8+1)); strcpy(usrConfFile, home); strcat(usrConfFile, "/.wmtvrc"); } while (1) { opind = 0; c = getopt_long (argc, argv, OPTIONS, long_options, &opind); if (c == -1) break; switch(c) { case 0: /* fprintf(stderr, "wmtv: option - %s", long_options[opind].name); if (optarg) fprintf(stderr, " with arg %s", optarg); printf("\n"); */ break; case 'd': display_name = strdup(optarg); break; case 'g': geometry = strdup(optarg); break; case 'e': exe = strdup(optarg); /* strcat(exe, " &"); */ break; case 'c': dev = strdup(optarg); break; case 'b': fprintf(stderr, "wmtv: option not implemented yet\n"); Usage(); exit(1); break; case 'v': Version(); exit(0); break; default: Usage(); exit(1); } } /* creat windows */ createXBMfromXPM (wmtv_mask_bits, wmtv_master_xpm, wmtv_mask_width, wmtv_mask_height); openXwindow (argc, argv, wmtv_master_xpm, wmtv_mask_bits, wmtv_mask_width, wmtv_mask_height); AddMouseRegion (NTFB, 47, 48, 59, 59); /* On/SetTune/Off Button */ AddMouseRegion (SCANLB, 23, 48, 35, 59); /* Left Preset/Scan Button */ AddMouseRegion (SCANRB, 35, 48, 47, 59); /* Right Preset/Scan Button */ AddMouseRegion (FULLSB, 5, 5, 59, 44); /* Toggle FullScreen */ init_signal(); /* wmtv main loop */ while (1) { if (restart) { TVOn(); if (ntfb_status == SETOFF) { ntfb_status = SETON; RedrawWindow(); XFlush(display); } restart = FALSE; continue; } while (XPending(display)) { XNextEvent(display, &Event); switch (Event.type) { case Expose: RedrawWindow(); break; case DestroyNotify: XCloseDisplay(display); ccapt = 0; if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) { perror("ioctl VIDIOCCAPTURE"); } close(tfd); usleep(50000L); exit(0); break; case ButtonPress: if ((Event.xany.window == fmwin) && fmode) { RetScreen(); } else { pressed_button = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y); switch (pressed_button) { case NTFB: ButtonDown(NTFB); t_lc = Event.xbutton.time; but_pressed = TRUE; break; case SCANLB: ButtonDown(SCANLB); if (ntfb_status == SETUNE) { switch (Event.xbutton.button) { case 1: timebutton = 1; while (timebutton == 1) if (isource == TELEVISION) ScanDown(); break; case 3: if (isource == TELEVISION) FineTuneDown(); break; } } else if (ntfb_status == SETON) ChanDown(); break; case SCANRB: ButtonDown(SCANRB); if (ntfb_status == SETUNE) { switch (Event.xbutton.button) { case 1: timebutton = 1; while (timebutton) if (isource == TELEVISION) ScanUp(); break; case 3: if (isource == TELEVISION) FineTuneUp(); break; } } else if (ntfb_status == SETON) ChanUp(); break; case FULLSB: ButtonDown(FULLSB); switch (Event.xbutton.button) { case 1: but_pressed = TRUE; break; case 2: but_pressed = TRUE; break; case 3: if (!mute) { MuteAudio(); } else { UnMuteAudio(); } break; } break; } RedrawWindow(); } break; case ButtonRelease: switch (pressed_button) { case NTFB: ButtonUp(NTFB); if (but_pressed) { if (Event.xbutton.time - t_lc >= 900) { btime = TRUE; but_pressed = FALSE; } } if (ntfb_status == SETOFF) { if (child_pid == -1) { ntfb_status = SETON; TVOn(); } } else if (ntfb_status == SETON) { if (!btime) { ntfb_status = SETUNE; copyXPMArea(96, 79, 11, 7, 6, 50); RedrawWindowXYWH(6, 50, 11, 7); } else if (btime) { ntfb_status = SETOFF; btime = FALSE; ic = TRUE; TVOff(); } } else if (ntfb_status == SETUNE) { if (!btime) { ftune[cchannel] = (rfreq - ccrfreq); /* fprintf(stderr, "wmtv: finetune offset = %ld\n", ftune[cchannel]); */ WriteRCFile(usrConfFile, wmtv_keys); ntfb_status = SETON; DrawPresetChan(cchannel); } else if (btime) { ntfb_status = SETOFF; btime = FALSE; ic = TRUE; TVOff(); } } break; case SCANLB: ButtonUp(SCANLB); if (ntfb_status == SETUNE) timebutton = 0; break; case SCANRB: ButtonUp(SCANRB); if (ntfb_status == SETUNE) timebutton = 0; break; case FULLSB: ButtonUp(FULLSB); switch (Event.xbutton.button) { case 1: { if (but_clicked) { but_pressed = FALSE; but_clicked = FALSE; if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) ) { if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) { if (exe) { pid_t pid; char *command; char *letters = "#nf"; char *(expansions[3]); ntfb_status = SETOFF; TVOff(); expansions[0] = malloc(3*sizeof(char)); snprintf(expansions[0], 3, "%d", cchannel+1); expansions[1] = comment[cchannel]; expansions[2] = malloc(15*sizeof(char)); snprintf(expansions[2], 15, "%.3f", (double)rfreq/(double)st); command = expand_format(exe, letters, expansions); /* system(exe); */ child_pid = fork(); if (child_pid == (pid_t) 0) { char *argv[4]; argv[0] = "sh"; argv[1] = "-c"; argv[2] = command; argv[3] = NULL; execv("/bin/sh", argv); exit(-1); } free(expansions[0]); free(expansions[2]); free(command); pid = waitpid(child_pid, NULL, WNOHANG); if (pid != 0) { child_pid = -1; restart = TRUE; } /* printf("Returned pid:\n"); */ #if 0 pid = fork(); /* child */ if (pid == (pid_t) 0) { execlp("xawtv", "xawtv", "&", (char *) 0); } else if (pid < (pid_t) 0) { perror("fork"); } /* parent */ else { if (waitpid(pid, NULL, 0) < 0) { perror("waitpid"); #endif } else { DoFullScreen(); } } } } if (but_pressed) { t_lc = Event.xbutton.time; x_lc = Event.xbutton.x; y_lc = Event.xbutton.y; but_clicked = TRUE; but_pressed = FALSE; } } break; case 2: { if (but_clicked) { but_pressed = FALSE; but_clicked = FALSE; if (((Event.xbutton.time - t_lc) <= 500) && (abs(Event.xbutton.x - x_lc) <= 10) && (abs(Event.xbutton.y - y_lc) <= 10) ) { if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) { DoFullScreen(); } } } if (but_pressed) { t_lc = Event.xbutton.time; x_lc = Event.xbutton.x; y_lc = Event.xbutton.y; but_clicked = TRUE; but_pressed = FALSE; } } break; case 3: break; } break; } RedrawWindow(); break; case VisibilityNotify: switch(Event.xvisibility.state) { case VisibilityFullyObscured: ccapt = 0; if (tfd && (ntfb_status != SETOFF) && !fmode) { if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) { perror("ioctl VIDIOCCAPTURE"); } } break; case VisibilityPartiallyObscured: ccapt = 0; if (tfd && (ntfb_status != SETOFF) && !fmode) { if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) { perror("ioctl VIDIOCCAPTURE"); } } break; case VisibilityUnobscured: ccapt = 1; if (tfd && (ntfb_status != SETOFF) && !fmode) { if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) { perror("ioctl VIDIOCCAPTURE"); } } break; } RedrawWindow(); break; case KeyPress: if ((Event.xany.window == fmwin) && fmode) { switch(XkbKeycodeToKeysym(display, Event.xkey.keycode, 0, 0)) { case XK_Up: if (isource == TELEVISION) ChanUp(); break; case XK_Down: if (isource == TELEVISION) ChanDown(); break; case XK_Right: VolumeUp(); break; case XK_Left: VolumeDown(); break; case XK_m: if (!mute) { MuteAudio(); } else { UnMuteAudio(); } break; case XK_Escape: RetScreen(); break; default: break; } } default: break; } XFlush(display); } usleep(50000L); } return(0); } /* ButtonDown function */ void ButtonDown(int button) { switch (button) { case NTFB: copyXPMArea(79, 100, 12, 11, 47, 48); RedrawWindowXYWH (47, 48, 12, 11); break; case SCANLB: copyXPMArea(55, 100, 12, 11, 23, 48); RedrawWindowXYWH(35, 48, 12, 11); break; case SCANRB: copyXPMArea(67, 100, 12, 11, 35, 48); RedrawWindowXYWH(35, 48, 12, 11); break; case FULLSB: break; } } /* ButtonUp function */ void ButtonUp(int button) { switch (button) { case NTFB: copyXPMArea(79, 88, 12, 11, 47, 48); RedrawWindowXYWH(47, 48, 12, 11); break; case SCANLB: copyXPMArea(55, 88, 12, 11, 23, 48); RedrawWindowXYWH(23, 48, 12, 11); break; case SCANRB: copyXPMArea(67, 88, 12, 11, 35, 48); RedrawWindowXYWH(35, 48, 12, 11); break; case FULLSB: break; } } /* TVOn function */ void TVOn(void) { int i; Window junkwin; int rx, ry; char *p; XWindowAttributes winattr; if (!XGetWindowAttributes (display, iconwin, &winattr)) { fprintf(stderr, "wmtv: error getting winattr of iconwin\n"); } if (!XTranslateCoordinates(display, iconwin, winattr.root, -winattr.border_width, -winattr.border_width, &rx, &ry, &junkwin)) { fprintf(stderr, "wmtv: error translating coordinates\n"); } /* This part was taken from xawtv's source code */ switch (system("v4l-conf -q")) { case -1: /* can't run */ fprintf(stderr,"could'nt start v4l-conf\n"); break; case 0: /* ok */ break; default: /* non-zero return */ fprintf(stderr,"v4l-conf had some trouble, " "trying to continue anyway\n"); } /* End of "stolen" part */ InitConfig(); GetFrameBuffer(); InitPalette(); ccapt = 1; vwin.x = rx; vwin.y = ry + 5; vwin.width = 64; vwin.height = 39; vclip[0].x = 0; /* Clipping Rect 1 */ vclip[0].y = 0; vclip[0].width = 5; vclip[0].height = 39; vclip[1].x = 59; /* Clipping Rect 2 */ vclip[1].y = 0; vclip[1].width = 5; vclip[1].height = 39; vwin.clips = vclip; vwin.clipcount = 2; vchn.channel = tvsource; vaud.audio = tvsource; if (source) { p = source; if (*p == 'T') isource = TELEVISION; else if (*p == 'C') { isource = COMPOSITE; while (isalpha(*p)) ++p; compchannel = atoi(p); } else if (*p == 'S') isource = SVIDEO; } if (!cnotune) { if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) perror("ioctl VIDIOCGTUNER"); if (vtun.flags & VIDEO_TUNER_LOW) st = 16000; else st = 16; } if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0) perror("ioctl VIDIOCGCHAN"); if (vchn.flags & VIDEO_VC_AUDIO) { if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0) perror("ioctl VIDIOCGAUDIO"); } if (vaud.flags & VIDEO_AUDIO_MUTE) { vaud.flags &= ~VIDEO_AUDIO_MUTE; /* Unmute */ vaud.volume = 0xFFFF; } if (isource == TELEVISION) { for (i=0; i < CHAN_ENTRIES; i++) { if (!strcmp(cname[cchannel], tvtuner[i].name)) { rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel]; ccrfreq = rfreq - ftune[cchannel]; break; } } DrawPresetChan(cchannel); } else if (isource == COMPOSITE) { DrawPresetChan(compchannel); } else if (isource == SVIDEO) { DrawPresetChan(-1); } if (vchn.flags & VIDEO_VC_AUDIO) { if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) perror("ioctl VIDIOCSAUDIO"); } if (ioctl(tfd, VIDIOCSCHAN, &vchn) < 0) perror("ioctl VIDIOCSCHAN"); if (!cnotune) { if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) perror("ioctl VIDIOCSFREQ"); } if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0) perror("ioctl VIDIOCSWIN"); if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) perror("ioctl VIDIOCCAPTURE"); } /* TVOff function */ void TVOff(void) { ccapt = 0; if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) perror("ioctl VIDIOCCAPTURE"); vaud.audio = tvsource; vaud.volume = 0; vaud.flags |= VIDEO_AUDIO_MUTE; if (vchn.flags & VIDEO_VC_AUDIO) { if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) perror("ioctl VIDIOCSAUDIO"); } close(tfd); copyXPMArea(66, 79, 11, 7, 6, 50); RedrawWindowXYWH(6, 50, 11, 7); } /* VolumeUp function */ void VolumeUp(void) { if(vchn.flags & VIDEO_VC_AUDIO) { if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0) fprintf(stderr, "Warning: v4l device does not support volume control.\n"); else if (vaud.volume <= 0xEEEE) { vaud.audio = tvsource; vaud.volume += 0x1111; if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) perror("ioctl VIDIOCSAUDIO"); } } } /* VoumeDown function */ void VolumeDown(void) { if (vchn.flags & VIDEO_VC_AUDIO) { if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0) fprintf(stderr, "Warning: v4l device does not support volume control.\n"); else if (vaud.volume >= 0x1111) { vaud.audio = tvsource; vaud.volume -= 0x1111; if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) perror("ioctl VIDIOCSAUDIO"); } } } /* MuteAudio function */ void MuteAudio(void) { if (vchn.flags & VIDEO_VC_AUDIO) { vaud.audio = tvsource; /* vaud.volume = 0; */ vaud.flags |= VIDEO_AUDIO_MUTE; if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) perror("ioctl VIDIOCSAUDIO"); } mute = TRUE; } /* UnMuteAudio function */ void UnMuteAudio(void) { if ((vchn.flags & VIDEO_VC_AUDIO) && (vaud.flags & VIDEO_AUDIO_MUTE)) { vaud.audio = tvsource; /* vaud.volume = (0xFFFF/2)+1; */ vaud.flags &= ~VIDEO_AUDIO_MUTE; if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) perror("ioctl VIDIOCSAUDIO"); } mute = FALSE; } /* ScanUp function */ void ScanUp(void) { rfreq += 2; usleep(50000L); if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) { perror("ioctl VIDIOCSFREQ"); } usleep(10000L); vtun.tuner = 0; if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) { perror("ioctl VIDIOCGTUNER"); } if (vtun.signal == 0xFFFF) { timebutton = 0; } } /* ScanDown function */ void ScanDown(void) { rfreq -= 2; usleep(50000L); if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) { perror("ioctl VIDIOCSFREQ"); } usleep(10000L); vtun.tuner = 0; if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) { perror("ioctl VIDIOCGTUNER"); } if (vtun.signal == 0xFFFF) { timebutton = 0; } } /* FineTuneUp function */ void FineTuneUp(void) { rfreq += 1; if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) { perror("ioctl VIDIOCSFREQ"); } } /* FineTuneDown function */ void FineTuneDown(void) { rfreq -= 1; if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) { perror("ioctl VIDIOCSFREQ"); } } /* ChanUp function */ void ChanUp(void) { int i; if (cchannel < maxpst) ++cchannel; for (i=0; i < CHAN_ENTRIES; i++) { if (!strcmp(cname[cchannel], tvtuner[i].name)) { rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel]; ccrfreq = rfreq - ftune[cchannel]; break; } } DrawPresetChan(cchannel); if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) perror("ioctl VIDIOCSFREQ"); } /* ChanDown function */ void ChanDown(void) { int i; if (cchannel != 0) --cchannel; for (i=0; i < CHAN_ENTRIES; i++) { if (!strcmp(cname[cchannel], tvtuner[i].name)) { rfreq = ((tvtuner[i].freq[freqnorm] / 1000) * st) + ftune[cchannel]; ccrfreq = rfreq - ftune[cchannel]; break; } } DrawPresetChan(cchannel); if (ioctl(tfd, VIDIOCSFREQ, &rfreq) < 0) perror("ioctl VIDIOCSFREQ"); } /* DrawPresetChan function */ void DrawPresetChan(int cchannel) { char temp[10]; char *p = temp; int j=0; int k=6; if (isource == TELEVISION) { sprintf(temp, "%02d", cchannel+1); if (*p == '0') { copyXPMArea(66, 79, 5, 7, k, 50); k += 6; j++; p++; } while (j < 2) { copyXPMArea((*p-'0')*6 + 1, 79, 5, 7, k, 50); k += 6; p++; j++; } } else if (isource == COMPOSITE) { copyXPMArea (109, 79, 5, 7, 6, 50); copyXPMArea ((compchannel*6) + 1, 79, 5, 7, 12, 50); } else if (isource == SVIDEO) { copyXPMArea(116, 79, 11, 7, 6, 50); } RedrawWindowXYWH(6, 50, 11, 7); } /* ParseRCFile function */ void ParseRCFile(const char *filename, rckeys *keys) { char *p; char temp[128]; char *tokens = " =\t\n"; FILE *fp; int key = 0; if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "wmtv: %s\n", strerror(errno)); norcfile = 1; return; } norcfile = 0; while (fgets(temp, 128, fp)) { if (temp[0] != '\n') { p = strtok(temp, tokens); for (key=0; keys[key].label; key++) { if ((!strcmp(p, keys[key].label))) { p = strtok(NULL, tokens); free(*keys[key].var); *keys[key].var = strdup(p); break; } } } } fclose(fp); } /* ParseRCFile2 function */ void ParseRCFile2(const char *filename) { int menu = FALSE; char temp[128], name[128]; FILE *fp; int len, i = 0; if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "wmtv: %s\n", strerror(errno)); norcfile = 1; return; } norcfile = 0; while (fgets(temp, 128, fp)) { if (*temp != '\n') { if (menu) { ftune[i]=0; if(sscanf(temp, " %s %n(%ld) %n", name, &len, &ftune[i], &len)>=1) { char *pos; cname[i]=strdup(name); comment[i]=temp[len]?strdup(temp+len):""; /* Remove the end-of-line symbol */ for (pos = comment[i]; *pos != '\0'; pos++) { if (*pos == '\n') { *pos = '\0'; break; } } } if(++i>=MAXCHAN) break; } else if (strchr(temp, '[')) { menu = TRUE; } } } tpst = i; fclose(fp); } /* WriteRCFile function */ void WriteRCFile(const char *filename, rckeys *keys) { long i; FILE *fp; int key; if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "wmtv: %s\n", strerror(errno)); return; } for (key=0; keys[key].label; key++) if (*keys[key].var) fprintf(fp, "%s = %s\n", keys[key].label, *keys[key].var); fprintf(fp, "\n[channel]\n"); for (i = 0; i <= maxpst; i++) fprintf(fp, "%s (%ld)\t%s\n", cname[i], ftune[i], comment[i]); fclose(fp); } /* InitPalette function */ void InitPalette(void) { if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) { perror ("ioctl VIDIOCGFBUF"); exit(-1); } if (vfb.base == NULL) { fprintf(stderr, "wmtv: no physical frame buffer access\n"); exit(1); } if (ioctl(tfd, VIDIOCGPICT, &vpic) < 0) { perror("ioctl VIDIOCGPICT"); } vpic.depth = vfb.depth; switch(vpic.depth) { case 8: vpic.palette = VIDEO_PALETTE_HI240; break; case 15: vpic.palette = VIDEO_PALETTE_RGB555; break; case 16: vpic.palette = VIDEO_PALETTE_RGB565; break; case 24: vpic.palette = VIDEO_PALETTE_RGB24; break; case 32: vpic.palette = VIDEO_PALETTE_RGB32; break; default: fprintf(stderr, "wmtv: unsupported depth %d\n", vpic.depth); exit(-1); } if (ioctl(tfd, VIDIOCSPICT, &vpic) < 0) { perror("ioctl VIDIOCSPICT"); } } /* InitConfig function */ void InitConfig(void) { int i; ParseRCFile(usrConfFile, wmtv_keys); ParseRCFile2(usrConfFile); if (norcfile) { ParseRCFile(sysConfFile, wmtv_keys); ParseRCFile2(sysConfFile); if (norcfile) { fprintf(stderr, "wmtv: error - config file not found\n"); exit(1); } } if (maxpreset != NULL) maxpst = atoi(maxpreset) - 1; else maxpst = 1; if ((tpst) != atoi(maxpreset)) { fprintf(stderr, "wmtv: error - maxpreset value does not match total channel value\n"); exit(1); } if ((tfd = open(dev, O_RDWR)) < 0) { perror("open failed"); } card_present = TRUE; if (norm) for (i=0; i < CHAN_NAMES; i++) { if (!strcmp(chan_names[i].cname, norm)) { freqnorm = chan_names[i].cind; } } if (freqnorm == -1) { fprintf(stderr, "wmtv: error - set freqnorm in config file\n"); exit(1); } if (ioctl(tfd, VIDIOCGCAP, &vcap) < 0) { perror("ioctl VIDIOCGCAP"); } if (!(vcap.type & VID_TYPE_SCALES)) { fprintf(stderr, "%s: video device does not support scalling\n", progname); exit(1); } if (!(vcap.type & VID_TYPE_CLIPPING)) { fprintf(stderr, "%s: video device does not support clipping\n", progname); } if (fullscreen) { fswidth = atoi(strtok(fullscreen, "x\n")); fsheight = atoi(strtok(NULL, "x\n")); } else { fswidth = 640; fsheight = 480; } if (source) { for (i=0; i < vcap.channels; i++) { vchn.channel = i; if (ioctl(tfd, VIDIOCGCHAN, &vchn) < 0) { perror("ioctl VIDIOCGCHAN"); } if (!strcmp(vchn.name, source)) { if (vchn.tuners) cnotune = 0; else cnotune = 1; vsource = 1; tvsource = vchn.channel; if ((ioctl(tfd, VIDIOCSCHAN, &vchn)) < 0) perror("ioctl VIDIOCSCHAN"); } } if (!vsource) fprintf(stderr, "wmtv: invalid source in config file\n"); } if (mode) { if (!cnotune) { vtun.tuner = 0; if (ioctl(tfd, VIDIOCGTUNER, &vtun) < 0) { perror("ioctl VIDIOCGTUNER"); } if (!strcmp(mode, "pal")) { if (vtun.flags & VIDEO_TUNER_PAL) { vtun.mode = VIDEO_MODE_PAL; if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) { perror("ioctl VIDIOCSTUNER"); } } } if (!strcmp(mode, "ntsc")) { if (vtun.flags & VIDEO_TUNER_NTSC) { vtun.mode = VIDEO_MODE_NTSC; if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) { perror("ioctl VIDIOCSTUNER"); } } } if (!strcmp(mode, "secam")) { if (vtun.flags & VIDEO_TUNER_SECAM) { vtun.mode = VIDEO_MODE_SECAM; if (ioctl(tfd, VIDIOCSTUNER, &vtun) < 0) { perror("ioctl VIDIOCSTUNER"); } } } } } for (i=0; i < vcap.audios; i++) { vaud.audio = i; if (ioctl(tfd, VIDIOCGAUDIO, &vaud) < 0) { perror("ioctl VIDIOCGAUDIO"); } if (!(vaud.flags & VIDEO_AUDIO_MUTE)) { vaud.flags |= VIDEO_AUDIO_MUTE; if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0) { perror("ioctl VIDIOCSAUDIO"); } } } if (ioctl(tfd, VIDIOCGFBUF, &vfb) < 0) { perror("ioctl VIDIOCGFBUF"); } } /* GetFrameBuffer function */ void GetFrameBuffer(void) { #if 0 void *baseaddr = NULL; int evbr, erbr, flr = 0; int bankr, memr, depth; int i, n; int bytesperline, bitsperpixel; XPixmapFormatValues *pf; #endif if (!XGetWindowAttributes(display, DefaultRootWindow(display), &Winattr)) { fprintf(stderr, "wmtv: error getting winattr of root\n"); } #if 0 depth = Winattr.depth; if (XF86DGAQueryExtension(display, &evbr, &erbr)) { XF86DGAQueryDirectVideo(display, XDefaultScreen(display), &flr); if (flr & XF86DGADirectPresent) { XF86DGAGetVideoLL(display, XDefaultScreen(display), (int *) &baseaddr, &bytesperline, &bankr, &memr); } } else { fprintf(stderr, "wmtv: error - XF86DGA Extensions not available\n"); exit(1); } pf = XListPixmapFormats(display, &n); for (i=0; i < n; i++) { if (pf[i].depth == depth) { depth = pf[i].bits_per_pixel; break; } } bitsperpixel = (depth+7) & 0xf8; bytesperline *= bitsperpixel/8; vfb.base = baseaddr; vfb.height = Winattr.height; vfb.width = Winattr.width; vfb.depth = bitsperpixel; vfb.bytesperline = bytesperline; if (Winattr.depth == 15) vfb.depth = 15; if (ioctl(tfd, VIDIOCSFBUF, &vfb) < 0) { perror("ioctl VIDIOCSFBUF"); } #endif } /* DoFullScreen function */ void DoFullScreen(void) { int i; int evbr, erbr = 0; int rx, ry; unsigned long back_pix, fore_pix; unsigned int borderwidth = 0; Window junkwin; XSizeHints fmsizehints; XWMHints fmxwmhints; XGCValues gcv; unsigned long gcm; unsigned long valuemask; XSetWindowAttributes fmWinattr; XWindowAttributes fmwinattr; ccapt = 0; if (ioctl (tfd, VIDIOCCAPTURE, &ccapt) < 0) { perror("ioctl VIDIOCCAPTURE"); } fmsizehints.x = 0; fmsizehints.y = 0; fmsizehints.width = fswidth; fmsizehints.height = fsheight; fmsizehints.max_width = vcap.maxwidth; fmsizehints.max_height = vcap.maxheight; fmsizehints.min_width = fswidth; fmsizehints.min_height = fsheight; fmsizehints.flags = (USPosition | USSize | PSize | PMinSize | PMaxSize); valuemask = 0; back_pix = WhitePixel(display, DefaultScreen(display)); fore_pix = BlackPixel(display, DefaultScreen(display)); fmwin = XCreateWindow(display, DefaultRootWindow(display), fmsizehints.x, fmsizehints.y, fmsizehints.width, fmsizehints.height, borderwidth, CopyFromParent, InputOutput, CopyFromParent, valuemask, &fmWinattr); XSetWMNormalHints(display, fmwin, &fmsizehints); gcm = (GCForeground | GCBackground | GCGraphicsExposures); gcv.foreground = fore_pix; gcv.background = back_pix; gcv.graphics_exposures = 0; fmGC = XCreateGC(display, DefaultRootWindow(display), gcm, &gcv); XSelectInput(display, fmwin, ButtonPressMask | ExposureMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | VisibilityChangeMask | KeyPressMask ); fmxwmhints.flags = StateHint; fmxwmhints.initial_state = NormalState; XSetWMHints(display, fmwin, &fmxwmhints); if (XF86VidModeQueryExtension(display, &evbr, &erbr)) { vidmode = TRUE; } else { fprintf(stderr, "wmtv: xf86mode extension not present\n"); fprintf(stderr, " switch disabled\n"); } XMapWindow(display, fmwin); usleep(50000L); if (!XGetWindowAttributes(display, fmwin, &fmwinattr)) { fprintf(stderr, "wmtv: error getting winattr of fmwin\n"); } usleep(50000L); if (!XTranslateCoordinates(display, fmwin, DefaultRootWindow(display), -fmwinattr.border_width, -fmwinattr.border_width, &rx, &ry, &junkwin)) { fprintf(stderr, "wmtv: error translating coordinates for fmwin"); } vswin.width = fswidth; vswin.height = fsheight; vswin.x = fmsizehints.x + rx; vswin.y = fmsizehints.y + ry; vswin.clipcount = 0; if (ioctl(tfd, VIDIOCSWIN, &vswin) < 0) { perror("ioctl VIDIOCSWIN"); } ccapt = 1; if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) { perror("ioctl VIDIOCCAPTURE"); } fmode = TRUE; if (vidmode) { XF86VidModeGetModeLine(display, XDefaultScreen(display), &dcret, &scmode); XF86VidModeGetAllModeLines(display, XDefaultScreen(display), &tml, &modelines); for (i=0; i < tml; i++) { if ((modelines[i]->hdisplay == fswidth) && (modelines[i]->vdisplay == fsheight)) { fullscreenmode = modelines[i]; mode_present = TRUE; break; } } if (!mode_present) { fprintf(stderr, "wmtv: mode line for resolution %d x %d not found\n", vcap.maxwidth, vcap.maxheight); } XRaiseWindow(display, fmwin); if (mode_present) { XF86VidModeSwitchToMode(display, XDefaultScreen(display), fullscreenmode); XF86VidModeSetViewPort(display, XDefaultScreen(display), vswin.x, vswin.y); XGrabPointer(display, fmwin, True, 0, GrabModeAsync, GrabModeAsync, fmwin, None, CurrentTime); } } } /* RetScreen function */ void RetScreen() { int i; XF86VidModeModeInfo *scm = NULL; ccapt = 0; if (ioctl(tfd, VIDIOCCAPTURE, &ccapt)) { perror("ioctl VIDIOCCAPTURE"); } if (mode_present) { for (i = 0; i < tml; i++) { if ((modelines[i]->hdisplay == Winattr.width) && (modelines[i]->vdisplay==Winattr.height)) scm = modelines[i]; } scm->dotclock = dcret; scm->hdisplay = scmode.hdisplay; scm->hsyncstart = scmode.hsyncstart; scm->hsyncend = scmode.hsyncend; scm->htotal = scmode.htotal; scm->vdisplay = scmode.vdisplay; scm->vsyncstart = scmode.vsyncstart; scm->vsyncend = scmode.vsyncend; scm->vtotal = scmode.vtotal; scm->flags = scmode.flags; /* scm->privsize = scmode.privsize; scm->private = scmode.private; */ XClearWindow(display, fmwin); XFreeGC(display, fmGC); XMapRaised(display, fmwin); XUnmapWindow(display, fmwin); XUngrabPointer(display, CurrentTime); } else { XClearWindow(display, fmwin); XFreeGC(display, fmGC); XMapRaised(display, fmwin); XUnmapWindow(display, fmwin); } if (vidmode && mode_present) { XF86VidModeSwitchToMode(display, XDefaultScreen(display), scm); vidmode = FALSE; } fmode = FALSE; mode_present = FALSE; ccapt = 1; if (ioctl(tfd, VIDIOCSWIN, &vwin) < 0) { perror("ioctl VIDIOCSWIN"); } if (ioctl(tfd, VIDIOCCAPTURE, &ccapt) < 0) { perror("ioctl VIDIOCCAPTURE"); } RedrawWindow(); } /* GrabImage function */ void GrabImage(void) { } /* Usage function */ void Usage(void) { fprintf(stderr, "\n"); fprintf(stderr, "wmtv v%s, Copyright (c) 1999 Wee Liang \n", VERSION); fprintf(stderr, "usage: wmtv [%s]\n", OPTIONS); fprintf(stderr, " -c, --device \tsets video4linux device to use\n"); fprintf(stderr, " -d, --display \tsets display name\n"); fprintf(stderr, " -g, --geometry <{+-}XP{+-}YP>\tsets geometry\n"); fprintf(stderr, " -b, --bpp\t\t\tdisplay color depth\n"); fprintf(stderr, " -e, --exe \t\tprogram to execute\n"); fprintf(stderr, " -v, --version\t\t\tprints version information\n"); fprintf(stderr, " -h, --help\t\t\tprints this message\n"); fprintf(stderr, "\n"); } /* Version function */ void Version(void) { fprintf(stderr, "wmtv version %s\n", VERSION); }