summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cfg-common.h3
-rw-r--r--libmpdemux/demuxer.c8
-rw-r--r--libmpdemux/open.c9
-rw-r--r--libmpdemux/tv.c168
-rw-r--r--libmpdemux/tv.h84
-rw-r--r--libmpdemux/tvi_def.h12
-rw-r--r--libmpdemux/tvi_dummy.c50
-rw-r--r--libmpdemux/tvi_v4l.c555
8 files changed, 731 insertions, 158 deletions
diff --git a/cfg-common.h b/cfg-common.h
index 1a0dba2c32..b2fd24dc06 100644
--- a/cfg-common.h
+++ b/cfg-common.h
@@ -94,11 +94,12 @@ struct config tvopts_conf[]={
{"on", &tv_param_on, CONF_TYPE_FLAG, 0, 0, 1},
{"driver", &tv_param_driver, CONF_TYPE_STRING, 0, 0, 0},
{"device", &tv_param_device, CONF_TYPE_STRING, 0, 0, 0},
- {"freq", &tv_param_freq, CONF_TYPE_FLOAT, CONF_RANGE, 0, 2500000},
+ {"freq", &tv_param_freq, CONF_TYPE_INT, CONF_RANGE, 0, 2500000},
{"channel", &tv_param_channel, CONF_TYPE_STRING, 0, 0, 0},
{"norm", &tv_param_norm, CONF_TYPE_STRING, 0, 0, 0},
{"width", &tv_param_width, CONF_TYPE_INT, 0, 0, 4096},
{"height", &tv_param_height, CONF_TYPE_INT, 0, 0, 4096},
+ {"input", &tv_param_input, CONF_TYPE_INT, 0, 0, 20},
{NULL, NULL, 0, 0, 0, 0}
};
#endif
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
index 76ee019e52..3b39177f87 100644
--- a/libmpdemux/demuxer.c
+++ b/libmpdemux/demuxer.c
@@ -158,7 +158,9 @@ int demux_asf_fill_buffer(demuxer_t *demux);
int demux_mov_fill_buffer(demuxer_t *demux,demux_stream_t* ds);
int demux_vivo_fill_buffer(demuxer_t *demux);
#ifdef USE_TV
-int demux_tv_fill_buffer(demuxer_t *demux);
+#include "tv.h"
+extern tvi_handle_t *tv_handler;
+int demux_tv_fill_buffer(demuxer_t *demux, tvi_handle_t *tvh);
#endif
int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){
@@ -174,7 +176,7 @@ int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){
case DEMUXER_TYPE_MOV: return demux_mov_fill_buffer(demux,ds);
case DEMUXER_TYPE_VIVO: return demux_vivo_fill_buffer(demux);
#ifdef USE_TV
- case DEMUXER_TYPE_TV: return demux_tv_fill_buffer(demux);
+ case DEMUXER_TYPE_TV: return demux_tv_fill_buffer(demux, tv_handler);
#endif
}
return 0;
@@ -554,7 +556,7 @@ switch(file_format){
}
#ifdef USE_TV
case DEMUXER_TYPE_TV: {
- demux_open_tv(demuxer);
+ demux_open_tv(demuxer, tv_handler);
break;
}
#endif
diff --git a/libmpdemux/open.c b/libmpdemux/open.c
index 6b820697d4..298d7064c5 100644
--- a/libmpdemux/open.c
+++ b/libmpdemux/open.c
@@ -72,7 +72,7 @@ extern int vcd_get_track_end(int fd,int track);
#ifdef USE_TV
#include "tv.h"
-extern tvi_handle_t *tv_handler;
+tvi_handle_t *tv_handler;
#endif
// Open a new stream (stdin/file/vcd/url)
@@ -251,12 +251,13 @@ if(dvd_title){
//============ Check for TV-input ====
if (tv_param_on==1)
{
- stream=new_stream(-1,STREAMTYPE_TV);
+ stream = new_stream(-1,STREAMTYPE_TV);
tv_handler = tv_begin();
if (!tv_handler)
return(NULL);
- tv_init(tv_handler);
- return(stream);
+ if (tv_init(tv_handler) == 1)
+ return(stream);
+ return(NULL);
}
#endif
diff --git a/libmpdemux/tv.c b/libmpdemux/tv.c
index ed1377433c..48f089bad3 100644
--- a/libmpdemux/tv.c
+++ b/libmpdemux/tv.c
@@ -13,19 +13,16 @@
#include "config.h"
#ifdef USE_TV
-#include "tv.h"
#include "mp_msg.h"
#include "help_mp.h"
#include "stream.h"
#include "demuxer.h"
#include "stheader.h"
-
-/* global! */
-tvi_handle_t *tv_handler;
+#include "tv.h"
/* some default values */
-float tv_param_freq = 0.0;
+unsigned long tv_param_freq = 0;
char *tv_param_channel = "0";
char *tv_param_norm = "pal";
int tv_param_on = 0;
@@ -33,6 +30,7 @@ char *tv_param_device = NULL;
char *tv_param_driver = "dummy";
int tv_param_width = -1;
int tv_param_height = -1;
+int tv_param_input = 0; /* used in v4l and bttv */
/* ================== DEMUX_TV ===================== */
@@ -42,25 +40,32 @@ int tv_param_height = -1;
1 = successfully read a packet
*/
/* fill demux->video and demux->audio */
-int demux_tv_fill_buffer(demuxer_t *demux)
+int demux_tv_fill_buffer(demuxer_t *demux, tvi_handle_t *tvh)
{
- int seq;
+ int seq = tvh->seq;
demux_stream_t *ds_video = NULL;
demux_packet_t *dp_video = NULL;
demux_stream_t *ds_audio = NULL;
demux_packet_t *dp_audio = NULL;
int len_video, len_audio;
+ printf("demux_tv_fill_buffer(sequence:%d) called!\n", seq);
+
demux->filepos = -1;
+ seq++;
+ tvh->seq++;
+
/* ================== ADD VIDEO PACKET =================== */
- len_video = tv_handler->functions->get_video_framesize(tv_handler->priv);
+ len_video = tvh->functions->get_video_framesize(tvh->priv);
ds_video = demux->video;
- if (!ds_video)
- {
+ if (!ds_video->asf_packet)
+ {
+ /* create new packet */
dp_video = new_demux_packet(len_video);
- tv_handler->functions->grab_video_frame(tv_handler->priv, dp_video->buffer, len_video);
+// printf("new dp_video->buffer: %p (%d bytes)\n", dp_video, len_video);
+ tvh->functions->grab_video_frame(tvh->priv, dp_video->buffer, len_video);
dp_video->pos = demux->filepos;
ds_video->asf_packet = dp_video;
ds_video->asf_seq = seq;
@@ -69,14 +74,17 @@ int demux_tv_fill_buffer(demuxer_t *demux)
{
if (ds_video->asf_seq != seq)
{
+ /* close segment, finalize packet */
ds_add_packet(ds_video, ds_video->asf_packet);
ds_video->asf_packet = NULL;
}
else
{
+ /* append data to segment */
dp_video = ds_video->asf_packet;
dp_video->buffer = realloc(dp_video->buffer, dp_video->len+len_video);
- tv_handler->functions->grab_video_frame(tv_handler->priv, dp_video->buffer+dp_video->len, len_video);
+// printf("dp_video->buffer: %p (%d bytes)\n", dp_video, dp_video->len+len_video);
+ tvh->functions->grab_video_frame(tvh->priv, dp_video->buffer+dp_video->len, len_video);
mp_dbg(MSGT_DEMUX,MSGL_DBG4, "video data appended %d+%d\n", dp_video->len, len_video);
dp_video->len += len_video;
}
@@ -84,13 +92,16 @@ int demux_tv_fill_buffer(demuxer_t *demux)
/* ================== ADD AUDIO PACKET =================== */
- len_audio = tv_handler->functions->get_audio_framesize(tv_handler->priv);
+ if (tvh->functions->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) != TVI_CONTROL_TRUE)
+ return 1; /* no audio, only video */
+
+ len_audio = tvh->functions->get_audio_framesize(tvh->priv);
ds_audio = demux->audio;
- if (!ds_audio)
+ if (!ds_audio->asf_packet)
{
dp_audio = new_demux_packet(len_audio);
- tv_handler->functions->grab_audio_frame(tv_handler->priv, dp_audio->buffer, len_audio);
+ tvh->functions->grab_audio_frame(tvh->priv, dp_audio->buffer, len_audio);
dp_audio->pos = demux->filepos;
ds_audio->asf_packet = dp_audio;
ds_audio->asf_seq = seq;
@@ -106,7 +117,7 @@ int demux_tv_fill_buffer(demuxer_t *demux)
{
dp_audio = ds_audio->asf_packet;
dp_audio->buffer = realloc(dp_audio->buffer, dp_audio->len+len_audio);
- tv_handler->functions->grab_audio_frame(tv_handler->priv, dp_audio->buffer+dp_audio->len, len_audio);
+ tvh->functions->grab_audio_frame(tvh->priv, dp_audio->buffer+dp_audio->len, len_audio);
mp_dbg(MSGT_DEMUX,MSGL_DBG4, "audio data appended %d+%d\n", dp_audio->len, len_audio);
dp_audio->len += len_audio;
}
@@ -115,18 +126,30 @@ int demux_tv_fill_buffer(demuxer_t *demux)
return 1;
}
-int demux_open_tv(demuxer_t *demuxer)
+int demux_open_tv(demuxer_t *demuxer, tvi_handle_t *tvh)
{
- sh_video_t *sh_video;
- tvi_handle_t *tvh = tv_handler;
+ sh_video_t *sh_video = NULL;
+ sh_audio_t *sh_audio = NULL;
tvi_functions_t *funcs = tvh->functions;
- sh_video = new_sh_video(demuxer,0);
+ if (funcs->control(tvh->priv, TVI_CONTROL_IS_VIDEO, 0) != TVI_CONTROL_TRUE)
+ {
+ printf("Error: no video input present!\n");
+ return;
+ }
+
+ sh_video = new_sh_video(demuxer, 0);
-// sh->format=0x7476696e; /* "tvin" */
- if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &sh_video->format) != TVI_CONTROL_TRUE)
- sh_video->format = 0x00000000;
+ /* hack to use YUV 4:2:0 format ;) */
+ sh_video->format = IMGFMT_YV12;
+ funcs->control(tvh->priv, TVI_CONTROL_VID_SET_FORMAT, &sh_video->format);
+ /* get IMGFMT_ */
+ funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &sh_video->format);
+ if (IMGFMT_IS_RGB(sh_video->format) || IMGFMT_IS_BGR(sh_video->format))
+ sh_video->format = 0x0;
+
+ /* set FPS and FRAMETIME */
if(!sh_video->fps)
{
if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FPS, &sh_video->fps) != TVI_CONTROL_TRUE)
@@ -169,47 +192,100 @@ int demux_open_tv(demuxer_t *demuxer)
}
else
funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &sh_video->disp_h);
-
- /* emulate BITMAPINFOHEADER */
- sh_video->bih = malloc(sizeof(BITMAPINFOHEADER));
- memset(sh_video->bih, 0, sizeof(BITMAPINFOHEADER));
- sh_video->bih->biSize = 40;
- sh_video->bih->biWidth = sh_video->disp_w;
- sh_video->bih->biHeight = sh_video->disp_h;
- if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_PLANES, &sh_video->bih->biPlanes) != TVI_CONTROL_TRUE)
- sh_video->bih->biPlanes = 1;
- if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_BITS, &sh_video->bih->biBitCount) != TVI_CONTROL_TRUE)
- sh_video->bih->biBitCount = 12;
- sh_video->bih->biCompression = sh_video->format;
- sh_video->bih->biSizeImage = sh_video->bih->biWidth * sh_video->bih->biHeight * 3;
+
+ printf("Output size: %dx%d\n", sh_video->disp_w, sh_video->disp_h);
demuxer->video->sh = sh_video;
sh_video->ds = demuxer->video;
demuxer->video->id = 0;
/* here comes audio init */
+ if (funcs->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE)
+ {
+ int audio_format;
+
+ sh_audio = new_sh_audio(demuxer, 0);
+
+ sh_audio->wf = malloc(sizeof(WAVEFORMATEX));
+ memset(sh_audio->wf, 0, sizeof(WAVEFORMATEX));
+
+ /* yeah, audio is present */
+ if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE)
+ goto no_audio;
+ switch(audio_format)
+ {
+ case AFMT_U8:
+ case AFMT_S8:
+ case AFMT_U16_LE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_S16_BE:
+ case AFMT_S32_LE:
+ case AFMT_S32_BE:
+ sh_audio->format = 0x1; /* PCM */
+ break;
+ case AFMT_IMA_ADPCM:
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_MPEG:
+ case AFMT_AC3:
+ default:
+ printf("%s unsupported!\n", audio_out_format_name(audio_format));
+ goto no_audio;
+ }
+
+ funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS, &sh_audio->wf->nChannels);
+ funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE, &sh_audio->wf->nSamplesPerSec);
+ funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLESIZE, &sh_audio->wf->nAvgBytesPerSec);
+
+ demuxer->audio->sh = sh_audio;
+ sh_audio->ds = demuxer->audio;
+ demuxer->audio->id = 0;
+ }
+no_audio:
+
+ /* set some params got from cmdline */
+ funcs->control(tvh->priv, TVI_CONTROL_SPC_SET_INPUT, &tv_param_input);
+
+ /* set freq in MHz - change this to float ! */
+ funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_FREQ, &tv_param_freq);
+
+ funcs->control(tvh->priv, TVI_CONTROL_TUN_GET_FREQ, &tv_param_freq);
+ printf("freq: %lu\n", tv_param_freq);
+
+ /* also start device! */
+ funcs->start(tvh->priv);
}
/* ================== STREAM_TV ===================== */
-tvi_handle_t *tv_begin()
+tvi_handle_t *tv_begin(void)
{
if (!strcmp(tv_param_driver, "dummy"))
- return tvi_init_dummy(tv_param_device);
+ return (tvi_handle_t *)tvi_init_dummy(tv_param_device);
if (!strcmp(tv_param_driver, "v4l"))
- return tvi_init_v4l(tv_param_device);
+ return (tvi_handle_t *)tvi_init_v4l(tv_param_device);
mp_msg(MSGT_TV, MSGL_ERR, "No such driver: %s\n", tv_param_driver);
return(NULL);
}
-void tv_init(tvi_handle_t *tvi)
+int tv_init(tvi_handle_t *tvh)
{
- printf("Using driver: %s\n", tvi->info->short_name);
- printf(" name: %s\n", tvi->info->name);
- printf(" author: %s\n", tvi->info->author);
- if (tvi->info->comment)
- printf(" comment: %s\n", tvi->info->comment);
+ tvi_param_t *params;
+
+ printf("Selected driver: %s\n", tvh->info->short_name);
+ printf(" name: %s\n", tvh->info->name);
+ printf(" author: %s\n", tvh->info->author);
+ if (tvh->info->comment)
+ printf(" comment: %s\n", tvh->info->comment);
+
+ params = malloc(sizeof(tvi_param_t)*2);
+ params[0].opt = malloc(strlen("input"));
+ sprintf((char *)params[0].opt, "input");
+ params[0].value = malloc(sizeof(int));
+ (int)*(void **)params[0].value = tv_param_input;
+ params[1].opt = params[1].value = NULL;
- return tvi->functions->init(tvi->priv);
+ return tvh->functions->init(tvh->priv, params);
}
#endif /* USE_TV */
diff --git a/libmpdemux/tv.h b/libmpdemux/tv.h
index c9e7e6daa6..0241eddb03 100644
--- a/libmpdemux/tv.h
+++ b/libmpdemux/tv.h
@@ -1,7 +1,10 @@
#include "config.h"
#ifdef USE_TV
-extern float tv_param_freq;
+#include "../libao2/afmt.h"
+#include "../libvo/img_format.h"
+
+extern unsigned long tv_param_freq;
extern char *tv_param_channel;
extern char *tv_param_norm;
extern int tv_param_on;
@@ -9,6 +12,7 @@ extern char *tv_param_device;
extern char *tv_param_driver;
extern int tv_param_width;
extern int tv_param_height;
+extern int tv_param_input;
typedef struct tvi_info_s
{
@@ -21,42 +25,78 @@ typedef struct tvi_info_s
typedef struct tvi_functions_s
{
int (*init)();
- int (*exit)();
+ int (*uninit)();
int (*control)();
+ int (*start)();
int (*grab_video_frame)();
int (*get_video_framesize)();
int (*grab_audio_frame)();
int (*get_audio_framesize)();
} tvi_functions_t;
+typedef struct tvi_param_s {
+ const char *opt;
+ void *value;
+} tvi_param_t;
+
typedef struct tvi_handle_s {
- tvi_info_t *info;
- tvi_functions_t *functions;
- void *priv;
+ tvi_info_t *info;
+ tvi_functions_t *functions;
+ void *priv;
+ tvi_param_t *params;
+ int seq;
} tvi_handle_t;
+
#define TVI_CONTROL_FALSE 0
#define TVI_CONTROL_TRUE 1
#define TVI_CONTROL_NA -1
#define TVI_CONTROL_UNKNOWN -2
+/* ======================== CONTROLS =========================== */
+
+/* GENERIC controls */
+#define TVI_CONTROL_IS_AUDIO 0x1
+#define TVI_CONTROL_IS_VIDEO 0x2
+#define TVI_CONTROL_IS_TUNER 0x3
+
+/* VIDEO controls */
+#define TVI_CONTROL_VID_GET_FPS 0x101
+#define TVI_CONTROL_VID_GET_PLANES 0x102
+#define TVI_CONTROL_VID_GET_BITS 0x103
+#define TVI_CONTROL_VID_CHK_BITS 0x104
+#define TVI_CONTROL_VID_SET_BITS 0x105
+#define TVI_CONTROL_VID_GET_FORMAT 0x106
+#define TVI_CONTROL_VID_CHK_FORMAT 0x107
+#define TVI_CONTROL_VID_SET_FORMAT 0x108
+#define TVI_CONTROL_VID_GET_WIDTH 0x109
+#define TVI_CONTROL_VID_CHK_WIDTH 0x110
+#define TVI_CONTROL_VID_SET_WIDTH 0x111
+#define TVI_CONTROL_VID_GET_HEIGHT 0x112
+#define TVI_CONTROL_VID_CHK_HEIGHT 0x113
+#define TVI_CONTROL_VID_SET_HEIGHT 0x114
+
+/* TUNER controls */
+#define TVI_CONTROL_TUN_GET_FREQ 0x201
+#define TVI_CONTROL_TUN_SET_FREQ 0x202
+#define TVI_CONTROL_TUN_GET_TUNER 0x203 /* update priv->tuner struct for used input */
+#define TVI_CONTROL_TUN_SET_TUNER 0x204 /* update priv->tuner struct for used input */
+#define TVI_CONTROL_TUN_GET_NORM 0x205
+#define TVI_CONTROL_TUN_SET_NORM 0x206
+
+/* AUDIO controls */
+#define TVI_CONTROL_AUD_GET_FORMAT 0x301
+#define TVI_CONTROL_AUD_GET_SAMPLERATE 0x302
+#define TVI_CONTROL_AUD_GET_SAMPLESIZE 0x303
+#define TVI_CONTROL_AUD_GET_CHANNELS 0x304
+
+/* SPECIFIC controls */
+#define TVI_CONTROL_SPC_GET_INPUT 0x401 /* set input channel (tv,s-video,composite..) */
+#define TVI_CONTROL_SPC_SET_INPUT 0x402 /* set input channel (tv,s-video,composite..) */
-#define TVI_CONTROL_VID_GET_FPS 1
-#define TVI_CONTROL_VID_GET_PLANES 2
-#define TVI_CONTROL_VID_GET_BITS 3
-#define TVI_CONTROL_VID_CHK_BITS 4
-#define TVI_CONTROL_VID_SET_BITS 5
-#define TVI_CONTROL_VID_GET_FORMAT 6
-#define TVI_CONTROL_VID_CHK_FORMAT 7
-#define TVI_CONTROL_VID_SET_FORMAT 8
-#define TVI_CONTROL_VID_GET_WIDTH 9
-#define TVI_CONTROL_VID_CHK_WIDTH 10
-#define TVI_CONTROL_VID_SET_WIDTH 11
-#define TVI_CONTROL_VID_GET_HEIGHT 12
-#define TVI_CONTROL_VID_CHK_HEIGHT 13
-#define TVI_CONTROL_VID_SET_HEIGHT 14
-
-#define TVI_CONTROL_TUN_GET_FREQ 100
-#define TVI_CONTROL_TUN_SET_FREQ 101
+//extern int demux_tv_fill_buffer(demuxer_t *demux, tvi_handle_t *tvh);
+//extern int demux_open_tv(demuxer_t *demux, tvi_handle_t *tvh);
+extern tvi_handle_t *tv_begin(void);
+extern int tv_init(tvi_handle_t *tvh);
#endif /* USE_TV */
diff --git a/libmpdemux/tvi_def.h b/libmpdemux/tvi_def.h
index 9e9973b5f9..87511951d7 100644
--- a/libmpdemux/tvi_def.h
+++ b/libmpdemux/tvi_def.h
@@ -1,6 +1,7 @@
-static int init(priv_t *priv);
-static int exit(priv_t *priv);
+static int init(priv_t *priv, tvi_param_t *params);
+static int uninit(priv_t *priv);
static int control(priv_t *priv, int cmd, void *arg);
+static int start(priv_t *priv);
static int grab_video_frame(priv_t *priv, char *buffer, int len);
static int get_video_framesize(priv_t *priv);
static int grab_audio_frame(priv_t *priv, char *buffer, int len);
@@ -9,8 +10,9 @@ static int get_audio_framesize(priv_t *priv);
static tvi_functions_t functions =
{
init,
- exit,
+ uninit,
control,
+ start,
grab_video_frame,
get_video_framesize,
grab_audio_frame,
@@ -23,7 +25,7 @@ static tvi_handle_t *new_handle()
if (!h)
return(NULL);
- h->priv = malloc(sizeof(priv_t));
+ h->priv = (priv_t *)malloc(sizeof(priv_t));
if (!h->priv)
{
free(h);
@@ -32,6 +34,8 @@ static tvi_handle_t *new_handle()
memset(h->priv, 0, sizeof(priv_t));
h->info = &info;
h->functions = &functions;
+ h->params = NULL;
+ h->seq = 0;
return(h);
}
diff --git a/libmpdemux/tvi_dummy.c b/libmpdemux/tvi_dummy.c
index 82d2c1e691..d2f9f71473 100644
--- a/libmpdemux/tvi_dummy.c
+++ b/libmpdemux/tvi_dummy.c
@@ -1,58 +1,92 @@
-#include <stdio.h>
+/*
+ Only a sample!
+*/
#include "config.h"
#ifdef USE_TV
+
+#include <stdio.h>
#include "tv.h"
+/* information about this file */
static tvi_info_t info = {
"NULL-TV",
"dummy",
"alex",
- "non-completed"
+ NULL
};
+/* private data's */
typedef struct {
+ int width;
+ int height;
} priv_t;
#include "tvi_def.h"
+/* handler creator - entry point ! */
tvi_handle_t *tvi_init_dummy(char *device)
{
return new_handle();
}
-static int init(priv_t *priv)
+/* initialisation */
+static int init(priv_t *priv, tvi_param_t *params)
+{
+ return 1;
+}
+
+/* that's the real start, we'got the format parameters (checked with control) */
+static int start(priv_t *priv)
{
}
-static int close(priv_t *priv)
+static int uninit(priv_t *priv)
{
}
static int control(priv_t *priv, int cmd, void *arg)
{
+ switch(cmd)
+ {
+ case TVI_CONTROL_IS_VIDEO:
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_GET_FORMAT:
+ (int)*(void **)arg = IMGFMT_YV12;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_SET_WIDTH:
+ priv->width = (int)*(void **)arg;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_SET_HEIGHT:
+ priv->height = (int)*(void **)arg;
+ return(TVI_CONTROL_TRUE);
+ case TVI_CONTROL_VID_CHK_WIDTH:
+ case TVI_CONTROL_VID_CHK_HEIGHT:
+ return(TVI_CONTROL_TRUE);
+ }
return(TVI_CONTROL_UNKNOWN);
}
static int grab_video_frame(priv_t *priv, char *buffer, int len)
{
- memset(buffer, 0x77, len);
+ memset(buffer, 0x42, len);
}
static int get_video_framesize(priv_t *priv)
{
- return 0;
+ /* YV12 */
+ return priv->width*priv->height*12/8;
}
static int grab_audio_frame(priv_t *priv, char *buffer, int len)
{
- memset(buffer, 0x77, len);
+ memset(buffer, 0x42, len);
}
static int get_audio_framesize(priv_t *priv)
{
- return 0;
+ return 1;
}
#endif /* USE_TV */
diff --git a/libmpdemux/tvi_v4l.c b/libmpdemux/tvi_v4l.c
index 43fb8713f4..11b80fa587 100644
--- a/libmpdemux/tvi_v4l.c
+++ b/libmpdemux/tvi_v4l.c
@@ -1,3 +1,14 @@
+/*
+ v4l interface for libmpemux/tvi
+
+ (C) Alex Beregszaszi <alex@naxine.org>
+
+ Some ideas are based on xawtv/libng's grab-v4l.c written by
+ Gerd Knorr <kraxel@bytesex.org>
+
+ CODE IS UNDER DEVELOPMENT, NO FEATURE REQUESTS PLEASE!
+*/
+
#include "config.h"
#ifdef USE_TV
@@ -5,6 +16,7 @@
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
+#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/videodev.h>
@@ -16,35 +28,168 @@
static tvi_info_t info = {
"Video for Linux TV Input",
"v4l",
- "alex",
- "non-completed"
+ "Alex Beregszaszi <alex@naxine.org>",
+ "under development"
+};
+
+struct vid_fmt {
+ int fmtid;
+ int width;
+ int height;
+ int bytesperline;
};
typedef struct {
+ /* general */
char *video_device;
int fd;
struct video_capability capability;
struct video_channel *channels;
struct video_tuner tuner;
- struct video_audio audio;
+
+ /* video */
struct video_picture picture;
+ int format; /* output format */
+ int width;
+ int height;
+ int bytesperline;
- int buffered;
struct video_mbuf mbuf;
- unsigned int *mmap;
+ unsigned char *mmap;
struct video_mmap *buf;
-
- int width;
- int height;
+ int nbuf;
+ int queue;
+
+ /* audio */
+ struct video_audio audio;
} priv_t;
#include "tvi_def.h"
static const char *device_cap[] = {
"capture", "tuner", "teletext", "overlay", "chromakey", "clipping",
- "frameram", "scales", "monochrome", NULL
+ "frameram", "scales", "monochrome", "subcapture", "mpeg-decoder",
+ "mpeg-encoder", "mjpeg-decoder", "mjpeg-encoder", NULL
};
+static const char *device_pal[] = {
+ "-", "grey", "hi240", "rgb16", "rgb24", "rgb32", "rgb15", "yuv422",
+ "yuyv", "uyvy", "yuv420", "yuv411", "raw", "yuv422p", "yuv411p",
+ "yuv420p", "yuv410p", NULL
+};
+#define PALETTE(x) ((x < sizeof(device_pal)/sizeof(char*)) ? device_pal[x] : "UNKNOWN")
+
+static int palette2depth(int palette)
+{
+ if (palette == VIDEO_PALETTE_YUV420P)
+ return 12;
+ return 32;
+}
+
+static int format2palette(int format)
+{
+ if (format == IMGFMT_YV12)
+ return VIDEO_PALETTE_YUV420P;
+ return VIDEO_PALETTE_RGB24;
+}
+
+#if 0
+struct STRTAB {
+ long nr;
+ const char *str;
+};
+
+static struct STRTAB stereo[] = {
+ { 0, "auto" },
+ { VIDEO_SOUND_MONO, "mono" },
+ { VIDEO_SOUND_STEREO, "stereo" },
+ { VIDEO_SOUND_LANG1, "lang1" },
+ { VIDEO_SOUND_LANG2, "lang1" },
+ { -1, NULL }
+};
+
+static struct STRTAB norms_v4l[] = {
+ { VIDEO_MODE_PAL, "PAL" },
+ { VIDEO_MODE_NTSC, "NTSC" },
+ { VIDEO_MODE_SECAM, "SECAM" },
+ { VIDEO_MODE_AUTO, "AUTO" },
+ { -1, NULL }
+};
+
+static struct STRTAB norms_bttv[] = {
+ { VIDEO_MODE_PAL, "PAL" },
+ { VIDEO_MODE_NTSC, "NTSC" },
+ { VIDEO_MODE_SECAM, "SECAM" },
+ { 3, "PAL-NC" },
+ { 4, "PAL-M" },
+ { 5, "PAL-N" },
+ { 6, "NTSC-JP" },
+ { -1, NULL }
+};
+
+static unsigned short _format2palette[VIDEO_FMT_COUNT] = {
+ 0, /* unused */
+ VIDEO_PALETTE_HI240, /* RGB8 */
+ VIDEO_PALETTE_GREY,
+ VIDEO_PALETTE_RGB555,
+ VIDEO_PALETTE_RGB565,
+ 0,
+ 0,
+ VIDEO_PALETTE_RGB24,
+ VIDEO_PALETTE_RGB32,
+ 0,
+ 0,
+ 0,
+ 0,
+ VIDEO_PALETTE_YUV422,
+ VIDEO_PALETTE_YUV422P,
+ VIDEO_PALETTE_YUV420P,
+};
+#define FMT2PAL(fmt) ((fmt < sizeof(format2palette)/sizeof(unsigned short)) ? \
+ format2palette[fmt] : 0);
+
+const unsigned int vfmt_to_depth[] = {
+ 0,
+ 8,
+ 8,
+ 16,
+ 16,
+ 16,
+ 16,
+ 24,
+ 32,
+ 24,
+ 32,
+ 16,
+ 32,
+ 16,
+ 16,
+ 12,
+ 0,
+ 0,
+};
+#endif
+
+static int one = 1, zero = 0;
+
+static int alarms;
+
+static void sigalarm(int signal)
+{
+ alarms++;
+ printf("v4l: timeout (got SIGALRM), hardware/driver problems?\n");
+}
+
+static void siginit(void)
+{
+ struct sigaction act, old;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sigalarm;
+ sigemptyset(&act.sa_mask);
+ sigaction(SIGALRM, &act, &old);
+}
+
tvi_handle_t *tvi_init_v4l(char *device)
{
tvi_handle_t *h;
@@ -56,10 +201,11 @@ tvi_handle_t *tvi_init_v4l(char *device)
priv = h->priv;
+ /* set video device name */
if (!device)
{
priv->video_device = malloc(strlen("/dev/video0"));
- strcpy(priv->video_device, &"/dev/video0");
+ sprintf(priv->video_device, "/dev/video0");
}
else
{
@@ -70,40 +216,52 @@ tvi_handle_t *tvi_init_v4l(char *device)
return(h);
}
-static int init(priv_t *priv)
+static int init(priv_t *priv, tvi_param_t *params)
{
int i;
priv->fd = open(priv->video_device, O_RDONLY);
if (priv->fd == -1)
{
- printf("v4l: open %s: %s\n", priv->video_device, strerror(errno));
+ printf("v4l: unable to open '%s': %s\n",
+ priv->video_device, strerror(errno));
goto err;
}
printf("fd: %d\n", priv->fd);
- /* get capabilities */
+ /* get capabilities (priv->capability is needed!) */
if (ioctl(priv->fd, VIDIOCGCAP, &priv->capability) == -1)
{
- printf("v4l: ioctl error: %s\n", strerror(errno));
+ printf("ioctl get capabilites error: %s\n", strerror(errno));
goto err;
}
fcntl(priv->fd, F_SETFD, FD_CLOEXEC);
-
- printf("capabilites: ");
+ siginit();
+
+#if 0
+ for (i=0; params[i].opt; i++)
+ {
+ if (!strcmp(params[i].opt, "input"))
+ priv->input = (int)*(void **)params[i].value;
+ }
+ printf("priv->input: %d\n", priv->input);
+#endif
+
+ printf("Selected device: %s\n", priv->capability.name);
+ printf(" Capabilites: ");
for (i = 0; device_cap[i] != NULL; i++)
if (priv->capability.type & (1 << i))
- printf(" %s", device_cap[i]);
+ printf("%s ", device_cap[i]);
printf("\n");
- printf(" type: %d\n", priv->capability.type);
- printf(" size: %dx%d => %dx%d\n",
+ printf(" Device type: %d\n", priv->capability.type);
+ printf(" Supported sizes: %dx%d => %dx%d\n",
priv->capability.minwidth, priv->capability.minheight,
priv->capability.maxwidth, priv->capability.maxheight);
priv->width = priv->capability.minwidth;
priv->height = priv->capability.minheight;
- printf(" channels: %d\n", priv->capability.channels);
+ printf(" Inputs: %d\n", priv->capability.channels);
priv->channels = malloc(sizeof(struct video_channel)*priv->capability.channels);
memset(priv->channels, 0, sizeof(struct video_channel)*priv->capability.channels);
@@ -111,40 +269,51 @@ static int init(priv_t *priv)
{
priv->channels[i].channel = i;
ioctl(priv->fd, VIDIOCGCHAN, &priv->channels[i]);
- printf(" %s: tuners:%d %s%s %s%s\n",
+ printf(" %d: %s: %s%s%s%s (tuner:%d, norm:%d)\n", i,
priv->channels[i].name,
- priv->channels[i].tuners,
(priv->channels[i].flags & VIDEO_VC_TUNER) ? "tuner " : "",
(priv->channels[i].flags & VIDEO_VC_AUDIO) ? "audio " : "",
(priv->channels[i].flags & VIDEO_TYPE_TV) ? "tv " : "",
- (priv->channels[i].flags & VIDEO_TYPE_CAMERA) ? "camera " : "");
+ (priv->channels[i].flags & VIDEO_TYPE_CAMERA) ? "camera " : "",
+ priv->channels[i].tuners,
+ priv->channels[i].norm);
}
- if (priv->capability.type & VID_TYPE_CAPTURE)
+ if (!(priv->capability.type & VID_TYPE_CAPTURE))
{
- if (ioctl(priv->fd, VIDIOCGMBUF, &priv->mbuf) == 0)
- {
- printf("mbuf: size=%d, frames=%d (first offset: %p)\n",
- priv->mbuf.size, priv->mbuf.frames, priv->mbuf.offsets[0]);
- priv->mmap = mmap(0, priv->mbuf.size, PROT_READ|PROT_WRITE,
- MAP_SHARED, priv->fd, 0);
- if (priv->mmap == -1)
- perror("mmap");
- }
- else
- priv->mmap = -1;
+ printf("Only grabbing supported (for overlay use another program)\n");
+ goto err;
+ }
+
+ /* map grab buffer */
+ if (ioctl(priv->fd, VIDIOCGMBUF, &priv->mbuf) == -1)
+ {
+ printf("ioctl get mbuf failed: %s\n", strerror(errno));
+ goto err;
+ }
- if (priv->mmap != -1)
- {
- priv->buf = malloc(priv->mbuf.frames * sizeof(struct video_mmap));
- memset(priv->buf, 0, priv->mbuf.frames * sizeof(struct video_mmap));
- priv->buffered = 1;
- }
- else
- priv->buffered = 0;
+ printf("mbuf: size=%d, frames=%d\n",
+ priv->mbuf.size, priv->mbuf.frames);
+ priv->mmap = mmap(0, priv->mbuf.size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, priv->fd, 0);
+ if (priv->mmap == -1)
+ {
+ printf("Unabel to map memory for buffers: %s\n", strerror(errno));
+ priv->mmap = malloc(priv->mbuf.size); /* our buffer */
}
+ if (!priv->mmap)
+ {
+ printf("Unable to allocate memory for buffers: %s\n", strerror(errno));
+ goto err;
+ }
+ printf("our buffer: %p\n", priv->mmap);
+
+ /* num of buffers */
+ priv->nbuf = priv->mbuf.frames;
- printf("buffered: %d\n", priv->buffered);
+ /* video buffers */
+ priv->buf = malloc(priv->nbuf * sizeof(struct video_mmap));
+ memset(priv->buf, 0, priv->nbuf * sizeof(struct video_mmap));
return(1);
@@ -154,32 +323,119 @@ err:
return(0);
}
-static int exit(priv_t *priv)
+static int uninit(priv_t *priv)
{
+#warning "Implement uninit!"
}
-static int tune(priv_t *priv, int freq, int chan, int norm)
+static int start(priv_t *priv)
{
- if (freq)
+ int i;
+
+
+ if (ioctl(priv->fd, VIDIOCGPICT, &priv->picture) == -1)
{
- ioctl(priv->fd, VIDIOCSFREQ, &freq);
- return(1);
+ printf("ioctl get picture failed: %s\n", strerror(errno));
+ return(0);
}
- if (chan && norm)
+ priv->picture.palette = format2palette(priv->format);
+ priv->picture.depth = palette2depth(priv->picture.palette);
+ priv->bytesperline = priv->width * priv->picture.depth / 8;
+
+ printf("Picture values:\n");
+ printf(" Depth: %d, Palette: %d (Format: %s)\n", priv->picture.depth,
+ priv->picture.palette, vo_format_name(priv->format));
+ printf(" Brightness: %d, Hue: %d, Colour: %d, Contrast: %d\n",
+ priv->picture.brightness, priv->picture.hue,
+ priv->picture.colour, priv->picture.contrast);
+
+
+ if (ioctl(priv->fd, VIDIOCSPICT, &priv->picture) == -1)
{
- /* set channel & norm ! */
+ printf("ioctl set picture failed: %s\n", strerror(errno));
+ return(0);
}
- return(0);
+ priv->nbuf = priv->mbuf.frames;
+ for (i=0; i < priv->nbuf; i++)
+ {
+ priv->buf[i].format = priv->picture.palette;
+ priv->buf[i].frame = i;
+ priv->buf[i].width = priv->width;
+ priv->buf[i].height = priv->height;
+ printf("buffer: %d => %p\n", i, &priv->buf[i]);
+ }
+
+ /* start capture */
+ if (ioctl(priv->fd, VIDIOCCAPTURE, &one) == -1)
+ {
+ printf("ioctl capture failed: %s\n", strerror(errno));
+ return(0);
+ }
}
static int control(priv_t *priv, int cmd, void *arg)
{
+ printf("debug: control(priv=%p, cmd=%d, arg=%p)\n",
+ priv, cmd, arg);
switch(