You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
739 lines
19 KiB
739 lines
19 KiB
4 years ago
|
/*
|
||
|
* 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);
|
||
|
}
|
||
|
|