From aebfbbf2bdda8e18beef90c16da97bd335f7d3b0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 12 Aug 2012 15:30:21 +0200 Subject: Remove win32/qt/xanim/real binary codecs loading Remove the win32 loader - the win32 emulation layer, as well as the code for using DirectShow/DMO/VFW codecs. Remove loading of xanim, QuickTime, and RealMedia codecs. The win32 emulation layer is based on a very old version of wine. Apparently, wine code was copied and hacked until it was somehow able to load a limited collection of binary codecs. It poked around in the code segment of some known binary codecs to disable unsupported win32 API calls to make them work. Example from module.c: for (i=0;i<5;i++) RVA(0x19e842)[i]=0x90; // make_new_region ? for (i=0;i<28;i++) RVA(0x19e86d)[i]=0x90; // call__call_CreateCompatibleDC ? for (i=0;i<5;i++) RVA(0x19e898)[i]=0x90; // jmp_to_call_loadbitmap ? for (i=0;i<9;i++) RVA(0x19e8ac)[i]=0x90; // call__calls_OLE_shit ? for (i=0;i<106;i++) RVA(0x261b10)[i]=0x90; // disable threads Just to show how utterly insane this code is. You wouldn't want even your worst enemy to have to maintain this. In fact, it seems nobody made major changes to this code ever since it was committed. Most formats can be decoded by libavcodecs these days, and the loader couldn't be used on 64 bit platforms anyway. The same is (probably) true for the other binary codecs. General note about how support for win32 codecs could be added back: It's not possible to replace the win32 loader code by using wine as library, because modern wine can not be linked with native Linux programs for certain reasons. It would be possible to to move DirectShow video decoding into a separate process linked with wine, like the CoreAVC-for-Linux patches do. There is also the mplayer-ww fork, which uses the dshownative library to use DirectShow codecs on Windows. --- stream/tvi_dshow.c | 3514 ---------------------------------------------------- stream/tvi_dshow.h | 728 ----------- 2 files changed, 4242 deletions(-) delete mode 100644 stream/tvi_dshow.c delete mode 100644 stream/tvi_dshow.h (limited to 'stream') 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 - * - * 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=:width=" - * * 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= - * * User can select used audio input, passing -tv audioid= - * - * 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 -#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 "#" 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] - plFreqTable[0] + 1); - *pplFreqTable = malloc((*pnLen) * sizeof(long)); - if (!*pplFreqTable) { - FreeLibrary(hDLL); - return E_FAIL; - } - for (i = 0; i < *pnLen; i++) { - (*pplFreqTable)[i] = plFreqTable[i + 2]; - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table #%d => (%ld)\n",i+*pnFirst,(*pplFreqTable)[i]); - } - FreeLibrary(hDLL); - return S_OK; -} - -/** - * \brief tunes to given frequency through IKsPropertySet call - * - * \param pTVTuner IAMTVTuner interface of capture device - * \param lFreq frequency to tune (in Hz) - * - * \return S_OK success - * \return apropriate error code otherwise - * - * \note - * Due to either bug in driver or error in following code calll to IKsProperty::Set - * in this methods always fail with error 0x8007007a. - * - * \todo test code on other machines and an error - */ -static HRESULT set_frequency_direct(IAMTVTuner * pTVTuner, long lFreq) -{ - HRESULT hr; - DWORD dwSupported = 0; - DWORD cbBytes = 0; - KSPROPERTY_TUNER_MODE_CAPS_S mode_caps; - KSPROPERTY_TUNER_FREQUENCY_S frequency; - IKsPropertySet *pKSProp; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency_direct called\n"); - - memset(&mode_caps, 0, sizeof(mode_caps)); - memset(&frequency, 0, sizeof(frequency)); - - hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp); - if (FAILED(hr)) - return hr; //no IKsPropertySet interface - - mode_caps.Mode = AMTUNER_MODE_TV; - hr = OLE_CALL_ARGS(pKSProp, QuerySupported, &PROPSETID_TUNER, - KSPROPERTY_TUNER_MODE_CAPS, &dwSupported); - if (FAILED(hr)) { - OLE_RELEASE_SAFE(pKSProp); - return hr; - } - - if (!dwSupported & KSPROPERTY_SUPPORT_GET) { - OLE_RELEASE_SAFE(pKSProp); - return E_FAIL; //PROPSETID_TINER not supported - } - - hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER, - KSPROPERTY_TUNER_MODE_CAPS, - INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps), - INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps), - &mode_caps, sizeof(mode_caps), &cbBytes); - - frequency.Frequency = lFreq; - - if (mode_caps.Strategy == KS_TUNER_STRATEGY_DRIVER_TUNES) - frequency.TuningFlags = KS_TUNER_TUNING_FINE; - else - frequency.TuningFlags = KS_TUNER_TUNING_EXACT; - - if (lFreq < mode_caps.MinFrequency || lFreq > mode_caps.MaxFrequency) { - OLE_RELEASE_SAFE(pKSProp); - return E_FAIL; - } - - hr = OLE_CALL_ARGS(pKSProp, Set, &PROPSETID_TUNER, - KSPROPERTY_TUNER_FREQUENCY, - INSTANCEDATA_OF_PROPERTY_PTR(&frequency), - INSTANCEDATA_OF_PROPERTY_SIZE(frequency), - &frequency, sizeof(frequency)); - if (FAILED(hr)) { - OLE_RELEASE_SAFE(pKSProp); - return hr; - } - - OLE_RELEASE_SAFE(pKSProp); - - return S_OK; -} - -/** - * \brief find channel with nearest frequency and set it - * - * \param priv driver's private data - * \param lFreq frequency in Hz - * - * \return S_OK if success - * \return E_FAIL if error occured - */ -static HRESULT set_nearest_freq(priv_t * priv, long lFreq) -{ - HRESULT hr; - int i; - long lFreqDiff=-1; - int nChannel; - TunerInputType tunerInput; - long lInput; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq called: %ld\n", lFreq); - if(priv->freq_table_len == -1 && !priv->freq_table) { - - hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput); - if(FAILED(hr)){ //Falling back to 0 - lInput=0; - } - - hr = OLE_CALL_ARGS(priv->pTVTuner, get_InputType, lInput, &tunerInput); - - if (load_freq_table(chanlist2country(priv->tv_param->chanlist), tunerInput, &(priv->freq_table), &(priv->freq_table_len), &(priv->first_channel)) != S_OK) {//FIXME - priv->freq_table_len=0; - priv->freq_table=NULL; - mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unable to load frequency table from kstvtune.ax\n"); - return E_FAIL; - }; - mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: loaded system (%s) frequency table for country id=%d (channels:%d).\n", tunerInput == TunerInputAntenna ? "broadcast" : "cable", - chanlist2country(priv->tv_param->chanlist), priv->freq_table_len); - } - - if (priv->freq_table_len <= 0) - return E_FAIL; - - //FIXME: rewrite search algo - nChannel = -1; - for (i = 0; i < priv->freq_table_len; i++) { - if (nChannel == -1 || labs(lFreq - priv->freq_table[i]) < lFreqDiff) { - nChannel = priv->first_channel + i; - lFreqDiff = labs(lFreq - priv->freq_table[i]); - } - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq #%d (%ld) => %d (%ld)\n",i+priv->first_channel,priv->freq_table[i], nChannel,lFreqDiff); - } - if (nChannel == -1) { - mp_tmsg(MSGT_TV,MSGL_ERR, "tvi_dshow: Unable to find nearest channel in system frequency table\n"); - return E_FAIL; - } - mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: set_nearest_freq #%d (%ld)\n",nChannel,priv->freq_table[nChannel - priv->first_channel]); - hr = OLE_CALL_ARGS(priv->pTVTuner, put_Channel, nChannel, - AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT); - if (FAILED(hr)) { - mp_tmsg(MSGT_TV,MSGL_ERR,"tvi_dshow: Unable to switch to nearest channel from system frequency table. Error:0x%x\n", (unsigned int)hr); - return E_FAIL; - } - return S_OK; -} - -/** - * \brief setting frequency. decides whether use direct call/workaround - * - * \param priv driver's private data - * \param lFreq frequency in Hz - * - * \return TVI_CONTROL_TRUE if success - * \return TVI_CONTROL_FALSE if error occured - * - * \todo check for freq boundary - */ -static int set_frequency(priv_t * priv, long lFreq) -{ - HRESULT hr; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency called: %ld\n", lFreq); - if (!priv->pTVTuner) - return TVI_CONTROL_FALSE; - if (priv->direct_setfreq_call) { //using direct call to set frequency - hr = set_frequency_direct(priv->pTVTuner, lFreq); - if (FAILED(hr)) { - mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to set frequency directly. OS built-in channels table will be used.\n"); - priv->direct_setfreq_call = 0; - } - } - if (!priv->direct_setfreq_call) { - hr = set_nearest_freq(priv, lFreq); - } - if (FAILED(hr)) - return TVI_CONTROL_FALSE; -#ifdef DEPRECATED - priv->pGrabber->ClearBuffer(priv->pGrabber); -#endif - return TVI_CONTROL_TRUE; -} - -/** - * \brief return current frequency from tuner (in Hz) - * - * \param pTVTuner IAMTVTuner interface of tuner - * \param plFreq address of variable that receives current frequency - * - * \return S_OK success - * \return E_POINTER pTVTuner==NULL || plFreq==NULL - * \return apropriate error code otherwise - */ -static HRESULT get_frequency_direct(IAMTVTuner * pTVTuner, long *plFreq) -{ - HRESULT hr; - KSPROPERTY_TUNER_STATUS_S TunerStatus; - DWORD cbBytes; - IKsPropertySet *pKSProp; - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency_direct called\n"); - - if (!plFreq) - return E_POINTER; - - hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp); - if (FAILED(hr)) { - mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq QueryInterface failed\n"); - return hr; - } - - hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER, - KSPROPERTY_TUNER_STATUS, - INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus), - INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus), - &TunerStatus, sizeof(TunerStatus), &cbBytes); - if (FAILED(hr)) { - mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq Get failure\n"); - return hr; - } - *plFreq = TunerStatus.CurrentFrequency; - return S_OK; -} - -/** - * \brief gets current frequency - * - * \param priv driver's private data structure - * \param plFreq - pointer to long int to store frequency to (in Hz) - * - * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise - */ -static int get_frequency(priv_t * priv, long *plFreq) -{ - HRESULT hr; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency called\n"); - - if (!plFreq || !priv->pTVTuner) - return TVI_CONTROL_FALSE; - - if (priv->direct_getfreq_call) { //using direct call to get frequency - hr = get_frequency_direct(priv->pTVTuner, plFreq); - if (FAILED(hr)) { - mp_tmsg(MSGT_TV, MSGL_INFO, "tvi_dshow: Unable to get frequency directly. OS built-in channels table will be used.\n"); - priv->direct_getfreq_call = 0; - } - } - if (!priv->direct_getfreq_call) { - hr=OLE_CALL_ARGS(priv->pTVTuner, get_VideoFrequency, plFreq); - if (FAILED(hr)) - return TVI_CONTROL_FALSE; - - } - return TVI_CONTROL_TRUE; -} - -/** - * \brief get tuner capabilities - * - * \param priv driver's private data - */ -static void get_capabilities(priv_t * priv) -{ - long lAvailableFormats; - HRESULT hr; - int i; - long lInputPins, lOutputPins, lRelated, lPhysicalType; - IEnumPins *pEnum; - char tmp[200]; - IPin *pPin = 0; - PIN_DIRECTION ThisPinDir; - PIN_INFO pi; - IAMAudioInputMixer *pIAMixer; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_capabilities called\n"); - if (priv->pTVTuner) { - - mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: supported norms:"); - hr = OLE_CALL_ARGS(priv->pTVTuner, get_AvailableTVFormats, - &lAvailableFormats); - if (FAILED(hr)) - tv_available_norms_count = 0; - else { - for (i = 0; i < TV_NORMS_COUNT; i++) { - if (lAvailableFormats & tv_norms[i].index) { - tv_available_norms[tv_available_norms_count] = i; - mp_msg(MSGT_TV, MSGL_V, " %d=%s;", - tv_available_norms_count + 1, tv_norms[i].name); - tv_available_norms_count++; - } - } - } - mp_msg(MSGT_TV, MSGL_INFO, "\n"); - } - if (priv->pCrossbar) { - OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, - &lInputPins); - - tv_available_inputs = malloc(sizeof(long) * lInputPins); - tv_available_inputs_count = 0; - - mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: available video inputs:"); - for (i = 0; i < lInputPins; i++) { - OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1, i, - &lRelated, &lPhysicalType); - - if (lPhysicalType < 0x1000) { - tv_available_inputs[tv_available_inputs_count++] = i; - mp_msg(MSGT_TV, MSGL_V, " %d=%s;", - tv_available_inputs_count - 1, - physcon2str(lPhysicalType)); - } - } - mp_msg(MSGT_TV, MSGL_INFO, "\n"); - - set_crossbar_input(priv, 0); - } - - if (priv->adev_index != -1) { - hr = OLE_CALL_ARGS(priv->chains[1]->pCaptureFilter, EnumPins, &pEnum); - if (FAILED(hr)) - return; - mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: available audio inputs:"); - i = 0; - while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) { - memset(&pi, 0, sizeof(pi)); - memset(tmp, 0, 200); - OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir); - if (ThisPinDir == PINDIR_INPUT) { - OLE_CALL_ARGS(pPin, QueryPinInfo, &pi); - wtoa(pi.achName, tmp, 200); - OLE_RELEASE_SAFE(pi.pFilter); - mp_msg(MSGT_TV, MSGL_V, " %d=%s", i, tmp); - mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin); - hr = OLE_QUERYINTERFACE(pPin, IID_IAMAudioInputMixer,pIAMixer); - if (SUCCEEDED(hr)) { - if (i == priv->tv_param->audio_id) { - OLE_CALL_ARGS(pIAMixer, put_Enable, TRUE); - if(priv->tv_param->volume>0) - OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.01 * priv->tv_param->volume); -#if 0 - else - OLE_CALL_ARGS(pIAMixer, put_MixLevel, 1.0); -#endif - mp_tmsg(MSGT_TV, MSGL_V, "(selected)"); - } else { - OLE_CALL_ARGS(pIAMixer, put_Enable, FALSE); -#if 0 - OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.0); -#endif - } - OLE_RELEASE_SAFE(pIAMixer); - } - mp_msg(MSGT_TV, MSGL_V, ";"); - OLE_RELEASE_SAFE(pPin); - i++; - } - } - mp_msg(MSGT_TV, MSGL_INFO, "\n"); - OLE_RELEASE_SAFE(pEnum); - } -} - -/* -*--------------------------------------------------------------------------------------- -* -* Filter related methods -* -*--------------------------------------------------------------------------------------- -*/ -/** - * \brief building in graph audio/video capture chain - * - * \param priv driver's private data - * \param pCaptureFilter pointer to capture device's IBaseFilter interface - * \param pbuf ringbuffer data structure - * \param pmt media type for chain (AM_MEDIA_TYPE) - * - * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure - */ -static HRESULT build_sub_graph(priv_t * priv, chain_t * chain, const GUID* ppin_category) -{ - HRESULT hr; - int nFormatProbed = 0; - - IPin *pSGOut; - IPin *pNRIn=NULL; - - IBaseFilter *pNR = NULL; - - hr=S_OK; - - //No supported formats - if(!chain->arpmt[0]) - return E_FAIL; - - do{ - hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, - (IUnknown *) chain->pCaptureFilter, - PINDIR_OUTPUT, ppin_category, - chain->majortype, FALSE, 0, &chain->pCapturePin); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - /* Addinf SampleGrabber filter for video stream */ - hr = CoCreateInstance((GUID *) & CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &chain->pSGF); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, chain->pSGF, L"Sample Grabber"); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) chain->pSGF,PINDIR_INPUT, NULL, NULL, FALSE, 0, &chain->pSGIn); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) chain->pSGF,PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pSGOut); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - - /* creating ringbuffer for video samples */ - chain->pCSGCB = CSampleGrabberCB_Create(chain->rbuf); - if(!chain->pCSGCB){ - mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY); - break; - } - - /* initializing SampleGrabber filter */ - hr = OLE_QUERYINTERFACE(chain->pSGF, IID_ISampleGrabber, chain->pSG); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data - hr = OLE_CALL_ARGS(chain->pSG, SetCallback, (ISampleGrabberCB *) chain->pCSGCB, 0); //we want to receive sample - - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - hr = OLE_CALL_ARGS(chain->pSG, SetOneShot, FALSE); //... for all frames - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - hr = OLE_CALL_ARGS(chain->pSG, SetBufferSamples, FALSE); //... do not buffer samples in sample grabber - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - - if(priv->tv_param->normalize_audio_chunks && chain->type==audio){ - set_buffer_preference(20,(WAVEFORMATEX*)(chain->arpmt[nFormatProbed]->pbFormat),chain->pCapturePin,chain->pSGIn); - } - - for(nFormatProbed=0; chain->arpmt[nFormatProbed]; nFormatProbed++) - { - DisplayMediaType("Probing format", chain->arpmt[nFormatProbed]); - hr = OLE_CALL_ARGS(chain->pSG, SetMediaType, chain->arpmt[nFormatProbed]); //set desired mediatype - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr); - continue; - } - /* connecting filters together: VideoCapture --> SampleGrabber */ - hr = OLE_CALL_ARGS(priv->pGraph, Connect, chain->pCapturePin, chain->pSGIn); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr); - continue; - } - break; - } - - if(!chain->arpmt[nFormatProbed]) - { - mp_msg(MSGT_TV, MSGL_WARN, "tvi_dshow: Unable to negotiate media format\n"); - hr = E_FAIL; - break; - } - - hr = OLE_CALL_ARGS(chain->pCapturePin, ConnectionMediaType, chain->pmt); - if(FAILED(hr)) - { - mp_tmsg(MSGT_TV, MSGL_WARN, "tvi_dshow: Unable to get actual mediatype (Error:0x%x). Assuming equal to requested.\n", (unsigned int)hr); - } - - if(priv->tv_param->hidden_video_renderer){ - IEnumFilters* pEnum; - IBaseFilter* pFilter; - - hr=OLE_CALL_ARGS(priv->pBuilder,RenderStream,NULL,NULL,(IUnknown*)chain->pCapturePin,NULL,NULL); - - OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum); - while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) { - LPVIDEOWINDOW pVideoWindow; - hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow); - if (SUCCEEDED(hr)) - { - OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0); - OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0); - OLE_RELEASE_SAFE(pVideoWindow); - } - OLE_RELEASE_SAFE(pFilter); - } - OLE_RELEASE_SAFE(pEnum); - }else - { -#if 0 - /* - Code below is disabled, because terminating chain with NullRenderer leads to jerky video. - Perhaps, this happens because NullRenderer filter discards each received - frame while discarded frames causes live source filter to dramatically reduce frame rate. - */ - /* adding sink for video stream */ - hr = CoCreateInstance((GUID *) & CLSID_NullRenderer, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pNR); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pNR, L"Null Renderer"); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pNR,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pNRIn); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr); - break; - } - /* - Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection - */ - if(memcmp(&(arpmt[nFormatProbed]->majortype),&MEDIATYPE_VBI,16)){ - /* connecting filters together: SampleGrabber --> NullRenderer */ - hr = OLE_CALL_ARGS(priv->pGraph, Connect, pSGOut, pNRIn); - if(FAILED(hr)){ - mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr); - break; - } - } -#endif - } - - hr = S_OK; - } while(0); - - OLE_RELEASE_SAFE(pSGOut); - OLE_RELEASE_SAFE(pNR); - OLE_RELEASE_SAFE(pNRIn); - - return hr; -} - -/** - * \brief configures crossbar for grabbing video stream from given input - * - * \param priv driver's private data - * \param input index of available video input to get data from - * - * \return TVI_CONTROL_TRUE success - * \return TVI_CONTROL_FALSE error - */ -static int set_crossbar_input(priv_t * priv, int input) -{ - HRESULT hr; - int i, nVideoDecoder, nAudioDecoder; - long lInput, lInputRelated, lRelated, lPhysicalType, lOutputPins, - lInputPins; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Configuring crossbar\n"); - if (!priv->pCrossbar || input < 0 - || input >= tv_available_inputs_count) - return TVI_CONTROL_FALSE; - - OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, &lInputPins); - - lInput = tv_available_inputs[input]; - - if (lInput < 0 || lInput >= lInputPins) - return TVI_CONTROL_FALSE; - - OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1 /* input */ , lInput, - &lInputRelated, &lPhysicalType); - - nVideoDecoder = nAudioDecoder = -1; - for (i = 0; i < lOutputPins; i++) { - OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 0 /*output */ , i, - &lRelated, &lPhysicalType); - if (lPhysicalType == PhysConn_Video_VideoDecoder) - nVideoDecoder = i; - if (lPhysicalType == PhysConn_Audio_AudioDecoder) - nAudioDecoder = i; - } - if (nVideoDecoder >= 0) { - //connecting given input with video decoder - hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nVideoDecoder, lInput); - if (hr != S_OK) { - mp_tmsg(MSGT_TV,MSGL_ERR,"Unable to connect given input to video decoder. Error:0x%x\n", (unsigned int)hr); - return TVI_CONTROL_FALSE; - } - } - if (nAudioDecoder >= 0 && lInputRelated >= 0) { - hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nAudioDecoder, - lInputRelated); - if (hr != S_OK) { - mp_tmsg(MSGT_TV,MSGL_ERR,"Unable to connect given input to audio decoder. Error:0x%x\n", (unsigned int)hr); - return TVI_CONTROL_FALSE; - } - } - return TVI_CONTROL_TRUE; -} - -/** - * \brief adjusts video control (hue,saturation,contrast,brightess) - * - * \param priv driver's private data - * \param control which control to adjust - * \param value new value for control (0-100) - * - * \return TVI_CONTROL_TRUE success - * \return TVI_CONTROL_FALSE error - */ -static int set_control(priv_t * priv, int control, int value) -{ - long lMin, lMax, lStepping, lDefault, lFlags, lValue; - HRESULT hr; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_control called\n"); - if (value < -100 || value > 100 || !priv->pVideoProcAmp) - return TVI_CONTROL_FALSE; - - hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control, - &lMin, &lMax, &lStepping, &lDefault, &lFlags); - if (FAILED(hr) || lFlags != VideoProcAmp_Flags_Manual) - return TVI_CONTROL_FALSE; - - lValue = lMin + (value + 100) * (lMax - lMin) / 200; - /* - Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256 - */ - if (lStepping > lMax) { - mp_msg(MSGT_TV, MSGL_DBG3, - "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n", - lStepping, lMax,control); - lStepping = 1; - } - lValue -= lValue % lStepping; - hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Set, control, lValue, - VideoProcAmp_Flags_Manual); - if (FAILED(hr)) - return TVI_CONTROL_FALSE; - - return TVI_CONTROL_TRUE; -} - -/** - * \brief get current value of video control (hue,saturation,contrast,brightess) - * - * \param priv driver's private data - * \param control which control to adjust - * \param pvalue address of variable thar receives current value - * - * \return TVI_CONTROL_TRUE success - * \return TVI_CONTROL_FALSE error - */ -static int get_control(priv_t * priv, int control, int *pvalue) -{ - long lMin, lMax, lStepping, lDefault, lFlags, lValue; - HRESULT hr; - - mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_control called\n"); - if (!pvalue || !priv->pVideoProcAmp) - return TVI_CONTROL_FALSE; - - hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control, - &lMin, &lMax, &lStepping, &lDefault, &lFlags); - if (FAILED(hr)) - return TVI_CONTROL_FALSE; - if (lMin == lMax) { - *pvalue = lMin; - return TVI_CONTROL_TRUE; - } - - hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Get, control, &lValue, &lFlags); - if (FAILED(hr)) - return TVI_CONTROL_FALSE; - - *pvalue = 200 * (lValue - lMin) / (lMax - lMin) - 100; - - return TVI_CONTROL_TRUE; -} - -/** - * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps - * \param fcc FourCC code for video format - * \param width picture width - * \param height pciture height - * \param fps frames per second (required for bitrate calculation) - * - * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise - */ -static AM_MEDIA_TYPE* create_video_format(int fcc, int width, int height, int fps) -{ - int i; - AM_MEDIA_TYPE mt; - VIDEOINFOHEADER vHdr; - - /* Check given fcc in lookup table*/ - for(i=0; img_fmt_list[i].fmt && img_fmt_list[i].fmt!=fcc; i++) /* NOTHING */; - if(!img_fmt_list[i].fmt) - return NULL; - - memset(&mt, 0, sizeof(AM_MEDIA_TYPE)); - memset(&vHdr, 0, sizeof(VIDEOINFOHEADER)); - - vHdr.bmiHeader.biSize = sizeof(vHdr.bmiHeader); - vHdr.bmiHeader.biWidth = width; - vHdr.bmiHeader.biHeight = height; - //FIXME: is biPlanes required too? - //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes; - vHdr.bmiHeader.biBitCount = img_fmt_list[i].nBits; - vHdr.bmiHeader.biCompression = img_fmt_list[i].nCompression; - vHdr.bmiHeader.biSizeImage = width * height * img_fmt_list[i].nBits / 8; - vHdr.dwBitRate = vHdr.bmiHeader.biSizeImage * 8 * fps; - - mt.pbFormat = (char*)&vHdr; - mt.cbFormat = sizeof(vHdr); - - mt.majortype = MEDIATYPE_Video; - mt.subtype = *img_fmt_list[i].subtype; - mt.formattype = FORMAT_VideoInfo; - - mt.bFixedSizeSamples = 1; - mt.bTemporalCompression = 0; - mt.lSampleSize = vHdr.bmiHeader.biSizeImage; - - return CreateMediaType(&mt); -} - -/** - * \brief extracts fcc,width,height from AM_MEDIA_TYPE - * - * \param pmt pointer to AM_MEDIA_TYPE to extract data from - * \param pfcc address of variable that receives FourCC - * \param pwidth address of variable that receives width - * \param pheight address of variable that recevies height - * - * \return 1 if data extracted success