Fix compilation: #undef standard library functions that are
[mplayer/glamo.git] / stream / tvi_dshow.c
blob37816f82cba584ad5ebbea542b1c2e7d73a8dc28
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 *---------------------------------------------------------------------------------------
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 *---------------------------------------------------------------------------------------
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 (%s)\n",nCountry,nInputType == TunerInputAntenna ? "broadcast" : "cable");
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];
929 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: load_freq_table #%d => (%ld)\n",i+*pnFirst,(*pplFreqTable)[i]);
931 FreeLibrary(hDLL);
932 return S_OK;
936 * \brief tunes to given frequency through IKsPropertySet call
938 * \param pTVTuner IAMTVTuner interface of capture device
939 * \param lFreq frequency to tune (in Hz)
941 * \return S_OK success
942 * \return apropriate error code otherwise
944 * \note
945 * Due to either bug in driver or error in following code calll to IKsProperty::Set
946 * in this methods always fail with error 0x8007007a.
948 * \todo test code on other machines and an error
950 static HRESULT set_frequency_direct(IAMTVTuner * pTVTuner, long lFreq)
952 HRESULT hr;
953 DWORD dwSupported = 0;
954 DWORD cbBytes = 0;
955 KSPROPERTY_TUNER_MODE_CAPS_S mode_caps;
956 KSPROPERTY_TUNER_FREQUENCY_S frequency;
957 IKsPropertySet *pKSProp;
959 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency_direct called\n");
961 memset(&mode_caps, 0, sizeof(mode_caps));
962 memset(&frequency, 0, sizeof(frequency));
964 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
965 if (FAILED(hr))
966 return hr; //no IKsPropertySet interface
968 mode_caps.Mode = AMTUNER_MODE_TV;
969 hr = OLE_CALL_ARGS(pKSProp, QuerySupported, &PROPSETID_TUNER,
970 KSPROPERTY_TUNER_MODE_CAPS, &dwSupported);
971 if (FAILED(hr)) {
972 OLE_RELEASE_SAFE(pKSProp);
973 return hr;
976 if (!dwSupported & KSPROPERTY_SUPPORT_GET) {
977 OLE_RELEASE_SAFE(pKSProp);
978 return E_FAIL; //PROPSETID_TINER not supported
981 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
982 KSPROPERTY_TUNER_MODE_CAPS,
983 INSTANCEDATA_OF_PROPERTY_PTR(&mode_caps),
984 INSTANCEDATA_OF_PROPERTY_SIZE(mode_caps),
985 &mode_caps, sizeof(mode_caps), &cbBytes);
987 frequency.Frequency = lFreq;
989 if (mode_caps.Strategy == KS_TUNER_STRATEGY_DRIVER_TUNES)
990 frequency.TuningFlags = KS_TUNER_TUNING_FINE;
991 else
992 frequency.TuningFlags = KS_TUNER_TUNING_EXACT;
994 if (lFreq < mode_caps.MinFrequency || lFreq > mode_caps.MaxFrequency) {
995 OLE_RELEASE_SAFE(pKSProp);
996 return E_FAIL;
999 hr = OLE_CALL_ARGS(pKSProp, Set, &PROPSETID_TUNER,
1000 KSPROPERTY_TUNER_FREQUENCY,
1001 INSTANCEDATA_OF_PROPERTY_PTR(&frequency),
1002 INSTANCEDATA_OF_PROPERTY_SIZE(frequency),
1003 &frequency, sizeof(frequency));
1004 if (FAILED(hr)) {
1005 OLE_RELEASE_SAFE(pKSProp);
1006 return hr;
1009 OLE_RELEASE_SAFE(pKSProp);
1011 return S_OK;
1015 * \brief find channel with nearest frequency and set it
1017 * \param priv driver's private data
1018 * \param lFreq frequency in Hz
1020 * \return S_OK if success
1021 * \return E_FAIL if error occured
1023 static HRESULT set_nearest_freq(priv_t * priv, long lFreq)
1025 HRESULT hr;
1026 int i;
1027 long lFreqDiff=-1;
1028 int nChannel;
1029 TunerInputType tunerInput;
1030 long lInput;
1032 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq called: %ld\n", lFreq);
1033 if(priv->freq_table_len == -1 && !priv->freq_table) {
1035 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
1036 if(FAILED(hr)){ //Falling back to 0
1037 lInput=0;
1040 hr = OLE_CALL_ARGS(priv->pTVTuner, get_InputType, lInput, &tunerInput);
1042 if (load_freq_table(chanlist2country(priv->tv_param->chanlist), tunerInput, &(priv->freq_table), &(priv->freq_table_len), &(priv->first_channel)) != S_OK) {//FIXME
1043 priv->freq_table_len=0;
1044 priv->freq_table=NULL;
1045 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableExtractFreqTable);
1046 return E_FAIL;
1048 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_FreqTableLoaded, tunerInput == TunerInputAntenna ? "broadcast" : "cable",
1049 chanlist2country(priv->tv_param->chanlist), priv->freq_table_len);
1052 if (priv->freq_table_len <= 0)
1053 return E_FAIL;
1055 //FIXME: rewrite search algo
1056 nChannel = -1;
1057 for (i = 0; i < priv->freq_table_len; i++) {
1058 if (nChannel == -1 || labs(lFreq - priv->freq_table[i]) < lFreqDiff) {
1059 nChannel = priv->first_channel + i;
1060 lFreqDiff = labs(lFreq - priv->freq_table[i]);
1062 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_nearest_freq #%d (%ld) => %d (%ld)\n",i+priv->first_channel,priv->freq_table[i], nChannel,lFreqDiff);
1064 if (nChannel == -1) {
1065 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableFindNearestChannel);
1066 return E_FAIL;
1068 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: set_nearest_freq #%d (%ld)\n",nChannel,priv->freq_table[nChannel - priv->first_channel]);
1069 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Channel, nChannel,
1070 AMTUNER_SUBCHAN_DEFAULT, AMTUNER_SUBCHAN_DEFAULT);
1071 if (FAILED(hr)) {
1072 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableToSetChannel, (unsigned int)hr);
1073 return E_FAIL;
1075 return S_OK;
1079 * \brief setting frequency. decides whether use direct call/workaround
1081 * \param priv driver's private data
1082 * \param lFreq frequency in Hz
1084 * \return TVI_CONTROL_TRUE if success
1085 * \return TVI_CONTROL_FALSE if error occured
1087 * \todo check for freq boundary
1089 static int set_frequency(priv_t * priv, long lFreq)
1091 HRESULT hr;
1093 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_frequency called: %ld\n", lFreq);
1094 if (!priv->pTVTuner)
1095 return TVI_CONTROL_FALSE;
1096 if (priv->direct_setfreq_call) { //using direct call to set frequency
1097 hr = set_frequency_direct(priv->pTVTuner, lFreq);
1098 if (FAILED(hr)) {
1099 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DirectSetFreqFailed);
1100 priv->direct_setfreq_call = 0;
1103 if (!priv->direct_setfreq_call) {
1104 hr = set_nearest_freq(priv, lFreq);
1106 if (FAILED(hr))
1107 return TVI_CONTROL_FALSE;
1108 #ifdef DEPRECATED
1109 priv->pGrabber->ClearBuffer(priv->pGrabber);
1110 #endif
1111 return TVI_CONTROL_TRUE;
1115 * \brief return current frequency from tuner (in Hz)
1117 * \param pTVTuner IAMTVTuner interface of tuner
1118 * \param plFreq address of variable that receives current frequency
1120 * \return S_OK success
1121 * \return E_POINTER pTVTuner==NULL || plFreq==NULL
1122 * \return apropriate error code otherwise
1124 static HRESULT get_frequency_direct(IAMTVTuner * pTVTuner, long *plFreq)
1126 HRESULT hr;
1127 KSPROPERTY_TUNER_STATUS_S TunerStatus;
1128 DWORD cbBytes;
1129 IKsPropertySet *pKSProp;
1130 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency_direct called\n");
1132 if (!plFreq)
1133 return E_POINTER;
1135 hr = OLE_QUERYINTERFACE(pTVTuner, IID_IKsPropertySet, pKSProp);
1136 if (FAILED(hr)) {
1137 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq QueryInterface failed\n");
1138 return hr;
1141 hr = OLE_CALL_ARGS(pKSProp, Get, &PROPSETID_TUNER,
1142 KSPROPERTY_TUNER_STATUS,
1143 INSTANCEDATA_OF_PROPERTY_PTR(&TunerStatus),
1144 INSTANCEDATA_OF_PROPERTY_SIZE(TunerStatus),
1145 &TunerStatus, sizeof(TunerStatus), &cbBytes);
1146 if (FAILED(hr)) {
1147 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get freq Get failure\n");
1148 return hr;
1150 *plFreq = TunerStatus.CurrentFrequency;
1151 return S_OK;
1155 * \brief gets current frequency
1157 * \param priv driver's private data structure
1158 * \param plFreq - pointer to long int to store frequency to (in Hz)
1160 * \return TVI_CONTROL_TRUE if success, TVI_CONTROL_FALSE otherwise
1162 static int get_frequency(priv_t * priv, long *plFreq)
1164 HRESULT hr;
1166 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_frequency called\n");
1168 if (!plFreq || !priv->pTVTuner)
1169 return TVI_CONTROL_FALSE;
1171 if (priv->direct_getfreq_call) { //using direct call to get frequency
1172 hr = get_frequency_direct(priv->pTVTuner, plFreq);
1173 if (FAILED(hr)) {
1174 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_DirectGetFreqFailed);
1175 priv->direct_getfreq_call = 0;
1178 if (!priv->direct_getfreq_call) {
1179 hr=OLE_CALL_ARGS(priv->pTVTuner, get_VideoFrequency, plFreq);
1180 if (FAILED(hr))
1181 return TVI_CONTROL_FALSE;
1184 return TVI_CONTROL_TRUE;
1188 * \brief get tuner capabilities
1190 * \param priv driver's private data
1192 static void get_capabilities(priv_t * priv)
1194 long lAvailableFormats;
1195 HRESULT hr;
1196 int i;
1197 long lInputPins, lOutputPins, lRelated, lPhysicalType;
1198 IEnumPins *pEnum;
1199 char tmp[200];
1200 IPin *pPin = 0;
1201 PIN_DIRECTION ThisPinDir;
1202 PIN_INFO pi;
1203 IAMAudioInputMixer *pIAMixer;
1205 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_capabilities called\n");
1206 if (priv->pTVTuner) {
1208 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_SupportedNorms);
1209 hr = OLE_CALL_ARGS(priv->pTVTuner, get_AvailableTVFormats,
1210 &lAvailableFormats);
1211 if (FAILED(hr))
1212 tv_available_norms_count = 0;
1213 else {
1214 for (i = 0; i < TV_NORMS_COUNT; i++) {
1215 if (lAvailableFormats & tv_norms[i].index) {
1216 tv_available_norms[tv_available_norms_count] = i;
1217 mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
1218 tv_available_norms_count + 1, tv_norms[i].name);
1219 tv_available_norms_count++;
1223 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1225 if (priv->pCrossbar) {
1226 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins,
1227 &lInputPins);
1229 tv_available_inputs = (long *) malloc(sizeof(long) * lInputPins);
1230 tv_available_inputs_count = 0;
1232 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableVideoInputs);
1233 for (i = 0; i < lInputPins; i++) {
1234 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1, i,
1235 &lRelated, &lPhysicalType);
1237 if (lPhysicalType < 0x1000) {
1238 tv_available_inputs[tv_available_inputs_count++] = i;
1239 mp_msg(MSGT_TV, MSGL_V, " %d=%s;",
1240 tv_available_inputs_count - 1,
1241 physcon2str(lPhysicalType));
1244 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1246 set_crossbar_input(priv, 0);
1249 if (priv->adev_index != -1) {
1250 hr = OLE_CALL_ARGS(priv->chains[1]->pCaptureFilter, EnumPins, &pEnum);
1251 if (FAILED(hr))
1252 return;
1253 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_AvailableAudioInputs);
1254 i = 0;
1255 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
1256 memset(&pi, 0, sizeof(pi));
1257 memset(tmp, 0, 200);
1258 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
1259 if (ThisPinDir == PINDIR_INPUT) {
1260 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
1261 wtoa(pi.achName, tmp, 200);
1262 OLE_RELEASE_SAFE(pi.pFilter);
1263 mp_msg(MSGT_TV, MSGL_V, " %d=%s", i, tmp);
1264 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
1265 hr = OLE_QUERYINTERFACE(pPin, IID_IAMAudioInputMixer,pIAMixer);
1266 if (SUCCEEDED(hr)) {
1267 if (i == priv->tv_param->audio_id) {
1268 OLE_CALL_ARGS(pIAMixer, put_Enable, TRUE);
1269 if(priv->tv_param->volume>0)
1270 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.01 * priv->tv_param->volume);
1271 #if 0
1272 else
1273 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 1.0);
1274 #endif
1275 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_InputSelected);
1276 } else {
1277 OLE_CALL_ARGS(pIAMixer, put_Enable, FALSE);
1278 #if 0
1279 OLE_CALL_ARGS(pIAMixer, put_MixLevel, 0.0);
1280 #endif
1282 OLE_RELEASE_SAFE(pIAMixer);
1284 mp_msg(MSGT_TV, MSGL_V, ";");
1285 OLE_RELEASE_SAFE(pPin);
1286 i++;
1289 mp_msg(MSGT_TV, MSGL_INFO, "\n");
1290 OLE_RELEASE_SAFE(pEnum);
1295 *---------------------------------------------------------------------------------------
1297 * Filter related methods
1299 *---------------------------------------------------------------------------------------
1302 * \brief building in graph audio/video capture chain
1304 * \param priv driver's private data
1305 * \param pCaptureFilter pointer to capture device's IBaseFilter interface
1306 * \param pbuf ringbuffer data structure
1307 * \param pmt media type for chain (AM_MEDIA_TYPE)
1309 * \note routine does not frees memory, allocated for grabber_rinbuffer_s structure
1311 static HRESULT build_sub_graph(priv_t * priv, chain_t * chain, const GUID* ppin_category)
1313 HRESULT hr;
1314 int nFormatProbed = 0;
1316 IPin *pSGOut;
1317 IPin *pNRIn=NULL;
1319 IBaseFilter *pNR = NULL;
1321 hr=S_OK;
1323 //No supported formats
1324 if(!chain->arpmt[0])
1325 return E_FAIL;
1328 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
1329 (IUnknown *) chain->pCaptureFilter,
1330 PINDIR_OUTPUT, ppin_category,
1331 chain->majortype, FALSE, 0, &chain->pCapturePin);
1332 if(FAILED(hr)){
1333 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr);
1334 break;
1336 /* Addinf SampleGrabber filter for video stream */
1337 hr = CoCreateInstance((GUID *) & CLSID_SampleGrabber, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &chain->pSGF);
1338 if(FAILED(hr)){
1339 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1340 break;
1342 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, chain->pSGF, L"Sample Grabber");
1343 if(FAILED(hr)){
1344 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(SampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1345 break;
1347 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) chain->pSGF,PINDIR_INPUT, NULL, NULL, FALSE, 0, &chain->pSGIn);
1348 if(FAILED(hr)){
1349 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGIn) call failed. Error:0x%x\n", (unsigned int)hr);
1350 break;
1352 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) chain->pSGF,PINDIR_OUTPUT, NULL, NULL, FALSE, 0, &pSGOut);
1353 if(FAILED(hr)){
1354 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pSGOut) call failed. Error:0x%x\n", (unsigned int)hr);
1355 break;
1358 /* creating ringbuffer for video samples */
1359 chain->pCSGCB = CSampleGrabberCB_Create(chain->rbuf);
1360 if(!chain->pCSGCB){
1361 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CSampleGrabberCB_Create(pbuf) call failed. Error:0x%x\n", (unsigned int)E_OUTOFMEMORY);
1362 break;
1365 /* initializing SampleGrabber filter */
1366 hr = OLE_QUERYINTERFACE(chain->pSGF, IID_ISampleGrabber, chain->pSG);
1367 if(FAILED(hr)){
1368 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: QueryInterface(IID_ISampleGrabber) call failed. Error:0x%x\n", (unsigned int)hr);
1369 break;
1371 // hr = OLE_CALL_ARGS(pSG, SetCallback, (ISampleGrabberCB *) pCSGCB, 1); //we want to receive copy of sample's data
1372 hr = OLE_CALL_ARGS(chain->pSG, SetCallback, (ISampleGrabberCB *) chain->pCSGCB, 0); //we want to receive sample
1374 if(FAILED(hr)){
1375 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetCallback(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1376 break;
1378 hr = OLE_CALL_ARGS(chain->pSG, SetOneShot, FALSE); //... for all frames
1379 if(FAILED(hr)){
1380 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetOneShot(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1381 break;
1383 hr = OLE_CALL_ARGS(chain->pSG, SetBufferSamples, FALSE); //... do not buffer samples in sample grabber
1384 if(FAILED(hr)){
1385 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetBufferSamples(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1386 break;
1389 if(priv->tv_param->normalize_audio_chunks && chain->type==audio){
1390 set_buffer_preference(20,(WAVEFORMATEX*)(chain->arpmt[nFormatProbed]->pbFormat),chain->pCapturePin,chain->pSGIn);
1393 for(nFormatProbed=0; chain->arpmt[nFormatProbed]; nFormatProbed++)
1395 DisplayMediaType("Probing format", chain->arpmt[nFormatProbed]);
1396 hr = OLE_CALL_ARGS(chain->pSG, SetMediaType, chain->arpmt[nFormatProbed]); //set desired mediatype
1397 if(FAILED(hr)){
1398 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: SetMediaType(pSG) call failed. Error:0x%x\n", (unsigned int)hr);
1399 continue;
1401 /* connecting filters together: VideoCapture --> SampleGrabber */
1402 hr = OLE_CALL_ARGS(priv->pGraph, Connect, chain->pCapturePin, chain->pSGIn);
1403 if(FAILED(hr)){
1404 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pCapturePin<->pSGIn connection. Error:0x%x\n", (unsigned int)hr);
1405 continue;
1407 break;
1410 if(!chain->arpmt[nFormatProbed])
1412 mp_msg(MSGT_TV, MSGL_WARN, "tvi_dshow: Unable to negotiate media format\n");
1413 hr = E_FAIL;
1414 break;
1417 hr = OLE_CALL_ARGS(chain->pCapturePin, ConnectionMediaType, chain->pmt);
1418 if(FAILED(hr))
1420 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_GetActualMediatypeFailed, (unsigned int)hr);
1423 if(priv->tv_param->hidden_video_renderer){
1424 IEnumFilters* pEnum;
1425 IBaseFilter* pFilter;
1427 hr=OLE_CALL_ARGS(priv->pBuilder,RenderStream,NULL,NULL,(IUnknown*)chain->pCapturePin,NULL,NULL);
1429 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
1430 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
1431 LPVIDEOWINDOW pVideoWindow;
1432 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
1433 if (SUCCEEDED(hr))
1435 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
1436 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
1437 OLE_RELEASE_SAFE(pVideoWindow);
1439 OLE_RELEASE_SAFE(pFilter);
1441 OLE_RELEASE_SAFE(pEnum);
1442 }else
1444 #if 0
1446 Code below is disabled, because terminating chain with NullRenderer leads to jerky video.
1447 Perhaps, this happens because NullRenderer filter discards each received
1448 frame while discarded frames causes live source filter to dramatically reduce frame rate.
1450 /* adding sink for video stream */
1451 hr = CoCreateInstance((GUID *) & CLSID_NullRenderer, NULL,CLSCTX_INPROC_SERVER, &IID_IBaseFilter,(void *) &pNR);
1452 if(FAILED(hr)){
1453 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: CoCreateInstance(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
1454 break;
1456 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, pNR, L"Null Renderer");
1457 if(FAILED(hr)){
1458 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: AddFilter(NullRenderer) call failed. Error:0x%x\n", (unsigned int)hr);
1459 break;
1461 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin, (IUnknown *) pNR,PINDIR_INPUT, NULL, NULL, FALSE, 0, &pNRIn);
1462 if(FAILED(hr)){
1463 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: FindPin(pNRIn) call failed. Error:0x%x\n", (unsigned int)hr);
1464 break;
1467 Prevent ending VBI chain with NullRenderer filter, because this causes VBI pin disconnection
1469 if(memcmp(&(arpmt[nFormatProbed]->majortype),&MEDIATYPE_VBI,16)){
1470 /* connecting filters together: SampleGrabber --> NullRenderer */
1471 hr = OLE_CALL_ARGS(priv->pGraph, Connect, pSGOut, pNRIn);
1472 if(FAILED(hr)){
1473 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Unable to create pSGOut<->pNRIn connection. Error:0x%x\n", (unsigned int)hr);
1474 break;
1477 #endif
1480 hr = S_OK;
1481 } while(0);
1483 OLE_RELEASE_SAFE(pSGOut);
1484 OLE_RELEASE_SAFE(pNR);
1485 OLE_RELEASE_SAFE(pNRIn);
1487 return hr;
1491 * \brief configures crossbar for grabbing video stream from given input
1493 * \param priv driver's private data
1494 * \param input index of available video input to get data from
1496 * \return TVI_CONTROL_TRUE success
1497 * \return TVI_CONTROL_FALSE error
1499 static int set_crossbar_input(priv_t * priv, int input)
1501 HRESULT hr;
1502 int i, nVideoDecoder, nAudioDecoder;
1503 long lInput, lInputRelated, lRelated, lPhysicalType, lOutputPins,
1504 lInputPins;
1506 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Configuring crossbar\n");
1507 if (!priv->pCrossbar || input < 0
1508 || input >= tv_available_inputs_count)
1509 return TVI_CONTROL_FALSE;
1511 OLE_CALL_ARGS(priv->pCrossbar, get_PinCounts, &lOutputPins, &lInputPins);
1513 lInput = tv_available_inputs[input];
1515 if (lInput < 0 || lInput >= lInputPins)
1516 return TVI_CONTROL_FALSE;
1518 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 1 /* input */ , lInput,
1519 &lInputRelated, &lPhysicalType);
1521 nVideoDecoder = nAudioDecoder = -1;
1522 for (i = 0; i < lOutputPins; i++) {
1523 OLE_CALL_ARGS(priv->pCrossbar, get_CrossbarPinInfo, 0 /*output */ , i,
1524 &lRelated, &lPhysicalType);
1525 if (lPhysicalType == PhysConn_Video_VideoDecoder)
1526 nVideoDecoder = i;
1527 if (lPhysicalType == PhysConn_Audio_AudioDecoder)
1528 nAudioDecoder = i;
1530 if (nVideoDecoder >= 0) {
1531 //connecting given input with video decoder
1532 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nVideoDecoder, lInput);
1533 if (hr != S_OK) {
1534 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputVideoDecoder, (unsigned int)hr);
1535 return TVI_CONTROL_FALSE;
1538 if (nAudioDecoder >= 0 && lInputRelated >= 0) {
1539 hr = OLE_CALL_ARGS(priv->pCrossbar, Route, nAudioDecoder,
1540 lInputRelated);
1541 if (hr != S_OK) {
1542 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableConnectInputAudioDecoder, (unsigned int)hr);
1543 return TVI_CONTROL_FALSE;
1546 return TVI_CONTROL_TRUE;
1550 * \brief adjusts video control (hue,saturation,contrast,brightess)
1552 * \param priv driver's private data
1553 * \param control which control to adjust
1554 * \param value new value for control (0-100)
1556 * \return TVI_CONTROL_TRUE success
1557 * \return TVI_CONTROL_FALSE error
1559 static int set_control(priv_t * priv, int control, int value)
1561 long lMin, lMax, lStepping, lDefault, lFlags, lValue;
1562 HRESULT hr;
1564 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: set_control called\n");
1565 if (value < -100 || value > 100 || !priv->pVideoProcAmp)
1566 return TVI_CONTROL_FALSE;
1568 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, GetRange, control,
1569 &lMin, &lMax, &lStepping, &lDefault, &lFlags);
1570 if (FAILED(hr) || lFlags != VideoProcAmp_Flags_Manual)
1571 return TVI_CONTROL_FALSE;
1573 lValue = lMin + (value + 100) * (lMax - lMin) / 200;
1575 Workaround for ATI AIW 7500. The driver reports: max=255, stepping=256
1577 if (lStepping > lMax) {
1578 mp_msg(MSGT_TV, MSGL_DBG3,
1579 "tvi_dshow: Stepping (%ld) is bigger than max value (%ld) for control %d. Assuming 1\n",
1580 lStepping, lMax,control);
1581 lStepping = 1;
1583 lValue -= lValue % lStepping;
1584 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Set, control, lValue,
1585 VideoProcAmp_Flags_Manual);
1586 if (FAILED(hr))
1587 return TVI_CONTROL_FALSE;
1589 return TVI_CONTROL_TRUE;
1593 * \brief get current value of video control (hue,saturation,contrast,brightess)
1595 * \param priv driver's private data
1596 * \param control which control to adjust
1597 * \param pvalue address of variable thar receives current value
1599 * \return TVI_CONTROL_TRUE success
1600 * \return TVI_CONTROL_FALSE error
1602 static int get_control(priv_t * priv, int control, int *pvalue)
1604 long lMin, lMax, lStepping, lDefault, lFlags, lValue;
1605 HRESULT hr;
1607 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: get_control called\n");
1608 if (!pvalue || !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))
1614 return TVI_CONTROL_FALSE;
1615 if (lMin == lMax) {
1616 *pvalue = lMin;
1617 return TVI_CONTROL_TRUE;
1620 hr = OLE_CALL_ARGS(priv->pVideoProcAmp, Get, control, &lValue, &lFlags);
1621 if (FAILED(hr))
1622 return TVI_CONTROL_FALSE;
1624 *pvalue = 200 * (lValue - lMin) / (lMax - lMin) - 100;
1626 return TVI_CONTROL_TRUE;
1630 * \brief create AM_MEDIA_TYPE structure, corresponding to given FourCC code and width/height/fps
1631 * \param fcc FourCC code for video format
1632 * \param width picture width
1633 * \param height pciture height
1634 * \param fps frames per second (required for bitrate calculation)
1636 * \return pointer to AM_MEDIA_TYPE structure if success, NULL - otherwise
1638 static AM_MEDIA_TYPE* create_video_format(int fcc, int width, int height, int fps)
1640 int i;
1641 AM_MEDIA_TYPE mt;
1642 VIDEOINFOHEADER vHdr;
1644 /* Check given fcc in lookup table*/
1645 for(i=0; img_fmt_list[i].fmt && img_fmt_list[i].fmt!=fcc; i++) /* NOTHING */;
1646 if(!img_fmt_list[i].fmt)
1647 return NULL;
1649 memset(&mt, 0, sizeof(AM_MEDIA_TYPE));
1650 memset(&vHdr, 0, sizeof(VIDEOINFOHEADER));
1652 vHdr.bmiHeader.biSize = sizeof(vHdr.bmiHeader);
1653 vHdr.bmiHeader.biWidth = width;
1654 vHdr.bmiHeader.biHeight = height;
1655 //FIXME: is biPlanes required too?
1656 //vHdr.bmiHeader.biPlanes = img_fmt_list[i].nPlanes;
1657 vHdr.bmiHeader.biBitCount = img_fmt_list[i].nBits;
1658 vHdr.bmiHeader.biCompression = img_fmt_list[i].nCompression;
1659 vHdr.bmiHeader.biSizeImage = width * height * img_fmt_list[i].nBits / 8;
1660 vHdr.dwBitRate = vHdr.bmiHeader.biSizeImage * 8 * fps;
1662 mt.pbFormat = (char*)&vHdr;
1663 mt.cbFormat = sizeof(vHdr);
1665 mt.majortype = MEDIATYPE_Video;
1666 mt.subtype = *img_fmt_list[i].subtype;
1667 mt.formattype = FORMAT_VideoInfo;
1669 mt.bFixedSizeSamples = 1;
1670 mt.bTemporalCompression = 0;
1671 mt.lSampleSize = vHdr.bmiHeader.biSizeImage;
1673 return CreateMediaType(&mt);
1677 * \brief extracts fcc,width,height from AM_MEDIA_TYPE
1679 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1680 * \param pfcc address of variable that receives FourCC
1681 * \param pwidth address of variable that receives width
1682 * \param pheight address of variable that recevies height
1684 * \return 1 if data extracted successfully, 0 - otherwise
1686 static int extract_video_format(AM_MEDIA_TYPE * pmt, int *pfcc,
1687 int *pwidth, int *pheight)
1689 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_video_format called\n");
1690 if (!pmt)
1691 return 0;
1692 if (!pmt->pbFormat)
1693 return 0;
1694 if (memcmp(&(pmt->formattype), &FORMAT_VideoInfo, 16) != 0)
1695 return 0;
1696 if (pfcc)
1697 *pfcc = subtype2imgfmt(&(pmt->subtype));
1698 if (pwidth)
1699 *pwidth = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biWidth;
1700 if (pheight)
1701 *pheight = ((VIDEOINFOHEADER *) pmt->pbFormat)->bmiHeader.biHeight;
1702 return 1;
1706 * \brief extracts samplerate,bits,channels from AM_MEDIA_TYPE
1708 * \param pmt pointer to AM_MEDIA_TYPE to extract data from
1709 * \param pfcc address of variable that receives samplerate
1710 * \param pwidth address of variable that receives number of bits per sample
1711 * \param pheight address of variable that recevies number of channels
1713 * \return 1 if data extracted successfully, 0 - otherwise
1715 static int extract_audio_format(AM_MEDIA_TYPE * pmt, int *psamplerate,
1716 int *pbits, int *pchannels)
1718 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: extract_audio_format called\n");
1719 if (!pmt)
1720 return 0;
1721 if (!pmt->pbFormat)
1722 return 0;
1723 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
1724 return 0;
1725 if (psamplerate)
1726 *psamplerate = ((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec;
1727 if (pbits)
1728 *pbits = ((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample;
1729 if (pchannels)
1730 *pchannels = ((WAVEFORMATEX *) pmt->pbFormat)->nChannels;
1731 return 1;
1735 * \brief checks if AM_MEDIA_TYPE compatible with given samplerate,bits,channels
1737 * \param pmt pointer to AM_MEDIA_TYPE for check
1738 * \param samplerate audio samplerate
1739 * \param bits bits per sample
1740 * \param channels number of audio channels
1742 * \return 1 if AM_MEDIA_TYPE compatible
1743 * \return 0 if not
1745 static int check_audio_format(AM_MEDIA_TYPE * pmt, int samplerate,
1746 int bits, int channels)
1748 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_audio_format called\n");
1749 if (!pmt)
1750 return 0;
1751 if (memcmp(&(pmt->majortype), &MEDIATYPE_Audio, 16) != 0)
1752 return 0;
1753 if (memcmp(&(pmt->subtype), &MEDIASUBTYPE_PCM, 16) != 0)
1754 return 0;
1755 if (memcmp(&(pmt->formattype), &FORMAT_WaveFormatEx, 16) != 0)
1756 return 0;
1757 if (!pmt->pbFormat)
1758 return 0;
1759 if (((WAVEFORMATEX *) pmt->pbFormat)->nSamplesPerSec != samplerate)
1760 return 0;
1761 if (((WAVEFORMATEX *) pmt->pbFormat)->wBitsPerSample != bits)
1762 return 0;
1763 if (channels > 0
1764 && ((WAVEFORMATEX *) pmt->pbFormat)->nChannels != channels)
1765 return 0;
1767 return 1;
1771 * \brief checks if AM_MEDIA_TYPE compatible with given fcc,width,height
1773 * \param pmt pointer to AM_MEDIA_TYPE for check
1774 * \param fcc FourCC (compression)
1775 * \param width width of picture
1776 * \param height height of picture
1778 * \return 1 if AM_MEDIA_TYPE compatible
1779 & \return 0 if not
1781 * \note
1782 * width and height are currently not used
1784 * \todo
1785 * add width/height check
1787 static int check_video_format(AM_MEDIA_TYPE * pmt, int fcc, int width,
1788 int height)
1790 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: check_video_format called\n");
1791 if (!pmt)
1792 return 0;
1793 if (memcmp(&(pmt->majortype), &MEDIATYPE_Video, 16) != 0)
1794 return 0;
1795 if (subtype2imgfmt(&(pmt->subtype)) != fcc)
1796 return 0;
1797 return 1;
1801 * \brief converts DirectShow subtype to MPlayer's IMGFMT
1803 * \param subtype DirectShow subtype for video format
1805 * \return MPlayer's IMGFMT or 0 if error occured
1807 static int subtype2imgfmt(const GUID * subtype)
1809 int i;
1810 for (i = 0; img_fmt_list[i].fmt; i++) {
1811 if (memcmp(subtype, img_fmt_list[i].subtype, 16) == 0)
1812 return img_fmt_list[i].fmt;
1814 return 0;
1818 * \brief prints filter name and it pins
1820 * \param pFilter - IBaseFilter to get data from
1822 * \return S_OK if success, error code otherwise
1824 static HRESULT show_filter_info(IBaseFilter * pFilter)
1826 char tmp[200];
1827 FILTER_INFO fi;
1828 LPENUMPINS pEnum = 0;
1829 IPin *pPin = 0;
1830 PIN_DIRECTION ThisPinDir;
1831 PIN_INFO pi;
1832 HRESULT hr;
1833 int i;
1835 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: show_filter_info called\n");
1836 memset(&fi, 0, sizeof(fi));
1837 memset(tmp, 0, 200);
1839 OLE_CALL_ARGS(pFilter, QueryFilterInfo, &fi);
1840 OLE_RELEASE_SAFE(fi.pGraph);
1841 wtoa(fi.achName, tmp, 200);
1842 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: BaseFilter (%p): Name=%s, Graph=%p output pins:",
1843 pFilter, tmp, fi.pGraph);
1844 hr = OLE_CALL_ARGS(pFilter, EnumPins, &pEnum);
1845 if (FAILED(hr))
1846 return hr;
1847 i = 0;
1848 while (OLE_CALL_ARGS(pEnum, Next, 1, &pPin, NULL) == S_OK) {
1849 memset(&pi, 0, sizeof(pi));
1850 memset(tmp, 0, 200);
1851 OLE_CALL_ARGS(pPin, QueryDirection, &ThisPinDir);
1852 if (ThisPinDir == PINDIR_OUTPUT) {
1853 OLE_CALL_ARGS(pPin, QueryPinInfo, &pi);
1854 wtoa(pi.achName, tmp, 200);
1855 OLE_RELEASE_SAFE(pi.pFilter);
1856 mp_msg(MSGT_TV, MSGL_DBG2, " %d=%s", i, tmp);
1857 mp_msg(MSGT_TV, MSGL_DBG3, " (%p)", pPin);
1858 mp_msg(MSGT_TV, MSGL_DBG2, ";");
1859 OLE_RELEASE_SAFE(pPin);
1860 i++;
1863 mp_msg(MSGT_TV, MSGL_DBG2, "\n");
1864 OLE_RELEASE_SAFE(pEnum);
1865 return S_OK;
1869 * \brief gets device's frendly in ANSI encoding
1871 * \param pM IMoniker interface, got in enumeration process
1872 * \param category device category
1874 * \return TVI_CONTROL_TRUE if operation succeded, TVI_CONTROL_FALSE - otherwise
1876 static int get_device_name(IMoniker * pM, char *pBuf, int nLen)
1878 HRESULT hr;
1879 VARIANT var;
1880 IPropertyBag *pPropBag;
1881 hr = OLE_CALL_ARGS(pM, BindToStorage, 0, 0, &IID_IPropertyBag,(void *) &pPropBag);
1882 if (FAILED(hr)) {
1883 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Call to BindToStorage failed\n");
1884 return TVI_CONTROL_FALSE;
1886 var.vt = VT_BSTR;
1887 hr = OLE_CALL_ARGS(pPropBag, Read, L"Description", (LPVARIANT) & var,
1888 NULL);
1889 if (FAILED(hr)) {
1890 hr = OLE_CALL_ARGS(pPropBag, Read, L"FriendlyName", (LPVARIANT) & var,
1891 NULL);
1893 OLE_RELEASE_SAFE(pPropBag);
1894 if (SUCCEEDED(hr)) {
1895 wtoa(var.bstrVal, pBuf, nLen);
1896 return TVI_CONTROL_TRUE;
1898 return TVI_CONTROL_FALSE;
1902 * \brief find capture device at given index
1904 * \param index device index to search for (-1 mean only print available)
1905 * \param category device category
1907 * \return IBaseFilter interface for capture device with given index
1909 * Sample values for category:
1910 * CLSID_VideoInputDeviceCategory - Video Capture Sources
1911 * CLSID_AudioInputDeviceCategory - Audio Capture Sources
1912 * See DirectShow SDK documentation for other possible values
1914 static IBaseFilter *find_capture_device(int index, REFCLSID category)
1916 IBaseFilter *pFilter = NULL;
1917 ICreateDevEnum *pDevEnum = NULL;
1918 IEnumMoniker *pClassEnum = NULL;
1919 IMoniker *pM;
1920 HRESULT hr;
1921 ULONG cFetched;
1922 int i;
1923 char tmp[DEVICE_NAME_MAX_LEN + 1];
1924 hr = CoCreateInstance((GUID *) & CLSID_SystemDeviceEnum, NULL,
1925 CLSCTX_INPROC_SERVER, &IID_ICreateDevEnum,
1926 (void *) &pDevEnum);
1927 if (FAILED(hr)) {
1928 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create device enumerator\n");
1929 return NULL;
1932 hr = OLE_CALL_ARGS(pDevEnum, CreateClassEnumerator, category, &pClassEnum, 0);
1933 OLE_RELEASE_SAFE(pDevEnum);
1934 if (FAILED(hr)) {
1935 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to create class enumerator\n");
1936 return NULL;
1938 if (hr == S_FALSE) {
1939 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: No capture devices found\n");
1940 return NULL;
1943 OLE_CALL(pClassEnum,Reset);
1944 for (i = 0; OLE_CALL_ARGS(pClassEnum, Next, 1, &pM, &cFetched) == S_OK; i++) {
1945 if(get_device_name(pM, tmp, DEVICE_NAME_MAX_LEN)!=TVI_CONTROL_TRUE)
1946 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableGetDeviceName, i);
1947 else
1948 mp_msg(MSGT_TV, MSGL_V, MSGTR_TVI_DS_DeviceName, i, tmp);
1949 if (index != -1 && i == index) {
1950 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_UsingDevice, index, tmp);
1951 hr = OLE_CALL_ARGS(pM, BindToObject, 0, 0, &IID_IBaseFilter,(void *) &pFilter);
1952 if (FAILED(hr))
1953 pFilter = NULL;
1955 OLE_RELEASE_SAFE(pM);
1957 if (index != -1 && !pFilter) {
1958 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_DeviceNotFound,
1959 index);
1961 OLE_RELEASE_SAFE(pClassEnum);
1963 return pFilter;
1967 * \brief get array of available formats through call to IAMStreamConfig::GetStreamCaps
1969 * \praram[in] chain chain data structure
1971 * \return S_OK success
1972 * \return E_POINTER one of parameters is NULL
1973 * \return E_FAIL required size of buffer is unknown for given media type
1974 * \return E_OUTOFMEMORY not enough memory
1975 * \return other error code from called methods
1977 * \remarks
1978 * last items of chain->arpmt and chain->arStreamCaps will be NULL
1980 static HRESULT get_available_formats_stream(chain_t *chain)
1982 AM_MEDIA_TYPE **arpmt;
1983 void **pBuf=NULL;
1985 HRESULT hr;
1986 int i, count, size;
1987 int done;
1989 mp_msg(MSGT_TV, MSGL_DBG4,
1990 "tvi_dshow: get_available_formats_stream called\n");
1992 if (!chain->pStreamConfig)
1993 return E_POINTER;
1995 hr=OLE_CALL_ARGS(chain->pStreamConfig, GetNumberOfCapabilities, &count, &size);
1996 if (FAILED(hr)) {
1997 mp_msg(MSGT_TV, MSGL_DBG4,
1998 "tvi_dshow: Call to GetNumberOfCapabilities failed (get_available_formats_stream)\n");
1999 return hr;
2001 if (chain->type == video){
2002 if (size != sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
2003 mp_msg(MSGT_TV, MSGL_DBG4,
2004 "tvi_dshow: Wrong video structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2005 return E_FAIL;
2007 } else if (chain->type == audio){
2008 if (size != sizeof(AUDIO_STREAM_CONFIG_CAPS)) {
2009 mp_msg(MSGT_TV, MSGL_DBG4,
2010 "tvi_dshow: Wrong audio structure size for GetNumberOfCapabilities (get_available_formats_stream)\n");
2011 return E_FAIL;
2013 } else {
2014 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_stream");
2015 return E_FAIL;
2017 done = 0;
2019 arpmt = (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
2020 if (arpmt) {
2021 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
2023 pBuf = (void **) malloc((count + 1) * sizeof(void *));
2024 if (pBuf) {
2025 memset(pBuf, 0, (count + 1) * sizeof(void *));
2027 for (i = 0; i < count; i++) {
2028 pBuf[i] = malloc(size);
2030 if (!pBuf[i])
2031 break;
2033 hr = OLE_CALL_ARGS(chain->pStreamConfig, GetStreamCaps, i,
2034 &(arpmt[i]), pBuf[i]);
2035 if (FAILED(hr))
2036 break;
2038 if (i == count) {
2039 chain->arpmt = arpmt;
2040 chain->arStreamCaps = pBuf;
2041 done = 1;
2045 if (!done) {
2046 for (i = 0; i < count; i++) {
2047 if (pBuf && pBuf[i])
2048 free(pBuf[i]);
2049 if (arpmt && arpmt[i])
2050 DeleteMediaType(arpmt[i]);
2052 if (pBuf)
2053 free(pBuf);
2054 if (arpmt)
2055 free(arpmt);
2056 if (hr != S_OK) {
2057 mp_msg(MSGT_TV, MSGL_DBG4, "tvi_dshow: Call to GetStreamCaps failed (get_available_formats_stream)\n");
2058 return hr;
2059 } else
2060 return E_OUTOFMEMORY;
2062 return S_OK;
2066 * \brief returns allocates an array and store available media formats for given pin type to it
2068 * \param pBuilder ICaptureGraphBuilder2 interface of graph builder
2069 * \param chain chain data structure
2071 * \return S_OK success
2072 * \return E_POINTER one of given pointers is null
2073 * \return apropriate error code otherwise
2075 static HRESULT get_available_formats_pin(ICaptureGraphBuilder2 * pBuilder,
2076 chain_t *chain)
2078 IEnumMediaTypes *pEnum;
2079 int i, count, size;
2080 ULONG cFetched;
2081 AM_MEDIA_TYPE *pmt;
2082 HRESULT hr;
2083 void **pBuf;
2084 AM_MEDIA_TYPE **arpmt; //This will be real array
2085 VIDEO_STREAM_CONFIG_CAPS *pVideoCaps;
2086 AUDIO_STREAM_CONFIG_CAPS *pAudioCaps;
2087 int p1, p2, p3;
2089 mp_msg(MSGT_TV, MSGL_DBG4,
2090 "tvi_dshow: get_available_formats_pin called\n");
2091 if (!pBuilder || !chain->pCaptureFilter)
2092 return E_POINTER;
2094 if (!chain->pCapturePin)
2096 hr = OLE_CALL_ARGS(pBuilder, FindPin,
2097 (IUnknown *) chain->pCaptureFilter,
2098 PINDIR_OUTPUT, &PIN_CATEGORY_CAPTURE,
2099 chain->majortype, FALSE, 0, &chain->pCapturePin);
2101 if (!chain->pCapturePin)
2102 return E_POINTER;
2104 if (chain->type == video) {
2105 size = sizeof(VIDEO_STREAM_CONFIG_CAPS);
2106 } else if (chain->type == audio) {
2107 size = sizeof(AUDIO_STREAM_CONFIG_CAPS);
2108 } else {
2109 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnsupportedMediaType,"get_available_formats_pin");
2110 return E_FAIL;
2113 hr = OLE_CALL_ARGS(chain->pCapturePin, EnumMediaTypes, &pEnum);
2114 if (FAILED(hr)) {
2115 mp_msg(MSGT_TV, MSGL_DBG4,
2116 "tvi_dshow: Call to EnumMediaTypes failed (get_available_formats_pin)\n");
2117 return hr;
2119 for (i = 0; OLE_CALL_ARGS(pEnum, Next, 1, &pmt, &cFetched) == S_OK; i++) {
2120 if (!pmt)
2121 break;
2123 OLE_CALL(pEnum,Reset);
2125 count = i;
2126 arpmt =
2127 (AM_MEDIA_TYPE **) malloc((count + 1) * sizeof(AM_MEDIA_TYPE *));
2128 if (!arpmt)
2129 return E_OUTOFMEMORY;
2130 memset(arpmt, 0, (count + 1) * sizeof(AM_MEDIA_TYPE *));
2132 for (i = 0;
2133 i < count
2134 && OLE_CALL_ARGS(pEnum, Next, 1, &(arpmt[i]), &cFetched) == S_OK;
2135 i++);
2137 OLE_RELEASE_SAFE(pEnum);
2140 pBuf = (void **) malloc((count + 1) * sizeof(void *));
2141 if (!pBuf) {
2142 for (i = 0; i < count; i++)
2143 if (arpmt[i])
2144 DeleteMediaType(arpmt[i]);
2145 free(arpmt);
2146 return E_OUTOFMEMORY;
2148 memset(pBuf, 0, (count + 1) * sizeof(void *));
2150 for (i = 0; i < count; i++) {
2151 pBuf[i] = malloc(size);
2152 if (!pBuf[i])
2153 break;
2154 memset(pBuf[i], 0, size);
2156 if (chain->type == video) {
2157 pVideoCaps = (VIDEO_STREAM_CONFIG_CAPS *) pBuf[i];
2158 extract_video_format(arpmt[i], NULL, &p1, &p2);
2159 pVideoCaps->MaxOutputSize.cx = pVideoCaps->MinOutputSize.cx =
2161 pVideoCaps->MaxOutputSize.cy = pVideoCaps->MinOutputSize.cy =
2163 } else {
2164 pAudioCaps = (AUDIO_STREAM_CONFIG_CAPS *) pBuf[i];
2165 extract_audio_format(arpmt[i], &p1, &p2, &p3);
2166 pAudioCaps->MaximumSampleFrequency =
2167 pAudioCaps->MinimumSampleFrequency = p1;
2168 pAudioCaps->MaximumBitsPerSample =
2169 pAudioCaps->MinimumBitsPerSample = p2;
2170 pAudioCaps->MaximumChannels = pAudioCaps->MinimumChannels = p3;
2174 if (i != count) {
2175 for (i = 0; i < count; i++) {
2176 if (arpmt[i])
2177 DeleteMediaType(arpmt[i]);
2178 if (pBuf[i])
2179 free(pBuf[i]);
2181 free(arpmt);
2182 free(pBuf);
2183 return E_OUTOFMEMORY;
2185 chain->arpmt = arpmt;
2186 chain->arStreamCaps = pBuf;
2188 return S_OK;
2192 *---------------------------------------------------------------------------------------
2194 * Public methods
2196 *---------------------------------------------------------------------------------------
2199 * \brief fills given buffer with audio data (usually one block)
2201 * \param priv driver's private data structure
2202 * \param buffer buffer to store data to
2203 * \param len buffer's size in bytes (usually one block size)
2205 * \return audio pts if audio present, 1 - otherwise
2207 static double grab_audio_frame(priv_t * priv, char *buffer, int len)
2209 int bytes = 0;
2210 int i;
2211 double pts;
2212 grabber_ringbuffer_t *rb = priv->chains[1]->rbuf;
2213 grabber_ringbuffer_t *vrb = priv->chains[0]->rbuf;
2215 if (!rb || !rb->ringbuffer)
2216 return 1;
2218 if(vrb && vrb->tStart<0){
2219 memset(buffer,0,len);
2220 return 0;
2222 if(vrb && rb->tStart<0)
2223 rb->tStart=vrb->tStart;
2225 if (len < rb->blocksize)
2226 bytes = len;
2227 else
2228 bytes = rb->blocksize;
2230 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (audio) called. %d blocks in buffer, %d bytes requested\n",
2231 rb->count, len);
2232 if(!rb->count){
2233 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
2234 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
2235 if(!rb->count){
2236 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
2237 return 0;
2239 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
2242 EnterCriticalSection(rb->pMutex);
2243 pts=rb->dpts[rb->head]-rb->tStart;
2244 memcpy(buffer, rb->ringbuffer[rb->head], bytes);
2245 rb->head = (rb->head + 1) % rb->buffersize;
2246 rb->count--;
2247 LeaveCriticalSection(rb->pMutex);
2248 return pts;
2252 * \brief returns audio frame size
2254 * \param priv driver's private data structure
2256 * \return audio block size if audio enabled and 1 - otherwise
2258 static int get_audio_framesize(priv_t * priv)
2260 if (!priv->chains[1]->rbuf)
2261 return 1; //no audio
2262 mp_msg(MSGT_TV,MSGL_DBG3,"get_audio_framesize: %d\n",priv->chains[1]->rbuf->blocksize);
2263 return priv->chains[1]->rbuf->blocksize;
2266 #ifdef CONFIG_TV_TELETEXT
2267 static int vbi_get_props(priv_t* priv,tt_stream_props* ptsp)
2269 if(!priv || !ptsp)
2270 return TVI_CONTROL_FALSE;
2272 //STUBS!!!
2273 ptsp->interlaced=0;
2274 ptsp->offset=256;
2276 ptsp->sampling_rate=27e6;
2277 ptsp->samples_per_line=720;
2279 ptsp->count[0]=16;
2280 ptsp->count[1]=16;
2281 //END STUBS!!!
2282 ptsp->bufsize = ptsp->samples_per_line * (ptsp->count[0] + ptsp->count[1]);
2284 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",
2285 ptsp->sampling_rate,
2286 ptsp->offset,
2287 ptsp->samples_per_line,
2288 ptsp->interlaced?"Yes":"No",
2289 ptsp->count[0],
2290 ptsp->count[1]);
2292 return TVI_CONTROL_TRUE;
2295 static void vbi_grabber(priv_t* priv)
2297 grabber_ringbuffer_t *rb = priv->chains[2]->rbuf;
2298 int i;
2299 unsigned char* buf;
2300 if (!rb || !rb->ringbuffer)
2301 return;
2303 buf=calloc(1,rb->blocksize);
2304 for(i=0; i<23 && rb->count; i++){
2305 memcpy(buf,rb->ringbuffer[rb->head],rb->blocksize);
2306 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_DECODE_PAGE,&buf);
2307 rb->head = (rb->head + 1) % rb->buffersize;
2308 rb->count--;
2310 free(buf);
2312 #endif /* CONFIG_TV_TELETEXT */
2315 * \brief fills given buffer with video data (usually one frame)
2317 * \param priv driver's private data structure
2318 * \param buffer buffer to store data to
2319 * \param len buffer's size in bytes (usually one frame size)
2321 * \return frame size if video present, 0 - otherwise
2323 static double grab_video_frame(priv_t * priv, char *buffer, int len)
2325 int bytes = 0;
2326 int i;
2327 double pts;
2328 grabber_ringbuffer_t *rb = priv->chains[0]->rbuf;
2330 if (!rb || !rb->ringbuffer)
2331 return 1;
2332 if (len < rb->blocksize)
2333 bytes = len;
2334 else
2335 bytes = rb->blocksize;
2337 mp_msg(MSGT_TV, MSGL_DBG3,"tvi_dshow: FillBuffer (video) called. %d blocks in buffer, %d bytes requested\n",
2338 rb->count, len);
2339 if(!rb->count){
2340 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting for frame\n");
2341 for(i=0;i<1000 && !rb->count;i++) usec_sleep(1000);
2342 if(!rb->count){
2343 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: waiting timeout\n");
2344 return 0;
2346 mp_msg(MSGT_TV,MSGL_DBG4,"tvi_dshow: got frame!\n");
2348 EnterCriticalSection(rb->pMutex);
2349 if(rb->tStart<0)
2350 rb->tStart=rb->dpts[rb->head];
2351 pts=rb->dpts[rb->head]-rb->tStart;
2352 memcpy(buffer, rb->ringbuffer[rb->head], bytes);
2353 rb->head = (rb->head + 1) % rb->buffersize;
2354 rb->count--;
2355 LeaveCriticalSection(rb->pMutex);
2357 #ifdef CONFIG_TV_TELETEXT
2358 vbi_grabber(priv);
2359 #endif
2360 return pts;
2364 * \brief returns frame size
2366 * \param priv driver's private data structure
2368 * \return frame size if video present, 0 - otherwise
2370 static int get_video_framesize(priv_t * priv)
2372 // if(!priv->pmtVideo) return 1; //no video
2373 // return priv->pmtVideo->lSampleSize;
2374 if (!priv->chains[0]->rbuf)
2375 return 1; //no video
2376 mp_msg(MSGT_TV,MSGL_DBG3,"geT_video_framesize: %d\n",priv->chains[0]->rbuf->blocksize);
2377 return priv->chains[0]->rbuf->blocksize;
2381 * \brief calculate audio buffer size
2382 * \param video_buf_size size of video buffer in bytes
2383 * \param video_bitrate video bit rate
2384 * \param audio_bitrate audio bit rate
2385 * \return audio buffer isze in bytes
2387 * \remarks length of video buffer and resulted audio buffer calculated in
2388 * seconds will be the same.
2390 static inline int audio_buf_size_from_video(int video_buf_size, int video_bitrate, int audio_bitrate)
2392 int audio_buf_size = audio_bitrate * (video_buf_size / video_bitrate);
2393 mp_msg(MSGT_TV,MSGL_DBG2,"tvi_dshow: Audio capture buffer: %d * %d / %d = %d\n",
2394 audio_bitrate,video_buf_size,video_bitrate,audio_buf_size);
2395 return audio_buf_size;
2399 * \brief common chain initialization routine
2400 * \param chain chain data structure
2402 * \note pCaptureFilter member should be initialized before call to this routine
2404 static HRESULT init_chain_common(ICaptureGraphBuilder2 *pBuilder, chain_t *chain)
2406 HRESULT hr;
2407 int i;
2409 if(!chain->pCaptureFilter)
2410 return E_POINTER;
2412 show_filter_info(chain->pCaptureFilter);
2414 hr = OLE_CALL_ARGS(pBuilder, FindPin,
2415 (IUnknown *) chain->pCaptureFilter,
2416 PINDIR_OUTPUT, chain->pin_category,
2417 chain->majortype, FALSE, 0, &chain->pCapturePin);
2419 if (FAILED(hr)) {
2420 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: FindPin(pCapturePin) call failed. Error:0x%x\n", (unsigned int)hr);
2421 return hr;
2424 hr = OLE_CALL_ARGS(pBuilder, FindInterface,
2425 chain->pin_category,
2426 chain->majortype,
2427 chain->pCaptureFilter,
2428 &IID_IAMStreamConfig,
2429 (void **) &(chain->pStreamConfig));
2430 if (FAILED(hr))
2431 chain->pStreamConfig = NULL;
2434 Getting available video formats (last pointer in array will be NULL)
2435 First tryin to call IAMStreamConfig::GetStreamCaos. this will give us additional information such as
2436 min/max picture dimensions, etc. If this call fails trying IPIn::EnumMediaTypes with default
2437 min/max values.
2439 hr = get_available_formats_stream(chain);
2440 if (FAILED(hr)) {
2441 mp_msg(MSGT_TV, MSGL_DBG2, "Unable to use IAMStreamConfig for retriving available formats (Error:0x%x). Using EnumMediaTypes instead\n", (unsigned int)hr);
2442 hr = get_available_formats_pin(pBuilder, chain);
2443 if(FAILED(hr)){
2444 return hr;
2447 chain->nFormatUsed = 0;
2449 //If argument to CreateMediaType is NULL then result will be NULL too.
2450 chain->pmt = CreateMediaType(chain->arpmt[0]);
2452 for (i = 0; chain->arpmt[i]; i++)
2453 DisplayMediaType("Available format", chain->arpmt[i]);
2455 return S_OK;
2458 * \brief build video stream chain in graph
2459 * \param priv private data structure
2461 * \return S_OK if chain was built successfully, apropriate error code otherwise
2463 static HRESULT build_video_chain(priv_t *priv)
2465 HRESULT hr;
2467 if(priv->chains[0]->rbuf)
2468 return S_OK;
2470 if (priv->chains[0]->pStreamConfig) {
2471 hr = OLE_CALL_ARGS(priv->chains[0]->pStreamConfig, SetFormat, priv->chains[0]->pmt);
2472 if (FAILED(hr)) {
2473 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectVideoFormat, (unsigned int)hr);
2477 priv->chains[0]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2478 if(!priv->chains[0]->rbuf)
2479 return E_OUTOFMEMORY;
2481 if (priv->tv_param->buffer_size >= 0) {
2482 priv->chains[0]->rbuf->buffersize = priv->tv_param->buffer_size;
2483 } else {
2484 priv->chains[0]->rbuf->buffersize = 16;
2487 priv->chains[0]->rbuf->buffersize *= 1024 * 1024;
2488 hr=build_sub_graph(priv, priv->chains[0], &PIN_CATEGORY_CAPTURE);
2489 if(FAILED(hr)){
2490 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVideoSubGraph,(unsigned int)hr);
2491 return hr;
2493 return S_OK;
2497 * \brief build audio stream chain in graph
2498 * \param priv private data structure
2500 * \return S_OK if chain was built successfully, apropriate error code otherwise
2502 static HRESULT build_audio_chain(priv_t *priv)
2504 HRESULT hr;
2506 if(priv->chains[1]->rbuf)
2507 return S_OK;
2509 if(priv->immediate_mode)
2510 return S_OK;
2512 if (priv->chains[1]->pStreamConfig) {
2513 hr = OLE_CALL_ARGS(priv->chains[1]->pStreamConfig, SetFormat,
2514 priv->chains[1]->pmt);
2515 if (FAILED(hr)) {
2516 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableSelectAudioFormat, (unsigned int)hr);
2520 if(priv->chains[1]->pmt){
2521 priv->chains[1]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2522 if(!priv->chains[1]->rbuf)
2523 return E_OUTOFMEMORY;
2525 /* let the audio buffer be the same size (in seconds) than video one */
2526 priv->chains[1]->rbuf->buffersize=audio_buf_size_from_video(
2527 priv->chains[0]->rbuf->buffersize,
2528 (((VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat)->dwBitRate),
2529 (((WAVEFORMATEX *) (priv->chains[1]->pmt->pbFormat))->nAvgBytesPerSec));
2531 hr=build_sub_graph(priv, priv->chains[1],&PIN_CATEGORY_CAPTURE);
2532 if(FAILED(hr)){
2533 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildAudioSubGraph,(unsigned int)hr);
2534 return 0;
2537 return S_OK;
2541 * \brief build VBI stream chain in graph
2542 * \param priv private data structure
2544 * \return S_OK if chain was built successfully, apropriate error code otherwise
2546 static HRESULT build_vbi_chain(priv_t *priv)
2548 #ifdef CONFIG_TV_TELETEXT
2549 HRESULT hr;
2551 if(priv->chains[2]->rbuf)
2552 return S_OK;
2554 if(priv->tv_param->tdevice)
2556 priv->chains[2]->rbuf=calloc(1,sizeof(grabber_ringbuffer_t));
2557 if(!priv->chains[2]->rbuf)
2558 return E_OUTOFMEMORY;
2560 init_ringbuffer(priv->chains[2]->rbuf,24,priv->tsp.bufsize);
2562 hr=build_sub_graph(priv, priv->chains[2],&PIN_CATEGORY_VBI);
2563 if(FAILED(hr)){
2564 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_UnableBuildVBISubGraph,(unsigned int)hr);
2565 return 0;
2568 #endif
2569 return S_OK;
2573 * \brief playback/capture real start
2575 * \param priv driver's private data structure
2577 * \return 1 if success, 0 - otherwise
2579 * TODO: move some code from init() here
2581 static int start(priv_t * priv)
2583 HRESULT hr;
2585 hr = build_video_chain(priv);
2586 if(FAILED(hr))
2587 return 0;
2589 hr = build_audio_chain(priv);
2590 if(FAILED(hr))
2591 return 0;
2593 hr = build_vbi_chain(priv);
2594 if(FAILED(hr))
2595 return 0;
2598 Graph is ready to capture. Starting graph.
2600 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
2601 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause 10sec\n");
2602 usec_sleep(10000000);
2603 mp_msg(MSGT_TV, MSGL_DBG2, "Debug pause end\n");
2605 if (!priv->pMediaControl) {
2606 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)E_POINTER);
2607 return 0;
2609 hr = OLE_CALL(priv->pMediaControl, Run);
2610 if (FAILED(hr)) {
2611 mp_msg(MSGT_TV,MSGL_ERR,MSGTR_TVI_DS_UnableStartGraph, (unsigned int)hr);
2612 return 0;
2614 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Graph is started.\n");
2615 priv->state = 1;
2617 return 1;
2621 * \brief driver initialization
2623 * \param priv driver's private data structure
2625 * \return 1 if success, 0 - otherwise
2627 static int init(priv_t * priv)
2629 HRESULT hr;
2630 int result = 0;
2631 long lInput, lTunerInput;
2632 IEnumFilters *pEnum;
2633 IBaseFilter *pFilter;
2634 IPin *pVPOutPin;
2635 int i;
2637 priv->state=0;
2639 CoInitialize(NULL);
2641 for(i=0; i<3;i++)
2642 priv->chains[i] = calloc(1, sizeof(chain_t));
2644 priv->chains[0]->type=video;
2645 priv->chains[0]->majortype=&MEDIATYPE_Video;
2646 priv->chains[0]->pin_category=&PIN_CATEGORY_CAPTURE;
2647 priv->chains[1]->type=audio;
2648 priv->chains[1]->majortype=&MEDIATYPE_Audio;
2649 priv->chains[1]->pin_category=&PIN_CATEGORY_CAPTURE;
2650 priv->chains[2]->type=vbi;
2651 priv->chains[2]->majortype=&MEDIATYPE_VBI;
2652 priv->chains[2]->pin_category=&PIN_CATEGORY_VBI;
2655 hr = CoCreateInstance((GUID *) & CLSID_FilterGraph, NULL,
2656 CLSCTX_INPROC_SERVER, &IID_IGraphBuilder,
2657 (void **) &priv->pGraph);
2658 if(FAILED(hr)){
2659 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(FilterGraph) call failed. Error:0x%x\n", (unsigned int)hr);
2660 break;
2662 //Debug
2663 if (mp_msg_test(MSGT_TV, MSGL_DBG2)) {
2664 AddToRot((IUnknown *) priv->pGraph, &(priv->dwRegister));
2667 hr = CoCreateInstance((GUID *) & CLSID_CaptureGraphBuilder2, NULL,
2668 CLSCTX_INPROC_SERVER, &IID_ICaptureGraphBuilder2,
2669 (void **) &priv->pBuilder);
2670 if(FAILED(hr)){
2671 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: CoCreateInstance(CaptureGraphBuilder) call failed. Error:0x%x\n", (unsigned int)hr);
2672 break;
2675 hr = OLE_CALL_ARGS(priv->pBuilder, SetFiltergraph, priv->pGraph);
2676 if(FAILED(hr)){
2677 mp_msg(MSGT_TV,MSGL_ERR, "tvi_dshow: SetFiltergraph call failed. Error:0x%x\n",(unsigned int)hr);
2678 break;
2681 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available video capture devices\n");
2682 priv->chains[0]->pCaptureFilter = find_capture_device(priv->dev_index, &CLSID_VideoInputDeviceCategory);
2683 if(!priv->chains[0]->pCaptureFilter){
2684 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoVideoCaptureDevice);
2685 break;
2687 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->chains[0]->pCaptureFilter, NULL);
2688 if(FAILED(hr)){
2689 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to add video capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
2690 break;
2692 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Searching for available audio capture devices\n");
2693 if (priv->adev_index != -1) {
2694 priv->chains[1]->pCaptureFilter = find_capture_device(priv->adev_index, &CLSID_AudioInputDeviceCategory); //output available audio edevices
2695 if(!priv->chains[1]->pCaptureFilter){
2696 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_NoAudioCaptureDevice);
2697 break;
2700 hr = OLE_CALL_ARGS(priv->pGraph, AddFilter, priv->chains[1]->pCaptureFilter, NULL);
2701 if(FAILED(hr)){
2702 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Unable to add audio capture device to Directshow graph. Error:0x%x\n", (unsigned int)hr);
2703 break;
2705 } else
2706 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IBaseFilter, priv->chains[1]->pCaptureFilter);
2708 /* increase refrence counter for capture filter ad store pointer into vbi chain structure too */
2709 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IBaseFilter, priv->chains[2]->pCaptureFilter);
2711 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter, IID_IAMVideoProcAmp,priv->pVideoProcAmp);
2712 if (FAILED(hr) && hr != E_NOINTERFACE)
2713 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Get IID_IAMVideoProcAmp failed (0x%x).\n", (unsigned int)hr);
2715 if (hr != S_OK) {
2716 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_VideoAdjustigNotSupported);
2717 priv->pVideoProcAmp = NULL;
2720 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2721 &PIN_CATEGORY_CAPTURE,
2722 priv->chains[0]->majortype,
2723 priv->chains[0]->pCaptureFilter,
2724 &IID_IAMCrossbar, (void **) &(priv->pCrossbar));
2725 if (FAILED(hr)) {
2726 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_SelectingInputNotSupported);
2727 priv->pCrossbar = NULL;
2730 if (priv->tv_param->amode >= 0) {
2731 IAMTVAudio *pTVAudio;
2732 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface, NULL, NULL,priv->chains[0]->pCaptureFilter,&IID_IAMTVAudio, (void *) &pTVAudio);
2733 if (hr == S_OK) {
2734 switch (priv->tv_param->amode) {
2735 case 0:
2736 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_MONO);
2737 break;
2738 case 1:
2739 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode, AMTVAUDIO_MODE_STEREO);
2740 break;
2741 case 2:
2742 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
2743 AMTVAUDIO_MODE_LANG_A);
2744 break;
2745 case 3:
2746 hr = OLE_CALL_ARGS(pTVAudio, put_TVAudioMode,
2747 AMTVAUDIO_MODE_LANG_B);
2748 break;
2750 OLE_RELEASE_SAFE(pTVAudio);
2751 if (FAILED(hr))
2752 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_UnableSetAudioMode, priv->tv_param->amode,(unsigned int)hr);
2756 // Video chain initialization
2757 hr = init_chain_common(priv->pBuilder, priv->chains[0]);
2758 if(FAILED(hr))
2759 break;
2762 Audio chain initialization
2763 Since absent audio stream is not fatal,
2764 at least one NULL pointer should be kept in format arrays
2765 (to avoid another additional check everywhere for array presence).
2767 hr = init_chain_common(priv->pBuilder, priv->chains[1]);
2768 if(FAILED(hr))
2770 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to initialize audio chain (Error:0x%x). Audio disabled\n", (unsigned long)hr);
2771 priv->chains[1]->arpmt=calloc(1, sizeof(AM_MEDIA_TYPE*));
2772 priv->chains[1]->arStreamCaps=calloc(1, sizeof(void*));
2776 VBI chain initialization
2777 Since absent VBI stream is not fatal,
2778 at least one NULL pointer should be kept in format arrays
2779 (to avoid another additional check everywhere for array presence).
2781 hr = init_chain_common(priv->pBuilder, priv->chains[2]);
2782 if(FAILED(hr))
2784 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to initialize VBI chain (Error:0x%x). Teletext disabled\n", (unsigned long)hr);
2785 priv->chains[2]->arpmt=calloc(1, sizeof(AM_MEDIA_TYPE*));
2786 priv->chains[2]->arStreamCaps=calloc(1, sizeof(void*));
2789 if (!priv->chains[0]->pStreamConfig)
2790 mp_msg(MSGT_TV, MSGL_INFO, MSGTR_TVI_DS_ChangingWidthHeightNotSupported);
2792 if (!priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed]
2793 || !extract_video_format(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed],
2794 &(priv->fcc), &(priv->width),
2795 &(priv->height))) {
2796 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingVideoFormatStruct);
2797 break;
2800 if (priv->chains[1]->arpmt[priv->chains[1]->nFormatUsed]) {
2801 if (!extract_audio_format(priv->chains[1]->pmt, &(priv->samplerate), NULL, NULL)) {
2802 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_ErrorParsingAudioFormatStruct);
2803 DisplayMediaType("audio format failed",priv->chains[1]->arpmt[priv->chains[1]->nFormatUsed]);
2804 break;
2808 hr = OLE_QUERYINTERFACE(priv->pGraph, IID_IMediaControl,priv->pMediaControl);
2809 if(FAILED(hr)){
2810 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableGetMediaControlInterface,(unsigned int)hr);
2811 break;
2813 hr = OLE_CALL_ARGS(priv->pBuilder, FindInterface,
2814 &PIN_CATEGORY_CAPTURE, NULL,
2815 priv->chains[0]->pCaptureFilter,
2816 &IID_IAMTVTuner, (void **) &(priv->pTVTuner));
2818 if (!priv->pTVTuner) {
2819 mp_msg(MSGT_TV, MSGL_DBG2, "tvi_dshow: Unable to access IAMTVTuner (0x%x)\n", (unsigned int)hr);
2822 // shows Tuner capabilities
2823 get_capabilities(priv);
2825 if (priv->pTVTuner) {
2826 hr = OLE_CALL_ARGS(priv->pTVTuner, put_CountryCode,
2827 chanlist2country(priv->tv_param->chanlist));
2828 if(FAILED(hr)){
2829 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_CountryCode failed. Error:0x%x\n",(unsigned int)hr);
2832 hr = OLE_CALL_ARGS(priv->pTVTuner, put_Mode, AMTUNER_MODE_TV);
2833 if(FAILED(hr)){
2834 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_Mode failed. Error:0x%x\n",(unsigned int)hr);
2835 break;
2838 hr = OLE_CALL_ARGS(priv->pTVTuner, get_ConnectInput, &lInput);
2839 if(FAILED(hr)){
2840 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to get_ConnectInput failed. Error:0x%x\n",(unsigned int)hr);
2841 break;
2844 /* small hack */
2845 lTunerInput = strstr(priv->tv_param->chanlist, "cable") ? TunerInputCable : TunerInputAntenna;
2847 hr = OLE_CALL_ARGS(priv->pTVTuner, put_InputType, lInput, lTunerInput);
2848 if(FAILED(hr)){
2849 mp_msg(MSGT_TV,MSGL_DBG2, "tvi_dshow: Call to put_InputType failed. Error:0x%x\n",(unsigned int)hr);
2850 break;
2856 for VIVO cards we should check if preview pin is available on video capture device.
2857 If it is not, we have to connect Video Port Manager filter to VP pin of capture device filter.
2858 Otherwise we will get 0x8007001f (Device is not functioning properly) when attempting to start graph
2860 hr = OLE_CALL_ARGS(priv->pBuilder, FindPin,
2861 (IUnknown *) priv->chains[0]->pCaptureFilter,
2862 PINDIR_OUTPUT,
2863 &PIN_CATEGORY_VIDEOPORT, NULL, FALSE,
2864 0, (IPin **) & pVPOutPin);
2865 if (SUCCEEDED(hr)) {
2866 hr = OLE_CALL_ARGS(priv->pGraph, Render, pVPOutPin);
2867 OLE_RELEASE_SAFE(pVPOutPin);
2869 if (FAILED(hr)) {
2870 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_UnableTerminateVPPin, (unsigned int)hr);
2871 break;
2875 OLE_CALL_ARGS(priv->pGraph, EnumFilters, &pEnum);
2876 while (OLE_CALL_ARGS(pEnum, Next, 1, &pFilter, NULL) == S_OK) {
2877 LPVIDEOWINDOW pVideoWindow;
2878 hr = OLE_QUERYINTERFACE(pFilter, IID_IVideoWindow, pVideoWindow);
2879 if (SUCCEEDED(hr))
2881 if(priv->tv_param->hidden_vp_renderer){
2882 OLE_CALL_ARGS(pVideoWindow,put_Visible,/* OAFALSE*/ 0);
2883 OLE_CALL_ARGS(pVideoWindow,put_AutoShow,/* OAFALSE*/ 0);
2884 }else
2886 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, pFilter);
2888 OLE_RELEASE_SAFE(pVideoWindow);
2890 OLE_RELEASE_SAFE(pFilter);
2892 OLE_RELEASE_SAFE(pEnum);
2893 if(priv->tv_param->system_clock)
2895 LPREFERENCECLOCK rc;
2896 IBaseFilter* pBF;
2897 hr = CoCreateInstance((GUID *) & CLSID_SystemClock, NULL,
2898 CLSCTX_INPROC_SERVER, &IID_IReferenceClock,
2899 (void *) &rc);
2901 OLE_QUERYINTERFACE(priv->pBuilder,IID_IBaseFilter,pBF);
2902 OLE_CALL_ARGS(pBF,SetSyncSource,rc);
2904 #ifdef CONFIG_TV_TELETEXT
2905 if(vbi_get_props(priv,&(priv->tsp))!=TVI_CONTROL_TRUE)
2906 break;
2907 #endif
2908 result = 1;
2909 } while(0);
2911 if (!result){
2912 mp_msg(MSGT_TV,MSGL_ERR, MSGTR_TVI_DS_GraphInitFailure);
2913 uninit(priv);
2915 return result;
2919 * \brief chain uninitialization
2920 * \param chain chain data structure
2922 static void destroy_chain(chain_t *chain)
2924 int i;
2926 if(!chain)
2927 return;
2929 OLE_RELEASE_SAFE(chain->pStreamConfig);
2930 OLE_RELEASE_SAFE(chain->pCaptureFilter);
2931 OLE_RELEASE_SAFE(chain->pCSGCB);
2932 OLE_RELEASE_SAFE(chain->pCapturePin);
2933 OLE_RELEASE_SAFE(chain->pSGIn);
2934 OLE_RELEASE_SAFE(chain->pSG);
2935 OLE_RELEASE_SAFE(chain->pSGF);
2937 if (chain->pmt)
2938 DeleteMediaType(chain->pmt);
2940 if (chain->arpmt) {
2941 for (i = 0; chain->arpmt[i]; i++) {
2942 DeleteMediaType(chain->arpmt[i]);
2944 free(chain->arpmt);
2947 if (chain->arStreamCaps) {
2948 for (i = 0; chain->arStreamCaps[i]; i++) {
2949 free(chain->arStreamCaps[i]);
2951 free(chain->arStreamCaps);
2954 if (chain->rbuf) {
2955 destroy_ringbuffer(chain->rbuf);
2956 free(chain->rbuf);
2957 chain->rbuf = NULL;
2959 free(chain);
2962 * \brief driver uninitialization
2964 * \param priv driver's private data structure
2966 * \return always 1
2968 static int uninit(priv_t * priv)
2970 int i;
2971 if (!priv)
2972 return 1;
2973 //Debug
2974 if (priv->dwRegister) {
2975 RemoveFromRot(priv->dwRegister);
2977 #ifdef CONFIG_TV_TELETEXT
2978 teletext_control(priv->priv_vbi,TV_VBI_CONTROL_STOP,(void*)1);
2979 #endif
2980 //stop audio grabber thread
2982 if (priv->state && priv->pMediaControl) {
2983 OLE_CALL(priv->pMediaControl, Stop);
2985 OLE_RELEASE_SAFE(priv->pMediaControl);
2986 priv->state = 0;
2988 if (priv->pGraph) {
2989 if (priv->chains[0]->pCaptureFilter)
2990 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->chains[0]->pCaptureFilter);
2991 if (priv->chains[1]->pCaptureFilter)
2992 OLE_CALL_ARGS(priv->pGraph, RemoveFilter, priv->chains[1]->pCaptureFilter);
2994 OLE_RELEASE_SAFE(priv->pCrossbar);
2995 OLE_RELEASE_SAFE(priv->pVideoProcAmp);
2996 OLE_RELEASE_SAFE(priv->pGraph);
2997 OLE_RELEASE_SAFE(priv->pBuilder);
2998 if(priv->freq_table){
2999 priv->freq_table_len=-1;
3000 free(priv->freq_table);
3001 priv->freq_table=NULL;
3004 for(i=0; i<3;i++)
3006 destroy_chain(priv->chains[i]);
3007 priv->chains[i] = NULL;
3009 CoUninitialize();
3010 return 1;
3014 * \brief driver pre-initialization
3016 * \param device string, containing device name in form "x[.y]", where x is video capture device
3017 * (default: 0, first available); y (if given) sets audio capture device
3019 * \return 1 if success,0 - otherwise
3021 static tvi_handle_t *tvi_init_dshow(tv_param_t* tv_param)
3023 tvi_handle_t *h;
3024 priv_t *priv;
3025 int a;
3027 h = new_handle();
3028 if (!h)
3029 return NULL;
3031 priv = h->priv;
3033 memset(priv, 0, sizeof(priv_t));
3034 priv->direct_setfreq_call = 1; //first using direct call. if it fails, workaround will be enabled
3035 priv->direct_getfreq_call = 1; //first using direct call. if it fails, workaround will be enabled
3036 priv->adev_index = -1;
3037 priv->freq_table_len=-1;
3038 priv->tv_param=tv_param;
3040 if (tv_param->device) {
3041 if (sscanf(tv_param->device, "%d", &a) == 1) {
3042 priv->dev_index = a;
3043 } else {
3044 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceParam, tv_param->device);
3045 free_handle(h);
3046 return NULL;
3048 if (priv->dev_index < 0) {
3049 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongDeviceIndex, a);
3050 free_handle(h);
3051 return NULL;
3054 if (tv_param->adevice) {
3055 if (sscanf(tv_param->adevice, "%d", &a) == 1) {
3056 priv->adev_index = a;
3057 } else {
3058 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceParam, tv_param->adevice);
3059 free_handle(h);
3060 return NULL;
3062 if (priv->dev_index < 0) {
3063 mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TVI_DS_WrongADeviceIndex, a);
3064 free_handle(h);
3065 return NULL;
3068 return h;
3072 * \brief driver's ioctl handler
3074 * \param priv driver's private data structure
3075 * \param cmd ioctl command
3076 * \param arg ioct command's parameter
3078 * \return TVI_CONTROL_TRUE if success
3079 * \return TVI_CONTROL_FALSE if failure
3080 * \return TVI_CONTROL_UNKNOWN if unknowm cmd called
3082 static int control(priv_t * priv, int cmd, void *arg)
3084 switch (cmd) {
3085 /* need rewrite */
3086 case TVI_CONTROL_VID_SET_FORMAT:
3088 int fcc, i,j;
3089 void* tmp,*tmp2;
3090 int result = TVI_CONTROL_TRUE;
3092 if (priv->state)
3093 return TVI_CONTROL_FALSE;
3094 fcc = *(int *) arg;
3096 if(!priv->chains[0]->arpmt)
3097 return TVI_CONTROL_FALSE;
3098 for (i = 0; priv->chains[0]->arpmt[i]; i++)
3099 if (check_video_format
3100 (priv->chains[0]->arpmt[i], fcc, priv->width, priv->height))
3101 break;
3102 if (!priv->chains[0]->arpmt[i])
3104 int fps = 0;
3105 VIDEOINFOHEADER* Vhdr = NULL;
3106 AM_MEDIA_TYPE *pmt;
3108 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));
3110 if (priv->chains[0]->arpmt[0])
3111 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->arpmt[0]->pbFormat;
3113 if(Vhdr && Vhdr->bmiHeader.biSizeImage)
3114 fps = Vhdr->dwBitRate / (8 * Vhdr->bmiHeader.biSizeImage);
3116 pmt=create_video_format(fcc, priv->width, priv->height, fps);
3117 if(!pmt)
3119 mp_msg(MSGT_TV, MSGL_V, "tvi_dshow: Unable to create AM_MEDIA_TYPE structure for given format\n");
3120 return TVI_CONTROL_FALSE;
3122 priv->chains[0]->arpmt=realloc(priv->chains[0]->arpmt, (i+2)*sizeof(AM_MEDIA_TYPE*));
3123 priv->chains[0]->arpmt[i+1] = NULL;
3124 priv->chains[0]->arpmt[i] = pmt;
3126 priv->chains[0]->arStreamCaps=realloc(priv->chains[0]->arStreamCaps, (i+2)*sizeof(void*));
3127 priv->chains[0]->arpmt[i+1] = NULL;
3129 result = TVI_CONTROL_FALSE;
3133 tmp=priv->chains[0]->arpmt[i];
3134 tmp2=priv->chains[0]->arStreamCaps[i];
3135 for(j=i; j>0; j--)
3137 priv->chains[0]->arpmt[j] = priv->chains[0]->arpmt[j-1];
3138 priv->chains[0]->arStreamCaps[j] = priv->chains[0]->arStreamCaps[j-1];
3140 priv->chains[0]->arpmt[0] = tmp;
3141 priv->chains[0]->arStreamCaps[0] = tmp2;
3143 priv->chains[0]->nFormatUsed = 0;
3145 if (priv->chains[0]->pmt)
3146 DeleteMediaType(priv->chains[0]->pmt);
3147 priv->chains[0]->pmt =
3148 CreateMediaType(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed]);
3149 DisplayMediaType("VID_SET_FORMAT", priv->chains[0]->pmt);
3151 Setting width & height to preferred by driver values
3153 extract_video_format(priv->chains[0]->arpmt[priv->chains[0]->nFormatUsed],
3154 &(priv->fcc), &(priv->width),
3155 &(priv->height));
3156 return result;
3158 case TVI_CONTROL_VID_GET_FORMAT:
3160 if(!priv->chains[0]->pmt)
3161 return TVI_CONTROL_FALSE;
3163 Build video chain (for video format negotiation).
3164 If this was done before, routine will do nothing.
3166 build_video_chain(priv);
3167 DisplayMediaType("VID_GET_FORMAT", priv->chains[0]->pmt);
3168 if (priv->fcc) {
3169 *(int *) arg = priv->fcc;
3170 return TVI_CONTROL_TRUE;
3171 } else
3172 return TVI_CONTROL_FALSE;
3174 case TVI_CONTROL_VID_SET_WIDTH:
3176 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3177 VIDEOINFOHEADER *Vhdr;
3178 int width = *(int *) arg;
3179 if (priv->state)
3180 return TVI_CONTROL_FALSE;
3182 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3183 if (!pCaps)
3184 return TVI_CONTROL_FALSE;
3185 if (width < pCaps->MinOutputSize.cx
3186 || width > pCaps->MaxOutputSize.cx)
3187 return TVI_CONTROL_FALSE;
3189 if (width % pCaps->OutputGranularityX)
3190 return TVI_CONTROL_FALSE;
3192 if (!priv->chains[0]->pmt || !priv->chains[0]->pmt->pbFormat)
3193 return TVI_CONTROL_FALSE;
3194 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3195 Vhdr->bmiHeader.biWidth = width;
3196 priv->chains[0]->pmt->lSampleSize = Vhdr->bmiHeader.biSizeImage =
3197 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
3198 Vhdr->bmiHeader.biHeight) >> 3;
3200 priv->width = width;
3202 return TVI_CONTROL_TRUE;
3204 case TVI_CONTROL_VID_GET_WIDTH:
3206 if (priv->width) {
3207 *(int *) arg = priv->width;
3208 return TVI_CONTROL_TRUE;
3209 } else
3210 return TVI_CONTROL_FALSE;
3212 case TVI_CONTROL_VID_CHK_WIDTH:
3214 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3215 int width = *(int *) arg;
3216 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3217 if (!pCaps)
3218 return TVI_CONTROL_FALSE;
3219 if (width < pCaps->MinOutputSize.cx
3220 || width > pCaps->MaxOutputSize.cx)
3221 return TVI_CONTROL_FALSE;
3223 if (width % pCaps->OutputGranularityX)
3224 return TVI_CONTROL_FALSE;
3225 return TVI_CONTROL_TRUE;
3227 case TVI_CONTROL_VID_SET_HEIGHT:
3229 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3230 VIDEOINFOHEADER *Vhdr;
3231 int height = *(int *) arg;
3232 if (priv->state)
3233 return TVI_CONTROL_FALSE;
3235 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3236 if (!pCaps)
3237 return TVI_CONTROL_FALSE;
3238 if (height < pCaps->MinOutputSize.cy
3239 || height > pCaps->MaxOutputSize.cy)
3240 return TVI_CONTROL_FALSE;
3242 if (height % pCaps->OutputGranularityY)
3243 return TVI_CONTROL_FALSE;
3245 if (!priv->chains[0]->pmt || !priv->chains[0]->pmt->pbFormat)
3246 return TVI_CONTROL_FALSE;
3247 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3249 if (Vhdr->bmiHeader.biHeight < 0)
3250 Vhdr->bmiHeader.biHeight = -height;
3251 else
3252 Vhdr->bmiHeader.biHeight = height;
3253 priv->chains[0]->pmt->lSampleSize = Vhdr->bmiHeader.biSizeImage =
3254 labs(Vhdr->bmiHeader.biBitCount * Vhdr->bmiHeader.biWidth *
3255 Vhdr->bmiHeader.biHeight) >> 3;
3257 priv->height = height;
3258 return TVI_CONTROL_TRUE;
3260 case TVI_CONTROL_VID_GET_HEIGHT:
3262 if (priv->height) {
3263 *(int *) arg = priv->height;
3264 return TVI_CONTROL_TRUE;
3265 } else
3266 return TVI_CONTROL_FALSE;
3268 case TVI_CONTROL_VID_CHK_HEIGHT:
3270 VIDEO_STREAM_CONFIG_CAPS *pCaps;
3271 int height = *(int *) arg;
3272 pCaps = priv->chains[0]->arStreamCaps[priv->chains[0]->nFormatUsed];
3273 if (!pCaps)
3274 return TVI_CONTROL_FALSE;
3275 if (height < pCaps->MinOutputSize.cy
3276 || height > pCaps->MaxOutputSize.cy)
3277 return TVI_CONTROL_FALSE;
3279 if (height % pCaps->OutputGranularityY)
3280 return TVI_CONTROL_FALSE;
3282 return TVI_CONTROL_TRUE;
3284 case TVI_CONTROL_IS_AUDIO:
3285 if (!priv->chains[1]->pmt)
3286 return TVI_CONTROL_FALSE;
3287 else
3288 return TVI_CONTROL_TRUE;
3289 case TVI_CONTROL_IS_VIDEO:
3290 return TVI_CONTROL_TRUE;
3291 case TVI_CONTROL_AUD_GET_FORMAT:
3293 *(int *) arg = AF_FORMAT_S16_LE;
3294 if (!priv->chains[1]->pmt)
3295 return TVI_CONTROL_FALSE;
3296 else
3297 return TVI_CONTROL_TRUE;
3299 case TVI_CONTROL_AUD_GET_CHANNELS:
3301 *(int *) arg = priv->channels;
3302 if (!priv->chains[1]->pmt)
3303 return TVI_CONTROL_FALSE;
3304 else
3305 return TVI_CONTROL_TRUE;
3307 case TVI_CONTROL_AUD_SET_SAMPLERATE:
3309 int i, samplerate;
3310 if (priv->state)
3311 return TVI_CONTROL_FALSE;
3312 if (!priv->chains[1]->arpmt[0])
3313 return TVI_CONTROL_FALSE;
3315 samplerate = *(int *) arg;
3317 for (i = 0; priv->chains[1]->arpmt[i]; i++)
3318 if (check_audio_format
3319 (priv->chains[1]->arpmt[i], samplerate, 16, priv->channels))
3320 break;
3321 if (!priv->chains[1]->arpmt[i]) {
3322 //request not found. failing back to first available
3323 mp_msg(MSGT_TV, MSGL_WARN, MSGTR_TVI_DS_SamplerateNotsupported, samplerate);
3324 i = 0;
3326 if (priv->chains[1]->pmt)
3327 DeleteMediaType(priv->chains[1]->pmt);
3328 priv->chains[1]->pmt = CreateMediaType(priv->chains[1]->arpmt[i]);
3329 extract_audio_format(priv->chains[1]->arpmt[i], &(priv->samplerate),
3330 NULL, &(priv->channels));
3331 return TVI_CONTROL_TRUE;
3333 case TVI_CONTROL_AUD_GET_SAMPLERATE:
3335 *(int *) arg = priv->samplerate;
3336 if (!priv->samplerate)
3337 return TVI_CONTROL_FALSE;
3338 if (!priv->chains[1]->pmt)
3339 return TVI_CONTROL_FALSE;
3340 else
3341 return TVI_CONTROL_TRUE;
3343 case TVI_CONTROL_AUD_GET_SAMPLESIZE:
3345 WAVEFORMATEX *pWF;
3346 if (!priv->chains[1]->pmt)
3347 return TVI_CONTROL_FALSE;
3348 if (!priv->chains[1]->pmt->pbFormat)
3349 return TVI_CONTROL_FALSE;
3350 pWF = (WAVEFORMATEX *) priv->chains[1]->pmt->pbFormat;
3351 *(int *) arg = pWF->wBitsPerSample / 8;
3352 return TVI_CONTROL_TRUE;
3354 case TVI_CONTROL_IS_TUNER:
3356 if (!priv->pTVTuner)
3357 return TVI_CONTROL_FALSE;
3359 return TVI_CONTROL_TRUE;
3361 case TVI_CONTROL_TUN_SET_NORM:
3363 IAMAnalogVideoDecoder *pVD;
3364 long lAnalogFormat;
3365 int i;
3366 HRESULT hr;
3368 i = *(int *) arg;
3369 i--;
3370 if (i < 0 || i >= tv_available_norms_count)
3371 return TVI_CONTROL_FALSE;
3372 lAnalogFormat = tv_norms[tv_available_norms[i]].index;
3374 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter,IID_IAMAnalogVideoDecoder, pVD);
3375 if (hr != S_OK)
3376 return TVI_CONTROL_FALSE;
3377 hr = OLE_CALL_ARGS(pVD, put_TVFormat, lAnalogFormat);
3378 OLE_RELEASE_SAFE(pVD);
3379 if (FAILED(hr))
3380 return TVI_CONTROL_FALSE;
3381 else
3382 return TVI_CONTROL_TRUE;
3384 case TVI_CONTROL_TUN_GET_NORM:
3386 long lAnalogFormat;
3387 int i;
3388 HRESULT hr;
3389 IAMAnalogVideoDecoder *pVD;
3391 hr = OLE_QUERYINTERFACE(priv->chains[0]->pCaptureFilter,IID_IAMAnalogVideoDecoder, pVD);
3392 if (hr == S_OK) {
3393 hr = OLE_CALL_ARGS(pVD, get_TVFormat, &lAnalogFormat);
3394 OLE_RELEASE_SAFE(pVD);
3397 if (FAILED(hr)) { //trying another method
3398 if (!priv->pTVTuner)
3399 return TVI_CONTROL_FALSE;
3400 hr=OLE_CALL_ARGS(priv->pTVTuner, get_TVFormat, &lAnalogFormat);
3401 if (FAILED(hr))
3402 return TVI_CONTROL_FALSE;
3404 for (i = 0; i < tv_available_norms_count; i++) {
3405 if (tv_norms[tv_available_norms[i]].index == lAnalogFormat) {
3406 *(int *) arg = i + 1;
3407 return TVI_CONTROL_TRUE;
3410 return TVI_CONTROL_FALSE;
3412 case TVI_CONTROL_SPC_GET_NORMID:
3414 int i;
3415 if (!priv->pTVTuner)
3416 return TVI_CONTROL_FALSE;
3417 for (i = 0; i < tv_available_norms_count; i++) {
3418 if (!strcasecmp
3419 (tv_norms[tv_available_norms[i]].name, (char *) arg)) {
3420 *(int *) arg = i + 1;
3421 return TVI_CONTROL_TRUE;
3424 return TVI_CONTROL_FALSE;
3426 case TVI_CONTROL_SPC_SET_INPUT:
3428 return set_crossbar_input(priv, *(int *) arg);
3430 case TVI_CONTROL_TUN_GET_FREQ:
3432 unsigned long lFreq;
3433 int ret;
3434 if (!priv->pTVTuner)
3435 return TVI_CONTROL_FALSE;
3437 ret = get_frequency(priv, &lFreq);
3438 lFreq = lFreq / (1000000/16); //convert from Hz to 1/16 MHz units
3440 *(unsigned long *) arg = lFreq;
3441 return ret;
3443 case TVI_CONTROL_TUN_SET_FREQ:
3445 unsigned long nFreq = *(unsigned long *) arg;
3446 if (!priv->pTVTuner)
3447 return TVI_CONTROL_FALSE;
3448 //convert to Hz
3449 nFreq = (1000000/16) * nFreq; //convert from 1/16 MHz units to Hz
3450 return set_frequency(priv, nFreq);
3452 case TVI_CONTROL_VID_SET_HUE:
3453 return set_control(priv, VideoProcAmp_Hue, *(int *) arg);
3454 case TVI_CONTROL_VID_GET_HUE:
3455 return get_control(priv, VideoProcAmp_Hue, (int *) arg);
3456 case TVI_CONTROL_VID_SET_CONTRAST:
3457 return set_control(priv, VideoProcAmp_Contrast, *(int *) arg);
3458 case TVI_CONTROL_VID_GET_CONTRAST:
3459 return get_control(priv, VideoProcAmp_Contrast, (int *) arg);
3460 case TVI_CONTROL_VID_SET_SATURATION:
3461 return set_control(priv, VideoProcAmp_Saturation, *(int *) arg);
3462 case TVI_CONTROL_VID_GET_SATURATION:
3463 return get_control(priv, VideoProcAmp_Saturation, (int *) arg);
3464 case TVI_CONTROL_VID_SET_BRIGHTNESS:
3465 return set_control(priv, VideoProcAmp_Brightness, *(int *) arg);
3466 case TVI_CONTROL_VID_GET_BRIGHTNESS:
3467 return get_control(priv, VideoProcAmp_Brightness, (int *) arg);
3469 case TVI_CONTROL_VID_GET_FPS:
3471 VIDEOINFOHEADER *Vhdr;
3472 if (!priv->chains[0]->pmt)
3473 return TVI_CONTROL_FALSE;
3474 if (!priv->chains[0]->pmt->pbFormat)
3475 return TVI_CONTROL_FALSE;
3476 Vhdr = (VIDEOINFOHEADER *) priv->chains[0]->pmt->pbFormat;
3477 *(float *) arg =
3478 (1.0 * Vhdr->dwBitRate) / (Vhdr->bmiHeader.biSizeImage * 8);
3479 return TVI_CONTROL_TRUE;
3481 case TVI_CONTROL_IMMEDIATE:
3482 priv->immediate_mode = 1;
3483 return TVI_CONTROL_TRUE;
3484 #ifdef CONFIG_TV_TELETEXT
3485 case TVI_CONTROL_VBI_INIT:
3487 void* ptr;
3488 ptr=&(priv->tsp);
3489 if(teletext_control(NULL,TV_VBI_CONTROL_START,&ptr)==TVI_CONTROL_TRUE)
3490 priv->priv_vbi=ptr;
3491 else
3492 priv->priv_vbi=NULL;
3493 return TVI_CONTROL_TRUE;
3495 default:
3496 return teletext_control(priv->priv_vbi,cmd,arg);
3497 #endif
3499 return TVI_CONTROL_UNKNOWN;