core: Clean up move-to-next-file logic
[mplayer.git] / stream / tvi_dshow.c
blob438ce7288f81c86752a71a7ba9581ff66bb7cd1a
1 /*
2 * TV support under Win32
4 * (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>
6 * Based on tvi_dummy.c with help of tv.c, tvi_v4l2.c code.
8 * This file is part of MPlayer.
10 * MPlayer is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * MPlayer is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * WARNING: This is alpha code!
28 * Abilities:
29 * * Watching TV under Win32 using WDM Capture driver and DirectShow
30 * * Grabbing synchronized audio/video with mencoder (synchronization is beeing done by DirectShow)
31 * * If device driver provides IAMStreamConfig interface, user can choose width/height with "-tv height=<h>:width=<w>"
32 * * Adjusting BRIGHTNESS,HUE,SATURATION,CONTRAST if supported by device
33 * * Selecting Tuner,S-Video,... as media source
34 * * User can select used video capture device, passing -tv device=<dev#>
35 * * User can select used audio input, passing -tv audioid=<input#>
37 * options which will not be implemented (probably sometime in future, if possible):
38 * * alsa
39 * * mjpeg
40 * * decimation=<1|2|4>
41 * * quality=<0\-100>
42 * * forceaudio
43 * * forcechan=<1\-2>
44 * * [volume|bass|treble|balance]
46 * Works with:
47 * - LifeView FlyTV Prime 34FM (SAA7134 based) with driver from Ivan Uskov
48 * Partially works with:
49 * - ATI 9200 VIVO based card
50 * - ATI AIW 7500
51 * - nVidia Ti-4400
53 * Known bugs:
54 * * stream goes with 24.93 FPS (NTSC), while reporting 25 FPS (PAL) ?!
55 * * direct set frequency call does not work ('Insufficient Buffer' error)
56 * * audio stream goes with about 1 sample/sec rate when capturing sound from audio card
58 * TODO:
59 * * check audio with small buffer on vivo !!!
60 * * norm for IAMVideoDecoder and for IAMTVtuner - differs !!
61 * * check how to change TVFormat on VIVO card without tuner
62 * * Flip image upside-down for RGB formats.
63 * *
64 * * remove debug sleep()
65 * * Add some notes to methods' parameters
66 * * refactor console messages
67 * * check using header files and keep only needed
68 * * add additional comments to methods' bodies
73 /// \ingroup tvi_dshow
75 #include "config.h"
77 #include <stdio.h>
78 #include "libmpcodecs/img_format.h"
79 #include "libaf/af_format.h"
80 #include "help_mp.h"
81 #include "osdep/timer.h"
84 #include "tv.h"
85 #include "mp_msg.h"
86 #include "frequencies.h"
89 #include "tvi_dshow.h"
91 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param);
94 *---------------------------------------------------------------------------------------
96 * Data structures
98 *---------------------------------------------------------------------------------------
100 /**
101 information about this file
103 const tvi_info_t tvi_info_dshow = {
104 tvi_init_dshow,
105 "DirectShow TV",
106 "dshow",
107 "Vladimir Voroshilov",
108 "Very experimental!! Use with caution"
113 ringbuffer related info
115 typedef struct {
116 CRITICAL_SECTION *pMutex; ///< pointer to critical section (mutex)
117 char **ringbuffer; ///< ringbuffer array
118 double*dpts; ///< samples' timestamps
120 int buffersize; ///< size of buffer in blocks
121 int blocksize; ///< size of individual block
122 int head; ///< index of first valid sample
123 int tail; ///< index of last valid sample
124 int count; ///< count of valid samples in ringbuffer
125 double tStart; ///< pts of first sample (first sample should have pts 0)
126 } grabber_ringbuffer_t;
128 typedef enum { unknown, video, audio, vbi } stream_type;
131 CSampleGrabberCD definition
133 typedef struct CSampleGrabberCB {
134 ISampleGrabberCBVtbl *lpVtbl;
135 int refcount;
136 GUID interfaces[2];
137 grabber_ringbuffer_t *pbuf;
138 } CSampleGrabberCB;
141 Chain related structure
143 typedef struct {
144 stream_type type; ///< stream type
145 const GUID* majortype; ///< GUID of major mediatype (video/audio/vbi)
146 const GUID* pin_category; ///< pin category (pointer to one of PIN_CATEGORY_*)
148 IBaseFilter *pCaptureFilter; ///< capture device filter
149 IAMStreamConfig *pStreamConfig; ///< for configuring stream
150 ISampleGrabber *pSG; ///< ISampleGrabber interface of SampleGrabber filter
151 IBaseFilter *pSGF; ///< IBaseFilter interface of SampleGrabber filter
152 IPin *pCapturePin; ///< output capture pin
153 IPin *pSGIn; ///< input pin of SampleGrabber filter
155 grabber_ringbuffer_t *rbuf; ///< sample frabber data
156 CSampleGrabberCB* pCSGCB; ///< callback object
158 AM_MEDIA_TYPE *pmt; ///< stream properties.
159 int nFormatUsed; ///< index of used format
160 AM_MEDIA_TYPE **arpmt; ///< available formats
161 void** arStreamCaps; ///< VIDEO_STREAM_CONFIG_CAPS or AUDIO_STREAM_CONFIG_CAPS
162 } chain_t;
164 typedef struct {
165 int dev_index; ///< capture device index in device list (defaul: 0, first available device)
166 int adev_index; ///< audio capture device index in device list (default: -1, not used)
167 int immediate_mode; ///< immediate mode (no sound capture)
168 int state; ///< state: 1-filter graph running, 0-filter graph stopped
169 int direct_setfreq_call; ///< 0-find nearest channels from system channel list(workaround),1-direct call to set frequency
170 int direct_getfreq_call; ///< 0-find frequncy from frequency table (workaround),1-direct call to get frequency
172 int fcc; ///< used video format code (FourCC)
173 int width; ///< picture width (default: auto)
174 int height; ///< picture height (default: auto)
176 int channels; ///< number of audio channels (default: auto)
177 int samplerate; ///< audio samplerate (default: auto)
179 long *freq_table; ///< frequency table (in Hz)
180 int freq_table_len; ///< length of freq table
181 int first_channel; ///< channel number of first entry in freq table
182 int input; ///< used input
184 chain_t* chains[3]; ///< chains' data (0-video, 1-audio, 2-vbi)
186 IAMTVTuner *pTVTuner; ///< interface for tuner device
187 IGraphBuilder *pGraph; ///< filter graph
188 ICaptureGraphBuilder2 *pBuilder; ///< graph builder
189 IMediaControl *pMediaControl; ///< interface for controlling graph (start, stop,...)
190 IAMVideoProcAmp *pVideoProcAmp; ///< for adjusting hue,saturation,etc
191 IAMCrossbar *pCrossbar; ///< for selecting input (Tuner,Composite,S-Video,...)
192 DWORD dwRegister; ///< allow graphedit to connect to our graph
193 void *priv_vbi; ///< private VBI data structure
194 tt_stream_props tsp; ///< data for VBI initialization
196 tv_param_t* tv_param; ///< TV parameters
197 } priv_t;
199 #include "tvi_def.h"
202 country table entry structure (for loading freq table stored in kstvtuner.ax
204 \note
205 structure have to be 2-byte aligned and have 10-byte length!!
207 typedef struct __attribute__((__packed__)) {
208 WORD CountryCode; ///< Country code
209 WORD CableFreqTable; ///< index of resource with frequencies for cable channels
210 WORD BroadcastFreqTable; ///< index of resource with frequencies for broadcast channels
211 DWORD VideoStandard; ///< used video standard
212 } TRCCountryList;
214 information about image formats
216 typedef struct {
217 uint32_t fmt; ///< FourCC
218 const GUID *subtype; ///< DirectShow's subtype
219 int nBits; ///< number of bits
220 int nCompression; ///< complression
221 int tail; ///< number of additional bytes followed VIDEOINFOHEADER structure
222 } img_fmt;
225 *---------------------------------------------------------------------------------------
227 * Methods forward declaration
229 *---------------------------------------------------------------------------------------
231 static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
232 int blocksize);
233 static HRESULT show_filter_info(IBaseFilter * pFilter);
234 #if 0
235 //defined in current MinGW release
236 HRESULT STDCALL GetRunningObjectTable(DWORD, IRunningObjectTable **);
237 HRESULT STDCALL CreateItemMoniker(LPCOLESTR, LPCOLESTR, IMoniker **);
238 #endif
239 static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
240 pbuf);
241 static int set_crossbar_input(priv_t * priv, int input);
242 static int subtype2imgfmt(const GUID * subtype);
245 *---------------------------------------------------------------------------------------
247 * Global constants and variables
249 *---------------------------------------------------------------------------------------
252 lookup tables for physical connector types
254 static const struct {
255 long type;
256 char *name;
257 } tv_physcon_types[]={
258 {PhysConn_Video_Tuner, "Tuner" },
259 {PhysConn_Video_Composite, "Composite" },
260 {PhysConn_Video_SVideo, "S-Video" },
261 {PhysConn_Video_RGB, "RGB" },
262 {PhysConn_Video_YRYBY, "YRYBY" },
263 {PhysConn_Video_SerialDigital, "SerialDigital" },
264 {PhysConn_Video_ParallelDigital, "ParallelDigital"},
265 {PhysConn_Video_VideoDecoder, "VideoDecoder" },
266 {PhysConn_Video_VideoEncoder, "VideoEncoder" },
267 {PhysConn_Video_SCART, "SCART" },
268 {PhysConn_Video_Black, "Blaack" },
269 {PhysConn_Audio_Tuner, "Tuner" },
270 {PhysConn_Audio_Line, "Line" },
271 {PhysConn_Audio_Mic, "Mic" },
272 {PhysConn_Audio_AESDigital, "AESDiital" },
273 {PhysConn_Audio_SPDIFDigital, "SPDIFDigital" },
274 {PhysConn_Audio_AudioDecoder, "AudioDecoder" },
275 {PhysConn_Audio_SCSI, "SCSI" },
276 {PhysConn_Video_SCSI, "SCSI" },
277 {PhysConn_Audio_AUX, "AUX" },
278 {PhysConn_Video_AUX, "AUX" },
279 {PhysConn_Audio_1394, "1394" },
280 {PhysConn_Video_1394, "1394" },
281 {PhysConn_Audio_USB, "USB" },
282 {PhysConn_Video_USB, "USB" },
283 {-1, NULL }
286 static const struct {
287 char *chanlist_name;
288 int country_code;
289 } tv_chanlist2country[]={
290 {"us-bcast", 1},
291 {"russia", 7},
292 {"argentina", 54},
293 {"japan-bcast", 81},
294 {"china-bcast", 86},
295 {"southafrica", 27},
296 {"australia", 61},
297 {"ireland", 353},
298 {"france", 33},
299 {"italy", 39},
300 {"newzealand", 64},
301 //directshow table uses eastern europe freq table for russia
302 {"europe-east", 7},
303 //directshow table uses western europe freq table for germany
304 {"europe-west", 49},
305 /* cable channels */
306 {"us-cable", 1},
307 {"us-cable-hrc", 1},
308 {"japan-cable", 81},
309 //default is USA
310 {NULL, 1}
314 array, contains information about various supported (i hope) image formats
316 static const img_fmt img_fmt_list[] = {
317 {IMGFMT_YUY2, &MEDIASUBTYPE_YUY2, 16, IMGFMT_YUY2, 0},
318 {IMGFMT_YV12, &MEDIASUBTYPE_YV12, 12, IMGFMT_YV12, 0},
319 {IMGFMT_IYUV, &MEDIASUBTYPE_IYUV, 12, IMGFMT_IYUV, 0},
320 {IMGFMT_I420, &MEDIASUBTYPE_I420, 12, IMGFMT_I420, 0},
321 {IMGFMT_UYVY, &MEDIASUBTYPE_UYVY, 16, IMGFMT_UYVY, 0},
322 {IMGFMT_YVYU, &MEDIASUBTYPE_YVYU, 16, IMGFMT_YVYU, 0},
323 {IMGFMT_YVU9, &MEDIASUBTYPE_YVU9, 9, IMGFMT_YVU9, 0},
324 {IMGFMT_BGR32, &MEDIASUBTYPE_RGB32, 32, 0, 0},
325 {IMGFMT_BGR24, &MEDIASUBTYPE_RGB24, 24, 0, 0},
326 {IMGFMT_BGR16, &MEDIASUBTYPE_RGB565, 16, 3, 12},
327 {IMGFMT_BGR15, &MEDIASUBTYPE_RGB555, 16, 3, 12},
328 {0, &GUID_NULL, 0, 0, 0}
331 #define TV_NORMS_COUNT 19
332 static const struct {
333 long index;
334 char *name;
335 } tv_norms[TV_NORMS_COUNT] = {
337 AnalogVideo_NTSC_M, "ntsc-m"}, {
338 AnalogVideo_NTSC_M_J, "ntsc-mj"}, {
339 AnalogVideo_NTSC_433, "ntsc-433"}, {
340 AnalogVideo_PAL_B, "pal-b"}, {
341 AnalogVideo_PAL_D, "pal-d"}, {
342 AnalogVideo_PAL_G, "pal-g"}, {
343 AnalogVideo_PAL_H, "pal-h"}, {
344 AnalogVideo_PAL_I, "pal-i"}, {
345 AnalogVideo_PAL_M, "pal-m"}, {
346 AnalogVideo_PAL_N, "pal-n"}, {
347 AnalogVideo_PAL_60, "pal-60"}, {
348 AnalogVideo_SECAM_B, "secam-b"}, {
349 AnalogVideo_SECAM_D, "secam-d"}, {
350 AnalogVideo_SECAM_G, "secam-g"}, {
351 AnalogVideo_SECAM_H, "secam-h"}, {
352 AnalogVideo_SECAM_K, "secam-k"}, {
353 AnalogVideo_SECAM_K1, "secam-k1"}, {
354 AnalogVideo_SECAM_L, "secam-l"}, {
355 AnalogVideo_SECAM_L1, "secam-l1"}
357 static long tv_available_norms[TV_NORMS_COUNT];
358 static int tv_available_norms_count = 0;
361 static long *tv_available_inputs;
362 static int tv_available_inputs_count = 0;
365 *---------------------------------------------------------------------------------------
367 * Various GUID definitions
369 *---------------------------------------------------------------------------------------
371 /// CLSID definitions (used for CoCreateInstance call)
372 DEFINE_GUID(CLSID_SampleGrabber, 0xC1F400A0, 0x3F08, 0x11d3, 0x9F, 0x0B,
373 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
374 DEFINE_GUID(CLSID_NullRenderer, 0xC1F400A4, 0x3F08, 0x11d3, 0x9F, 0x0B,
375 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37);
376 DEFINE_GUID(CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, 0xBD, 0x3B,
377 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
378 DEFINE_GUID(CLSID_CaptureGraphBuilder2, 0xBF87B6E1, 0x8C27, 0x11d0, 0xB3,
379 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
380 DEFINE_GUID(CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, 0x11d0,
381 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
382 DEFINE_GUID(CLSID_AudioInputDeviceCategory, 0x33d9a762, 0x90c8, 0x11d0,
383 0xbd, 0x43, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
384 DEFINE_GUID(CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, 0x9f, 0x53,
385 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
386 DEFINE_GUID(CLSID_SystemClock, 0xe436ebb1, 0x524f, 0x11ce, 0x9f, 0x53,
387 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
388 #ifdef NOT_USED
389 DEFINE_GUID(CLSID_CaptureGraphBuilder, 0xBF87B6E0, 0x8C27, 0x11d0, 0xB3,
390 0xF0, 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
391 DEFINE_GUID(CLSID_VideoPortManager, 0x6f26a6cd, 0x967b, 0x47fd, 0x87, 0x4a,
392 0x7a, 0xed, 0x2c, 0x9d, 0x25, 0xa2);
393 DEFINE_GUID(IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00, 0x20,
394 0xaf, 0x0b, 0xa7, 0x70);
395 DEFINE_GUID(IID_ICaptureGraphBuilder, 0xbf87b6e0, 0x8c27, 0x11d0, 0xb3,
396 0xf0, 0x00, 0xaa, 0x00, 0x37, 0x61, 0xc5);
397 DEFINE_GUID(IID_IFilterGraph, 0x56a8689f, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
398 0x20, 0xaf, 0x0b, 0xa7, 0x70);
399 DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
400 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
401 #endif
403 /// IID definitions (used for QueryInterface call)
404 DEFINE_GUID(IID_IReferenceClock, 0x56a86897, 0x0ad4, 0x11ce, 0xb0, 0x3a,
405 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
406 DEFINE_GUID(IID_IAMBufferNegotiation, 0x56ED71A0, 0xAF5F, 0x11D0, 0xB3, 0xF0,
407 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
408 DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa,
409 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93);
410 DEFINE_GUID(IID_ISampleGrabber, 0x6B652FFF, 0x11FE, 0x4fce, 0x92, 0xAD,
411 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F);
412 DEFINE_GUID(IID_ISampleGrabberCB, 0x0579154A, 0x2B53, 0x4994, 0xB0, 0xD0,
413 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85);
414 DEFINE_GUID(IID_ICaptureGraphBuilder2, 0x93e5a4e0, 0x2d50, 0x11d2, 0xab,
415 0xfa, 0x00, 0xa0, 0xc9, 0xc6, 0xe3, 0x8d);
416 DEFINE_GUID(IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, 0xbd, 0x3b,
417 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86);
418 DEFINE_GUID(IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce, 0xb0, 0x3a,
419 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
420 DEFINE_GUID(IID_IAMVideoProcAmp, 0xC6E13360, 0x30AC, 0x11d0, 0xA1, 0x8C,
421 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
422 DEFINE_GUID(IID_IVideoWindow, 0x56a868b4, 0x0ad4, 0x11ce, 0xb0, 0x3a, 0x00,
423 0x20, 0xaf, 0x0b, 0xa7, 0x70);
424 DEFINE_GUID(IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce, 0xb0, 0x3a,
425 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
426 DEFINE_GUID(IID_IAMTVTuner, 0x211A8766, 0x03AC, 0x11d1, 0x8D, 0x13, 0x00,
427 0xAA, 0x00, 0xBD, 0x83, 0x39);
428 DEFINE_GUID(IID_IAMCrossbar, 0xc6e13380, 0x30ac, 0x11d0, 0xa1, 0x8c, 0x00,
429 0xa0, 0xc9, 0x11, 0x89, 0x56);
430 DEFINE_GUID(IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0, 0xa1, 0x8c,
431 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56);
432 DEFINE_GUID(IID_IAMAudioInputMixer, 0x54C39221, 0x8380, 0x11d0, 0xB3, 0xF0,
433 0x00, 0xAA, 0x00, 0x37, 0x61, 0xC5);
434 DEFINE_GUID(IID_IAMTVAudio, 0x83EC1C30, 0x23D1, 0x11d1, 0x99, 0xE6, 0x00,
435 0xA0, 0xC9, 0x56, 0x02, 0x66);
436 DEFINE_GUID(IID_IAMAnalogVideoDecoder, 0xC6E13350, 0x30AC, 0x11d0, 0xA1,
437 0x8C, 0x00, 0xA0, 0xC9, 0x11, 0x89, 0x56);
438 DEFINE_GUID(IID_IPropertyBag, 0x55272a00, 0x42cb, 0x11ce, 0x81, 0x35, 0x00,
439 0xaa, 0x00, 0x4b, 0xb8, 0x51);
440 DEFINE_GUID(PIN_CATEGORY_CAPTURE, 0xfb6c4281, 0x0353, 0x11d1, 0x90, 0x5f,
441 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
442 DEFINE_GUID(PIN_CATEGORY_VIDEOPORT, 0xfb6c4285, 0x0353, 0x11d1, 0x90, 0x5f,
443 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
444 DEFINE_GUID(PIN_CATEGORY_PREVIEW, 0xfb6c4282, 0x0353, 0x11d1, 0x90, 0x5f,
445 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
446 DEFINE_GUID(PIN_CATEGORY_VBI, 0xfb6c4284, 0x0353, 0x11d1, 0x90, 0x5f,
447 0x00, 0x00, 0xc0, 0xcc, 0x16, 0xba);
448 DEFINE_GUID(PROPSETID_TUNER, 0x6a2e0605, 0x28e4, 0x11d0, 0xa1, 0x8c, 0x00,
449 0xa0, 0xc9, 0x11, 0x89, 0x56);
450 DEFINE_GUID(MEDIATYPE_VBI, 0xf72a76e1, 0xeb0a, 0x11d0, 0xac, 0xe4, 0x00,
451 0x00, 0xc0, 0xcc, 0x16, 0xba);
453 #define INSTANCEDATA_OF_PROPERTY_PTR(x) (((KSPROPERTY*)(x)) + 1)
454 #define INSTANCEDATA_OF_PROPERTY_SIZE(x) (sizeof((x)) - sizeof(KSPROPERTY))
456 #define DEVICE_NAME_MAX_LEN 2000
458 /*---------------------------------------------------------------------------------------
459 * Methods, called only from this file
460 *---------------------------------------------------------------------------------------*/
462 void set_buffer_preference(int nDiv,WAVEFORMATEX* pWF,IPin* pOutPin,IPin* pInPin){
463 ALLOCATOR_PROPERTIES prop;
464 IAMBufferNegotiation* pBN;
465 HRESULT hr;
467 prop.cbAlign = -1;
468 prop.cbBuffer = pWF->nAvgBytesPerSec/nDiv;
469 if (!prop.cbBuffer)
470 prop.cbBuffer = 1;
471 prop.cbBuffer += pWF->nBlockAlign - 1;
472 prop.cbBuffer -= prop.cbBuffer % pWF->nBlockAlign;
473 prop.cbPrefix = -1;
474 prop.cBuffers = -1;
476 hr=OLE_QUERYINTERFACE(pOutPin,IID_IAMBufferNegotiation,pBN);
477 if(FAILED(hr))
478 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pOutPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x\n",(unsigned int)hr);
479 else{
480 hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop);
481 if(FAILED(hr))
482 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow:pOutPin->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr);
483 OLE_RELEASE_SAFE(pBN);
485 hr=OLE_QUERYINTERFACE(pInPin,IID_IAMBufferNegotiation,pBN);
486 if(FAILED(hr))
487 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPin->QueryInterface(IID_IAMBufferNegotiation) Error: 0x%x",(unsigned int)hr);
488 else{
489 hr=OLE_CALL_ARGS(pBN,SuggestAllocatorProperties,&prop);
490 if(FAILED(hr))
491 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: pInPit->SuggestAllocatorProperties Error:0x%x\n",(unsigned int)hr);
492 OLE_RELEASE_SAFE(pBN);
496 *---------------------------------------------------------------------------------------
498 * CSampleGrabberCD class. Used for receiving samples from DirectShow.
500 *---------------------------------------------------------------------------------------
502 /// CSampleGrabberCD destructor
503 static void CSampleGrabberCB_Destroy(CSampleGrabberCB * This)
505 free(This->lpVtbl);
506 free(This);
509 /// CSampleGrabberCD IUnknown interface methods implementation
510 static long STDCALL CSampleGrabberCB_QueryInterface(ISampleGrabberCB *
511 This,
512 const GUID * riid,
513 void **ppvObject)
515 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
516 GUID *r;
517 unsigned int i = 0;
518 Debug printf("CSampleGrabberCB_QueryInterface(%p) called\n", This);
519 if (!ppvObject)
520 return E_POINTER;
521 for (r = me->interfaces;
522 i < sizeof(me->interfaces) / sizeof(me->interfaces[0]); r++, i++)
523 if (!memcmp(r, riid, sizeof(*r))) {
524 OLE_CALL(This, AddRef);
525 *ppvObject = This;
526 return 0;
528 Debug printf("Query failed! (GUID: 0x%x)\n", *(unsigned int *) riid);
529 return E_NOINTERFACE;
532 static long STDCALL CSampleGrabberCB_AddRef(ISampleGrabberCB * This)
534 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
535 Debug printf("CSampleGrabberCB_AddRef(%p) called (ref:%d)\n", This,
536 me->refcount);
537 return ++(me->refcount);
540 static long STDCALL CSampleGrabberCB_Release(ISampleGrabberCB * This)
542 CSampleGrabberCB *me = (CSampleGrabberCB *) This;
543 Debug printf("CSampleGrabberCB_Release(%p) called (new ref:%d)\n",
544 This, me->refcount - 1);
545 if (--(me->refcount) == 0)
546 CSampleGrabberCB_Destroy(me);
547 return 0;
551 HRESULT STDCALL CSampleGrabberCB_BufferCB(ISampleGrabberCB * This,
552 double SampleTime,
553 BYTE * pBuffer, long lBufferLen)
555 CSampleGrabberCB *this = (CSampleGrabberCB *) This;
556 grabber_ringbuffer_t *rb = this->pbuf;
558 if (!lBufferLen)
559 return E_FAIL;
561 if (!rb->ringbuffer) {
562 rb->buffersize /= lBufferLen;
563 if (init_ringbuffer(rb, rb->buffersize, lBufferLen) != S_OK)
564 return E_FAIL;
566 mp_msg(MSGT_TV, MSGL_DBG4,
567 "tvi_dshow: BufferCB(%p): len=%ld ts=%f\n", This, lBufferLen, SampleTime);
568 EnterCriticalSection(rb->pMutex);
569 if (rb->count >= rb->buffersize) {
570 rb->head = (rb->head + 1) % rb->buffersize;
571 rb->count--;
574 memcpy(rb->ringbuffer[rb->tail], pBuffer,
575 lBufferLen < rb->blocksize ? lBufferLen : rb->blocksize);
576 rb->dpts[rb->tail] = SampleTime;
577 rb->tail = (rb->tail + 1) % rb->buffersize;
578 rb->count++;
579 LeaveCriticalSection(rb->pMutex);
581 return S_OK;
584 /// wrapper. directshow does the same when BufferCB callback is requested
585 HRESULT STDCALL CSampleGrabberCB_SampleCB(ISampleGrabberCB * This,
586 double SampleTime,
587 LPMEDIASAMPLE pSample)
589 char* buf;
590 long len;
591 long long tStart,tEnd;
592 HRESULT hr;
593 grabber_ringbuffer_t *rb = ((CSampleGrabberCB*)This)->pbuf;
595 len=OLE_CALL(pSample,GetSize);
596 tStart=tEnd=0;
597 hr=OLE_CALL_ARGS(pSample,GetTime,&tStart,&tEnd);
598 if(FAILED(hr)){
599 return hr;
601 mp_msg(MSGT_TV, MSGL_DBG4,"tvi_dshow: SampleCB(%p): %d/%d %f\n", This,rb->count,rb->buffersize,1e-7*tStart);
602 hr=OLE_CALL_ARGS(pSample,GetPointer,(void*)&buf);
603 if(FAILED(hr)){
604 return hr;
606 hr=CSampleGrabberCB_BufferCB(This,1e-7*tStart,buf,len);
607 return hr;
611 /// main grabbing routine
612 static CSampleGrabberCB *CSampleGrabberCB_Create(grabber_ringbuffer_t *
613 pbuf)
615 CSampleGrabberCB *This = malloc(sizeof(CSampleGrabberCB));
616 if (!This)
617 return NULL;
619 This->lpVtbl = malloc(sizeof(ISampleGrabberVtbl));
620 if (!This->lpVtbl) {
621 CSampleGrabberCB_Destroy(This);
622 return NULL;
624 This->refcount = 1;
625 This->lpVtbl->QueryInterface = CSampleGrabberCB_QueryInterface;
626 This->lpVtbl->AddRef = CSampleGrabberCB_AddRef;
627 This->lpVtbl->Release = CSampleGrabberCB_Release;
628 This->lpVtbl->SampleCB = CSampleGrabberCB_SampleCB;
629 This->lpVtbl->BufferCB = CSampleGrabberCB_BufferCB;
631 This->interfaces[0] = IID_IUnknown;
632 This->interfaces[1] = IID_ISampleGrabberCB;
634 This->pbuf = pbuf;
636 return This;
640 *---------------------------------------------------------------------------------------
642 * ROT related methods (register, unregister)
644 *---------------------------------------------------------------------------------------
646 /**
647 Registering graph in ROT. User will be able to connect to graph from GraphEdit.
649 static HRESULT AddToRot(IUnknown * pUnkGraph, DWORD * pdwRegister)
651 IMoniker *pMoniker;
652 IRunningObjectTable *pROT;
653 WCHAR wsz[256];
654 HRESULT hr;
656 if (FAILED(GetRunningObjectTable(0, &pROT))) {
657 return E_FAIL;
659 wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR) pUnkGraph,
660 GetCurrentProcessId());
661 hr = CreateItemMoniker(L"!", wsz, &pMoniker);
662 if (SUCCEEDED(hr)) {
663 hr = OLE_CALL_ARGS(pROT, Register, ROTFLAGS_REGISTRATIONKEEPSALIVE,
664 pUnkGraph, pMoniker, pdwRegister);
665 OLE_RELEASE_SAFE(pMoniker);
667 OLE_RELEASE_SAFE(pROT);
668 return hr;
671 /// Unregistering graph in ROT
672 static void RemoveFromRot(DWORD dwRegister)
674 IRunningObjectTable *pROT;
675 if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
676 OLE_CALL_ARGS(pROT, Revoke, dwRegister);
677 OLE_RELEASE_SAFE(pROT);
682 *---------------------------------------------------------------------------------------
684 * ringbuffer related methods (init, destroy)
686 *---------------------------------------------------------------------------------------
689 * \brief ringbuffer destroying routine
691 * \param rb pointer to empty (just allocated) ringbuffer structure
693 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
695 static void destroy_ringbuffer(grabber_ringbuffer_t * rb)
697 int i;
699 if (!rb)
700 return;
702 if (rb->ringbuffer) {
703 for (i = 0; i < rb->buffersize; i++)
704 if (rb->ringbuffer[i])
705 free(rb->ringbuffer[i]);
706 free(rb->ringbuffer);
707 rb->ringbuffer = NULL;
709 if (rb->dpts) {
710 free(rb->dpts);
711 rb->dpts = NULL;
713 if (rb->pMutex) {
714 DeleteCriticalSection(rb->pMutex);
715 free(rb->pMutex);
716 rb->pMutex = NULL;
719 rb->blocksize = 0;
720 rb->buffersize = 0;
721 rb->head = 0;
722 rb->tail = 0;
723 rb->count = 0;
727 * \brief ringbuffer initialization
729 * \param rb pointer to empty (just allocated) ringbuffer structure
730 * \param buffersize size of buffer in blocks
731 * \param blocksize size of buffer's block
733 * \return S_OK if success
734 * \return E_OUTOFMEMORY not enough memory
736 * \note routine does not allocates memory for grabber_rinbuffer_s structure
738 static HRESULT init_ringbuffer(grabber_ringbuffer_t * rb, int buffersize,
739 int blocksize)
741 int i;
743 if (!rb)
744 return E_OUTOFMEMORY;
746 rb->buffersize = buffersize < 2 ? 2 : buffersize;
747 rb->blocksize = blocksize;
749 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Capture buffer: %d blocks of %d bytes.\n",
750 rb->buffersize, rb->blocksize);
752 rb->ringbuffer = (char **) malloc(rb->buffersize * sizeof(char *));
753 if (!rb)
754 return E_POINTER;
755 memset(rb->ringbuffer, 0, rb->buffersize * sizeof(char *));
757 for (i = 0; i < rb->buffersize; i++) {
758 rb->ringbuffer[i] = (char *) malloc(rb->blocksize * sizeof(char));
759 if (!rb->ringbuffer[i]) {
760 destroy_ringbuffer(rb);
761 return E_OUTOFMEMORY;
764 rb->dpts = (double*) malloc(rb->buffersize * sizeof(double));
765 if (!rb->dpts) {
766 destroy_ringbuffer(rb);
767 return E_OUTOFMEMORY;
769 rb->head = 0;
770 rb->tail = 0;
771 rb->count = 0;
772 rb->tStart = -1;
773 rb->pMutex = (CRITICAL_SECTION *) malloc(sizeof(CRITICAL_SECTION));
774 if (!rb->pMutex) {
775 destroy_ringbuffer(rb);
776 return E_OUTOFMEMORY;
778 InitializeCriticalSection(rb->pMutex);
779 return S_OK;
783 *---------------------------------------------------------------------------------------
785 * Tuner related methods (frequency, capabilities, etc
787 *---------------------------------------------------------------------------------------
790 * \brief returns string with name for givend PsysCon_* constant
792 * \param lPhysicalType constant from PhysicalConnectorType enumeration
794 * \return pointer to string with apropriate name
796 * \note
797 * Caller should not free returned pointer
799 static char *physcon2str(const long lPhysicalType)
801 int i;
802 for(i=0; tv_physcon_types[i].name; i++)
803 if(tv_physcon_types[i].type==lPhysicalType)
804 return tv_physcon_types[i].name;
805 return "Unknown";
809 * \brief converts MPlayer's chanlist to system country code.
811 * \param chanlist MPlayer's chanlist name
813 * \return system country code
815 * \remarks
816 * After call to IAMTVTuner::put_CountryCode with returned value tuner switches to frequency table used in specified
817 * country (which is usually larger then MPlayer's one, so workaround will work fine).
819 * \todo
820 * Resolve trouble with cable channels (DirectShow's tuners must be switched between broadcast and cable channels modes.
822 static int chanlist2country(char *chanlist)
824 int i;
825 for(i=0; tv_chanlist2country[i].chanlist_name; i++)
826 if (!strcmp(chanlist, tv_chanlist2country[i].chanlist_name))
827 break;
828 return tv_chanlist2country[i].country_code;
832 * \brief loads specified resource from module and return pointer to it
834 * \param hDLL valid module desriptor
835 * \param index index of resource. resource with name "#<index>" will be loaded
837 * \return pointer to loader resource or NULL if error occured
839 static void *GetRC(HMODULE hDLL, int index)
841 char szRCDATA[10];
842 char szName[10];
843 HRSRC hRes;
844 HGLOBAL hTable;
846 snprintf(szRCDATA, 10, "#%d", (int)RT_RCDATA);
847 snprintf(szName, 10, "#%d", index);
849 hRes = FindResource(hDLL, szName, szRCDATA);
850 if (!hRes) {
851 return NULL;
853 hTable = LoadResource(hDLL, hRes);
854 if (!hTable) {
855 return NULL;
857 return LockResource(hTable);
861 * \brief loads frequency table for given country from kstvtune.ax
863 * \param[in] nCountry - country code
864 * \param[in] nInputType (TunerInputCable or TunerInputAntenna)
865 * \param[out] pplFreqTable - address of variable that receives pointer to array, containing frequencies
866 * \param[out] pnLen length of array
867 * \param[out] pnFirst - channel number of first entry in array (nChannelMax)
869 * \return S_OK if success
870 * \return E_POINTER pplFreqTable==NULL || plFirst==NULL || pnLen==NULL
871 * \return E_FAIL error occured during load
873 * \remarks
874 * - array must be freed by caller
875 * - MSDN says that it is not neccessery to unlock or free resource. It will be done after unloading DLL
877 static HRESULT load_freq_table(int nCountry, int nInputType,
878 long **pplFreqTable, int *pnLen,
879 int *pnFirst)
881 HMODULE hDLL;
882 long *plFreqTable;
883 TRCCountryList *pCountryList;
884 int i, index;
886 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table called %d (%d)\n",nCountry,nInputType);
887 /* ASSERT(sizeof(TRCCountryList)==10); // need properly aligned structure */
889 if (!pplFreqTable || !pnFirst || !pnLen)
890 return E_POINTER;
891 if (!nCountry)
892 return E_FAIL;
894 hDLL = LoadLibrary("kstvtune.ax");
895 if (!hDLL) {
896 return E_FAIL;
898 pCountryList = GetRC(hDLL, 9999);
899 if (!pCountryList) {
900 FreeLibrary(hDLL);
901 return E_FAIL;
903 for (i = 0; pCountryList[i].CountryCode != 0; i++)
904 if (pCountryList[i].CountryCode == nCountry)
905 break;
906 if (pCountryList[i].CountryCode == 0) {
907 FreeLibrary(hDLL);
908 return E_FAIL;
910 if (nInputType == TunerInputCable)
911 index = pCountryList[i].CableFreqTable;
912 else
913 index = pCountryList[i].BroadcastFreqTable;
915 plFreqTable = GetRC(hDLL, index); //First element is number of first channel, second - number of last channel
916 if (!plFreqTable) {
917 FreeLibrary(hDLL);
918 return E_FAIL;
920 *pnFirst = plFreqTable[0];
921 *pnLen = (int) (plFreqTable[1] - plFreqTable[0] + 1);
922 *pplFreqTable = (long *) malloc((*pnLen) * sizeof(long));
923 if (!*pplFreqTable) {
924 FreeLibrary(hDLL);
925 return E_FAIL;
927 for (i = 0; i < *pnLen; i++) {
928 (*pplFreqTable)[i] = plFreqTable[i + 2];
930 FreeLibrary(hDLL);
931 return S_OK;
935 * \brief tunes to given frequency through IKsPropertySet call
937 * \param pTVTuner IAMTVTuner interface of capture device
938 * \param lFreq frequency to tune (in Hz)
940 * \return S_OK success
941 * \return apropriate error code otherwise
943 * \note
944 * Due to either bug in driver or error in following code calll to IKsProperty::Set
945 * in this methods always fail with error 0x8007007a.
947 * \todo test code on other machines and an error
949 static HRESULT set_frequency_direct(IAMTVTuner * pTVTuner, long lFreq)
951 HRESULT hr;
952 DWORD dwSupported = 0;
953 DWORD cbBytes = 0;
954 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps;
955 KSPROPERTY_TUNER_FREQUENCY_S frequency;
956 IKsPropertySet *pKSProp;
958 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency_direct called\n");
960 memset(&mode_caps, 0, sizeof(mode_caps));
961 memset(&frequency, 0, sizeof(frequency));
963 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
964 if (FAILED(hr))
965 return hr; //no IKsPropertySet interface
967 mode_caps.Mode = AMTUNER_MODE_TV;
968 hr = OLE_CALL_ARGS(pKSProp, QuerySupported, &PROPSETID_TUNER,
969 KSPROPERTY_TUNER_MODE_CAPS, &dwSupported);
970 if (FAILED(hr)) {
971 OLE_RELEASE_SAFE(pKSProp);
972 return hr;
975 if (!dwSupported & KSPROPERTY_SUPPORT_GET) {
976 OLE_RELEASE_SAFE(pKSProp);
977 return E_FAIL; //PROPSETID_TINER not supported
980 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
981 KSPROPERTY_TUNER_MODE_CAPS,
982 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps),
983 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps),
984 &mode_caps, sizeof(mode_caps), &cbBytes);
986 frequency.Frequency = lFreq;
988 if (mode_caps.Strategy == KS_TUNER_STRATEGY_DRIVER_TUNES)
989 frequency.TuningFlags = KS_TUNER_TUNING_FINE;
990 else
991 frequency.TuningFlags = KS_TUNER_TUNING_EXACT;
993 if (lFreq < mode_caps.MinFrequency || lFreq > mode_caps.MaxFrequency) {
994 OLE_RELEASE_SAFE(pKSProp);
995 return E_FAIL;
998 hr = OLE_CALL_ARGS(pKSProp, Set, &PROPSETID_TUNER,
999 KSPROPERTY_TUNER_FREQUENCY,
1000 INSTANCEDATA_OF_PROPERTY_PTR(&frequency),
1001 INSTANCEDATA_OF_PROPERTY_SIZE(frequency),
1002 &frequency, sizeof(frequency));
1003 if (FAILED(hr)) {
1004 OLE_RELEASE_SAFE(pKSProp);
1005 return hr;
1008 OLE_RELEASE_SAFE(pKSProp);
1010 return S_OK;
1014 * \brief find channel with nearest frequency and set it
1016 * \param priv driver's private data
1017 * \param lFreq frequency in Hz
1019 * \return S_OK if success
1020 * \return E_FAIL if error occured
1022 static HRESULT set_nearest_freq(priv_t * priv, long lFreq)
1024 HRESULT hr;
1025 int i;
1026 long lFreqDiff=-1;
1027 int nChannel;
1028 TunerInputType tunerInput;
1029 long lInput;
1031 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq called\n");
1032 if(priv->freq_table_len == -1 && !priv->freq_table) {
1034 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
1035 if(FAILED(hr)){ //Falling back to 0
1036 lInput=0;
1039 hr = OLE_CALL_ARGS(priv->pTVTuner, get_InputType, lInput, &tunerInput);
1041 if (load_freq_table(chanlist2country(priv->tv_param->chanlist), tunerInput, &(priv->freq_table), &(priv->freq_table_len), &(priv->first_channel)) != S_OK) {//FIXME
1042 priv->freq_table_len=0;
1043 priv->freq_table=NULL;
1044 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableExtractFreqTable);
1045 return E_FAIL;
1047 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_FreqTableLoaded, tunerInput == TunerInputAntenna ? "broadcast" : "cable",
1048 chanlist2country(priv->tv_param->chanlist), priv->freq_table_len);
1051 if (priv->freq_table_len <= 0)
1052 return E_FAIL;
1054 //FIXME: rewrite search algo
1055 nChannel = -1;
1056 for (i = 0; i < priv->freq_table_len; i++) {
1057 if (nChannel == -1 || labs(lFreq - priv->freq_table[i]) < lFreqDiff) {
1058 nChannel = priv->first_channel + i;
1059 lFreqDiff = labs(lFreq - priv->freq_table[i]);
1062 if (nChannel == -1) {
1063 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableFindNearestChannel);
1064 return E_FAIL;
1066 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Channel, nChannel,
1067 AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT);
1068 if (FAILED(hr)) {
1069 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableToSetChannel, (unsigned int)hr);
1070 return E_FAIL;
1072 return S_OK;
1076 * \brief setting frequency. decides whether use direct call/workaround
1078 * \param priv driver's private data
1079 * \param lFreq frequency in Hz
1081 * \return TVI_CONTROL_TRUE if success
1082 * \return TVI_CONTROL_FALSE if error occured
1084 * \todo check for freq boundary
1086 static int set_frequency(priv_t * priv, long lFreq)
1088 HRESULT hr;
1090 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency called\n");
1091 if (!priv->pTVTuner)
1092 return TVI_CONTROL_FALSE;
1093 if (priv->direct_setfreq_call) { //using direct call to set frequency
1094 hr = set_frequency_direct(priv->pTVTuner, lFreq);
1095 if (FAILED(hr)) {
1096 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DirectSetFreqFailed);
1097 priv->direct_setfreq_call = 0;
1100 if (!priv->direct_setfreq_call) {
1101 hr = set_nearest_freq(priv, lFreq);
1103 if (FAILED(hr))
1104 return TVI_CONTROL_FALSE;
1105 #ifdef DEPRECATED
1106 priv->pGrabber->ClearBuffer(priv->pGrabber);
1107 #endif
1108 return TVI_CONTROL_TRUE;
1112 * \brief return current frequency from tuner (in Hz)
1114 * \param pTVTuner IAMTVTuner interface of tuner
1115 * \param plFreq address of variable that receives current frequency
1117 * \return S_OK success
1118 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1119 * \return apropriate error code otherwise
1121 static HRESULT get_frequency_direct(IAMTVTuner * pTVTuner, long *plFreq)
1123 HRESULT hr;
1124 KSPROPERTY_TUNER_STATUS_S TunerStatus;
1125 DWORD cbBytes;
1126 IKsPropertySet *pKSProp;
1127 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency_direct called\n");
1129 if (!plFreq)
1130 return E_POINTER;
1132 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
1133 if (FAILED(hr)) {
1134 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq QueryInterface failed\n");
1135 return hr;
1138 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
1139 KSPROPERTY_TUNER_STATUS,
1140 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus),
1141 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus),
1142 &TunerStatus, sizeof(TunerStatus), &cbBytes);
1143 if (FAILED(hr)) {
1144 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq Get failure\n");
1145 return hr;
1147 *plFreq = TunerStatus.CurrentFrequency;
1148 return S_OK;
1152 * \brief gets current frequency
1154 * \param priv driver's private data structure
1155 * \param plFreq - pointer to long int to store frequency to (in Hz)
1157 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1159 static int get_frequency(priv_t * priv, long *plFreq)
1161 HRESULT hr;
1163 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency called\n");
1165 if (!plFreq || !priv->pTVTuner)
1166 return TVI_CONTROL_FALSE;
1168 if (priv->direct_getfreq_call) { //using direct call to get frequency
1169 hr = get_frequency_direct(priv->pTVTuner, plFreq);
1170 if (FAILED(hr)) {
1171 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_DirectGetFreqFailed);
1172 priv->direct_getfreq_call = 0;
1175 if (!priv->direct_getfreq_call) {
1176 hr=OLE_CALL_ARGS(priv->pTVTuner, get_VideoFrequency, plFreq);
1177 if (FAILED(hr))
1178 return TVI_CONTROL_FALSE;
1181 return TVI_CONTROL_TRUE;
1185 * \brief get tuner capabilities
1187 * \param priv driver's private data
1189 static void get_capabilities(priv_t * priv)
1191 long lAvailableFormats;
1192 HRESULT hr;
1193 int i;
1194 long lInputPins, lOutputPins, lRelated, lPhysicalType;
1195 IEnumPins *pEnum;
1196 char tmp[200];
1197 IPin *pPin = 0;
1198 PIN_DIRECTION ThisPinDir;
1199 PIN_INFO pi;
1200 IAMAudioInputMixer *pIAMixer;
1202 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_capabilities called\n");
1203 if (priv->pTVTuner) {
1205 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_SupportedNorms);
1206 hr = OLE_CALL_ARGS(priv->pTVTuner, get_AvailableTVFormats,
1207 &lAvailableFormats);
1208 if (FAILED(hr))
1209 tv_available_norms_count = 0;
1210 else {
1211 for (i = 0; i < TV_NORMS_COUNT; i++) {
1212 if (lAvailableFormats & tv_norms[i].index) {
1213 tv_available_norms[tv_available_norms_count] = i;
1214 mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
1215 tv_available_norms_count + 1, tv_norms[i].name);
1216 tv_available_norms_count++;
1220 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1222 if (priv->pCrossbar) {
1223 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins,
1224 &lInputPins);
1226 tv_available_inputs = (long *) malloc(sizeof(long) * lInputPins);
1227 tv_available_inputs_count = 0;
1229 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableVideoInputs);
1230 for (i = 0; i < lInputPins; i++) {
1231 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1, i,
1232 &lRelated, &lPhysicalType);
1234 if (lPhysicalType < 0x1000) {
1235 tv_available_inputs[tv_available_inputs_count++] = i;
1236 mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
1237 tv_available_inputs_count - 1,
1238 physcon2str(lPhysicalType));
1241 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1243 set_crossbar_input(priv, 0);
1246 if (priv->adev_index != -1) {
1247 hr = OLE_CALL_ARGS(priv->chains[1]->pCaptureFilter, EnumPins, &pEnum);
1248 if (FAILED(hr))
1249 return;
1250 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableAudioInputs);
1251 i = 0;
1252 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
1253 memset(&pi, 0, sizeof(pi));
1254 memset(tmp, 0, 200);
1255 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
1256 if (ThisPinDir == PINDIR_INPUT) {
1257 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
1258 wtoa(pi.achName, tmp, 200);
1259 OLE_RELEASE_SAFE(pi.pFilter);
1260 mp_msg(MSGT_TV, MSGL_V, " %d=%s", i, tmp);
1261 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
1262 hr = OLE_QUERYINTERFACE(pPin, IID_IAMAudioInputMixer,pIAMixer);
1263 if (SUCCEEDED(hr)) {
1264 if (i == priv->tv_param->audio_id) {
1265 OLE_CALL_ARGS(pIAMixer, put_Enable, TRUE);
1266 if(priv->tv_param->volume>0)
1267 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.01 * priv->tv_param->volume);
1268 #if 0
1269 else
1270 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 1.0);
1271 #endif
1272 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_InputSelected);
1273 } else {
1274 OLE_CALL_ARGS(pIAMixer, put_Enable, FALSE);
1275 #if 0
1276 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.0);
1277 #endif
1279 OLE_RELEASE_SAFE(pIAMixer);
1281 mp_msg(MSGT_TV, MSGL_V, ";");
1282 OLE_RELEASE_SAFE(pPin);
1283 i++;
1286 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1287 OLE_RELEASE_SAFE(pEnum);
1292 *---------------------------------------------------------------------------------------
1294 * Filter related methods
1296 *---------------------------------------------------------------------------------------
1299 * \brief routine for reconnecting two pins with new media type
1300 * \param pGraph IGraphBuilder interface
1301 * \param chan chain data
1302 * \param pmt [in/out] new mediatype for pin connection
1304 * \return S_OK if operation successfult, error code otherwise
1305 * will also return media type of new connection into pmt variable
1307 static HRESULT reconnect_pins(IGraphBuilder *pGraph, chain_t *chain, AM_MEDIA_TYPE *pmt)
1309 AM_MEDIA_TYPE old_mt;
1310 HRESULT hr;
1312 do {
1313 /* save old media type for reconnection in case of error */
1314 hr = OLE_CALL_ARGS(chain->pCapturePin, ConnectionMediaType, &old_mt);
1315 if(FAILED(hr))
1316 return hr;
1318 hr = OLE_CALL(chain->pCapturePin, Disconnect);
1319 if(FAILED(hr))
1320 return hr;
1322 hr = OLE_CALL_ARGS(chain->pSG, SetMediaType, pmt);
1323 if(FAILED(hr))
1324 return hr;
1326 hr = OLE_CALL_ARGS(pGraph, Connect, chain->pCapturePin, chain->pSGIn);
1327 if(FAILED(hr))
1329 OLE_CALL_ARGS(chain->pSG, SetMediaType, &old_mt);
1330 OLE_CALL_ARGS(pGraph, Connect, chain->pCapturePin, chain->pSGIn);
1331 break;
1333 hr = OLE_CALL_ARGS(chain->pCapturePin, ConnectionMediaType, &old_mt);
1335 hr = S_OK;
1336 } while(0);
1338 FreeMediaType(pmt);
1339 CopyMediaType(pmt, &old_mt);
1340 FreeMediaType(&old_mt);
1341 return hr;
1345 * \brief building in graph audio/video capture chain
1347 * \param priv driver's private data
1348 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1349 * \param pbuf ringbuffer data structure
1350 * \param pmt media type for chain (AM_MEDIA_TYPE)
1352 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1354 static HRESULT build_sub_graph(priv_t * priv, chain_t * chain, const GUID* ppin_category)
1356 HRESULT hr;
1357 int nFormatProbed = 0;
1359 IPin *pSGOut;
1360 IPin *pNRIn=NULL;
1362 IBaseFilter *pNR = NULL;
1364 hr=S_OK;
1366 //No supported formats
1367 if(!chain->arpmt[0])
1368 return E_FAIL;
1371 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
1372 (IUnknown *) chain->pCaptureFilter,
1373 PINDIR_OUTPUT, ppin_category,
1374 chain->majortype, FALSE, 0, &chain->pCapturePin);
1375 if(FAILED(hr)){
1376 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr);
1377 break;
1379 /* Addinf SampleGrabber filter for video stream */
1380 hr = CoCreateInstance((GUID *) & CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &chain->pSGF);
1381 if(FAILED(hr)){
1382 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1383 break;
1385 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, chain->pSGF, L"Sample Grabber");
1386 if(FAILED(hr)){
1387 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1388 break;
1390 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) chain->pSGF,PINDIR_INPUT, NULL, NULL, FALSE, 0, &chain->pSGIn);
1391 if(FAILED(hr)){
1392 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr);
1393 break;
1395 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) chain->pSGF,PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pSGOut);
1396 if(FAILED(hr)){
1397 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr);
1398 break;
1401 /* creating ringbuffer for video samples */
1402 chain->pCSGCB = CSampleGrabberCB_Create(chain->rbuf);
1403 if(!chain->pCSGCB){
1404 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY);
1405 break;
1408 /* initializing SampleGrabber filter */
1409 hr = OLE_QUERYINTERFACE(chain->pSGF, IID_ISampleGrabber, chain->pSG);
1410 if(FAILED(hr)){
1411 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1412 break;
1414 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1415 hr = OLE_CALL_ARGS(chain->pSG, SetCallback, (ISampleGrabberCB *) chain->pCSGCB, 0); //we want to receive sample
1417 if(FAILED(hr)){
1418 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1419 break;
1421 hr = OLE_CALL_ARGS(chain->pSG, SetOneShot, FALSE); //... for all frames
1422 if(FAILED(hr)){
1423 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1424 break;
1426 hr = OLE_CALL_ARGS(chain->pSG, SetBufferSamples, FALSE); //... do not buffer samples in sample grabber
1427 if(FAILED(hr)){
1428 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1429 break;
1432 if(priv->tv_param->normalize_audio_chunks && chain->type==audio){
1433 set_buffer_preference(20,(WAVEFORMATEX*)(chain->arpmt[nFormatProbed]->pbFormat),chain->pCapturePin,chain->pSGIn);
1436 for(nFormatProbed=0; chain->arpmt[nFormatProbed]; nFormatProbed++)
1438 DisplayMediaType("Probing format", chain->arpmt[nFormatProbed]);
1439 hr = OLE_CALL_ARGS(chain->pSG, SetMediaType, chain->arpmt[nFormatProbed]); //set desired mediatype
1440 if(FAILED(hr)){
1441 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1442 continue;
1444 /* connecting filters together: VideoCapture --> SampleGrabber */
1445 hr = OLE_CALL_ARGS(priv->pGraph, Connect, chain->pCapturePin, chain->pSGIn);
1446 if(FAILED(hr)){
1447 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr);
1448 continue;
1450 break;
1453 if(!chain->arpmt[nFormatProbed])
1455 mp_msg(MSGT_TV, MSGL_WARN, "tvi_dshow: Unable to negotiate media format\n");
1456 hr = E_FAIL;
1457 break;
1460 hr = OLE_CALL_ARGS(chain->pCapturePin, ConnectionMediaType, chain->pmt);
1461 if(FAILED(hr))
1463 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_GetActualMediatypeFailed, (unsigned int)hr);
1466 if(priv->tv_param->hidden_video_renderer){
1467 IEnumFilters* pEnum;
1468 IBaseFilter* pFilter;
1470 hr=OLE_CALL_ARGS(priv->pBuilder,RenderStream,NULL,NULL,(IUnknown*)chain->pCapturePin,NULL,NULL);
1472 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
1473 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
1474 LPVIDEOWINDOW pVideoWindow;
1475 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
1476 if (SUCCEEDED(hr))
1478 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
1479 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
1480 OLE_RELEASE_SAFE(pVideoWindow);
1482 OLE_RELEASE_SAFE(pFilter);
1484 OLE_RELEASE_SAFE(pEnum);
1485 }else
1487 #if 0
1489 Code below is disabled, because terminating chain with NullRenderer leads to jerky video.
1490 Perhaps, this happens because NullRenderer filter discards each received
1491 frame while discarded frames causes live source filter to dramatically reduce frame rate.
1493 /* adding sink for video stream */
1494 hr = CoCreateInstance((GUID *) & CLSID_NullRenderer, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pNR);
1495 if(FAILED(hr)){
1496 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
1497 break;
1499 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pNR, L"Null Renderer");
1500 if(FAILED(hr)){
1501 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
1502 break;
1504 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pNR,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pNRIn);
1505 if(FAILED(hr)){
1506 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr);
1507 break;
1510 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1512 if(memcmp(&(arpmt[nFormatProbed]->majortype),&MEDIATYPE_VBI,16)){
1513 /* connecting filters together: SampleGrabber --> NullRenderer */
1514 hr = OLE_CALL_ARGS(priv->pGraph, Connect, pSGOut, pNRIn);
1515 if(FAILED(hr)){
1516 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr);
1517 break;
1520 #endif
1523 hr = S_OK;
1524 } while(0);
1526 OLE_RELEASE_SAFE(pSGOut);
1527 OLE_RELEASE_SAFE(pNR);
1528 OLE_RELEASE_SAFE(pNRIn);
1530 return hr;
1534 * \brief configures crossbar for grabbing video stream from given input
1536 * \param priv driver's private data
1537 * \param input index of available video input to get data from
1539 * \return TVI_CONTROL_TRUE success
1540 * \return TVI_CONTROL_FALSE error
1542 static int set_crossbar_input(priv_t * priv, int input)
1544 HRESULT hr;
1545 int i, nVideoDecoder, nAudioDecoder;
1546 long lInput, lInputRelated, lRelated, lPhysicalType, lOutputPins,
1547 lInputPins;
1549 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Configuring crossbar\n");
1550 if (!priv->pCrossbar || input < 0
1551 || input >= tv_available_inputs_count)
1552 return TVI_CONTROL_FALSE;
1554 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, &lInputPins);
1556 lInput = tv_available_inputs[input];
1558 if (lInput < 0 || lInput >= lInputPins)
1559 return TVI_CONTROL_FALSE;
1561 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1 /* input */ , lInput,
1562 &lInputRelated, &lPhysicalType);
1564 nVideoDecoder = nAudioDecoder = -1;
1565 for (i = 0; i < lOutputPins; i++) {
1566 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 0 /*output */ , i,
1567 &lRelated, &lPhysicalType);
1568 if (lPhysicalType == PhysConn_Video_VideoDecoder)
1569 nVideoDecoder = i;
1570 if (lPhysicalType == PhysConn_Audio_AudioDecoder)
1571 nAudioDecoder = i;
1573 if (nVideoDecoder >= 0) {
1574 //connecting given input with video decoder
1575 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nVideoDecoder, lInput);
1576 if (hr != S_OK) {
1577 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputVideoDecoder, (unsigned int)hr);
1578 return TVI_CONTROL_FALSE;
1581 if (nAudioDecoder >= 0 && lInputRelated >= 0) {
1582 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nAudioDecoder,
1583 lInputRelated);
1584 if (hr != S_OK) {
1585 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputAudioDecoder, (unsigned int)hr);
1586 return TVI_CONTROL_FALSE;
1589 return TVI_CONTROL_TRUE;
1593 * \brief adjusts video control (hue,saturation,contrast,brightess)
1595 * \param priv driver's private data
1596 * \param control which control to adjust
1597 * \param value new value for control (0-100)
1599 * \return TVI_CONTROL_TRUE success
1600 * \return TVI_CONTROL_FALSE error
1602 static int set_control(priv_t * priv, int control, int value)
1604 long lMin, lMax, lStepping, lDefault, lFlags, lValue;
1605 HRESULT hr;
1607 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_control called\n");
1608 if (value < -100 || value > 100 || !priv->pVideoProcAmp)
1609 return TVI_CONTROL_FALSE;
1611 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
1612 &lMin, &lMax, &lStepping, &lDefault, &lFlags);
1613 if (FAILED(hr) || lFlags != VideoProcAmp_Flags_Manual)
1614 return TVI_CONTROL_FALSE;
1616 lValue = lMin + (value + 100) * (lMax - lMin) / 200;
1618 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1620 if (lStepping > lMax) {
1621 mp_msg(MSGT_TV, MSGL_DBG3,
1622 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1623 lStepping, lMax,control);
1624 lStepping = 1;
1626 lValue -= lValue % lStepping;
1627 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Set, control, lValue,
1628 VideoProcAmp_Flags_Manual);
1629 if (FAILED(hr))
1630 return TVI_CONTROL_FALSE;
1632 return TVI_CONTROL_TRUE;
1636 * \brief get current value of video control (hue,saturation,contrast,brightess)
1638 * \param priv driver's private data
1639 * \param control which control to adjust
1640 * \param pvalue address of variable thar receives current value
1642 * \return TVI_CONTROL_TRUE success
1643 * \return TVI_CONTROL_FALSE error
1645 static int get_control(priv_t * priv, int control, int *pvalue)
1647 long lMin, lMax, lStepping, lDefault, lFlags, lValue;
1648 HRESULT hr;
1650 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_control called\n");
1651 if (!pvalue || !priv->pVideoProcAmp)
1652 return TVI_CONTROL_FALSE;
1654 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
1655 &lMin, &lMax, &lStepping, &lDefault, &lFlags);
1656 if (FAILED(hr))
1657 return TVI_CONTROL_FALSE;
1658 if (lMin == lMax) {
1659 *pvalue = lMin;
1660 return TVI_CONTROL_TRUE;
1663 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Get, control, &lValue, &lFlags);
1664 if (FAILED(hr))
1665 return TVI_CONTROL_FALSE;
1667 *pvalue = 200 * (lValue - lMin) / (lMax - lMin) - 100;
1669 return TVI_CONTROL_TRUE;
1673 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps
1674 * \param fcc FourCC code for video format
1675 * \param width picture width
1676 * \param height pciture height
1677 * \param fps frames per second (required for bitrate calculation)
1679 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise
1681 static AM_MEDIA_TYPE* create_video_format(int fcc, int width, int height, int fps)
1683 int i;
1684 AM_MEDIA_TYPE mt;
1685 VIDEOINFOHEADER vHdr;
1687 /* Check given fcc in lookup table*/
1688 for(i=0; img_fmt_list[i].fmt && img_fmt_list[i].fmt!=fcc; i++) /* NOTHING */;
1689 if(!img_fmt_list[i].fmt)
1690 return NULL;
1692 memset(&mt, 0, sizeof(AM_MEDIA_TYPE));
1693 memset(&vHdr, 0, sizeof(VIDEOINFOHEADER));
1695 vHdr.bmiHeader.biSize = sizeof(vHdr.bmiHeader);
1696 vHdr.bmiHeader.biWidth = width;
1697 vHdr.bmiHeader.biHeight = height;
1698 //FIXME: is biPlanes required too?
1699 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes;
1700 vHdr.bmiHeader.biBitCount = img_fmt_list[i].nBits;
1701 vHdr.bmiHeader.biCompression = img_fmt_list[i].nCompression;
1702 vHdr.bmiHeader.biSizeImage = width * height * img_fmt_list[i].nBits / 8;
1703 vHdr.dwBitRate = vHdr.bmiHeader.biSizeImage * 8 * fps;
1705 mt.pbFormat = (char*)&vHdr;
1706 mt.cbFormat = sizeof(vHdr);
1708 mt.majortype = MEDIATYPE_Video;
1709 mt.subtype = *img_fmt_list[i].subtype;
1710 mt.formattype = FORMAT_VideoInfo;
1712 mt.bFixedSizeSamples = 1;
1713 mt.bTemporalCompression = 0;
1714 mt.lSampleSize = vHdr.bmiHeader.biSizeImage;
1716 return CreateMediaType(&mt);
1720 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1722 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1723 * \param pfcc address of variable that receives FourCC
1724 * \param pwidth address of variable that receives width
1725 * \param pheight address of variable that recevies height
1727 * \return 1 if data extracted successfully, 0 - otherwise
1729 static int extract_video_format(AM_MEDIA_TYPE * pmt, int *pfcc,
1730 int *pwidth, int *pheight)
1732 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_video_format called\n");
1733 if (!pmt)
1734 return 0;
1735 if (!pmt->pbFormat)
1736 return 0;
1737 if (memcmp(&(pmt->formattype), &FORMAT_VideoInfo, 16) != 0)
1738 return 0;
1739 if (pfcc)
1740 *pfcc = subtype2imgfmt(&(pmt->subtype));
1741 if (pwidth)
1742 *pwidth = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biWidth;
1743 if (pheight)
1744 *pheight = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biHeight;
1745 return 1;
1749 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1751 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1752 * \param pfcc address of variable that receives samplerate
1753 * \param pwidth address of variable that receives number of bits per sample
1754 * \param pheight address of variable that recevies number of channels
1756 * \return 1 if data extracted successfully, 0 - otherwise
1758 static int extract_audio_format(AM_MEDIA_TYPE * pmt, int *psamplerate,
1759 int *pbits, int *pchannels)
1761 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_audio_format called\n");
1762 if (!pmt)
1763 return 0;
1764 if (!pmt->pbFormat)
1765 return 0;
1766 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
1767 return 0;
1768 if (psamplerate)
1769 *psamplerate = ((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec;
1770 if (pbits)
1771 *pbits = ((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample;
1772 if (pchannels)
1773 *pchannels = ((WAVEFORMATEX *) pmt->pbFormat)->nChannels;
1774 return 1;
1778 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1780 * \param pmt pointer to AM_MEDIA_TYPE for check
1781 * \param samplerate audio samplerate
1782 * \param bits bits per sample
1783 * \param channels number of audio channels
1785 * \return 1 if AM_MEDIA_TYPE compatible
1786 * \return 0 if not
1788 static int check_audio_format(AM_MEDIA_TYPE * pmt, int samplerate,
1789 int bits, int channels)
1791 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_audio_format called\n");
1792 if (!pmt)
1793 return 0;
1794 if (memcmp(&(pmt->majortype), &MEDIATYPE_Audio, 16) != 0)
1795 return 0;
1796 if (memcmp(&(pmt->subtype), &MEDIASUBTYPE_PCM, 16) != 0)
1797 return 0;
1798 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
1799 return 0;
1800 if (!pmt->pbFormat)
1801 return 0;
1802 if (((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec != samplerate)
1803 return 0;
1804 if (((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample != bits)
1805 return 0;
1806 if (channels > 0
1807 && ((WAVEFORMATEX *) pmt->pbFormat)->nChannels != channels)
1808 return 0;
1810 return 1;
1814 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1816 * \param pmt pointer to AM_MEDIA_TYPE for check
1817 * \param fcc FourCC (compression)
1818 * \param width width of picture
1819 * \param height height of picture
1821 * \return 1 if AM_MEDIA_TYPE compatible
1822 & \return 0 if not
1824 * \note
1825 * width and height are currently not used
1827 * \todo
1828 * add width/height check
1830 static int check_video_format(AM_MEDIA_TYPE * pmt, int fcc, int width,
1831 int height)
1833 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_video_format called\n");
1834 if (!pmt)
1835 return 0;
1836 if (memcmp(&(pmt->majortype), &MEDIATYPE_Video, 16) != 0)
1837 return 0;
1838 if (subtype2imgfmt(&(pmt->subtype)) != fcc)
1839 return 0;
1840 return 1;
1844 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1846 * \param subtype DirectShow subtype for video format
1848 * \return MPlayer's IMGFMT or 0 if error occured
1850 static int subtype2imgfmt(const GUID * subtype)
1852 int i;
1853 for (i = 0; img_fmt_list[i].fmt; i++) {
1854 if (memcmp(subtype, img_fmt_list[i].subtype, 16) == 0)
1855 return img_fmt_list[i].fmt;
1857 return 0;
1861 * \brief prints filter name and it pins
1863 * \param pFilter - IBaseFilter to get data from
1865 * \return S_OK if success, error code otherwise
1867 static HRESULT show_filter_info(IBaseFilter * pFilter)
1869 char tmp[200];
1870 FILTER_INFO fi;
1871 LPENUMPINS pEnum = 0;
1872 IPin *pPin = 0;
1873 PIN_DIRECTION ThisPinDir;
1874 PIN_INFO pi;
1875 HRESULT hr;
1876 int i;
1878 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: show_filter_info called\n");
1879 memset(&fi, 0, sizeof(fi));
1880 memset(tmp, 0, 200);
1882 OLE_CALL_ARGS(pFilter, QueryFilterInfo, &fi);
1883 OLE_RELEASE_SAFE(fi.pGraph);
1884 wtoa(fi.achName, tmp, 200);
1885 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1886 pFilter, tmp, fi.pGraph);
1887 hr = OLE_CALL_ARGS(pFilter, EnumPins, &pEnum);
1888 if (FAILED(hr))
1889 return hr;
1890 i = 0;
1891 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
1892 memset(&pi, 0, sizeof(pi));
1893 memset(tmp, 0, 200);
1894 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
1895 if (ThisPinDir == PINDIR_OUTPUT) {
1896 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
1897 wtoa(pi.achName, tmp, 200);
1898 OLE_RELEASE_SAFE(pi.pFilter);
1899 mp_msg(MSGT_TV, MSGL_DBG2, " %d=%s", i, tmp);
1900 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
1901 mp_msg(MSGT_TV, MSGL_DBG2, ";");
1902 OLE_RELEASE_SAFE(pPin);
1903 i++;
1906 mp_msg(MSGT_TV, MSGL_DBG2, "\n");
1907 OLE_RELEASE_SAFE(pEnum);
1908 return S_OK;
1912 * \brief gets device's frendly in ANSI encoding
1914 * \param pM IMoniker interface, got in enumeration process
1915 * \param category device category
1917 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1919 static int get_device_name(IMoniker * pM, char *pBuf, int nLen)
1921 HRESULT hr;
1922 VARIANT var;
1923 IPropertyBag *pPropBag;
1924 hr = OLE_CALL_ARGS(pM, BindToStorage, 0, 0, &IID_IPropertyBag,(void *) &pPropBag);
1925 if (FAILED(hr)) {
1926 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Call to BindToStorage failed\n");
1927 return TVI_CONTROL_FALSE;
1929 var.vt = VT_BSTR;
1930 hr = OLE_CALL_ARGS(pPropBag, Read, L"Description", (LPVARIANT) & var,
1931 NULL);
1932 if (FAILED(hr)) {
1933 hr = OLE_CALL_ARGS(pPropBag, Read, L"FriendlyName", (LPVARIANT) & var,
1934 NULL);
1936 OLE_RELEASE_SAFE(pPropBag);
1937 if (SUCCEEDED(hr)) {
1938 wtoa(var.bstrVal, pBuf, nLen);
1939 return TVI_CONTROL_TRUE;
1941 return TVI_CONTROL_FALSE;
1945 * \brief find capture device at given index
1947 * \param index device index to search for (-1 mean only print available)
1948 * \param category device category
1950 * \return IBaseFilter interface for capture device with given index
1952 * Sample values for category:
1953 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1954 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1955 * See DirectShow SDK documentation for other possible values
1957 static IBaseFilter *find_capture_device(int index, REFCLSID category)
1959 IBaseFilter *pFilter = NULL;
1960 ICreateDevEnum *pDevEnum = NULL;
1961 IEnumMoniker *pClassEnum = NULL;
1962 IMoniker *pM;
1963 HRESULT hr;
1964 ULONG cFetched;
1965 int i;
1966 char tmp[DEVICE_NAME_MAX_LEN + 1];
1967 hr = CoCreateInstance((GUID *) & CLSID_SystemDeviceEnum, NULL,
1968 CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum,
1969 (void *) &pDevEnum);
1970 if (FAILED(hr)) {
1971 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create device enumerator\n");
1972 return NULL;
1975 hr = OLE_CALL_ARGS(pDevEnum, CreateClassEnumerator, category, &pClassEnum, 0);
1976 OLE_RELEASE_SAFE(pDevEnum);
1977 if (FAILED(hr)) {
1978 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create class enumerator\n");
1979 return NULL;
1981 if (hr == S_FALSE) {
1982 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: No capture devices found\n");
1983 return NULL;
1986 OLE_CALL(pClassEnum,Reset);
1987 for (i = 0; OLE_CALL_ARGS(pClassEnum, Next, 1, &pM, &cFetched) == S_OK; i++) {
1988 if(get_device_name(pM, tmp, DEVICE_NAME_MAX_LEN)!=TVI_CONTROL_TRUE)
1989 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableGetDeviceName, i);
1990 else
1991 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DeviceName, i, tmp);
1992 if (index != -1 && i == index) {
1993 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_UsingDevice, index, tmp);
1994 hr = OLE_CALL_ARGS(pM, BindToObject, 0, 0, &IID_IBaseFilter,(void *) &pFilter);
1995 if (FAILED(hr))
1996 pFilter = NULL;
1998 OLE_RELEASE_SAFE(pM);
2000 if (index != -1 && !pFilter) {
2001 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_DeviceNotFound,
2002 index);
2004 OLE_RELEASE_SAFE(pClassEnum);
2006 return pFilter;
2010 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
2012 * \praram[in] chain chain data structure
2014 * \return S_OK success
2015 * \return E_POINTER one of parameters is NULL
2016 * \return E_FAIL required size of buffer is unknown for given media type
2017 * \return E_OUTOFMEMORY not enough memory
2018 * \return other error code from called methods
2020 * \remarks
2021 * last items of chain->arpmt and chain->arStreamCaps will be NULL
2023 static HRESULT get_available_formats_stream(chain_t *chain)
2025 AM_MEDIA_TYPE **arpmt;
2026 void **pBuf=NULL;
2028 HRESULT hr;
2029 int i, count, size;
2030 int done;
2032 mp_msg(MSGT_TV, MSGL_DBG4,
2033 "tvi_dshow: get_available_formats_stream called\n");
2035 if (!chain->pStreamConfig)
2036 return E_POINTER;
2038 hr=OLE_CALL_ARGS(chain->pStreamConfig, GetNumberOfCapabilities, &count, &size);
2039 if (FAILED(hr)) {
2040 mp_msg(MSGT_TV, MSGL_DBG4,
2041 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
2042 return hr;
2044 if (chain->type == video){
2045 if (size != sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
2046 mp_msg(MSGT_TV, MSGL_DBG4,
2047 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2048 return E_FAIL;
2050 } else if (chain->type == audio){
2051 if (size != sizeof(AUDIO_STREAM_CONFIG_CAPS)) {
2052 mp_msg(MSGT_TV, MSGL_DBG4,
2053 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2054 return E_FAIL;
2056 } else {
2057 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_stream");
2058 return E_FAIL;
2060 done = 0;
2062 arpmt = (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
2063 if (arpmt) {
2064 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
2066 pBuf = (void **) malloc((count + 1) * sizeof(void *));
2067 if (pBuf) {
2068 memset(pBuf, 0, (count + 1) * sizeof(void *));
2070 for (i = 0; i < count; i++) {
2071 pBuf[i] = malloc(size);
2073 if (!pBuf[i])
2074 break;
2076 hr = OLE_CALL_ARGS(chain->pStreamConfig, GetStreamCaps, i,
2077 &(arpmt[i]), pBuf[i]);
2078 if (FAILED(hr))
2079 break;
2081 if (i == count) {
2082 chain->arpmt = arpmt;
2083 chain->arStreamCaps = pBuf;
2084 done = 1;
2088 if (!done) {
2089 for (i = 0; i < count; i++) {
2090 if (pBuf && pBuf[i])
2091 free(pBuf[i]);
2092 if (arpmt && arpmt[i])
2093 DeleteMediaType(arpmt[i]);
2095 if (pBuf)
2096 free(pBuf);
2097 if (arpmt)
2098 free(arpmt);
2099 if (hr != S_OK) {
2100 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
2101 return hr;
2102 } else
2103 return E_OUTOFMEMORY;
2105 return S_OK;
2109 * \brief returns allocates an array and store available media formats for given pin type to it
2111 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2112 * \param chain chain data structure
2114 * \return S_OK success
2115 * \return E_POINTER one of given pointers is null
2116 * \return apropriate error code otherwise
2118 static HRESULT get_available_formats_pin(ICaptureGraphBuilder2 * pBuilder,
2119 chain_t *chain)
2121 IEnumMediaTypes *pEnum;
2122 int i, count, size;
2123 ULONG cFetched;
2124 AM_MEDIA_TYPE *pmt;
2125 HRESULT hr;
2126 void **pBuf;
2127 AM_MEDIA_TYPE **arpmt; //This will be real array
2128 VIDEO_STREAM_CONFIG_CAPS *pVideoCaps;
2129 AUDIO_STREAM_CONFIG_CAPS *pAudioCaps;
2130 int p1, p2, p3;
2132 mp_msg(MSGT_TV, MSGL_DBG4,
2133 "tvi_dshow: get_available_formats_pin called\n");
2134 if (!pBuilder || !chain->pCaptureFilter)
2135 return E_POINTER;
2137 if (!chain->pCapturePin)
2139 hr = OLE_CALL_ARGS(pBuilder, FindPin,
2140 (IUnknown *) chain->pCaptureFilter,
2141 PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE,
2142 chain->majortype, FALSE, 0, &chain->pCapturePin);
2144 if (!chain->pCapturePin)
2145 return E_POINTER;
2147 if (chain->type == video) {
2148 size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
2149 } else if (chain->type == audio) {
2150 size = sizeof(AUDIO_STREAM_CONFIG_CAPS);
2151 } else {
2152 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_pin");
2153 return E_FAIL;
2156 hr = OLE_CALL_ARGS(chain->pCapturePin, EnumMediaTypes, &pEnum);
2157 if (FAILED(hr)) {
2158 mp_msg(MSGT_TV, MSGL_DBG4,
2159 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2160 return hr;
2162 for (i = 0; OLE_CALL_ARGS(pEnum, Next, 1, &pmt, &cFetched) == S_OK; i++) {
2163 if (!pmt)
2164 break;
2166 OLE_CALL(pEnum,Reset);
2168 count = i;
2169 arpmt =
2170 (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
2171 if (!arpmt)
2172 return E_OUTOFMEMORY;
2173 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
2175 for (i = 0;
2176 i < count
2177 && OLE_CALL_ARGS(pEnum, Next, 1, &(arpmt[i]), &cFetched) == S_OK;
2178 i++);
2180 OLE_RELEASE_SAFE(pEnum);
2183 pBuf = (void **) malloc((count + 1) * sizeof(void *));
2184 if (!pBuf) {
2185 for (i = 0; i < count; i++)
2186 if (arpmt[i])
2187 DeleteMediaType(arpmt[i]);
2188 free(arpmt);
2189 return E_OUTOFMEMORY;
2191 memset(pBuf, 0, (count + 1) * sizeof(void *));
2193 for (i = 0; i < count; i++) {
2194 pBuf[i] = malloc(size);
2195 if (!pBuf[i])
2196 break;
2197 memset(pBuf[i], 0, size);
2199 if (chain->type == video) {
2200 pVideoCaps = (VIDEO_STREAM_CONFIG_CAPS *) pBuf[i];
2201 extract_video_format(arpmt[i], NULL, &p1, &p2);
2202 pVideoCaps->MaxOutputSize.cx = pVideoCaps->MinOutputSize.cx =
2204 pVideoCaps->MaxOutputSize.cy = pVideoCaps->MinOutputSize.cy =
2206 } else {
2207 pAudioCaps = (AUDIO_STREAM_CONFIG_CAPS *) pBuf[i];
2208 extract_audio_format(arpmt[i], &p1, &p2, &p3);
2209 pAudioCaps->MaximumSampleFrequency =
2210 pAudioCaps->MinimumSampleFrequency = p1;
2211 pAudioCaps->MaximumBitsPerSample =
2212 pAudioCaps->MinimumBitsPerSample = p2;
2213 pAudioCaps->MaximumChannels = pAudioCaps->MinimumChannels = p3;
2217 if (i != count) {
2218 for (i = 0; i < count; i++) {
2219 if (arpmt[i])
2220 DeleteMediaType(arpmt[i]);
2221 if (pBuf[i])
2222 free(pBuf[i]);
2224 free(arpmt);
2225 free(pBuf);
2226 return E_OUTOFMEMORY;
2228 chain->arpmt = arpmt;
2229 chain->arStreamCaps = pBuf;
2231 return S_OK;
2235 *---------------------------------------------------------------------------------------
2237 * Public methods
2239 *---------------------------------------------------------------------------------------
2242 * \brief fills given buffer with audio data (usually one block)
2244 * \param priv driver's private data structure
2245 * \param buffer buffer to store data to
2246 * \param len buffer's size in bytes (usually one block size)
2248 * \return audio pts if audio present, 1 - otherwise
2250 static double grab_audio_frame(priv_t * priv, char *buffer, int len)
2252 int bytes = 0;
2253 int i;
2254 double pts;
2255 grabber_ringbuffer_t *rb = priv->chains[1]->rbuf;
2256 grabber_ringbuffer_t *vrb = priv->chains[0]->rbuf;
2258 if (!rb || !rb->ringbuffer)
2259 return 1;
2261 if(vrb && vrb->tStart<0){
2262 memset(buffer,0,len);
2263 return 0;
2265 if(vrb && rb->tStart<0)
2266 rb->tStart=vrb->tStart;
2268 if (len < rb->blocksize)
2269 bytes = len;
2270 else
2271 bytes = rb->blocksize;
2273 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2274 rb->count, len);
2275 if(!rb->count){
2276 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
2277 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
2278 if(!rb->count){
2279 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
2280 return 0;
2282 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
2285 EnterCriticalSection(rb->pMutex);
2286 pts=rb->dpts[rb->head]-rb->tStart;
2287 memcpy(buffer, rb->ringbuffer[rb->head], bytes);
2288 rb->head = (rb->head + 1) % rb->buffersize;
2289 rb->count--;
2290 LeaveCriticalSection(rb->pMutex);
2291 return pts;
2295 * \brief returns audio frame size
2297 * \param priv driver's private data structure
2299 * \return audio block size if audio enabled and 1 - otherwise
2301 static int get_audio_framesize(priv_t * priv)
2303 if (!priv->chains[1]->rbuf)
2304 return 1; //no audio
2305 mp_msg(MSGT_TV,MSGL_DBG3,"get_audio_framesize: %d\n",priv->chains[1]->rbuf->blocksize);
2306 return priv->chains[1]->rbuf->blocksize;
2309 #ifdef CONFIG_TV_TELETEXT
2310 static int vbi_get_props(priv_t* priv,tt_stream_props* ptsp)
2312 if(!priv || !ptsp)
2313 return TVI_CONTROL_FALSE;
2315 //STUBS!!!
2316 ptsp->interlaced=0;
2317 ptsp->offset=256;
2319 ptsp->sampling_rate=27e6;
2320 ptsp->samples_per_line=720;
2322 ptsp->count[0]=16;
2323 ptsp->count[1]=16;
2324 //END STUBS!!!
2325 ptsp->bufsize = ptsp->samples_per_line * (ptsp->count[0] + ptsp->count[1]);
2327 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",
2328 ptsp->sampling_rate,
2329 ptsp->offset,
2330 ptsp->samples_per_line,
2331 ptsp->interlaced?"Yes":"No",
2332 ptsp->count[0],
2333 ptsp->count[1]);
2335 return TVI_CONTROL_TRUE;
2338 static void vbi_grabber(priv_t* priv)
2340 grabber_ringbuffer_t *rb = priv->chains[2]->rbuf;
2341 int i;
2342 unsigned char* buf;
2343 if (!rb || !rb->ringbuffer)
2344 return;
2346 buf=calloc(1,rb->blocksize);
2347 for(i=0; i<23 && rb->count; i++){
2348 memcpy(buf,rb->ringbuffer[rb->head],rb->blocksize);
2349 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_DECODE_PAGE,&buf);
2350 rb->head = (rb->head + 1) % rb->buffersize;
2351 rb->count--;
2353 free(buf);
2355 #endif /* CONFIG_TV_TELETEXT */
2358 * \brief fills given buffer with video data (usually one frame)
2360 * \param priv driver's private data structure
2361 * \param buffer buffer to store data to
2362 * \param len buffer's size in bytes (usually one frame size)
2364 * \return frame size if video present, 0 - otherwise
2366 static double grab_video_frame(priv_t * priv, char *buffer, int len)
2368 int bytes = 0;
2369 int i;
2370 double pts;
2371 grabber_ringbuffer_t *rb = priv->chains[0]->rbuf;
2373 if (!rb || !rb->ringbuffer)
2374 return 1;
2375 if (len < rb->blocksize)
2376 bytes = len;
2377 else
2378 bytes = rb->blocksize;
2380 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2381 rb->count, len);
2382 if(!rb->count){
2383 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
2384 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
2385 if(!rb->count){
2386 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
2387 return 0;
2389 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
2391 EnterCriticalSection(rb->pMutex);
2392 if(rb->tStart<0)
2393 rb->tStart=rb->dpts[rb->head];
2394 pts=rb->dpts[rb->head]-rb->tStart;
2395 memcpy(buffer, rb->ringbuffer[rb->head], bytes);
2396 rb->head = (rb->head + 1) % rb->buffersize;
2397 rb->count--;
2398 LeaveCriticalSection(rb->pMutex);
2400 #ifdef CONFIG_TV_TELETEXT
2401 vbi_grabber(priv);
2402 #endif
2403 return pts;
2407 * \brief returns frame size
2409 * \param priv driver's private data structure
2411 * \return frame size if video present, 0 - otherwise
2413 static int get_video_framesize(priv_t * priv)
2415 // if(!priv->pmtVideo) return 1; //no video
2416 // return priv->pmtVideo->lSampleSize;
2417 if (!priv->chains[0]->rbuf)
2418 return 1; //no video
2419 mp_msg(MSGT_TV,MSGL_DBG3,"geT_video_framesize: %d\n",priv->chains[0]->rbuf->blocksize);
2420 return priv->chains[0]->rbuf->blocksize;
2424 * \brief calculate audio buffer size
2425 * \param video_buf_size size of video buffer in bytes
2426 * \param video_bitrate video bit rate
2427 * \param audio_bitrate audio bit rate
2428 * \return audio buffer isze in bytes
2430 * \remarks length of video buffer and resulted audio buffer calculated in
2431 * seconds will be the same.
2433 static inline int audio_buf_size_from_video(int video_buf_size, int video_bitrate, int audio_bitrate)
2435 int audio_buf_size = audio_bitrate * (video_buf_size / video_bitrate);
2436 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2437 audio_bitrate,video_buf_size,video_bitrate,audio_buf_size);
2438 return audio_buf_size;
2442 * \brief common chain initialization routine
2443 * \param chain chain data structure
2445 * \note pCaptureFilter member should be initialized before call to this routine
2447 static HRESULT init_chain_common(ICaptureGraphBuilder2 *pBuilder, chain_t *chain)
2449 HRESULT hr;
2450 int i;
2452 if(!chain->pCaptureFilter)
2453 return E_POINTER;
2455 show_filter_info(chain->pCaptureFilter);
2457 hr = OLE_CALL_ARGS(pBuilder, FindPin,
2458 (IUnknown *) chain->pCaptureFilter,
2459 PINDIR_OUTPUT, chain->pin_category,
2460 chain->majortype, FALSE, 0, &chain->pCapturePin);
2462 if (FAILED(hr)) {
2463 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr);
2464 return hr;
2467 hr = OLE_CALL_ARGS(pBuilder, FindInterface,
2468 chain->pin_category,
2469 chain->majortype,
2470 chain->pCaptureFilter,
2471 &IID_IAMStreamConfig,
2472 (void **) &(chain->pStreamConfig));
2473 if (FAILED(hr))
2474 chain->pStreamConfig = NULL;
2477 Getting available video formats (last pointer in array will be NULL)
2478 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2479 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2480 min/max values.
2482 hr = get_available_formats_stream(chain);
2483 if (FAILED(hr)) {
2484 mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr);
2485 hr = get_available_formats_pin(pBuilder, chain);
2486 if(FAILED(hr)){
2487 return hr;
2490 chain->nFormatUsed = 0;
2492 //If argument to CreateMediaType is NULL then result will be NULL too.
2493 chain->pmt = CreateMediaType(chain->arpmt[0]);
2495 for (i = 0; chain->arpmt[i]; i++)
2496 DisplayMediaType("Available format", chain->arpmt[i]);
2498 return S_OK;
2501 * \brief build video stream chain in graph
2502 * \param priv private data structure
2504 * \return S_OK if chain was built successfully, apropriate error code otherwise
2506 static HRESULT build_video_chain(priv_t *priv)
2508 HRESULT hr;
2510 if(priv->chains[0]->rbuf)
2511 return S_OK;
2513 if (priv->chains[0]->pStreamConfig) {
2514 hr = OLE_CALL_ARGS(priv->chains[0]->pStreamConfig, SetFormat, priv->chains[0]->pmt);
2515 if (FAILED(hr)) {
2516 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectVideoFormat, (unsigned int)hr);
2520 priv->chains[0]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2521 if(!priv->chains[0]->rbuf)
2522 return E_OUTOFMEMORY;
2524 if (priv->tv_param->buffer_size >= 0) {
2525 priv->chains[0]->rbuf->buffersize = priv->tv_param->buffer_size;
2526 } else {
2527 priv->chains[0]->rbuf->buffersize = 16;
2530 priv->chains[0]->rbuf->buffersize *= 1024 * 1024;
2531 hr=build_sub_graph(priv, priv->chains[0], &PIN_CATEGORY_CAPTURE);
2532 if(FAILED(hr)){
2533 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVideoSubGraph,(unsigned int)hr);
2534 return hr;
2536 return S_OK;
2540 * \brief build audio stream chain in graph
2541 * \param priv private data structure
2543 * \return S_OK if chain was built successfully, apropriate error code otherwise
2545 static HRESULT build_audio_chain(priv_t *priv)
2547 HRESULT hr;
2549 if(priv->chains[1]->rbuf)
2550 return S_OK;
2552 if(priv->immediate_mode)
2553 return S_OK;
2555 if (priv->chains[1]->pStreamConfig) {
2556 hr = OLE_CALL_ARGS(priv->chains[1]->pStreamConfig, SetFormat,
2557 priv->chains[1]->pmt);
2558 if (FAILED(hr)) {
2559 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectAudioFormat, (unsigned int)hr);
2563 if(priv->chains[1]->pmt){
2564 priv->chains[1]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2565 if(!priv->chains[1]->rbuf)
2566 return E_OUTOFMEMORY;
2568 /* let the audio buffer be the same size (in seconds) than video one */
2569 priv->chains[1]->rbuf->buffersize=audio_buf_size_from_video(
2570 priv->chains[0]->rbuf->buffersize,
2571 (((VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat)->dwBitRate),
2572 (((WAVEFORMATEX *) (priv->chains[1]->pmt->pbFormat))->nAvgBytesPerSec));
2574 hr=build_sub_graph(priv, priv->chains[1],&PIN_CATEGORY_CAPTURE);
2575 if(FAILED(hr)){
2576 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildAudioSubGraph,(unsigned int)hr);
2577 return 0;
2580 return S_OK;
2584 * \brief build VBI stream chain in graph
2585 * \param priv private data structure
2587 * \return S_OK if chain was built successfully, apropriate error code otherwise
2589 static HRESULT build_vbi_chain(priv_t *priv)
2591 #ifdef CONFIG_TV_TELETEXT
2592 HRESULT hr;
2594 if(priv->chains[2]->rbuf)
2595 return S_OK;
2597 if(priv->tv_param->tdevice)
2599 priv->chains[2]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2600 if(!priv->chains[2]->rbuf)
2601 return E_OUTOFMEMORY;
2603 init_ringbuffer(priv->chains[2]->rbuf,24,priv->tsp.bufsize);
2605 hr=build_sub_graph(priv, priv->chains[2],&PIN_CATEGORY_VBI);
2606 if(FAILED(hr)){
2607 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVBISubGraph,(unsigned int)hr);
2608 return 0;
2611 #endif
2612 return S_OK;
2616 * \brief playback/capture real start
2618 * \param priv driver's private data structure
2620 * \return 1 if success, 0 - otherwise
2622 * TODO: move some code from init() here
2624 static int start(priv_t * priv)
2626 HRESULT hr;
2628 hr = build_video_chain(priv);
2629 if(FAILED(hr))
2630 return 0;
2632 hr = build_audio_chain(priv);
2633 if(FAILED(hr))
2634 return 0;
2636 hr = build_vbi_chain(priv);
2637 if(FAILED(hr))
2638 return 0;
2641 Graph is ready to capture. Starting graph.
2643 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
2644 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause 10sec\n");
2645 usec_sleep(10000000);
2646 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause end\n");
2648 if (!priv->pMediaControl) {
2649 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)E_POINTER);
2650 return 0;
2652 hr = OLE_CALL(priv->pMediaControl, Run);
2653 if (FAILED(hr)) {
2654 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableStartGraph, (unsigned int)hr);
2655 return 0;
2657 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Graph is started.\n");
2658 priv->state = 1;
2660 return 1;
2664 * \brief driver initialization
2666 * \param priv driver's private data structure
2668 * \return 1 if success, 0 - otherwise
2670 static int init(priv_t * priv)
2672 HRESULT hr;
2673 int result = 0;
2674 long lInput, lTunerInput;
2675 IEnumFilters *pEnum;
2676 IBaseFilter *pFilter;
2677 IPin *pVPOutPin;
2678 int i;
2680 priv->state=0;
2682 CoInitialize(NULL);
2684 for(i=0; i<3;i++)
2685 priv->chains[i] = calloc(1, sizeof(chain_t));
2687 priv->chains[0]->type=video;
2688 priv->chains[0]->majortype=&MEDIATYPE_Video;
2689 priv->chains[0]->pin_category=&PIN_CATEGORY_CAPTURE;
2690 priv->chains[1]->type=audio;
2691 priv->chains[1]->majortype=&MEDIATYPE_Audio;
2692 priv->chains[1]->pin_category=&PIN_CATEGORY_CAPTURE;
2693 priv->chains[2]->type=vbi;
2694 priv->chains[2]->majortype=&MEDIATYPE_VBI;
2695 priv->chains[2]->pin_category=&PIN_CATEGORY_VBI;
2698 hr = CoCreateInstance((GUID *) & CLSID_FilterGraph, NULL,
2699 CLSCTX_INPROC_SERVER, &IID_IGraphBuilder,
2700 (void **) &priv->pGraph);
2701 if(FAILED(hr)){
2702 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr);
2703 break;
2705 //Debug
2706 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
2707 AddToRot((IUnknown *) priv->pGraph, &(priv->dwRegister));
2710 hr = CoCreateInstance((GUID *) & CLSID_CaptureGraphBuilder2, NULL,
2711 CLSCTX_INPROC_SERVER, &IID_ICaptureGraphBuilder2,
2712 (void **) &priv->pBuilder);
2713 if(FAILED(hr)){
2714 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr);
2715 break;
2718 hr = OLE_CALL_ARGS(priv->pBuilder, SetFiltergraph, priv->pGraph);
2719 if(FAILED(hr)){
2720 mp_msg(MSGT_TV,MSGL_ERR, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr);
2721 break;
2724 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available video capture devices\n");
2725 priv->chains[0]->pCaptureFilter = find_capture_device(priv->dev_index, &CLSID_VideoInputDeviceCategory);
2726 if(!priv->chains[0]->pCaptureFilter){
2727 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoVideoCaptureDevice);
2728 break;
2730 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->chains[0]->pCaptureFilter, NULL);
2731 if(FAILED(hr)){
2732 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
2733 break;
2735 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available audio capture devices\n");
2736 if (priv->adev_index != -1) {
2737 priv->chains[1]->pCaptureFilter = find_capture_device(priv->adev_index, &CLSID_AudioInputDeviceCategory); //output available audio edevices
2738 if(!priv->chains[1]->pCaptureFilter){
2739 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoAudioCaptureDevice);
2740 break;
2743 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->chains[1]->pCaptureFilter, NULL);
2744 if(FAILED(hr)){
2745 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
2746 break;
2748 } else
2749 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IBaseFilter, priv->chains[1]->pCaptureFilter);
2751 /* increase refrence counter for capture filter ad store pointer into vbi chain structure too */
2752 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IBaseFilter, priv->chains[2]->pCaptureFilter);
2754 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IAMVideoProcAmp,priv->pVideoProcAmp);
2755 if (FAILED(hr) && hr != E_NOINTERFACE)
2756 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr);
2758 if (hr != S_OK) {
2759 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_VideoAdjustigNotSupported);
2760 priv->pVideoProcAmp = NULL;
2763 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2764 &PIN_CATEGORY_CAPTURE,
2765 priv->chains[0]->majortype,
2766 priv->chains[0]->pCaptureFilter,
2767 &IID_IAMCrossbar, (void **) &(priv->pCrossbar));
2768 if (FAILED(hr)) {
2769 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_SelectingInputNotSupported);
2770 priv->pCrossbar = NULL;
2773 if (priv->tv_param->amode >= 0) {
2774 IAMTVAudio *pTVAudio;
2775 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, NULL, NULL,priv->chains[0]->pCaptureFilter,&IID_IAMTVAudio, (void *) &pTVAudio);
2776 if (hr == S_OK) {
2777 switch (priv->tv_param->amode) {
2778 case 0:
2779 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_MONO);
2780 break;
2781 case 1:
2782 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_STEREO);
2783 break;
2784 case 2:
2785 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
2786 AMTVAUDIO_MODE_LANG_A);
2787 break;
2788 case 3:
2789 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
2790 AMTVAUDIO_MODE_LANG_B);
2791 break;
2793 OLE_RELEASE_SAFE(pTVAudio);
2794 if (FAILED(hr))
2795 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_UnableSetAudioMode, priv->tv_param->amode,(unsigned int)hr);
2799 // Video chain initialization
2800 hr = init_chain_common(priv->pBuilder, priv->chains[0]);
2801 if(FAILED(hr))
2802 break;
2805 Audio chain initialization
2806 Since absent audio stream is not fatal,
2807 at least one NULL pointer should be kept in format arrays
2808 (to avoid another additional check everywhere for array presence).
2810 hr = init_chain_common(priv->pBuilder, priv->chains[1]);
2811 if(FAILED(hr))
2813 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to initialize audio chain (Error:0x%x). Audio disabled\n", (unsigned long)hr);
2814 priv->chains[1]->arpmt=calloc(1, sizeof(AM_MEDIA_TYPE*));
2815 priv->chains[1]->arStreamCaps=calloc(1, sizeof(void*));
2819 VBI chain initialization
2820 Since absent VBI stream is not fatal,
2821 at least one NULL pointer should be kept in format arrays
2822 (to avoid another additional check everywhere for array presence).
2824 hr = init_chain_common(priv->pBuilder, priv->chains[2]);
2825 if(FAILED(hr))
2827 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to initialize VBI chain (Error:0x%x). Teletext disabled\n", (unsigned long)hr);
2828 priv->chains[2]->arpmt=calloc(1, sizeof(AM_MEDIA_TYPE*));
2829 priv->chains[2]->arStreamCaps=calloc(1, sizeof(void*));
2832 if (!priv->chains[0]->pStreamConfig)
2833 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_ChangingWidthHeightNotSupported);
2835 if (!priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed]
2836 || !extract_video_format(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed],
2837 &(priv->fcc), &(priv->width),
2838 &(priv->height))) {
2839 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingVideoFormatStruct);
2840 break;
2843 if (priv->chains[1]->arpmt[priv->chains[1]->nFormatUsed]) {
2844 if (!extract_audio_format(priv->chains[1]->pmt, &(priv->samplerate), NULL, NULL)) {
2845 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingAudioFormatStruct);
2846 DisplayMediaType("audio format failed",priv->chains[1]->arpmt[priv->chains[1]->nFormatUsed]);
2847 break;
2851 hr = OLE_QUERYINTERFACE(priv->pGraph, IID_IMediaControl,priv->pMediaControl);
2852 if(FAILED(hr)){
2853 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)hr);
2854 break;
2856 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2857 &PIN_CATEGORY_CAPTURE, NULL,
2858 priv->chains[0]->pCaptureFilter,
2859 &IID_IAMTVTuner, (void **) &(priv->pTVTuner));
2861 if (!priv->pTVTuner) {
2862 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr);
2865 // shows Tuner capabilities
2866 get_capabilities(priv);
2868 if (priv->pTVTuner) {
2869 hr = OLE_CALL_ARGS(priv->pTVTuner, put_CountryCode,
2870 chanlist2country(priv->tv_param->chanlist));
2871 if(FAILED(hr)){
2872 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr);
2875 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Mode, AMTUNER_MODE_TV);
2876 if(FAILED(hr)){
2877 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr);
2878 break;
2881 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
2882 if(FAILED(hr)){
2883 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr);
2884 break;
2887 /* small hack */
2888 lTunerInput = strstr(priv->tv_param->chanlist, "cable") ? TunerInputCable : TunerInputAntenna;
2890 hr = OLE_CALL_ARGS(priv->pTVTuner, put_InputType, lInput, lTunerInput);
2891 if(FAILED(hr)){
2892 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr);
2893 break;
2899 for VIVO cards we should check if preview pin is available on video capture device.
2900 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
2901 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
2903 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
2904 (IUnknown *) priv->chains[0]->pCaptureFilter,
2905 PINDIR_OUTPUT,
2906 &PIN_CATEGORY_VIDEOPORT, NULL, FALSE,
2907 0, (IPin **) & pVPOutPin);
2908 if (SUCCEEDED(hr)) {
2909 hr = OLE_CALL_ARGS(priv->pGraph, Render, pVPOutPin);
2910 OLE_RELEASE_SAFE(pVPOutPin);
2912 if (FAILED(hr)) {
2913 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableTerminateVPPin, (unsigned int)hr);
2914 break;
2918 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
2919 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
2920 LPVIDEOWINDOW pVideoWindow;
2921 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
2922 if (SUCCEEDED(hr))
2924 if(priv->tv_param->hidden_vp_renderer){
2925 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
2926 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
2927 }else
2929 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, pFilter);
2931 OLE_RELEASE_SAFE(pVideoWindow);
2933 OLE_RELEASE_SAFE(pFilter);
2935 OLE_RELEASE_SAFE(pEnum);
2936 if(priv->tv_param->system_clock)
2938 LPREFERENCECLOCK rc;
2939 IBaseFilter* pBF;
2940 hr = CoCreateInstance((GUID *) & CLSID_SystemClock, NULL,
2941 CLSCTX_INPROC_SERVER, &IID_IReferenceClock,
2942 (void *) &rc);
2944 OLE_QUERYINTERFACE(priv->pBuilder,IID_IBaseFilter,pBF);
2945 OLE_CALL_ARGS(pBF,SetSyncSource,rc);
2947 #ifdef CONFIG_TV_TELETEXT
2948 if(vbi_get_props(priv,&(priv->tsp))!=TVI_CONTROL_TRUE)
2949 break;
2950 #endif
2951 result = 1;
2952 } while(0);
2954 if (!result){
2955 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_GraphInitFailure);
2956 uninit(priv);
2958 return result;
2962 * \brief chain uninitialization
2963 * \param chain chain data structure
2965 static void destroy_chain(chain_t *chain)
2967 int i;
2969 if(!chain)
2970 return;
2972 OLE_RELEASE_SAFE(chain->pStreamConfig);
2973 OLE_RELEASE_SAFE(chain->pCaptureFilter);
2974 OLE_RELEASE_SAFE(chain->pCSGCB);
2975 OLE_RELEASE_SAFE(chain->pCapturePin);
2976 OLE_RELEASE_SAFE(chain->pSGIn);
2977 OLE_RELEASE_SAFE(chain->pSG);
2978 OLE_RELEASE_SAFE(chain->pSGF);
2980 if (chain->pmt)
2981 DeleteMediaType(chain->pmt);
2983 if (chain->arpmt) {
2984 for (i = 0; chain->arpmt[i]; i++) {
2985 DeleteMediaType(chain->arpmt[i]);
2987 free(chain->arpmt);
2990 if (chain->arStreamCaps) {
2991 for (i = 0; chain->arStreamCaps[i]; i++) {
2992 free(chain->arStreamCaps[i]);
2994 free(chain->arStreamCaps);
2997 if (chain->rbuf) {
2998 destroy_ringbuffer(chain->rbuf);
2999 free(chain->rbuf);
3000 chain->rbuf = NULL;
3002 free(chain);
3005 * \brief driver uninitialization
3007 * \param priv driver's private data structure
3009 * \return always 1
3011 static int uninit(priv_t * priv)
3013 int i;
3014 if (!priv)
3015 return 1;
3016 //Debug
3017 if (priv->dwRegister) {
3018 RemoveFromRot(priv->dwRegister);
3020 #ifdef CONFIG_TV_TELETEXT
3021 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1);
3022 #endif
3023 //stop audio grabber thread
3025 if (priv->state && priv->pMediaControl) {
3026 OLE_CALL(priv->pMediaControl, Stop);
3028 OLE_RELEASE_SAFE(priv->pMediaControl);
3029 priv->state = 0;
3031 if (priv->pGraph) {
3032 if (priv->chains[0]->pCaptureFilter)
3033 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->chains[0]->pCaptureFilter);
3034 if (priv->chains[1]->pCaptureFilter)
3035 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->chains[1]->pCaptureFilter);
3037 OLE_RELEASE_SAFE(priv->pCrossbar);
3038 OLE_RELEASE_SAFE(priv->pVideoProcAmp);
3039 OLE_RELEASE_SAFE(priv->pGraph);
3040 OLE_RELEASE_SAFE(priv->pBuilder);
3041 if(priv->freq_table){
3042 priv->freq_table_len=-1;
3043 free(priv->freq_table);
3044 priv->freq_table=NULL;
3047 for(i=0; i<3;i++)
3049 destroy_chain(priv->chains[i]);
3050 priv->chains[i] = NULL;
3052 CoUninitialize();
3053 return 1;
3057 * \brief driver pre-initialization
3059 * \param device string, containing device name in form "x[.y]", where x is video capture device
3060 * (default: 0, first available); y (if given) sets audio capture device
3062 * \return 1 if success,0 - otherwise
3064 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param)
3066 tvi_handle_t *h;
3067 priv_t *priv;
3068 int a;
3070 h = new_handle();
3071 if (!h)
3072 return NULL;
3074 priv = h->priv;
3076 memset(priv, 0, sizeof(priv_t));
3077 priv->direct_setfreq_call = 1; //first using direct call. if it fails, workaround will be enabled
3078 priv->direct_getfreq_call = 1; //first using direct call. if it fails, workaround will be enabled
3079 priv->adev_index = -1;
3080 priv->freq_table_len=-1;
3081 priv->tv_param=tv_param;
3083 if (tv_param->device) {
3084 if (sscanf(tv_param->device, "%d", &a) == 1) {
3085 priv->dev_index = a;
3086 } else {
3087 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceParam, tv_param->device);
3088 free_handle(h);
3089 return NULL;
3091 if (priv->dev_index < 0) {
3092 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceIndex, a);
3093 free_handle(h);
3094 return NULL;
3097 if (tv_param->adevice) {
3098 if (sscanf(tv_param->adevice, "%d", &a) == 1) {
3099 priv->adev_index = a;
3100 } else {
3101 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceParam, tv_param->adevice);
3102 free_handle(h);
3103 return NULL;
3105 if (priv->dev_index < 0) {
3106 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceIndex, a);
3107 free_handle(h);
3108 return NULL;
3111 return h;
3115 * \brief driver's ioctl handler
3117 * \param priv driver's private data structure
3118 * \param cmd ioctl command
3119 * \param arg ioct command's parameter
3121 * \return TVI_CONTROL_TRUE if success
3122 * \return TVI_CONTROL_FALSE if failure
3123 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
3125 static int control(priv_t * priv, int cmd, void *arg)
3127 switch (cmd) {
3128 /* need rewrite */
3129 case TVI_CONTROL_VID_SET_FORMAT:
3131 int fcc, i,j;
3132 void* tmp,*tmp2;
3133 int result = TVI_CONTROL_TRUE;
3135 if (priv->state)
3136 return TVI_CONTROL_FALSE;
3137 fcc = *(int *) arg;
3139 if(!priv->chains[0]->arpmt)
3140 return TVI_CONTROL_FALSE;
3141 for (i = 0; priv->chains[0]->arpmt[i]; i++)
3142 if (check_video_format
3143 (priv->chains[0]->arpmt[i], fcc, priv->width, priv->height))
3144 break;
3145 if (!priv->chains[0]->arpmt[i])
3147 int fps = 0;
3148 VIDEOINFOHEADER* Vhdr = NULL;
3149 AM_MEDIA_TYPE *pmt;
3151 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: will try also use undeclared video format: %dx%d, %s\n",priv->width, priv->height, vo_format_name(fcc));
3153 if (priv->chains[0]->arpmt[0])
3154 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->arpmt[0]->pbFormat;
3156 if(Vhdr && Vhdr->bmiHeader.biSizeImage)
3157 fps = Vhdr->dwBitRate / (8 * Vhdr->bmiHeader.biSizeImage);
3159 pmt=create_video_format(fcc, priv->width, priv->height, fps);
3160 if(!pmt)
3162 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to create AM_MEDIA_TYPE structure for given format\n");
3163 return TVI_CONTROL_FALSE;
3165 priv->chains[0]->arpmt=realloc(priv->chains[0]->arpmt, (i+2)*sizeof(AM_MEDIA_TYPE*));
3166 priv->chains[0]->arpmt[i+1] = NULL;
3167 priv->chains[0]->arpmt[i] = pmt;
3169 priv->chains[0]->arStreamCaps=realloc(priv->chains[0]->arStreamCaps, (i+2)*sizeof(void*));
3170 priv->chains[0]->arpmt[i+1] = NULL;
3172 result = TVI_CONTROL_FALSE;
3176 tmp=priv->chains[0]->arpmt[i];
3177 tmp2=priv->chains[0]->arStreamCaps[i];
3178 for(j=i; j>0; j--)
3180 priv->chains[0]->arpmt[j] = priv->chains[0]->arpmt[j-1];
3181 priv->chains[0]->arStreamCaps[j] = priv->chains[0]->arStreamCaps[j-1];
3183 priv->chains[0]->arpmt[0] = tmp;
3184 priv->chains[0]->arStreamCaps[0] = tmp2;
3186 priv->chains[0]->nFormatUsed = 0;
3188 if (priv->chains[0]->pmt)
3189 DeleteMediaType(priv->chains[0]->pmt);
3190 priv->chains[0]->pmt =
3191 CreateMediaType(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed]);
3192 DisplayMediaType("VID_SET_FORMAT", priv->chains[0]->pmt);
3194 Setting width & height to preferred by driver values
3196 extract_video_format(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed],
3197 &(priv->fcc), &(priv->width),
3198 &(priv->height));
3199 return result;
3201 case TVI_CONTROL_VID_GET_FORMAT:
3203 if(!priv->chains[0]->pmt)
3204 return TVI_CONTROL_FALSE;
3206 Build video chain (for video format negotiation).
3207 If this was done before, routine will do nothing.
3209 build_video_chain(priv);
3210 DisplayMediaType("VID_GET_FORMAT", priv->chains[0]->pmt);
3211 if (priv->fcc) {
3212 *(int *) arg = priv->fcc;
3213 return TVI_CONTROL_TRUE;
3214 } else
3215 return TVI_CONTROL_FALSE;
3217 case TVI_CONTROL_VID_SET_WIDTH:
3219 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3220 VIDEOINFOHEADER *Vhdr;
3221 int width = *(int *) arg;
3222 if (priv->state)
3223 return TVI_CONTROL_FALSE;
3225 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3226 if (!pCaps)
3227 return TVI_CONTROL_FALSE;
3228 if (width < pCaps->MinOutputSize.cx
3229 || width > pCaps->MaxOutputSize.cx)
3230 return TVI_CONTROL_FALSE;
3232 if (width % pCaps->OutputGranularityX)
3233 return TVI_CONTROL_FALSE;
3235 if (!priv->chains[0]->pmt || !priv->chains[0]->pmt->pbFormat)
3236 return TVI_CONTROL_FALSE;
3237 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3238 Vhdr->bmiHeader.biWidth = width;
3239 priv->chains[0]->pmt->lSampleSize = Vhdr->bmiHeader.biSizeImage =
3240 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
3241 Vhdr->bmiHeader.biHeight) >> 3;
3243 priv->width = width;
3245 return TVI_CONTROL_TRUE;
3247 case TVI_CONTROL_VID_GET_WIDTH:
3249 if (priv->width) {
3250 *(int *) arg = priv->width;
3251 return TVI_CONTROL_TRUE;
3252 } else
3253 return TVI_CONTROL_FALSE;
3255 case TVI_CONTROL_VID_CHK_WIDTH:
3257 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3258 int width = *(int *) arg;
3259 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3260 if (!pCaps)
3261 return TVI_CONTROL_FALSE;
3262 if (width < pCaps->MinOutputSize.cx
3263 || width > pCaps->MaxOutputSize.cx)
3264 return TVI_CONTROL_FALSE;
3266 if (width % pCaps->OutputGranularityX)
3267 return TVI_CONTROL_FALSE;
3268 return TVI_CONTROL_TRUE;
3270 case TVI_CONTROL_VID_SET_HEIGHT:
3272 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3273 VIDEOINFOHEADER *Vhdr;
3274 int height = *(int *) arg;
3275 if (priv->state)
3276 return TVI_CONTROL_FALSE;
3278 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3279 if (!pCaps)
3280 return TVI_CONTROL_FALSE;
3281 if (height < pCaps->MinOutputSize.cy
3282 || height > pCaps->MaxOutputSize.cy)
3283 return TVI_CONTROL_FALSE;
3285 if (height % pCaps->OutputGranularityY)
3286 return TVI_CONTROL_FALSE;
3288 if (!priv->chains[0]->pmt || !priv->chains[0]->pmt->pbFormat)
3289 return TVI_CONTROL_FALSE;
3290 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3292 if (Vhdr->bmiHeader.biHeight < 0)
3293 Vhdr->bmiHeader.biHeight = -height;
3294 else
3295 Vhdr->bmiHeader.biHeight = height;
3296 priv->chains[0]->pmt->lSampleSize = Vhdr->bmiHeader.biSizeImage =
3297 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
3298 Vhdr->bmiHeader.biHeight) >> 3;
3300 priv->height = height;
3301 return TVI_CONTROL_TRUE;
3303 case TVI_CONTROL_VID_GET_HEIGHT:
3305 if (priv->height) {
3306 *(int *) arg = priv->height;
3307 return TVI_CONTROL_TRUE;
3308 } else
3309 return TVI_CONTROL_FALSE;
3311 case TVI_CONTROL_VID_CHK_HEIGHT:
3313 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3314 int height = *(int *) arg;
3315 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3316 if (!pCaps)
3317 return TVI_CONTROL_FALSE;
3318 if (height < pCaps->MinOutputSize.cy
3319 || height > pCaps->MaxOutputSize.cy)
3320 return TVI_CONTROL_FALSE;
3322 if (height % pCaps->OutputGranularityY)
3323 return TVI_CONTROL_FALSE;
3325 return TVI_CONTROL_TRUE;
3327 case TVI_CONTROL_IS_AUDIO:
3328 if (!priv->chains[1]->pmt)
3329 return TVI_CONTROL_FALSE;
3330 else
3331 return TVI_CONTROL_TRUE;
3332 case TVI_CONTROL_IS_VIDEO:
3333 return TVI_CONTROL_TRUE;
3334 case TVI_CONTROL_AUD_GET_FORMAT:
3336 *(int *) arg = AF_FORMAT_S16_LE;
3337 if (!priv->chains[1]->pmt)
3338 return TVI_CONTROL_FALSE;
3339 else
3340 return TVI_CONTROL_TRUE;
3342 case TVI_CONTROL_AUD_GET_CHANNELS:
3344 *(int *) arg = priv->channels;
3345 if (!priv->chains[1]->pmt)
3346 return TVI_CONTROL_FALSE;
3347 else
3348 return TVI_CONTROL_TRUE;
3350 case TVI_CONTROL_AUD_SET_SAMPLERATE:
3352 int i, samplerate;
3353 if (priv->state)
3354 return TVI_CONTROL_FALSE;
3355 if (!priv->chains[1]->arpmt[0])
3356 return TVI_CONTROL_FALSE;
3358 samplerate = *(int *) arg;;
3360 for (i = 0; priv->chains[1]->arpmt[i]; i++)
3361 if (check_audio_format
3362 (priv->chains[1]->arpmt[i], samplerate, 16, priv->channels))
3363 break;
3364 if (!priv->chains[1]->arpmt[i]) {
3365 //request not found. failing back to first available
3366 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_SamplerateNotsupported, samplerate);
3367 i = 0;
3369 if (priv->chains[1]->pmt)
3370 DeleteMediaType(priv->chains[1]->pmt);
3371 priv->chains[1]->pmt = CreateMediaType(priv->chains[1]->arpmt[i]);
3372 extract_audio_format(priv->chains[1]->arpmt[i], &(priv->samplerate),
3373 NULL, &(priv->channels));
3374 return TVI_CONTROL_TRUE;
3376 case TVI_CONTROL_AUD_GET_SAMPLERATE:
3378 *(int *) arg = priv->samplerate;
3379 if (!priv->samplerate)
3380 return TVI_CONTROL_FALSE;
3381 if (!priv->chains[1]->pmt)
3382 return TVI_CONTROL_FALSE;
3383 else
3384 return TVI_CONTROL_TRUE;
3386 case TVI_CONTROL_AUD_GET_SAMPLESIZE:
3388 WAVEFORMATEX *pWF;
3389 if (!priv->chains[1]->pmt)
3390 return TVI_CONTROL_FALSE;
3391 if (!priv->chains[1]->pmt->pbFormat)
3392 return TVI_CONTROL_FALSE;
3393 pWF = (WAVEFORMATEX *) priv->chains[1]->pmt->pbFormat;
3394 *(int *) arg = pWF->wBitsPerSample / 8;
3395 return TVI_CONTROL_TRUE;
3397 case TVI_CONTROL_IS_TUNER:
3399 if (!priv->pTVTuner)
3400 return TVI_CONTROL_FALSE;
3402 return TVI_CONTROL_TRUE;
3404 case TVI_CONTROL_TUN_SET_NORM:
3406 IAMAnalogVideoDecoder *pVD;
3407 long lAnalogFormat;
3408 int i;
3409 HRESULT hr;
3411 i = *(int *) arg;
3412 i--;
3413 if (i < 0 || i >= tv_available_norms_count)
3414 return TVI_CONTROL_FALSE;
3415 lAnalogFormat = tv_norms[tv_available_norms[i]].index;
3417 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter,IID_IAMAnalogVideoDecoder, pVD);
3418 if (hr != S_OK)
3419 return TVI_CONTROL_FALSE;
3420 hr = OLE_CALL_ARGS(pVD, put_TVFormat, lAnalogFormat);
3421 OLE_RELEASE_SAFE(pVD);
3422 if (FAILED(hr))
3423 return TVI_CONTROL_FALSE;
3424 else
3425 return TVI_CONTROL_TRUE;
3427 case TVI_CONTROL_TUN_GET_NORM:
3429 long lAnalogFormat;
3430 int i;
3431 HRESULT hr;
3432 IAMAnalogVideoDecoder *pVD;
3434 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter,IID_IAMAnalogVideoDecoder, pVD);
3435 if (hr == S_OK) {
3436 hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat);
3437 OLE_RELEASE_SAFE(pVD);
3440 if (FAILED(hr)) { //trying another method
3441 if (!priv->pTVTuner)
3442 return TVI_CONTROL_FALSE;
3443 hr=OLE_CALL_ARGS(priv->pTVTuner, get_TVFormat, &lAnalogFormat);
3444 if (FAILED(hr))
3445 return TVI_CONTROL_FALSE;
3447 for (i = 0; i < tv_available_norms_count; i++) {
3448 if (tv_norms[tv_available_norms[i]].index == lAnalogFormat) {
3449 *(int *) arg = i + 1;
3450 return TVI_CONTROL_TRUE;
3453 return TVI_CONTROL_FALSE;
3455 case TVI_CONTROL_SPC_GET_NORMID:
3457 int i;
3458 if (!priv->pTVTuner)
3459 return TVI_CONTROL_FALSE;
3460 for (i = 0; i < tv_available_norms_count; i++) {
3461 if (!strcasecmp
3462 (tv_norms[tv_available_norms[i]].name, (char *) arg)) {
3463 *(int *) arg = i + 1;
3464 return TVI_CONTROL_TRUE;
3467 return TVI_CONTROL_FALSE;
3469 case TVI_CONTROL_SPC_SET_INPUT:
3471 return set_crossbar_input(priv, *(int *) arg);
3473 case TVI_CONTROL_TUN_GET_FREQ:
3475 unsigned long lFreq;
3476 int ret;
3477 if (!priv->pTVTuner)
3478 return TVI_CONTROL_FALSE;
3480 ret = get_frequency(priv, &lFreq);
3481 lFreq = lFreq * 16 / 1000000; //convert from Hz to 1/16 MHz units
3483 *(unsigned long *) arg = lFreq;
3484 return ret;
3486 case TVI_CONTROL_TUN_SET_FREQ:
3488 unsigned long nFreq = *(unsigned long *) arg;
3489 if (!priv->pTVTuner)
3490 return TVI_CONTROL_FALSE;
3491 //convert to Hz
3492 nFreq = 1000000 * nFreq / 16; //convert from 1/16 MHz units to Hz
3493 return set_frequency(priv, nFreq);
3495 case TVI_CONTROL_VID_SET_HUE:
3496 return set_control(priv, VideoProcAmp_Hue, *(int *) arg);
3497 case TVI_CONTROL_VID_GET_HUE:
3498 return get_control(priv, VideoProcAmp_Hue, (int *) arg);
3499 case TVI_CONTROL_VID_SET_CONTRAST:
3500 return set_control(priv, VideoProcAmp_Contrast, *(int *) arg);
3501 case TVI_CONTROL_VID_GET_CONTRAST:
3502 return get_control(priv, VideoProcAmp_Contrast, (int *) arg);
3503 case TVI_CONTROL_VID_SET_SATURATION:
3504 return set_control(priv, VideoProcAmp_Saturation, *(int *) arg);
3505 case TVI_CONTROL_VID_GET_SATURATION:
3506 return get_control(priv, VideoProcAmp_Saturation, (int *) arg);
3507 case TVI_CONTROL_VID_SET_BRIGHTNESS:
3508 return set_control(priv, VideoProcAmp_Brightness, *(int *) arg);
3509 case TVI_CONTROL_VID_GET_BRIGHTNESS:
3510 return get_control(priv, VideoProcAmp_Brightness, (int *) arg);
3512 case TVI_CONTROL_VID_GET_FPS:
3514 VIDEOINFOHEADER *Vhdr;
3515 if (!priv->chains[0]->pmt)
3516 return TVI_CONTROL_FALSE;
3517 if (!priv->chains[0]->pmt->pbFormat)
3518 return TVI_CONTROL_FALSE;
3519 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3520 *(float *) arg =
3521 (1.0 * Vhdr->dwBitRate) / (Vhdr->bmiHeader.biSizeImage * 8);
3522 return TVI_CONTROL_TRUE;
3524 case TVI_CONTROL_IMMEDIATE:
3525 priv->immediate_mode = 1;
3526 return TVI_CONTROL_TRUE;
3527 #ifdef CONFIG_TV_TELETEXT
3528 case TVI_CONTROL_VBI_INIT:
3530 void* ptr;
3531 ptr=&(priv->tsp);
3532 if(teletext_control(NULL,TV_VBI_CONTROL_START,&ptr)==TVI_CONTROL_TRUE)
3533 priv->priv_vbi=ptr;
3534 else
3535 priv->priv_vbi=NULL;
3536 return TVI_CONTROL_TRUE;
3538 default:
3539 return teletext_control(priv->priv_vbi,cmd,arg);
3540 #endif
3542 return TVI_CONTROL_UNKNOWN;