// INCLUDE HEADER //////////////////////////////////////////////////////// // See header file for licensing info #include "bt848.h" #include #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 502100 #include #include #else #include #include #endif #include // GLOBAL VARS /////////////////////////////////////////////////////////// int fd, res; int curfreq = 0; // The following are for the SDL viewer caddr_t buf; int paused = 0; int rows, cols, size, i, c; struct meteor_capframe cap; struct meteor_geomet geo; SDL_Surface *screen; SDL_Overlay *overlay; // SDL_Event event; SDL_Rect rect = { 0 }; // TUNER FUNCTIONS /////////////////////////////////////////////////////// // Open tuner int tuner_init() { if ((fd = open(TUNERDEV, O_RDWR)) < 0) { return -1; } return 0; } // close tuner int tuner_quit() { return close(fd); } // Video source int tuner_tunerdev() { int current; int asrc; int vsrc; current = tuner_videosource(); if (current < 0) { return -1; } for (vsrc = 0; vsrc < 5; vsrc++) { if (tuner_videosource_set(vsrc) < 0) { return -1; } asrc = tuner_audiosource(); if (asrc < 0) { return -1; } if (asrc != 1) { tuner_videosource_set(current); return vsrc; } } return -1; } int tuner_videosource_set(int videosource) { if (videosource < 0 || videosource > 4) { return -1; } if (videosource == 0) { videosource = METEOR_DEV0; } if (videosource == 1) { videosource = METEOR_DEV1; } if (videosource == 2) { videosource = METEOR_DEV2; } if (videosource == 3) { videosource = METEOR_DEV3; } if (videosource == 4) { videosource = METEOR_DEV_SVIDEO; } res = ioctl(fd, METEORSINPUT, &videosource); return res; } int tuner_videosource() { unsigned long videosource; if (ioctl(fd, METEORGINPUT, &videosource) < 0) { close(fd); return -1; } if (videosource == METEOR_DEV0) { videosource = 0; } if (videosource == METEOR_DEV1) { videosource = 1; } if (videosource == METEOR_DEV2) { videosource = 2; } if (videosource == METEOR_DEV3) { videosource = 3; } if (videosource == METEOR_DEV_SVIDEO) { videosource = 4; } return (int)videosource; } // Audio source int tuner_audiosource_set(int audiosource) { if (audiosource != AUDIO_TUNER && audiosource != AUDIO_INTERN && audiosource != AUDIO_EXTERN && audiosource != AUDIO_MUTE && audiosource != AUDIO_UNMUTE) { return -1; } res = ioctl(fd, BT848_SAUDIO, &audiosource); return res; } int tuner_audiosource() { int audiosource; if (ioctl(fd, BT848_GAUDIO, &audiosource) < 0) { close(fd); return -1; } return audiosource; } // AFC int tuner_afc_set(int afcbool) { if (afcbool != 0 && afcbool != 1) { return -1; } res = ioctl(fd, TVTUNER_SETAFC, &afcbool); return res; } int tuner_afc() { int afcbool; if (ioctl(fd, TVTUNER_GETAFC, &afcbool) < 0) { close(fd); return -1; } if (afcbool != 1) { afcbool = 0; } return afcbool; } // Frequency MHz int tuner_frequency_set(int frequency) { int f; if (frequency > MAXFREQ) { frequency = MAXFREQ; } if (frequency < MINFREQ) { frequency = MINFREQ; } f = frequency * FREQFACTOR; res = ioctl(fd, TVTUNER_SETFREQ, &f); if (res == 0) { curfreq = frequency; } return res; } int tuner_frequency() { int frequency; if (ioctl(fd, TVTUNER_GETFREQ, &frequency) < 0) { return -1; } if (frequency == 0) { return curfreq; } return (frequency / FREQFACTOR); } // Brightness, contrast, color, saturation % int tuner_brightness_set(int brightness) { if (brightness > MAXPERC) { brightness = MAXPERC; } if (brightness < MINPERC) { brightness = MINPERC; } brightness = (BT848_BRIGHTMIN + brightness * (BT848_BRIGHTMAX - BT848_BRIGHTMIN) / MAXPERC); res = ioctl(fd, BT848_SBRIG, &brightness); return res; } int tuner_brightness() { int brightness; if (ioctl(fd, BT848_GBRIG, &brightness) < 0) { return -1; } return (brightness + BT848_BRIGHTMAX); } int tuner_contrast_set(int contrast) { if (contrast > MAXPERC) { contrast = MAXPERC; } if (contrast < MINPERC) { contrast = MINPERC; } contrast = contrast * BT848_CONTRASTMAX / MAXPERC; res = ioctl(fd, BT848_SCONT, &contrast); return res; } int tuner_contrast() { int contrast; if (ioctl(fd, BT848_GCONT, &contrast) < 0) { return -1; } return contrast * MAXPERC / BT848_CONTRASTMAX; } int tuner_color_set(int color) { if (color > MAXPERC) { color = MAXPERC; } if (color < MINPERC) { color = MINPERC; } color = color * BT848_SATVMAX / MAXPERC; res = ioctl(fd, BT848_SVSAT, &color) & ioctl(fd, BT848_SHUE, HUEVAL); return res; } int tuner_color() { int color; if (ioctl(fd, BT848_GVSAT, &color) < 0) { return -1; } return (color + 1) * MAXPERC / BT848_SATVMAX; } int tuner_saturation_set(int saturation) { if (saturation > MAXPERC) { saturation = MAXPERC; } if (saturation < MINPERC) { saturation = MINPERC; } saturation = saturation * BT848_SATVMAX / MAXPERC; res = ioctl(fd, BT848_SUSAT, &saturation) & ioctl(fd, BT848_SHUE, HUEVAL); return res; } int tuner_saturation() { int saturation; if (ioctl(fd, BT848_GUSAT, &saturation) < 0) { return -1; } return (saturation + 1) * MAXPERC / BT848_SATVMAX; } // VIEWER FUNCTIONS ////////////////////////////////////////////////////// int viewer_init(int width, int height, int std) { if ((i = open(BKTRDEV, O_RDONLY)) < 0) { return 1; } if (std == 1) c = BT848_IFORM_F_NTSCM; else if (std == 2) c = BT848_IFORM_F_SECAM; else c = BT848_IFORM_F_PALBDGHI; if (c == BT848_IFORM_F_NTSCM) { cols = 640; rows = 480; } else { cols = 768; rows = 576; } size = rows * cols * 2; // Capture geometry, we capture full frames for TV geo.rows = rows; geo.columns = cols; geo.frames = 1; geo.oformat = METEOR_GEO_YUV_PACKED; if (ioctl(i, METEORSETGEO, &geo) < 0) { close(i); return 2; } // Note omission of setting input device (defaults to DEV0) // This is considered a "tuner function" // Set video standard if (ioctl(i, BT848SFMT, &c) < 0) { close(i); return 3; } // SDL init and such rect.w = width; rect.h = height; if (SDL_Init(SDL_INIT_VIDEO) < 0) { SDL_Quit(); close(i); return 4; } if ((screen = SDL_SetVideoMode(rect.w, rect.h, 0, SDL_RESIZABLE)) == NULL) { SDL_Quit(); close(i); return 5; } if ((overlay = SDL_CreateYUVOverlay(cols, rows, SDL_UYVY_OVERLAY, screen)) == NULL) { SDL_Quit(); close(i); return 6; } SDL_DisplayYUVOverlay(overlay, &rect); // Set signal handler paused = 1; signal(SIGUSR1, frame_handler); // Capture on c = METEOR_CAP_CONTINOUS; if (ioctl(i, METEORCAPTUR, &c) < 0) { signal(SIGUSR1, SIG_DFL); SDL_Quit(); close(i); return 7; } // Set the signal ("got frame") c = SIGUSR1; if (ioctl(i, METEORSSIGNAL, &c) < 0) { c = METEOR_CAP_STOP_CONT; ioctl(i, METEORCAPTUR, &c); signal(SIGUSR1, SIG_DFL); SDL_Quit(); close(i); return 8; } // Framebuffer buf = mmap((caddr_t)0, size, PROT_READ, MAP_SHARED, i, (off_t)0); if (buf == (caddr_t)MAP_FAILED) { c = METEOR_SIG_MODE_MASK; ioctl(i, METEORSSIGNAL, &c); c = METEOR_CAP_STOP_CONT; ioctl(i, METEORCAPTUR, &c); signal(SIGUSR1, SIG_DFL); SDL_Quit(); close(i); return 9; } // All succeeded return 0; } void viewer_start() { paused = 0; } void viewer_pause() { paused = 1; } void viewer_resize(int width, int height) { rect.w = width; rect.h = height; SDL_SetVideoMode(rect.w, rect.h, 0, SDL_RESIZABLE); if (paused) { SDL_DisplayYUVOverlay(overlay, &rect); } } void viewer_quit() { c = METEOR_SIG_MODE_MASK; ioctl(i, METEORSSIGNAL, &c); c = METEOR_CAP_STOP_CONT; ioctl(i, METEORCAPTUR, &c); signal(SIGUSR1, SIG_DFL); SDL_Quit(); munmap(buf, size); close(i); } void frame_handler() { if (!paused) { SDL_LockYUVOverlay(overlay); memcpy(overlay->pixels[0], buf, size); SDL_UnlockYUVOverlay(overlay); SDL_DisplayYUVOverlay(overlay, &rect); } } // END ///////////////////////////////////////////////////////////////////