diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/import/import_bktr.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/import/import_bktr.c | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/import/import_bktr.c b/debian/transcode/transcode-1.1.7/import/import_bktr.c new file mode 100644 index 00000000..20ad35dd --- /dev/null +++ b/debian/transcode/transcode-1.1.7/import/import_bktr.c @@ -0,0 +1,738 @@ +/* + * import_bktr.c + * + * Copyright (C) Jacob Meuser - September 2004 + * based on code, hints and suggestions from: Roger Hardiman, + * Steve O'Hara-Smith, Erik Slagter and Stefan Scheffler + * + * This file is part of transcode, a video stream processing tool + * + * transcode 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. + * + * transcode 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define MOD_NAME "import_bktr.so" +#define MOD_VERSION "v0.0.2 (2004-10-02)" +#define MOD_CODEC "(video) bktr" + +#include "transcode.h" +#include "libtc/libtc.h" +#include "libtc/optstr.h" +#include "libtcvideo/tcvideo.h" + +/*%* + *%* DESCRIPTION + *%* This module reads video frames from an capture device using bktr module. + *%* This module is designed to work on *BSD. For linux, use the v4l module. + *%* + *%* #BUILD-DEPENDS + *%* + *%* #DEPENDS + *%* + *%* PROCESSING + *%* import/demuxer + *%* + *%* MEDIA + *%* video + *%* + *%* #INPUT + *%* + *%* OUTPUT + *%* YUV420, YUV422P, RGB24 + *%* + *%* OPTION + *%* format (string) + *%* selects video normalization. + *%* + *%* OPTION + *%* vsource (string) + *%* selects video source (device dependant input). + *%* + *%* OPTION + *%* asource (string) + *%* selects audio source (device dependant input). + *%* + *%* OPTION + *%* tunerdev (string) + *%* help: selects tuner devince. + *%*/ + +static int verbose_flag = TC_QUIET; +static int capability_flag = TC_CAP_RGB | TC_CAP_YUV | TC_CAP_YUV422; + +#define MOD_PRE bktr +#include "import_def.h" + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/mman.h> + +#ifdef HAVE_DEV_IC_BT8XX_H +#include <dev/ic/bt8xx.h> +#else +# ifdef HAVE_DEV_BKTR_IOCTL_BT848_H +# include <dev/bktr/ioctl_meteor.h> +# include <dev/bktr/ioctl_bt848.h> +# else +# ifdef HAVE_MACHINE_IOCTL_BT848_H +# include <machine/ioctl_meteor.h> +# include <machine/ioctl_bt848.h> +# endif +# endif +#endif + + +static const struct { + char *name; + u_int format; +} formats[] = { + { "ntsc", METEOR_FMT_NTSC }, + { "pal", METEOR_FMT_PAL }, + { 0 } +}; + +static const struct { + char *name; + u_int vsource; +} vsources[] = { + { "composite", METEOR_INPUT_DEV0 }, + { "tuner", METEOR_INPUT_DEV1 }, + { "svideo_comp", METEOR_INPUT_DEV2 }, + { "svideo", METEOR_INPUT_DEV_SVIDEO }, + { "input3", METEOR_INPUT_DEV3 }, + { 0 } +}; + +static const struct { + char *name; + u_int asource; +} asources[] = { + { "tuner", AUDIO_TUNER }, + { "external", AUDIO_EXTERN }, + { "internal", AUDIO_INTERN }, + { 0 } +}; + +void bktr_usage(void); +int bktr_parse_options(char *); +static void catchsignal(int); +int bktr_init(int, const char *, int, int, int, char *); +int bktr_grab(size_t, char *); +int bktr_stop(); +static void copy_buf_yuv422(char *, size_t); +static void copy_buf_yuv(char *, size_t); +static void copy_buf_rgb(char *, size_t); + + +volatile sig_atomic_t bktr_frame_waiting; + +sigset_t sa_mask; + +uint8_t *bktr_buffer; +size_t bktr_buffer_size; +static int bktr_vfd = -1; +static int bktr_tfd = -1; +char bktr_tuner[128] = "/dev/tuner0"; +int bktr_convert; +#define BKTR2RGB 0 +#define BKTR2YUV422 1 +#define BKTR2YUV 2 +u_int bktr_format = 0; +u_int bktr_vsource = METEOR_INPUT_DEV1; /* tuner */ +u_int bktr_asource = AUDIO_TUNER; +int bktr_hwfps = 0; +int bktr_mute = 0; +TCVHandle bktr_tcvhandle = 0; + + +void bktr_usage(void) +{ + int i; + + tc_log_info(MOD_NAME, + "* Overview"); + tc_log_info(MOD_NAME, + " This module grabs video frames from bktr(4) devices"); + tc_log_info(MOD_NAME, + " found on BSD systems."); + + tc_log_info(MOD_NAME, + "* Options"); + + tc_log_info(MOD_NAME, + " 'format=<format>' Video norm, valid arguments:"); + for (i = 0; formats[i].name; i++) + tc_log_info(MOD_NAME, " %s", formats[i].name); + tc_log_info(MOD_NAME, + " default: driver default"); + + tc_log_info(MOD_NAME, + " 'vsource=<vsource>' Video source, valid arguments:"); + for (i = 0; vsources[i].name; i++) + tc_log_info(MOD_NAME, " %s", vsources[i].name); + tc_log_info(MOD_NAME, + " default: driver default (usually 'composite')"); + + tc_log_info(MOD_NAME, + " 'asource=<asource>' Audio source, valid arguments:"); + for (i = 0; asources[i].name; i++) + tc_log_info(MOD_NAME, " %s", asources[i].name); + tc_log_info(MOD_NAME, + " default: driver default (usually 'tuner')"); + + tc_log_info(MOD_NAME, + " 'tunerdev=<tunerdev>' Tuner device, default: %s", + bktr_tuner); + + tc_log_info(MOD_NAME, + " 'mute' Mute the bktr device, off by default."); + + tc_log_info(MOD_NAME, + " 'hwfps' Set frame rate in hardware, off by default."); + tc_log_info(MOD_NAME, + " It's possible to get smoother captures by using"); + tc_log_info(MOD_NAME, + " -f to capture in the highest possible frame rate"); + tc_log_info(MOD_NAME, + " along with a frame rate filter to get a lower fps."); + + tc_log_info(MOD_NAME, + " 'help' Show this help message"); + + tc_log_info(MOD_NAME, ""); +} + +int bktr_parse_options(char *options) +{ + char format[128]; + char vsource[128]; + char asource[128]; + char tuner[128]; + int i; + + if (optstr_lookup(options, "help") != NULL) { + bktr_usage(); + return(1); + } + + if (optstr_lookup(options, "hwfps") != NULL) + bktr_hwfps = 1; + + if (optstr_lookup(options, "mute") != NULL) + bktr_mute = 1; + + if (optstr_get(options, "format", "%[^:]", &format) >= 0) { + for (i = 0; formats[i].name; i++) + if (strncmp(formats[i].name, format, 128) == 0) + break; + if (formats[i].name) + bktr_format = formats[i].format; + else { + tc_log_warn(MOD_NAME, + "invalid format: %s", + format); + return(1); + } + } + + if (optstr_get(options, "vsource", "%[^:]", &vsource) >= 0) { + for (i = 0; vsources[i].name; i++) + if (strncmp(vsources[i].name, vsource, 128) == 0) + break; + if (vsources[i].name) + bktr_vsource = vsources[i].vsource; + else { + tc_log_warn(MOD_NAME, + "invalid vsource: %s", + vsource); + return(1); + } + } + + if (optstr_get(options, "asource", "%[^:]", &asource) >= 0) { + for (i = 0; asources[i].name; i++) + if (strncmp(asources[i].name, asource, 128) == 0) + break; + if (asources[i].name) + bktr_asource = asources[i].asource; + else { + tc_log_warn(MOD_NAME, + "invalid asource: %s", + asource); + return(1); + } + } + + if (optstr_get(options, "tunerdev", "%[^:]", &tuner) >= 0) + strlcpy(bktr_tuner, tuner, sizeof(bktr_tuner)); + + return(0); +} + +static void catchsignal(int signal) +{ + if (signal == SIGUSR1) + bktr_frame_waiting = 1; +} + +int bktr_init(int video_codec, const char *video_device, + int width, int height, + int fps, char *options) +{ + struct meteor_geomet geo; + struct meteor_pixfmt pxf; + struct sigaction act; + int h_max, w_max; + int rgb_idx = -1; + int yuv422_idx = -1; + int yuv_idx = -1; + int i; + + if (options != NULL) + if (bktr_parse_options(options)) + return(1); + + switch (bktr_format) { + case METEOR_FMT_NTSC: h_max = 480; w_max = 640; break; + case METEOR_FMT_PAL: h_max = 576; w_max = 768; break; + default: h_max = 576; w_max = 768; break; + } + + if (width > w_max) { + tc_log_warn(MOD_NAME, + "import width '%d' too large! " + "PAL max width = 768, NTSC max width = 640", + width); + return(1); + } + + if (height > h_max) { + tc_log_warn(MOD_NAME, + "import height %d too large! " + "PAL max height = 576, NTSC max height = 480", + height); + return(1); + } + + bktr_tcvhandle = tcv_init(); + if (!bktr_tcvhandle) { + tcv_log_warn(MOD_NAME, "tcv_init() failed"); + return(1); + } + + /* set the audio via the tuner. opening the device unmutes it. */ + /* closing the device mutes it again. so we hold it open */ + + bktr_tfd = open(bktr_tuner, O_RDONLY); + if (bktr_tfd < 0) { + tc_log_perror(MOD_NAME, "open tuner"); + return(1); + } + + if (ioctl(bktr_tfd, BT848_SAUDIO, &bktr_asource) < 0) { + tc_log_perror(MOD_NAME, "BT848_SAUDIO asource"); + return(1); + } + + if (bktr_mute) { + i = AUDIO_MUTE; + if (ioctl(bktr_tfd, BT848_SAUDIO, &i) < 0) { + tc_log_perror(MOD_NAME, "BT848_SAUDIO AUDIO_MUTE"); + return(1); + } + } else { + i = AUDIO_UNMUTE; + if (ioctl(bktr_tfd, BT848_SAUDIO, &i) < 0) { + tc_log_perror(MOD_NAME, "BT848_SAUDIO AUDIO_UNMUTE"); + return(1); + } + } + + /* open the video device */ + + bktr_vfd = open(video_device, O_RDONLY); + if (bktr_vfd < 0) { + tc_log_perror(MOD_NAME, video_device); + return(1); + } + + /* get the indices of supported formats that transcode can use */ + + for (i = 0; ; i++) { + pxf.index = i; + if (ioctl(bktr_vfd, METEORGSUPPIXFMT, &pxf) < 0) { + if (errno == EINVAL) + break; + else + return(1); + } + switch(pxf.type) { + case METEOR_PIXTYPE_RGB: + if ((pxf.Bpp == 4) && (pxf.swap_bytes == 0) && + (pxf.swap_shorts == 0)) { + rgb_idx = pxf.index; + } + break; + case METEOR_PIXTYPE_YUV_PACKED: + if ((pxf.swap_bytes == 0) && (pxf.swap_shorts == 1)) { + yuv422_idx = pxf.index; + } + break; + case METEOR_PIXTYPE_YUV_12: + if ((pxf.swap_bytes == 1) && (pxf.swap_shorts == 1)) { + yuv_idx = pxf.index; + } + break; + case METEOR_PIXTYPE_YUV: + default: + break; + } + } + + /* set format, conversion function, and buffer size */ + + switch(video_codec) { + case CODEC_RGB: + i = rgb_idx; + bktr_convert = BKTR2RGB; + bktr_buffer_size = width * height * 4; + break; + case CODEC_YUV422: + i = yuv422_idx; + bktr_convert = BKTR2YUV422; + bktr_buffer_size = width * height * 2; + break; + case CODEC_YUV: + i = yuv_idx; + bktr_convert = BKTR2YUV; + bktr_buffer_size = width * height * 3 / 2; + break; + default: + tc_log_warn(MOD_NAME, + "video_codec (%d) must be %d or %d or %d\n", + video_codec, CODEC_RGB, CODEC_YUV422, CODEC_YUV); + return(1); + } + + if (ioctl(bktr_vfd, METEORSACTPIXFMT, &i) < 0) { + tc_log_perror(MOD_NAME, "METEORSACTPIXFMT"); + return(1); + } + + /* set the geometry */ + + geo.rows = height; + geo.columns = width; + geo.frames = 1; + geo.oformat = 0; + + if (verbose_flag & TC_DEBUG) { + tc_log_info(MOD_NAME, + "geo.rows = %d, geo.columns = %d, " + "geo.frames = %d, geo.oformat = %ld", + geo.rows, geo.columns, + geo.frames, (long)geo.oformat); + } + + if (ioctl(bktr_vfd, METEORSETGEO, &geo) < 0) { + tc_log_perror(MOD_NAME, "METEORSETGEO"); + return(1); + } + + /* extra options */ + + if (bktr_vsource) { + if (ioctl(bktr_vfd, METEORSINPUT, &bktr_vsource) < 0) { + tc_log_perror(MOD_NAME, "METEORSINPUT"); + return(1); + } + } + + if (bktr_format) { + if (ioctl(bktr_vfd, METEORSFMT, &bktr_format) < 0) { + tc_log_perror(MOD_NAME, "METEORSFMT"); + return(1); + } + } + + if (bktr_hwfps) { + if (ioctl(bktr_vfd, METEORSFPS, &fps) < 0) { + tc_log_perror(MOD_NAME, "METEORSFPS"); + return(1); + } + } + + /* mmap the buffer */ + + bktr_buffer = mmap(0, bktr_buffer_size, PROT_READ, MAP_SHARED, bktr_vfd, 0); + + if (bktr_buffer == MAP_FAILED) { + tc_log_perror(MOD_NAME, "mmap bktr_buffer"); + return(1); + } + + /* for sigsuspend() */ + sigfillset(&sa_mask); + sigdelset(&sa_mask, SIGUSR1); + sigdelset(&sa_mask, SIGALRM); + + /* signal handler to know when data is ready to be read() */ + + memset(&act, 0, sizeof(act)); + sigemptyset(&act.sa_mask); + act.sa_handler = catchsignal; + sigaction(SIGUSR1, &act, NULL); + sigaction(SIGALRM, &act, NULL); + + i = SIGUSR1; + if (ioctl(bktr_vfd, METEORSSIGNAL, &i) < 0) { + tc_log_perror(MOD_NAME, "METEORSSIGNAL"); + return(1); + } + + /* let `er rip! */ + + i = METEOR_CAP_CONTINOUS; + if (ioctl(bktr_vfd, METEORCAPTUR, &i) < 0) { + tc_log_perror(MOD_NAME, "METEORCAPTUR"); + return(1); + } + + return(0); +} + +int bktr_grab(size_t size, char *dest) +{ + /* wait for a "buffer full" signal, but longer than 1 second */ + + alarm(1); + sigsuspend(&sa_mask); + alarm(0); + + if (bktr_frame_waiting) { + bktr_frame_waiting = 0; + if (dest) { + if (verbose_flag & TC_DEBUG) { + tc_log_info(MOD_NAME, "copying %lu bytes, buffer size is %lu", + (unsigned long)size, + (unsigned long)bktr_buffer_size); + } + switch (bktr_convert) { + case BKTR2RGB: copy_buf_rgb(dest, size); break; + case BKTR2YUV422: copy_buf_yuv422(dest, size); break; + case BKTR2YUV: copy_buf_yuv(dest, size); break; + default: + tc_log_warn(MOD_NAME, + "unrecognized video conversion request"); + return(1); + break; + } + } else { + tc_log_warn(MOD_NAME, + "no destination buffer to copy frames to"); + return(1); + } + } else { /* bktr_frame_waiting */ + tc_log_warn(MOD_NAME, "sigalrm"); + } + + return(0); +} + +static void copy_buf_yuv422(char *dest, size_t size) +{ + uint8_t *planes; + + if (bktr_buffer_size != size) { + tc_log_warn(MOD_NAME, + "buffer sizes do not match (input %lu != output %lu)", + (unsigned long)bktr_buffer_size, (unsigned long)size); + } + tcv_convert(bktr_tcvhandle, bktr_buffer, dest, size/2, 1, + IMG_UYVY, IMG_YUV422P); +} + +static void copy_buf_yuv(char *dest, size_t size) +{ + int y_size = bktr_buffer_size * 4 / 6; + int u_size = bktr_buffer_size * 1 / 6; + int y_offset = 0; + int u1_offset = y_size + 0; + int u2_offset = y_size + u_size; + + if (bktr_buffer_size != size) + tc_log_warn(MOD_NAME, + "buffer sizes do not match (input %lu != output %lu)", + (unsigned long)bktr_buffer_size, (unsigned long)size); + + ac_memcpy(dest + y_offset, bktr_buffer + y_offset, y_size); + ac_memcpy(dest + u1_offset, bktr_buffer + u1_offset, u_size); + ac_memcpy(dest + u2_offset, bktr_buffer + u2_offset, u_size); +} + +static void copy_buf_rgb(char *dest, size_t size) +{ + int i; + + /* 24 bit RGB packed into 32 bits (NULL, R, G, B) */ + + if ((bktr_buffer_size * 3 / 4) != size) + tc_log_warn(MOD_NAME, + "buffer sizes do not match (input %lu != output %lu)", + (unsigned long)bktr_buffer_size * 3 / 4, (unsigned long)size); + + /* bktr_buffer_size was set to width * height * 4 (32 bits) */ + /* so width * height = bktr_buffer_size / 4 */ + tcv_convert(bktr_tcvhandle, bktr_buffer, dest, bktr_buffer_size/4, 1, + IMG_ARGB32, IMG_RGB24); +} + + +int bktr_stop() +{ + int c; + + /* shutdown signals first */ + + c = METEOR_SIG_MODE_MASK; + ioctl(bktr_vfd, METEORSSIGNAL, &c); + + alarm(0); + + c = METEOR_CAP_STOP_CONT; + ioctl(bktr_vfd, METEORCAPTUR, &c); + + c = AUDIO_MUTE; + if (ioctl(bktr_tfd, BT848_SAUDIO, &c) < 0) { + tc_log_perror(MOD_NAME, "BT848_SAUDIO AUDIO_MUTE"); + return(1); + } + + if (bktr_vfd > 0) { + close(bktr_vfd); + bktr_vfd = -1; + } + + if (bktr_tfd > 0) { + close(bktr_tfd); + bktr_tfd = -1; + } + + munmap(bktr_buffer, bktr_buffer_size); + + return(0); +} + + + +/* ------------------------------------------------------------ + * + * open stream + * + * ------------------------------------------------------------*/ + +MOD_open +{ + int ret = TC_IMPORT_OK; + + switch (param->flag) { + case TC_VIDEO: + if (verbose_flag & TC_DEBUG) { + tc_log_info(MOD_NAME, + "bktr video grabbing"); + } + if (bktr_init(vob->im_v_codec, vob->video_in_file, + vob->im_v_width, vob->im_v_height, + vob->fps, vob->im_v_string)) { + ret = TC_IMPORT_ERROR; + } + break; + case TC_AUDIO: + tc_log_warn(MOD_NAME, + "unsupported request (init audio)\n"); + break; + default: + tc_log_warn(MOD_NAME, + "unsupported request (init)\n"); + ret = TC_IMPORT_ERROR; + break; + } + + return(ret); +} + + +/* ------------------------------------------------------------ + * + * decode stream + * + * ------------------------------------------------------------*/ + +MOD_decode +{ + int ret = TC_IMPORT_OK; + + switch (param->flag) { + case TC_VIDEO: + if (bktr_grab(param->size, param->buffer)) { + tc_log_warn(MOD_NAME, + "error in grabbing video"); + ret = TC_IMPORT_ERROR; + } + break; + case TC_AUDIO: + tc_log_warn(MOD_NAME, + "unsupported request (decode audio)"); + ret = TC_IMPORT_ERROR; + break; + default: + tc_log_warn(MOD_NAME, + "unsupported request (decode)"); + ret = TC_IMPORT_ERROR; + break; + } + + return(ret); +} + +/* ------------------------------------------------------------ + * + * close stream + * + * ------------------------------------------------------------*/ + +MOD_close +{ + int ret = TC_IMPORT_OK; + + switch (param->flag) { + case TC_VIDEO: + bktr_stop(); + break; + case TC_AUDIO: + tc_log_warn(MOD_NAME, + "unsupported request (close audio)"); + ret = TC_IMPORT_ERROR; + break; + default: + tc_log_warn(MOD_NAME, + "unsupported request (close)"); + ret = TC_IMPORT_ERROR; + break; + } + + return(ret); +} + |
