summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/mplayer.117
-rw-r--r--cfg-common.h17
-rwxr-xr-xconfigure37
-rw-r--r--help/help_mp-en.h46
-rw-r--r--stream/Makefile1
-rw-r--r--stream/stream_tv.c16
-rw-r--r--stream/tv.c26
-rw-r--r--stream/tv.h37
-rw-r--r--stream/tvi_dshow.c3298
-rw-r--r--stream/tvi_dshow.h693
10 files changed, 4175 insertions, 13 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index 9e6a8a9c93..d06c2d0559 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -1909,6 +1909,23 @@ as primary language until a type 28 packet is received.
Useful when the teletext system uses a non-latin character set, but language
codes are not transmitted via teletext type 28 packets for some reason.
To see a list of supported language codes set this option to \-1.
+.IPs "hidden_video_renderer (dshow only)"
+Terminate stream with video renderer instead of Null renderer (default: off).
+Will help if video freezes but audio does not.
+NOTE: May not work with \-vo directx and \-vf crop combination.
+.IPs "hidden_vp_renderer (dshow only)"
+Terminate VideoPort pin stream with video renderer
+instead of removing it from the graph (default: off).
+Useful if your card has a VideoPort pin and video is choppy.
+NOTE: May not work with \-vo directx and \-vf crop combination.
+.IPs "system_clock (dshow only)"
+Use system clock as sync source instead of the default graph clock (usually the clock
+from one of the live sources in graph).
+.IPs "normalize_audio_chunks (dshow only)"
+Create audio chunks with a time length equal to
+video frame time length (default: off).
+Some audio cards create audio chunks about 0.5s in size, resulting in
+choppy video when using immediatemode=0.
.RE
.
.TP
diff --git a/cfg-common.h b/cfg-common.h
index 1fde9d2f6b..960d5519e6 100644
--- a/cfg-common.h
+++ b/cfg-common.h
@@ -426,7 +426,7 @@ m_option_t tvopts_conf[]={
{"chanlist", &stream_tv_defaults.chanlist, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"norm", &stream_tv_defaults.norm, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"automute", &stream_tv_defaults.automute, CONF_TYPE_INT, CONF_RANGE, 0, 255, NULL},
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
{"normid", &stream_tv_defaults.normid, CONF_TYPE_INT, 0, 0, 0, NULL},
#endif
{"width", &stream_tv_defaults.width, CONF_TYPE_INT, 0, 0, 4096, NULL},
@@ -440,9 +440,12 @@ m_option_t tvopts_conf[]={
{"hue", &stream_tv_defaults.hue, CONF_TYPE_INT, CONF_RANGE, -100, 100, NULL},
{"saturation", &stream_tv_defaults.saturation, CONF_TYPE_INT, CONF_RANGE, -100, 100, NULL},
{"gain", &stream_tv_defaults.gain, CONF_TYPE_INT, CONF_RANGE, -1, 100, NULL},
-#if defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)
+#if defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
+ {"buffersize", &stream_tv_defaults.buffer_size, CONF_TYPE_INT, CONF_RANGE, 16, 1024, NULL},
{"amode", &stream_tv_defaults.amode, CONF_TYPE_INT, CONF_RANGE, 0, 3, NULL},
{"volume", &stream_tv_defaults.volume, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL},
+#endif
+#if defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)
{"bass", &stream_tv_defaults.bass, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL},
{"treble", &stream_tv_defaults.treble, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL},
{"balance", &stream_tv_defaults.balance, CONF_TYPE_INT, CONF_RANGE, 0, 65535, NULL},
@@ -464,6 +467,16 @@ m_option_t tvopts_conf[]={
{"tlang", &stream_tv_defaults.tlang, CONF_TYPE_INT, CONF_RANGE, -1, 0x7f, NULL},
#endif /* HAVE_TV_TELETEXT */
{"audioid", &stream_tv_defaults.audio_id, CONF_TYPE_INT, CONF_RANGE, 0, 9, NULL},
+#ifdef HAVE_TV_DSHOW
+ {"hidden_video_renderer", &stream_tv_defaults.hidden_video_renderer, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+ {"nohidden_video_renderer", &stream_tv_defaults.hidden_video_renderer, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+ {"hidden_vp_renderer", &stream_tv_defaults.hidden_vp_renderer, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+ {"nohidden_vp_renderer", &stream_tv_defaults.hidden_vp_renderer, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+ {"system_clock", &stream_tv_defaults.system_clock, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+ {"nosystem_clock", &stream_tv_defaults.system_clock, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+ {"normalize_audio_chunks", &stream_tv_defaults.normalize_audio_chunks, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+ {"nonormalize_audio_chunks", &stream_tv_defaults.normalize_audio_chunks, CONF_TYPE_FLAG, 0, 0, 0, NULL},
+#endif
{NULL, NULL, 0, 0, 0, 0, NULL}
};
#endif /* USE_TV */
diff --git a/configure b/configure
index f862f60ea1..50c33ff836 100755
--- a/configure
+++ b/configure
@@ -612,6 +612,7 @@ _tv=yes
_tv_v4l1=auto
_tv_v4l2=auto
_tv_bsdbt848=auto
+_tv_dshow=auto
_tv_teletext=auto
_pvr=auto
_network=yes
@@ -975,6 +976,8 @@ for ac_option do
--disable-tv-v4l1) _tv_v4l1=no ;;
--enable-tv-v4l2) _tv_v4l2=yes ;;
--disable-tv-v4l2) _tv_v4l2=no ;;
+ --enable-tv-dshow) _tv_dshow=yes ;;
+ --disable-tv-dshow) _tv_dshow=no ;;
--enable-tv-teletext) _tv_teletext=yes ;;
--disable-tv-teletext) _tv_teletext=no ;;
--enable-radio) _radio=yes ;;
@@ -6805,6 +6808,32 @@ EOF
fi #if bsd
+echocheck "DirectShow TV interface"
+if test "$_tv_dshow" = auto ; then
+ _tv_dshow=no
+ if test "$_tv" = yes && win32 ; then
+ cat > $TMPC <<EOF
+#include <ole2.h>
+int main(void) {
+ void* p;
+ CoCreateInstance((GUID*)&GUID_NULL, NULL, CLSCTX_INPROC_SERVER, &GUID_NULL, &p);
+ return 0;
+}
+EOF
+ cc_check -lole32 -luuid && _tv_dshow=yes
+ fi
+fi
+if test "$_tv_dshow" = yes ; then
+ _inputmodules="tv-dshow $_inputmodules"
+ _def_tv_dshow='#define HAVE_TV_DSHOW 1'
+ _ld_extra="$_ld_extra -lole32 -luuid"
+else
+ _noinputmodules="tv-dshow $_noinputmodules"
+ _def_tv_dshow='#undef HAVE_TV_DSHOW'
+fi
+echores "$_tv_dshow"
+
+
echocheck "Video 4 Linux TV interface"
if test "$_tv_v4l1" = auto ; then
_tv_v4l1=no
@@ -6859,8 +6888,8 @@ echores "$_tv_v4l2"
echocheck "TV teletext interface"
if test "$_tv_teletext" = auto ; then
_tv_teletext=no
- if test "$_freetype" = yes && test "$_pthreads" = yes ; then
- if test "$_tv_v4l2" = yes || test "$_v4l" = yes ; then
+ if test "$_freetype" = yes && test "$_pthreads" = yes; then
+ if test "$_tv_v4l2" = yes || test "$_v4l" = yes || test "$_tv_dshow" = yes; then
_tv_teletext=yes
fi
fi
@@ -7621,6 +7650,7 @@ TV = $_tv
TV_V4L = $_tv_v4l
TV_V4L1 = $_tv_v4l1
TV_V4L2 = $_tv_v4l2
+TV_DSHOW = $_tv_dshow
TV_BSDBT848 = $_tv_bsdbt848
TV_TELETEXT = $_tv_teletext
AUDIO_INPUT = $_audio_input
@@ -8167,6 +8197,9 @@ $_def_tv_v4l1
/* Enable Video 4 Linux 2 TV interface support */
$_def_tv_v4l2
+/* Enable DirectShow TV interface support */
+$_def_tv_dshow
+
/* *BSD BrookTree headers */
$_def_ioctl_meteor_h_name
$_def_ioctl_bt848_h_name
diff --git a/help/help_mp-en.h b/help/help_mp-en.h
index 5f89d9c582..b3bf8c25a7 100644
--- a/help/help_mp-en.h
+++ b/help/help_mp-en.h
@@ -2099,3 +2099,49 @@ static char help_text[]=
#define MSGTR_TV_Bt848UnableToStopCapture "tvi_bsdbt848: Unable to stop capture. Error: %s\n"
#define MSGTR_TV_TTSupportedLanguages "Supported Teletext languages:\n"
#define MSGTR_TV_TTSelectedLanguage "Selected default teletext language: %s\n"
+
+//tvi_dshow.c
+#define MSGTR_TVI_DS_UnableConnectInputVideoDecoder "Unable to connect given input to video decoder. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableConnectInputAudioDecoder "Unable to connect given input to audio decoder. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableSelectVideoFormat "tvi_dshow: Unable to select video format. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableSelectAudioFormat "tvi_dshow: Unable to select audio format. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableGetMediaControlInterface "tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableStartGraph "tvi_dshow: Unable to start graph! Error:0x%x\n"
+#define MSGTR_TVI_DS_DeviceNotFound "tvi_dshow: Device #%d not found\n"
+#define MSGTR_TVI_DS_UnableGetDeviceName "tvi_dshow: Unable to get name for device #%d\n"
+#define MSGTR_TVI_DS_UsingDevice "tvi_dshow: Using device #%d: %s\n"
+#define MSGTR_TVI_DS_DeviceName "tvi_dshow: Device #%d: %s\n"
+#define MSGTR_TVI_DS_DirectGetFreqFailed "tvi_dshow: Unable to get frequency directly. OS built-in channels table will be used.\n"
+#define MSGTR_TVI_DS_DirectSetFreqFailed "tvi_dshow: Unable to set frequency directly. OS built-in channels table will be used.\n"
+#define MSGTR_TVI_DS_SupportedNorms "tvi_dshow: supported norms:"
+#define MSGTR_TVI_DS_AvailableVideoInputs "tvi_dshow: available video inputs:"
+#define MSGTR_TVI_DS_AvailableAudioInputs "tvi_dshow: available audio inputs:"
+//following phrase will be printed near the selected audio/video input
+#define MSGTR_TVI_DS_InputSelected "(selected)"
+#define MSGTR_TVI_DS_UnableExtractFreqTable "tvi_dshow: Unable to load frequency table from kstvtune.ax\n"
+#define MSGTR_TVI_DS_WrongDeviceParam "tvi_dshow: Wrong device parameter: %s\n"
+#define MSGTR_TVI_DS_WrongDeviceIndex "tvi_dshow: Wrong device index: %d\n"
+#define MSGTR_TVI_DS_WrongADeviceParam "tvi_dshow: Wrong adevice parameter: %s\n"
+#define MSGTR_TVI_DS_WrongADeviceIndex "tvi_dshow: Wrong adevice index: %d\n"
+
+#define MSGTR_TVI_DS_SamplerateNotsupported "tvi_dshow: Samplerate %d is not supported by device. Failing back to first available.\n"
+#define MSGTR_TVI_DS_VideoAdjustigNotSupported "tvi_dshow: Adjusting of brightness/hue/saturation/contrast is not supported by device\n"
+
+#define MSGTR_TVI_DS_ChangingWidthHeightNotSupported "tvi_dshow: Changing video width/height is not supported by device.\n"
+#define MSGTR_TVI_DS_SelectingInputNotSupported "tvi_dshow: Selection of capture source is not supported by device\n"
+#define MSGTR_TVI_DS_FreqTableLoaded "tvi_dshow: loaded system (%s) frequency table for country id=%d (channels:%d).\n"
+#define MSGTR_TVI_DS_ErrorParsingAudioFormatStruct "tvi_dshow: Unable to parse audio format structure.\n"
+#define MSGTR_TVI_DS_ErrorParsingVideoFormatStruct "tvi_dshow: Unable to parse video format structure.\n"
+#define MSGTR_TVI_DS_UnableSetAudioMode "tvi_dshow: Unable to set audio mode %d. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnsupportedMediaType "tvi_dshow: Unsupported media type passed to %s\n"
+#define MSGTR_TVI_DS_UnableGetsupportedVideoFormats "tvi_dshow: Unable to get supported media formats from video pin. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableGetsupportedAudioFormats "tvi_dshow: Unable to get supported media formats from audio pin. Error:0x%x Disabling audio.\n"
+#define MSGTR_TVI_DS_UnableFindNearestChannel "tvi_dshow: Unable to find nearest channel in system frequency table\n"
+#define MSGTR_TVI_DS_UnableToSetChannel "tvi_dshow: Unable to switch to nearest channel from system frequency table. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableTerminateVPPin "tvi_dshow: Unable to terminate VideoPort pin with any filter in graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildVideoSubGraph "tvi_dshow: Unable to build video chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildAudioSubGraph "tvi_dshow: Unable to build audio chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_UnableBuildVBISubGraph "tvi_dshow: Unable to build VBI chain of capture graph. Error:0x%x\n"
+#define MSGTR_TVI_DS_GraphInitFailure "tvi_dshow: Directshow graph initialization failure.\n"
+#define MSGTR_TVI_DS_NoVideoCaptureDevice "tvi_dshow: Unable to find video capture device\n"
+#define MSGTR_TVI_DS_NoAudioCaptureDevice "tvi_dshow: Unable to find audio capture device\n"
diff --git a/stream/Makefile b/stream/Makefile
index 623154359e..f69b5d350c 100644
--- a/stream/Makefile
+++ b/stream/Makefile
@@ -52,6 +52,7 @@ SRCS_COMMON-$(STREAM_CACHE) += cache2.c
SRCS_COMMON-$(STREAMING_LIVE555) += stream_livedotcom.c
SRCS_COMMON-$(TV) += stream_tv.c tv.c frequencies.c tvi_dummy.c
SRCS_COMMON-$(TV_BSDBT848) += tvi_bsdbt848.c
+SRCS_COMMON-$(TV_DSHOW) += tvi_dshow.c
SRCS_COMMON-$(TV_TELETEXT) += tvi_vbi.c
SRCS_COMMON-$(TV_V4L1) += tvi_v4l.c audio_in.c
SRCS_COMMON-$(TV_V4L2) += tvi_v4l2.c audio_in.c
diff --git a/stream/stream_tv.c b/stream/stream_tv.c
index 95ba0b97a7..4328e72df9 100644
--- a/stream/stream_tv.c
+++ b/stream/stream_tv.c
@@ -36,7 +36,7 @@ tv_param_t stream_tv_defaults = {
"europe-east", //chanlist
"pal", //norm
0, //automute
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
-1, //normid
#endif
NULL, //device
@@ -51,15 +51,18 @@ tv_param_t stream_tv_defaults = {
0, //immediate;
44100, //audiorate;
0, //audio_id
-#if defined(HAVE_TV_V4L)
+#if defined(HAVE_TV_V4L) || defined(HAVE_TV_DSHOW)
-1, //amode
-1, //volume
+#if defined(HAVE_TV_V4L)
-1, //bass
-1, //treble
-1, //balance
-1, //forcechan
0, //force_audio
+#endif
-1, //buffer_size
+#if defined(HAVE_TV_V4L)
0, //mjpeg
2, //decimation
90, //quality
@@ -68,6 +71,7 @@ tv_param_t stream_tv_defaults = {
#endif
#endif
NULL, //adevice
+#endif
0, //brightness
0, //contrast
0, //hue
@@ -80,7 +84,13 @@ tv_param_t stream_tv_defaults = {
0, //scan_autostart
50, //scan_threshold
- 0.5 //scan_period
+ 0.5, //scan_period
+#ifdef HAVE_TV_DSHOW
+ 0, //hidden_video_renderer;
+ 0, //hidden_vp_renderer;
+ 0, //system_clock;
+ 0 //normalize_audio_chunks;
+#endif
};
#define ST_OFF(f) M_ST_OFF(tv_param_t,f)
diff --git a/stream/tv.c b/stream/tv.c
index 3315905930..7443445e28 100644
--- a/stream/tv.c
+++ b/stream/tv.c
@@ -42,6 +42,9 @@ char *tv_channel_last_real;
/* enumerating drivers (like in stream.c) */
extern tvi_info_t tvi_info_dummy;
+#ifdef HAVE_TV_DSHOW
+extern tvi_info_dshow;
+#endif
#ifdef HAVE_TV_V4L1
extern tvi_info_t tvi_info_v4l;
#endif
@@ -63,6 +66,9 @@ static const tvi_info_t* tvi_driver_list[]={
#ifdef HAVE_TV_BSDBT848
&tvi_info_bsdbt848,
#endif
+#ifdef HAVE_TV_DSHOW
+ &tvi_info_dshow,
+#endif
&tvi_info_dummy,
NULL
};
@@ -200,9 +206,14 @@ static int demux_tv_fill_buffer(demuxer_t *demux, demux_stream_t *ds)
static int norm_from_string(tvi_handle_t *tvh, char* norm)
{
+ if (1
#ifdef HAVE_TV_V4L2
- if (strcmp(tvh->tv_param->driver, "v4l2") != 0) {
+ && strcmp(tvh->tv_param->driver, "v4l2") != 0 &&
#endif
+#ifdef HAVE_TV_DSHOW
+ && strcmp(tvh->tv_param->driver, "dshow") != 0
+#endif
+ ) {
if (!strcasecmp(norm, "pal"))
return TV_NORM_PAL;
else if (!strcasecmp(norm, "ntsc"))
@@ -221,7 +232,7 @@ static int norm_from_string(tvi_handle_t *tvh, char* norm)
mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TV_BogusNormParameter, norm, "PAL");
return TV_NORM_PAL;
}
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
} else {
tvi_functions_t *funcs = tvh->functions;
char str[8];
@@ -361,8 +372,15 @@ static int open_tv(tvi_handle_t *tvh)
/* set some params got from cmdline */
funcs->control(tvh->priv, TVI_CONTROL_SPC_SET_INPUT, &tvh->tv_param->input);
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
+ if (0
#ifdef HAVE_TV_V4L2
- if (!strcmp(tvh->tv_param->driver, "v4l2") && tvh->tv_param->normid >= 0) {
+ || (!strcmp(tvh->tv_param->driver, "v4l2") && tvh->tv_param->normid >= 0)
+#endif
+#ifdef HAVE_TV_DSHOW
+ || (!strcmp(tvh->tv_param->driver, "dshow") && tvh->tv_param->normid >= 0)
+#endif
+ ) {
mp_msg(MSGT_TV, MSGL_V, MSGTR_TV_SelectedNormId, tvh->tv_param->normid);
if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->tv_param->normid) != TVI_CONTROL_TRUE) {
mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_CannotSetNorm);
@@ -376,7 +394,7 @@ static int open_tv(tvi_handle_t *tvh)
if (funcs->control(tvh->priv, TVI_CONTROL_TUN_SET_NORM, &tvh->norm) != TVI_CONTROL_TRUE) {
mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_CannotSetNorm);
}
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
}
#endif
diff --git a/stream/tv.h b/stream/tv.h
index ff04a901d3..acd78f108f 100644
--- a/stream/tv.h
+++ b/stream/tv.h
@@ -11,7 +11,7 @@ typedef struct tv_param_s {
char *chanlist;
char *norm;
int automute;
-#ifdef HAVE_TV_V4L2
+#if defined(HAVE_TV_V4L2) || defined(HAVE_TV_DSHOW)
int normid;
#endif
char *device;
@@ -26,15 +26,18 @@ typedef struct tv_param_s {
int immediate;
int audiorate;
int audio_id;
-#if defined(HAVE_TV_V4L)
+#if defined(HAVE_TV_V4L) || defined(HAVE_TV_DSHOW)
int amode;
int volume;
+#if defined(HAVE_TV_V4L)
int bass;
int treble;
int balance;
int forcechan;
int force_audio;
+#endif
int buffer_size;
+#if defined(HAVE_TV_V4L)
int mjpeg;
int decimation;
int quality;
@@ -43,6 +46,7 @@ typedef struct tv_param_s {
#endif
#endif
char* adevice;
+#endif
int brightness;
int contrast;
int hue;
@@ -56,6 +60,35 @@ typedef struct tv_param_s {
int scan;
int scan_threshold;
float scan_period;
+
+#ifdef HAVE_TV_DSHOW
+ /**
+ Terminate stream with video renderer instead of Null renderer
+ Will help if video freezes but audio does not.
+ May not work with -vo directx and -vf crop combination.
+ */
+ int hidden_video_renderer;
+ /**
+ For VIVO cards VP pin have to be rendered too.
+ This tweak will cause VidePort pin stream to be terminated with video renderer
+ instead of removing it from graph.
+ Use if your card have vp pin and video is still choppy.
+ May not work with -vo directx and -vf crop combination.
+ */
+ int hidden_vp_renderer;
+ /**
+ Use system clock as sync source instead of default graph clock (usually the clock
+ from one of live sources in graph.
+ */
+ int system_clock;
+ /**
+ Some audio cards creates audio chunks with about 0.5 sec size.
+ This can cause choppy video when using mplayer with immediatemode=0
+ Use followingtweak to decrease audio chunk sizes.
+ It will create audio chunks with time length equal to one video frame time.
+ */
+ int normalize_audio_chunks;
+#endif
} tv_param_t;
extern tv_param_t stream_tv_defaults;
diff --git a/stream/tvi_dshow.c b/stream/tvi_dshow.c
new file mode 100644
index 0000000000..43ab094c2f
--- /dev/null
+++ b/stream/tvi_dshow.c
@@ -0,0 +1,3298 @@
+/*
+ * TV support under Win32
+ *
+ * (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>.
+ *
+ * Based on tvi_dummy.c with help of tv.c, tvi_v4l2.c code .
+ *
+ * -------------------------------------------------------------------------------
+ *
+ * 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 of the License, 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * -------------------------------------------------------------------------------
+ *
+ *
+ * WARNING: This is alpha code!
+ *
+ * Abilities:
+ * * Watching TV under Win32 using WDM Capture driver and DirectShow
+ * * Grabbing synchronized audio/video with mencoder (synchronization is beeing done by DirectShow)
+ * * If device driver provides IAMStreamConfig interface, user can choose width/height with "-tv height=<h>:width=<w>"
+ * * Adjusting BRIGHTNESS,HUE,SATURATION,CONTRAST if supported by device
+ * * Selecting Tuner,S-Video,... as media source
+ * * User can select used video capture device, passing -tv device=<dev#>
+ * * User can select used audio input, passing -tv audioid=<input#>
+ *
+ * options which will not be implemented (probably sometime in future, if possible):
+ * * alsa
+ * * mjpeg
+ * * decimation=<1|2|4>
+ * * quality=<0\-100>
+ * * forceaudio
+ * * forcechan=<1\-2>
+ * * [volume|bass|treble|balance]
+ *
+ * Works with:
+ * - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
+ * Partially works with:
+ * - ATI 9200 VIVO based card
+ * - ATI AIW 7500
+ * - nVidia Ti-4400
+ *
+ * Known bugs:
+ * * stream goes with 24.93 FPS (NTSC), while reporting 25 FPS (PAL) ?!
+ * * direct set frequency call does not work ('Insufficient Buffer' error)
+ * * audio stream goes with about 1 sample/sec rate when capturing sound from audio card
+ *
+ * TODO:
+ * * check audio with small buffer on vivo !!!
+ * * norm for IAMVideoDecoder and for IAMTVtuner - differs !!
+ * * check how to change TVFormat on VIVO card without tuner
+ * * Flip image upside-down for RGB formats.
+ * *
+ * * remove debug sleep()
+ * * Add some notes to methods' parameters
+ * * refactor console messages
+ * * check using header files and keep only needed
+ * * add additional comments to methods' bodies
+ *
+ */
+
+
+/// \ingroup tvi_dshow
+
+#include "config.h"
+
+#include <stdio.h>
+#include "libmpcodecs/img_format.h"
+#include "libaf/af_format.h"
+#include "help_mp.h"
+#include "osdep/timer.h"
+
+
+#include "tv.h"
+#include "mp_msg.h"
+#include "frequencies.h"
+
+
+#include "tvi_dshow.h"
+
+static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param);
+
+/*
+*---------------------------------------------------------------------------------------
+*
+* Data structures
+*
+*---------------------------------------------------------------------------------------
+*/
+/**
+ information about this file
+*/
+tvi_info_t tvi_info_dshow = {
+ tvi_init_dshow,
+ "DirectShow TV",
+ "dshow",
+ "Vladimir Voroshilov",
+ "Very experimental!! Use with caution"
+};
+
+
+/**
+ringbuffer related info
+*/
+typedef struct {
+ CRITICAL_SECTION *pMutex; ///< pointer to critical section (mutex)
+ char **ringbuffer; ///< ringbuffer array
+ double*dpts; ///< samples' timestamps
+
+ int buffersize; ///< size of buffer in blocks
+ int blocksize; ///< size of individual block
+ int head; ///< index of first valid sample
+ int tail; ///< index of last valid sample
+ int count; ///< count of valid samples in ringbuffer
+ double tStart; ///< pts of first sample (first sample should have pts 0)
+} grabber_ringbuffer_t;
+
+/**
+ CSampleGrabberCD definition
+*/
+typedef struct CSampleGrabberCB {
+ ISampleGrabberCBVtbl *lpVtbl;
+ int refcount;
+ GUID interfaces[2];
+ grabber_ringbuffer_t *pbuf;
+} CSampleGrabberCB;
+
+typedef struct {
+ int dev_index; ///< capture device index in device list (defaul: 0, first available device)
+ int adev_index; ///< audio capture device index in device list (default: -1, not used)
+ int immediate_mode; ///< immediate mode (no sound capture)
+ int state; ///< state: 1-filter graph running, 0-filter graph stopped
+ int direct_setfreq_call; ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency
+ int direct_getfreq_call; ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency
+
+ int fcc; ///< used video format code (FourCC)
+ int width; ///< picture width (default: auto)
+ int height; ///< picture height (default: auto)
+
+ int channels; ///< number of audio channels (default: auto)
+ int samplerate; ///< audio samplerate (default: auto)
+
+ long *freq_table; ///< frequency table (in Hz)
+ int freq_table_len; ///< length of freq table
+ int first_channel; ///< channel number of first entry in freq table
+ int input; ///< used input
+
+ // video related stuff
+ int nVideoFormatUsed; ///< index of used video format
+ AM_MEDIA_TYPE **arpmtVideo; ///< available video formats
+ VIDEO_STREAM_CONFIG_CAPS **arVideoCaps; ///< capabilities of output video
+ AM_MEDIA_TYPE *pmtVideo; ///< video stream properties
+ grabber_ringbuffer_t *v_buf;
+ IBaseFilter *pVideoFilter; ///< interface for capture device
+ IAMStreamConfig *pVideoStreamConfig; ///< for configuring video stream
+
+ // audio related stuff
+ int nAudioFormatUsed; ///< index of used audio format
+ AM_MEDIA_TYPE **arpmtAudio; ///< available audio formats
+ AUDIO_STREAM_CONFIG_CAPS **arAudioCaps; ///< capabilities of output audio
+ AM_MEDIA_TYPE *pmtAudio; ///< audio stream properties.
+ grabber_ringbuffer_t *a_buf;
+ IBaseFilter *pAudioFilter; ///< interface for audio capture device (if adevice passed)
+ IAMStreamConfig *pAudioStreamConfig; ///< for configuring audio stream
+
+ AM_MEDIA_TYPE *pmtVBI; ///< available audio formats
+ grabber_ringbuffer_t *vbi_buf;
+
+ IAMTVTuner *pTVTuner; ///< interface for tuner device
+ IGraphBuilder *pGraph; ///< filter graph
+ ICaptureGraphBuilder2 *pBuilder; ///< graph builder
+ IMediaControl *pMediaControl; ///< interface for controlling graph (start, stop,...)
+ IAMVideoProcAmp *pVideoProcAmp; ///< for adjusting hue,saturation,etc
+ IAMCrossbar *pCrossbar; ///< for selecting input (Tuner,Composite,S-Video,...)
+ DWORD dwRegister; ///< allow graphedit to connect to our graph
+ CSampleGrabberCB* pCSGCB; ///< callback object
+ void *priv_vbi; ///< private VBI data structure
+ tt_stream_props tsp; ///< data for VBI initialization
+
+ tv_param_t* tv_param; ///< TV parameters
+} priv_t;
+
+#include "tvi_def.h"
+
+/**
+ country table entry structure (for loading freq table stored in kstvtuner.ax
+
+ \note
+ structure have to be 2-byte aligned and have 10-byte length!!
+*/
+typedef struct __attribute__((__packed__)) {
+ WORD CountryCode; ///< Country code
+ WORD CableFreqTable; ///< index of resource with frequencies for cable channels
+ WORD BroadcastFreqTable; ///< index of resource with frequencies for broadcast channels
+ DWORD VideoStandard; ///< used video standard
+} TRCCountryList;
+/**
+ information about image formats
+*/
+typedef struct {
+ uint32_t fmt; ///< FourCC
+ const GUID *subtype; ///< DirectShow's subtype
+ int nBits; ///< number of bits
+ int nCompression; ///< complression
+ int tail; ///< number of additional bytes followed VIDEOINFOHEADER structure
+} img_fmt;
+
+/*
+*---------------------------------------------------------------------------------------
+*
+* Methods forward declaration
+*
+*---------------------------------------------------------------------------------------
+*/
+static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
+ int blocksize);
+static HRESULT show_filter_info(IBaseFilter * pFilter);
+#if 0
+//defined in current MinGW release
+HRESULT STDCALL GetRunningObjectTable(DWORD, IRunningObjectTable **);
+HRESULT STDCALL CreateItemMoniker(LPCOLESTR, LPCOLESTR, IMoniker **);
+#endif
+static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
+ pbuf);
+static int set_crossbar_input(priv_t * priv, int input);
+static int subtype2imgfmt(const GUID * subtype);
+
+/*
+*---------------------------------------------------------------------------------------
+*
+* Global constants and variables
+*
+*---------------------------------------------------------------------------------------
+*/
+/**
+ lookup tables for physical connector types
+ */
+static const struct {
+ long type;
+ char *name;
+} tv_physcon_types[]={
+ {PhysConn_Video_Tuner, "Tuner" },
+ {PhysConn_Video_Composite, "Composite" },
+ {PhysConn_Video_SVideo, "S-Video" },
+ {PhysConn_Video_RGB, "RGB" },
+ {PhysConn_Video_YRYBY, "YRYBY" },
+ {PhysConn_Video_SerialDigital, "SerialDigital" },
+ {PhysConn_Video_ParallelDigital, "ParallelDigital"},
+ {PhysConn_Video_VideoDecoder, "VideoDecoder" },
+ {PhysConn_Video_VideoEncoder, "VideoEncoder" },
+ {PhysConn_Video_SCART, "SCART" },
+ {PhysConn_Video_Black, "Blaack" },
+ {PhysConn_Audio_Tuner, "Tuner" },
+ {PhysConn_Audio_Line, "Line" },
+ {PhysConn_Audio_Mic, "Mic" },
+ {PhysConn_Audio_AESDigital, "AESDiital" },
+ {PhysConn_Audio_SPDIFDigital, "SPDIFDigital" },
+ {PhysConn_Audio_AudioDecoder, "AudioDecoder" },
+ {PhysConn_Audio_SCSI, "SCSI" },
+ {PhysConn_Video_SCSI, "SCSI" },
+ {PhysConn_Audio_AUX, "AUX" },
+ {PhysConn_Video_AUX, "AUX" },
+ {PhysConn_Audio_1394, "1394" },
+ {PhysConn_Video_1394, "1394" },
+ {PhysConn_Audio_USB, "USB" },
+ {PhysConn_Video_USB, "USB" },
+ {-1, NULL }
+};
+
+static const struct {
+ char *chanlist_name;
+ int country_code;
+} tv_chanlist2country[]={
+ {"us-bcast", 1},
+ {"russia", 7},
+ {"argentina", 54},
+ {"japan-bcast", 81},
+ {"china-bcast", 86},
+ {"southafrica", 27},
+ {"australia", 61},
+ {"ireland", 353},
+ {"france", 33},
+ {"italy", 39},
+ {"newzealand", 64},
+ //directshow table uses eastern europe freq table for russia
+ {"europe-east", 7},
+ //directshow table uses western europe freq table for germany
+ {"europe-west", 49},
+ /* cable channels */
+ {"us-cable", 1},
+ {"us-cable-hrc", 1},
+ {"japan-cable", 81},
+ //default is USA
+ {NULL, 1}
+};
+
+/**
+ array, contains information about various supported (i hope) image formats
+*/
+static const img_fmt img_fmt_list[] = {
+ {IMGFMT_YUY2, &MEDIASUBTYPE_YUY2, 0, IMGFMT_YUY2, 0},
+ {IMGFMT_YV12, &MEDIASUBTYPE_YV12, 0, IMGFMT_YV12, 0},
+ {IMGFMT_IYUV, &MEDIASUBTYPE_IYUV, 0, IMGFMT_IYUV, 0},
+ {IMGFMT_I420, &MEDIASUBTYPE_I420, 0, IMGFMT_I420, 0},
+ {IMGFMT_UYVY, &MEDIASUBTYPE_UYVY, 0, IMGFMT_UYVY, 0},
+ {IMGFMT_YVYU, &MEDIASUBTYPE_YVYU, 0, IMGFMT_YVYU, 0},
+ {IMGFMT_YVU9, &MEDIASUBTYPE_YVU9, 0, IMGFMT_YVU9, 0},
+ {IMGFMT_BGR32, &MEDIASUBTYPE_RGB32, 32, 0, 0},
+ {IMGFMT_BGR24, &MEDIASUBTYPE_RGB24, 24, 0, 0},
+ {IMGFMT_BGR16, &MEDIASUBTYPE_RGB565, 16, 3, 12},
+ {IMGFMT_BGR15, &MEDIASUBTYPE_RGB555, 16, 3, 12},
+ {0, &GUID_NULL, 0, 0, 0}
+};
+
+#define TV_NORMS_COUNT 19
+static const struct {
+ long index;
+ char *name;
+} tv_norms[TV_NORMS_COUNT] = {
+ {
+ AnalogVideo_NTSC_M, "ntsc-m"}, {
+ AnalogVideo_NTSC_M_J, "ntsc-mj"}, {
+ AnalogVideo_NTSC_433, "ntsc-433"}, {
+ AnalogVideo_PAL_B, "pal-b"}, {
+ AnalogVideo_PAL_D, "pal-d"}, {
+ AnalogVideo_PAL_G, "pal-g"}, {
+ AnalogVideo_PAL_H, "pal-h"}, {
+ AnalogVideo_PAL_I, "pal-i"}, {
+ AnalogVideo_PAL_M, "pal-m"}, {
+ AnalogVideo_PAL_N, "pal-n"}, {
+ AnalogVideo_PAL_60, "pal-60"}, {
+ AnalogVideo_SECAM_B, "secam-b"}, {
+ AnalogVideo_SECAM_D, "secam-d"}, {
+ AnalogVideo_SECAM_G, "secam-g"}, {
+ AnalogVideo_SECAM_H, "secam-h"}, {
+ AnalogVideo_SECAM_K, "secam-k"}, {
+ AnalogVideo_SECAM_K1, "secam-k1"}, {
+ AnalogVideo_SECAM_L, "secam-l"}, {
+ AnalogVideo_SECAM_L1, "secam-l1"}
+};
+static long tv_available_norms[TV_NORMS_COUNT];
+static int tv_available_norms_count = 0;
+
+
+static long *tv_available_inputs;
+static int tv_available_inputs_count = 0;
+
+/*
+*---------------------------------------------------------------------------------------
+*
+* Various GUID definitions
+*
+*---------------------------------------------------------------------------------------
+*/
+/// CLSID definitions (used for CoCreateInstance call)
+DEFINE_GUID(CLSID_SampleGrabber, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B,
+ 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
+DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B,
+ 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
+DEFINE_GUID(CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B,
+ 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
+DEFINE_GUID(CLSID_CaptureGraphBuilder2, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3,
+ 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
+DEFINE_GUID(CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, 0x11d0,
+ 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
+DEFINE_GUID(CLSID_AudioInputDeviceCategory, 0x33d9a762, 0x90c8, 0x11d0,
+ 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
+DEFINE_GUID(CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53,
+ 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(CLSID_SystemClock, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53,
+ 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+#ifdef NOT_USED
+DEFINE_GUID(CLSID_CaptureGraphBuilder, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3,
+ 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
+DEFINE_GUID(CLSID_VideoPortManager, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a,
+ 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2);
+DEFINE_GUID(IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20,
+ 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(IID_ICaptureGraphBuilder, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3,
+ 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5);
+DEFINE_GUID(IID_IFilterGraph, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
+ 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
+ 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
+#endif
+
+/// IID definitions (used for QueryInterface call)
+DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a,
+ 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
+DEFINE_GUID(IID_IAMBufferNegotiation, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0,
+ 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
+DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa,
+ 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
+DEFINE_GUID(IID_ISampleGrabber, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD,
+ 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F);
+DEFINE_GUID(IID_ISampleGrabberCB, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0,
+ 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85);