Fix vf_tcdump's compilation
[mplayer/kovensky.git] / stream / tvi_dshow.c
blob54b8b43f270a6b7ed60ea32a0b660ba3eb026460
1 /*
2 * TV support under Win32
4 * (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>
6 * Based on tvi_dummy.c with help of tv.c, tvi_v4l2.c code.
8 * This file is part of MPlayer.
10 * MPlayer is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * MPlayer is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * WARNING: This is alpha code!
28 * Abilities:
29 * * Watching TV under Win32 using WDM Capture driver and DirectShow
30 * * Grabbing synchronized audio/video with mencoder (synchronization is beeing done by DirectShow)
31 * * If device driver provides IAMStreamConfig interface, user can choose width/height with "-tv height=<h>:width=<w>"
32 * * Adjusting BRIGHTNESS,HUE,SATURATION,CONTRAST if supported by device
33 * * Selecting Tuner,S-Video,... as media source
34 * * User can select used video capture device, passing -tv device=<dev#>
35 * * User can select used audio input, passing -tv audioid=<input#>
37 * options which will not be implemented (probably sometime in future, if possible):
38 * * alsa
39 * * mjpeg
40 * * decimation=<1|2|4>
41 * * quality=<0\-100>
42 * * forceaudio
43 * * forcechan=<1\-2>
44 * * [volume|bass|treble|balance]
46 * Works with:
47 * - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
48 * Partially works with:
49 * - ATI 9200 VIVO based card
50 * - ATI AIW 7500
51 * - nVidia Ti-4400
53 * Known bugs:
54 * * stream goes with 24.93 FPS (NTSC), while reporting 25 FPS (PAL) ?!
55 * * direct set frequency call does not work ('Insufficient Buffer' error)
56 * * audio stream goes with about 1 sample/sec rate when capturing sound from audio card
58 * TODO:
59 * * check audio with small buffer on vivo !!!
60 * * norm for IAMVideoDecoder and for IAMTVtuner - differs !!
61 * * check how to change TVFormat on VIVO card without tuner
62 * * Flip image upside-down for RGB formats.
63 * *
64 * * remove debug sleep()
65 * * Add some notes to methods' parameters
66 * * refactor console messages
67 * * check using header files and keep only needed
68 * * add additional comments to methods' bodies
73 /// \ingroup tvi_dshow
75 #include "config.h"
77 #include <stdio.h>
78 #include "libmpcodecs/img_format.h"
79 #include "libmpcodecs/dec_teletext.h"
80 #include "libaf/af_format.h"
81 #include "osdep/timer.h"
84 #include "tv.h"
85 #include "mp_msg.h"
86 #include "frequencies.h"
89 #include "tvi_dshow.h"
91 #ifndef STDCALL
92 // mingw64 needs this
93 #define STDCALL __stdcall
94 #endif
96 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param);
99 *---------------------------------------------------------------------------------------
101 * Data structures
103 *---------------------------------------------------------------------------------------
106 information about this file
108 const tvi_info_t tvi_info_dshow = {
109 tvi_init_dshow,
110 "DirectShow TV",
111 "dshow",
112 "Vladimir Voroshilov",
113 "Very experimental!! Use with caution"
118 ringbuffer related info
120 typedef struct {
121 CRITICAL_SECTION *pMutex; ///< pointer to critical section (mutex)
122 char **ringbuffer; ///< ringbuffer array
123 double*dpts; ///< samples' timestamps
125 int buffersize; ///< size of buffer in blocks
126 int blocksize; ///< size of individual block
127 int head; ///< index of first valid sample
128 int tail; ///< index of last valid sample
129 int count; ///< count of valid samples in ringbuffer
130 double tStart; ///< pts of first sample (first sample should have pts 0)
131 } grabber_ringbuffer_t;
133 typedef enum { unknown, video, audio, vbi } stream_type;
136 CSampleGrabberCD definition
138 typedef struct CSampleGrabberCB {
139 ISampleGrabberCBVtbl *lpVtbl;
140 int refcount;
141 GUID interfaces[2];
142 grabber_ringbuffer_t *pbuf;
143 } CSampleGrabberCB;
146 Chain related structure
148 typedef struct {
149 stream_type type; ///< stream type
150 const GUID* majortype; ///< GUID of major mediatype (video/audio/vbi)
151 const GUID* pin_category; ///< pin category (pointer to one of PIN_CATEGORY_*)
153 IBaseFilter *pCaptureFilter; ///< capture device filter
154 IAMStreamConfig *pStreamConfig; ///< for configuring stream
155 ISampleGrabber *pSG; ///< ISampleGrabber interface of SampleGrabber filter
156 IBaseFilter *pSGF; ///< IBaseFilter interface of SampleGrabber filter
157 IPin *pCapturePin; ///< output capture pin
158 IPin *pSGIn; ///< input pin of SampleGrabber filter
160 grabber_ringbuffer_t *rbuf; ///< sample frabber data
161 CSampleGrabberCB* pCSGCB; ///< callback object
163 AM_MEDIA_TYPE *pmt; ///< stream properties.
164 int nFormatUsed; ///< index of used format
165 AM_MEDIA_TYPE **arpmt; ///< available formats
166 void** arStreamCaps; ///< VIDEO_STREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS
167 } chain_t;
169 typedef struct {
170 int dev_index; ///< capture device index in device list (defaul: 0, first available device)
171 int adev_index; ///< audio capture device index in device list (default: -1, not used)
172 int immediate_mode; ///< immediate mode (no sound capture)
173 int state; ///< state: 1-filter graph running, 0-filter graph stopped
174 int direct_setfreq_call; ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency
175 int direct_getfreq_call; ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency
177 int fcc; ///< used video format code (FourCC)
178 int width; ///< picture width (default: auto)
179 int height; ///< picture height (default: auto)
181 int channels; ///< number of audio channels (default: auto)
182 int samplerate; ///< audio samplerate (default: auto)
184 long *freq_table; ///< frequency table (in Hz)
185 int freq_table_len; ///< length of freq table
186 int first_channel; ///< channel number of first entry in freq table
187 int input; ///< used input
189 chain_t* chains[3]; ///< chains' data (0-video, 1-audio, 2-vbi)
191 IAMTVTuner *pTVTuner; ///< interface for tuner device
192 IGraphBuilder *pGraph; ///< filter graph
193 ICaptureGraphBuilder2 *pBuilder; ///< graph builder
194 IMediaControl *pMediaControl; ///< interface for controlling graph (start, stop,...)
195 IAMVideoProcAmp *pVideoProcAmp; ///< for adjusting hue,saturation,etc
196 IAMCrossbar *pCrossbar; ///< for selecting input (Tuner,Composite,S-Video,...)
197 DWORD dwRegister; ///< allow graphedit to connect to our graph
198 void *priv_vbi; ///< private VBI data structure
199 tt_stream_props tsp; ///< data for VBI initialization
201 tv_param_t* tv_param; ///< TV parameters
202 } priv_t;
204 #include "tvi_def.h"
207 country table entry structure (for loading freq table stored in kstvtuner.ax
209 \note
210 structure have to be 2-byte aligned and have 10-byte length!!
212 typedef struct __attribute__((__packed__)) {
213 WORD CountryCode; ///< Country code
214 WORD CableFreqTable; ///< index of resource with frequencies for cable channels
215 WORD BroadcastFreqTable; ///< index of resource with frequencies for broadcast channels
216 DWORD VideoStandard; ///< used video standard
217 } TRCCountryList;
219 information about image formats
221 typedef struct {
222 uint32_t fmt; ///< FourCC
223 const GUID *subtype; ///< DirectShow's subtype
224 int nBits; ///< number of bits
225 int nCompression; ///< complression
226 int tail; ///< number of additional bytes followed VIDEOINFOHEADER structure
227 } img_fmt;
230 *---------------------------------------------------------------------------------------
232 * Methods forward declaration
234 *---------------------------------------------------------------------------------------
236 static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
237 int blocksize);
238 static HRESULT show_filter_info(IBaseFilter * pFilter);
239 #if 0
240 //defined in current MinGW release
241 HRESULT STDCALL GetRunningObjectTable(DWORD, IRunningObjectTable **);
242 HRESULT STDCALL CreateItemMoniker(LPCOLESTR, LPCOLESTR, IMoniker **);
243 #endif
244 static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
245 pbuf);
246 static int set_crossbar_input(priv_t * priv, int input);
247 static int subtype2imgfmt(const GUID * subtype);
250 *---------------------------------------------------------------------------------------
252 * Global constants and variables
254 *---------------------------------------------------------------------------------------
257 lookup tables for physical connector types
259 static const struct {
260 long type;
261 char *name;
262 } tv_physcon_types[]={
263 {PhysConn_Video_Tuner, "Tuner" },
264 {PhysConn_Video_Composite, "Composite" },
265 {PhysConn_Video_SVideo, "S-Video" },
266 {PhysConn_Video_RGB, "RGB" },
267 {PhysConn_Video_YRYBY, "YRYBY" },
268 {PhysConn_Video_SerialDigital, "SerialDigital" },
269 {PhysConn_Video_ParallelDigital, "ParallelDigital"},
270 {PhysConn_Video_VideoDecoder, "VideoDecoder" },
271 {PhysConn_Video_VideoEncoder, "VideoEncoder" },
272 {PhysConn_Video_SCART, "SCART" },
273 {PhysConn_Video_Black, "Blaack" },
274 {PhysConn_Audio_Tuner, "Tuner" },
275 {PhysConn_Audio_Line, "Line" },
276 {PhysConn_Audio_Mic, "Mic" },
277 {PhysConn_Audio_AESDigital, "AESDiital" },
278 {PhysConn_Audio_SPDIFDigital, "SPDIFDigital" },
279 {PhysConn_Audio_AudioDecoder, "AudioDecoder" },
280 {PhysConn_Audio_SCSI, "SCSI" },
281 {PhysConn_Video_SCSI, "SCSI" },
282 {PhysConn_Audio_AUX, "AUX" },
283 {PhysConn_Video_AUX, "AUX" },
284 {PhysConn_Audio_1394, "1394" },
285 {PhysConn_Video_1394, "1394" },
286 {PhysConn_Audio_USB, "USB" },
287 {PhysConn_Video_USB, "USB" },
288 {-1, NULL }
291 static const struct {
292 char *chanlist_name;
293 int country_code;
294 } tv_chanlist2country[]={
295 {"us-bcast", 1},
296 {"russia", 7},
297 {"argentina", 54},
298 {"japan-bcast", 81},
299 {"china-bcast", 86},
300 {"southafrica", 27},
301 {"australia", 61},
302 {"ireland", 353},
303 {"france", 33},
304 {"italy", 39},
305 {"newzealand", 64},
306 //directshow table uses eastern europe freq table for russia
307 {"europe-east", 7},
308 //directshow table uses western europe freq table for germany
309 {"europe-west", 49},
310 /* cable channels */
311 {"us-cable", 1},
312 {"us-cable-hrc", 1},
313 {"japan-cable", 81},
314 //default is USA
315 {NULL, 1}
319 array, contains information about various supported (i hope) image formats
321 static const img_fmt img_fmt_list[] = {
322 {IMGFMT_YUY2, &MEDIASUBTYPE_YUY2, 16, IMGFMT_YUY2, 0},
323 {IMGFMT_YV12, &MEDIASUBTYPE_YV12, 12, IMGFMT_YV12, 0},
324 {IMGFMT_IYUV, &MEDIASUBTYPE_IYUV, 12, IMGFMT_IYUV, 0},
325 {IMGFMT_I420, &MEDIASUBTYPE_I420, 12, IMGFMT_I420, 0},
326 {IMGFMT_UYVY, &MEDIASUBTYPE_UYVY, 16, IMGFMT_UYVY, 0},
327 {IMGFMT_YVYU, &MEDIASUBTYPE_YVYU, 16, IMGFMT_YVYU, 0},
328 {IMGFMT_YVU9, &MEDIASUBTYPE_YVU9, 9, IMGFMT_YVU9, 0},
329 {IMGFMT_BGR32, &MEDIASUBTYPE_RGB32, 32, 0, 0},
330 {IMGFMT_BGR24, &MEDIASUBTYPE_RGB24, 24, 0, 0},
331 {IMGFMT_BGR16, &MEDIASUBTYPE_RGB565, 16, 3, 12},
332 {IMGFMT_BGR15, &MEDIASUBTYPE_RGB555, 16, 3, 12},
333 {0, &GUID_NULL, 0, 0, 0}
336 #define TV_NORMS_COUNT 19
337 static const struct {
338 long index;
339 char *name;
340 } tv_norms[TV_NORMS_COUNT] = {
342 AnalogVideo_NTSC_M, "ntsc-m"}, {
343 AnalogVideo_NTSC_M_J, "ntsc-mj"}, {
344 AnalogVideo_NTSC_433, "ntsc-433"}, {
345 AnalogVideo_PAL_B, "pal-b"}, {
346 AnalogVideo_PAL_D, "pal-d"}, {
347 AnalogVideo_PAL_G, "pal-g"}, {
348 AnalogVideo_PAL_H, "pal-h"}, {
349 AnalogVideo_PAL_I, "pal-i"}, {
350 AnalogVideo_PAL_M, "pal-m"}, {
351 AnalogVideo_PAL_N, "pal-n"}, {
352 AnalogVideo_PAL_60, "pal-60"}, {
353 AnalogVideo_SECAM_B, "secam-b"}, {
354 AnalogVideo_SECAM_D, "secam-d"}, {
355 AnalogVideo_SECAM_G, "secam-g"}, {
356 AnalogVideo_SECAM_H, "secam-h"}, {
357 AnalogVideo_SECAM_K, "secam-k"}, {
358 AnalogVideo_SECAM_K1, "secam-k1"}, {
359 AnalogVideo_SECAM_L, "secam-l"}, {
360 AnalogVideo_SECAM_L1, "secam-l1"}
362 static long tv_available_norms[TV_NORMS_COUNT];
363 static int tv_available_norms_count = 0;
366 static long *tv_available_inputs;
367 static int tv_available_inputs_count = 0;
370 *---------------------------------------------------------------------------------------
372 * Various GUID definitions
374 *---------------------------------------------------------------------------------------
376 // selectany can not be used with "static", fixes compilation with mingw-w64
377 #undef DECLSPEC_SELECTANY
378 #define DECLSPEC_SELECTANY
379 /// CLSID definitions (used for CoCreateInstance call)
380 #define CLSID_SampleGrabber MP_CLSID_SampleGrabber
381 static DEFINE_GUID(CLSID_SampleGrabber, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B,
382 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
383 #define CLSID_NullRenderer MP_CLSID_NullRenderer
384 static DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B,
385 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
386 #define CLSID_SystemDeviceEnum MP_CLSID_SystemDeviceEnum
387 static DEFINE_GUID(CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B,
388 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
389 #define CLSID_CaptureGraphBuilder2 MP_CLSID_CaptureGraphBuilder2
390 static DEFINE_GUID(CLSID_CaptureGraphBuilder2, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3,
391 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
392 #define CLSID_VideoInputDeviceCategory MP_CLSID_VideoInputDeviceCategory
393 static DEFINE_GUID(CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, 0x11d0,
394 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
395 #define CLSID_AudioInputDeviceCategory MP_CLSID_AudioInputDeviceCategory
396 static DEFINE_GUID(CLSID_AudioInputDeviceCategory, 0x33d9a762, 0x90c8, 0x11d0,
397 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
398 #define CLSID_FilterGraph MP_CLSID_FilterGraph
399 static DEFINE_GUID(CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53,
400 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
401 #define CLSID_SystemClock MP_CLSID_SystemClock
402 static DEFINE_GUID(CLSID_SystemClock, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53,
403 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
404 #ifdef NOT_USED
405 #define CLSID_CaptureGraphBuilder MP_CLSID_CaptureGraphBuilder
406 static DEFINE_GUID(CLSID_CaptureGraphBuilder, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3,
407 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
408 #define CLSID_VideoPortManager MP_CLSID_VideoPortManager
409 static DEFINE_GUID(CLSID_VideoPortManager, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a,
410 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2);
411 #define IID_IPin MP_IID_IPin
412 static DEFINE_GUID(IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20,
413 0xaf, 0x0b, 0xa7, 0x70);
414 #define IID_ICaptureGraphBuilder MP_IID_ICaptureGraphBuilder
415 static DEFINE_GUID(IID_ICaptureGraphBuilder, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3,
416 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5);
417 #define IID_IFilterGraph MP_IID_IFilterGraph
418 static DEFINE_GUID(IID_IFilterGraph, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
419 0x20, 0xaf, 0x0b, 0xa7, 0x70);
420 #define PIN_CATEGORY_PREVIEW MP_PIN_CATEGORY_PREVIEW
421 static DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
422 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
423 #endif
425 /// IID definitions (used for QueryInterface call)
426 #define IID_IReferenceClock MP_IID_IReferenceClock
427 static DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a,
428 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
429 #define IID_IAMBufferNegotiation MP_IID_IAMBufferNegotiation
430 static DEFINE_GUID(IID_IAMBufferNegotiation, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0,
431 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
432 #define IID_IKsPropertySet MP_IID_IKsPropertySet
433 static DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa,
434 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
435 #define IID_ISampleGrabber MP_IID_ISampleGrabber
436 static DEFINE_GUID(IID_ISampleGrabber, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD,
437 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F);
438 #define IID_ISampleGrabberCB MP_IID_ISampleGrabberCB
439 static DEFINE_GUID(IID_ISampleGrabberCB, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0,
440 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85);
441 #define IID_ICaptureGraphBuilder2 MP_IID_ICaptureGraphBuilder2
442 static DEFINE_GUID(IID_ICaptureGraphBuilder2, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab,
443 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d);
444 #define IID_ICreateDevEnum MP_IID_ICreateDevEnum
445 static DEFINE_GUID(IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b,
446 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
447 #define IID_IGraphBuilder MP_IID_IGraphBuilder
448 static DEFINE_GUID(IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a,
449 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
450 #define IID_IAMVideoProcAmp MP_IID_IAMVideoProcAmp
451 static DEFINE_GUID(IID_IAMVideoProcAmp, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C,
452 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
453 #define IID_IVideoWindow MP_IID_IVideoWindow
454 static DEFINE_GUID(IID_IVideoWindow, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
455 0x20, 0xaf, 0x0b, 0xa7, 0x70);
456 #define IID_IMediaControl MP_IID_IMediaControl
457 static DEFINE_GUID(IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a,
458 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
459 #define IID_IAMTVTuner MP_IID_IAMTVTuner
460 static DEFINE_GUID(IID_IAMTVTuner, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00,
461 0xAA, 0x00, 0xBD, 0x83, 0x39);
462 #define IID_IAMCrossbar MP_IID_IAMCrossbar
463 static DEFINE_GUID(IID_IAMCrossbar, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00,
464 0xa0, 0xc9, 0x11, 0x89, 0x56);
465 #define IID_IAMStreamConfig MP_IID_IAMStreamConfig
466 static DEFINE_GUID(IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c,
467 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56);
468 #define IID_IAMAudioInputMixer MP_IID_IAMAudioInputMixer
469 static DEFINE_GUID(IID_IAMAudioInputMixer, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0,
470 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
471 #define IID_IAMTVAudio MP_IID_IAMTVAudio
472 static DEFINE_GUID(IID_IAMTVAudio, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00,
473 0xA0, 0xC9, 0x56, 0x02, 0x66);
474 #define IID_IAMAnalogVideoDecoder MP_IID_IAMAnalogVideoDecoder
475 static DEFINE_GUID(IID_IAMAnalogVideoDecoder, 0xC6E13350, 0x30AC, 0x11d0, 0xA1,
476 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
477 #define IID_IPropertyBag MP_IID_IPropertyBag
478 static DEFINE_GUID(IID_IPropertyBag, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00,
479 0xaa, 0x00, 0x4b, 0xb8, 0x51);
480 #define PIN_CATEGORY_CAPTURE MP_PIN_CATEGORY_CAPTURE
481 static DEFINE_GUID(PIN_CATEGORY_CAPTURE, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f,
482 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
483 #define PIN_CATEGORY_VIDEOPORT MP_PIN_CATEGORY_VIDEOPORT
484 static DEFINE_GUID(PIN_CATEGORY_VIDEOPORT, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f,
485 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
486 #define PIN_CATEGORY_PREVIEW MP_PIN_CATEGORY_PREVIEW
487 static DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
488 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
489 #define PIN_CATEGORY_VBI MP_PIN_CATEGORY_VBI
490 static DEFINE_GUID(PIN_CATEGORY_VBI, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f,
491 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
492 #define PROPSETID_TUNER MP_PROPSETID_TUNER
493 static DEFINE_GUID(PROPSETID_TUNER, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00,
494 0xa0, 0xc9, 0x11, 0x89, 0x56);
495 #define MEDIATYPE_VBI MP_MEDIATYPE_VBI
496 static DEFINE_GUID(MEDIATYPE_VBI, 0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00,
497 0x00, 0xc0, 0xcc, 0x16, 0xba);
499 #define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1)
500 #define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
502 #define DEVICE_NAME_MAX_LEN 2000
504 /*---------------------------------------------------------------------------------------
505 * Methods, called only from this file
506 *---------------------------------------------------------------------------------------*/
508 void set_buffer_preference(int nDiv,WAVEFORMATEX* pWF,IPin* pOutPin,IPin* pInPin){
509 ALLOCATOR_PROPERTIES prop;
510 IAMBufferNegotiation* pBN;
511 HRESULT hr;
513 prop.cbAlign = -1;
514 prop.cbBuffer = pWF->nAvgBytesPerSec/nDiv;
515 if (!prop.cbBuffer)
516 prop.cbBuffer = 1;
517 prop.cbBuffer += pWF->nBlockAlign - 1;
518 prop.cbBuffer -= prop.cbBuffer % pWF->nBlockAlign;
519 prop.cbPrefix = -1;
520 prop.cBuffers = -1;
522 hr=OLE_QUERYINTERFACE(pOutPin,IID_IAMBufferNegotiation,pBN);
523 if(FAILED(hr))
524 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr);
525 else{
526 hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop);
527 if(FAILED(hr))
528 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr);
529 OLE_RELEASE_SAFE(pBN);
531 hr=OLE_QUERYINTERFACE(pInPin,IID_IAMBufferNegotiation,pBN);
532 if(FAILED(hr))
533 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr);
534 else{
535 hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop);
536 if(FAILED(hr))
537 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr);
538 OLE_RELEASE_SAFE(pBN);
542 *---------------------------------------------------------------------------------------
544 * CSampleGrabberCD class. Used for receiving samples from DirectShow.
546 *---------------------------------------------------------------------------------------
548 /// CSampleGrabberCD destructor
549 static void CSampleGrabberCB_Destroy(CSampleGrabberCB * This)
551 free(This->lpVtbl);
552 free(This);
555 /// CSampleGrabberCD IUnknown interface methods implementation
556 static long STDCALL CSampleGrabberCB_QueryInterface(ISampleGrabberCB *
557 This,
558 const GUID * riid,
559 void **ppvObject)
561 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
562 GUID *r;
563 unsigned int i = 0;
564 Debug printf("CSampleGrabberCB_QueryInterface(%p) called\n", This);
565 if (!ppvObject)
566 return E_POINTER;
567 for (r = me->interfaces;
568 i < sizeof(me->interfaces) / sizeof(me->interfaces[0]); r++, i++)
569 if (!memcmp(r, riid, sizeof(*r))) {
570 OLE_CALL(This, AddRef);
571 *ppvObject = This;
572 return 0;
574 Debug printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid);
575 return E_NOINTERFACE;
578 static long STDCALL CSampleGrabberCB_AddRef(ISampleGrabberCB * This)
580 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
581 Debug printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This,
582 me->refcount);
583 return ++(me->refcount);
586 static long STDCALL CSampleGrabberCB_Release(ISampleGrabberCB * This)
588 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
589 Debug printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n",
590 This, me->refcount - 1);
591 if (--(me->refcount) == 0)
592 CSampleGrabberCB_Destroy(me);
593 return 0;
597 HRESULT STDCALL CSampleGrabberCB_BufferCB(ISampleGrabberCB * This,
598 double SampleTime,
599 BYTE * pBuffer, long lBufferLen)
601 CSampleGrabberCB *this = (CSampleGrabberCB *) This;
602 grabber_ringbuffer_t *rb = this->pbuf;
604 if (!lBufferLen)
605 return E_FAIL;
607 if (!rb->ringbuffer) {
608 rb->buffersize /= lBufferLen;
609 if (init_ringbuffer(rb, rb->buffersize, lBufferLen) != S_OK)
610 return E_FAIL;
612 mp_msg(MSGT_TV, MSGL_DBG4,
613 "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This, lBufferLen, SampleTime);
614 EnterCriticalSection(rb->pMutex);
615 if (rb->count >= rb->buffersize) {
616 rb->head = (rb->head + 1) % rb->buffersize;
617 rb->count--;
620 memcpy(rb->ringbuffer[rb->tail], pBuffer,
621 lBufferLen < rb->blocksize ? lBufferLen : rb->blocksize);
622 rb->dpts[rb->tail] = SampleTime;
623 rb->tail = (rb->tail + 1) % rb->buffersize;
624 rb->count++;
625 LeaveCriticalSection(rb->pMutex);
627 return S_OK;
630 /// wrapper. directshow does the same when BufferCB callback is requested
631 HRESULT STDCALL CSampleGrabberCB_SampleCB(ISampleGrabberCB * This,
632 double SampleTime,
633 LPMEDIASAMPLE pSample)
635 char* buf;
636 long len;
637 long long tStart,tEnd;
638 HRESULT hr;
639 grabber_ringbuffer_t *rb = ((CSampleGrabberCB*)This)->pbuf;
641 len=OLE_CALL(pSample,GetSize);
642 tStart=tEnd=0;
643 hr=OLE_CALL_ARGS(pSample,GetTime,&tStart,&tEnd);
644 if(FAILED(hr)){
645 return hr;
647 mp_msg(MSGT_TV, MSGL_DBG4,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This,rb->count,rb->buffersize,1e-7*tStart);
648 hr=OLE_CALL_ARGS(pSample,GetPointer,(void*)&buf);
649 if(FAILED(hr)){
650 return hr;
652 hr=CSampleGrabberCB_BufferCB(This,1e-7*tStart,buf,len);
653 return hr;
657 /// main grabbing routine
658 static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
659 pbuf)
661 CSampleGrabberCB *This = malloc(sizeof(CSampleGrabberCB));
662 if (!This)
663 return NULL;
665 This->lpVtbl = malloc(sizeof(ISampleGrabberVtbl));
666 if (!This->lpVtbl) {
667 CSampleGrabberCB_Destroy(This);
668 return NULL;
670 This->refcount = 1;
671 This->lpVtbl->QueryInterface = CSampleGrabberCB_QueryInterface;
672 This->lpVtbl->AddRef = CSampleGrabberCB_AddRef;
673 This->lpVtbl->Release = CSampleGrabberCB_Release;
674 This->lpVtbl->SampleCB = CSampleGrabberCB_SampleCB;
675 This->lpVtbl->BufferCB = CSampleGrabberCB_BufferCB;
677 This->interfaces[0] = IID_IUnknown;
678 This->interfaces[1] = IID_ISampleGrabberCB;
680 This->pbuf = pbuf;
682 return This;
686 *---------------------------------------------------------------------------------------
688 * ROT related methods (register, unregister)
690 *---------------------------------------------------------------------------------------
693 Registering graph in ROT. User will be able to connect to graph from GraphEdit.
695 static HRESULT AddToRot(IUnknown * pUnkGraph, DWORD * pdwRegister)
697 IMoniker *pMoniker;
698 IRunningObjectTable *pROT;
699 WCHAR wsz[256];
700 HRESULT hr;
702 if (FAILED(GetRunningObjectTable(0, &pROT))) {
703 return E_FAIL;
705 wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR) pUnkGraph,
706 GetCurrentProcessId());
707 hr = CreateItemMoniker(L"!", wsz, &pMoniker);
708 if (SUCCEEDED(hr)) {
709 hr = OLE_CALL_ARGS(pROT, Register, ROTFLAGS_REGISTRATIONKEEPSALIVE,
710 pUnkGraph, pMoniker, pdwRegister);
711 OLE_RELEASE_SAFE(pMoniker);
713 OLE_RELEASE_SAFE(pROT);
714 return hr;
717 /// Unregistering graph in ROT
718 static void RemoveFromRot(DWORD dwRegister)
720 IRunningObjectTable *pROT;
721 if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
722 OLE_CALL_ARGS(pROT, Revoke, dwRegister);
723 OLE_RELEASE_SAFE(pROT);
728 *---------------------------------------------------------------------------------------
730 * ringbuffer related methods (init, destroy)
732 *---------------------------------------------------------------------------------------
735 * \brief ringbuffer destroying routine
737 * \param rb pointer to empty (just allocated) ringbuffer structure
739 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
741 static void destroy_ringbuffer(grabber_ringbuffer_t * rb)
743 int i;
745 if (!rb)
746 return;
748 if (rb->ringbuffer) {
749 for (i = 0; i < rb->buffersize; i++)
750 if (rb->ringbuffer[i])
751 free(rb->ringbuffer[i]);
752 free(rb->ringbuffer);
753 rb->ringbuffer = NULL;
755 if (rb->dpts) {
756 free(rb->dpts);
757 rb->dpts = NULL;
759 if (rb->pMutex) {
760 DeleteCriticalSection(rb->pMutex);
761 free(rb->pMutex);
762 rb->pMutex = NULL;
765 rb->blocksize = 0;
766 rb->buffersize = 0;
767 rb->head = 0;
768 rb->tail = 0;
769 rb->count = 0;
773 * \brief ringbuffer initialization
775 * \param rb pointer to empty (just allocated) ringbuffer structure
776 * \param buffersize size of buffer in blocks
777 * \param blocksize size of buffer's block
779 * \return S_OK if success
780 * \return E_OUTOFMEMORY not enough memory
782 * \note routine does not allocates memory for grabber_rinbuffer_s structure
784 static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
785 int blocksize)
787 int i;
789 if (!rb)
790 return E_OUTOFMEMORY;
792 rb->buffersize = buffersize < 2 ? 2 : buffersize;
793 rb->blocksize = blocksize;
795 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n",
796 rb->buffersize, rb->blocksize);
798 rb->ringbuffer = malloc(rb->buffersize * sizeof(char *));
799 if (!rb)
800 return E_POINTER;
801 memset(rb->ringbuffer, 0, rb->buffersize * sizeof(char *));
803 for (i = 0; i < rb->buffersize; i++) {
804 rb->ringbuffer[i] = malloc(rb->blocksize * sizeof(char));
805 if (!rb->ringbuffer[i]) {
806 destroy_ringbuffer(rb);
807 return E_OUTOFMEMORY;
810 rb->dpts = malloc(rb->buffersize * sizeof(double));
811 if (!rb->dpts) {
812 destroy_ringbuffer(rb);
813 return E_OUTOFMEMORY;
815 rb->head = 0;
816 rb->tail = 0;
817 rb->count = 0;
818 rb->tStart = -1;
819 rb->pMutex = malloc(sizeof(CRITICAL_SECTION));
820 if (!rb->pMutex) {
821 destroy_ringbuffer(rb);
822 return E_OUTOFMEMORY;
824 InitializeCriticalSection(rb->pMutex);
825 return S_OK;
829 *---------------------------------------------------------------------------------------
831 * Tuner related methods (frequency, capabilities, etc
833 *---------------------------------------------------------------------------------------
836 * \brief returns string with name for givend PsysCon_* constant
838 * \param lPhysicalType constant from PhysicalConnectorType enumeration
840 * \return pointer to string with apropriate name
842 * \note
843 * Caller should not free returned pointer
845 static char *physcon2str(const long lPhysicalType)
847 int i;
848 for(i=0; tv_physcon_types[i].name; i++)
849 if(tv_physcon_types[i].type==lPhysicalType)
850 return tv_physcon_types[i].name;
851 return "Unknown";
855 * \brief converts MPlayer's chanlist to system country code.
857 * \param chanlist MPlayer's chanlist name
859 * \return system country code
861 * \remarks
862 * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified
863 * country (which is usually larger then MPlayer's one, so workaround will work fine).
865 * \todo
866 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
868 static int chanlist2country(char *chanlist)
870 int i;
871 for(i=0; tv_chanlist2country[i].chanlist_name; i++)
872 if (!strcmp(chanlist, tv_chanlist2country[i].chanlist_name))
873 break;
874 return tv_chanlist2country[i].country_code;
878 * \brief loads specified resource from module and return pointer to it
880 * \param hDLL valid module desriptor
881 * \param index index of resource. resource with name "#<index>" will be loaded
883 * \return pointer to loader resource or NULL if error occured
885 static void *GetRC(HMODULE hDLL, int index)
887 char szRCDATA[10];
888 char szName[10];
889 HRSRC hRes;
890 HGLOBAL hTable;
892 snprintf(szRCDATA, 10, "#%d", (int)RT_RCDATA);
893 snprintf(szName, 10, "#%d", index);
895 hRes = FindResource(hDLL, szName, szRCDATA);
896 if (!hRes) {
897 return NULL;
899 hTable = LoadResource(hDLL, hRes);
900 if (!hTable) {
901 return NULL;
903 return LockResource(hTable);
907 * \brief loads frequency table for given country from kstvtune.ax
909 * \param[in] nCountry - country code
910 * \param[in] nInputType (TunerInputCable or TunerInputAntenna)
911 * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies
912 * \param[out] pnLen length of array
913 * \param[out] pnFirst - channel number of first entry in array (nChannelMax)
915 * \return S_OK if success
916 * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL
917 * \return E_FAIL error occured during load
919 * \remarks
920 * - array must be freed by caller
921 * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL
923 static HRESULT load_freq_table(int nCountry, int nInputType,
924 long **pplFreqTable, int *pnLen,
925 int *pnFirst)
927 HMODULE hDLL;
928 long *plFreqTable;
929 TRCCountryList *pCountryList;
930 int i, index;
932 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table called %d (%s)\n",nCountry,nInputType == TunerInputAntenna ? "broadcast" : "cable");
933 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
935 if (!pplFreqTable || !pnFirst || !pnLen)
936 return E_POINTER;
937 if (!nCountry)
938 return E_FAIL;
940 hDLL = LoadLibrary("kstvtune.ax");
941 if (!hDLL) {
942 return E_FAIL;
944 pCountryList = GetRC(hDLL, 9999);
945 if (!pCountryList) {
946 FreeLibrary(hDLL);
947 return E_FAIL;
949 for (i = 0; pCountryList[i].CountryCode != 0; i++)
950 if (pCountryList[i].CountryCode == nCountry)
951 break;
952 if (pCountryList[i].CountryCode == 0) {
953 FreeLibrary(hDLL);
954 return E_FAIL;
956 if (nInputType == TunerInputCable)
957 index = pCountryList[i].CableFreqTable;
958 else
959 index = pCountryList[i].BroadcastFreqTable;
961 plFreqTable = GetRC(hDLL, index); //First element is number of first channel, second - number of last channel
962 if (!plFreqTable) {
963 FreeLibrary(hDLL);
964 return E_FAIL;
966 *pnFirst = plFreqTable[0];
967 *pnLen = (int) (plFreqTable[1] - plFreqTable[0] + 1);
968 *pplFreqTable = malloc((*pnLen) * sizeof(long));
969 if (!*pplFreqTable) {
970 FreeLibrary(hDLL);
971 return E_FAIL;
973 for (i = 0; i < *pnLen; i++) {
974 (*pplFreqTable)[i] = plFreqTable[i + 2];
975 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table #%d => (%ld)\n",i+*pnFirst,(*pplFreqTable)[i]);
977 FreeLibrary(hDLL);
978 return S_OK;
982 * \brief tunes to given frequency through IKsPropertySet call
984 * \param pTVTuner IAMTVTuner interface of capture device
985 * \param lFreq frequency to tune (in Hz)
987 * \return S_OK success
988 * \return apropriate error code otherwise
990 * \note
991 * Due to either bug in driver or error in following code calll to IKsProperty::Set
992 * in this methods always fail with error 0x8007007a.
994 * \todo test code on other machines and an error
996 static HRESULT set_frequency_direct(IAMTVTuner * pTVTuner, long lFreq)
998 HRESULT hr;
999 DWORD dwSupported = 0;
1000 DWORD cbBytes = 0;
1001 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps;
1002 KSPROPERTY_TUNER_FREQUENCY_S frequency;
1003 IKsPropertySet *pKSProp;
1005 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency_direct called\n");
1007 memset(&mode_caps, 0, sizeof(mode_caps));
1008 memset(&frequency, 0, sizeof(frequency));
1010 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
1011 if (FAILED(hr))
1012 return hr; //no IKsPropertySet interface
1014 mode_caps.Mode = AMTUNER_MODE_TV;
1015 hr = OLE_CALL_ARGS(pKSProp, QuerySupported, &PROPSETID_TUNER,
1016 KSPROPERTY_TUNER_MODE_CAPS, &dwSupported);
1017 if (FAILED(hr)) {
1018 OLE_RELEASE_SAFE(pKSProp);
1019 return hr;
1022 if (!dwSupported & KSPROPERTY_SUPPORT_GET) {
1023 OLE_RELEASE_SAFE(pKSProp);
1024 return E_FAIL; //PROPSETID_TINER not supported
1027 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
1028 KSPROPERTY_TUNER_MODE_CAPS,
1029 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps),
1030 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps),
1031 &mode_caps, sizeof(mode_caps), &cbBytes);
1033 frequency.Frequency = lFreq;
1035 if (mode_caps.Strategy == KS_TUNER_STRATEGY_DRIVER_TUNES)
1036 frequency.TuningFlags = KS_TUNER_TUNING_FINE;
1037 else
1038 frequency.TuningFlags = KS_TUNER_TUNING_EXACT;
1040 if (lFreq < mode_caps.MinFrequency || lFreq > mode_caps.MaxFrequency) {
1041 OLE_RELEASE_SAFE(pKSProp);
1042 return E_FAIL;
1045 hr = OLE_CALL_ARGS(pKSProp, Set, &PROPSETID_TUNER,
1046 KSPROPERTY_TUNER_FREQUENCY,
1047 INSTANCEDATA_OF_PROPERTY_PTR(&frequency),
1048 INSTANCEDATA_OF_PROPERTY_SIZE(frequency),
1049 &frequency, sizeof(frequency));
1050 if (FAILED(hr)) {
1051 OLE_RELEASE_SAFE(pKSProp);
1052 return hr;
1055 OLE_RELEASE_SAFE(pKSProp);
1057 return S_OK;
1061 * \brief find channel with nearest frequency and set it
1063 * \param priv driver's private data
1064 * \param lFreq frequency in Hz
1066 * \return S_OK if success
1067 * \return E_FAIL if error occured
1069 static HRESULT set_nearest_freq(priv_t * priv, long lFreq)
1071 HRESULT hr;
1072 int i;
1073 long lFreqDiff=-1;
1074 int nChannel;
1075 TunerInputType tunerInput;
1076 long lInput;
1078 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq called: %ld\n", lFreq);
1079 if(priv->freq_table_len == -1 && !priv->freq_table) {
1081 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
1082 if(FAILED(hr)){ //Falling back to 0
1083 lInput=0;
1086 hr = OLE_CALL_ARGS(priv->pTVTuner, get_InputType, lInput, &tunerInput);
1088 if (load_freq_table(chanlist2country(priv->tv_param->chanlist), tunerInput, &(priv->freq_table), &(priv->freq_table_len), &(priv->first_channel)) != S_OK) {//FIXME
1089 priv->freq_table_len=0;
1090 priv->freq_table=NULL;
1091 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unable to load frequency table from kstvtune.ax\n");
1092 return E_FAIL;
1094 mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: loaded system (%s) frequency table for country id=%d (channels:%d).\n", tunerInput == TunerInputAntenna ? "broadcast" : "cable",
1095 chanlist2country(priv->tv_param->chanlist), priv->freq_table_len);
1098 if (priv->freq_table_len <= 0)
1099 return E_FAIL;
1101 //FIXME: rewrite search algo
1102 nChannel = -1;
1103 for (i = 0; i < priv->freq_table_len; i++) {
1104 if (nChannel == -1 || labs(lFreq - priv->freq_table[i]) < lFreqDiff) {
1105 nChannel = priv->first_channel + i;
1106 lFreqDiff = labs(lFreq - priv->freq_table[i]);
1108 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);
1110 if (nChannel == -1) {
1111 mp_tmsg(MSGT_TV,MSGL_ERR, "tvi_dshow: Unable to find nearest channel in system frequency table\n");
1112 return E_FAIL;
1114 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: set_nearest_freq #%d (%ld)\n",nChannel,priv->freq_table[nChannel - priv->first_channel]);
1115 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Channel, nChannel,
1116 AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT);
1117 if (FAILED(hr)) {
1118 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);
1119 return E_FAIL;
1121 return S_OK;
1125 * \brief setting frequency. decides whether use direct call/workaround
1127 * \param priv driver's private data
1128 * \param lFreq frequency in Hz
1130 * \return TVI_CONTROL_TRUE if success
1131 * \return TVI_CONTROL_FALSE if error occured
1133 * \todo check for freq boundary
1135 static int set_frequency(priv_t * priv, long lFreq)
1137 HRESULT hr;
1139 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency called: %ld\n", lFreq);
1140 if (!priv->pTVTuner)
1141 return TVI_CONTROL_FALSE;
1142 if (priv->direct_setfreq_call) { //using direct call to set frequency
1143 hr = set_frequency_direct(priv->pTVTuner, lFreq);
1144 if (FAILED(hr)) {
1145 mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to set frequency directly. OS built-in channels table will be used.\n");
1146 priv->direct_setfreq_call = 0;
1149 if (!priv->direct_setfreq_call) {
1150 hr = set_nearest_freq(priv, lFreq);
1152 if (FAILED(hr))
1153 return TVI_CONTROL_FALSE;
1154 #ifdef DEPRECATED
1155 priv->pGrabber->ClearBuffer(priv->pGrabber);
1156 #endif
1157 return TVI_CONTROL_TRUE;
1161 * \brief return current frequency from tuner (in Hz)
1163 * \param pTVTuner IAMTVTuner interface of tuner
1164 * \param plFreq address of variable that receives current frequency
1166 * \return S_OK success
1167 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1168 * \return apropriate error code otherwise
1170 static HRESULT get_frequency_direct(IAMTVTuner * pTVTuner, long *plFreq)
1172 HRESULT hr;
1173 KSPROPERTY_TUNER_STATUS_S TunerStatus;
1174 DWORD cbBytes;
1175 IKsPropertySet *pKSProp;
1176 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency_direct called\n");
1178 if (!plFreq)
1179 return E_POINTER;
1181 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
1182 if (FAILED(hr)) {
1183 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq QueryInterface failed\n");
1184 return hr;
1187 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
1188 KSPROPERTY_TUNER_STATUS,
1189 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus),
1190 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus),
1191 &TunerStatus, sizeof(TunerStatus), &cbBytes);
1192 if (FAILED(hr)) {
1193 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq Get failure\n");
1194 return hr;
1196 *plFreq = TunerStatus.CurrentFrequency;
1197 return S_OK;
1201 * \brief gets current frequency
1203 * \param priv driver's private data structure
1204 * \param plFreq - pointer to long int to store frequency to (in Hz)
1206 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1208 static int get_frequency(priv_t * priv, long *plFreq)
1210 HRESULT hr;
1212 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency called\n");
1214 if (!plFreq || !priv->pTVTuner)
1215 return TVI_CONTROL_FALSE;
1217 if (priv->direct_getfreq_call) { //using direct call to get frequency
1218 hr = get_frequency_direct(priv->pTVTuner, plFreq);
1219 if (FAILED(hr)) {
1220 mp_tmsg(MSGT_TV, MSGL_INFO, "tvi_dshow: Unable to get frequency directly. OS built-in channels table will be used.\n");
1221 priv->direct_getfreq_call = 0;
1224 if (!priv->direct_getfreq_call) {
1225 hr=OLE_CALL_ARGS(priv->pTVTuner, get_VideoFrequency, plFreq);
1226 if (FAILED(hr))
1227 return TVI_CONTROL_FALSE;
1230 return TVI_CONTROL_TRUE;
1234 * \brief get tuner capabilities
1236 * \param priv driver's private data
1238 static void get_capabilities(priv_t * priv)
1240 long lAvailableFormats;
1241 HRESULT hr;
1242 int i;
1243 long lInputPins, lOutputPins, lRelated, lPhysicalType;
1244 IEnumPins *pEnum;
1245 char tmp[200];
1246 IPin *pPin = 0;
1247 PIN_DIRECTION ThisPinDir;
1248 PIN_INFO pi;
1249 IAMAudioInputMixer *pIAMixer;
1251 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_capabilities called\n");
1252 if (priv->pTVTuner) {
1254 mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: supported norms:");
1255 hr = OLE_CALL_ARGS(priv->pTVTuner, get_AvailableTVFormats,
1256 &lAvailableFormats);
1257 if (FAILED(hr))
1258 tv_available_norms_count = 0;
1259 else {
1260 for (i = 0; i < TV_NORMS_COUNT; i++) {
1261 if (lAvailableFormats & tv_norms[i].index) {
1262 tv_available_norms[tv_available_norms_count] = i;
1263 mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
1264 tv_available_norms_count + 1, tv_norms[i].name);
1265 tv_available_norms_count++;
1269 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1271 if (priv->pCrossbar) {
1272 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins,
1273 &lInputPins);
1275 tv_available_inputs = malloc(sizeof(long) * lInputPins);
1276 tv_available_inputs_count = 0;
1278 mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: available video inputs:");
1279 for (i = 0; i < lInputPins; i++) {
1280 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1, i,
1281 &lRelated, &lPhysicalType);
1283 if (lPhysicalType < 0x1000) {
1284 tv_available_inputs[tv_available_inputs_count++] = i;
1285 mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
1286 tv_available_inputs_count - 1,
1287 physcon2str(lPhysicalType));
1290 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1292 set_crossbar_input(priv, 0);
1295 if (priv->adev_index != -1) {
1296 hr = OLE_CALL_ARGS(priv->chains[1]->pCaptureFilter, EnumPins, &pEnum);
1297 if (FAILED(hr))
1298 return;
1299 mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: available audio inputs:");
1300 i = 0;
1301 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
1302 memset(&pi, 0, sizeof(pi));
1303 memset(tmp, 0, 200);
1304 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
1305 if (ThisPinDir == PINDIR_INPUT) {
1306 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
1307 wtoa(pi.achName, tmp, 200);
1308 OLE_RELEASE_SAFE(pi.pFilter);
1309 mp_msg(MSGT_TV, MSGL_V, " %d=%s", i, tmp);
1310 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
1311 hr = OLE_QUERYINTERFACE(pPin, IID_IAMAudioInputMixer,pIAMixer);
1312 if (SUCCEEDED(hr)) {
1313 if (i == priv->tv_param->audio_id) {
1314 OLE_CALL_ARGS(pIAMixer, put_Enable, TRUE);
1315 if(priv->tv_param->volume>0)
1316 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.01 * priv->tv_param->volume);
1317 #if 0
1318 else
1319 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 1.0);
1320 #endif
1321 mp_tmsg(MSGT_TV, MSGL_V, "(selected)");
1322 } else {
1323 OLE_CALL_ARGS(pIAMixer, put_Enable, FALSE);
1324 #if 0
1325 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.0);
1326 #endif
1328 OLE_RELEASE_SAFE(pIAMixer);
1330 mp_msg(MSGT_TV, MSGL_V, ";");
1331 OLE_RELEASE_SAFE(pPin);
1332 i++;
1335 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1336 OLE_RELEASE_SAFE(pEnum);
1341 *---------------------------------------------------------------------------------------
1343 * Filter related methods
1345 *---------------------------------------------------------------------------------------
1348 * \brief building in graph audio/video capture chain
1350 * \param priv driver's private data
1351 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1352 * \param pbuf ringbuffer data structure
1353 * \param pmt media type for chain (AM_MEDIA_TYPE)
1355 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1357 static HRESULT build_sub_graph(priv_t * priv, chain_t * chain, const GUID* ppin_category)
1359 HRESULT hr;
1360 int nFormatProbed = 0;
1362 IPin *pSGOut;
1363 IPin *pNRIn=NULL;
1365 IBaseFilter *pNR = NULL;
1367 hr=S_OK;
1369 //No supported formats
1370 if(!chain->arpmt[0])
1371 return E_FAIL;
1374 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
1375 (IUnknown *) chain->pCaptureFilter,
1376 PINDIR_OUTPUT, ppin_category,
1377 chain->majortype, FALSE, 0, &chain->pCapturePin);
1378 if(FAILED(hr)){
1379 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr);
1380 break;
1382 /* Addinf SampleGrabber filter for video stream */
1383 hr = CoCreateInstance((GUID *) & CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &chain->pSGF);
1384 if(FAILED(hr)){
1385 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1386 break;
1388 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, chain->pSGF, L"Sample Grabber");
1389 if(FAILED(hr)){
1390 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1391 break;
1393 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) chain->pSGF,PINDIR_INPUT, NULL, NULL, FALSE, 0, &chain->pSGIn);
1394 if(FAILED(hr)){
1395 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr);
1396 break;
1398 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) chain->pSGF,PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pSGOut);
1399 if(FAILED(hr)){
1400 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr);
1401 break;
1404 /* creating ringbuffer for video samples */
1405 chain->pCSGCB = CSampleGrabberCB_Create(chain->rbuf);
1406 if(!chain->pCSGCB){
1407 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY);
1408 break;
1411 /* initializing SampleGrabber filter */
1412 hr = OLE_QUERYINTERFACE(chain->pSGF, IID_ISampleGrabber, chain->pSG);
1413 if(FAILED(hr)){
1414 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1415 break;
1417 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1418 hr = OLE_CALL_ARGS(chain->pSG, SetCallback, (ISampleGrabberCB *) chain->pCSGCB, 0); //we want to receive sample
1420 if(FAILED(hr)){
1421 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1422 break;
1424 hr = OLE_CALL_ARGS(chain->pSG, SetOneShot, FALSE); //... for all frames
1425 if(FAILED(hr)){
1426 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1427 break;
1429 hr = OLE_CALL_ARGS(chain->pSG, SetBufferSamples, FALSE); //... do not buffer samples in sample grabber
1430 if(FAILED(hr)){
1431 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1432 break;
1435 if(priv->tv_param->normalize_audio_chunks && chain->type==audio){
1436 set_buffer_preference(20,(WAVEFORMATEX*)(chain->arpmt[nFormatProbed]->pbFormat),chain->pCapturePin,chain->pSGIn);
1439 for(nFormatProbed=0; chain->arpmt[nFormatProbed]; nFormatProbed++)
1441 DisplayMediaType("Probing format", chain->arpmt[nFormatProbed]);
1442 hr = OLE_CALL_ARGS(chain->pSG, SetMediaType, chain->arpmt[nFormatProbed]); //set desired mediatype
1443 if(FAILED(hr)){
1444 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1445 continue;
1447 /* connecting filters together: VideoCapture --> SampleGrabber */
1448 hr = OLE_CALL_ARGS(priv->pGraph, Connect, chain->pCapturePin, chain->pSGIn);
1449 if(FAILED(hr)){
1450 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr);
1451 continue;
1453 break;
1456 if(!chain->arpmt[nFormatProbed])
1458 mp_msg(MSGT_TV, MSGL_WARN, "tvi_dshow: Unable to negotiate media format\n");
1459 hr = E_FAIL;
1460 break;
1463 hr = OLE_CALL_ARGS(chain->pCapturePin, ConnectionMediaType, chain->pmt);
1464 if(FAILED(hr))
1466 mp_tmsg(MSGT_TV, MSGL_WARN, "tvi_dshow: Unable to get actual mediatype (Error:0x%x). Assuming equal to requested.\n", (unsigned int)hr);
1469 if(priv->tv_param->hidden_video_renderer){
1470 IEnumFilters* pEnum;
1471 IBaseFilter* pFilter;
1473 hr=OLE_CALL_ARGS(priv->pBuilder,RenderStream,NULL,NULL,(IUnknown*)chain->pCapturePin,NULL,NULL);
1475 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
1476 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
1477 LPVIDEOWINDOW pVideoWindow;
1478 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
1479 if (SUCCEEDED(hr))
1481 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
1482 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
1483 OLE_RELEASE_SAFE(pVideoWindow);
1485 OLE_RELEASE_SAFE(pFilter);
1487 OLE_RELEASE_SAFE(pEnum);
1488 }else
1490 #if 0
1492 Code below is disabled, because terminating chain with NullRenderer leads to jerky video.
1493 Perhaps, this happens because NullRenderer filter discards each received
1494 frame while discarded frames causes live source filter to dramatically reduce frame rate.
1496 /* adding sink for video stream */
1497 hr = CoCreateInstance((GUID *) & CLSID_NullRenderer, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pNR);
1498 if(FAILED(hr)){
1499 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
1500 break;
1502 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pNR, L"Null Renderer");
1503 if(FAILED(hr)){
1504 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
1505 break;
1507 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pNR,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pNRIn);
1508 if(FAILED(hr)){
1509 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr);
1510 break;
1513 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1515 if(memcmp(&(arpmt[nFormatProbed]->majortype),&MEDIATYPE_VBI,16)){
1516 /* connecting filters together: SampleGrabber --> NullRenderer */
1517 hr = OLE_CALL_ARGS(priv->pGraph, Connect, pSGOut, pNRIn);
1518 if(FAILED(hr)){
1519 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr);
1520 break;
1523 #endif
1526 hr = S_OK;
1527 } while(0);
1529 OLE_RELEASE_SAFE(pSGOut);
1530 OLE_RELEASE_SAFE(pNR);
1531 OLE_RELEASE_SAFE(pNRIn);
1533 return hr;
1537 * \brief configures crossbar for grabbing video stream from given input
1539 * \param priv driver's private data
1540 * \param input index of available video input to get data from
1542 * \return TVI_CONTROL_TRUE success
1543 * \return TVI_CONTROL_FALSE error
1545 static int set_crossbar_input(priv_t * priv, int input)
1547 HRESULT hr;
1548 int i, nVideoDecoder, nAudioDecoder;
1549 long lInput, lInputRelated, lRelated, lPhysicalType, lOutputPins,
1550 lInputPins;
1552 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Configuring crossbar\n");
1553 if (!priv->pCrossbar || input < 0
1554 || input >= tv_available_inputs_count)
1555 return TVI_CONTROL_FALSE;
1557 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, &lInputPins);
1559 lInput = tv_available_inputs[input];
1561 if (lInput < 0 || lInput >= lInputPins)
1562 return TVI_CONTROL_FALSE;
1564 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1 /* input */ , lInput,
1565 &lInputRelated, &lPhysicalType);
1567 nVideoDecoder = nAudioDecoder = -1;
1568 for (i = 0; i < lOutputPins; i++) {
1569 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 0 /*output */ , i,
1570 &lRelated, &lPhysicalType);
1571 if (lPhysicalType == PhysConn_Video_VideoDecoder)
1572 nVideoDecoder = i;
1573 if (lPhysicalType == PhysConn_Audio_AudioDecoder)
1574 nAudioDecoder = i;
1576 if (nVideoDecoder >= 0) {
1577 //connecting given input with video decoder
1578 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nVideoDecoder, lInput);
1579 if (hr != S_OK) {
1580 mp_tmsg(MSGT_TV,MSGL_ERR,"Unable to connect given input to video decoder. Error:0x%x\n", (unsigned int)hr);
1581 return TVI_CONTROL_FALSE;
1584 if (nAudioDecoder >= 0 && lInputRelated >= 0) {
1585 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nAudioDecoder,
1586 lInputRelated);
1587 if (hr != S_OK) {
1588 mp_tmsg(MSGT_TV,MSGL_ERR,"Unable to connect given input to audio decoder. Error:0x%x\n", (unsigned int)hr);
1589 return TVI_CONTROL_FALSE;
1592 return TVI_CONTROL_TRUE;
1596 * \brief adjusts video control (hue,saturation,contrast,brightess)
1598 * \param priv driver's private data
1599 * \param control which control to adjust
1600 * \param value new value for control (0-100)
1602 * \return TVI_CONTROL_TRUE success
1603 * \return TVI_CONTROL_FALSE error
1605 static int set_control(priv_t * priv, int control, int value)
1607 long lMin, lMax, lStepping, lDefault, lFlags, lValue;
1608 HRESULT hr;
1610 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_control called\n");
1611 if (value < -100 || value > 100 || !priv->pVideoProcAmp)
1612 return TVI_CONTROL_FALSE;
1614 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
1615 &lMin, &lMax, &lStepping, &lDefault, &lFlags);
1616 if (FAILED(hr) || lFlags != VideoProcAmp_Flags_Manual)
1617 return TVI_CONTROL_FALSE;
1619 lValue = lMin + (value + 100) * (lMax - lMin) / 200;
1621 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1623 if (lStepping > lMax) {
1624 mp_msg(MSGT_TV, MSGL_DBG3,
1625 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1626 lStepping, lMax,control);
1627 lStepping = 1;
1629 lValue -= lValue % lStepping;
1630 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Set, control, lValue,
1631 VideoProcAmp_Flags_Manual);
1632 if (FAILED(hr))
1633 return TVI_CONTROL_FALSE;
1635 return TVI_CONTROL_TRUE;
1639 * \brief get current value of video control (hue,saturation,contrast,brightess)
1641 * \param priv driver's private data
1642 * \param control which control to adjust
1643 * \param pvalue address of variable thar receives current value
1645 * \return TVI_CONTROL_TRUE success
1646 * \return TVI_CONTROL_FALSE error
1648 static int get_control(priv_t * priv, int control, int *pvalue)
1650 long lMin, lMax, lStepping, lDefault, lFlags, lValue;
1651 HRESULT hr;
1653 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_control called\n");
1654 if (!pvalue || !priv->pVideoProcAmp)
1655 return TVI_CONTROL_FALSE;
1657 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
1658 &lMin, &lMax, &lStepping, &lDefault, &lFlags);
1659 if (FAILED(hr))
1660 return TVI_CONTROL_FALSE;
1661 if (lMin == lMax) {
1662 *pvalue = lMin;
1663 return TVI_CONTROL_TRUE;
1666 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Get, control, &lValue, &lFlags);
1667 if (FAILED(hr))
1668 return TVI_CONTROL_FALSE;
1670 *pvalue = 200 * (lValue - lMin) / (lMax - lMin) - 100;
1672 return TVI_CONTROL_TRUE;
1676 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps
1677 * \param fcc FourCC code for video format
1678 * \param width picture width
1679 * \param height pciture height
1680 * \param fps frames per second (required for bitrate calculation)
1682 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise
1684 static AM_MEDIA_TYPE* create_video_format(int fcc, int width, int height, int fps)
1686 int i;
1687 AM_MEDIA_TYPE mt;
1688 VIDEOINFOHEADER vHdr;
1690 /* Check given fcc in lookup table*/
1691 for(i=0; img_fmt_list[i].fmt && img_fmt_list[i].fmt!=fcc; i++) /* NOTHING */;
1692 if(!img_fmt_list[i].fmt)
1693 return NULL;
1695 memset(&mt, 0, sizeof(AM_MEDIA_TYPE));
1696 memset(&vHdr, 0, sizeof(VIDEOINFOHEADER));
1698 vHdr.bmiHeader.biSize = sizeof(vHdr.bmiHeader);
1699 vHdr.bmiHeader.biWidth = width;
1700 vHdr.bmiHeader.biHeight = height;
1701 //FIXME: is biPlanes required too?
1702 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes;
1703 vHdr.bmiHeader.biBitCount = img_fmt_list[i].nBits;
1704 vHdr.bmiHeader.biCompression = img_fmt_list[i].nCompression;
1705 vHdr.bmiHeader.biSizeImage = width * height * img_fmt_list[i].nBits / 8;
1706 vHdr.dwBitRate = vHdr.bmiHeader.biSizeImage * 8 * fps;
1708 mt.pbFormat = (char*)&vHdr;
1709 mt.cbFormat = sizeof(vHdr);
1711 mt.majortype = MEDIATYPE_Video;
1712 mt.subtype = *img_fmt_list[i].subtype;
1713 mt.formattype = FORMAT_VideoInfo;
1715 mt.bFixedSizeSamples = 1;
1716 mt.bTemporalCompression = 0;
1717 mt.lSampleSize = vHdr.bmiHeader.biSizeImage;
1719 return CreateMediaType(&mt);
1723 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1725 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1726 * \param pfcc address of variable that receives FourCC
1727 * \param pwidth address of variable that receives width
1728 * \param pheight address of variable that recevies height
1730 * \return 1 if data extracted successfully, 0 - otherwise
1732 static int extract_video_format(AM_MEDIA_TYPE * pmt, int *pfcc,
1733 int *pwidth, int *pheight)
1735 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_video_format called\n");
1736 if (!pmt)
1737 return 0;
1738 if (!pmt->pbFormat)
1739 return 0;
1740 if (memcmp(&(pmt->formattype), &FORMAT_VideoInfo, 16) != 0)
1741 return 0;
1742 if (pfcc)
1743 *pfcc = subtype2imgfmt(&(pmt->subtype));
1744 if (pwidth)
1745 *pwidth = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biWidth;
1746 if (pheight)
1747 *pheight = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biHeight;
1748 return 1;
1752 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1754 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1755 * \param pfcc address of variable that receives samplerate
1756 * \param pwidth address of variable that receives number of bits per sample
1757 * \param pheight address of variable that recevies number of channels
1759 * \return 1 if data extracted successfully, 0 - otherwise
1761 static int extract_audio_format(AM_MEDIA_TYPE * pmt, int *psamplerate,
1762 int *pbits, int *pchannels)
1764 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_audio_format called\n");
1765 if (!pmt)
1766 return 0;
1767 if (!pmt->pbFormat)
1768 return 0;
1769 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
1770 return 0;
1771 if (psamplerate)
1772 *psamplerate = ((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec;
1773 if (pbits)
1774 *pbits = ((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample;
1775 if (pchannels)
1776 *pchannels = ((WAVEFORMATEX *) pmt->pbFormat)->nChannels;
1777 return 1;
1781 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1783 * \param pmt pointer to AM_MEDIA_TYPE for check
1784 * \param samplerate audio samplerate
1785 * \param bits bits per sample
1786 * \param channels number of audio channels
1788 * \return 1 if AM_MEDIA_TYPE compatible
1789 * \return 0 if not
1791 static int check_audio_format(AM_MEDIA_TYPE * pmt, int samplerate,
1792 int bits, int channels)
1794 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_audio_format called\n");
1795 if (!pmt)
1796 return 0;
1797 if (memcmp(&(pmt->majortype), &MEDIATYPE_Audio, 16) != 0)
1798 return 0;
1799 if (memcmp(&(pmt->subtype), &MEDIASUBTYPE_PCM, 16) != 0)
1800 return 0;
1801 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
1802 return 0;
1803 if (!pmt->pbFormat)
1804 return 0;
1805 if (((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec != samplerate)
1806 return 0;
1807 if (((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample != bits)
1808 return 0;
1809 if (channels > 0
1810 && ((WAVEFORMATEX *) pmt->pbFormat)->nChannels != channels)
1811 return 0;
1813 return 1;
1817 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1819 * \param pmt pointer to AM_MEDIA_TYPE for check
1820 * \param fcc FourCC (compression)
1821 * \param width width of picture
1822 * \param height height of picture
1824 * \return 1 if AM_MEDIA_TYPE compatible
1825 & \return 0 if not
1827 * \note
1828 * width and height are currently not used
1830 * \todo
1831 * add width/height check
1833 static int check_video_format(AM_MEDIA_TYPE * pmt, int fcc, int width,
1834 int height)
1836 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_video_format called\n");
1837 if (!pmt)
1838 return 0;
1839 if (memcmp(&(pmt->majortype), &MEDIATYPE_Video, 16) != 0)
1840 return 0;
1841 if (subtype2imgfmt(&(pmt->subtype)) != fcc)
1842 return 0;
1843 return 1;
1847 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1849 * \param subtype DirectShow subtype for video format
1851 * \return MPlayer's IMGFMT or 0 if error occured
1853 static int subtype2imgfmt(const GUID * subtype)
1855 int i;
1856 for (i = 0; img_fmt_list[i].fmt; i++) {
1857 if (memcmp(subtype, img_fmt_list[i].subtype, 16) == 0)
1858 return img_fmt_list[i].fmt;
1860 return 0;
1864 * \brief prints filter name and it pins
1866 * \param pFilter - IBaseFilter to get data from
1868 * \return S_OK if success, error code otherwise
1870 static HRESULT show_filter_info(IBaseFilter * pFilter)
1872 char tmp[200];
1873 FILTER_INFO fi;
1874 LPENUMPINS pEnum = 0;
1875 IPin *pPin = 0;
1876 PIN_DIRECTION ThisPinDir;
1877 PIN_INFO pi;
1878 HRESULT hr;
1879 int i;
1881 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: show_filter_info called\n");
1882 memset(&fi, 0, sizeof(fi));
1883 memset(tmp, 0, 200);
1885 OLE_CALL_ARGS(pFilter, QueryFilterInfo, &fi);
1886 OLE_RELEASE_SAFE(fi.pGraph);
1887 wtoa(fi.achName, tmp, 200);
1888 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1889 pFilter, tmp, fi.pGraph);
1890 hr = OLE_CALL_ARGS(pFilter, EnumPins, &pEnum);
1891 if (FAILED(hr))
1892 return hr;
1893 i = 0;
1894 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
1895 memset(&pi, 0, sizeof(pi));
1896 memset(tmp, 0, 200);
1897 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
1898 if (ThisPinDir == PINDIR_OUTPUT) {
1899 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
1900 wtoa(pi.achName, tmp, 200);
1901 OLE_RELEASE_SAFE(pi.pFilter);
1902 mp_msg(MSGT_TV, MSGL_DBG2, " %d=%s", i, tmp);
1903 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
1904 mp_msg(MSGT_TV, MSGL_DBG2, ";");
1905 OLE_RELEASE_SAFE(pPin);
1906 i++;
1909 mp_msg(MSGT_TV, MSGL_DBG2, "\n");
1910 OLE_RELEASE_SAFE(pEnum);
1911 return S_OK;
1915 * \brief gets device's frendly in ANSI encoding
1917 * \param pM IMoniker interface, got in enumeration process
1918 * \param category device category
1920 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1922 static int get_device_name(IMoniker * pM, char *pBuf, int nLen)
1924 HRESULT hr;
1925 VARIANT var;
1926 IPropertyBag *pPropBag;
1927 hr = OLE_CALL_ARGS(pM, BindToStorage, 0, 0, &IID_IPropertyBag,(void *) &pPropBag);
1928 if (FAILED(hr)) {
1929 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Call to BindToStorage failed\n");
1930 return TVI_CONTROL_FALSE;
1932 var.vt = VT_BSTR;
1933 hr = OLE_CALL_ARGS(pPropBag, Read, L"Description", (LPVARIANT) & var,
1934 NULL);
1935 if (FAILED(hr)) {
1936 hr = OLE_CALL_ARGS(pPropBag, Read, L"FriendlyName", (LPVARIANT) & var,
1937 NULL);
1939 OLE_RELEASE_SAFE(pPropBag);
1940 if (SUCCEEDED(hr)) {
1941 wtoa(var.bstrVal, pBuf, nLen);
1942 return TVI_CONTROL_TRUE;
1944 return TVI_CONTROL_FALSE;
1948 * \brief find capture device at given index
1950 * \param index device index to search for (-1 mean only print available)
1951 * \param category device category
1953 * \return IBaseFilter interface for capture device with given index
1955 * Sample values for category:
1956 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1957 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1958 * See DirectShow SDK documentation for other possible values
1960 static IBaseFilter *find_capture_device(int index, REFCLSID category)
1962 IBaseFilter *pFilter = NULL;
1963 ICreateDevEnum *pDevEnum = NULL;
1964 IEnumMoniker *pClassEnum = NULL;
1965 IMoniker *pM;
1966 HRESULT hr;
1967 ULONG cFetched;
1968 int i;
1969 char tmp[DEVICE_NAME_MAX_LEN + 1];
1970 hr = CoCreateInstance((GUID *) & CLSID_SystemDeviceEnum, NULL,
1971 CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum,
1972 (void *) &pDevEnum);
1973 if (FAILED(hr)) {
1974 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create device enumerator\n");
1975 return NULL;
1978 hr = OLE_CALL_ARGS(pDevEnum, CreateClassEnumerator, category, &pClassEnum, 0);
1979 OLE_RELEASE_SAFE(pDevEnum);
1980 if (FAILED(hr)) {
1981 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create class enumerator\n");
1982 return NULL;
1984 if (hr == S_FALSE) {
1985 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: No capture devices found\n");
1986 return NULL;
1989 OLE_CALL(pClassEnum,Reset);
1990 for (i = 0; OLE_CALL_ARGS(pClassEnum, Next, 1, &pM, &cFetched) == S_OK; i++) {
1991 if(get_device_name(pM, tmp, DEVICE_NAME_MAX_LEN)!=TVI_CONTROL_TRUE)
1992 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unable to get name for device #%d\n", i);
1993 else
1994 mp_tmsg(MSGT_TV, MSGL_V, "tvi_dshow: Device #%d: %s\n", i, tmp);
1995 if (index != -1 && i == index) {
1996 mp_tmsg(MSGT_TV, MSGL_INFO, "tvi_dshow: Using device #%d: %s\n", index, tmp);
1997 hr = OLE_CALL_ARGS(pM, BindToObject, 0, 0, &IID_IBaseFilter,(void *) &pFilter);
1998 if (FAILED(hr))
1999 pFilter = NULL;
2001 OLE_RELEASE_SAFE(pM);
2003 if (index != -1 && !pFilter) {
2004 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Device #%d not found\n",
2005 index);
2007 OLE_RELEASE_SAFE(pClassEnum);
2009 return pFilter;
2013 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
2015 * \praram[in] chain chain data structure
2017 * \return S_OK success
2018 * \return E_POINTER one of parameters is NULL
2019 * \return E_FAIL required size of buffer is unknown for given media type
2020 * \return E_OUTOFMEMORY not enough memory
2021 * \return other error code from called methods
2023 * \remarks
2024 * last items of chain->arpmt and chain->arStreamCaps will be NULL
2026 static HRESULT get_available_formats_stream(chain_t *chain)
2028 AM_MEDIA_TYPE **arpmt;
2029 void **pBuf=NULL;
2031 HRESULT hr;
2032 int i, count, size;
2033 int done;
2035 mp_msg(MSGT_TV, MSGL_DBG4,
2036 "tvi_dshow: get_available_formats_stream called\n");
2038 if (!chain->pStreamConfig)
2039 return E_POINTER;
2041 hr=OLE_CALL_ARGS(chain->pStreamConfig, GetNumberOfCapabilities, &count, &size);
2042 if (FAILED(hr)) {
2043 mp_msg(MSGT_TV, MSGL_DBG4,
2044 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
2045 return hr;
2047 if (chain->type == video){
2048 if (size != sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
2049 mp_msg(MSGT_TV, MSGL_DBG4,
2050 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2051 return E_FAIL;
2053 } else if (chain->type == audio){
2054 if (size != sizeof(AUDIO_STREAM_CONFIG_CAPS)) {
2055 mp_msg(MSGT_TV, MSGL_DBG4,
2056 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2057 return E_FAIL;
2059 } else {
2060 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unsupported media type passed to %s\n","get_available_formats_stream");
2061 return E_FAIL;
2063 done = 0;
2065 arpmt = malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
2066 if (arpmt) {
2067 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
2069 pBuf = malloc((count + 1) * sizeof(void *));
2070 if (pBuf) {
2071 memset(pBuf, 0, (count + 1) * sizeof(void *));
2073 for (i = 0; i < count; i++) {
2074 pBuf[i] = malloc(size);
2076 if (!pBuf[i])
2077 break;
2079 hr = OLE_CALL_ARGS(chain->pStreamConfig, GetStreamCaps, i,
2080 &(arpmt[i]), pBuf[i]);
2081 if (FAILED(hr))
2082 break;
2084 if (i == count) {
2085 chain->arpmt = arpmt;
2086 chain->arStreamCaps = pBuf;
2087 done = 1;
2091 if (!done) {
2092 for (i = 0; i < count; i++) {
2093 if (pBuf && pBuf[i])
2094 free(pBuf[i]);
2095 if (arpmt && arpmt[i])
2096 DeleteMediaType(arpmt[i]);
2098 if (pBuf)
2099 free(pBuf);
2100 if (arpmt)
2101 free(arpmt);
2102 if (hr != S_OK) {
2103 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
2104 return hr;
2105 } else
2106 return E_OUTOFMEMORY;
2108 return S_OK;
2112 * \brief returns allocates an array and store available media formats for given pin type to it
2114 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2115 * \param chain chain data structure
2117 * \return S_OK success
2118 * \return E_POINTER one of given pointers is null
2119 * \return apropriate error code otherwise
2121 static HRESULT get_available_formats_pin(ICaptureGraphBuilder2 * pBuilder,
2122 chain_t *chain)
2124 IEnumMediaTypes *pEnum;
2125 int i, count, size;
2126 ULONG cFetched;
2127 AM_MEDIA_TYPE *pmt;
2128 HRESULT hr;
2129 void **pBuf;
2130 AM_MEDIA_TYPE **arpmt; //This will be real array
2131 VIDEO_STREAM_CONFIG_CAPS *pVideoCaps;
2132 AUDIO_STREAM_CONFIG_CAPS *pAudioCaps;
2133 int p1, p2, p3;
2135 mp_msg(MSGT_TV, MSGL_DBG4,
2136 "tvi_dshow: get_available_formats_pin called\n");
2137 if (!pBuilder || !chain->pCaptureFilter)
2138 return E_POINTER;
2140 if (!chain->pCapturePin)
2142 hr = OLE_CALL_ARGS(pBuilder, FindPin,
2143 (IUnknown *) chain->pCaptureFilter,
2144 PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE,
2145 chain->majortype, FALSE, 0, &chain->pCapturePin);
2147 if (!chain->pCapturePin)
2148 return E_POINTER;
2150 if (chain->type == video) {
2151 size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
2152 } else if (chain->type == audio) {
2153 size = sizeof(AUDIO_STREAM_CONFIG_CAPS);
2154 } else {
2155 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unsupported media type passed to %s\n","get_available_formats_pin");
2156 return E_FAIL;
2159 hr = OLE_CALL_ARGS(chain->pCapturePin, EnumMediaTypes, &pEnum);
2160 if (FAILED(hr)) {
2161 mp_msg(MSGT_TV, MSGL_DBG4,
2162 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2163 return hr;
2165 for (i = 0; OLE_CALL_ARGS(pEnum, Next, 1, &pmt, &cFetched) == S_OK; i++) {
2166 if (!pmt)
2167 break;
2169 OLE_CALL(pEnum,Reset);
2171 count = i;
2172 arpmt = malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
2173 if (!arpmt)
2174 return E_OUTOFMEMORY;
2175 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
2177 for (i = 0;
2178 i < count
2179 && OLE_CALL_ARGS(pEnum, Next, 1, &(arpmt[i]), &cFetched) == S_OK;
2180 i++);
2182 OLE_RELEASE_SAFE(pEnum);
2185 pBuf = malloc((count + 1) * sizeof(void *));
2186 if (!pBuf) {
2187 for (i = 0; i < count; i++)
2188 if (arpmt[i])
2189 DeleteMediaType(arpmt[i]);
2190 free(arpmt);
2191 return E_OUTOFMEMORY;
2193 memset(pBuf, 0, (count + 1) * sizeof(void *));
2195 for (i = 0; i < count; i++) {
2196 pBuf[i] = malloc(size);
2197 if (!pBuf[i])
2198 break;
2199 memset(pBuf[i], 0, size);
2201 if (chain->type == video) {
2202 pVideoCaps = (VIDEO_STREAM_CONFIG_CAPS *) pBuf[i];
2203 extract_video_format(arpmt[i], NULL, &p1, &p2);
2204 pVideoCaps->MaxOutputSize.cx = pVideoCaps->MinOutputSize.cx =
2206 pVideoCaps->MaxOutputSize.cy = pVideoCaps->MinOutputSize.cy =
2208 } else {
2209 pAudioCaps = (AUDIO_STREAM_CONFIG_CAPS *) pBuf[i];
2210 extract_audio_format(arpmt[i], &p1, &p2, &p3);
2211 pAudioCaps->MaximumSampleFrequency =
2212 pAudioCaps->MinimumSampleFrequency = p1;
2213 pAudioCaps->MaximumBitsPerSample =
2214 pAudioCaps->MinimumBitsPerSample = p2;
2215 pAudioCaps->MaximumChannels = pAudioCaps->MinimumChannels = p3;
2219 if (i != count) {
2220 for (i = 0; i < count; i++) {
2221 if (arpmt[i])
2222 DeleteMediaType(arpmt[i]);
2223 if (pBuf[i])
2224 free(pBuf[i]);
2226 free(arpmt);
2227 free(pBuf);
2228 return E_OUTOFMEMORY;
2230 chain->arpmt = arpmt;
2231 chain->arStreamCaps = pBuf;
2233 return S_OK;
2237 *---------------------------------------------------------------------------------------
2239 * Public methods
2241 *---------------------------------------------------------------------------------------
2244 * \brief fills given buffer with audio data (usually one block)
2246 * \param priv driver's private data structure
2247 * \param buffer buffer to store data to
2248 * \param len buffer's size in bytes (usually one block size)
2250 * \return audio pts if audio present, 1 - otherwise
2252 static double grab_audio_frame(priv_t * priv, char *buffer, int len)
2254 int bytes = 0;
2255 int i;
2256 double pts;
2257 grabber_ringbuffer_t *rb = priv->chains[1]->rbuf;
2258 grabber_ringbuffer_t *vrb = priv->chains[0]->rbuf;
2260 if (!rb || !rb->ringbuffer)
2261 return 1;
2263 if(vrb && vrb->tStart<0){
2264 memset(buffer,0,len);
2265 return 0;
2267 if(vrb && rb->tStart<0)
2268 rb->tStart=vrb->tStart;
2270 if (len < rb->blocksize)
2271 bytes = len;
2272 else
2273 bytes = rb->blocksize;
2275 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2276 rb->count, len);
2277 if(!rb->count){
2278 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
2279 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
2280 if(!rb->count){
2281 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
2282 return 0;
2284 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
2287 EnterCriticalSection(rb->pMutex);
2288 pts=rb->dpts[rb->head]-rb->tStart;
2289 memcpy(buffer, rb->ringbuffer[rb->head], bytes);
2290 rb->head = (rb->head + 1) % rb->buffersize;
2291 rb->count--;
2292 LeaveCriticalSection(rb->pMutex);
2293 return pts;
2297 * \brief returns audio frame size
2299 * \param priv driver's private data structure
2301 * \return audio block size if audio enabled and 1 - otherwise
2303 static int get_audio_framesize(priv_t * priv)
2305 if (!priv->chains[1]->rbuf)
2306 return 1; //no audio
2307 mp_msg(MSGT_TV,MSGL_DBG3,"get_audio_framesize: %d\n",priv->chains[1]->rbuf->blocksize);
2308 return priv->chains[1]->rbuf->blocksize;
2311 static int vbi_get_props(priv_t* priv,tt_stream_props* ptsp)
2313 if(!priv || !ptsp)
2314 return TVI_CONTROL_FALSE;
2316 //STUBS!!!
2317 ptsp->interlaced=0;
2318 ptsp->offset=256;
2320 ptsp->sampling_rate=27e6;
2321 ptsp->samples_per_line=720;
2323 ptsp->count[0]=16;
2324 ptsp->count[1]=16;
2325 //END STUBS!!!
2326 ptsp->bufsize = ptsp->samples_per_line * (ptsp->count[0] + ptsp->count[1]);
2328 mp_msg(MSGT_TV,MSGL_V,"vbi_get_props: sampling_rate=%d,offset:%d,samples_per_line: %d\n interlaced:%s, count=[%d,%d]\n",
2329 ptsp->sampling_rate,
2330 ptsp->offset,
2331 ptsp->samples_per_line,
2332 ptsp->interlaced?"Yes":"No",
2333 ptsp->count[0],
2334 ptsp->count[1]);
2336 return TVI_CONTROL_TRUE;
2339 static void vbi_grabber(priv_t* priv)
2341 grabber_ringbuffer_t *rb = priv->chains[2]->rbuf;
2342 int i;
2343 unsigned char* buf;
2344 if (!rb || !rb->ringbuffer)
2345 return;
2347 buf=calloc(1,rb->blocksize);
2348 for(i=0; i<23 && rb->count; i++){
2349 memcpy(buf,rb->ringbuffer[rb->head],rb->blocksize);
2350 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_DECODE_PAGE,&buf);
2351 rb->head = (rb->head + 1) % rb->buffersize;
2352 rb->count--;
2354 free(buf);
2358 * \brief fills given buffer with video data (usually one frame)
2360 * \param priv driver's private data structure
2361 * \param buffer buffer to store data to
2362 * \param len buffer's size in bytes (usually one frame size)
2364 * \return frame size if video present, 0 - otherwise
2366 static double grab_video_frame(priv_t * priv, char *buffer, int len)
2368 int bytes = 0;
2369 int i;
2370 double pts;
2371 grabber_ringbuffer_t *rb = priv->chains[0]->rbuf;
2373 if (!rb || !rb->ringbuffer)
2374 return 1;
2375 if (len < rb->blocksize)
2376 bytes = len;
2377 else
2378 bytes = rb->blocksize;
2380 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2381 rb->count, len);
2382 if(!rb->count){
2383 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
2384 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
2385 if(!rb->count){
2386 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
2387 return 0;
2389 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
2391 EnterCriticalSection(rb->pMutex);
2392 if(rb->tStart<0)
2393 rb->tStart=rb->dpts[rb->head];
2394 pts=rb->dpts[rb->head]-rb->tStart;
2395 memcpy(buffer, rb->ringbuffer[rb->head], bytes);
2396 rb->head = (rb->head + 1) % rb->buffersize;
2397 rb->count--;
2398 LeaveCriticalSection(rb->pMutex);
2400 vbi_grabber(priv);
2401 return pts;
2405 * \brief returns frame size
2407 * \param priv driver's private data structure
2409 * \return frame size if video present, 0 - otherwise
2411 static int get_video_framesize(priv_t * priv)
2413 // if(!priv->pmtVideo) return 1; //no video
2414 // return priv->pmtVideo->lSampleSize;
2415 if (!priv->chains[0]->rbuf)
2416 return 1; //no video
2417 mp_msg(MSGT_TV,MSGL_DBG3,"geT_video_framesize: %d\n",priv->chains[0]->rbuf->blocksize);
2418 return priv->chains[0]->rbuf->blocksize;
2422 * \brief calculate audio buffer size
2423 * \param video_buf_size size of video buffer in bytes
2424 * \param video_bitrate video bit rate
2425 * \param audio_bitrate audio bit rate
2426 * \return audio buffer isze in bytes
2428 * \remarks length of video buffer and resulted audio buffer calculated in
2429 * seconds will be the same.
2431 static inline int audio_buf_size_from_video(int video_buf_size, int video_bitrate, int audio_bitrate)
2433 int audio_buf_size = audio_bitrate * (video_buf_size / video_bitrate);
2434 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2435 audio_bitrate,video_buf_size,video_bitrate,audio_buf_size);
2436 return audio_buf_size;
2440 * \brief common chain initialization routine
2441 * \param chain chain data structure
2443 * \note pCaptureFilter member should be initialized before call to this routine
2445 static HRESULT init_chain_common(ICaptureGraphBuilder2 *pBuilder, chain_t *chain)
2447 HRESULT hr;
2448 int i;
2450 if(!chain->pCaptureFilter)
2451 return E_POINTER;
2453 show_filter_info(chain->pCaptureFilter);
2455 hr = OLE_CALL_ARGS(pBuilder, FindPin,
2456 (IUnknown *) chain->pCaptureFilter,
2457 PINDIR_OUTPUT, chain->pin_category,
2458 chain->majortype, FALSE, 0, &chain->pCapturePin);
2460 if (FAILED(hr)) {
2461 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr);
2462 return hr;
2465 hr = OLE_CALL_ARGS(pBuilder, FindInterface,
2466 chain->pin_category,
2467 chain->majortype,
2468 chain->pCaptureFilter,
2469 &IID_IAMStreamConfig,
2470 (void **) &(chain->pStreamConfig));
2471 if (FAILED(hr))
2472 chain->pStreamConfig = NULL;
2475 Getting available video formats (last pointer in array will be NULL)
2476 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2477 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2478 min/max values.
2480 hr = get_available_formats_stream(chain);
2481 if (FAILED(hr)) {
2482 mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr);
2483 hr = get_available_formats_pin(pBuilder, chain);
2484 if(FAILED(hr)){
2485 return hr;
2488 chain->nFormatUsed = 0;
2490 //If argument to CreateMediaType is NULL then result will be NULL too.
2491 chain->pmt = CreateMediaType(chain->arpmt[0]);
2493 for (i = 0; chain->arpmt[i]; i++)
2494 DisplayMediaType("Available format", chain->arpmt[i]);
2496 return S_OK;
2499 * \brief build video stream chain in graph
2500 * \param priv private data structure
2502 * \return S_OK if chain was built successfully, apropriate error code otherwise
2504 static HRESULT build_video_chain(priv_t *priv)
2506 HRESULT hr;
2508 if(priv->chains[0]->rbuf)
2509 return S_OK;
2511 if (priv->chains[0]->pStreamConfig) {
2512 hr = OLE_CALL_ARGS(priv->chains[0]->pStreamConfig, SetFormat, priv->chains[0]->pmt);
2513 if (FAILED(hr)) {
2514 mp_tmsg(MSGT_TV,MSGL_ERR,"tvi_dshow: Unable to select video format. Error:0x%x\n", (unsigned int)hr);
2518 priv->chains[0]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2519 if(!priv->chains[0]->rbuf)
2520 return E_OUTOFMEMORY;
2522 if (priv->tv_param->buffer_size >= 0) {
2523 priv->chains[0]->rbuf->buffersize = priv->tv_param->buffer_size;
2524 } else {
2525 priv->chains[0]->rbuf->buffersize = 16;
2528 priv->chains[0]->rbuf->buffersize *= 1024 * 1024;
2529 hr=build_sub_graph(priv, priv->chains[0], &PIN_CATEGORY_CAPTURE);
2530 if(FAILED(hr)){
2531 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unable to build video chain of capture graph. Error:0x%x\n",(unsigned int)hr);
2532 return hr;
2534 return S_OK;
2538 * \brief build audio stream chain in graph
2539 * \param priv private data structure
2541 * \return S_OK if chain was built successfully, apropriate error code otherwise
2543 static HRESULT build_audio_chain(priv_t *priv)
2545 HRESULT hr;
2547 if(priv->chains[1]->rbuf)
2548 return S_OK;
2550 if(priv->immediate_mode)
2551 return S_OK;
2553 if (priv->chains[1]->pStreamConfig) {
2554 hr = OLE_CALL_ARGS(priv->chains[1]->pStreamConfig, SetFormat,
2555 priv->chains[1]->pmt);
2556 if (FAILED(hr)) {
2557 mp_tmsg(MSGT_TV,MSGL_ERR,"tvi_dshow: Unable to select audio format. Error:0x%x\n", (unsigned int)hr);
2561 if(priv->chains[1]->pmt){
2562 priv->chains[1]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2563 if(!priv->chains[1]->rbuf)
2564 return E_OUTOFMEMORY;
2566 /* let the audio buffer be the same size (in seconds) than video one */
2567 priv->chains[1]->rbuf->buffersize=audio_buf_size_from_video(
2568 priv->chains[0]->rbuf->buffersize,
2569 (((VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat)->dwBitRate),
2570 (((WAVEFORMATEX *) (priv->chains[1]->pmt->pbFormat))->nAvgBytesPerSec));
2572 hr=build_sub_graph(priv, priv->chains[1],&PIN_CATEGORY_CAPTURE);
2573 if(FAILED(hr)){
2574 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unable to build audio chain of capture graph. Error:0x%x\n",(unsigned int)hr);
2575 return 0;
2578 return S_OK;
2582 * \brief build VBI stream chain in graph
2583 * \param priv private data structure
2585 * \return S_OK if chain was built successfully, apropriate error code otherwise
2587 static HRESULT build_vbi_chain(priv_t *priv)
2589 HRESULT hr;
2591 if(priv->chains[2]->rbuf)
2592 return S_OK;
2594 if(priv->tv_param->teletext.device)
2596 priv->chains[2]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2597 if(!priv->chains[2]->rbuf)
2598 return E_OUTOFMEMORY;
2600 init_ringbuffer(priv->chains[2]->rbuf,24,priv->tsp.bufsize);
2602 hr=build_sub_graph(priv, priv->chains[2],&PIN_CATEGORY_VBI);
2603 if(FAILED(hr)){
2604 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unable to build VBI chain of capture graph. Error:0x%x\n",(unsigned int)hr);
2605 return 0;
2608 return S_OK;
2612 * \brief playback/capture real start
2614 * \param priv driver's private data structure
2616 * \return 1 if success, 0 - otherwise
2618 * TODO: move some code from init() here
2620 static int start(priv_t * priv)
2622 HRESULT hr;
2624 hr = build_video_chain(priv);
2625 if(FAILED(hr))
2626 return 0;
2628 hr = build_audio_chain(priv);
2629 if(FAILED(hr))
2630 return 0;
2632 hr = build_vbi_chain(priv);
2633 if(FAILED(hr))
2634 return 0;
2637 Graph is ready to capture. Starting graph.
2639 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
2640 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause 10sec\n");
2641 usec_sleep(10000000);
2642 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause end\n");
2644 if (!priv->pMediaControl) {
2645 mp_tmsg(MSGT_TV,MSGL_ERR,"tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n",(unsigned int)E_POINTER);
2646 return 0;
2648 hr = OLE_CALL(priv->pMediaControl, Run);
2649 if (FAILED(hr)) {
2650 mp_tmsg(MSGT_TV,MSGL_ERR,"tvi_dshow: Unable to start graph! Error:0x%x\n", (unsigned int)hr);
2651 return 0;
2653 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Graph is started.\n");
2654 priv->state = 1;
2656 return 1;
2660 * \brief driver initialization
2662 * \param priv driver's private data structure
2664 * \return 1 if success, 0 - otherwise
2666 static int init(priv_t * priv)
2668 HRESULT hr;
2669 int result = 0;
2670 long lInput, lTunerInput;
2671 IEnumFilters *pEnum;
2672 IBaseFilter *pFilter;
2673 IPin *pVPOutPin;
2674 int i;
2676 priv->state=0;
2678 CoInitialize(NULL);
2680 for(i=0; i<3;i++)
2681 priv->chains[i] = calloc(1, sizeof(chain_t));
2683 priv->chains[0]->type=video;
2684 priv->chains[0]->majortype=&MEDIATYPE_Video;
2685 priv->chains[0]->pin_category=&PIN_CATEGORY_CAPTURE;
2686 priv->chains[1]->type=audio;
2687 priv->chains[1]->majortype=&MEDIATYPE_Audio;
2688 priv->chains[1]->pin_category=&PIN_CATEGORY_CAPTURE;
2689 priv->chains[2]->type=vbi;
2690 priv->chains[2]->majortype=&MEDIATYPE_VBI;
2691 priv->chains[2]->pin_category=&PIN_CATEGORY_VBI;
2694 hr = CoCreateInstance((GUID *) & CLSID_FilterGraph, NULL,
2695 CLSCTX_INPROC_SERVER, &IID_IGraphBuilder,
2696 (void **) &priv->pGraph);
2697 if(FAILED(hr)){
2698 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr);
2699 break;
2701 //Debug
2702 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
2703 AddToRot((IUnknown *) priv->pGraph, &(priv->dwRegister));
2706 hr = CoCreateInstance((GUID *) & CLSID_CaptureGraphBuilder2, NULL,
2707 CLSCTX_INPROC_SERVER, &IID_ICaptureGraphBuilder2,
2708 (void **) &priv->pBuilder);
2709 if(FAILED(hr)){
2710 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr);
2711 break;
2714 hr = OLE_CALL_ARGS(priv->pBuilder, SetFiltergraph, priv->pGraph);
2715 if(FAILED(hr)){
2716 mp_msg(MSGT_TV,MSGL_ERR, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr);
2717 break;
2720 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available video capture devices\n");
2721 priv->chains[0]->pCaptureFilter = find_capture_device(priv->dev_index, &CLSID_VideoInputDeviceCategory);
2722 if(!priv->chains[0]->pCaptureFilter){
2723 mp_tmsg(MSGT_TV,MSGL_ERR, "tvi_dshow: Unable to find video capture device\n");
2724 break;
2726 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->chains[0]->pCaptureFilter, NULL);
2727 if(FAILED(hr)){
2728 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
2729 break;
2731 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available audio capture devices\n");
2732 if (priv->adev_index != -1) {
2733 priv->chains[1]->pCaptureFilter = find_capture_device(priv->adev_index, &CLSID_AudioInputDeviceCategory); //output available audio edevices
2734 if(!priv->chains[1]->pCaptureFilter){
2735 mp_tmsg(MSGT_TV,MSGL_ERR, "tvi_dshow: Unable to find audio capture device\n");
2736 break;
2739 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->chains[1]->pCaptureFilter, NULL);
2740 if(FAILED(hr)){
2741 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
2742 break;
2744 } else
2745 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IBaseFilter, priv->chains[1]->pCaptureFilter);
2747 /* increase refrence counter for capture filter ad store pointer into vbi chain structure too */
2748 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IBaseFilter, priv->chains[2]->pCaptureFilter);
2750 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IAMVideoProcAmp,priv->pVideoProcAmp);
2751 if (FAILED(hr) && hr != E_NOINTERFACE)
2752 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr);
2754 if (hr != S_OK) {
2755 mp_tmsg(MSGT_TV, MSGL_INFO, "tvi_dshow: Adjusting of brightness/hue/saturation/contrast is not supported by device\n");
2756 priv->pVideoProcAmp = NULL;
2759 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2760 &PIN_CATEGORY_CAPTURE,
2761 priv->chains[0]->majortype,
2762 priv->chains[0]->pCaptureFilter,
2763 &IID_IAMCrossbar, (void **) &(priv->pCrossbar));
2764 if (FAILED(hr)) {
2765 mp_tmsg(MSGT_TV, MSGL_INFO, "tvi_dshow: Selection of capture source is not supported by device\n");
2766 priv->pCrossbar = NULL;
2769 if (priv->tv_param->amode >= 0) {
2770 IAMTVAudio *pTVAudio;
2771 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, NULL, NULL,priv->chains[0]->pCaptureFilter,&IID_IAMTVAudio, (void *) &pTVAudio);
2772 if (hr == S_OK) {
2773 switch (priv->tv_param->amode) {
2774 case 0:
2775 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_MONO);
2776 break;
2777 case 1:
2778 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_STEREO);
2779 break;
2780 case 2:
2781 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
2782 AMTVAUDIO_MODE_LANG_A);
2783 break;
2784 case 3:
2785 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
2786 AMTVAUDIO_MODE_LANG_B);
2787 break;
2789 OLE_RELEASE_SAFE(pTVAudio);
2790 if (FAILED(hr))
2791 mp_tmsg(MSGT_TV, MSGL_WARN, "tvi_dshow: Unable to set audio mode %d. Error:0x%x\n", priv->tv_param->amode,(unsigned int)hr);
2795 // Video chain initialization
2796 hr = init_chain_common(priv->pBuilder, priv->chains[0]);
2797 if(FAILED(hr))
2798 break;
2801 Audio chain initialization
2802 Since absent audio stream is not fatal,
2803 at least one NULL pointer should be kept in format arrays
2804 (to avoid another additional check everywhere for array presence).
2806 hr = init_chain_common(priv->pBuilder, priv->chains[1]);
2807 if(FAILED(hr))
2809 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to initialize audio chain (Error:0x%x). Audio disabled\n", (unsigned long)hr);
2810 priv->chains[1]->arpmt=calloc(1, sizeof(AM_MEDIA_TYPE*));
2811 priv->chains[1]->arStreamCaps=calloc(1, sizeof(void*));
2815 VBI chain initialization
2816 Since absent VBI stream is not fatal,
2817 at least one NULL pointer should be kept in format arrays
2818 (to avoid another additional check everywhere for array presence).
2820 hr = init_chain_common(priv->pBuilder, priv->chains[2]);
2821 if(FAILED(hr))
2823 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to initialize VBI chain (Error:0x%x). Teletext disabled\n", (unsigned long)hr);
2824 priv->chains[2]->arpmt=calloc(1, sizeof(AM_MEDIA_TYPE*));
2825 priv->chains[2]->arStreamCaps=calloc(1, sizeof(void*));
2828 if (!priv->chains[0]->pStreamConfig)
2829 mp_tmsg(MSGT_TV, MSGL_INFO, "tvi_dshow: Changing video width/height is not supported by device.\n");
2831 if (!priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed]
2832 || !extract_video_format(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed],
2833 &(priv->fcc), &(priv->width),
2834 &(priv->height))) {
2835 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unable to parse video format structure.\n");
2836 break;
2839 if (priv->chains[1]->arpmt[priv->chains[1]->nFormatUsed]) {
2840 if (!extract_audio_format(priv->chains[1]->pmt, &(priv->samplerate), NULL, NULL)) {
2841 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Unable to parse audio format structure.\n");
2842 DisplayMediaType("audio format failed",priv->chains[1]->arpmt[priv->chains[1]->nFormatUsed]);
2843 break;
2847 hr = OLE_QUERYINTERFACE(priv->pGraph, IID_IMediaControl,priv->pMediaControl);
2848 if(FAILED(hr)){
2849 mp_tmsg(MSGT_TV,MSGL_ERR, "tvi_dshow: Unable to get IMediaControl interface. Error:0x%x\n",(unsigned int)hr);
2850 break;
2852 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2853 &PIN_CATEGORY_CAPTURE, NULL,
2854 priv->chains[0]->pCaptureFilter,
2855 &IID_IAMTVTuner, (void **) &(priv->pTVTuner));
2857 if (!priv->pTVTuner) {
2858 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr);
2861 // shows Tuner capabilities
2862 get_capabilities(priv);
2864 if (priv->pTVTuner) {
2865 hr = OLE_CALL_ARGS(priv->pTVTuner, put_CountryCode,
2866 chanlist2country(priv->tv_param->chanlist));
2867 if(FAILED(hr)){
2868 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr);
2871 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Mode, AMTUNER_MODE_TV);
2872 if(FAILED(hr)){
2873 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr);
2874 break;
2877 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
2878 if(FAILED(hr)){
2879 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr);
2880 break;
2883 /* small hack */
2884 lTunerInput = strstr(priv->tv_param->chanlist, "cable") ? TunerInputCable : TunerInputAntenna;
2886 hr = OLE_CALL_ARGS(priv->pTVTuner, put_InputType, lInput, lTunerInput);
2887 if(FAILED(hr)){
2888 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr);
2889 break;
2895 for VIVO cards we should check if preview pin is available on video capture device.
2896 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
2897 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
2899 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
2900 (IUnknown *) priv->chains[0]->pCaptureFilter,
2901 PINDIR_OUTPUT,
2902 &PIN_CATEGORY_VIDEOPORT, NULL, FALSE,
2903 0, (IPin **) & pVPOutPin);
2904 if (SUCCEEDED(hr)) {
2905 hr = OLE_CALL_ARGS(priv->pGraph, Render, pVPOutPin);
2906 OLE_RELEASE_SAFE(pVPOutPin);
2908 if (FAILED(hr)) {
2909 mp_tmsg(MSGT_TV,MSGL_ERR, "tvi_dshow: Unable to terminate VideoPort pin with any filter in graph. Error:0x%x\n", (unsigned int)hr);
2910 break;
2914 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
2915 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
2916 LPVIDEOWINDOW pVideoWindow;
2917 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
2918 if (SUCCEEDED(hr))
2920 if(priv->tv_param->hidden_vp_renderer){
2921 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
2922 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
2923 }else
2925 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, pFilter);
2927 OLE_RELEASE_SAFE(pVideoWindow);
2929 OLE_RELEASE_SAFE(pFilter);
2931 OLE_RELEASE_SAFE(pEnum);
2932 if(priv->tv_param->system_clock)
2934 LPREFERENCECLOCK rc;
2935 IBaseFilter* pBF;
2936 hr = CoCreateInstance((GUID *) & CLSID_SystemClock, NULL,
2937 CLSCTX_INPROC_SERVER, &IID_IReferenceClock,
2938 (void *) &rc);
2940 OLE_QUERYINTERFACE(priv->pBuilder,IID_IBaseFilter,pBF);
2941 OLE_CALL_ARGS(pBF,SetSyncSource,rc);
2943 if(vbi_get_props(priv,&(priv->tsp))!=TVI_CONTROL_TRUE)
2944 break;
2945 result = 1;
2946 } while(0);
2948 if (!result){
2949 mp_tmsg(MSGT_TV,MSGL_ERR, "tvi_dshow: Directshow graph initialization failure.\n");
2950 uninit(priv);
2952 return result;
2956 * \brief chain uninitialization
2957 * \param chain chain data structure
2959 static void destroy_chain(chain_t *chain)
2961 int i;
2963 if(!chain)
2964 return;
2966 OLE_RELEASE_SAFE(chain->pStreamConfig);
2967 OLE_RELEASE_SAFE(chain->pCaptureFilter);
2968 OLE_RELEASE_SAFE(chain->pCSGCB);
2969 OLE_RELEASE_SAFE(chain->pCapturePin);
2970 OLE_RELEASE_SAFE(chain->pSGIn);
2971 OLE_RELEASE_SAFE(chain->pSG);
2972 OLE_RELEASE_SAFE(chain->pSGF);
2974 if (chain->pmt)
2975 DeleteMediaType(chain->pmt);
2977 if (chain->arpmt) {
2978 for (i = 0; chain->arpmt[i]; i++) {
2979 DeleteMediaType(chain->arpmt[i]);
2981 free(chain->arpmt);
2984 if (chain->arStreamCaps) {
2985 for (i = 0; chain->arStreamCaps[i]; i++) {
2986 free(chain->arStreamCaps[i]);
2988 free(chain->arStreamCaps);
2991 if (chain->rbuf) {
2992 destroy_ringbuffer(chain->rbuf);
2993 free(chain->rbuf);
2994 chain->rbuf = NULL;
2996 free(chain);
2999 * \brief driver uninitialization
3001 * \param priv driver's private data structure
3003 * \return always 1
3005 static int uninit(priv_t * priv)
3007 int i;
3008 if (!priv)
3009 return 1;
3010 //Debug
3011 if (priv->dwRegister) {
3012 RemoveFromRot(priv->dwRegister);
3014 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1);
3015 //stop audio grabber thread
3017 if (priv->state && priv->pMediaControl) {
3018 OLE_CALL(priv->pMediaControl, Stop);
3020 OLE_RELEASE_SAFE(priv->pMediaControl);
3021 priv->state = 0;
3023 if (priv->pGraph) {
3024 if (priv->chains[0]->pCaptureFilter)
3025 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->chains[0]->pCaptureFilter);
3026 if (priv->chains[1]->pCaptureFilter)
3027 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->chains[1]->pCaptureFilter);
3029 OLE_RELEASE_SAFE(priv->pCrossbar);
3030 OLE_RELEASE_SAFE(priv->pVideoProcAmp);
3031 OLE_RELEASE_SAFE(priv->pGraph);
3032 OLE_RELEASE_SAFE(priv->pBuilder);
3033 if(priv->freq_table){
3034 priv->freq_table_len=-1;
3035 free(priv->freq_table);
3036 priv->freq_table=NULL;
3039 for(i=0; i<3;i++)
3041 destroy_chain(priv->chains[i]);
3042 priv->chains[i] = NULL;
3044 CoUninitialize();
3045 return 1;
3049 * \brief driver pre-initialization
3051 * \param device string, containing device name in form "x[.y]", where x is video capture device
3052 * (default: 0, first available); y (if given) sets audio capture device
3054 * \return 1 if success,0 - otherwise
3056 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param)
3058 tvi_handle_t *h;
3059 priv_t *priv;
3060 int a;
3062 h = new_handle();
3063 if (!h)
3064 return NULL;
3066 priv = h->priv;
3068 memset(priv, 0, sizeof(priv_t));
3069 priv->direct_setfreq_call = 1; //first using direct call. if it fails, workaround will be enabled
3070 priv->direct_getfreq_call = 1; //first using direct call. if it fails, workaround will be enabled
3071 priv->adev_index = -1;
3072 priv->freq_table_len=-1;
3073 priv->tv_param=tv_param;
3075 if (tv_param->device) {
3076 if (sscanf(tv_param->device, "%d", &a) == 1) {
3077 priv->dev_index = a;
3078 } else {
3079 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Wrong device parameter: %s\n", tv_param->device);
3080 free_handle(h);
3081 return NULL;
3083 if (priv->dev_index < 0) {
3084 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Wrong device index: %d\n", a);
3085 free_handle(h);
3086 return NULL;
3089 if (tv_param->adevice) {
3090 if (sscanf(tv_param->adevice, "%d", &a) == 1) {
3091 priv->adev_index = a;
3092 } else {
3093 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Wrong adevice parameter: %s\n", tv_param->adevice);
3094 free_handle(h);
3095 return NULL;
3097 if (priv->dev_index < 0) {
3098 mp_tmsg(MSGT_TV, MSGL_ERR, "tvi_dshow: Wrong adevice index: %d\n", a);
3099 free_handle(h);
3100 return NULL;
3103 return h;
3107 * \brief driver's ioctl handler
3109 * \param priv driver's private data structure
3110 * \param cmd ioctl command
3111 * \param arg ioct command's parameter
3113 * \return TVI_CONTROL_TRUE if success
3114 * \return TVI_CONTROL_FALSE if failure
3115 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
3117 static int control(priv_t * priv, int cmd, void *arg)
3119 switch (cmd) {
3120 /* need rewrite */
3121 case TVI_CONTROL_VID_SET_FORMAT:
3123 int fcc, i,j;
3124 void* tmp,*tmp2;
3125 int result = TVI_CONTROL_TRUE;
3127 if (priv->state)
3128 return TVI_CONTROL_FALSE;
3129 fcc = *(int *) arg;
3131 if(!priv->chains[0]->arpmt)
3132 return TVI_CONTROL_FALSE;
3133 for (i = 0; priv->chains[0]->arpmt[i]; i++)
3134 if (check_video_format
3135 (priv->chains[0]->arpmt[i], fcc, priv->width, priv->height))
3136 break;
3137 if (!priv->chains[0]->arpmt[i])
3139 int fps = 0;
3140 VIDEOINFOHEADER* Vhdr = NULL;
3141 AM_MEDIA_TYPE *pmt;
3143 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: will try also use undeclared video format: %dx%d, %s\n",priv->width, priv->height, vo_format_name(fcc));
3145 if (priv->chains[0]->arpmt[0])
3146 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->arpmt[0]->pbFormat;
3148 if(Vhdr && Vhdr->bmiHeader.biSizeImage)
3149 fps = Vhdr->dwBitRate / (8 * Vhdr->bmiHeader.biSizeImage);
3151 pmt=create_video_format(fcc, priv->width, priv->height, fps);
3152 if(!pmt)
3154 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to create AM_MEDIA_TYPE structure for given format\n");
3155 return TVI_CONTROL_FALSE;
3157 priv->chains[0]->arpmt=realloc(priv->chains[0]->arpmt, (i+2)*sizeof(AM_MEDIA_TYPE*));
3158 priv->chains[0]->arpmt[i+1] = NULL;
3159 priv->chains[0]->arpmt[i] = pmt;
3161 priv->chains[0]->arStreamCaps=realloc(priv->chains[0]->arStreamCaps, (i+2)*sizeof(void*));
3162 priv->chains[0]->arpmt[i+1] = NULL;
3164 result = TVI_CONTROL_FALSE;
3168 tmp=priv->chains[0]->arpmt[i];
3169 tmp2=priv->chains[0]->arStreamCaps[i];
3170 for(j=i; j>0; j--)
3172 priv->chains[0]->arpmt[j] = priv->chains[0]->arpmt[j-1];
3173 priv->chains[0]->arStreamCaps[j] = priv->chains[0]->arStreamCaps[j-1];
3175 priv->chains[0]->arpmt[0] = tmp;
3176 priv->chains[0]->arStreamCaps[0] = tmp2;
3178 priv->chains[0]->nFormatUsed = 0;
3180 if (priv->chains[0]->pmt)
3181 DeleteMediaType(priv->chains[0]->pmt);
3182 priv->chains[0]->pmt =
3183 CreateMediaType(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed]);
3184 DisplayMediaType("VID_SET_FORMAT", priv->chains[0]->pmt);
3186 Setting width & height to preferred by driver values
3188 extract_video_format(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed],
3189 &(priv->fcc), &(priv->width),
3190 &(priv->height));
3191 return result;
3193 case TVI_CONTROL_VID_GET_FORMAT:
3195 if(!priv->chains[0]->pmt)
3196 return TVI_CONTROL_FALSE;
3198 Build video chain (for video format negotiation).
3199 If this was done before, routine will do nothing.
3201 build_video_chain(priv);
3202 DisplayMediaType("VID_GET_FORMAT", priv->chains[0]->pmt);
3203 if (priv->fcc) {
3204 *(int *) arg = priv->fcc;
3205 return TVI_CONTROL_TRUE;
3206 } else
3207 return TVI_CONTROL_FALSE;
3209 case TVI_CONTROL_VID_SET_WIDTH:
3211 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3212 VIDEOINFOHEADER *Vhdr;
3213 int width = *(int *) arg;
3214 if (priv->state)
3215 return TVI_CONTROL_FALSE;
3217 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3218 if (!pCaps)
3219 return TVI_CONTROL_FALSE;
3220 if (width < pCaps->MinOutputSize.cx
3221 || width > pCaps->MaxOutputSize.cx)
3222 return TVI_CONTROL_FALSE;
3224 if (width % pCaps->OutputGranularityX)
3225 return TVI_CONTROL_FALSE;
3227 if (!priv->chains[0]->pmt || !priv->chains[0]->pmt->pbFormat)
3228 return TVI_CONTROL_FALSE;
3229 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3230 Vhdr->bmiHeader.biWidth = width;
3231 priv->chains[0]->pmt->lSampleSize = Vhdr->bmiHeader.biSizeImage =
3232 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
3233 Vhdr->bmiHeader.biHeight) >> 3;
3235 priv->width = width;
3237 return TVI_CONTROL_TRUE;
3239 case TVI_CONTROL_VID_GET_WIDTH:
3241 if (priv->width) {
3242 *(int *) arg = priv->width;
3243 return TVI_CONTROL_TRUE;
3244 } else
3245 return TVI_CONTROL_FALSE;
3247 case TVI_CONTROL_VID_CHK_WIDTH:
3249 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3250 int width = *(int *) arg;
3251 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3252 if (!pCaps)
3253 return TVI_CONTROL_FALSE;
3254 if (width < pCaps->MinOutputSize.cx
3255 || width > pCaps->MaxOutputSize.cx)
3256 return TVI_CONTROL_FALSE;
3258 if (width % pCaps->OutputGranularityX)
3259 return TVI_CONTROL_FALSE;
3260 return TVI_CONTROL_TRUE;
3262 case TVI_CONTROL_VID_SET_HEIGHT:
3264 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3265 VIDEOINFOHEADER *Vhdr;
3266 int height = *(int *) arg;
3267 if (priv->state)
3268 return TVI_CONTROL_FALSE;
3270 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3271 if (!pCaps)
3272 return TVI_CONTROL_FALSE;
3273 if (height < pCaps->MinOutputSize.cy
3274 || height > pCaps->MaxOutputSize.cy)
3275 return TVI_CONTROL_FALSE;
3277 if (height % pCaps->OutputGranularityY)
3278 return TVI_CONTROL_FALSE;
3280 if (!priv->chains[0]->pmt || !priv->chains[0]->pmt->pbFormat)
3281 return TVI_CONTROL_FALSE;
3282 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3284 if (Vhdr->bmiHeader.biHeight < 0)
3285 Vhdr->bmiHeader.biHeight = -height;
3286 else
3287 Vhdr->bmiHeader.biHeight = height;
3288 priv->chains[0]->pmt->lSampleSize = Vhdr->bmiHeader.biSizeImage =
3289 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
3290 Vhdr->bmiHeader.biHeight) >> 3;
3292 priv->height = height;
3293 return TVI_CONTROL_TRUE;
3295 case TVI_CONTROL_VID_GET_HEIGHT:
3297 if (priv->height) {
3298 *(int *) arg = priv->height;
3299 return TVI_CONTROL_TRUE;
3300 } else
3301 return TVI_CONTROL_FALSE;
3303 case TVI_CONTROL_VID_CHK_HEIGHT:
3305 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3306 int height = *(int *) arg;
3307 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3308 if (!pCaps)
3309 return TVI_CONTROL_FALSE;
3310 if (height < pCaps->MinOutputSize.cy
3311 || height > pCaps->MaxOutputSize.cy)
3312 return TVI_CONTROL_FALSE;
3314 if (height % pCaps->OutputGranularityY)
3315 return TVI_CONTROL_FALSE;
3317 return TVI_CONTROL_TRUE;
3319 case TVI_CONTROL_IS_AUDIO:
3320 if (!priv->chains[1]->pmt)
3321 return TVI_CONTROL_FALSE;
3322 else
3323 return TVI_CONTROL_TRUE;
3324 case TVI_CONTROL_IS_VIDEO:
3325 return TVI_CONTROL_TRUE;
3326 case TVI_CONTROL_AUD_GET_FORMAT:
3328 *(int *) arg = AF_FORMAT_S16_LE;
3329 if (!priv->chains[1]->pmt)
3330 return TVI_CONTROL_FALSE;
3331 else
3332 return TVI_CONTROL_TRUE;
3334 case TVI_CONTROL_AUD_GET_CHANNELS:
3336 *(int *) arg = priv->channels;
3337 if (!priv->chains[1]->pmt)
3338 return TVI_CONTROL_FALSE;
3339 else
3340 return TVI_CONTROL_TRUE;
3342 case TVI_CONTROL_AUD_SET_SAMPLERATE:
3344 int i, samplerate;
3345 if (priv->state)
3346 return TVI_CONTROL_FALSE;
3347 if (!priv->chains[1]->arpmt[0])
3348 return TVI_CONTROL_FALSE;
3350 samplerate = *(int *) arg;
3352 for (i = 0; priv->chains[1]->arpmt[i]; i++)
3353 if (check_audio_format
3354 (priv->chains[1]->arpmt[i], samplerate, 16, priv->channels))
3355 break;
3356 if (!priv->chains[1]->arpmt[i]) {
3357 //request not found. failing back to first available
3358 mp_tmsg(MSGT_TV, MSGL_WARN, "tvi_dshow: Samplerate %d is not supported by device. Failing back to first available.\n", samplerate);
3359 i = 0;
3361 if (priv->chains[1]->pmt)
3362 DeleteMediaType(priv->chains[1]->pmt);
3363 priv->chains[1]->pmt = CreateMediaType(priv->chains[1]->arpmt[i]);
3364 extract_audio_format(priv->chains[1]->arpmt[i], &(priv->samplerate),
3365 NULL, &(priv->channels));
3366 return TVI_CONTROL_TRUE;
3368 case TVI_CONTROL_AUD_GET_SAMPLERATE:
3370 *(int *) arg = priv->samplerate;
3371 if (!priv->samplerate)
3372 return TVI_CONTROL_FALSE;
3373 if (!priv->chains[1]->pmt)
3374 return TVI_CONTROL_FALSE;
3375 else
3376 return TVI_CONTROL_TRUE;
3378 case TVI_CONTROL_AUD_GET_SAMPLESIZE:
3380 WAVEFORMATEX *pWF;
3381 if (!priv->chains[1]->pmt)
3382 return TVI_CONTROL_FALSE;
3383 if (!priv->chains[1]->pmt->pbFormat)
3384 return TVI_CONTROL_FALSE;
3385 pWF = (WAVEFORMATEX *) priv->chains[1]->pmt->pbFormat;
3386 *(int *) arg = pWF->wBitsPerSample / 8;
3387 return TVI_CONTROL_TRUE;
3389 case TVI_CONTROL_IS_TUNER:
3391 if (!priv->pTVTuner)
3392 return TVI_CONTROL_FALSE;
3394 return TVI_CONTROL_TRUE;
3396 case TVI_CONTROL_TUN_SET_NORM:
3398 IAMAnalogVideoDecoder *pVD;
3399 long lAnalogFormat;
3400 int i;
3401 HRESULT hr;
3403 i = *(int *) arg;
3404 i--;
3405 if (i < 0 || i >= tv_available_norms_count)
3406 return TVI_CONTROL_FALSE;
3407 lAnalogFormat = tv_norms[tv_available_norms[i]].index;
3409 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter,IID_IAMAnalogVideoDecoder, pVD);
3410 if (hr != S_OK)
3411 return TVI_CONTROL_FALSE;
3412 hr = OLE_CALL_ARGS(pVD, put_TVFormat, lAnalogFormat);
3413 OLE_RELEASE_SAFE(pVD);
3414 if (FAILED(hr))
3415 return TVI_CONTROL_FALSE;
3416 else
3417 return TVI_CONTROL_TRUE;
3419 case TVI_CONTROL_TUN_GET_NORM:
3421 long lAnalogFormat;
3422 int i;
3423 HRESULT hr;
3424 IAMAnalogVideoDecoder *pVD;
3426 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter,IID_IAMAnalogVideoDecoder, pVD);
3427 if (hr == S_OK) {
3428 hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat);
3429 OLE_RELEASE_SAFE(pVD);
3432 if (FAILED(hr)) { //trying another method
3433 if (!priv->pTVTuner)
3434 return TVI_CONTROL_FALSE;
3435 hr=OLE_CALL_ARGS(priv->pTVTuner, get_TVFormat, &lAnalogFormat);
3436 if (FAILED(hr))
3437 return TVI_CONTROL_FALSE;
3439 for (i = 0; i < tv_available_norms_count; i++) {
3440 if (tv_norms[tv_available_norms[i]].index == lAnalogFormat) {
3441 *(int *) arg = i + 1;
3442 return TVI_CONTROL_TRUE;
3445 return TVI_CONTROL_FALSE;
3447 case TVI_CONTROL_SPC_GET_NORMID:
3449 int i;
3450 if (!priv->pTVTuner)
3451 return TVI_CONTROL_FALSE;
3452 for (i = 0; i < tv_available_norms_count; i++) {
3453 if (!strcasecmp
3454 (tv_norms[tv_available_norms[i]].name, (char *) arg)) {
3455 *(int *) arg = i + 1;
3456 return TVI_CONTROL_TRUE;
3459 return TVI_CONTROL_FALSE;
3461 case TVI_CONTROL_SPC_SET_INPUT:
3463 return set_crossbar_input(priv, *(int *) arg);
3465 case TVI_CONTROL_TUN_GET_FREQ:
3467 unsigned long lFreq;
3468 int ret;
3469 if (!priv->pTVTuner)
3470 return TVI_CONTROL_FALSE;
3472 ret = get_frequency(priv, &lFreq);
3473 lFreq = lFreq / (1000000/16); //convert from Hz to 1/16 MHz units
3475 *(unsigned long *) arg = lFreq;
3476 return ret;
3478 case TVI_CONTROL_TUN_SET_FREQ:
3480 unsigned long nFreq = *(unsigned long *) arg;
3481 if (!priv->pTVTuner)
3482 return TVI_CONTROL_FALSE;
3483 //convert to Hz
3484 nFreq = (1000000/16) * nFreq; //convert from 1/16 MHz units to Hz
3485 return set_frequency(priv, nFreq);
3487 case TVI_CONTROL_VID_SET_HUE:
3488 return set_control(priv, VideoProcAmp_Hue, *(int *) arg);
3489 case TVI_CONTROL_VID_GET_HUE:
3490 return get_control(priv, VideoProcAmp_Hue, (int *) arg);
3491 case TVI_CONTROL_VID_SET_CONTRAST:
3492 return set_control(priv, VideoProcAmp_Contrast, *(int *) arg);
3493 case TVI_CONTROL_VID_GET_CONTRAST:
3494 return get_control(priv, VideoProcAmp_Contrast, (int *) arg);
3495 case TVI_CONTROL_VID_SET_SATURATION:
3496 return set_control(priv, VideoProcAmp_Saturation, *(int *) arg);
3497 case TVI_CONTROL_VID_GET_SATURATION:
3498 return get_control(priv, VideoProcAmp_Saturation, (int *) arg);
3499 case TVI_CONTROL_VID_SET_BRIGHTNESS:
3500 return set_control(priv, VideoProcAmp_Brightness, *(int *) arg);
3501 case TVI_CONTROL_VID_GET_BRIGHTNESS:
3502 return get_control(priv, VideoProcAmp_Brightness, (int *) arg);
3504 case TVI_CONTROL_VID_GET_FPS:
3506 VIDEOINFOHEADER *Vhdr;
3507 if (!priv->chains[0]->pmt)
3508 return TVI_CONTROL_FALSE;
3509 if (!priv->chains[0]->pmt->pbFormat)
3510 return TVI_CONTROL_FALSE;
3511 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3512 *(float *) arg =
3513 (1.0 * Vhdr->dwBitRate) / (Vhdr->bmiHeader.biSizeImage * 8);
3514 return TVI_CONTROL_TRUE;
3516 case TVI_CONTROL_IMMEDIATE:
3517 priv->immediate_mode = 1;
3518 return TVI_CONTROL_TRUE;
3519 case TVI_CONTROL_VBI_INIT:
3521 void* ptr;
3522 ptr=&(priv->tsp);
3523 if(teletext_control(NULL,TV_VBI_CONTROL_START,&ptr)==VBI_CONTROL_TRUE)
3524 priv->priv_vbi=ptr;
3525 else
3526 priv->priv_vbi=NULL;
3527 return TVI_CONTROL_TRUE;
3529 case TVI_CONTROL_GET_VBI_PTR:
3530 *(void **)arg=priv->priv_vbi;
3531 return TVI_CONTROL_TRUE;
3533 return TVI_CONTROL_UNKNOWN;