comparison stream/tvi_dshow.c @ 24744:d81eef9beb1b

DirectShow based tv:// driver for win32 Teletext is also supported (but 625 system parameters are hardcoded). pthreads is required for teletext. Code is still experimental.
author voroshil
date Sat, 13 Oct 2007 17:14:39 +0000
parents
children b64074f0f124
comparison
equal deleted inserted replaced
24743:acb856c03bd8 24744:d81eef9beb1b
1 /*
2 * TV support under Win32
3 *
4 * (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>.
5 *
6 * Based on tvi_dummy.c with help of tv.c, tvi_v4l2.c code .
7 *
8 * -------------------------------------------------------------------------------
9 *
10 * This program 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.
14 *
15 * This program 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.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 *
25 * -------------------------------------------------------------------------------
26 *
27 *
28 * WARNING: This is alpha code!
29 *
30 * Abilities:
31 * * Watching TV under Win32 using WDM Capture driver and DirectShow
32 * * Grabbing synchronized audio/video with mencoder (synchronization is beeing done by DirectShow)
33 * * If device driver provides IAMStreamConfig interface, user can choose width/height with "-tv height=<h>:width=<w>"
34 * * Adjusting BRIGHTNESS,HUE,SATURATION,CONTRAST if supported by device
35 * * Selecting Tuner,S-Video,... as media source
36 * * User can select used video capture device, passing -tv device=<dev#>
37 * * User can select used audio input, passing -tv audioid=<input#>
38 *
39 * options which will not be implemented (probably sometime in future, if possible):
40 * * alsa
41 * * mjpeg
42 * * decimation=<1|2|4>
43 * * quality=<0\-100>
44 * * forceaudio
45 * * forcechan=<1\-2>
46 * * [volume|bass|treble|balance]
47 *
48 * Works with:
49 * - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
50 * Partially works with:
51 * - ATI 9200 VIVO based card
52 * - ATI AIW 7500
53 * - nVidia Ti-4400
54 *
55 * Known bugs:
56 * * stream goes with 24.93 FPS (NTSC), while reporting 25 FPS (PAL) ?!
57 * * direct set frequency call does not work ('Insufficient Buffer' error)
58 * * audio stream goes with about 1 sample/sec rate when capturing sound from audio card
59 *
60 * TODO:
61 * * check audio with small buffer on vivo !!!
62 * * norm for IAMVideoDecoder and for IAMTVtuner - differs !!
63 * * check how to change TVFormat on VIVO card without tuner
64 * * Flip image upside-down for RGB formats.
65 * *
66 * * remove debug sleep()
67 * * Add some notes to methods' parameters
68 * * refactor console messages
69 * * check using header files and keep only needed
70 * * add additional comments to methods' bodies
71 *
72 */
73
74
75 /// \ingroup tvi_dshow
76
77 #include "config.h"
78
79 #include <stdio.h>
80 #include "libmpcodecs/img_format.h"
81 #include "libaf/af_format.h"
82 #include "help_mp.h"
83 #include "osdep/timer.h"
84
85
86 #include "tv.h"
87 #include "mp_msg.h"
88 #include "frequencies.h"
89
90
91 #include "tvi_dshow.h"
92
93 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param);
94
95 /*
96 *---------------------------------------------------------------------------------------
97 *
98 * Data structures
99 *
100 *---------------------------------------------------------------------------------------
101 */
102 /**
103 information about this file
104 */
105 tvi_info_t tvi_info_dshow = {
106 tvi_init_dshow,
107 "DirectShow TV",
108 "dshow",
109 "Vladimir Voroshilov",
110 "Very experimental!! Use with caution"
111 };
112
113
114 /**
115 ringbuffer related info
116 */
117 typedef struct {
118 CRITICAL_SECTION *pMutex; ///< pointer to critical section (mutex)
119 char **ringbuffer; ///< ringbuffer array
120 double*dpts; ///< samples' timestamps
121
122 int buffersize; ///< size of buffer in blocks
123 int blocksize; ///< size of individual block
124 int head; ///< index of first valid sample
125 int tail; ///< index of last valid sample
126 int count; ///< count of valid samples in ringbuffer
127 double tStart; ///< pts of first sample (first sample should have pts 0)
128 } grabber_ringbuffer_t;
129
130 /**
131 CSampleGrabberCD definition
132 */
133 typedef struct CSampleGrabberCB {
134 ISampleGrabberCBVtbl *lpVtbl;
135 int refcount;
136 GUID interfaces[2];
137 grabber_ringbuffer_t *pbuf;
138 } CSampleGrabberCB;
139
140 typedef struct {
141 int dev_index; ///< capture device index in device list (defaul: 0, first available device)
142 int adev_index; ///< audio capture device index in device list (default: -1, not used)
143 int immediate_mode; ///< immediate mode (no sound capture)
144 int state; ///< state: 1-filter graph running, 0-filter graph stopped
145 int direct_setfreq_call; ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency
146 int direct_getfreq_call; ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency
147
148 int fcc; ///< used video format code (FourCC)
149 int width; ///< picture width (default: auto)
150 int height; ///< picture height (default: auto)
151
152 int channels; ///< number of audio channels (default: auto)
153 int samplerate; ///< audio samplerate (default: auto)
154
155 long *freq_table; ///< frequency table (in Hz)
156 int freq_table_len; ///< length of freq table
157 int first_channel; ///< channel number of first entry in freq table
158 int input; ///< used input
159
160 // video related stuff
161 int nVideoFormatUsed; ///< index of used video format
162 AM_MEDIA_TYPE **arpmtVideo; ///< available video formats
163 VIDEO_STREAM_CONFIG_CAPS **arVideoCaps; ///< capabilities of output video
164 AM_MEDIA_TYPE *pmtVideo; ///< video stream properties
165 grabber_ringbuffer_t *v_buf;
166 IBaseFilter *pVideoFilter; ///< interface for capture device
167 IAMStreamConfig *pVideoStreamConfig; ///< for configuring video stream
168
169 // audio related stuff
170 int nAudioFormatUsed; ///< index of used audio format
171 AM_MEDIA_TYPE **arpmtAudio; ///< available audio formats
172 AUDIO_STREAM_CONFIG_CAPS **arAudioCaps; ///< capabilities of output audio
173 AM_MEDIA_TYPE *pmtAudio; ///< audio stream properties.
174 grabber_ringbuffer_t *a_buf;
175 IBaseFilter *pAudioFilter; ///< interface for audio capture device (if adevice passed)
176 IAMStreamConfig *pAudioStreamConfig; ///< for configuring audio stream
177
178 AM_MEDIA_TYPE *pmtVBI; ///< available audio formats
179 grabber_ringbuffer_t *vbi_buf;
180
181 IAMTVTuner *pTVTuner; ///< interface for tuner device
182 IGraphBuilder *pGraph; ///< filter graph
183 ICaptureGraphBuilder2 *pBuilder; ///< graph builder
184 IMediaControl *pMediaControl; ///< interface for controlling graph (start, stop,...)
185 IAMVideoProcAmp *pVideoProcAmp; ///< for adjusting hue,saturation,etc
186 IAMCrossbar *pCrossbar; ///< for selecting input (Tuner,Composite,S-Video,...)
187 DWORD dwRegister; ///< allow graphedit to connect to our graph
188 CSampleGrabberCB* pCSGCB; ///< callback object
189 void *priv_vbi; ///< private VBI data structure
190 tt_stream_props tsp; ///< data for VBI initialization
191
192 tv_param_t* tv_param; ///< TV parameters
193 } priv_t;
194
195 #include "tvi_def.h"
196
197 /**
198 country table entry structure (for loading freq table stored in kstvtuner.ax
199
200 \note
201 structure have to be 2-byte aligned and have 10-byte length!!
202 */
203 typedef struct __attribute__((__packed__)) {
204 WORD CountryCode; ///< Country code
205 WORD CableFreqTable; ///< index of resource with frequencies for cable channels
206 WORD BroadcastFreqTable; ///< index of resource with frequencies for broadcast channels
207 DWORD VideoStandard; ///< used video standard
208 } TRCCountryList;
209 /**
210 information about image formats
211 */
212 typedef struct {
213 uint32_t fmt; ///< FourCC
214 const GUID *subtype; ///< DirectShow's subtype
215 int nBits; ///< number of bits
216 int nCompression; ///< complression
217 int tail; ///< number of additional bytes followed VIDEOINFOHEADER structure
218 } img_fmt;
219
220 /*
221 *---------------------------------------------------------------------------------------
222 *
223 * Methods forward declaration
224 *
225 *---------------------------------------------------------------------------------------
226 */
227 static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
228 int blocksize);
229 static HRESULT show_filter_info(IBaseFilter * pFilter);
230 #if 0
231 //defined in current MinGW release
232 HRESULT STDCALL GetRunningObjectTable(DWORD, IRunningObjectTable **);
233 HRESULT STDCALL CreateItemMoniker(LPCOLESTR, LPCOLESTR, IMoniker **);
234 #endif
235 static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
236 pbuf);
237 static int set_crossbar_input(priv_t * priv, int input);
238 static int subtype2imgfmt(const GUID * subtype);
239
240 /*
241 *---------------------------------------------------------------------------------------
242 *
243 * Global constants and variables
244 *
245 *---------------------------------------------------------------------------------------
246 */
247 /**
248 lookup tables for physical connector types
249 */
250 static const struct {
251 long type;
252 char *name;
253 } tv_physcon_types[]={
254 {PhysConn_Video_Tuner, "Tuner" },
255 {PhysConn_Video_Composite, "Composite" },
256 {PhysConn_Video_SVideo, "S-Video" },
257 {PhysConn_Video_RGB, "RGB" },
258 {PhysConn_Video_YRYBY, "YRYBY" },
259 {PhysConn_Video_SerialDigital, "SerialDigital" },
260 {PhysConn_Video_ParallelDigital, "ParallelDigital"},
261 {PhysConn_Video_VideoDecoder, "VideoDecoder" },
262 {PhysConn_Video_VideoEncoder, "VideoEncoder" },
263 {PhysConn_Video_SCART, "SCART" },
264 {PhysConn_Video_Black, "Blaack" },
265 {PhysConn_Audio_Tuner, "Tuner" },
266 {PhysConn_Audio_Line, "Line" },
267 {PhysConn_Audio_Mic, "Mic" },
268 {PhysConn_Audio_AESDigital, "AESDiital" },
269 {PhysConn_Audio_SPDIFDigital, "SPDIFDigital" },
270 {PhysConn_Audio_AudioDecoder, "AudioDecoder" },
271 {PhysConn_Audio_SCSI, "SCSI" },
272 {PhysConn_Video_SCSI, "SCSI" },
273 {PhysConn_Audio_AUX, "AUX" },
274 {PhysConn_Video_AUX, "AUX" },
275 {PhysConn_Audio_1394, "1394" },
276 {PhysConn_Video_1394, "1394" },
277 {PhysConn_Audio_USB, "USB" },
278 {PhysConn_Video_USB, "USB" },
279 {-1, NULL }
280 };
281
282 static const struct {
283 char *chanlist_name;
284 int country_code;
285 } tv_chanlist2country[]={
286 {"us-bcast", 1},
287 {"russia", 7},
288 {"argentina", 54},
289 {"japan-bcast", 81},
290 {"china-bcast", 86},
291 {"southafrica", 27},
292 {"australia", 61},
293 {"ireland", 353},
294 {"france", 33},
295 {"italy", 39},
296 {"newzealand", 64},
297 //directshow table uses eastern europe freq table for russia
298 {"europe-east", 7},
299 //directshow table uses western europe freq table for germany
300 {"europe-west", 49},
301 /* cable channels */
302 {"us-cable", 1},
303 {"us-cable-hrc", 1},
304 {"japan-cable", 81},
305 //default is USA
306 {NULL, 1}
307 };
308
309 /**
310 array, contains information about various supported (i hope) image formats
311 */
312 static const img_fmt img_fmt_list[] = {
313 {IMGFMT_YUY2, &MEDIASUBTYPE_YUY2, 0, IMGFMT_YUY2, 0},
314 {IMGFMT_YV12, &MEDIASUBTYPE_YV12, 0, IMGFMT_YV12, 0},
315 {IMGFMT_IYUV, &MEDIASUBTYPE_IYUV, 0, IMGFMT_IYUV, 0},
316 {IMGFMT_I420, &MEDIASUBTYPE_I420, 0, IMGFMT_I420, 0},
317 {IMGFMT_UYVY, &MEDIASUBTYPE_UYVY, 0, IMGFMT_UYVY, 0},
318 {IMGFMT_YVYU, &MEDIASUBTYPE_YVYU, 0, IMGFMT_YVYU, 0},
319 {IMGFMT_YVU9, &MEDIASUBTYPE_YVU9, 0, IMGFMT_YVU9, 0},
320 {IMGFMT_BGR32, &MEDIASUBTYPE_RGB32, 32, 0, 0},
321 {IMGFMT_BGR24, &MEDIASUBTYPE_RGB24, 24, 0, 0},
322 {IMGFMT_BGR16, &MEDIASUBTYPE_RGB565, 16, 3, 12},
323 {IMGFMT_BGR15, &MEDIASUBTYPE_RGB555, 16, 3, 12},
324 {0, &GUID_NULL, 0, 0, 0}
325 };
326
327 #define TV_NORMS_COUNT 19
328 static const struct {
329 long index;
330 char *name;
331 } tv_norms[TV_NORMS_COUNT] = {
332 {
333 AnalogVideo_NTSC_M, "ntsc-m"}, {
334 AnalogVideo_NTSC_M_J, "ntsc-mj"}, {
335 AnalogVideo_NTSC_433, "ntsc-433"}, {
336 AnalogVideo_PAL_B, "pal-b"}, {
337 AnalogVideo_PAL_D, "pal-d"}, {
338 AnalogVideo_PAL_G, "pal-g"}, {
339 AnalogVideo_PAL_H, "pal-h"}, {
340 AnalogVideo_PAL_I, "pal-i"}, {
341 AnalogVideo_PAL_M, "pal-m"}, {
342 AnalogVideo_PAL_N, "pal-n"}, {
343 AnalogVideo_PAL_60, "pal-60"}, {
344 AnalogVideo_SECAM_B, "secam-b"}, {
345 AnalogVideo_SECAM_D, "secam-d"}, {
346 AnalogVideo_SECAM_G, "secam-g"}, {
347 AnalogVideo_SECAM_H, "secam-h"}, {
348 AnalogVideo_SECAM_K, "secam-k"}, {
349 AnalogVideo_SECAM_K1, "secam-k1"}, {
350 AnalogVideo_SECAM_L, "secam-l"}, {
351 AnalogVideo_SECAM_L1, "secam-l1"}
352 };
353 static long tv_available_norms[TV_NORMS_COUNT];
354 static int tv_available_norms_count = 0;
355
356
357 static long *tv_available_inputs;
358 static int tv_available_inputs_count = 0;
359
360 /*
361 *---------------------------------------------------------------------------------------
362 *
363 * Various GUID definitions
364 *
365 *---------------------------------------------------------------------------------------
366 */
367 /// CLSID definitions (used for CoCreateInstance call)
368 DEFINE_GUID(CLSID_SampleGrabber, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B,
369 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
370 DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B,
371 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
372 DEFINE_GUID(CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B,
373 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
374 DEFINE_GUID(CLSID_CaptureGraphBuilder2, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3,
375 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
376 DEFINE_GUID(CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, 0x11d0,
377 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
378 DEFINE_GUID(CLSID_AudioInputDeviceCategory, 0x33d9a762, 0x90c8, 0x11d0,
379 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
380 DEFINE_GUID(CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53,
381 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
382 DEFINE_GUID(CLSID_SystemClock, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53,
383 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
384 #ifdef NOT_USED
385 DEFINE_GUID(CLSID_CaptureGraphBuilder, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3,
386 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
387 DEFINE_GUID(CLSID_VideoPortManager, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a,
388 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2);
389 DEFINE_GUID(IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20,
390 0xaf, 0x0b, 0xa7, 0x70);
391 DEFINE_GUID(IID_ICaptureGraphBuilder, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3,
392 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5);
393 DEFINE_GUID(IID_IFilterGraph, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
394 0x20, 0xaf, 0x0b, 0xa7, 0x70);
395 DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
396 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
397 #endif
398
399 /// IID definitions (used for QueryInterface call)
400 DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a,
401 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
402 DEFINE_GUID(IID_IAMBufferNegotiation, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0,
403 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
404 DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa,
405 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
406 DEFINE_GUID(IID_ISampleGrabber, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD,
407 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F);
408 DEFINE_GUID(IID_ISampleGrabberCB, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0,
409 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85);
410 DEFINE_GUID(IID_ICaptureGraphBuilder2, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab,
411 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d);
412 DEFINE_GUID(IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b,
413 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
414 DEFINE_GUID(IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a,
415 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
416 DEFINE_GUID(IID_IAMVideoProcAmp, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C,
417 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
418 DEFINE_GUID(IID_IVideoWindow, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
419 0x20, 0xaf, 0x0b, 0xa7, 0x70);
420 DEFINE_GUID(IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a,
421 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
422 DEFINE_GUID(IID_IAMTVTuner, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00,
423 0xAA, 0x00, 0xBD, 0x83, 0x39);
424 DEFINE_GUID(IID_IAMCrossbar, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00,
425 0xa0, 0xc9, 0x11, 0x89, 0x56);
426 DEFINE_GUID(IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c,
427 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56);
428 DEFINE_GUID(IID_IAMAudioInputMixer, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0,
429 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
430 DEFINE_GUID(IID_IAMTVAudio, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00,
431 0xA0, 0xC9, 0x56, 0x02, 0x66);
432 DEFINE_GUID(IID_IAMAnalogVideoDecoder, 0xC6E13350, 0x30AC, 0x11d0, 0xA1,
433 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
434 DEFINE_GUID(IID_IPropertyBag, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00,
435 0xaa, 0x00, 0x4b, 0xb8, 0x51);
436 DEFINE_GUID(PIN_CATEGORY_CAPTURE, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f,
437 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
438 DEFINE_GUID(PIN_CATEGORY_VIDEOPORT, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f,
439 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
440 DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
441 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
442 DEFINE_GUID(PIN_CATEGORY_VBI, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f,
443 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
444 DEFINE_GUID(PROPSETID_TUNER, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00,
445 0xa0, 0xc9, 0x11, 0x89, 0x56);
446 DEFINE_GUID(MEDIATYPE_VBI, 0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00,
447 0x00, 0xc0, 0xcc, 0x16, 0xba);
448
449 #define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1)
450 #define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
451
452 #define DEVICE_NAME_MAX_LEN 2000
453
454 /*---------------------------------------------------------------------------------------
455 * Methods, called only from this file
456 *---------------------------------------------------------------------------------------*/
457
458 void set_buffer_preference(int nDiv,WAVEFORMATEX* pWF,IPin* pOutPin,IPin* pInPin){
459 ALLOCATOR_PROPERTIES prop;
460 IAMBufferNegotiation* pBN;
461 HRESULT hr;
462
463 prop.cbAlign = -1;
464 prop.cbBuffer = pWF->nAvgBytesPerSec/nDiv;
465 if (!prop.cbBuffer)
466 prop.cbBuffer = 1;
467 prop.cbBuffer += pWF->nBlockAlign - 1;
468 prop.cbBuffer -= prop.cbBuffer % pWF->nBlockAlign;
469 prop.cbPrefix = -1;
470 prop.cBuffers = -1;
471
472 hr=OLE_QUERYINTERFACE(pOutPin,IID_IAMBufferNegotiation,pBN);
473 if(FAILED(hr))
474 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr);
475 else{
476 hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop);
477 if(FAILED(hr))
478 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr);
479 OLE_RELEASE_SAFE(pBN);
480 }
481 hr=OLE_QUERYINTERFACE(pInPin,IID_IAMBufferNegotiation,pBN);
482 if(FAILED(hr))
483 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr);
484 else{
485 hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop);
486 if(FAILED(hr))
487 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr);
488 OLE_RELEASE_SAFE(pBN);
489 }
490 }
491 /*
492 *---------------------------------------------------------------------------------------
493 *
494 * CSampleGrabberCD class. Used for receiving samples from DirectShow.
495 *
496 *---------------------------------------------------------------------------------------
497 */
498 /// CSampleGrabberCD destructor
499 static void CSampleGrabberCB_Destroy(CSampleGrabberCB * This)
500 {
501 free(This->lpVtbl);
502 free(This);
503 }
504
505 /// CSampleGrabberCD IUnknown interface methods implementation
506 static long STDCALL CSampleGrabberCB_QueryInterface(ISampleGrabberCB *
507 This,
508 const GUID * riid,
509 void **ppvObject)
510 {
511 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
512 GUID *r;
513 unsigned int i = 0;
514 Debug printf("CSampleGrabberCB_QueryInterface(%p) called\n", This);
515 if (!ppvObject)
516 return E_POINTER;
517 for (r = me->interfaces;
518 i < sizeof(me->interfaces) / sizeof(me->interfaces[0]); r++, i++)
519 if (!memcmp(r, riid, sizeof(*r))) {
520 OLE_CALL(This, AddRef);
521 *ppvObject = This;
522 return 0;
523 }
524 Debug printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid);
525 return E_NOINTERFACE;
526 }
527
528 static long STDCALL CSampleGrabberCB_AddRef(ISampleGrabberCB * This)
529 {
530 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
531 Debug printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This,
532 me->refcount);
533 return ++(me->refcount);
534 }
535
536 static long STDCALL CSampleGrabberCB_Release(ISampleGrabberCB * This)
537 {
538 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
539 Debug printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n",
540 This, me->refcount - 1);
541 if (--(me->refcount) == 0)
542 CSampleGrabberCB_Destroy(me);
543 return 0;
544 }
545
546
547 HRESULT STDCALL CSampleGrabberCB_BufferCB(ISampleGrabberCB * This,
548 double SampleTime,
549 BYTE * pBuffer, long lBufferLen)
550 {
551 CSampleGrabberCB *this = (CSampleGrabberCB *) This;
552 grabber_ringbuffer_t *rb = this->pbuf;
553
554 if (!lBufferLen)
555 return E_FAIL;
556
557 if (!rb->ringbuffer) {
558 rb->buffersize /= lBufferLen;
559 if (init_ringbuffer(rb, rb->buffersize, lBufferLen) != S_OK)
560 return E_FAIL;
561 }
562 mp_msg(MSGT_TV, MSGL_DBG4,
563 "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This, lBufferLen, SampleTime);
564 EnterCriticalSection(rb->pMutex);
565 if (rb->count >= rb->buffersize) {
566 rb->head = (rb->head + 1) % rb->buffersize;
567 rb->count--;
568 }
569
570 memcpy(rb->ringbuffer[rb->tail], pBuffer,
571 lBufferLen < rb->blocksize ? lBufferLen : rb->blocksize);
572 rb->dpts[rb->tail] = SampleTime;
573 rb->tail = (rb->tail + 1) % rb->buffersize;
574 rb->count++;
575 LeaveCriticalSection(rb->pMutex);
576
577 return S_OK;
578 }
579
580 /// wrapper. directshow does the same when BufferCB callback is requested
581 HRESULT STDCALL CSampleGrabberCB_SampleCB(ISampleGrabberCB * This,
582 double SampleTime,
583 LPMEDIASAMPLE pSample)
584 {
585 char* buf;
586 long len;
587 long long tStart,tEnd;
588 HRESULT hr;
589 grabber_ringbuffer_t *rb = ((CSampleGrabberCB*)This)->pbuf;
590
591 len=OLE_CALL(pSample,GetSize);
592 tStart=tEnd=0;
593 hr=OLE_CALL_ARGS(pSample,GetTime,&tStart,&tEnd);
594 if(FAILED(hr)){
595 return hr;
596 }
597 mp_msg(MSGT_TV, MSGL_DBG4,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This,rb->count,rb->buffersize,1e-7*tStart);
598 hr=OLE_CALL_ARGS(pSample,GetPointer,(void*)&buf);
599 if(FAILED(hr)){
600 return hr;
601 }
602 hr=CSampleGrabberCB_BufferCB(This,1e-7*tStart,buf,len);
603 return hr;
604
605 }
606
607 /// main grabbing routine
608 static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
609 pbuf)
610 {
611 CSampleGrabberCB *This = malloc(sizeof(CSampleGrabberCB));
612 if (!This)
613 return NULL;
614
615 This->lpVtbl = malloc(sizeof(ISampleGrabberVtbl));
616 if (!This->lpVtbl) {
617 CSampleGrabberCB_Destroy(This);
618 return NULL;
619 }
620 This->refcount = 1;
621 This->lpVtbl->QueryInterface = CSampleGrabberCB_QueryInterface;
622 This->lpVtbl->AddRef = CSampleGrabberCB_AddRef;
623 This->lpVtbl->Release = CSampleGrabberCB_Release;
624 This->lpVtbl->SampleCB = CSampleGrabberCB_SampleCB;
625 This->lpVtbl->BufferCB = CSampleGrabberCB_BufferCB;
626
627 This->interfaces[0] = IID_IUnknown;
628 This->interfaces[1] = IID_ISampleGrabberCB;
629
630 This->pbuf = pbuf;
631
632 return This;
633 }
634
635 /*
636 *---------------------------------------------------------------------------------------
637 *
638 * ROT related methods (register, unregister)
639 *
640 *---------------------------------------------------------------------------------------
641 */
642 /**
643 Registering graph in ROT. User will be able to connect to graph from GraphEdit.
644 */
645 static HRESULT AddToRot(IUnknown * pUnkGraph, DWORD * pdwRegister)
646 {
647 IMoniker *pMoniker;
648 IRunningObjectTable *pROT;
649 WCHAR wsz[256];
650 HRESULT hr;
651
652 if (FAILED(GetRunningObjectTable(0, &pROT))) {
653 return E_FAIL;
654 }
655 wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR) pUnkGraph,
656 GetCurrentProcessId());
657 hr = CreateItemMoniker(L"!", wsz, &pMoniker);
658 if (SUCCEEDED(hr)) {
659 hr = OLE_CALL_ARGS(pROT, Register, ROTFLAGS_REGISTRATIONKEEPSALIVE,
660 pUnkGraph, pMoniker, pdwRegister);
661 OLE_RELEASE_SAFE(pMoniker);
662 }
663 OLE_RELEASE_SAFE(pROT);
664 return hr;
665 }
666
667 /// Unregistering graph in ROT
668 static void RemoveFromRot(DWORD dwRegister)
669 {
670 IRunningObjectTable *pROT;
671 if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
672 OLE_CALL_ARGS(pROT, Revoke, dwRegister);
673 OLE_RELEASE_SAFE(pROT);
674 }
675 }
676
677 /*
678 *---------------------------------------------------------------------------------------
679 *
680 * ringbuffer related methods (init, destroy)
681 *
682 *---------------------------------------------------------------------------------------
683 */
684 /**
685 * \brief ringbuffer destroying routine
686 *
687 * \param rb pointer to empty (just allocated) ringbuffer structure
688 *
689 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
690 */
691 static void destroy_ringbuffer(grabber_ringbuffer_t * rb)
692 {
693 int i;
694
695 if (!rb)
696 return;
697
698 if (rb->ringbuffer) {
699 for (i = 0; i < rb->buffersize; i++)
700 if (rb->ringbuffer[i])
701 free(rb->ringbuffer[i]);
702 free(rb->ringbuffer);
703 rb->ringbuffer = NULL;
704 }
705 if (rb->dpts) {
706 free(rb->dpts);
707 rb->dpts = NULL;
708 }
709 if (rb->pMutex) {
710 DeleteCriticalSection(rb->pMutex);
711 free(rb->pMutex);
712 rb->pMutex = NULL;
713 }
714
715 rb->blocksize = 0;
716 rb->buffersize = 0;
717 rb->head = 0;
718 rb->tail = 0;
719 rb->count = 0;
720 }
721
722 /**
723 * \brief ringbuffer initialization
724 *
725 * \param rb pointer to empty (just allocated) ringbuffer structure
726 * \param buffersize size of buffer in blocks
727 * \param blocksize size of buffer's block
728 *
729 * \return S_OK if success
730 * \return E_OUTOFMEMORY not enough memory
731 *
732 * \note routine does not allocates memory for grabber_rinbuffer_s structure
733 */
734 static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
735 int blocksize)
736 {
737 int i;
738
739 if (!rb)
740 return E_OUTOFMEMORY;
741
742 rb->buffersize = buffersize < 2 ? 2 : buffersize;
743 rb->blocksize = blocksize;
744
745 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n",
746 rb->buffersize, rb->blocksize);
747
748 rb->ringbuffer = (char **) malloc(rb->buffersize * sizeof(char *));
749 if (!rb)
750 return E_POINTER;
751 memset(rb->ringbuffer, 0, rb->buffersize * sizeof(char *));
752
753 for (i = 0; i < rb->buffersize; i++) {
754 rb->ringbuffer[i] = (char *) malloc(rb->blocksize * sizeof(char));
755 if (!rb->ringbuffer[i]) {
756 destroy_ringbuffer(rb);
757 return E_OUTOFMEMORY;
758 }
759 }
760 rb->dpts = (double*) malloc(rb->buffersize * sizeof(double));
761 if (!rb->dpts) {
762 destroy_ringbuffer(rb);
763 return E_OUTOFMEMORY;
764 }
765 rb->head = 0;
766 rb->tail = 0;
767 rb->count = 0;
768 rb->tStart = -1;
769 rb->pMutex = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION));
770 if (!rb->pMutex) {
771 destroy_ringbuffer(rb);
772 return E_OUTOFMEMORY;
773 }
774 InitializeCriticalSection(rb->pMutex);
775 return S_OK;
776 }
777
778 /*
779 *---------------------------------------------------------------------------------------
780 *
781 * Tuner related methods (frequency, capabilities, etc
782 *
783 *---------------------------------------------------------------------------------------
784 */
785 /**
786 * \brief returns string with name for givend PsysCon_* constant
787 *
788 * \param lPhysicalType constant from PhysicalConnectorType enumeration
789 *
790 * \return pointer to string with apropriate name
791 *
792 * \note
793 * Caller should not free returned pointer
794 */
795 static char *physcon2str(const long lPhysicalType)
796 {
797 int i;
798 for(i=0; tv_physcon_types[i].name; i++)
799 if(tv_physcon_types[i].type==lPhysicalType)
800 return tv_physcon_types[i].name;
801 return "Unknown";
802 };
803
804 /**
805 * \brief converts MPlayer's chanlist to system country code.
806 *
807 * \param chanlist MPlayer's chanlist name
808 *
809 * \return system country code
810 *
811 * \remarks
812 * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified
813 * country (which is usually larger then MPlayer's one, so workaround will work fine).
814 *
815 * \todo
816 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
817 */
818 static int chanlist2country(char *chanlist)
819 {
820 int i;
821 for(i=0; tv_chanlist2country[i].chanlist_name; i++)
822 if (!strcmp(chanlist, tv_chanlist2country[i].chanlist_name))
823 break;
824 return tv_chanlist2country[i].country_code;
825 }
826
827 /**
828 * \brief loads specified resource from module and return pointer to it
829 *
830 * \param hDLL valid module desriptor
831 * \param index index of resource. resource with name "#<index>" will be loaded
832 *
833 * \return pointer to loader resource or NULL if error occured
834 */
835 static void *GetRC(HMODULE hDLL, int index)
836 {
837 char szRCDATA[10];
838 char szName[10];
839 HRSRC hRes;
840 HGLOBAL hTable;
841
842 snprintf(szRCDATA, 10, "#%d", (int)RT_RCDATA);
843 snprintf(szName, 10, "#%d", index);
844
845 hRes = FindResource(hDLL, szName, szRCDATA);
846 if (!hRes) {
847 return NULL;
848 }
849 hTable = LoadResource(hDLL, hRes);
850 if (!hTable) {
851 return NULL;
852 }
853 return LockResource(hTable);
854 }
855
856 /**
857 * \brief loads frequency table for given country from kstvtune.ax
858 *
859 * \param[in] nCountry - country code
860 * \param[in] nInputType (TunerInputCable or TunerInputAntenna)
861 * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies
862 * \param[out] pnLen length of array
863 * \param[out] pnFirst - channel number of first entry in array (nChannelMax)
864 *
865 * \return S_OK if success
866 * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL
867 * \return E_FAIL error occured during load
868 *
869 * \remarks
870 * - array must be freed by caller
871 * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL
872 */
873 static HRESULT load_freq_table(int nCountry, int nInputType,
874 long **pplFreqTable, int *pnLen,
875 int *pnFirst)
876 {
877 HMODULE hDLL;
878 long *plFreqTable;
879 TRCCountryList *pCountryList;
880 int i, index;
881
882 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table called %d (%d)\n",nCountry,nInputType);
883 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
884
885 if (!pplFreqTable || !pnFirst || !pnLen)
886 return E_POINTER;
887 if (!nCountry)
888 return E_FAIL;
889
890 hDLL = LoadLibrary("kstvtune.ax");
891 if (!hDLL) {
892 return E_FAIL;
893 }
894 pCountryList = GetRC(hDLL, 9999);
895 if (!pCountryList) {
896 FreeLibrary(hDLL);
897 return E_FAIL;
898 }
899 for (i = 0; pCountryList[i].CountryCode != 0; i++)
900 if (pCountryList[i].CountryCode == nCountry)
901 break;
902 if (pCountryList[i].CountryCode == 0) {
903 FreeLibrary(hDLL);
904 return E_FAIL;
905 }
906 if (nInputType == TunerInputCable)
907 index = pCountryList[i].CableFreqTable;
908 else
909 index = pCountryList[i].BroadcastFreqTable;
910
911 plFreqTable = GetRC(hDLL, index); //First element is number of first channel, second - number of last channel
912 if (!plFreqTable) {
913 FreeLibrary(hDLL);
914 return E_FAIL;
915 }
916 *pnFirst = plFreqTable[0];
917 *pnLen = (int) (plFreqTable[1] - plFreqTable[0] + 1);
918 *pplFreqTable = (long *) malloc((*pnLen) * sizeof(long));
919 if (!*pplFreqTable) {
920 FreeLibrary(hDLL);
921 return E_FAIL;
922 }
923 for (i = 0; i < *pnLen; i++) {
924 (*pplFreqTable)[i] = plFreqTable[i + 2];
925 }
926 FreeLibrary(hDLL);
927 return S_OK;
928 }
929
930 /**
931 * \brief tunes to given frequency through IKsPropertySet call
932 *
933 * \param pTVTuner IAMTVTuner interface of capture device
934 * \param lFreq frequency to tune (in Hz)
935 *
936 * \return S_OK success
937 * \return apropriate error code otherwise
938 *
939 * \note
940 * Due to either bug in driver or error in following code calll to IKsProperty::Set
941 * in this methods always fail with error 0x8007007a.
942 *
943 * \todo test code on other machines and an error
944 */
945 static HRESULT set_frequency_direct(IAMTVTuner * pTVTuner, long lFreq)
946 {
947 HRESULT hr;
948 DWORD dwSupported = 0;
949 DWORD cbBytes = 0;
950 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps;
951 KSPROPERTY_TUNER_FREQUENCY_S frequency;
952 IKsPropertySet *pKSProp;
953
954 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency_direct called\n");
955
956 memset(&mode_caps, 0, sizeof(mode_caps));
957 memset(&frequency, 0, sizeof(frequency));
958
959 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
960 if (FAILED(hr))
961 return hr; //no IKsPropertySet interface
962
963 mode_caps.Mode = AMTUNER_MODE_TV;
964 hr = OLE_CALL_ARGS(pKSProp, QuerySupported, &PROPSETID_TUNER,
965 KSPROPERTY_TUNER_MODE_CAPS, &dwSupported);
966 if (FAILED(hr)) {
967 OLE_RELEASE_SAFE(pKSProp);
968 return hr;
969 }
970
971 if (!dwSupported & KSPROPERTY_SUPPORT_GET) {
972 OLE_RELEASE_SAFE(pKSProp);
973 return E_FAIL; //PROPSETID_TINER not supported
974 }
975
976 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
977 KSPROPERTY_TUNER_MODE_CAPS,
978 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps),
979 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps),
980 &mode_caps, sizeof(mode_caps), &cbBytes);
981
982 frequency.Frequency = lFreq;
983
984 if (mode_caps.Strategy == KS_TUNER_STRATEGY_DRIVER_TUNES)
985 frequency.TuningFlags = KS_TUNER_TUNING_FINE;
986 else
987 frequency.TuningFlags = KS_TUNER_TUNING_EXACT;
988
989 if (lFreq < mode_caps.MinFrequency || lFreq > mode_caps.MaxFrequency) {
990 OLE_RELEASE_SAFE(pKSProp);
991 return E_FAIL;
992 }
993
994 hr = OLE_CALL_ARGS(pKSProp, Set, &PROPSETID_TUNER,
995 KSPROPERTY_TUNER_FREQUENCY,
996 INSTANCEDATA_OF_PROPERTY_PTR(&frequency),
997 INSTANCEDATA_OF_PROPERTY_SIZE(frequency),
998 &frequency, sizeof(frequency));
999 if (FAILED(hr)) {
1000 OLE_RELEASE_SAFE(pKSProp);
1001 return hr;
1002 }
1003
1004 OLE_RELEASE_SAFE(pKSProp);
1005
1006 return S_OK;
1007 }
1008
1009 /**
1010 * \brief find channel with nearest frequency and set it
1011 *
1012 * \param priv driver's private data
1013 * \param lFreq frequency in Hz
1014 *
1015 * \return S_OK if success
1016 * \return E_FAIL if error occured
1017 */
1018 static HRESULT set_nearest_freq(priv_t * priv, long lFreq)
1019 {
1020 HRESULT hr;
1021 int i;
1022 long lFreqDiff=-1;
1023 int nChannel;
1024 TunerInputType tunerInput;
1025 long lInput;
1026
1027 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq called\n");
1028 if(priv->freq_table_len == -1 && !priv->freq_table) {
1029
1030 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
1031 if(FAILED(hr)){ //Falling back to 0
1032 lInput=0;
1033 }
1034
1035 hr = OLE_CALL_ARGS(priv->pTVTuner, get_InputType, lInput, &tunerInput);
1036
1037 if (load_freq_table(chanlist2country(priv->tv_param->chanlist), tunerInput, &(priv->freq_table), &(priv->freq_table_len), &(priv->first_channel)) != S_OK) {//FIXME
1038 priv->freq_table_len=0;
1039 priv->freq_table=NULL;
1040 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableExtractFreqTable);
1041 return E_FAIL;
1042 };
1043 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_FreqTableLoaded, tunerInput == TunerInputAntenna ? "broadcast" : "cable",
1044 chanlist2country(priv->tv_param->chanlist), priv->freq_table_len);
1045 }
1046
1047 if (priv->freq_table_len <= 0)
1048 return E_FAIL;
1049
1050 //FIXME: rewrite search algo
1051 nChannel = -1;
1052 for (i = 0; i < priv->freq_table_len; i++) {
1053 if (nChannel == -1 || labs(lFreq - priv->freq_table[i]) < lFreqDiff) {
1054 nChannel = priv->first_channel + i;
1055 lFreqDiff = labs(lFreq - priv->freq_table[i]);
1056 }
1057 }
1058 if (nChannel == -1) {
1059 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableFindNearestChannel);
1060 return E_FAIL;
1061 }
1062 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Channel, nChannel,
1063 AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT);
1064 if (FAILED(hr)) {
1065 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableToSetChannel, (unsigned int)hr);
1066 return E_FAIL;
1067 }
1068 return S_OK;
1069 }
1070
1071 /**
1072 * \brief setting frequency. decides whether use direct call/workaround
1073 *
1074 * \param priv driver's private data
1075 * \param lFreq frequency in Hz
1076 *
1077 * \return TVI_CONTROL_TRUE if success
1078 * \return TVI_CONTROL_FALSE if error occured
1079 *
1080 * \todo check for freq boundary
1081 */
1082 static int set_frequency(priv_t * priv, long lFreq)
1083 {
1084 HRESULT hr;
1085
1086 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency called\n");
1087 if (!priv->pTVTuner)
1088 return TVI_CONTROL_FALSE;
1089 if (priv->direct_setfreq_call) { //using direct call to set frequency
1090 hr = set_frequency_direct(priv->pTVTuner, lFreq);
1091 if (FAILED(hr)) {
1092 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DirectSetFreqFailed);
1093 priv->direct_setfreq_call = 0;
1094 }
1095 }
1096 if (!priv->direct_setfreq_call) {
1097 hr = set_nearest_freq(priv, lFreq);
1098 }
1099 if (FAILED(hr))
1100 return TVI_CONTROL_FALSE;
1101 #ifdef DEPRECATED
1102 priv->pGrabber->ClearBuffer(priv->pGrabber);
1103 #endif
1104 return TVI_CONTROL_TRUE;
1105 }
1106
1107 /**
1108 * \brief return current frequency from tuner (in Hz)
1109 *
1110 * \param pTVTuner IAMTVTuner interface of tuner
1111 * \param plFreq address of variable that receives current frequency
1112 *
1113 * \return S_OK success
1114 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1115 * \return apropriate error code otherwise
1116 */
1117 static HRESULT get_frequency_direct(IAMTVTuner * pTVTuner, long *plFreq)
1118 {
1119 HRESULT hr;
1120 KSPROPERTY_TUNER_STATUS_S TunerStatus;
1121 DWORD cbBytes;
1122 IKsPropertySet *pKSProp;
1123 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency_direct called\n");
1124
1125 if (!plFreq)
1126 return E_POINTER;
1127
1128 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
1129 if (FAILED(hr)) {
1130 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq QueryInterface failed\n");
1131 return hr;
1132 }
1133
1134 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
1135 KSPROPERTY_TUNER_STATUS,
1136 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus),
1137 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus),
1138 &TunerStatus, sizeof(TunerStatus), &cbBytes);
1139 if (FAILED(hr)) {
1140 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq Get failure\n");
1141 return hr;
1142 }
1143 *plFreq = TunerStatus.CurrentFrequency;
1144 return S_OK;
1145 }
1146
1147 /**
1148 * \brief gets current frequency
1149 *
1150 * \param priv driver's private data structure
1151 * \param plFreq - pointer to long int to store frequency to (in Hz)
1152 *
1153 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1154 */
1155 static int get_frequency(priv_t * priv, long *plFreq)
1156 {
1157 HRESULT hr;
1158
1159 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency called\n");
1160
1161 if (!plFreq || !priv->pTVTuner)
1162 return TVI_CONTROL_FALSE;
1163
1164 if (priv->direct_getfreq_call) { //using direct call to get frequency
1165 hr = get_frequency_direct(priv->pTVTuner, plFreq);
1166 if (FAILED(hr)) {
1167 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_DirectGetFreqFailed);
1168 priv->direct_getfreq_call = 0;
1169 }
1170 }
1171 if (!priv->direct_getfreq_call) {
1172 hr=OLE_CALL_ARGS(priv->pTVTuner, get_VideoFrequency, plFreq);
1173 if (FAILED(hr))
1174 return TVI_CONTROL_FALSE;
1175
1176 }
1177 return TVI_CONTROL_TRUE;
1178 }
1179
1180 /**
1181 * \brief get tuner capabilities
1182 *
1183 * \param priv driver's private data
1184 */
1185 static void get_capabilities(priv_t * priv)
1186 {
1187 long lAvailableFormats;
1188 HRESULT hr;
1189 int i;
1190 long lInputPins, lOutputPins, lRelated, lPhysicalType;
1191 IEnumPins *pEnum;
1192 char tmp[200];
1193 IPin *pPin = 0;
1194 PIN_DIRECTION ThisPinDir;
1195 PIN_INFO pi;
1196 IAMAudioInputMixer *pIAMixer;
1197
1198 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_capabilities called\n");
1199 if (priv->pTVTuner) {
1200
1201 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_SupportedNorms);
1202 hr = OLE_CALL_ARGS(priv->pTVTuner, get_AvailableTVFormats,
1203 &lAvailableFormats);
1204 if (FAILED(hr))
1205 tv_available_norms_count = 0;
1206 else {
1207 for (i = 0; i < TV_NORMS_COUNT; i++) {
1208 if (lAvailableFormats & tv_norms[i].index) {
1209 tv_available_norms[tv_available_norms_count] = i;
1210 mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
1211 tv_available_norms_count + 1, tv_norms[i].name);
1212 tv_available_norms_count++;
1213 }
1214 }
1215 }
1216 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1217 }
1218 if (priv->pCrossbar) {
1219 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins,
1220 &lInputPins);
1221
1222 tv_available_inputs = (long *) malloc(sizeof(long) * lInputPins);
1223 tv_available_inputs_count = 0;
1224
1225 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableVideoInputs);
1226 for (i = 0; i < lInputPins; i++) {
1227 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1, i,
1228 &lRelated, &lPhysicalType);
1229
1230 if (lPhysicalType < 0x1000) {
1231 tv_available_inputs[tv_available_inputs_count++] = i;
1232 mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
1233 tv_available_inputs_count - 1,
1234 physcon2str(lPhysicalType));
1235 }
1236 }
1237 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1238
1239 set_crossbar_input(priv, 0);
1240 }
1241
1242 if (priv->adev_index != -1) {
1243 hr = OLE_CALL_ARGS(priv->pAudioFilter, EnumPins, &pEnum);
1244 if (FAILED(hr))
1245 return;
1246 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableAudioInputs);
1247 i = 0;
1248 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
1249 memset(&pi, 0, sizeof(pi));
1250 memset(tmp, 0, 200);
1251 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
1252 if (ThisPinDir == PINDIR_INPUT) {
1253 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
1254 wtoa(pi.achName, tmp, 200);
1255 OLE_RELEASE_SAFE(pi.pFilter);
1256 mp_msg(MSGT_TV, MSGL_V, " %d=%s", i, tmp);
1257 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
1258 hr = OLE_QUERYINTERFACE(pPin, IID_IAMAudioInputMixer,pIAMixer);
1259 if (SUCCEEDED(hr)) {
1260 if (i == priv->tv_param->audio_id) {
1261 OLE_CALL_ARGS(pIAMixer, put_Enable, TRUE);
1262 if(priv->tv_param->volume>0)
1263 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.01 * priv->tv_param->volume);
1264 #if 0
1265 else
1266 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 1.0);
1267 #endif
1268 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_InputSelected);
1269 } else {
1270 OLE_CALL_ARGS(pIAMixer, put_Enable, FALSE);
1271 #if 0
1272 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.0);
1273 #endif
1274 }
1275 OLE_RELEASE_SAFE(pIAMixer);
1276 }
1277 mp_msg(MSGT_TV, MSGL_V, ";");
1278 OLE_RELEASE_SAFE(pPin);
1279 i++;
1280 }
1281 }
1282 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1283 OLE_RELEASE_SAFE(pEnum);
1284 }
1285 }
1286
1287 /*
1288 *---------------------------------------------------------------------------------------
1289 *
1290 * Filter related methods
1291 *
1292 *---------------------------------------------------------------------------------------
1293 */
1294 /**
1295 * \brief building in graph audio/video capture chain
1296 *
1297 * \param priv driver's private data
1298 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1299 * \param pbuf ringbuffer data structure
1300 * \param pmt media type for chain (AM_MEDIA_TYPE)
1301 *
1302 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1303 */
1304 static HRESULT build_sub_graph(priv_t * priv, IBaseFilter * pCaptureFilter,
1305 grabber_ringbuffer_t * pbuf,
1306 AM_MEDIA_TYPE * pmt, const GUID* ppin_category)
1307 {
1308 HRESULT hr;
1309
1310 IPin *pSGIn;
1311 IPin *pSGOut;
1312 IPin *pNRIn=NULL;
1313 IPin *pCapturePin;
1314
1315 IBaseFilter *pNR = NULL;
1316 IBaseFilter *pSGF = NULL;
1317
1318 ISampleGrabber *pSG = NULL;
1319
1320 hr=S_OK;
1321 do{
1322 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
1323 (IUnknown *) pCaptureFilter,
1324 PINDIR_OUTPUT, ppin_category,
1325 &(pmt->majortype), FALSE, 0, &pCapturePin);
1326 if(FAILED(hr)){
1327 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr);
1328 break;
1329 }
1330 /* Addinf SampleGrabber filter for video stream */
1331 hr = CoCreateInstance((GUID *) & CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pSGF);
1332 if(FAILED(hr)){
1333 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1334 break;
1335 }
1336 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pSGF, L"Sample Grabber");
1337 if(FAILED(hr)){
1338 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1339 break;
1340 }
1341 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pSGF,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pSGIn);
1342 if(FAILED(hr)){
1343 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr);
1344 break;
1345 }
1346 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pSGF,PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pSGOut);
1347 if(FAILED(hr)){
1348 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr);
1349 break;
1350 }
1351
1352 /* creating ringbuffer for video samples */
1353 priv->pCSGCB = CSampleGrabberCB_Create(pbuf);
1354 if(!priv->pCSGCB){
1355 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY);
1356 break;
1357 }
1358
1359 /* initializing SampleGrabber filter */
1360 hr = OLE_QUERYINTERFACE(pSGF, IID_ISampleGrabber, pSG);
1361 if(FAILED(hr)){
1362 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1363 break;
1364 }
1365 hr = OLE_CALL_ARGS(pSG, SetMediaType, pmt); //set desired mediatype
1366 if(FAILED(hr)){
1367 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1368 break;
1369 }
1370 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1371 hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) priv->pCSGCB, 0); //we want to receive sample
1372
1373 if(FAILED(hr)){
1374 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1375 break;
1376 }
1377 hr = OLE_CALL_ARGS(pSG, SetOneShot, FALSE); //... for all frames
1378 if(FAILED(hr)){
1379 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1380 break;
1381 }
1382 hr = OLE_CALL_ARGS(pSG, SetBufferSamples, FALSE); //... do not buffer samples in sample grabber
1383 if(FAILED(hr)){
1384 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1385 break;
1386 }
1387 OLE_RELEASE_SAFE(pSG);
1388
1389 if(priv->tv_param->normalize_audio_chunks && !memcmp(&(pmt->majortype),&(MEDIATYPE_Audio),16)){
1390 set_buffer_preference(20,(WAVEFORMATEX*)(pmt->pbFormat),pCapturePin,pSGIn);
1391 }
1392
1393 /* connecting filters together: VideoCapture --> SampleGrabber */
1394 hr = OLE_CALL_ARGS(priv->pGraph, Connect, pCapturePin, pSGIn);
1395 if(FAILED(hr)){
1396 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr);
1397 break;
1398 }
1399
1400 if(priv->tv_param->hidden_video_renderer){
1401 IEnumFilters* pEnum;
1402 IBaseFilter* pFilter;
1403
1404 hr=OLE_CALL_ARGS(priv->pBuilder,RenderStream,NULL,NULL,(IUnknown*)pCapturePin,NULL,NULL);
1405
1406 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
1407 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
1408 LPVIDEOWINDOW pVideoWindow;
1409 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
1410 if (SUCCEEDED(hr))
1411 {
1412 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
1413 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
1414 OLE_RELEASE_SAFE(pVideoWindow);
1415 }
1416 OLE_RELEASE_SAFE(pFilter);
1417 }
1418 OLE_RELEASE_SAFE(pEnum);
1419 }else
1420 {
1421 /* adding sink for video stream */
1422 hr = CoCreateInstance((GUID *) & CLSID_NullRenderer, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pNR);
1423 if(FAILED(hr)){
1424 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
1425 break;
1426 }
1427 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pNR, L"Null Renderer");
1428 if(FAILED(hr)){
1429 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
1430 break;
1431 }
1432 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pNR,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pNRIn);
1433 if(FAILED(hr)){
1434 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr);
1435 break;
1436 }
1437 /*
1438 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1439 */
1440 if(memcmp(&(pmt->majortype),&MEDIATYPE_VBI,16)){
1441 /* connecting filters together: SampleGrabber --> NullRenderer */
1442 hr = OLE_CALL_ARGS(priv->pGraph, Connect, pSGOut, pNRIn);
1443 if(FAILED(hr)){
1444 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr);
1445 break;
1446 }
1447 }
1448 }
1449
1450 hr = S_OK;
1451 } while(0);
1452 OLE_RELEASE_SAFE(pSGF);
1453 OLE_RELEASE_SAFE(pSGIn);
1454 OLE_RELEASE_SAFE(pSGOut);
1455 OLE_RELEASE_SAFE(pNR);
1456 OLE_RELEASE_SAFE(pNRIn);
1457 OLE_RELEASE_SAFE(pCapturePin);
1458
1459 return hr;
1460 }
1461
1462 /**
1463 * \brief configures crossbar for grabbing video stream from given input
1464 *
1465 * \param priv driver's private data
1466 * \param input index of available video input to get data from
1467 *
1468 * \return TVI_CONTROL_TRUE success
1469 * \return TVI_CONTROL_FALSE error
1470 */
1471 static int set_crossbar_input(priv_t * priv, int input)
1472 {
1473 HRESULT hr;
1474 int i, nVideoDecoder, nAudioDecoder;
1475 long lInput, lInputRelated, lRelated, lPhysicalType, lOutputPins,
1476 lInputPins;
1477
1478 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Configuring crossbar\n");
1479 if (!priv->pCrossbar || input < 0
1480 || input >= tv_available_inputs_count)
1481 return TVI_CONTROL_FALSE;
1482
1483 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, &lInputPins);
1484
1485 lInput = tv_available_inputs[input];
1486
1487 if (lInput < 0 || lInput >= lInputPins)
1488 return TVI_CONTROL_FALSE;
1489
1490 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1 /* input */ , lInput,
1491 &lInputRelated, &lPhysicalType);
1492
1493 nVideoDecoder = nAudioDecoder = -1;
1494 for (i = 0; i < lOutputPins; i++) {
1495 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 0 /*output */ , i,
1496 &lRelated, &lPhysicalType);
1497 if (lPhysicalType == PhysConn_Video_VideoDecoder)
1498 nVideoDecoder = i;
1499 if (lPhysicalType == PhysConn_Audio_AudioDecoder)
1500 nAudioDecoder = i;
1501 }
1502 if (nVideoDecoder >= 0) {
1503 //connecting given input with video decoder
1504 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nVideoDecoder, lInput);
1505 if (hr != S_OK) {
1506 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputVideoDecoder, (unsigned int)hr);
1507 return TVI_CONTROL_FALSE;
1508 }
1509 }
1510 if (nAudioDecoder >= 0 && lInputRelated >= 0) {
1511 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nAudioDecoder,
1512 lInputRelated);
1513 if (hr != S_OK) {
1514 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputAudioDecoder, (unsigned int)hr);
1515 return TVI_CONTROL_FALSE;
1516 }
1517 }
1518 return TVI_CONTROL_TRUE;
1519 }
1520
1521 /**
1522 * \brief adjusts video control (hue,saturation,contrast,brightess)
1523 *
1524 * \param priv driver's private data
1525 * \param control which control to adjust
1526 * \param value new value for control (0-100)
1527 *
1528 * \return TVI_CONTROL_TRUE success
1529 * \return TVI_CONTROL_FALSE error
1530 */
1531 static int set_control(priv_t * priv, int control, int value)
1532 {
1533 long lMin, lMax, lStepping, lDefault, lFlags, lValue;
1534 HRESULT hr;
1535
1536 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_control called\n");
1537 if (value < -100 || value > 100 || !priv->pVideoProcAmp)
1538 return TVI_CONTROL_FALSE;
1539
1540 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
1541 &lMin, &lMax, &lStepping, &lDefault, &lFlags);
1542 if (FAILED(hr) || lFlags != VideoProcAmp_Flags_Manual)
1543 return TVI_CONTROL_FALSE;
1544
1545 lValue = lMin + (value + 100) * (lMax - lMin) / 200;
1546 /*
1547 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1548 */
1549 if (lStepping > lMax) {
1550 mp_msg(MSGT_TV, MSGL_DBG3,
1551 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1552 lStepping, lMax,control);
1553 lStepping = 1;
1554 }
1555 lValue -= lValue % lStepping;
1556 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Set, control, lValue,
1557 VideoProcAmp_Flags_Manual);
1558 if (FAILED(hr))
1559 return TVI_CONTROL_FALSE;
1560
1561 return TVI_CONTROL_TRUE;
1562 }
1563
1564 /**
1565 * \brief get current value of video control (hue,saturation,contrast,brightess)
1566 *
1567 * \param priv driver's private data
1568 * \param control which control to adjust
1569 * \param pvalue address of variable thar receives current value
1570 *
1571 * \return TVI_CONTROL_TRUE success
1572 * \return TVI_CONTROL_FALSE error
1573 */
1574 static int get_control(priv_t * priv, int control, int *pvalue)
1575 {
1576 long lMin, lMax, lStepping, lDefault, lFlags, lValue;
1577 HRESULT hr;
1578
1579 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_control called\n");
1580 if (!pvalue || !priv->pVideoProcAmp)
1581 return TVI_CONTROL_FALSE;
1582
1583 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
1584 &lMin, &lMax, &lStepping, &lDefault, &lFlags);
1585 if (FAILED(hr))
1586 return TVI_CONTROL_FALSE;
1587 if (lMin == lMax) {
1588 *pvalue = lMin;
1589 return TVI_CONTROL_TRUE;
1590 }
1591
1592 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Get, control, &lValue, &lFlags);
1593 if (FAILED(hr))
1594 return TVI_CONTROL_FALSE;
1595
1596 *pvalue = 200 * (lValue - lMin) / (lMax - lMin) - 100;
1597
1598 return TVI_CONTROL_TRUE;
1599 }
1600
1601 /**
1602 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1603 *
1604 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1605 * \param pfcc address of variable that receives FourCC
1606 * \param pwidth address of variable that receives width
1607 * \param pheight address of variable that recevies height
1608 *
1609 * \return 1 if data extracted successfully, 0 - otherwise
1610 */
1611 static int extract_video_format(AM_MEDIA_TYPE * pmt, int *pfcc,
1612 int *pwidth, int *pheight)
1613 {
1614 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_video_format called\n");
1615 if (!pmt)
1616 return 0;
1617 if (!pmt->pbFormat)
1618 return 0;
1619 if (memcmp(&(pmt->formattype), &FORMAT_VideoInfo, 16) != 0)
1620 return 0;
1621 if (pfcc)
1622 *pfcc = subtype2imgfmt(&(pmt->subtype));
1623 if (pwidth)
1624 *pwidth = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biWidth;
1625 if (pheight)
1626 *pheight = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biHeight;
1627 return 1;
1628 }
1629
1630 /**
1631 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1632 *
1633 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1634 * \param pfcc address of variable that receives samplerate
1635 * \param pwidth address of variable that receives number of bits per sample
1636 * \param pheight address of variable that recevies number of channels
1637 *
1638 * \return 1 if data extracted successfully, 0 - otherwise
1639 */
1640 static int extract_audio_format(AM_MEDIA_TYPE * pmt, int *psamplerate,
1641 int *pbits, int *pchannels)
1642 {
1643 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_audio_format called\n");
1644 if (!pmt)
1645 return 0;
1646 if (!pmt->pbFormat)
1647 return 0;
1648 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
1649 return 0;
1650 if (psamplerate)
1651 *psamplerate = ((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec;
1652 if (pbits)
1653 *pbits = ((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample;
1654 if (pchannels)
1655 *pchannels = ((WAVEFORMATEX *) pmt->pbFormat)->nChannels;
1656 return 1;
1657 }
1658
1659 /**
1660 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1661 *
1662 * \param pmt pointer to AM_MEDIA_TYPE for check
1663 * \param samplerate audio samplerate
1664 * \param bits bits per sample
1665 * \param channels number of audio channels
1666 *
1667 * \return 1 if AM_MEDIA_TYPE compatible
1668 * \return 0 if not
1669 */
1670 static int check_audio_format(AM_MEDIA_TYPE * pmt, int samplerate,
1671 int bits, int channels)
1672 {
1673 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_audio_format called\n");
1674 if (!pmt)
1675 return 0;
1676 if (memcmp(&(pmt->majortype), &MEDIATYPE_Audio, 16) != 0)
1677 return 0;
1678 if (memcmp(&(pmt->subtype), &MEDIASUBTYPE_PCM, 16) != 0)
1679 return 0;
1680 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
1681 return 0;
1682 if (!pmt->pbFormat)
1683 return 0;
1684 if (((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec != samplerate)
1685 return 0;
1686 if (((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample != bits)
1687 return 0;
1688 if (channels > 0
1689 && ((WAVEFORMATEX *) pmt->pbFormat)->nChannels != channels)
1690 return 0;
1691
1692 return 1;
1693 }
1694
1695 /**
1696 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1697 *
1698 * \param pmt pointer to AM_MEDIA_TYPE for check
1699 * \param fcc FourCC (compression)
1700 * \param width width of picture
1701 * \param height height of picture
1702 *
1703 * \return 1 if AM_MEDIA_TYPE compatible
1704 & \return 0 if not
1705 *
1706 * \note
1707 * width and height are currently not used
1708 *
1709 * \todo
1710 * add width/height check
1711 */
1712 static int check_video_format(AM_MEDIA_TYPE * pmt, int fcc, int width,
1713 int height)
1714 {
1715 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_video_format called\n");
1716 if (!pmt)
1717 return 0;
1718 if (memcmp(&(pmt->majortype), &MEDIATYPE_Video, 16) != 0)
1719 return 0;
1720 if (subtype2imgfmt(&(pmt->subtype)) != fcc)
1721 return 0;
1722 return 1;
1723 }
1724
1725 /**
1726 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1727 *
1728 * \param subtype DirectShow subtype for video format
1729 *
1730 * \return MPlayer's IMGFMT or 0 if error occured
1731 */
1732 static int subtype2imgfmt(const GUID * subtype)
1733 {
1734 int i;
1735 for (i = 0; img_fmt_list[i].fmt; i++) {
1736 if (memcmp(subtype, img_fmt_list[i].subtype, 16) == 0)
1737 return img_fmt_list[i].fmt;
1738 }
1739 return 0;
1740 }
1741
1742 /**
1743 * \brief prints filter name and it pins
1744 *
1745 * \param pFilter - IBaseFilter to get data from
1746 *
1747 * \return S_OK if success, error code otherwise
1748 */
1749 static HRESULT show_filter_info(IBaseFilter * pFilter)
1750 {
1751 char tmp[200];
1752 FILTER_INFO fi;
1753 LPENUMPINS pEnum = 0;
1754 IPin *pPin = 0;
1755 PIN_DIRECTION ThisPinDir;
1756 PIN_INFO pi;
1757 HRESULT hr;
1758 int i;
1759
1760 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: show_filter_info called\n");
1761 memset(&fi, 0, sizeof(fi));
1762 memset(tmp, 0, 200);
1763
1764 OLE_CALL_ARGS(pFilter, QueryFilterInfo, &fi);
1765 OLE_RELEASE_SAFE(fi.pGraph);
1766 wtoa(fi.achName, tmp, 200);
1767 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1768 pFilter, tmp, fi.pGraph);
1769 hr = OLE_CALL_ARGS(pFilter, EnumPins, &pEnum);
1770 if (FAILED(hr))
1771 return hr;
1772 i = 0;
1773 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
1774 memset(&pi, 0, sizeof(pi));
1775 memset(tmp, 0, 200);
1776 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
1777 if (ThisPinDir == PINDIR_OUTPUT) {
1778 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
1779 wtoa(pi.achName, tmp, 200);
1780 OLE_RELEASE_SAFE(pi.pFilter);
1781 mp_msg(MSGT_TV, MSGL_DBG2, " %d=%s", i, tmp);
1782 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
1783 mp_msg(MSGT_TV, MSGL_DBG2, ";");
1784 OLE_RELEASE_SAFE(pPin);
1785 i++;
1786 }
1787 }
1788 mp_msg(MSGT_TV, MSGL_DBG2, "\n");
1789 OLE_RELEASE_SAFE(pEnum);
1790 return S_OK;
1791 }
1792
1793 /**
1794 * \brief gets device's frendly in ANSI encoding
1795 *
1796 * \param pM IMoniker interface, got in enumeration process
1797 * \param category device category
1798 *
1799 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1800 */
1801 static int get_device_name(IMoniker * pM, char *pBuf, int nLen)
1802 {
1803 HRESULT hr;
1804 VARIANT var;
1805 IPropertyBag *pPropBag;
1806 hr = OLE_CALL_ARGS(pM, BindToStorage, 0, 0, &IID_IPropertyBag,(void *) &pPropBag);
1807 if (FAILED(hr)) {
1808 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Call to BindToStorage failed\n");
1809 return TVI_CONTROL_FALSE;
1810 }
1811 var.vt = VT_BSTR;
1812 hr = OLE_CALL_ARGS(pPropBag, Read, L"Description", (LPVARIANT) & var,
1813 NULL);
1814 if (FAILED(hr)) {
1815 hr = OLE_CALL_ARGS(pPropBag, Read, L"FriendlyName", (LPVARIANT) & var,
1816 NULL);
1817 }
1818 OLE_RELEASE_SAFE(pPropBag);
1819 if (SUCCEEDED(hr)) {
1820 wtoa(var.bstrVal, pBuf, nLen);
1821 return TVI_CONTROL_TRUE;
1822 }
1823 return TVI_CONTROL_FALSE;
1824 }
1825
1826 /**
1827 * \brief find capture device at given index
1828 *
1829 * \param index device index to search for (-1 mean only print available)
1830 * \param category device category
1831 *
1832 * \return IBaseFilter interface for capture device with given index
1833 *
1834 * Sample values for category:
1835 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1836 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1837 * See DirectShow SDK documentation for other possible values
1838 */
1839 static IBaseFilter *find_capture_device(int index, REFCLSID category)
1840 {
1841 IBaseFilter *pFilter = NULL;
1842 ICreateDevEnum *pDevEnum = NULL;
1843 IEnumMoniker *pClassEnum = NULL;
1844 IMoniker *pM;
1845 HRESULT hr;
1846 ULONG cFetched;
1847 int i;
1848 char tmp[DEVICE_NAME_MAX_LEN + 1];
1849 hr = CoCreateInstance((GUID *) & CLSID_SystemDeviceEnum, NULL,
1850 CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum,
1851 (void *) &pDevEnum);
1852 if (FAILED(hr)) {
1853 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create device enumerator\n");
1854 return NULL;
1855 }
1856
1857 hr = OLE_CALL_ARGS(pDevEnum, CreateClassEnumerator, category, &pClassEnum, 0);
1858 OLE_RELEASE_SAFE(pDevEnum);
1859 if (FAILED(hr)) {
1860 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create class enumerator\n");
1861 return NULL;
1862 }
1863 if (hr == S_FALSE) {
1864 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: No capture devices found\n");
1865 return NULL;
1866 }
1867
1868 OLE_CALL(pClassEnum,Reset);
1869 for (i = 0; OLE_CALL_ARGS(pClassEnum, Next, 1, &pM, &cFetched) == S_OK; i++) {
1870 if(get_device_name(pM, tmp, DEVICE_NAME_MAX_LEN)!=TVI_CONTROL_TRUE)
1871 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableGetDeviceName, i);
1872 else
1873 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DeviceName, i, tmp);
1874 if (index != -1 && i == index) {
1875 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_UsingDevice, index, tmp);
1876 hr = OLE_CALL_ARGS(pM, BindToObject, 0, 0, &IID_IBaseFilter,(void *) &pFilter);
1877 if (FAILED(hr))
1878 pFilter = NULL;
1879 }
1880 OLE_RELEASE_SAFE(pM);
1881 }
1882 if (index != -1 && !pFilter) {
1883 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_DeviceNotFound,
1884 index);
1885 }
1886 OLE_RELEASE_SAFE(pClassEnum);
1887
1888 return pFilter;
1889 }
1890
1891 /**
1892 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
1893 *
1894 * \param[in] pVideoStreamConfig IAMStreamConfig of used capture device's output pin
1895 * \param[in] pMediaType MEDIATYPE_Video or MEDIATYPE_Audio
1896 * \param[out] parpmtMedia address of variable that receives pointer to array of AM_MEDIA_TYPE structures
1897 * \param[out] parCaps address of variable thar receives pointer to array of VIDEOSTREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS
1898 *
1899 * \return S_OK success
1900 * \return E_POINTER one of parameters is NULL
1901 * \return E_FAIL required size of buffer is unknown for given media type
1902 * \return E_OUTOFMEMORY not enough memory
1903 * \return other error code from called methods
1904 *
1905 * \remarks
1906 * last item or returned arrays will be NULL
1907 */
1908 static HRESULT get_available_formats_stream(IAMStreamConfig *
1909 pStreamConfig,
1910 const GUID * pMediaType,
1911 AM_MEDIA_TYPE *** parpmtMedia,
1912 void ***parCaps)
1913 {
1914 AM_MEDIA_TYPE **arpmt;
1915 void **pBuf=NULL;
1916
1917 HRESULT hr;
1918 int i, count, size;
1919 int done;
1920
1921 mp_msg(MSGT_TV, MSGL_DBG4,
1922 "tvi_dshow: get_available_formats_stream called\n");
1923
1924 if (!pStreamConfig || !pMediaType || !parpmtMedia || !parCaps)
1925 return E_POINTER;
1926
1927 hr=OLE_CALL_ARGS(pStreamConfig, GetNumberOfCapabilities, &count, &size);
1928 if (FAILED(hr)) {
1929 mp_msg(MSGT_TV, MSGL_DBG4,
1930 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
1931 return hr;
1932 }
1933 if (memcmp(pMediaType, &MEDIATYPE_Video, 16) == 0){
1934 if (size != sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
1935 mp_msg(MSGT_TV, MSGL_DBG4,
1936 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
1937 return E_FAIL;
1938 } else if (memcmp(pMediaType, &MEDIATYPE_Audio, 16) == 0){
1939 if (size != sizeof(AUDIO_STREAM_CONFIG_CAPS)) {
1940 mp_msg(MSGT_TV, MSGL_DBG4,
1941 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
1942 return E_FAIL;
1943 } else {
1944 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_stream");
1945 return E_FAIL;
1946 }
1947 }
1948 }
1949 done = 0;
1950
1951 arpmt = (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
1952 if (arpmt) {
1953 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
1954
1955 pBuf = (void **) malloc((count + 1) * sizeof(void *));
1956 if (pBuf) {
1957 memset(pBuf, 0, (count + 1) * sizeof(void *));
1958
1959 for (i = 0; i < count; i++) {
1960 pBuf[i] = malloc(size);
1961
1962 if (!pBuf[i])
1963 break;
1964
1965 hr = OLE_CALL_ARGS(pStreamConfig, GetStreamCaps, i,
1966 &(arpmt[i]), pBuf[i]);
1967 if (FAILED(hr))
1968 break;
1969 }
1970 if (i == count) {
1971 *parpmtMedia = arpmt;
1972 *parCaps = pBuf;
1973 done = 1;
1974 }
1975 }
1976 }
1977 if (!done) {
1978 for (i = 0; i < count; i++) {
1979 if (pBuf && pBuf[i])
1980 free(pBuf[i]);
1981 if (arpmt && arpmt[i])
1982 DeleteMediaType(arpmt[i]);
1983 }
1984 if (pBuf)
1985 free(pBuf);
1986 if (arpmt)
1987 free(arpmt);
1988 if (hr != S_OK) {
1989 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
1990 return hr;
1991 } else
1992 return E_OUTOFMEMORY;
1993 }
1994 return S_OK;
1995 }
1996
1997 /**
1998 * \brief returns allocates an array and store available media formats for given pin type to it
1999 *
2000 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2001 * \param pFilter IBaseFilter interface of capture device
2002 * \param pMediaType media type for search (MEDIATYPE_Video or MEDIATYPE_Audio)
2003 * \param[out] parpmtMediaType address of variable that receives pointer to array
2004 *
2005 * \return S_OK success
2006 * \return E_POINTER one of given pointers is null
2007 * \return apropriate error code otherwise
2008 */
2009 static HRESULT get_available_formats_pin(ICaptureGraphBuilder2 * pBuilder,
2010 IBaseFilter * pFilter,
2011 const GUID * pMediaType,
2012 AM_MEDIA_TYPE *** parpmtMedia,
2013 void ***parCaps)
2014 {
2015 IEnumMediaTypes *pEnum;
2016 IPin *pPin;
2017 int i, count, size;
2018 ULONG cFetched;
2019 AM_MEDIA_TYPE *pmt;
2020 HRESULT hr;
2021 void **pBuf;
2022 AM_MEDIA_TYPE **arpmt; //This will be real array
2023 int isvideo;
2024 VIDEO_STREAM_CONFIG_CAPS *pVideoCaps;
2025 AUDIO_STREAM_CONFIG_CAPS *pAudioCaps;
2026 int p1, p2, p3;
2027
2028 mp_msg(MSGT_TV, MSGL_DBG4,
2029 "tvi_dshow: get_available_formats_pin called\n");
2030 if (!pBuilder || !pFilter || !pMediaType || !parpmtMedia)
2031 return E_POINTER;
2032
2033 hr = OLE_CALL_ARGS(pBuilder, FindPin, (IUnknown *) pFilter,
2034 PINDIR_OUTPUT, NULL, pMediaType, FALSE, 0, &pPin);
2035 if (FAILED(hr)) {
2036 mp_msg(MSGT_TV, MSGL_DBG4,
2037 "tvi_dshow: Call to FindPin failed (get_available_formats_pin)\n");
2038 return hr;
2039 }
2040 if (memcmp(pMediaType, &MEDIATYPE_Video, 16) == 0) {
2041 isvideo = 1;
2042 size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
2043 } else if (memcmp(pMediaType, &MEDIATYPE_Audio, 16) == 0) {
2044 isvideo = 0;
2045 size = sizeof(AUDIO_STREAM_CONFIG_CAPS);
2046 } else {
2047 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_pin");
2048 return E_FAIL;
2049 }
2050
2051 hr = OLE_CALL_ARGS(pPin, EnumMediaTypes, &pEnum);
2052 OLE_RELEASE_SAFE(pPin);
2053 if (FAILED(hr)) {
2054 mp_msg(MSGT_TV, MSGL_DBG4,
2055 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2056 return hr;
2057 }
2058 for (i = 0; OLE_CALL_ARGS(pEnum, Next, 1, &pmt, &cFetched) == S_OK; i++) {
2059 if (!pmt)
2060 break;
2061 }
2062 OLE_CALL(pEnum,Reset);
2063
2064 count = i;
2065 arpmt =
2066 (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
2067 if (!arpmt)
2068 return E_OUTOFMEMORY;
2069 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
2070
2071 for (i = 0;
2072 i < count
2073 && OLE_CALL_ARGS(pEnum, Next, 1, &(arpmt[i]), &cFetched) == S_OK;
2074 i++);
2075
2076 OLE_RELEASE_SAFE(pEnum);
2077
2078
2079 pBuf = (void **) malloc((count + 1) * sizeof(void *));
2080 if (!pBuf) {
2081 for (i = 0; i < count; i++)
2082 if (arpmt[i])
2083 DeleteMediaType(arpmt[i]);
2084 free(arpmt);
2085 return E_OUTOFMEMORY;
2086 }
2087 memset(pBuf, 0, (count + 1) * sizeof(void *));
2088
2089 for (i = 0; i < count; i++) {
2090 pBuf[i] = malloc(size);
2091 if (!pBuf[i])
2092 break;
2093 memset(pBuf[i], 0, size);
2094
2095 if (isvideo) {
2096 pVideoCaps = (VIDEO_STREAM_CONFIG_CAPS *) pBuf[i];
2097 extract_video_format(arpmt[i], NULL, &p1, &p2);
2098 pVideoCaps->MaxOutputSize.cx = pVideoCaps->MinOutputSize.cx =
2099 p1;
2100 pVideoCaps->MaxOutputSize.cy = pVideoCaps->MinOutputSize.cy =
2101 p2;
2102 } else {
2103 pAudioCaps = (AUDIO_STREAM_CONFIG_CAPS *) pBuf[i];
2104 extract_audio_format(arpmt[i], &p1, &p2, &p3);
2105 pAudioCaps->MaximumSampleFrequency =
2106 pAudioCaps->MinimumSampleFrequency = p1;
2107 pAudioCaps->MaximumBitsPerSample =
2108 pAudioCaps->MinimumBitsPerSample = p2;
2109 pAudioCaps->MaximumChannels = pAudioCaps->MinimumChannels = p3;
2110 }
2111
2112 }
2113 if (i != count) {
2114 for (i = 0; i < count; i++) {
2115 if (arpmt[i])
2116 DeleteMediaType(arpmt[i]);
2117 if (pBuf[i])
2118 free(pBuf[i]);
2119 }
2120 free(arpmt);
2121 free(pBuf);
2122 return E_OUTOFMEMORY;
2123 }
2124 *parpmtMedia = arpmt;
2125 *parCaps = pBuf;
2126
2127 return S_OK;
2128 }
2129
2130 /*
2131 *---------------------------------------------------------------------------------------
2132 *
2133 * Public methods
2134 *
2135 *---------------------------------------------------------------------------------------
2136 */
2137 /**
2138 * \brief fills given buffer with audio data (usually one block)
2139 *
2140 * \param priv driver's private data structure
2141 * \param buffer buffer to store data to
2142 * \param len buffer's size in bytes (usually one block size)
2143 *
2144 * \return audio pts if audio present, 1 - otherwise
2145 */
2146 static double grab_audio_frame(priv_t * priv, char *buffer, int len)
2147 {
2148 int bytes = 0;
2149 int i;
2150 double pts;
2151 grabber_ringbuffer_t *rb = priv->a_buf;
2152 grabber_ringbuffer_t *vrb = priv->v_buf;
2153
2154 if (!rb || !rb->ringbuffer)
2155 return 1;
2156
2157 if(vrb && vrb->tStart<0){
2158 memset(buffer,0,len);
2159 return 0;
2160 }
2161 if(vrb && rb->tStart<0)
2162 rb->tStart=vrb->tStart;
2163
2164 if (len < rb->blocksize)
2165 bytes = len;
2166 else
2167 bytes = rb->blocksize;
2168
2169 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2170 rb->count, len);
2171 if(!rb->count){
2172 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
2173 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
2174 if(!rb->count){
2175 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
2176 return 0;
2177 }
2178 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
2179 }
2180
2181 EnterCriticalSection(rb->pMutex);
2182 pts=rb->dpts[rb->head]-rb->tStart;
2183 memcpy(buffer, rb->ringbuffer[rb->head], bytes);
2184 rb->head = (rb->head + 1) % rb->buffersize;
2185 rb->count--;
2186 LeaveCriticalSection(rb->pMutex);
2187 return pts;
2188 }
2189
2190 /**
2191 * \brief returns audio frame size
2192 *
2193 * \param priv driver's private data structure
2194 *
2195 * \return audio block size if audio enabled and 1 - otherwise
2196 */
2197 static int get_audio_framesize(priv_t * priv)
2198 {
2199 if (!priv->a_buf)
2200 return 1; //no audio
2201 mp_msg(MSGT_TV,MSGL_DBG3,"get_audio_framesize: %d\n",priv->a_buf->blocksize);
2202 return priv->a_buf->blocksize;
2203 }
2204
2205 #ifdef HAVE_TV_TELETEXT
2206 static int vbi_get_props(priv_t* priv,tt_stream_props* ptsp)
2207 {
2208 if(!priv || !ptsp)
2209 return TVI_CONTROL_FALSE;
2210
2211 //STUBS!!!
2212 ptsp->interlaced=0;
2213 ptsp->offset=256;
2214
2215 ptsp->sampling_rate=27e6;
2216 ptsp->samples_per_line=720;
2217
2218 ptsp->count[0]=16;
2219 ptsp->count[1]=16;
2220 //END STUBS!!!
2221 ptsp->bufsize = ptsp->samples_per_line * (ptsp->count[0] + ptsp->count[1]);
2222
2223 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",
2224 ptsp->sampling_rate,
2225 ptsp->offset,
2226 ptsp->samples_per_line,
2227 ptsp->interlaced?"Yes":"No",
2228 ptsp->count[0],
2229 ptsp->count[1]);
2230
2231 return TVI_CONTROL_TRUE;
2232 }
2233
2234 static void vbi_grabber(priv_t* priv)
2235 {
2236 grabber_ringbuffer_t *rb = priv->vbi_buf;
2237 int i;
2238 unsigned char* buf;
2239 if (!rb || !rb->ringbuffer)
2240 return;
2241
2242 buf=calloc(1,rb->blocksize);
2243 for(i=0; i<23 && rb->count; i++){
2244 memcpy(buf,rb->ringbuffer[rb->head],rb->blocksize);
2245 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_DECODE_PAGE,&buf);
2246 rb->head = (rb->head + 1) % rb->buffersize;
2247 rb->count--;
2248 }
2249 free(buf);
2250 }
2251 #endif //HAVE_TV_TELETEXT
2252
2253 /**
2254 * \brief fills given buffer with video data (usually one frame)
2255 *
2256 * \param priv driver's private data structure
2257 * \param buffer buffer to store data to
2258 * \param len buffer's size in bytes (usually one frame size)
2259 *
2260 * \return frame size if video present, 0 - otherwise
2261 */
2262 static double grab_video_frame(priv_t * priv, char *buffer, int len)
2263 {
2264 int bytes = 0;
2265 int i;
2266 double pts;
2267 grabber_ringbuffer_t *rb = priv->v_buf;
2268
2269 if (!rb || !rb->ringbuffer)
2270 return 1;
2271 if (len < rb->blocksize)
2272 bytes = len;
2273 else
2274 bytes = rb->blocksize;
2275
2276 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2277 rb->count, len);
2278 if(!rb->count){
2279 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
2280 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
2281 if(!rb->count){
2282 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
2283 return 0;
2284 }
2285 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
2286 }
2287 EnterCriticalSection(rb->pMutex);
2288 if(rb->tStart<0)
2289 rb->tStart=rb->dpts[rb->head];
2290 pts=rb->dpts[rb->head]-rb->tStart;
2291 memcpy(buffer, rb->ringbuffer[rb->head], bytes);
2292 rb->head = (rb->head + 1) % rb->buffersize;
2293 rb->count--;
2294 LeaveCriticalSection(rb->pMutex);
2295
2296 #ifdef HAVE_TV_TELETEXT
2297 vbi_grabber(priv);
2298 #endif
2299 return pts;
2300 }
2301
2302 /**
2303 * \brief returns frame size
2304 *
2305 * \param priv driver's private data structure
2306 *
2307 * \return frame size if video present, 0 - otherwise
2308 */
2309 static int get_video_framesize(priv_t * priv)
2310 {
2311 // if(!priv->pmtVideo) return 1; //no video
2312 // return(priv->pmtVideo->lSampleSize);
2313 if (!priv->v_buf)
2314 return 1; //no video
2315 mp_msg(MSGT_TV,MSGL_DBG3,"geT_video_framesize: %d\n",priv->v_buf->blocksize);
2316 return priv->v_buf->blocksize;
2317 }
2318
2319 /**
2320 * \brief calculate audio buffer size
2321 * \param video_buf_size size of video buffer in bytes
2322 * \param video_bitrate video bit rate
2323 * \param audio_bitrate audio bit rate
2324 * \return audio buffer isze in bytes
2325 *
2326 * \remarks length of video buffer and resulted audio buffer calculated in
2327 * seconds will be the same.
2328 */
2329 static inline int audio_buf_size_from_video(int video_buf_size, int video_bitrate, int audio_bitrate)
2330 {
2331 int audio_buf_size = audio_bitrate * (video_buf_size / video_bitrate);
2332 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2333 audio_bitrate,video_buf_size,video_bitrate,audio_buf_size);
2334 return audio_buf_size;
2335 }
2336
2337 /**
2338 * \brief playback/capture real start
2339 *
2340 * \param priv driver's private data structure
2341 *
2342 * \return 1 if success, 0 - otherwise
2343 *
2344 * TODO: move some code from init() here
2345 */
2346 static int start(priv_t * priv)
2347 {
2348 HRESULT hr;
2349
2350 if (priv->pVideoStreamConfig) {
2351 hr = OLE_CALL_ARGS(priv->pVideoStreamConfig, SetFormat, priv->pmtVideo);
2352 if (FAILED(hr)) {
2353 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectVideoFormat, (unsigned int)hr);
2354 }
2355 }
2356
2357 if (!priv->immediate_mode && priv->pAudioStreamConfig) {
2358 hr = OLE_CALL_ARGS(priv->pAudioStreamConfig, SetFormat,
2359 priv->pmtAudio);
2360 if (FAILED(hr)) {
2361 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectAudioFormat, (unsigned int)hr);
2362 }
2363 }
2364
2365 priv->v_buf=calloc(1,sizeof(grabber_ringbuffer_t));
2366
2367 if (priv->tv_param->buffer_size >= 0) {
2368 priv->v_buf->buffersize = priv->tv_param->buffer_size;
2369 } else {
2370 priv->v_buf->buffersize = 16;
2371 }
2372
2373 priv->v_buf->buffersize *= 1024 * 1024;
2374 hr=build_sub_graph(priv, priv->pVideoFilter, priv->v_buf, priv->pmtVideo,&PIN_CATEGORY_CAPTURE);
2375 if(FAILED(hr)){
2376 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVideoSubGraph,(unsigned int)hr);
2377 return 0;
2378 }
2379 if(priv->pmtAudio && !priv->immediate_mode){
2380 priv->a_buf=calloc(1,sizeof(grabber_ringbuffer_t));
2381
2382 /* let the audio buffer be the same size (in seconds) than video one */
2383 priv->a_buf->buffersize=audio_buf_size_from_video(
2384 priv->v_buf->buffersize,
2385 (((VIDEOINFOHEADER *) priv->pmtVideo->pbFormat)->dwBitRate),
2386 (((WAVEFORMATEX *) (priv->pmtAudio->pbFormat))->nAvgBytesPerSec));
2387
2388 hr=build_sub_graph(priv, priv->pAudioFilter, priv->a_buf,priv->pmtAudio,&PIN_CATEGORY_CAPTURE);
2389 if(FAILED(hr)){
2390 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildAudioSubGraph,(unsigned int)hr);
2391 return 0;
2392 }
2393 }
2394
2395 #ifdef HAVE_TV_TELETEXT
2396 if(priv->tv_param->tdevice)
2397 {
2398 priv->vbi_buf=calloc(1,sizeof(grabber_ringbuffer_t));
2399 init_ringbuffer(priv->vbi_buf,24,priv->tsp.bufsize);
2400
2401 priv->pmtVBI=calloc(1,sizeof(AM_MEDIA_TYPE));
2402 priv->pmtVBI->majortype=MEDIATYPE_VBI;
2403 hr=build_sub_graph(priv, priv->pVideoFilter, priv->vbi_buf,priv->pmtVBI,&PIN_CATEGORY_VBI);
2404 if(FAILED(hr)){
2405 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVBISubGraph,(unsigned int)hr);
2406 return 0;
2407 }
2408 }
2409 #endif
2410 /*
2411 Graph is ready to capture. Starting graph.
2412 */
2413 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
2414 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause 10sec\n");
2415 usec_sleep(10000000);
2416 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause end\n");
2417 }
2418 if (!priv->pMediaControl) {
2419 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)E_POINTER);
2420 return 0;
2421 }
2422 hr = OLE_CALL(priv->pMediaControl, Run);
2423 if (FAILED(hr)) {
2424 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableStartGraph, (unsigned int)hr);
2425 return 0;
2426 }
2427 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Graph is started.\n");
2428 priv->state = 1;
2429
2430 return (1);
2431 }
2432
2433 /**
2434 * \brief driver initialization
2435 *
2436 * \param priv driver's private data structure
2437 *
2438 * \return 1 if success, 0 - otherwise
2439 */
2440 static int init(priv_t * priv)
2441 {
2442 HRESULT hr;
2443 int result = 0;
2444 long lInput, lTunerInput;
2445 IEnumFilters *pEnum;
2446 IBaseFilter *pFilter;
2447 IPin *pVPOutPin;
2448
2449 priv->state=0;
2450 CoInitialize(NULL);
2451 do{
2452 hr = CoCreateInstance((GUID *) & CLSID_FilterGraph, NULL,
2453 CLSCTX_INPROC_SERVER, &IID_IGraphBuilder,
2454 (void **) &priv->pGraph);
2455 if(FAILED(hr)){
2456 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr);
2457 break;
2458 }
2459 //Debug
2460 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
2461 AddToRot((IUnknown *) priv->pGraph, &(priv->dwRegister));
2462 }
2463
2464 hr = CoCreateInstance((GUID *) & CLSID_CaptureGraphBuilder2, NULL,
2465 CLSCTX_INPROC_SERVER, &IID_ICaptureGraphBuilder2,
2466 (void **) &priv->pBuilder);
2467 if(FAILED(hr)){
2468 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr);
2469 break;
2470 }
2471
2472 hr = OLE_CALL_ARGS(priv->pBuilder, SetFiltergraph, priv->pGraph);
2473 if(FAILED(hr)){
2474 mp_msg(MSGT_TV,MSGL_ERR, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr);
2475 break;
2476 }
2477
2478 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available video capture devices\n");
2479 priv->pVideoFilter = find_capture_device(priv->dev_index, &CLSID_VideoInputDeviceCategory);
2480 if(!priv->pVideoFilter){
2481 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoVideoCaptureDevice);
2482 break;
2483 }
2484 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->pVideoFilter, NULL);
2485 if(FAILED(hr)){
2486 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
2487 break;
2488 }
2489 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available audio capture devices\n");
2490 if (priv->adev_index != -1) {
2491 priv->pAudioFilter = find_capture_device(priv->adev_index, &CLSID_AudioInputDeviceCategory); //output available audio edevices
2492 if(!priv->pAudioFilter){
2493 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoAudioCaptureDevice);
2494 break;
2495 }
2496
2497 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->pAudioFilter, NULL);
2498 if(FAILED(hr)){
2499 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
2500 break;
2501 }
2502 } else
2503 hr = OLE_QUERYINTERFACE(priv->pVideoFilter, IID_IBaseFilter, priv->pAudioFilter);
2504
2505 hr = OLE_QUERYINTERFACE(priv->pVideoFilter, IID_IAMVideoProcAmp,priv->pVideoProcAmp);
2506 if (FAILED(hr) && hr != E_NOINTERFACE)
2507 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr);
2508
2509 if (hr != S_OK) {
2510 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_VideoAdjustigNotSupported);
2511 priv->pVideoProcAmp = NULL;
2512 }
2513
2514 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2515 &PIN_CATEGORY_CAPTURE,
2516 &MEDIATYPE_Video,
2517 priv->pVideoFilter,
2518 &IID_IAMCrossbar, (void **) &(priv->pCrossbar));
2519 if (FAILED(hr)) {
2520 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_SelectingInputNotSupported);
2521 priv->pCrossbar = NULL;
2522 }
2523
2524 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2525 &PIN_CATEGORY_CAPTURE,
2526 &MEDIATYPE_Video,
2527 priv->pVideoFilter,
2528 &IID_IAMStreamConfig,
2529 (void **) &(priv->pVideoStreamConfig));
2530 if (FAILED(hr)) {
2531 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_ChangingWidthHeightNotSupported);
2532 priv->pVideoStreamConfig = NULL;
2533 }
2534
2535 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2536 &PIN_CATEGORY_CAPTURE,
2537 &MEDIATYPE_Audio,
2538 priv->pAudioFilter,
2539 &IID_IAMStreamConfig,
2540 (void **) &(priv->pAudioStreamConfig));
2541 if (FAILED(hr)) {
2542 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IAMStreamConfig(audio) failed (0x%x).\n", (unsigned int)hr);
2543 priv->pAudioStreamConfig = NULL;
2544 }
2545
2546 if (priv->tv_param->amode >= 0) {
2547 IAMTVAudio *pTVAudio;
2548 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, NULL, NULL,priv->pVideoFilter,&IID_IAMTVAudio, (void *) &pTVAudio);
2549 if (hr == S_OK) {
2550 switch (priv->tv_param->amode) {
2551 case 0:
2552 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_MONO);
2553 break;
2554 case 1:
2555 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_STEREO);
2556 break;
2557 case 2:
2558 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
2559 AMTVAUDIO_MODE_LANG_A);
2560 break;
2561 case 3:
2562 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
2563 AMTVAUDIO_MODE_LANG_B);
2564 break;
2565 }
2566 OLE_RELEASE_SAFE(pTVAudio);
2567 if (FAILED(hr))
2568 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_UnableSetAudioMode, priv->tv_param->amode,(unsigned int)hr);
2569 }
2570 }
2571 /*
2572 Getting available video formats (last pointer in array will be NULL)
2573 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2574 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2575 min/max values.
2576 */
2577
2578 hr = get_available_formats_stream(priv->pVideoStreamConfig,
2579 &MEDIATYPE_Video,
2580 &(priv->arpmtVideo),
2581 (void ***) &(priv->arVideoCaps));
2582 if (FAILED(hr)) {
2583 mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available video formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr);
2584 hr = get_available_formats_pin(priv->pBuilder, priv->pVideoFilter,
2585 &MEDIATYPE_Video,
2586 &(priv->arpmtVideo),
2587 (void ***) &(priv->arVideoCaps));
2588 if(FAILED(hr)){
2589 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableGetsupportedVideoFormats, (unsigned int)hr);
2590 break;
2591 }
2592 }
2593 priv->nVideoFormatUsed = 0;
2594
2595 if (!priv->arpmtVideo[priv->nVideoFormatUsed]
2596 || !extract_video_format(priv->arpmtVideo[priv->nVideoFormatUsed],
2597 &(priv->fcc), &(priv->width),
2598 &(priv->height))) {
2599 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingVideoFormatStruct);
2600 break;
2601 }
2602 priv->pmtVideo = CreateMediaType(priv->arpmtVideo[priv->nVideoFormatUsed]);
2603 /*
2604 Getting available audio formats (last pointer in array will be NULL)
2605 */
2606 hr = get_available_formats_stream(priv->pAudioStreamConfig,
2607 &MEDIATYPE_Audio,
2608 &(priv->arpmtAudio),
2609 (void ***) &(priv->arAudioCaps));
2610 if (FAILED(hr)) {
2611 mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available audio formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr);
2612 hr = get_available_formats_pin(priv->pBuilder, priv->pAudioFilter,
2613 &MEDIATYPE_Audio,
2614 &(priv->arpmtAudio),
2615 (void ***) &(priv->arAudioCaps));
2616 if (FAILED(hr)) {
2617 mp_msg(MSGT_TV,MSGL_WARN, MSGTR_TVI_DS_UnableGetsupportedAudioFormats, (unsigned int)hr);
2618 /*
2619 Following combination will disable sound
2620 */
2621 priv->arpmtAudio = (AM_MEDIA_TYPE **) malloc(sizeof(AM_MEDIA_TYPE *));
2622 priv->arpmtAudio[0] = NULL;
2623 priv->pmtAudio = NULL;
2624 priv->pAudioStreamConfig = NULL;
2625 }
2626 }
2627 /* debug */
2628 {
2629 int i;
2630 for (i = 0; priv->arpmtVideo[i]; i++) {
2631 DisplayMediaType("Available video format", priv->arpmtVideo[i]);
2632 }
2633 for (i = 0; priv->arpmtAudio[i]; i++) {
2634 DisplayMediaType("Available audio format", priv->arpmtAudio[i]);
2635 }
2636 }
2637 priv->nAudioFormatUsed = 0;
2638 if (priv->arpmtAudio[priv->nAudioFormatUsed]) {
2639 priv->pmtAudio = CreateMediaType(priv->arpmtAudio[priv->nAudioFormatUsed]);
2640 if (!extract_audio_format(priv->pmtAudio, &(priv->samplerate), NULL, NULL)) {
2641 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingAudioFormatStruct);
2642 DisplayMediaType("audio format failed",priv->arpmtAudio[priv->nAudioFormatUsed]);
2643 break;
2644 }
2645 }
2646 show_filter_info(priv->pVideoFilter);
2647
2648 hr = OLE_QUERYINTERFACE(priv->pGraph, IID_IMediaControl,priv->pMediaControl);
2649 if(FAILED(hr)){
2650 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)hr);
2651 break;
2652 }
2653 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2654 &PIN_CATEGORY_CAPTURE, NULL,
2655 priv->pVideoFilter,
2656 &IID_IAMTVTuner, (void **) &(priv->pTVTuner));
2657
2658 if (!priv->pTVTuner) {
2659 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr);
2660 }
2661
2662 // shows Tuner capabilities
2663 get_capabilities(priv);
2664
2665 if (priv->pTVTuner) {
2666 hr = OLE_CALL_ARGS(priv->pTVTuner, put_CountryCode,
2667 chanlist2country(priv->tv_param->chanlist));
2668 if(FAILED(hr)){
2669 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr);
2670 break;
2671 }
2672
2673 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Mode, AMTUNER_MODE_TV);
2674 if(FAILED(hr)){
2675 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr);
2676 break;
2677 }
2678
2679 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
2680 if(FAILED(hr)){
2681 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr);
2682 break;
2683 }
2684
2685 /* small hack */
2686 lTunerInput = strstr(priv->tv_param->chanlist, "cable") ? TunerInputCable : TunerInputAntenna;
2687
2688 hr = OLE_CALL_ARGS(priv->pTVTuner, put_InputType, lInput, lTunerInput);
2689 if(FAILED(hr)){
2690 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr);
2691 break;
2692 }
2693
2694 }
2695
2696 /**
2697 for VIVO cards we should check if preview pin is available on video capture device.
2698 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
2699 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
2700 */
2701 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
2702 (IUnknown *) priv->pVideoFilter,
2703 PINDIR_OUTPUT,
2704 &PIN_CATEGORY_VIDEOPORT, NULL, FALSE,
2705 0, (IPin **) & pVPOutPin);
2706 if (SUCCEEDED(hr)) {
2707 hr = OLE_CALL_ARGS(priv->pGraph, Render, pVPOutPin);
2708 OLE_RELEASE_SAFE(pVPOutPin);
2709
2710 if (FAILED(hr)) {
2711 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableTerminateVPPin, (unsigned int)hr);
2712 break;
2713 }
2714 }
2715
2716 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
2717 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
2718 LPVIDEOWINDOW pVideoWindow;
2719 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
2720 if (SUCCEEDED(hr))
2721 {
2722 if(priv->tv_param->hidden_vp_renderer){
2723 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
2724 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
2725 }else
2726 {
2727 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, pFilter);
2728 }
2729 OLE_RELEASE_SAFE(pVideoWindow);
2730 }
2731 OLE_RELEASE_SAFE(pFilter);
2732 }
2733 OLE_RELEASE_SAFE(pEnum);
2734 if(priv->tv_param->system_clock)
2735 {
2736 LPREFERENCECLOCK rc;
2737 IBaseFilter* pBF;
2738 hr = CoCreateInstance((GUID *) & CLSID_SystemClock, NULL,
2739 CLSCTX_INPROC_SERVER, &IID_IReferenceClock,
2740 (void *) &rc);
2741
2742 OLE_QUERYINTERFACE(priv->pBuilder,IID_IBaseFilter,pBF);
2743 OLE_CALL_ARGS(pBF,SetSyncSource,rc);
2744 }
2745 #ifdef HAVE_TV_TELETEXT
2746 if(vbi_get_props(priv,&(priv->tsp))!=TVI_CONTROL_TRUE)
2747 break;
2748 #endif
2749 result = 1;
2750 } while(0);
2751
2752 if (!result){
2753 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_GraphInitFailure);
2754 uninit(priv);
2755 }
2756 return result;
2757 }
2758
2759 /**
2760 * \brief driver uninitialization
2761 *
2762 * \param priv driver's private data structure
2763 *
2764 * \return always 1
2765 */
2766 static int uninit(priv_t * priv)
2767 {
2768 int i;
2769 if (!priv)
2770 return (1);
2771 //Debug
2772 if (priv->dwRegister) {
2773 RemoveFromRot(priv->dwRegister);
2774 }
2775 #ifdef HAVE_TV_TELETEXT
2776 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1);
2777 #endif
2778 //stop audio grabber thread
2779
2780 if (priv->state && priv->pMediaControl) {
2781 OLE_CALL(priv->pMediaControl, Stop);
2782 }
2783 OLE_RELEASE_SAFE(priv->pMediaControl);
2784 priv->state = 0;
2785
2786 if (priv->pGraph) {
2787 if (priv->pVideoFilter)
2788 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->pVideoFilter);
2789 if (priv->pAudioFilter)
2790 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->pAudioFilter);
2791 }
2792 OLE_RELEASE_SAFE(priv->pCrossbar);
2793 OLE_RELEASE_SAFE(priv->pVideoStreamConfig);
2794 OLE_RELEASE_SAFE(priv->pAudioStreamConfig);
2795 OLE_RELEASE_SAFE(priv->pVideoProcAmp);
2796 OLE_RELEASE_SAFE(priv->pVideoFilter);
2797 OLE_RELEASE_SAFE(priv->pAudioFilter);
2798 OLE_RELEASE_SAFE(priv->pGraph);
2799 OLE_RELEASE_SAFE(priv->pBuilder);
2800 OLE_RELEASE_SAFE(priv->pCSGCB);
2801
2802 if (priv->pmtVideo)
2803 DeleteMediaType(priv->pmtVideo);
2804 if (priv->pmtAudio)
2805 DeleteMediaType(priv->pmtAudio);
2806 if (priv->pmtVBI)
2807 DeleteMediaType(priv->pmtVBI);
2808
2809 if (priv->arpmtVideo) {
2810 for (i = 0; priv->arpmtVideo[i]; i++) {
2811 DeleteMediaType(priv->arpmtVideo[i]);
2812 }
2813 free(priv->arpmtVideo);
2814 }
2815 if (priv->arVideoCaps) {
2816 for (i = 0; priv->arVideoCaps[i]; i++) {
2817 free(priv->arVideoCaps[i]);
2818 }
2819 free(priv->arVideoCaps);
2820 }
2821 if (priv->arpmtAudio) {
2822 for (i = 0; priv->arpmtAudio[i]; i++) {
2823 DeleteMediaType(priv->arpmtAudio[i]);
2824 }
2825 free(priv->arpmtAudio);
2826 }
2827 if (priv->arAudioCaps) {
2828 for (i = 0; priv->arAudioCaps[i]; i++) {
2829 free(priv->arAudioCaps[i]);
2830 }
2831 free(priv->arAudioCaps);
2832 }
2833 if (priv->a_buf) {
2834 destroy_ringbuffer(priv->a_buf);
2835 free(priv->a_buf);
2836 priv->a_buf = NULL;
2837 }
2838 if (priv->v_buf) {
2839 destroy_ringbuffer(priv->v_buf);
2840 free(priv->v_buf);
2841 priv->v_buf = NULL;
2842 }
2843 if (priv->vbi_buf) {
2844 destroy_ringbuffer(priv->vbi_buf);
2845 free(priv->vbi_buf);
2846 priv->vbi_buf = NULL;
2847 }
2848 if(priv->freq_table){
2849 priv->freq_table_len=-1;
2850 free(priv->freq_table);
2851 priv->freq_table=NULL;
2852 }
2853 CoUninitialize();
2854 return (1);
2855 }
2856
2857 /**
2858 * \brief driver pre-initialization
2859 *
2860 * \param device string, containing device name in form "x[.y]", where x is video capture device
2861 * (default: 0, first available); y (if given) sets audio capture device
2862 *
2863 * \return 1 if success,0 - otherwise
2864 */
2865 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param)
2866 {
2867 tvi_handle_t *h;
2868 priv_t *priv;
2869 int a;
2870
2871 h = new_handle();
2872 if (!h)
2873 return (NULL);
2874
2875 priv = h->priv;
2876
2877 memset(priv, 0, sizeof(priv_t));
2878 priv->direct_setfreq_call = 1; //first using direct call. if it fails, workaround will be enabled
2879 priv->direct_getfreq_call = 1; //first using direct call. if it fails, workaround will be enabled
2880 priv->adev_index = -1;
2881 priv->freq_table_len=-1;
2882 priv->tv_param=tv_param;
2883
2884 if (tv_param->device) {
2885 if (sscanf(tv_param->device, "%d", &a) == 1) {
2886 priv->dev_index = a;
2887 } else {
2888 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceParam, tv_param->device);
2889 free_handle(h);
2890 return NULL;
2891 }
2892 if (priv->dev_index < 0) {
2893 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceIndex, a);
2894 free_handle(h);
2895 return NULL;
2896 }
2897 }
2898 if (tv_param->adevice) {
2899 if (sscanf(tv_param->adevice, "%d", &a) == 1) {
2900 priv->adev_index = a;
2901 } else {
2902 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceParam, tv_param->adevice);
2903 free_handle(h);
2904 return NULL;
2905 }
2906 if (priv->dev_index < 0) {
2907 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceIndex, a);
2908 free_handle(h);
2909 return NULL;
2910 }
2911 }
2912 return h;
2913 }
2914
2915 /**
2916 * \brief driver's ioctl handler
2917 *
2918 * \param priv driver's private data structure
2919 * \param cmd ioctl command
2920 * \param arg ioct command's parameter
2921 *
2922 * \return TVI_CONTROL_TRUE if success
2923 * \return TVI_CONTROL_FALSE if failure
2924 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
2925 */
2926 static int control(priv_t * priv, int cmd, void *arg)
2927 {
2928 switch (cmd) {
2929 /* need rewrite */
2930 case TVI_CONTROL_VID_SET_FORMAT:
2931 {
2932 int fcc, i;
2933 if (priv->state)
2934 return TVI_CONTROL_FALSE;
2935 fcc = *(int *) arg;
2936
2937 if(!priv->arpmtVideo)
2938 return TVI_CONTROL_FALSE;
2939 for (i = 0; priv->arpmtVideo[i]; i++)
2940 if (check_video_format
2941 (priv->arpmtVideo[i], fcc, priv->width, priv->height))
2942 break;
2943 if (!priv->arpmtVideo[i])
2944 return TVI_CONTROL_FALSE;
2945
2946 priv->nVideoFormatUsed = i;
2947
2948 if (priv->pmtVideo)
2949 DeleteMediaType(priv->pmtVideo);
2950 priv->pmtVideo =
2951 CreateMediaType(priv->arpmtVideo[priv->nVideoFormatUsed]);
2952 DisplayMediaType("VID_SET_FORMAT", priv->pmtVideo);
2953 /*
2954 Setting width & height to preferred by driver values
2955 */
2956 extract_video_format(priv->arpmtVideo[priv->nVideoFormatUsed],
2957 &(priv->fcc), &(priv->width),
2958 &(priv->height));
2959 return TVI_CONTROL_TRUE;
2960 }
2961 case TVI_CONTROL_VID_GET_FORMAT:
2962 {
2963 if(!priv->pmtVideo)
2964 return TVI_CONTROL_FALSE;
2965 DisplayMediaType("VID_GET_FORMAT", priv->pmtVideo);
2966 if (priv->fcc) {
2967 *(int *) arg = priv->fcc;
2968 return (TVI_CONTROL_TRUE);
2969 } else
2970 return (TVI_CONTROL_FALSE);
2971 }
2972 case TVI_CONTROL_VID_SET_WIDTH:
2973 {
2974 VIDEO_STREAM_CONFIG_CAPS *pCaps;
2975 VIDEOINFOHEADER *Vhdr;
2976 int width = *(int *) arg;
2977 if (priv->state)
2978 return TVI_CONTROL_FALSE;
2979
2980 pCaps = priv->arVideoCaps[priv->nVideoFormatUsed];
2981 if (!pCaps)
2982 return TVI_CONTROL_FALSE;
2983 if (width < pCaps->MinOutputSize.cx
2984 || width > pCaps->MaxOutputSize.cx)
2985 return TVI_CONTROL_FALSE;
2986
2987 if (width % pCaps->OutputGranularityX)
2988 return TVI_CONTROL_FALSE;
2989
2990 if (!priv->pmtVideo || !priv->pmtVideo->pbFormat)
2991 return TVI_CONTROL_FALSE;
2992 Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat;
2993 Vhdr->bmiHeader.biWidth = width;
2994 priv->pmtVideo->lSampleSize = Vhdr->bmiHeader.biSizeImage =
2995 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
2996 Vhdr->bmiHeader.biHeight) >> 3;
2997
2998 priv->width = width;
2999
3000 return (TVI_CONTROL_TRUE);
3001 }
3002 case TVI_CONTROL_VID_GET_WIDTH:
3003 {
3004 if (priv->width) {
3005 *(int *) arg = priv->width;
3006 return (TVI_CONTROL_TRUE);
3007 } else
3008 return TVI_CONTROL_FALSE;
3009 }
3010 case TVI_CONTROL_VID_CHK_WIDTH:
3011 {
3012 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3013 int width = *(int *) arg;
3014 pCaps = priv->arVideoCaps[priv->nVideoFormatUsed];
3015 if (!pCaps)
3016 return TVI_CONTROL_FALSE;
3017 if (width < pCaps->MinOutputSize.cx
3018 || width > pCaps->MaxOutputSize.cx)
3019 return TVI_CONTROL_FALSE;
3020
3021 if (width % pCaps->OutputGranularityX)
3022 return TVI_CONTROL_FALSE;
3023 return (TVI_CONTROL_TRUE);
3024 }
3025 case TVI_CONTROL_VID_SET_HEIGHT:
3026 {
3027 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3028 VIDEOINFOHEADER *Vhdr;
3029 int height = *(int *) arg;
3030 if (priv->state)
3031 return TVI_CONTROL_FALSE;
3032
3033 pCaps = priv->arVideoCaps[priv->nVideoFormatUsed];
3034 if (!pCaps)
3035 return TVI_CONTROL_FALSE;
3036 if (height < pCaps->MinOutputSize.cy
3037 || height > pCaps->MaxOutputSize.cy)
3038 return TVI_CONTROL_FALSE;
3039
3040 if (height % pCaps->OutputGranularityY)
3041 return TVI_CONTROL_FALSE;
3042
3043 if (!priv->pmtVideo || !priv->pmtVideo->pbFormat)
3044 return TVI_CONTROL_FALSE;
3045 Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat;
3046
3047 if (Vhdr->bmiHeader.biHeight < 0)
3048 Vhdr->bmiHeader.biHeight = -height;
3049 else
3050 Vhdr->bmiHeader.biHeight = height;
3051 priv->pmtVideo->lSampleSize = Vhdr->bmiHeader.biSizeImage =
3052 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
3053 Vhdr->bmiHeader.biHeight) >> 3;
3054
3055 priv->height = height;
3056 return (TVI_CONTROL_TRUE);
3057 }
3058 case TVI_CONTROL_VID_GET_HEIGHT:
3059 {
3060 if (priv->height) {
3061 *(int *) arg = priv->height;
3062 return (TVI_CONTROL_TRUE);
3063 } else
3064 return TVI_CONTROL_FALSE;
3065 }
3066 case TVI_CONTROL_VID_CHK_HEIGHT:
3067 {
3068 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3069 int height = *(int *) arg;
3070 pCaps = priv->arVideoCaps[priv->nVideoFormatUsed];
3071 if (!pCaps)
3072 return TVI_CONTROL_FALSE;
3073 if (height < pCaps->MinOutputSize.cy
3074 || height > pCaps->MaxOutputSize.cy)
3075 return TVI_CONTROL_FALSE;
3076
3077 if (height % pCaps->OutputGranularityY)
3078 return TVI_CONTROL_FALSE;
3079
3080 return (TVI_CONTROL_TRUE);
3081 }
3082 case TVI_CONTROL_IS_AUDIO:
3083 if (!priv->pmtAudio)
3084 return TVI_CONTROL_FALSE;
3085 else
3086 return TVI_CONTROL_TRUE;
3087 case TVI_CONTROL_IS_VIDEO:
3088 return TVI_CONTROL_TRUE;
3089 case TVI_CONTROL_AUD_GET_FORMAT:
3090 {
3091 *(int *) arg = AF_FORMAT_S16_LE;
3092 if (!priv->pmtAudio)
3093 return TVI_CONTROL_FALSE;
3094 else
3095 return TVI_CONTROL_TRUE;
3096 }
3097 case TVI_CONTROL_AUD_GET_CHANNELS:
3098 {
3099 *(int *) arg = priv->channels;
3100 if (!priv->pmtAudio)
3101 return TVI_CONTROL_FALSE;
3102 else
3103 return TVI_CONTROL_TRUE;
3104 }
3105 case TVI_CONTROL_AUD_SET_SAMPLERATE:
3106 {
3107 int i, samplerate;
3108 if (priv->state)
3109 return TVI_CONTROL_FALSE;
3110 if (!priv->arpmtAudio[0])
3111 return TVI_CONTROL_FALSE;
3112
3113 samplerate = *(int *) arg;;
3114
3115 for (i = 0; priv->arpmtAudio[i]; i++)
3116 if (check_audio_format
3117 (priv->arpmtAudio[i], samplerate, 16, priv->channels))
3118 break;
3119 if (!priv->arpmtAudio[i]) {
3120 //request not found. failing back to first available
3121 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_SamplerateNotsupported, samplerate);
3122 i = 0;
3123 }
3124 if (priv->pmtAudio)
3125 DeleteMediaType(priv->pmtAudio);
3126 priv->pmtAudio = CreateMediaType(priv->arpmtAudio[i]);
3127 extract_audio_format(priv->arpmtAudio[i], &(priv->samplerate),
3128 NULL, &(priv->channels));
3129 return TVI_CONTROL_TRUE;
3130 }
3131 case TVI_CONTROL_AUD_GET_SAMPLERATE:
3132 {
3133 *(int *) arg = priv->samplerate;
3134 if (!priv->samplerate)
3135 return TVI_CONTROL_FALSE;
3136 if (!priv->pmtAudio)
3137 return TVI_CONTROL_FALSE;
3138 else
3139 return TVI_CONTROL_TRUE;
3140 }
3141 case TVI_CONTROL_AUD_GET_SAMPLESIZE:
3142 {
3143 WAVEFORMATEX *pWF;
3144 if (!priv->pmtAudio)
3145 return TVI_CONTROL_FALSE;
3146 if (!priv->pmtAudio->pbFormat)
3147 return TVI_CONTROL_FALSE;
3148 pWF = (WAVEFORMATEX *) priv->pmtAudio->pbFormat;
3149 *(int *) arg = pWF->wBitsPerSample / 8;
3150 return TVI_CONTROL_TRUE;
3151 }
3152 case TVI_CONTROL_IS_TUNER:
3153 {
3154 if (!priv->pTVTuner)
3155 return TVI_CONTROL_FALSE;
3156
3157 return (TVI_CONTROL_TRUE);
3158 }
3159 case TVI_CONTROL_TUN_SET_NORM:
3160 {
3161 IAMAnalogVideoDecoder *pVD;
3162 long lAnalogFormat;
3163 int i;
3164 HRESULT hr;
3165
3166 i = *(int *) arg;
3167 i--;
3168 if (i < 0 || i >= tv_available_norms_count)
3169 return TVI_CONTROL_FALSE;
3170 lAnalogFormat = tv_norms[tv_available_norms[i]].index;
3171
3172 hr = OLE_QUERYINTERFACE(priv->pVideoFilter,IID_IAMAnalogVideoDecoder, pVD);
3173 if (hr != S_OK)
3174 return TVI_CONTROL_FALSE;
3175 hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat);
3176 OLE_RELEASE_SAFE(pVD);
3177 if (FAILED(hr))
3178 return (TVI_CONTROL_FALSE);
3179 else
3180 return (TVI_CONTROL_TRUE);
3181 }
3182 case TVI_CONTROL_TUN_GET_NORM:
3183 {
3184 long lAnalogFormat;
3185 int i;
3186 HRESULT hr;
3187 IAMAnalogVideoDecoder *pVD;
3188
3189 hr = OLE_QUERYINTERFACE(priv->pVideoFilter,IID_IAMAnalogVideoDecoder, pVD);
3190 if (hr == S_OK) {
3191 hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat);
3192 OLE_RELEASE_SAFE(pVD);
3193 }
3194
3195 if (FAILED(hr)) { //trying another method
3196 if (!priv->pTVTuner)
3197 return TVI_CONTROL_FALSE;
3198 hr=OLE_CALL_ARGS(priv->pTVTuner, get_TVFormat, &lAnalogFormat);
3199 if (FAILED(hr))
3200 return TVI_CONTROL_FALSE;
3201 }
3202 for (i = 0; i < tv_available_norms_count; i++) {
3203 if (tv_norms[tv_available_norms[i]].index == lAnalogFormat) {
3204 *(int *) arg = i + 1;
3205 return TVI_CONTROL_TRUE;
3206 }
3207 }
3208 return (TVI_CONTROL_FALSE);
3209 }
3210 case TVI_CONTROL_SPC_GET_NORMID:
3211 {
3212 int i;
3213 if (!priv->pTVTuner)
3214 return TVI_CONTROL_FALSE;
3215 for (i = 0; i < tv_available_norms_count; i++) {
3216 if (!strcasecmp
3217 (tv_norms[tv_available_norms[i]].name, (char *) arg)) {
3218 *(int *) arg = i + 1;
3219 return TVI_CONTROL_TRUE;
3220 }
3221 }
3222 return TVI_CONTROL_FALSE;
3223 }
3224 case TVI_CONTROL_SPC_SET_INPUT:
3225 {
3226 return set_crossbar_input(priv, *(int *) arg);
3227 }
3228 case TVI_CONTROL_TUN_GET_FREQ:
3229 {
3230 unsigned long lFreq;
3231 int ret;
3232 if (!priv->pTVTuner)
3233 return TVI_CONTROL_FALSE;
3234
3235 ret = get_frequency(priv, &lFreq);
3236 lFreq = lFreq * 16 / 1000000; //convert from Hz to 1/16 MHz units
3237
3238 *(unsigned long *) arg = lFreq;
3239 return ret;
3240 }
3241 case TVI_CONTROL_TUN_SET_FREQ:
3242 {
3243 unsigned long nFreq = *(unsigned long *) arg;
3244 if (!priv->pTVTuner)
3245 return TVI_CONTROL_FALSE;
3246 //convert to Hz
3247 nFreq = 1000000 * nFreq / 16; //convert from 1/16 MHz units to Hz
3248 return set_frequency(priv, nFreq);
3249 }
3250 case TVI_CONTROL_VID_SET_HUE:
3251 return set_control(priv, VideoProcAmp_Hue, *(int *) arg);
3252 case TVI_CONTROL_VID_GET_HUE:
3253 return get_control(priv, VideoProcAmp_Hue, (int *) arg);
3254 case TVI_CONTROL_VID_SET_CONTRAST:
3255 return set_control(priv, VideoProcAmp_Contrast, *(int *) arg);
3256 case TVI_CONTROL_VID_GET_CONTRAST:
3257 return get_control(priv, VideoProcAmp_Contrast, (int *) arg);
3258 case TVI_CONTROL_VID_SET_SATURATION:
3259 return set_control(priv, VideoProcAmp_Saturation, *(int *) arg);
3260 case TVI_CONTROL_VID_GET_SATURATION:
3261 return get_control(priv, VideoProcAmp_Saturation, (int *) arg);
3262 case TVI_CONTROL_VID_SET_BRIGHTNESS:
3263 return set_control(priv, VideoProcAmp_Brightness, *(int *) arg);
3264 case TVI_CONTROL_VID_GET_BRIGHTNESS:
3265 return get_control(priv, VideoProcAmp_Brightness, (int *) arg);
3266
3267 case TVI_CONTROL_VID_GET_FPS:
3268 {
3269 VIDEOINFOHEADER *Vhdr;
3270 if (!priv->pmtVideo)
3271 return TVI_CONTROL_FALSE;
3272 if (!priv->pmtVideo->pbFormat)
3273 return TVI_CONTROL_FALSE;
3274 Vhdr = (VIDEOINFOHEADER *) priv->pmtVideo->pbFormat;
3275 *(float *) arg =
3276 (1.0 * Vhdr->dwBitRate) / Vhdr->bmiHeader.biSizeImage;
3277 return TVI_CONTROL_TRUE;
3278 }
3279 case TVI_CONTROL_IMMEDIATE:
3280 priv->immediate_mode = 1;
3281 return TVI_CONTROL_TRUE;
3282 #ifdef HAVE_TV_TELETEXT
3283 case TVI_CONTROL_VBI_INIT:
3284 {
3285 void* ptr;
3286 ptr=&(priv->tsp);
3287 if(teletext_control(NULL,TV_VBI_CONTROL_START,&ptr)==TVI_CONTROL_TRUE)
3288 priv->priv_vbi=ptr;
3289 else
3290 priv->priv_vbi=NULL;
3291 return TVI_CONTROL_TRUE;
3292 }
3293 default:
3294 return teletext_control(priv->priv_vbi,cmd,arg);
3295 #endif
3296 }
3297 return (TVI_CONTROL_UNKNOWN);
3298 }