diff options
-rw-r--r-- | DOCS/man/en/mplayer.1 | 17 | ||||
-rw-r--r-- | cfg-common.h | 17 | ||||
-rwxr-xr-x | configure | 37 | ||||
-rw-r--r-- | help/help_mp-en.h | 46 | ||||
-rw-r--r-- | stream/Makefile | 1 | ||||
-rw-r--r-- | stream/stream_tv.c | 16 | ||||
-rw-r--r-- | stream/tv.c | 26 | ||||
-rw-r--r-- | stream/tv.h | 37 | ||||
-rw-r--r-- | stream/tvi_dshow.c | 3298 | ||||
-rw-r--r-- | stream/tvi_dshow.h | 693 |
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 */ @@ -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); |