diff options
Diffstat (limited to 'stream/tvi_dshow.c')
-rw-r--r-- | stream/tvi_dshow.c | 3514 |
1 files changed, 0 insertions, 3514 deletions
diff --git a/stream/tvi_dshow.c b/stream/tvi_dshow.c deleted file mode 100644 index db3004b5ba..0000000000 --- a/stream/tvi_dshow.c +++ /dev/null @@ -1,3514 +0,0 @@ -/* - * 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 file is part of MPlayer. - * - * MPlayer 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. - * - * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, 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 "osdep/timer.h" - - -#include "tv.h" -#include "mp_msg.h" -#include "frequencies.h" - - -#include "tvi_dshow.h" - -#ifndef STDCALL -// mingw64 needs this -#define STDCALL __stdcall -#endif - -static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param); - -/* -*--------------------------------------------------------------------------------------- -* -* Data structures -* -*--------------------------------------------------------------------------------------- -*/ -/** - information about this file -*/ -const 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; - -typedef enum { unknown, video, audio, vbi } stream_type; - -/** - CSampleGrabberCD definition -*/ -typedef struct CSampleGrabberCB { - ISampleGrabberCBVtbl *lpVtbl; - int refcount; - GUID interfaces[2]; - grabber_ringbuffer_t *pbuf; -} CSampleGrabberCB; - -/** - Chain related structure - */ -typedef struct { - stream_type type; ///< stream type - const GUID* majortype; ///< GUID of major mediatype (video/audio/vbi) - const GUID* pin_category; ///< pin category (pointer to one of PIN_CATEGORY_*) - - IBaseFilter *pCaptureFilter; ///< capture device filter - IAMStreamConfig *pStreamConfig; ///< for configuring stream - ISampleGrabber *pSG; ///< ISampleGrabber interface of SampleGrabber filter - IBaseFilter *pSGF; ///< IBaseFilter interface of SampleGrabber filter - IPin *pCapturePin; ///< output capture pin - IPin *pSGIn; ///< input pin of SampleGrabber filter - - grabber_ringbuffer_t *rbuf; ///< sample frabber data - CSampleGrabberCB* pCSGCB; ///< callback object - - AM_MEDIA_TYPE *pmt; ///< stream properties. - int nFormatUsed; ///< index of used format - AM_MEDIA_TYPE **arpmt; ///< available formats - void** arStreamCaps; ///< VIDEO_STREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS -} chain_t; - -typedef struct tt_stream_props_s{ - int sampling_rate; - int samples_per_line; - int offset; - int count[2]; ///< number of lines in first and second fields - int interlaced; ///< vbi data are interlaced - int bufsize; ///< required buffer size -} tt_stream_props; - -typedef struct priv { - 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 - - chain_t* chains[3]; ///< chains' data (0-video, 1-audio, 2-vbi) - - 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 - 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, 16, IMGFMT_YUY2, 0}, - {IMGFMT_YV12, &MEDIASUBTYPE_YV12, 12, IMGFMT_YV12, 0}, - {IMGFMT_IYUV, &MEDIASUBTYPE_IYUV, 12, IMGFMT_IYUV, 0}, - {IMGFMT_I420, &MEDIASUBTYPE_I420, 12, IMGFMT_I420, 0}, - {IMGFMT_UYVY, &MEDIASUBTYPE_UYVY, 16, IMGFMT_UYVY, 0}, - {IMGFMT_YVYU, &MEDIASUBTYPE_YVYU, 16, IMGFMT_YVYU, 0}, - {IMGFMT_YVU9, &MEDIASUBTYPE_YVU9, 9, 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 -* -*--------------------------------------------------------------------------------------- -*/ -// selectany can not be used with "static", fixes compilation with mingw-w64 -#undef DECLSPEC_SELECTANY -#define DECLSPEC_SELECTANY -/// CLSID definitions (used for CoCreateInstance call) -#define CLSID_SampleGrabber MP_CLSID_SampleGrabber -static DEFINE_GUID(CLSID_SampleGrabber, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B, - 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); -#define CLSID_NullRenderer MP_CLSID_NullRenderer -static DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B, - 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37); -#define CLSID_SystemDeviceEnum MP_CLSID_SystemDeviceEnum -static DEFINE_GUID(CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B, - 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86); -#define CLSID_CaptureGraphBuilder2 MP_CLSID_CaptureGraphBuilder2 -static DEFINE_GUID(CLSID_CaptureGraphBuilder2, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3, - 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5); -#define CLSID_VideoInputDeviceCategory MP_CLSID_VideoInputDeviceCategory -static DEFINE_GUID(CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, 0x11d0, - 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86); -#define CLSID_AudioInputDeviceCategory MP_CLSID_AudioInputDeviceCategory -static DEFINE_GUID(CLSID_AudioInputDeviceCategory, 0x33d9a762, 0x90c8, 0x11d0, - 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86); -#define CLSID_FilterGraph MP_CLSID_FilterGraph -static DEFINE_GUID(CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53, - 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); -#define CLSID_SystemClock MP_CLSID_SystemClock -static DEFINE_GUID(CLSID_SystemClock, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53, - 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); -#ifdef NOT_USED -#define CLSID_CaptureGraphBuilder MP_CLSID_CaptureGraphBuilder -static DEFINE_GUID(CLSID_CaptureGraphBuilder, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3, - 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5); -#define CLSID_VideoPortManager MP_CLSID_VideoPortManager -static DEFINE_GUID(CLSID_VideoPortManager, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a, - 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2); -#define IID_IPin MP_IID_IPin -static DEFINE_GUID(IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20, - 0xaf, 0x0b, 0xa7, 0x70); -#define IID_ICaptureGraphBuilder MP_IID_ICaptureGraphBuilder -static DEFINE_GUID(IID_ICaptureGraphBuilder, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3, - 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5); -#define IID_IFilterGraph MP_IID_IFilterGraph -static DEFINE_GUID(IID_IFilterGraph, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, - 0x20, 0xaf, 0x0b, 0xa7, 0x70); -#define PIN_CATEGORY_PREVIEW MP_PIN_CATEGORY_PREVIEW -static DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f, - 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); -#endif - -/// IID definitions (used for QueryInterface call) -#define IID_IReferenceClock MP_IID_IReferenceClock -static DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a, - 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); -#define IID_IAMBufferNegotiation MP_IID_IAMBufferNegotiation -static DEFINE_GUID(IID_IAMBufferNegotiation, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0, - 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5); -#define IID_IKsPropertySet MP_IID_IKsPropertySet -static DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, - 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); -#define IID_ISampleGrabber MP_IID_ISampleGrabber -static DEFINE_GUID(IID_ISampleGrabber, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD, - 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F); -#define IID_ISampleGrabberCB MP_IID_ISampleGrabberCB -static DEFINE_GUID(IID_ISampleGrabberCB, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0, - 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85); -#define IID_ICaptureGraphBuilder2 MP_IID_ICaptureGraphBuilder2 -static DEFINE_GUID(IID_ICaptureGraphBuilder2, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab, - 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d); -#define IID_ICreateDevEnum MP_IID_ICreateDevEnum -static DEFINE_GUID(IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b, - 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86); -#define IID_IGraphBuilder MP_IID_IGraphBuilder -static DEFINE_GUID(IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a, - 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); -#define IID_IAMVideoProcAmp MP_IID_IAMVideoProcAmp -static DEFINE_GUID(IID_IAMVideoProcAmp, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C, - 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56); -#define IID_IVideoWindow MP_IID_IVideoWindow -static DEFINE_GUID(IID_IVideoWindow, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, - 0x20, 0xaf, 0x0b, 0xa7, 0x70); -#define IID_IMediaControl MP_IID_IMediaControl -static DEFINE_GUID(IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a, - 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); -#define IID_IAMTVTuner MP_IID_IAMTVTuner -static DEFINE_GUID(IID_IAMTVTuner, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00, - 0xAA, 0x00, 0xBD, 0x83, 0x39); -#define IID_IAMCrossbar MP_IID_IAMCrossbar -static DEFINE_GUID(IID_IAMCrossbar, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00, - 0xa0, 0xc9, 0x11, 0x89, 0x56); -#define IID_IAMStreamConfig MP_IID_IAMStreamConfig -static DEFINE_GUID(IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c, - 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56); -#define IID_IAMAudioInputMixer MP_IID_IAMAudioInputMixer -static DEFINE_GUID(IID_IAMAudioInputMixer, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0, - 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5); -#define IID_IAMTVAudio MP_IID_IAMTVAudio -static DEFINE_GUID(IID_IAMTVAudio, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00, - 0xA0, 0xC9, 0x56, 0x02, 0x66); -#define IID_IAMAnalogVideoDecoder MP_IID_IAMAnalogVideoDecoder -static DEFINE_GUID(IID_IAMAnalogVideoDecoder, 0xC6E13350, 0x30AC, 0x11d0, 0xA1, - 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56); -#define IID_IPropertyBag MP_IID_IPropertyBag -static DEFINE_GUID(IID_IPropertyBag, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00, - 0xaa, 0x00, 0x4b, 0xb8, 0x51); -#define PIN_CATEGORY_CAPTURE MP_PIN_CATEGORY_CAPTURE -static DEFINE_GUID(PIN_CATEGORY_CAPTURE, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f, - 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); -#define PIN_CATEGORY_VIDEOPORT MP_PIN_CATEGORY_VIDEOPORT -static DEFINE_GUID(PIN_CATEGORY_VIDEOPORT, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f, - 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); -#define PIN_CATEGORY_PREVIEW MP_PIN_CATEGORY_PREVIEW -static DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f, - 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); -#define PIN_CATEGORY_VBI MP_PIN_CATEGORY_VBI -static DEFINE_GUID(PIN_CATEGORY_VBI, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f, - 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba); -#define PROPSETID_TUNER MP_PROPSETID_TUNER -static DEFINE_GUID(PROPSETID_TUNER, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00, - 0xa0, 0xc9, 0x11, 0x89, 0x56); -#define MEDIATYPE_VBI MP_MEDIATYPE_VBI -static DEFINE_GUID(MEDIATYPE_VBI, 0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00, - 0x00, 0xc0, 0xcc, 0x16, 0xba); - -#define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1) -#define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY)) - -#define DEVICE_NAME_MAX_LEN 2000 - -/*--------------------------------------------------------------------------------------- -* Methods, called only from this file -*---------------------------------------------------------------------------------------*/ - -static void set_buffer_preference(int nDiv, WAVEFORMATEX *pWF, - IPin *pOutPin, IPin *pInPin) -{ - ALLOCATOR_PROPERTIES prop; - IAMBufferNegotiation* pBN; - HRESULT hr; - - prop.cbAlign = -1; - prop.cbBuffer = pWF->nAvgBytesPerSec/nDiv; - if (!prop.cbBuffer) - prop.cbBuffer = 1; - prop.cbBuffer += pWF->nBlockAlign - 1; - prop.cbBuffer -= prop.cbBuffer % pWF->nBlockAlign; - prop.cbPrefix = -1; - prop.cBuffers = -1; - - hr=OLE_QUERYINTERFACE(pOutPin,IID_IAMBufferNegotiation,pBN); - if(FAILED(hr)) - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr); - else{ - hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop); - if(FAILED(hr)) - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr); - OLE_RELEASE_SAFE(pBN); - } - hr=OLE_QUERYINTERFACE(pInPin,IID_IAMBufferNegotiation,pBN); - if(FAILED(hr)) - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr); - else{ - hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop); - if(FAILED(hr)) - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr); - OLE_RELEASE_SAFE(pBN); - } -} -/* -*--------------------------------------------------------------------------------------- -* -* CSampleGrabberCD class. Used for receiving samples from DirectShow. -* -*--------------------------------------------------------------------------------------- -*/ -/// CSampleGrabberCD destructor -static void CSampleGrabberCB_Destroy(CSampleGrabberCB * This) -{ - free(This->lpVtbl); - free(This); -} - -/// CSampleGrabberCD IUnknown interface methods implementation -static long STDCALL CSampleGrabberCB_QueryInterface(ISampleGrabberCB * - This, - const GUID * riid, - void **ppvObject) -{ - CSampleGrabberCB *me = (CSampleGrabberCB *) This; - GUID *r; - unsigned int i = 0; - Debug printf("CSampleGrabberCB_QueryInterface(%p) called\n", This); - if (!ppvObject) - return E_POINTER; - for (r = me->interfaces; - i < sizeof(me->interfaces) / sizeof(me->interfaces[0]); r++, i++) - if (!memcmp(r, riid, sizeof(*r))) { - OLE_CALL(This, AddRef); - *ppvObject = This; - return 0; - } - Debug printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid); - return E_NOINTERFACE; -} - -static long STDCALL CSampleGrabberCB_AddRef(ISampleGrabberCB * This) -{ - CSampleGrabberCB *me = (CSampleGrabberCB *) This; - Debug printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This, - me->refcount); - return ++(me->refcount); -} - -static long STDCALL CSampleGrabberCB_Release(ISampleGrabberCB * This) -{ - CSampleGrabberCB *me = (CSampleGrabberCB *) This; - Debug printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n", - This, me->refcount - 1); - if (--(me->refcount) == 0) - CSampleGrabberCB_Destroy(me); - return 0; -} - - -static HRESULT STDCALL CSampleGrabberCB_BufferCB(ISampleGrabberCB *This, - double SampleTime, - BYTE *pBuffer, - long lBufferLen) -{ - CSampleGrabberCB *this = (CSampleGrabberCB *) This; - grabber_ringbuffer_t *rb = this->pbuf; - - if (!lBufferLen) - return E_FAIL; - - if (!rb->ringbuffer) { - rb->buffersize /= lBufferLen; - if (init_ringbuffer(rb, rb->buffersize, lBufferLen) != S_OK) - return E_FAIL; - } - mp_msg(MSGT_TV, MSGL_DBG4, - "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This, lBufferLen, SampleTime); - EnterCriticalSection(rb->pMutex); - if (rb->count >= rb->buffersize) { - rb->head = (rb->head + 1) % rb->buffersize; - rb->count--; - } - - memcpy(rb->ringbuffer[rb->tail], pBuffer, - lBufferLen < rb->blocksize ? lBufferLen : rb->blocksize); - rb->dpts[rb->tail] = SampleTime; - rb->tail = (rb->tail + 1) % rb->buffersize; - rb->count++; - LeaveCriticalSection(rb->pMutex); - - return S_OK; -} - -/// wrapper. directshow does the same when BufferCB callback is requested -static HRESULT STDCALL CSampleGrabberCB_SampleCB(ISampleGrabberCB *This, - double SampleTime, - LPMEDIASAMPLE pSample) -{ - char* buf; - long len; - long long tStart,tEnd; - HRESULT hr; - grabber_ringbuffer_t *rb = ((CSampleGrabberCB*)This)->pbuf; - - len=OLE_CALL(pSample,GetSize); - tStart=tEnd=0; - hr=OLE_CALL_ARGS(pSample,GetTime,&tStart,&tEnd); - if(FAILED(hr)){ - return hr; - } - mp_msg(MSGT_TV, MSGL_DBG4,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This,rb->count,rb->buffersize,1e-7*tStart); - hr=OLE_CALL_ARGS(pSample,GetPointer,(void*)&buf); - if(FAILED(hr)){ - return hr; - } - hr=CSampleGrabberCB_BufferCB(This,1e-7*tStart,buf,len); - return hr; - -} - -/// main grabbing routine -static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t * - pbuf) -{ - CSampleGrabberCB *This = malloc(sizeof(CSampleGrabberCB)); - if (!This) - return NULL; - - This->lpVtbl = malloc(sizeof(ISampleGrabberVtbl)); - if (!This->lpVtbl) { - CSampleGrabberCB_Destroy(This); - return NULL; - } - This->refcount = 1; - This->lpVtbl->QueryInterface = CSampleGrabberCB_QueryInterface; - This->lpVtbl->AddRef = CSampleGrabberCB_AddRef; - This->lpVtbl->Release = CSampleGrabberCB_Release; - This->lpVtbl->SampleCB = CSampleGrabberCB_SampleCB; - This->lpVtbl->BufferCB = CSampleGrabberCB_BufferCB; - - This->interfaces[0] = IID_IUnknown; - This->interfaces[1] = IID_ISampleGrabberCB; - - This->pbuf = pbuf; - - return This; -} - -/* -*--------------------------------------------------------------------------------------- -* -* ROT related methods (register, unregister) -* -*--------------------------------------------------------------------------------------- -*/ -/** -Registering graph in ROT. User will be able to connect to graph from GraphEdit. -*/ -static HRESULT AddToRot(IUnknown * pUnkGraph, DWORD * pdwRegister) -{ - IMoniker *pMoniker; - IRunningObjectTable *pROT; - WCHAR wsz[256]; - HRESULT hr; - - if (FAILED(GetRunningObjectTable(0, &pROT))) { - return E_FAIL; - } - wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR) pUnkGraph, - GetCurrentProcessId()); - hr = CreateItemMoniker(L"!", wsz, &pMoniker); - if (SUCCEEDED(hr)) { - hr = OLE_CALL_ARGS(pROT, Register, ROTFLAGS_REGISTRATIONKEEPSALIVE, - pUnkGraph, pMoniker, pdwRegister); - OLE_RELEASE_SAFE(pMoniker); - } - OLE_RELEASE_SAFE(pROT); - return hr; -} - -/// Unregistering graph in ROT -static void RemoveFromRot(DWORD dwRegister) -{ - IRunningObjectTable *pROT; - if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) { - OLE_CALL_ARGS(pROT, Revoke, dwRegister); - OLE_RELEASE_SAFE(pROT); - } -} - -/* -*--------------------------------------------------------------------------------------- -* -* ringbuffer related methods (init, destroy) -* -*--------------------------------------------------------------------------------------- -*/ -/** - * \brief ringbuffer destroying routine - * - * \param rb pointer to empty (just allocated) ringbuffer structure - * - * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure - */ -static void destroy_ringbuffer(grabber_ringbuffer_t * rb) -{ - int i; - - if (!rb) - return; - - if (rb->ringbuffer) { - for (i = 0; i < rb->buffersize; i++) - free(rb->ringbuffer[i]); - free(rb->ringbuffer); - rb->ringbuffer = NULL; - } - free(rb->dpts); - rb->dpts = NULL; - if (rb->pMutex) { - DeleteCriticalSection(rb->pMutex); - free(rb->pMutex); - rb->pMutex = NULL; - } - - rb->blocksize = 0; - rb->buffersize = 0; - rb->head = 0; - rb->tail = 0; - rb->count = 0; -} - -/** - * \brief ringbuffer initialization - * - * \param rb pointer to empty (just allocated) ringbuffer structure - * \param buffersize size of buffer in blocks - * \param blocksize size of buffer's block - * - * \return S_OK if success - * \return E_OUTOFMEMORY not enough memory - * - * \note routine does not allocates memory for grabber_rinbuffer_s structure - */ -static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize, - int blocksize) -{ - int i; - - if (!rb) - return E_OUTOFMEMORY; - - rb->buffersize = buffersize < 2 ? 2 : buffersize; - rb->blocksize = blocksize; - - mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n", - rb->buffersize, rb->blocksize); - - rb->ringbuffer = malloc(rb->buffersize * sizeof(char *)); - if (!rb) - return E_POINTER; - memset(rb->ringbuffer, 0, rb->buffersize * sizeof(char *)); - - for (i = 0; i < rb->buffersize; i++) { - rb->ringbuffer[i] = malloc(rb->blocksize * sizeof(char)); - if (!rb->ringbuffer[i]) { - destroy_ringbuffer(rb); - return E_OUTOFMEMORY; - } - } - rb->dpts = malloc(rb->buffersize * sizeof(double)); - if (!rb->dpts) { - destroy_ringbuffer(rb); - return E_OUTOFMEMORY; - } - rb->head = 0; - rb->tail = 0; - rb->count = 0; - rb->tStart = -1; - rb->pMutex = malloc(sizeof(CRITICAL_SECTION)); - if (!rb->pMutex) { - destroy_ringbuffer(rb); - return E_OUTOFMEMORY; - } - InitializeCriticalSection(rb->pMutex); - return S_OK; -} - -/* -*--------------------------------------------------------------------------------------- -* -* Tuner related methods (frequency, capabilities, etc -* -*--------------------------------------------------------------------------------------- -*/ -/** - * \brief returns string with name for givend PsysCon_* constant - * - * \param lPhysicalType constant from PhysicalConnectorType enumeration - * - * \return pointer to string with apropriate name - * - * \note - * Caller should not free returned pointer - */ -static char *physcon2str(const long lPhysicalType) -{ - int i; - for(i=0; tv_physcon_types[i].name; i++) - if(tv_physcon_types[i].type==lPhysicalType) - return tv_physcon_types[i].name; - return "Unknown"; -}; - -/** - * \brief converts MPlayer's chanlist to system country code. - * - * \param chanlist MPlayer's chanlist name - * - * \return system country code - * - * \remarks - * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified - * country (which is usually larger then MPlayer's one, so workaround will work fine). - * - * \todo - * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes. - */ -static int chanlist2country(char *chanlist) -{ - int i; - for(i=0; tv_chanlist2country[i].chanlist_name; i++) - if (!strcmp(chanlist, tv_chanlist2country[i].chanlist_name)) - break; - return tv_chanlist2country[i].country_code; -} - -/** - * \brief loads specified resource from module and return pointer to it - * - * \param hDLL valid module desriptor - * \param index index of resource. resource with name "#<index>" will be loaded - * - * \return pointer to loader resource or NULL if error occured - */ -static void *GetRC(HMODULE hDLL, int index) -{ - char szRCDATA[10]; - char szName[10]; - HRSRC hRes; - HGLOBAL hTable; - - snprintf(szRCDATA, 10, "#%d", (int)RT_RCDATA); - snprintf(szName, 10, "#%d", index); - - hRes = FindResource(hDLL, szName, szRCDATA); - if (!hRes) { - return NULL; - } - hTable = LoadResource(hDLL, hRes); - if (!hTable) { - return NULL; - } - return LockResource(hTable); -} - -/** - * \brief loads frequency table for given country from kstvtune.ax - * - * \param[in] nCountry - country code - * \param[in] nInputType (TunerInputCable or TunerInputAntenna) - * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies - * \param[out] pnLen length of array - * \param[out] pnFirst - channel number of first entry in array (nChannelMax) - * - * \return S_OK if success - * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL - * \return E_FAIL error occured during load - * - * \remarks - * - array must be freed by caller - * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL - */ -static HRESULT load_freq_table(int nCountry, int nInputType, - long **pplFreqTable, int *pnLen, - int *pnFirst) -{ - HMODULE hDLL; - long *plFreqTable; - TRCCountryList *pCountryList; - int i, index; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table called %d (%s)\n",nCountry,nInputType == TunerInputAntenna ? "broadcast" : "cable"); - /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */ - - if (!pplFreqTable || !pnFirst || !pnLen) - return E_POINTER; - if (!nCountry) - return E_FAIL; - - hDLL = LoadLibrary("kstvtune.ax"); - if (!hDLL) { - return E_FAIL; - } - pCountryList = GetRC(hDLL, 9999); - if (!pCountryList) { - FreeLibrary(hDLL); - return E_FAIL; - } - for (i = 0; pCountryList[i].CountryCode != 0; i++) - if (pCountryList[i].CountryCode == nCountry) - break; - if (pCountryList[i].CountryCode == 0) { - FreeLibrary(hDLL); - return E_FAIL; - } - if (nInputType == TunerInputCable) - index = pCountryList[i].CableFreqTable; - else - index = pCountryList[i].BroadcastFreqTable; - - plFreqTable = GetRC(hDLL, index); //First element is number of first channel, second - number of last channel - if (!plFreqTable) { - FreeLibrary(hDLL); - return E_FAIL; - } - *pnFirst = plFreqTable[0]; - *pnLen = (int) (plFreqTable[1] |